diff --git a/DEPS b/DEPS
index f35045e0..94244705 100644
--- a/DEPS
+++ b/DEPS
@@ -304,7 +304,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': '504acfa470a1061162997431b17424f3147df9bd',
+  'skia_revision': '279b5bb5f31992d234f1b61b59089091a9ec283b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -812,7 +812,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    'bb050faf6ca68b61af1d27b414a5a425dd75b0e1',
+    '4e5e172d77ef078a38721208e253a7d269f25316',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1228,7 +1228,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'c5ca42c6955b899f41974c668069c1b63a179276',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '3213f77419e7e8539c6b257581e1ccc8ce22b84b',
       'condition': 'checkout_linux',
   },
 
@@ -1248,7 +1248,7 @@
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'ba2a8c54a1dc8efe2d2d675931fd7568a80518c3',
+      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'ccb8eff8054733bf3055db237fb2d72282e7ccca',
     'condition': 'checkout_src_internal',
   },
 
@@ -1860,7 +1860,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@f91531b69366aa8d18c0447f2b3e86257e44a31c',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@38913f747b19e3fabc01f6a0a92222a339918f4b',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907',
@@ -1897,7 +1897,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd1b65aa5a88f6efd900604dfcda840154e9f16e2',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '1585e66de78d0d2e600f467eddafc445eaff1c90',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'dd99850161ffe15f9ea48dc9c5379d9369059fbd',
 
   'src/third_party/webrtc':
     Var('webrtc_git') + '/src.git' + '@' + '4aaacb4382bf3e7510eb3f09564f6795fafea465',
@@ -2009,7 +2009,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/eche_app/app',
-        'version': 'X_-AEe7yM_cIfjl8vvM3tB4fV0hSLraWg9TJUd_efL8C',
+        'version': 'f1hXXbK55nXgnpNLOinFIhUFhDbbIDKWvhOUff0vO2gC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -2031,7 +2031,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'ABZq-_Ze-t3iqPVevzJMmQjSDf2N_zfWSD74_XU6STQC',
+        'version': 'KJGeg_QmY4-opKCOIVMQ2E9kHwp--oxJSZ1hRWEUIw4C',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
index 7fb4478..e878451 100644
--- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
+++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -164,9 +164,6 @@
                             + "hierarchy level."),
             Flag.baseFeature(AutofillFeatures.AUTOFILL_SPLIT_CREDIT_CARD_NUMBERS_CAUTIOUSLY,
                     "Split credit card numbers over multiple fields more cautiously."),
-            Flag.baseFeature(AutofillFeatures.AUTOFILL_ACROSS_IFRAMES,
-                    "Enable Autofill for frame-transcending forms (forms whose fields live in "
-                            + "different frames)."),
             Flag.baseFeature(AutofillFeatures.AUTOFILL_ENABLE_DEPENDENT_LOCALITY_PARSING,
                     "Enables parsing dependent locality fields (e.g. Bairros in Brazil)."),
             Flag.baseFeature(AutofillFeatures.AUTOFILL_ENABLE_EXPIRATION_DATE_IMPROVEMENTS,
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index dd6fe7e..2053d97a 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1066,8 +1066,6 @@
     "shelf/shelf_navigation_widget.cc",
     "shelf/shelf_navigation_widget.h",
     "shelf/shelf_observer.h",
-    "shelf/shelf_party_feature_pod_controller.cc",
-    "shelf/shelf_party_feature_pod_controller.h",
     "shelf/shelf_shutdown_confirmation_bubble.cc",
     "shelf/shelf_shutdown_confirmation_bubble.h",
     "shelf/shelf_test_api.cc",
@@ -3185,7 +3183,6 @@
     "shelf/shelf_drag_handle_unittest.cc",
     "shelf/shelf_layout_manager_unittest.cc",
     "shelf/shelf_locking_manager_unittest.cc",
-    "shelf/shelf_party_feature_pod_controller_unittest.cc",
     "shelf/shelf_tooltip_manager_unittest.cc",
     "shelf/shelf_unittest.cc",
     "shelf/shelf_view_unittest.cc",
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 0c76453..23ea612 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -6421,24 +6421,6 @@
       </message>
 
       <!-- Shelf Party -->
-      <message name="IDS_ASH_STATUS_TRAY_SHELF_PARTY_LABEL" desc="The text shown in the tray menu button that toggles Shelf Party mode.">
-        Shelf Party
-      </message>
-      <message name="IDS_ASH_STATUS_TRAY_SHELF_PARTY_TOGGLE_TOOLTIP" desc="The tooltip text used for the tray menu button that toggles Shelf Party mode.">
-        Toggle Shelf Party. <ph name="STATE_TEXT">$1<ex>Shelf Party is on.</ex></ph>
-      </message>
-      <message name="IDS_ASH_STATUS_TRAY_SHELF_PARTY_ENABLED_STATE_TOOLTIP" desc="The tooltip text indicating that Shelf Party mode is on.">
-        Shelf Party is on.
-      </message>
-      <message name="IDS_ASH_STATUS_TRAY_SHELF_PARTY_DISABLED_STATE_TOOLTIP" desc="The tooltip text indicating that Shelf Party mode is off.">
-        Shelf Party is off.
-      </message>
-      <message name="IDS_ASH_STATUS_TRAY_SHELF_PARTY_ON_SUBLABEL" desc="The sub label text shown under the tray menu button when Shelf Party mode is on.">
-        On
-      </message>
-      <message name="IDS_ASH_STATUS_TRAY_SHELF_PARTY_OFF_SUBLABEL" desc="The sub label text shown under the tray menu button when Shelf Party mode is off.">
-        Off
-      </message>
       <message name="IDS_ASH_SHELF_ALL_PINNED_ITEMS_ARE_PARTYING" desc="The message that is displayed on the shelf when all pinned items are in Shelf Party (and therefore not shown on the shelf).">
         All pinned items are partying
       </message>
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_SHELF_PARTY_DISABLED_STATE_TOOLTIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_SHELF_PARTY_DISABLED_STATE_TOOLTIP.png.sha1
deleted file mode 100644
index 4e04b245..0000000
--- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_SHELF_PARTY_DISABLED_STATE_TOOLTIP.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-d54188f8bff1ce8b7373f98a92b92bfd0fee092e
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_SHELF_PARTY_ENABLED_STATE_TOOLTIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_SHELF_PARTY_ENABLED_STATE_TOOLTIP.png.sha1
deleted file mode 100644
index 30011e1..0000000
--- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_SHELF_PARTY_ENABLED_STATE_TOOLTIP.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-a0a1d8bbf3bda871177fda7df20f198e883e3634
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_SHELF_PARTY_LABEL.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_SHELF_PARTY_LABEL.png.sha1
deleted file mode 100644
index 5aa5e0ce..0000000
--- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_SHELF_PARTY_LABEL.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-07e87468238a9ee999d954266cc29c6cb81c9e6a
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_SHELF_PARTY_OFF_SUBLABEL.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_SHELF_PARTY_OFF_SUBLABEL.png.sha1
deleted file mode 100644
index 6d0b483a..0000000
--- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_SHELF_PARTY_OFF_SUBLABEL.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-9b14f0cdbecc32ed7a4de8de4da1424ca136513b
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_SHELF_PARTY_ON_SUBLABEL.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_SHELF_PARTY_ON_SUBLABEL.png.sha1
deleted file mode 100644
index 5aa5e0ce..0000000
--- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_SHELF_PARTY_ON_SUBLABEL.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-07e87468238a9ee999d954266cc29c6cb81c9e6a
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_SHELF_PARTY_TOGGLE_TOOLTIP.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_SHELF_PARTY_TOGGLE_TOOLTIP.png.sha1
deleted file mode 100644
index 30011e1..0000000
--- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_SHELF_PARTY_TOGGLE_TOOLTIP.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-a0a1d8bbf3bda871177fda7df20f198e883e3634
\ No newline at end of file
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index f8906a0..c0c9340 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -989,7 +989,9 @@
              base::FEATURE_DISABLED_BY_DEFAULT);
 
 // Enables V2 of search functionality in files.
-BASE_FEATURE(kFilesSearchV2, "FilesSearchV2", base::FEATURE_ENABLED_BY_DEFAULT);
+BASE_FEATURE(kFilesSearchV2,
+             "FilesSearchV2",
+             base::FEATURE_DISABLED_BY_DEFAULT);
 
 // Enables partitioning of removable disks in file manager.
 BASE_FEATURE(kFilesSinglePartitionFormat,
diff --git a/ash/constants/quick_settings_catalogs.h b/ash/constants/quick_settings_catalogs.h
index 3e5dba3e..51760b2 100644
--- a/ash/constants/quick_settings_catalogs.h
+++ b/ash/constants/quick_settings_catalogs.h
@@ -56,7 +56,7 @@
   kIME = 12,
   kLocale = 13,
   kDarkMode = 14,
-  kShelfParty = 15,
+  kShelfParty_DEPRECATED = 15,
   kAutozoom = 16,
   kHotspot = 17,
   kMaxValue = kHotspot
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc
index 73299415..d87155b 100644
--- a/ash/login/ui/login_auth_user_view.cc
+++ b/ash/login/ui/login_auth_user_view.cc
@@ -74,6 +74,7 @@
 #include "ui/views/controls/button/md_text_button.h"
 #include "ui/views/controls/highlight_path_generator.h"
 #include "ui/views/controls/label.h"
+#include "ui/views/highlight_border.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/fill_layout.h"
 #include "ui/views/layout/flex_layout.h"
@@ -99,10 +100,10 @@
 const int kPinPasswordToggleButtonPaddingTop = 24;
 const int kPinPasswordToggleButtonPaddingBottom = 20;
 
-// The background color id of the button used for switching between pin and
-// password. Applied only for Jellyroll.
-constexpr ui::ColorId kPinPasswordToggleColorId =
-    cros_tokens::kCrosSysSystemOnBase1;
+// The highlight radius of the button used for switching between pin and
+// password.
+constexpr int kPinPasswordToggleButtonHighlightRadiusDp =
+    kPinPasswordToggleButtonHeight / 2;
 
 // Distance from the end of pin keyboard to the bottom of the big user view.
 const int kDistanceFromPinKeyboardToBigUserViewBottomDp = 50;
@@ -844,7 +845,11 @@
       gfx::Size(/*ignored*/ 0, kPinPasswordToggleButtonHeight));
 
   if (chromeos::features::IsJellyrollEnabled()) {
-    pin_password_toggle_->SetBackgroundColorId(kPinPasswordToggleColorId);
+    pin_password_toggle_->SetPillButtonType(
+        PillButton::kDefaultElevatedLargeWithoutIcon);
+    pin_password_toggle_->SetBorder(std::make_unique<views::HighlightBorder>(
+        kPinPasswordToggleButtonHighlightRadiusDp,
+        views::HighlightBorder::Type::kHighlightBorderNoShadow));
   }
 
   auto pin_view = std::make_unique<LoginPinView>(
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn
index d015a87..34a26f8bf 100644
--- a/ash/resources/vector_icons/BUILD.gn
+++ b/ash/resources/vector_icons/BUILD.gn
@@ -311,7 +311,6 @@
     "shelf_overflow.icon",
     "shelf_overflow_horizontal_dots.icon",
     "shelf_overview.icon",
-    "shelf_party.icon",
     "shelf_position.icon",
     "shelf_shutdown_button.icon",
     "shelf_sign_out_button.icon",
diff --git a/ash/resources/vector_icons/shelf_party.icon b/ash/resources/vector_icons/shelf_party.icon
deleted file mode 100644
index 0f5fd805..0000000
--- a/ash/resources/vector_icons/shelf_party.icon
+++ /dev/null
@@ -1,43 +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.
-
-CANVAS_DIMENSIONS, 24,
-MOVE_TO, 13.16f, 8.8f,
-R_CUBIC_TO, -1.69f, 4.61f, -7.68f, 7.64f, -9.53f, 6.96f,
-CUBIC_TO, 1.79f, 15.09f, -0.82f, 8.9f, 0.87f, 4.29f,
-R_ARC_TO, 6.55f, 6.55f, 0, 1, 1, 12.29f, 4.51f,
-CLOSE,
-NEW_PATH,
-MOVE_TO, 4.2f, 14.23f,
-LINE_TO, 0, 16.17f,
-R_LINE_TO, 6.15f, 2.25f,
-CLOSE,
-NEW_PATH,
-MOVE_TO, 20.5f, 15.39f,
-R_CUBIC_TO, -0.99f, -0.03f, -2.02f, 0.18f, -3.01f, 0.54f,
-R_CUBIC_TO, -1.99f, 0.72f, -3.99f, 1.99f, -5.94f, 3.2f,
-R_CUBIC_TO, -1.95f, 1.21f, -3.84f, 2.35f, -5.41f, 2.84f,
-R_CUBIC_TO, -0.79f, 0.25f, -1.48f, 0.34f, -2.06f, 0.25f,
-R_CUBIC_TO, -0.58f, -0.09f, -1.07f, -0.32f, -1.56f, -0.85f,
-R_CUBIC_TO, -0.05f, -0.05f, -0.12f, -0.22f, -0.04f, -0.63f,
-R_CUBIC_TO, 0.07f, -0.41f, 0.28f, -0.96f, 0.54f, -1.48f,
-R_CUBIC_TO, 0.52f, -1.04f, 1.19f, -1.97f, 1.19f, -1.97f,
-LINE_TO, 2.8f, 16.25f,
-R_CUBIC_TO, 0, 0, -0.75f, 1.01f, -1.35f, 2.23f,
-R_CUBIC_TO, -0.3f, 0.61f, -0.57f, 1.27f, -0.69f, 1.96f,
-R_CUBIC_TO, -0.12f, 0.69f, -0.08f, 1.51f, 0.49f, 2.12f,
-R_CUBIC_TO, 0.73f, 0.78f, 1.63f, 1.24f, 2.57f, 1.39f,
-R_CUBIC_TO, 0.94f, 0.14f, 1.89f, 0, 2.85f, -0.3f,
-R_CUBIC_TO, 1.91f, -0.6f, 3.86f, -1.82f, 5.81f, -3.03f,
-R_CUBIC_TO, 1.95f, -1.21f, 3.9f, -2.41f, 5.61f, -3.04f,
-R_CUBIC_TO, 1.71f, -0.62f, 3.04f, -0.68f, 4.19f, 0.18f,
-R_CUBIC_TO, -0.11f, -0.08f, -0.07f, -0.1f, -0.05f, 0.02f,
-R_CUBIC_TO, 0.02f, 0.13f, 0.03f, 0.35f, 0.01f, 0.57f,
-R_CUBIC_TO, -0.04f, 0.44f, -0.14f, 0.86f, -0.14f, 0.86f,
-R_LINE_TO, 1.7f, 0.43f,
-R_CUBIC_TO, 0, 0, 0.14f, -0.53f, 0.19f, -1.16f,
-R_ARC_TO, 3.93f, 3.93f, 0, 0, 0, -0.04f, -1.02f,
-R_CUBIC_TO, -0.06f, -0.36f, -0.2f, -0.8f, -0.63f, -1.12f,
-R_CUBIC_TO, -0.86f, -0.64f, -1.82f, -0.93f, -2.82f, -0.96f,
-CLOSE
diff --git a/ash/shelf/login_shelf_view.cc b/ash/shelf/login_shelf_view.cc
index c7659d2..418e1b3 100644
--- a/ash/shelf/login_shelf_view.cc
+++ b/ash/shelf/login_shelf_view.cc
@@ -54,7 +54,6 @@
 #include "ui/base/models/image_model.h"
 #include "ui/base/models/menu_model.h"
 #include "ui/base/models/simple_menu_model.h"
-#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/color/color_id.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/display/manager/display_configurator.h"
@@ -75,6 +74,7 @@
 #include "ui/views/controls/menu/menu_runner.h"
 #include "ui/views/controls/menu/menu_types.h"
 #include "ui/views/focus/focus_search.h"
+#include "ui/views/highlight_border.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/view_class_properties.h"
 #include "ui/views/widget/widget.h"
@@ -117,11 +117,6 @@
   return IsOobe() ? kColorAshButtonIconColorLight : kColorAshButtonIconColor;
 }
 
-ui::ColorId GetButtonBackgroundColorId() {
-  return IsOobe() ? cros_tokens::kCrosSysSystemOnBase
-                  : cros_tokens::kCrosSysSystemOnBase1;
-}
-
 LoginMetricsRecorder::ShelfButtonClickTarget GetUserClickTarget(int button_id) {
   switch (button_id) {
     case LoginShelfView::kShutdown:
@@ -163,6 +158,9 @@
 // Spacing between the button image and label.
 constexpr int kImageLabelSpacingDp = 8;
 
+// The highlight radius of the button.
+constexpr int kButtonHighlightRadiusDp = 16;
+
 void AnimateButtonOpacity(ui::Layer* layer,
                           float target_opacity,
                           base::TimeDelta animation_duration,
@@ -213,9 +211,13 @@
   }
 
   void UpdateButtonColors() {
-    SetEnabledTextColorIds(GetButtonTextColorId());
     if (chromeos::features::IsJellyrollEnabled()) {
-      SetBackgroundColorId(GetButtonBackgroundColorId());
+      SetPillButtonType(PillButton::kDefaultElevatedLargeWithIconLeading);
+      SetBorder(std::make_unique<views::HighlightBorder>(
+          kButtonHighlightRadiusDp,
+          views::HighlightBorder::Type::kHighlightBorderNoShadow));
+    } else {
+      SetEnabledTextColorIds(GetButtonTextColorId());
     }
     SetImageModel(
         views::Button::STATE_NORMAL,
diff --git a/ash/shelf/shelf_party_feature_pod_controller.cc b/ash/shelf/shelf_party_feature_pod_controller.cc
deleted file mode 100644
index b39586d17..0000000
--- a/ash/shelf/shelf_party_feature_pod_controller.cc
+++ /dev/null
@@ -1,153 +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 "ash/shelf/shelf_party_feature_pod_controller.h"
-
-#include "ash/constants/ash_features.h"
-#include "ash/constants/quick_settings_catalogs.h"
-#include "ash/public/cpp/shelf_model.h"
-#include "ash/resources/vector_icons/vector_icons.h"
-#include "ash/session/session_controller_impl.h"
-#include "ash/shelf/shelf_controller.h"
-#include "ash/shell.h"
-#include "ash/strings/grit/ash_strings.h"
-#include "ash/system/unified/feature_pod_button.h"
-#include "ash/system/unified/feature_tile.h"
-#include "ash/system/unified/quick_settings_metrics_util.h"
-#include "components/session_manager/session_manager_types.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace ash {
-namespace {
-
-bool IsButtonVisible() {
-  SessionControllerImpl* session_controller =
-      Shell::Get()->session_controller();
-  return session_controller->GetSessionState() ==
-             session_manager::SessionState::ACTIVE &&
-         !session_controller->IsEnterpriseManaged();
-}
-
-}  // namespace
-
-ShelfPartyFeaturePodController::ShelfPartyFeaturePodController() = default;
-
-ShelfPartyFeaturePodController::~ShelfPartyFeaturePodController() {
-  Shell::Get()->session_controller()->RemoveObserver(this);
-  Shell::Get()->shelf_controller()->model()->RemoveObserver(this);
-}
-
-FeaturePodButton* ShelfPartyFeaturePodController::CreateButton() {
-  DCHECK(!button_);
-  DCHECK(!features::IsQsRevampEnabled());
-  button_ = new FeaturePodButton(this);
-  button_->DisableLabelButtonFocus();
-  button_->SetVectorIcon(kShelfPartyIcon);
-  button_->SetLabel(
-      l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SHELF_PARTY_LABEL));
-
-  // Init the button with invisible state. The `UpdateButton` method will update
-  // the visibility based on the current condition.
-  button_->SetVisible(false);
-  UpdateButton();
-  Shell::Get()->session_controller()->AddObserver(this);
-  Shell::Get()->shelf_controller()->model()->AddObserver(this);
-  return button_;
-}
-
-std::unique_ptr<FeatureTile> ShelfPartyFeaturePodController::CreateTile(
-    bool compact) {
-  DCHECK(!tile_);
-  DCHECK(features::IsQsRevampEnabled());
-  auto tile = std::make_unique<FeatureTile>(
-      base::BindRepeating(&ShelfPartyFeaturePodController::OnIconPressed,
-                          weak_factory_.GetWeakPtr()));
-  tile_ = tile.get();
-  tile_->SetVectorIcon(kShelfPartyIcon);
-  tile_->SetLabel(
-      l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SHELF_PARTY_LABEL));
-
-  // `UpdateTile()` will update visibility.
-  tile_->SetVisible(false);
-  UpdateTile();
-  Shell::Get()->session_controller()->AddObserver(this);
-  Shell::Get()->shelf_controller()->model()->AddObserver(this);
-  return tile;
-}
-
-QsFeatureCatalogName ShelfPartyFeaturePodController::GetCatalogName() {
-  return QsFeatureCatalogName::kShelfParty;
-}
-
-void ShelfPartyFeaturePodController::OnIconPressed() {
-  TrackToggleUMA(/*target_toggle_state=*/!Shell::Get()
-                     ->shelf_controller()
-                     ->model()
-                     ->in_shelf_party());
-  Shell::Get()->shelf_controller()->model()->ToggleShelfParty();
-}
-
-void ShelfPartyFeaturePodController::OnSessionStateChanged(
-    session_manager::SessionState state) {
-  Update();
-}
-
-void ShelfPartyFeaturePodController::ShelfPartyToggled(bool in_shelf_party) {
-  Update();
-}
-
-void ShelfPartyFeaturePodController::Update() {
-  if (features::IsQsRevampEnabled()) {
-    UpdateTile();
-  } else {
-    UpdateButton();
-  }
-}
-
-void ShelfPartyFeaturePodController::UpdateButton() {
-  DCHECK(button_);
-  const bool visible = IsButtonVisible();
-  // If the button's visibility changes from invisible to visible, log its
-  // visibility.
-  if (!button_->GetVisible() && visible)
-    TrackVisibilityUMA();
-  button_->SetVisible(visible);
-
-  const bool toggled =
-      Shell::Get()->shelf_controller()->model()->in_shelf_party();
-  button_->SetToggled(toggled);
-  button_->SetSubLabel(l10n_util::GetStringUTF16(
-      toggled ? IDS_ASH_STATUS_TRAY_SHELF_PARTY_ON_SUBLABEL
-              : IDS_ASH_STATUS_TRAY_SHELF_PARTY_OFF_SUBLABEL));
-  button_->SetIconAndLabelTooltips(l10n_util::GetStringFUTF16(
-      IDS_ASH_STATUS_TRAY_SHELF_PARTY_TOGGLE_TOOLTIP,
-      l10n_util::GetStringUTF16(
-          toggled ? IDS_ASH_STATUS_TRAY_SHELF_PARTY_ENABLED_STATE_TOOLTIP
-                  : IDS_ASH_STATUS_TRAY_SHELF_PARTY_DISABLED_STATE_TOOLTIP)));
-}
-
-void ShelfPartyFeaturePodController::UpdateTile() {
-  DCHECK(tile_);
-  const bool visible = IsButtonVisible();
-  // If the button's visibility changes from invisible to visible, log its
-  // visibility.
-  if (!tile_->GetVisible() && visible) {
-    TrackVisibilityUMA();
-  }
-  tile_->SetVisible(visible);
-
-  const bool toggled =
-      Shell::Get()->shelf_controller()->model()->in_shelf_party();
-  tile_->SetToggled(toggled);
-  tile_->SetSubLabel(l10n_util::GetStringUTF16(
-      toggled ? IDS_ASH_STATUS_TRAY_SHELF_PARTY_ON_SUBLABEL
-              : IDS_ASH_STATUS_TRAY_SHELF_PARTY_OFF_SUBLABEL));
-  tile_->SetTooltipText(l10n_util::GetStringFUTF16(
-      IDS_ASH_STATUS_TRAY_SHELF_PARTY_TOGGLE_TOOLTIP,
-      l10n_util::GetStringUTF16(
-          toggled ? IDS_ASH_STATUS_TRAY_SHELF_PARTY_ENABLED_STATE_TOOLTIP
-                  : IDS_ASH_STATUS_TRAY_SHELF_PARTY_DISABLED_STATE_TOOLTIP)));
-}
-
-}  // namespace ash
diff --git a/ash/shelf/shelf_party_feature_pod_controller.h b/ash/shelf/shelf_party_feature_pod_controller.h
deleted file mode 100644
index a068a3c..0000000
--- a/ash/shelf/shelf_party_feature_pod_controller.h
+++ /dev/null
@@ -1,60 +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 ASH_SHELF_SHELF_PARTY_FEATURE_POD_CONTROLLER_H_
-#define ASH_SHELF_SHELF_PARTY_FEATURE_POD_CONTROLLER_H_
-
-#include "ash/ash_export.h"
-#include "ash/constants/quick_settings_catalogs.h"
-#include "ash/public/cpp/session/session_observer.h"
-#include "ash/public/cpp/shelf_model_observer.h"
-#include "ash/system/unified/feature_pod_controller_base.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/weak_ptr.h"
-
-namespace ash {
-
-class FeaturePodButton;
-class FeatureTile;
-
-// Controller of a feature pod button that toggles shelf party mode.
-class ASH_EXPORT ShelfPartyFeaturePodController
-    : public FeaturePodControllerBase,
-      public SessionObserver,
-      public ShelfModelObserver {
- public:
-  ShelfPartyFeaturePodController();
-  ShelfPartyFeaturePodController(const ShelfPartyFeaturePodController&) =
-      delete;
-  ShelfPartyFeaturePodController& operator=(
-      const ShelfPartyFeaturePodController&) = delete;
-  ~ShelfPartyFeaturePodController() override;
-
-  // FeaturePodControllerBase:
-  FeaturePodButton* CreateButton() override;
-  std::unique_ptr<FeatureTile> CreateTile(bool compact = false) override;
-  QsFeatureCatalogName GetCatalogName() override;
-  void OnIconPressed() override;
-
-  // SessionObserver:
-  void OnSessionStateChanged(session_manager::SessionState state) override;
-
-  // ShelfModelObserver:
-  void ShelfPartyToggled(bool in_shelf_party) override;
-
- private:
-  void Update();
-  void UpdateButton();
-  void UpdateTile();
-
-  // Owned by the views hierarchy.
-  raw_ptr<FeaturePodButton, ExperimentalAsh> button_ = nullptr;
-  raw_ptr<FeatureTile, ExperimentalAsh> tile_ = nullptr;
-
-  base::WeakPtrFactory<ShelfPartyFeaturePodController> weak_factory_{this};
-};
-
-}  // namespace ash
-
-#endif  // ASH_SHELF_SHELF_PARTY_FEATURE_POD_CONTROLLER_H_
diff --git a/ash/shelf/shelf_party_feature_pod_controller_unittest.cc b/ash/shelf/shelf_party_feature_pod_controller_unittest.cc
deleted file mode 100644
index 7cae504..0000000
--- a/ash/shelf/shelf_party_feature_pod_controller_unittest.cc
+++ /dev/null
@@ -1,126 +0,0 @@
-// 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 "ash/shelf/shelf_party_feature_pod_controller.h"
-
-#include <memory>
-
-#include "ash/constants/ash_features.h"
-#include "ash/public/cpp/shelf_model.h"
-#include "ash/shelf/shelf_controller.h"
-#include "ash/shell.h"
-#include "ash/system/unified/feature_pod_button.h"
-#include "ash/system/unified/feature_tile.h"
-#include "ash/test/ash_test_base.h"
-#include "base/memory/ptr_util.h"
-#include "base/test/scoped_feature_list.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace ash {
-
-// Tests are parameterized by feature QsRevamp.
-class ShelfPartyFeaturePodControllerTest
-    : public AshTestBase,
-      public testing::WithParamInterface<bool> {
- public:
-  ShelfPartyFeaturePodControllerTest() {
-    if (IsQsRevampEnabled()) {
-      feature_list_.InitWithFeatures(
-          {features::kShelfParty, features::kQsRevamp}, {});
-    } else {
-      feature_list_.InitWithFeatures({features::kShelfParty},
-                                     {features::kQsRevamp});
-    }
-  }
-
-  bool IsQsRevampEnabled() const { return GetParam(); }
-
-  // AshTestBase:
-  void TearDown() override {
-    tile_.reset();
-    button_.reset();
-    controller_.reset();
-    AshTestBase::TearDown();
-  }
-
-  void CreateButton() {
-    controller_ = std::make_unique<ShelfPartyFeaturePodController>();
-    if (IsQsRevampEnabled()) {
-      tile_ = controller_->CreateTile();
-    } else {
-      button_ = base::WrapUnique(controller_->CreateButton());
-    }
-  }
-
-  bool IsButtonVisible() {
-    return IsQsRevampEnabled() ? tile_->GetVisible() : button_->GetVisible();
-  }
-
-  bool IsButtonToggled() {
-    return IsQsRevampEnabled() ? tile_->IsToggled() : button_->IsToggled();
-  }
-
-  void PressIcon() { controller_->OnIconPressed(); }
-
- private:
-  base::test::ScopedFeatureList feature_list_;
-  std::unique_ptr<ShelfPartyFeaturePodController> controller_;
-  std::unique_ptr<FeaturePodButton> button_;
-  std::unique_ptr<FeatureTile> tile_;
-};
-
-INSTANTIATE_TEST_SUITE_P(QsRevamp,
-                         ShelfPartyFeaturePodControllerTest,
-                         testing::Bool());
-
-TEST_P(ShelfPartyFeaturePodControllerTest, ButtonVisibility) {
-  auto* session_controller = GetSessionControllerClient();
-  // The button is visible in an active session.
-  CreateButton();
-  EXPECT_TRUE(IsButtonVisible());
-
-  // The button is not visible at the lock screen.
-  session_controller->LockScreen();
-  CreateButton();
-  EXPECT_FALSE(IsButtonVisible());
-
-  // The button is not visible when enterprise managed.
-  session_controller->set_is_enterprise_managed(true);
-  session_controller->SetSessionState(session_manager::SessionState::ACTIVE);
-  CreateButton();
-  EXPECT_FALSE(IsButtonVisible());
-}
-
-TEST_P(ShelfPartyFeaturePodControllerTest, PressIconTogglesShelfParty) {
-  auto* shelf_model = Shell::Get()->shelf_controller()->model();
-  CreateButton();
-  ASSERT_FALSE(shelf_model->in_shelf_party());
-
-  // Pressing the icon enables shelf party.
-  PressIcon();
-  EXPECT_TRUE(shelf_model->in_shelf_party());
-
-  // Pressing the icon again disables shelf party.
-  PressIcon();
-  EXPECT_FALSE(shelf_model->in_shelf_party());
-}
-
-TEST_P(ShelfPartyFeaturePodControllerTest, ShelfPartyToggled) {
-  auto* shelf_model = Shell::Get()->shelf_controller()->model();
-  CreateButton();
-  ASSERT_FALSE(shelf_model->in_shelf_party());
-  EXPECT_FALSE(IsButtonToggled());
-
-  // Toggles the shelf party from `shelf_model` to enable shelf party.
-  shelf_model->ToggleShelfParty();
-  EXPECT_TRUE(shelf_model->in_shelf_party());
-  EXPECT_TRUE(IsButtonToggled());
-
-  // Toggles again to disable shelf party.
-  shelf_model->ToggleShelfParty();
-  EXPECT_FALSE(shelf_model->in_shelf_party());
-  EXPECT_FALSE(IsButtonToggled());
-}
-
-}  // namespace ash
diff --git a/ash/shelf/shelf_unittest.cc b/ash/shelf/shelf_unittest.cc
index 2c2ce69..a0d4817 100644
--- a/ash/shelf/shelf_unittest.cc
+++ b/ash/shelf/shelf_unittest.cc
@@ -14,7 +14,6 @@
 #include "ash/shelf/shelf_app_button.h"
 #include "ash/shelf/shelf_controller.h"
 #include "ash/shelf/shelf_layout_manager.h"
-#include "ash/shelf/shelf_party_feature_pod_controller.h"
 #include "ash/shelf/shelf_view.h"
 #include "ash/shelf/shelf_view_test_api.h"
 #include "ash/shelf/shelf_widget.h"
diff --git a/ash/system/unified/power_button_pixeltest.cc b/ash/system/unified/power_button_pixeltest.cc
index 64585c9d..e3229b3e 100644
--- a/ash/system/unified/power_button_pixeltest.cc
+++ b/ash/system/unified/power_button_pixeltest.cc
@@ -61,8 +61,8 @@
 
 TEST_F(PowerButtonPixelTest, NoSession) {
   EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
-      "check_button",
-      /*revision_number=*/1, GetPowerButton()));
+      "check_power_button",
+      /*revision_number=*/2, GetPowerButton()));
 
   SimulatePowerButtonPress();
   EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
diff --git a/ash/system/unified/unified_system_tray_controller.cc b/ash/system/unified/unified_system_tray_controller.cc
index e45c5dc..9d26c8f 100644
--- a/ash/system/unified/unified_system_tray_controller.cc
+++ b/ash/system/unified/unified_system_tray_controller.cc
@@ -16,7 +16,6 @@
 #include "ash/public/cpp/system_tray_client.h"
 #include "ash/public/cpp/update_types.h"
 #include "ash/session/session_controller_impl.h"
-#include "ash/shelf/shelf_party_feature_pod_controller.h"
 #include "ash/shell.h"
 #include "ash/system/accessibility/accessibility_feature_pod_controller.h"
 #include "ash/system/accessibility/unified_accessibility_detailed_view_controller.h"
@@ -706,9 +705,6 @@
   AddFeaturePodItem(std::make_unique<IMEFeaturePodController>(this));
   AddFeaturePodItem(std::make_unique<LocaleFeaturePodController>(this));
   AddFeaturePodItem(std::make_unique<DarkModeFeaturePodController>(this));
-  if (base::FeatureList::IsEnabled(features::kShelfParty)) {
-    AddFeaturePodItem(std::make_unique<ShelfPartyFeaturePodController>());
-  }
   if (media::ShouldEnableAutoFraming()) {
     AddFeaturePodItem(std::make_unique<AutozoomFeaturePodController>());
   }
@@ -776,11 +772,6 @@
   }
   create_tile(std::make_unique<VPNFeaturePodController>(this),
               feature_pod_controllers_, tiles);
-
-  if (base::FeatureList::IsEnabled(features::kShelfParty)) {
-    create_tile(std::make_unique<ShelfPartyFeaturePodController>(),
-                feature_pod_controllers_, tiles);
-  }
   create_tile(std::make_unique<PrivacyScreenFeaturePodController>(),
               feature_pod_controllers_, tiles);
 
diff --git a/ash/webui/file_manager/resources/labs/labs.html b/ash/webui/file_manager/resources/labs/labs.html
index 95d31c8..7e13f34 100644
--- a/ash/webui/file_manager/resources/labs/labs.html
+++ b/ash/webui/file_manager/resources/labs/labs.html
@@ -10,6 +10,7 @@
   <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
   <link rel="stylesheet" href="chrome://resources/chromeos/colors/cros_styles.css">
   <link rel="stylesheet" href="chrome://theme/colors.css?sets=legacy,sys">
+  <link rel="stylesheet" href="chrome://theme/typography.css">
   <style>
     body {
       background-color: var(--cros-bg-color);
@@ -55,6 +56,14 @@
       text-decoration: underline;
     }
 
+    [theme='legacy'] iron-icon {
+      padding: 6px;
+    }
+
+    [theme='refresh23'] iron-icon {
+      padding: 10px;
+    }
+
   </style>
 
   <script type="module" src="./main.js"></script>
@@ -75,13 +84,22 @@
         <xf-tree-item label="Level 1 (2 children)" icon="my_files">
           <xf-tree-item label="Level 1.1 (2 children)" icon="downloads">
             <xf-tree-item label="Level 1.1.1 (no children)" selected icon="camera-folder"></xf-tree-item>
-            <xf-tree-item label="Level 1.1.2 (no children)" disabled icon="usb"></xf-tree-item>
+            <xf-tree-item label="Level 1.1.2 (no children)" disabled icon="invalid_type"></xf-tree-item>
           </xf-tree-item>
-          <xf-tree-item label="Level 1.2 (no children)" icon="folder"></xf-tree-item>
+          <xf-tree-item label="Level 1.2 (no children)" icon="folder" renaming>
+            <input type="text" slot="rename">
+          </xf-tree-item>
         </xf-tree-item>
         <xf-tree-item label="Level 2 (may have children)" may-have-children separator icon="smb"></xf-tree-item>
-        <xf-tree-item label="Level 3 (no children)">
-          <span class="trailing-icon" tabindex="0" slot="trailingIcon">X</span>
+        <xf-tree-item label="Level 3 (no children)" icon="usb">
+          <cr-button class="root-eject align-right-icon" tabindex="0" slot="trailingIcon">
+            <iron-icon icon="files20:eject"></iron-icon>
+          </cr-button>
+        </xf-tree-item>
+        <xf-tree-item label="Level 4 (no children)" icon="usb">
+          <span class="external-link-icon align-right-icon" slot="trailingIcon">
+            <iron-icon icon="files20:external-link"></iron-icon>
+          </span>
         </xf-tree-item>
       </xf-tree>
     </div>
@@ -98,13 +116,22 @@
         <xf-tree-item label="Level 1 (2 children)" icon="my_files">
           <xf-tree-item label="Level 1.1 (2 children)" icon="downloads">
             <xf-tree-item label="Level 1.1.1 (no children)" selected icon="camera-folder"></xf-tree-item>
-            <xf-tree-item label="Level 1.1.2 (no children)" disabled icon="usb"></xf-tree-item>
+            <xf-tree-item label="Level 1.1.2 (no children)" disabled icon="invalid_type"></xf-tree-item>
           </xf-tree-item>
-          <xf-tree-item label="Level 1.2 (no children)" icon="folder"></xf-tree-item>
+          <xf-tree-item label="Level 1.2 (no children)" icon="folder" renaming>
+            <input type="text" slot="rename">
+          </xf-tree-item>
         </xf-tree-item>
         <xf-tree-item label="Level 2 (may have children)" may-have-children separator icon="smb"></xf-tree-item>
-        <xf-tree-item label="Level 3 (no children)" icon="invalid_type">
-          <span class="trailing-icon" tabindex="0" slot="trailingIcon">X</span>
+        <xf-tree-item label="Level 3 (no children)" icon="usb">
+          <cr-button class="root-eject align-right-icon" tabindex="0" slot="trailingIcon">
+            <iron-icon icon="files20:eject"></iron-icon>
+          </cr-button>
+        </xf-tree-item>
+        <xf-tree-item label="Level 4 (no children)" icon="usb">
+          <span class="external-link-icon align-right-icon" slot="trailingIcon">
+            <iron-icon icon="files20:external-link"></iron-icon>
+          </span>
         </xf-tree-item>
       </xf-tree>
     </div>
diff --git a/ash/webui/file_manager/resources/labs/main.ts b/ash/webui/file_manager/resources/labs/main.ts
index 7baf4b9..0ecae2c 100644
--- a/ash/webui/file_manager/resources/labs/main.ts
+++ b/ash/webui/file_manager/resources/labs/main.ts
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'chrome://file-manager/foreground/elements/icons.js';
 import 'chrome://file-manager/widgets/xf_breadcrumb.js';
 import 'chrome://file-manager/widgets/xf_icon.js';
 import 'chrome://file-manager/widgets/xf_tree.js';
 import 'chrome://file-manager/widgets/xf_tree_item.js';
+import 'chrome://resources/cr_elements/cr_button/cr_button.js';
+import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
 
 import {FocusOutlineManager} from 'chrome://resources/js/focus_outline_manager.js';
 
diff --git a/ash/wm/drag_window_controller.cc b/ash/wm/drag_window_controller.cc
index f841611..f94adc7 100644
--- a/ash/wm/drag_window_controller.cc
+++ b/ash/wm/drag_window_controller.cc
@@ -127,7 +127,7 @@
     // be modified so that it can optionally be clipped to the main window's
     // bounds.
     widget_->SetContentsView(std::make_unique<WindowMirrorView>(
-        original_window, /*show_non_client_view=*/true));
+        original_window, /*show_non_client_view=*/true, /*sync_bounds=*/true));
 
     aura::Window* window = widget_->GetNativeWindow();
     window->SetId(kShellWindowId_PhantomWindow);
diff --git a/ash/wm/window_mirror_view.cc b/ash/wm/window_mirror_view.cc
index e482c85..522b1901 100644
--- a/ash/wm/window_mirror_view.cc
+++ b/ash/wm/window_mirror_view.cc
@@ -32,8 +32,11 @@
 }  // namespace
 
 WindowMirrorView::WindowMirrorView(aura::Window* source,
-                                   bool show_non_client_view)
-    : source_(source), show_non_client_view_(show_non_client_view) {
+                                   bool show_non_client_view,
+                                   bool sync_bounds)
+    : source_(source),
+      show_non_client_view_(show_non_client_view),
+      sync_bounds_(sync_bounds) {
   source_->AddObserver(this);
   DCHECK(source);
 }
@@ -127,7 +130,7 @@
 }
 
 void WindowMirrorView::InitLayerOwner() {
-  layer_owner_ = wm::MirrorLayers(source_, /*sync_bounds=*/false);
+  layer_owner_ = wm::MirrorLayers(source_, sync_bounds_);
   layer_owner_->root()->SetOpacity(1.f);
 
   SetPaintToLayer();
diff --git a/ash/wm/window_mirror_view.h b/ash/wm/window_mirror_view.h
index 36f51dd..f9553f1 100644
--- a/ash/wm/window_mirror_view.h
+++ b/ash/wm/window_mirror_view.h
@@ -28,7 +28,8 @@
                                     public aura::WindowObserver {
  public:
   explicit WindowMirrorView(aura::Window* source,
-                            bool show_non_client_view = false);
+                            bool show_non_client_view = false,
+                            bool sync_bounds = false);
 
   WindowMirrorView(const WindowMirrorView&) = delete;
   WindowMirrorView& operator=(const WindowMirrorView&) = delete;
@@ -79,6 +80,9 @@
   // If true, shows the non client view in the mirror.
   const bool show_non_client_view_;
 
+  // If true, synchronize the bounds from the source to the mirrored layers.
+  const bool sync_bounds_;
+
   std::unique_ptr<aura::WindowOcclusionTracker::ScopedForceVisible>
       force_occlusion_tracker_visible_;
 };
diff --git a/build/PRESUBMIT.py b/build/PRESUBMIT.py
index 41872491..c6cc1ccd 100644
--- a/build/PRESUBMIT.py
+++ b/build/PRESUBMIT.py
@@ -4,10 +4,6 @@
 
 PRESUBMIT_VERSION = '2.0.0'
 
-# This line is 'magic' in that git-cl looks for it to decide whether to
-# use Python3 instead of Python2 when running the code in this file.
-USE_PYTHON3 = True
-
 import textwrap
 
 
diff --git a/build/PRESUBMIT_test.py b/build/PRESUBMIT_test.py
index c5065f4..c39c19c 100755
--- a/build/PRESUBMIT_test.py
+++ b/build/PRESUBMIT_test.py
@@ -14,7 +14,6 @@
 from PRESUBMIT_test_mocks import MockAffectedFile
 from PRESUBMIT_test_mocks import MockInputApi, MockOutputApi
 
-USE_PYTHON3 = True
 
 
 def _fails_deps_check(line, filename='BUILD.gn'):
diff --git a/build/android/PRESUBMIT.py b/build/android/PRESUBMIT.py
index 8348558..08f6ec5 100644
--- a/build/android/PRESUBMIT.py
+++ b/build/android/PRESUBMIT.py
@@ -8,7 +8,6 @@
 details on the presubmit API built into depot_tools.
 """
 
-USE_PYTHON3 = True
 
 
 def CommonChecks(input_api, output_api):
diff --git a/build/android/gyp/bytecode_processor.py b/build/android/gyp/bytecode_processor.py
index ea9470c..868f31b 100755
--- a/build/android/gyp/bytecode_processor.py
+++ b/build/android/gyp/bytecode_processor.py
@@ -19,10 +19,6 @@
 from util import server_utils
 import action_helpers  # build_utils adds //build to sys.path.
 
-_SRC_PATH = pathlib.Path(build_utils.DIR_SOURCE_ROOT).resolve()
-sys.path.append(str(_SRC_PATH / 'tools/android/modularization/gn'))
-from dep_operations import NO_VALID_GN_STR
-
 
 def _ShouldIgnoreDep(dep_name: str):
   if 'gen.base_module.R' in dep_name:
@@ -73,24 +69,12 @@
   return os.path.join(ninja_target_name, 'BUILD.gn')
 
 
-def _EnsureDirectClasspathIsComplete(
-    *,
-    input_jar: str,
-    gn_target: str,
-    output_dir: str,
-    sdk_classpath_jars: List[str],
-    direct_classpath_jars: List[str],
-    full_classpath_jars: List[str],
-    full_classpath_gn_targets: List[str],
-    warnings_as_errors: bool,
-):
-  logging.info('Parsing %d direct classpath jars', len(sdk_classpath_jars))
-  sdk_classpath_deps = set()
-  for jar in sdk_classpath_jars:
-    deps = jar_utils.extract_full_class_names_from_jar(
-        build_output_dir=pathlib.Path(output_dir), jar_path=pathlib.Path(jar))
-    sdk_classpath_deps.update(deps)
-
+def _EnsureDirectClasspathIsComplete(*, input_jar: str, gn_target: str,
+                                     output_dir: str,
+                                     direct_classpath_jars: List[str],
+                                     full_classpath_jars: List[str],
+                                     full_classpath_gn_targets: List[str],
+                                     warnings_as_errors: bool):
   logging.info('Parsing %d direct classpath jars', len(direct_classpath_jars))
   direct_classpath_deps = set()
   for jar in direct_classpath_jars:
@@ -116,9 +100,7 @@
   # dep_graph.keys() is a list of all the classes in the current input_jar. Skip
   # all of these to avoid checking dependencies in the same target (e.g. A
   # depends on B, but both A and B are in input_jar).
-  # Since the bundle will always have access to classes in the current android
-  # sdk, those should not be considered missing.
-  seen_deps = set(dep_graph.keys()) | sdk_classpath_deps
+  seen_deps = set(dep_graph.keys())
   for dep_from, deps_to in dep_graph.items():
     for dep_to in deps_to - seen_deps:
       if _ShouldIgnoreDep(dep_to):
@@ -129,46 +111,27 @@
         missing_targets[missing_target_names][dep_to] = dep_from
 
   if missing_targets:
-
-    def print_and_maybe_exit():
-      print('=' * 30 + ' Dependency Checks Failed ' + '=' * 30)
-      print(f'Target: {gn_target}')
-      print('Direct classpath is incomplete. To fix, add deps on:')
-      for missing_target_names, data in missing_targets.items():
-        if len(missing_target_names) > 1:
-          print(f' * One of {", ".join(missing_target_names)}')
-        else:
-          print(f' * {missing_target_names[0]}')
-        for missing_class, used_by in data.items():
-          print(f'     ** {missing_class} (needed by {used_by})')
-      if warnings_as_errors:
-        sys.exit(1)
-
-    # TODO(https://crbug.com/1099522): This is better as a GN arg.
-    if os.environ.get('AUTO_ADD_MISSING_DEPS') != '1':
-      print_and_maybe_exit()
-    else:
-      # TODO(https://crbug.com/1099522): This should be generalized into util.
-      build_file_path = _GnTargetToBuildFilePath(gn_target)
+    print('=' * 30 + ' Dependency Checks Failed ' + '=' * 30)
+    print(f'Target: {gn_target}')
+    print('Direct classpath is incomplete. To fix, add deps on:')
+    for missing_target_names, data in missing_targets.items():
+      if len(missing_target_names) > 1:
+        print(f' * One of {", ".join(missing_target_names)}')
+      else:
+        print(f' * {missing_target_names[0]}')
+      for missing_class, used_by in data.items():
+        print(f'     ** {missing_class} (needed by {used_by})')
+    if os.environ.get('AUTO_ADD_MISSING_DEPS') == '1':
       cmd = [
           'tools/android/modularization/gn/dep_operations.py', 'add', '--quiet',
-          '--file', build_file_path, '--target', gn_target, '--deps'
+          '--file',
+          _GnTargetToBuildFilePath(gn_target), '--target', gn_target, '--deps'
       ]
       # For simplicity, always pick the first suggested target.
-      # TODO(https://crbug.com/1099522): Swap deps with preferred deps.
-      missing_deps = [names[0] for names in missing_targets.keys()]
-      cmd += missing_deps
-      try:
-        build_utils.CheckOutput(cmd, cwd=build_utils.DIR_SOURCE_ROOT)
-      except build_utils.CalledProcessError as e:
-        if NO_VALID_GN_STR in e.output:
-          print(f'Unable to add missing dep(s) to {build_file_path}.')
-          print_and_maybe_exit()
-        else:
-          raise
-      else:
-        print(f'Successfully updated {build_file_path} with missing direct '
-              f'deps: {missing_deps}')
+      cmd += [names[0] for names in missing_targets.keys()]
+      build_utils.CheckOutput(cmd, cwd=build_utils.DIR_SOURCE_ROOT)
+    if warnings_as_errors:
+      sys.exit(1)
 
 
 def _AddSwitch(parser, val):
@@ -232,7 +195,6 @@
         input_jar=args.input_jar,
         gn_target=args.gn_target,
         output_dir=args.chromium_output_dir,
-        sdk_classpath_jars=args.sdk_classpath_jars,
         direct_classpath_jars=args.direct_classpath_jars,
         full_classpath_jars=args.full_classpath_jars,
         full_classpath_gn_targets=args.full_classpath_gn_targets,
diff --git a/build/android/gyp/bytecode_processor.pydeps b/build/android/gyp/bytecode_processor.pydeps
index 1e6956a..a0ba450a 100644
--- a/build/android/gyp/bytecode_processor.pydeps
+++ b/build/android/gyp/bytecode_processor.pydeps
@@ -16,12 +16,6 @@
 ../../../third_party/colorama/src/colorama/win32.py
 ../../../third_party/colorama/src/colorama/winterm.py
 ../../../tools/android/modularization/convenience/lookup_dep.py
-../../../tools/android/modularization/gn/dep_operations.py
-../../../tools/android/modularization/gn/json_gn_editor.py
-../../../tools/android/modularization/gn/utils.py
-../../../tools/android/python_utils/__init__.py
-../../../tools/android/python_utils/git_metadata_utils.py
-../../../tools/android/python_utils/subprocess_utils.py
 ../../action_helpers.py
 ../../gn_helpers.py
 ../list_java_targets.py
diff --git a/build/chromeos/PRESUBMIT.py b/build/chromeos/PRESUBMIT.py
index b9734e6..61ba20b 100644
--- a/build/chromeos/PRESUBMIT.py
+++ b/build/chromeos/PRESUBMIT.py
@@ -8,7 +8,6 @@
 """
 
 
-USE_PYTHON3 = True
 
 
 def CommonChecks(input_api, output_api):
diff --git a/build/config/clang/clang.gni b/build/config/clang/clang.gni
index e295a25..0de9792 100644
--- a/build/config/clang/clang.gni
+++ b/build/config/clang/clang.gni
@@ -16,7 +16,7 @@
 
   enable_check_raw_ptr_fields =
       build_with_chromium && !is_official_build &&
-      ((is_linux && !is_castos) || (is_android && !is_cast_android) || is_win)
+      ((is_linux && !is_castos) || (is_android && !is_cast_android))
 
   clang_base_path = default_clang_base_path
 
diff --git a/build/config/siso/config.star b/build/config/siso/config.star
new file mode 100644
index 0000000..e64ba22
--- /dev/null
+++ b/build/config/siso/config.star
@@ -0,0 +1,30 @@
+# -*- bazel-starlark -*-
+# 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.
+"""Config module for checking siso -config flags."""
+
+load("@builtin//struct.star", "module")
+
+__KNOWN_CONFIG_OPTIONS = [
+    "rewrapper_to_reproxy",
+]
+
+def __check(ctx):
+    if "config" in ctx.flags:
+        for cfg in ctx.flags["config"].split(","):
+            if cfg not in __KNOWN_CONFIG_OPTIONS:
+                print("unknown config: %s" % cfg)
+
+def __get(ctx, key):
+    if "config" in ctx.flags:
+        for cfg in ctx.flags["config"].split(","):
+            if cfg == key:
+                return True
+    return False
+
+config = module(
+    "config",
+    check = __check,
+    get = __get,
+)
diff --git a/build/config/siso/linux.star b/build/config/siso/linux.star
index d02318e..5e2fe0f 100644
--- a/build/config/siso/linux.star
+++ b/build/config/siso/linux.star
@@ -6,9 +6,11 @@
 
 load("@builtin//struct.star", "module")
 load("./clang_linux.star", "clang")
+load("./config.star", "config")
 load("./mojo.star", "mojo")
 load("./nacl_linux.star", "nacl")
 load("./remote_exec_wrapper.star", "remote_exec_wrapper")
+load("./rewrapper_to_reproxy.star", "rewrapper_to_reproxy")
 
 __filegroups = {}
 __filegroups.update(clang.filegroups)
@@ -19,15 +21,21 @@
 __handlers.update(clang.handlers)
 __handlers.update(mojo.handlers)
 __handlers.update(nacl.handlers)
+__handlers.update(remote_exec_wrapper.handlers)
+__handlers.update(rewrapper_to_reproxy.handlers)
 
 def __step_config(ctx, step_config):
+    config.check(ctx)
     step_config["platforms"] = {
         "default": {
             "OSFamily": "Linux",
             "container-image": "docker://gcr.io/chops-private-images-prod/rbe/siso-chromium/linux@sha256:d4fcda628ebcdb3dd79b166619c56da08d5d7bd43d1a7b1f69734904cc7a1bb2",
         },
     }
-    if remote_exec_wrapper.enabled(ctx):
+    # rewrapper_to_reproxy takes precedence over remote exec wrapper handler if enabled.
+    if rewrapper_to_reproxy.enabled(ctx):
+        step_config = rewrapper_to_reproxy.step_config(ctx, step_config)
+    elif remote_exec_wrapper.enabled(ctx):
         step_config = remote_exec_wrapper.step_config(ctx, step_config)
     else:
         step_config = clang.step_config(ctx, step_config)
diff --git a/build/config/siso/mac.star b/build/config/siso/mac.star
index 7a638b9d3..2bd6a4b 100644
--- a/build/config/siso/mac.star
+++ b/build/config/siso/mac.star
@@ -11,6 +11,8 @@
 __handlers = {}
 
 def __step_config(ctx, step_config):
+    # TODO(b/273407069): Handle reproxy mode.
+    config.check(ctx)
     if remote_exec_wrapper.enabled(ctx):
         step_config = remote_exec_wrapper.step_config(ctx, step_config)
     return step_config
diff --git a/build/config/siso/rewrapper_to_reproxy.star b/build/config/siso/rewrapper_to_reproxy.star
new file mode 100644
index 0000000..a048d646
--- /dev/null
+++ b/build/config/siso/rewrapper_to_reproxy.star
@@ -0,0 +1,76 @@
+# -*- bazel-starlark -*-
+# 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.
+"""Siso configuration for rewriting remote exec wrapper calls into reproxy config."""
+
+load("@builtin//lib/gn.star", "gn")
+load("@builtin//struct.star", "module")
+load("./config.star", "config")
+
+__filegroups = {}
+
+def __remove_rewrapper(ctx, cmd):
+    # Slice from the first non-arg passed to rewrapper.
+    # (Whilst rewrapper usage is `rewrapper [-flags] -- command ...` we don't pass -- to rewrapper.)
+    non_flag_start = -1
+    for i, arg in enumerate(cmd.args):
+        if i == 0:
+            continue
+        if not arg.startswith('-'):
+            non_flag_start = i
+            break
+    if non_flag_start < 1:
+        fail("couldn't find first non-arg passed to rewrapper")
+    ctx.actions.fix(
+        args = cmd.args[non_flag_start:],
+    )
+
+__handlers = {
+    "remove_rewrapper": __remove_rewrapper,
+}
+
+def __enabled(ctx):
+    if config.get(ctx, "rewrapper_to_reproxy") and "args.gn" in ctx.metadata:
+        gn_args = gn.parse_args(ctx.metadata["args.gn"])
+        if gn_args.get("use_remoteexec") == "true":
+            return True
+    return False
+
+def __step_config(ctx, step_config):
+    # TODO(b/273407069): Read reproxy config from config files.
+    step_config["rules"].extend([
+        {
+            "name": "clang/cxx",
+            "action": "(.*_)?cxx",
+            "handler": "remove_rewrapper",
+            "reproxy_config": {"labels": {"type": "compile", "compiler": "clang", "lang": "cpp"}},
+        },
+        {
+            "name": "clang/cc",
+            "action": "(.*_)?cc",
+            "handler": "remove_rewrapper",
+            "reproxy_config": {"labels": {"type": "compile", "compiler": "clang", "lang": "cpp"}},
+        },
+        {
+            "name": "clang/objcxx",
+            "action": "(.*_)?objcxx",
+            "handler": "remove_rewrapper",
+            "reproxy_config": {"labels": {"type": "compile", "compiler": "clang", "lang": "cpp"}},
+        },
+        {
+            "name": "clang/objc",
+            "action": "(.*_)?objc",
+            "handler": "remove_rewrapper",
+            "reproxy_config": {"labels": {"type": "compile", "compiler": "clang", "lang": "cpp"}},
+        },
+    ])
+    return step_config
+
+rewrapper_to_reproxy = module(
+    "rewrapper_to_reproxy",
+    enabled = __enabled,
+    step_config = __step_config,
+    filegroups = __filegroups,
+    handlers = __handlers,
+)
diff --git a/build/config/siso/windows.star b/build/config/siso/windows.star
index 88636f7..f2f6bf0 100644
--- a/build/config/siso/windows.star
+++ b/build/config/siso/windows.star
@@ -11,6 +11,8 @@
 __handlers = {}
 
 def __step_config(ctx, step_config):
+    # TODO(b/273407069): Handle reproxy mode.
+    config.check(ctx)
     if remote_exec_wrapper.enabled(ctx):
         step_config = remote_exec_wrapper.step_config(ctx, step_config)
     return step_config
diff --git a/build/fuchsia/PRESUBMIT.py b/build/fuchsia/PRESUBMIT.py
index f42f4c2..1c0222a1 100644
--- a/build/fuchsia/PRESUBMIT.py
+++ b/build/fuchsia/PRESUBMIT.py
@@ -7,7 +7,6 @@
 details on the presubmit API built into depot_tools.
 """
 
-USE_PYTHON3 = True
 
 import os
 
diff --git a/build/fuchsia/test/PRESUBMIT.py b/build/fuchsia/test/PRESUBMIT.py
index fc5dcfe..076d1b0 100644
--- a/build/fuchsia/test/PRESUBMIT.py
+++ b/build/fuchsia/test/PRESUBMIT.py
@@ -7,7 +7,6 @@
 for more details about the presubmit API built into depot_tools.
 """
 
-USE_PYTHON3 = True
 
 _EXTRA_PATHS_COMPONENTS = [('testing', )]
 
diff --git a/build/ios/PRESUBMIT.py b/build/ios/PRESUBMIT.py
index 0c7a355..f737a7e 100644
--- a/build/ios/PRESUBMIT.py
+++ b/build/ios/PRESUBMIT.py
@@ -4,7 +4,6 @@
 
 PRESUBMIT_VERSION = '2.0.0'
 
-USE_PYTHON3 = True
 
 TEST_PATTERNS = [r'.+_test.py$']
 
diff --git a/build/lacros/PRESUBMIT.py b/build/lacros/PRESUBMIT.py
index 642ee7e..13d3423 100644
--- a/build/lacros/PRESUBMIT.py
+++ b/build/lacros/PRESUBMIT.py
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 """Presubmit script for changes affecting //build/lacros"""
 
-USE_PYTHON3 = True
 
 
 def _CommonChecks(input_api, output_api):
diff --git a/build/skia_gold_common/PRESUBMIT.py b/build/skia_gold_common/PRESUBMIT.py
index f3cc772d..14ea488 100644
--- a/build/skia_gold_common/PRESUBMIT.py
+++ b/build/skia_gold_common/PRESUBMIT.py
@@ -7,7 +7,6 @@
 for more details on the presubmit API built into depot_tools.
 """
 
-USE_PYTHON3 = True
 
 PRESUBMIT_VERSION = '2.0.0'
 
diff --git a/build/util/PRESUBMIT.py b/build/util/PRESUBMIT.py
index 88fd9bf..bac696bb 100644
--- a/build/util/PRESUBMIT.py
+++ b/build/util/PRESUBMIT.py
@@ -6,7 +6,6 @@
 """Presubmit for build/util"""
 
 
-USE_PYTHON3 = True
 
 
 def _GetFilesToSkip(input_api):
diff --git a/build/util/lib/common/PRESUBMIT.py b/build/util/lib/common/PRESUBMIT.py
index b0477fd5..5c92f3ce 100644
--- a/build/util/lib/common/PRESUBMIT.py
+++ b/build/util/lib/common/PRESUBMIT.py
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 
 
-USE_PYTHON3 = True
 
 
 def _RunTests(input_api, output_api):
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index 313eff5..4018eb4 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -2114,6 +2114,9 @@
     // Attempt to re-use an existing PaintRecord if possible.
     new_records[input] = std::make_pair(
         paint_image_id, std::move(paint_worklet_records_[input].second));
+    // The move constructor of absl::optional does not clear the source to
+    // nullopt.
+    paint_worklet_records_[input].second = absl::nullopt;
   }
   paint_worklet_records_.swap(new_records);
 
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index d0891de..32d7762 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -6260,6 +6260,37 @@
   EXPECT_TRUE(pending_layer()->GetPaintWorkletRecordMap().contains(input3));
 }
 
+TEST_F(LegacySWPictureLayerImplTest, PaintWorkletInputsIdenticalEntries) {
+  gfx::Size layer_bounds(1000, 1000);
+
+  auto recording_source = FakeRecordingSource::CreateRecordingSource(
+      gfx::Rect(layer_bounds), layer_bounds);
+  scoped_refptr<TestPaintWorkletInput> input =
+      base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(100, 100));
+  PaintImage image = CreatePaintWorkletPaintImage(input);
+  recording_source->add_draw_image(image, gfx::Point(100, 100));
+  recording_source->add_draw_image(image, gfx::Point(100, 100));
+  recording_source->Rerecord();
+
+  // All inputs should be registered on the pending layer.
+  SetupPendingTree(recording_source->CreateRasterSource(), gfx::Size(),
+                   Region(gfx::Rect(layer_bounds)));
+  EXPECT_EQ(pending_layer()->GetPaintWorkletRecordMap().size(), 1u);
+  EXPECT_TRUE(pending_layer()->GetPaintWorkletRecordMap().contains(input));
+
+  PaintRecord record;
+  pending_layer()->SetPaintWorkletRecord(input, record);
+  pending_layer()->picture_layer_tiling_set()->RemoveAllTiles();
+  recording_source->Rerecord();
+  pending_layer()->SetRasterSource(recording_source->CreateRasterSource(),
+                                   Region());
+  EXPECT_EQ(pending_layer()->GetPaintWorkletRecordMap().size(), 1u);
+  auto it = pending_layer()->GetPaintWorkletRecordMap().find(input);
+  ASSERT_NE(it, pending_layer()->GetPaintWorkletRecordMap().end());
+  // For now the paint record is cleared for multiple identical inputs.
+  EXPECT_FALSE(it->second.second.has_value());
+}
+
 TEST_F(LegacySWPictureLayerImplTest, NoTilingsUsesScaleOne) {
   auto render_pass = viz::CompositorRenderPass::Create();
 
diff --git a/cc/metrics/compositor_timing_history.cc b/cc/metrics/compositor_timing_history.cc
index 575eba92..86b60acf 100644
--- a/cc/metrics/compositor_timing_history.cc
+++ b/cc/metrics/compositor_timing_history.cc
@@ -32,12 +32,6 @@
   virtual void AddBeginImplFrameLatency(base::TimeDelta delta) = 0;
   virtual void AddDrawDuration(base::TimeDelta duration) = 0;
 
-  // crbug.com/758439: the following functions are used to report timing in
-  // certain conditions targeting blink / compositor animations.
-  // Only the renderer would get the meaningful data.
-  virtual void AddDrawIntervalWithCustomPropertyAnimations(
-      base::TimeDelta duration) = 0;
-
   virtual void AddImplFrameDeadlineType(
       CompositorTimingHistory::DeadlineMode deadline_mode) = 0;
 };
@@ -329,13 +323,6 @@
                                              interval);
   }
 
-  void AddDrawIntervalWithCustomPropertyAnimations(
-      base::TimeDelta interval) override {
-    UMA_HISTOGRAM_CUSTOM_TIMES_VSYNC_ALIGNED(
-        "Scheduling.Renderer.DrawIntervalWithCustomPropertyAnimations",
-        interval);
-  }
-
   void AddBeginImplFrameLatency(base::TimeDelta delta) override {
     UMA_HISTOGRAM_CUSTOM_TIMES_DURATION(
         "Scheduling.Renderer.BeginImplFrameLatency", delta);
@@ -361,9 +348,6 @@
   // browser rendering fps is not at 60.
   void AddDrawInterval(base::TimeDelta interval) override {}
 
-  void AddDrawIntervalWithCustomPropertyAnimations(
-      base::TimeDelta interval) override {}
-
   void AddBeginImplFrameLatency(base::TimeDelta delta) override {
     UMA_HISTOGRAM_CUSTOM_TIMES_DURATION(
         "Scheduling.Browser.BeginImplFrameLatency", delta);
@@ -385,8 +369,6 @@
  public:
   ~NullUMAReporter() override = default;
   void AddDrawInterval(base::TimeDelta interval) override {}
-  void AddDrawIntervalWithCustomPropertyAnimations(
-      base::TimeDelta inverval) override {}
   void AddBeginImplFrameLatency(base::TimeDelta delta) override {}
   void AddDrawDuration(base::TimeDelta duration) override {}
   void AddImplFrameDeadlineType(
@@ -771,8 +753,7 @@
   draw_start_time_ = Now();
 }
 
-void CompositorTimingHistory::DidDraw(bool used_new_active_tree,
-                                      bool has_custom_property_animations) {
+void CompositorTimingHistory::DidDraw() {
   DCHECK_NE(base::TimeTicks(), draw_start_time_);
   base::TimeTicks draw_end_time = Now();
   base::TimeDelta draw_duration = draw_end_time - draw_start_time_;
@@ -807,16 +788,9 @@
           draw_end_time);
       g_num_long_draw_intervals++;
     }
-    if (has_custom_property_animations &&
-        previous_frame_had_custom_property_animations_)
-      uma_reporter_->AddDrawIntervalWithCustomPropertyAnimations(draw_interval);
   }
-  previous_frame_had_custom_property_animations_ =
-      has_custom_property_animations;
   draw_end_time_prev_ = draw_end_time;
 
-  if (used_new_active_tree)
-    new_active_tree_draw_end_time_prev_ = draw_end_time;
   draw_start_time_ = base::TimeTicks();
 }
 
diff --git a/cc/metrics/compositor_timing_history.h b/cc/metrics/compositor_timing_history.h
index 8eb87e84..bc06c40 100644
--- a/cc/metrics/compositor_timing_history.h
+++ b/cc/metrics/compositor_timing_history.h
@@ -83,8 +83,7 @@
   void WillActivate();
   void DidActivate();
   void WillDraw();
-  void DidDraw(bool used_new_active_tree,
-               bool has_custom_property_animations);
+  void DidDraw();
   void WillInvalidateOnImplSide();
 
   // Record the scheduler's deadline mode and send to UMA.
@@ -112,7 +111,6 @@
 
   // Used to calculate frame rates of Main and Impl threads.
   bool compositor_drawing_continuously_;
-  base::TimeTicks new_active_tree_draw_end_time_prev_;
   base::TimeTicks draw_end_time_prev_;
 
   // If you add any history here, please remember to reset it in
@@ -169,9 +167,6 @@
 
   // Owned by LayerTreeHost and is destroyed when LayerTreeHost is destroyed.
   raw_ptr<RenderingStatsInstrumentation> rendering_stats_instrumentation_;
-
-  // Used only for reporting animation targeted UMA.
-  bool previous_frame_had_custom_property_animations_ = false;
 };
 
 }  // namespace cc
diff --git a/cc/metrics/compositor_timing_history_unittest.cc b/cc/metrics/compositor_timing_history_unittest.cc
index 6018064..f6853ffc 100644
--- a/cc/metrics/compositor_timing_history_unittest.cc
+++ b/cc/metrics/compositor_timing_history_unittest.cc
@@ -122,7 +122,7 @@
   AdvanceNowBy(one_second);
   timing_history_.WillDraw();
   AdvanceNowBy(draw_duration);
-  timing_history_.DidDraw(true, false);
+  timing_history_.DidDraw();
 
   EXPECT_EQ(begin_main_frame_queue_duration,
             timing_history_.BeginMainFrameQueueDurationCriticalEstimate());
@@ -173,7 +173,7 @@
   AdvanceNowBy(one_second);
   timing_history_.WillDraw();
   AdvanceNowBy(draw_duration);
-  timing_history_.DidDraw(false, false);
+  timing_history_.DidDraw();
 
   EXPECT_EQ(base::TimeDelta(),
             timing_history_.BeginMainFrameQueueDurationCriticalEstimate());
diff --git a/cc/paint/paint_record.h b/cc/paint/paint_record.h
index 7afa6de..9eaca49b 100644
--- a/cc/paint/paint_record.h
+++ b/cc/paint/paint_record.h
@@ -25,6 +25,8 @@
  public:
   PaintRecord();
   ~PaintRecord();
+  // After move, the source is invalid (with nullptr buffer_) and can't be
+  // used anymore.
   PaintRecord(PaintRecord&&);
   PaintRecord& operator=(PaintRecord&&);
   PaintRecord(const PaintRecord&);
@@ -34,7 +36,10 @@
     return buffer_->EqualsForTesting(*other.buffer_);
   }
 
-  const PaintOpBuffer& buffer() const { return *buffer_; }
+  const PaintOpBuffer& buffer() const {
+    CHECK(buffer_);
+    return *buffer_;
+  }
 
   size_t size() const { return buffer_->size(); }
   bool empty() const { return buffer_->empty(); }
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index ad87162..60fa3447 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -804,15 +804,11 @@
 void Scheduler::DrawIfPossible() {
   DCHECK(!inside_scheduled_action_);
   base::AutoReset<bool> mark_inside(&inside_scheduled_action_, true);
-  bool drawing_with_new_active_tree =
-      state_machine_.active_tree_needs_first_draw() &&
-      !state_machine_.previous_pending_tree_was_impl_side();
   compositor_timing_history_->WillDraw();
   state_machine_.WillDraw();
   DrawResult result = client_->ScheduledActionDrawIfPossible();
   state_machine_.DidDraw(result);
-  compositor_timing_history_->DidDraw(drawing_with_new_active_tree,
-                                      client_->HasInvalidationAnimation());
+  compositor_timing_history_->DidDraw();
 }
 
 void Scheduler::DrawForced() {
@@ -832,8 +828,7 @@
   state_machine_.WillDraw();
   DrawResult result = client_->ScheduledActionDrawForced();
   state_machine_.DidDraw(result);
-  compositor_timing_history_->DidDraw(drawing_with_new_active_tree,
-                                      client_->HasInvalidationAnimation());
+  compositor_timing_history_->DidDraw();
 }
 
 void Scheduler::SetDeferBeginMainFrame(bool defer_begin_main_frame) {
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h
index d576c498..902cf389 100644
--- a/cc/scheduler/scheduler.h
+++ b/cc/scheduler/scheduler.h
@@ -89,9 +89,6 @@
       base::TimeTicks time) = 0;
   virtual void FrameIntervalUpdated(base::TimeDelta interval) = 0;
 
-  // Functions used for reporting animation targeting UMA, crbug.com/758439.
-  virtual bool HasInvalidationAnimation() const = 0;
-
  protected:
   virtual ~SchedulerClient() {}
 };
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
index ae55ae3..97c37ab 100644
--- a/cc/scheduler/scheduler_unittest.cc
+++ b/cc/scheduler/scheduler_unittest.cc
@@ -279,8 +279,6 @@
     PushAction("RemoveObserver(this)");
   }
 
-  bool HasInvalidationAnimation() const override { return false; }
-
  protected:
   bool InsideBeginImplFrameCallback(bool state) {
     return inside_begin_impl_frame_ == state;
diff --git a/cc/trees/proxy_impl.cc b/cc/trees/proxy_impl.cc
index a8d3677..764c615e 100644
--- a/cc/trees/proxy_impl.cc
+++ b/cc/trees/proxy_impl.cc
@@ -496,10 +496,6 @@
     scheduler_->SetVideoNeedsBeginFrames(needs_begin_frames);
 }
 
-bool ProxyImpl::HasInvalidationAnimation() const {
-  return host_impl_->mutator_host()->HasInvalidationAnimation();
-}
-
 bool ProxyImpl::IsInsideDraw() {
   return inside_draw_;
 }
diff --git a/cc/trees/proxy_impl.h b/cc/trees/proxy_impl.h
index d1b085b..09546216 100644
--- a/cc/trees/proxy_impl.h
+++ b/cc/trees/proxy_impl.h
@@ -161,7 +161,6 @@
   void ScheduledActionBeginMainFrameNotExpectedUntil(
       base::TimeTicks time) override;
   void FrameIntervalUpdated(base::TimeDelta interval) override {}
-  bool HasInvalidationAnimation() const override;
 
   DrawResult DrawInternal(bool forced_draw);
 
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index d20eda35..bfc464d 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -525,13 +525,6 @@
     scheduler_on_impl_thread_->SetVideoNeedsBeginFrames(needs_begin_frames);
 }
 
-bool SingleThreadProxy::HasInvalidationAnimation() const {
-  // DebugScopedSetImplThread here is just a formality; all SchedulerClient
-  // methods should have it.
-  DebugScopedSetImplThread impl(task_runner_provider_);
-  return false;
-}
-
 bool SingleThreadProxy::IsInsideDraw() {
   DCHECK(!task_runner_provider_->HasImplThread() ||
          task_runner_provider_->IsImplThread());
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index 3ad6491..d3c28a9a 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -108,7 +108,6 @@
   void ScheduledActionBeginMainFrameNotExpectedUntil(
       base::TimeTicks time) override;
   void FrameIntervalUpdated(base::TimeDelta interval) override;
-  bool HasInvalidationAnimation() const override;
 
   // LayerTreeHostImplClient implementation
   void DidLoseLayerTreeFrameSinkOnImplThread() override;
diff --git a/chrome/VERSION b/chrome/VERSION
index 08763b2..8c4781322 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=116
 MINOR=0
-BUILD=5801
+BUILD=5802
 PATCH=0
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 20208c3f..bf302938 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-116.0.5794.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-116.0.5795.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 93b7219..4f08ba1 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -6166,6 +6166,9 @@
   <message name="IDS_BOREALIS_INSTALLER_ERROR_RETRY" desc="Button for Steam (noun, name of app) installer to retry after failing.">
     Retry
   </message>
+  <message name="IDS_BOREALIS_BETA_BADGE" desc="Badge text indicating that borealis (steam on chromeos) is a beta product, i.e. it is still under development.">
+    Beta
+  </message>
   <message name="IDS_BOREALIS_CLIENT_UNINSTALL_CONFIRM_BODY" desc="Confirmation dialog for uninstalling Steam (name of app).">
       Any games and apps installed via Steam will also be removed from this device
   </message>
diff --git a/chrome/app/chromeos_strings_grdp/IDS_BOREALIS_BETA_BADGE.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_BOREALIS_BETA_BADGE.png.sha1
new file mode 100644
index 0000000..1b571d9
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_BOREALIS_BETA_BADGE.png.sha1
@@ -0,0 +1 @@
+3d7f342ba8c692eabf5a899c6fc824fd6f34e1f6
\ No newline at end of file
diff --git a/chrome/app/vector_icons/BUILD.gn b/chrome/app/vector_icons/BUILD.gn
index 7b75c7a..05111fb1 100644
--- a/chrome/app/vector_icons/BUILD.gn
+++ b/chrome/app/vector_icons/BUILD.gn
@@ -109,7 +109,6 @@
     "leading_scroll.icon",
     "link.icon",
     "link_chrome_refresh.icon",
-    "location_on_chrome_refresh.icon",
     "media_controls_arrow_drop_down.icon",
     "media_controls_arrow_drop_up.icon",
     "media_toolbar_button.icon",
diff --git a/chrome/app/vector_icons/location_on_chrome_refresh.icon b/chrome/app/vector_icons/location_on_chrome_refresh.icon
deleted file mode 100644
index 5b6c4ce2..0000000
--- a/chrome/app/vector_icons/location_on_chrome_refresh.icon
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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, 10.01f, 18.15f,
-R_CUBIC_TO, -0.22f, 0, -0.41f, -0.06f, -0.57f, -0.18f,
-R_CUBIC_TO, -0.16f, -0.12f, -0.28f, -0.29f, -0.36f, -0.49f,
-R_CUBIC_TO, -0.32f, -0.8f, -0.65f, -1.52f, -1.01f, -2.15f,
-R_CUBIC_TO, -0.36f, -0.64f, -0.86f, -1.37f, -1.5f, -2.2f,
-R_CUBIC_TO, -0.69f, -0.88f, -1.25f, -1.74f, -1.68f, -2.56f,
-R_CUBIC_TO, -0.43f, -0.82f, -0.65f, -1.81f, -0.65f, -2.97f,
-R_CUBIC_TO, 0, -1.6f, 0.56f, -2.96f, 1.68f, -4.08f,
-CUBIC_TO, 7.04f, 2.4f, 8.4f, 1.84f, 10.01f, 1.84f,
-R_CUBIC_TO, 1.61f, 0, 2.97f, 0.56f, 4.09f, 1.68f,
-R_CUBIC_TO, 1.12f, 1.12f, 1.68f, 2.49f, 1.68f, 4.1f,
-R_CUBIC_TO, 0, 1.24f, -0.24f, 2.27f, -0.71f, 3.09f,
-R_CUBIC_TO, -0.47f, 0.82f, -1.01f, 1.62f, -1.62f, 2.43f,
-R_CUBIC_TO, -0.67f, 0.86f, -1.18f, 1.61f, -1.54f, 2.24f,
-R_CUBIC_TO, -0.36f, 0.63f, -0.68f, 1.33f, -0.97f, 2.11f,
-R_CUBIC_TO, -0.09f, 0.2f, -0.21f, 0.37f, -0.37f, 0.49f,
-R_CUBIC_TO, -0.16f, 0.12f, -0.34f, 0.19f, -0.55f, 0.19f,
-CLOSE,
-R_MOVE_TO, 0, -2.89f,
-R_CUBIC_TO, 0.23f, -0.47f, 0.5f, -0.94f, 0.79f, -1.4f,
-R_CUBIC_TO, 0.3f, -0.46f, 0.72f, -1.06f, 1.28f, -1.8f,
-R_CUBIC_TO, 0.58f, -0.74f, 1.05f, -1.43f, 1.42f, -2.07f,
-R_CUBIC_TO, 0.37f, -0.64f, 0.55f, -1.43f, 0.55f, -2.39f,
-R_CUBIC_TO, 0, -1.11f, -0.4f, -2.06f, -1.19f, -2.85f,
-R_CUBIC_TO, -0.79f, -0.79f, -1.75f, -1.19f, -2.86f, -1.19f,
-R_CUBIC_TO, -1.11f, 0, -2.07f, 0.4f, -2.85f, 1.19f,
-R_CUBIC_TO, -0.79f, 0.79f, -1.18f, 1.75f, -1.18f, 2.85f,
-R_CUBIC_TO, 0, 0.95f, 0.19f, 1.75f, 0.56f, 2.39f,
-R_CUBIC_TO, 0.37f, 0.64f, 0.84f, 1.33f, 1.41f, 2.07f,
-R_CUBIC_TO, 0.56f, 0.74f, 0.99f, 1.34f, 1.28f, 1.8f,
-R_CUBIC_TO, 0.29f, 0.46f, 0.56f, 0.93f, 0.79f, 1.4f,
-CLOSE,
-R_MOVE_TO, 0, -5.64f,
-R_CUBIC_TO, 0.56f, 0, 1.04f, -0.19f, 1.43f, -0.58f,
-R_CUBIC_TO, 0.39f, -0.39f, 0.59f, -0.86f, 0.59f, -1.43f,
-R_CUBIC_TO, 0, -0.57f, -0.19f, -1.04f, -0.58f, -1.43f,
-R_CUBIC_TO, -0.39f, -0.39f, -0.86f, -0.59f, -1.43f, -0.59f,
-R_CUBIC_TO, -0.57f, 0, -1.04f, 0.19f, -1.43f, 0.58f,
-CUBIC_TO, 8.2f, 6.56f, 8, 7.03f, 8, 7.6f,
-R_CUBIC_TO, 0, 0.57f, 0.19f, 1.04f, 0.58f, 1.43f,
-R_CUBIC_TO, 0.39f, 0.39f, 0.86f, 0.59f, 1.43f, 0.59f,
-CLOSE
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index ce16dbb..94420ffe 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -5421,6 +5421,9 @@
      flag_descriptions::kSystemProxyForSystemServicesName,
      flag_descriptions::kSystemProxyForSystemServicesDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kSystemProxyForSystemServices)},
+    {"enable-federated-service", flag_descriptions::kFederatedServiceName,
+     flag_descriptions::kFederatedServiceDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(ash::features::kFederatedService)},
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 #if BUILDFLAG(IS_CHROMEOS)
     {"enable-cros-touch-text-editing-redesign",
@@ -6782,6 +6785,10 @@
      flag_descriptions::kStartSurfaceWithAccessibilityDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kStartSurfaceWithAccessibility)},
 
+    {"enable-surface-polish", flag_descriptions::kSurfacePolishName,
+     flag_descriptions::kSurfacePolishDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kSurfacePolish)},
+
     {"enable-show-scrollable-mvt-on-ntp",
      flag_descriptions::kShowScrollableMVTOnNTPAndroidName,
      flag_descriptions::kShowScrollableMVTOnNTPAndroidDescription, kOsAndroid,
diff --git a/chrome/browser/apps/app_deduplication_service/app_deduplication_service.cc b/chrome/browser/apps/app_deduplication_service/app_deduplication_service.cc
index 3510e2c7..e675533 100644
--- a/chrome/browser/apps/app_deduplication_service/app_deduplication_service.cc
+++ b/chrome/browser/apps/app_deduplication_service/app_deduplication_service.cc
@@ -123,12 +123,8 @@
   }
 
   for (const auto& entry : group->second.entries) {
-    auto status_it = entry_status_.find(entry);
-    if (status_it == entry_status_.end()) {
-      continue;
-    }
-    if (status_it->second == EntryStatus::kNonApp ||
-        status_it->second == EntryStatus::kInstalledApp) {
+    if (entry.entry_status == EntryStatus::kNonApp ||
+        entry.entry_status == EntryStatus::kInstalledApp) {
       entries.push_back(entry);
     }
   }
@@ -151,55 +147,6 @@
   return duplication_index_1 == duplication_index_2;
 }
 
-// This function is only used when the kAppDeduplicationService flag
-// is enabled.
-void AppDeduplicationService::OnDuplicatedGroupListUpdated(
-    const proto::DuplicatedGroupList& duplicated_group_list) {
-  // Use the index as the internal indexing key for fast look up. If the
-  // size of the duplicated groups goes over integer 32 limit, a new indexing
-  // key needs to be introduced.
-  uint32_t index = 1;
-  for (auto const& group : duplicated_group_list.duplicate_group()) {
-    DuplicateGroup duplicate_group;
-    for (auto const& app : group.app()) {
-      const std::string& app_id = app.app_id_for_platform();
-      const std::string& source = app.source_name();
-      Entry entry;
-      // TODO(b/238394602): Add more data type when real data is ready.
-      // TODO(b/238394602): Add server data verification.
-      if (source == "arc") {
-        entry = Entry(app_id, AppType::kArc);
-      } else if (source == "web") {
-        entry = Entry(app_id, AppType::kWeb);
-      } else if (source == "website") {
-        GURL entry_url = GURL(app_id);
-        if (entry_url.is_valid()) {
-          entry = Entry(GURL(app_id));
-        } else {
-          continue;
-        }
-      } else {
-        continue;
-      }
-
-      entry_to_group_map_[entry] = index;
-      // Initialize entry status.
-      entry_status_[entry] = entry.entry_type == EntryType::kApp
-                                 ? EntryStatus::kNotInstalledApp
-                                 : EntryStatus::kNonApp;
-      duplicate_group.entries.push_back(std::move(entry));
-    }
-    duplication_map_[index] = std::move(duplicate_group);
-    index++;
-  }
-
-  apps::AppServiceProxy* proxy =
-      apps::AppServiceProxyFactory::GetForProfile(profile_);
-  proxy->AppRegistryCache().ForEachApp([this](const apps::AppUpdate& update) {
-    UpdateInstallationStatus(update);
-  });
-}
-
 void AppDeduplicationService::OnAppUpdate(const apps::AppUpdate& update) {
   UpdateInstallationStatus(update);
 }
@@ -212,15 +159,9 @@
 void AppDeduplicationService::UpdateInstallationStatus(
     const apps::AppUpdate& update) {
   Entry entry(update.PublisherId(), update.AppType());
-  auto it = entry_status_.find(entry);
-
-  if (it == entry_status_.end()) {
-    return;
-  }
-
-  it->second = apps_util::IsInstalled(update.Readiness())
-                   ? EntryStatus::kInstalledApp
-                   : EntryStatus::kNotInstalledApp;
+  entry.entry_status = apps_util::IsInstalled(update.Readiness())
+                           ? EntryStatus::kInstalledApp
+                           : EntryStatus::kNotInstalledApp;
 }
 
 absl::optional<uint32_t> AppDeduplicationService::FindDuplicationIndex(
@@ -361,11 +302,11 @@
         entry = Entry(app_id, source);
       }
 
-      entry_to_group_map_[entry] = index;
       // Initialize entry status.
-      entry_status_[entry] = entry.entry_type == EntryType::kApp
-                                 ? EntryStatus::kNotInstalledApp
-                                 : EntryStatus::kNonApp;
+      entry.entry_status = entry.entry_type == EntryType::kApp
+                               ? EntryStatus::kNotInstalledApp
+                               : EntryStatus::kNonApp;
+      entry_to_group_map_[entry] = index;
       duplicate_group.entries.push_back(std::move(entry));
     }
     if (!duplicate_group.entries.empty()) {
diff --git a/chrome/browser/apps/app_deduplication_service/app_deduplication_service.h b/chrome/browser/apps/app_deduplication_service/app_deduplication_service.h
index b3131c3..5b26b7e 100644
--- a/chrome/browser/apps/app_deduplication_service/app_deduplication_service.h
+++ b/chrome/browser/apps/app_deduplication_service/app_deduplication_service.h
@@ -51,14 +51,6 @@
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
  private:
-  friend class AppDeduplicationServiceTest;
-  FRIEND_TEST_ALL_PREFIXES(AppDeduplicationServiceTest,
-                           OnDuplicatedGroupListUpdated);
-  FRIEND_TEST_ALL_PREFIXES(AppDeduplicationServiceTest,
-                           ExactDuplicateAllInstalled);
-  FRIEND_TEST_ALL_PREFIXES(AppDeduplicationServiceTest, Installation);
-  FRIEND_TEST_ALL_PREFIXES(AppDeduplicationServiceTest, Websites);
-
   friend class AppDeduplicationServiceAlmanacTest;
   FRIEND_TEST_ALL_PREFIXES(AppDeduplicationServiceAlmanacTest,
                            DeduplicateDataToEntries);
@@ -75,22 +67,11 @@
   FRIEND_TEST_ALL_PREFIXES(AppDeduplicationServiceAlmanacTest,
                            ValidServiceWithDuplicates);
 
-  enum class EntryStatus {
-    // This entry is not an app entry (could be website, phonehub, etc.).
-    kNonApp = 0,
-    kInstalledApp = 1,
-    kNotInstalledApp = 2
-  };
-
   // Starts the process of calling the server to retrieve duplicate app data.
   // A call is only made to the server if there is a difference of over 24 hours
   // between now and the time stored in the server pref.
   void StartLoginFlow();
 
-  // AppProvisioningDataManager::Observer:
-  void OnDuplicatedGroupListUpdated(
-      const proto::DuplicatedGroupList& duplicated_apps_map) override;
-
   // apps::AppRegistryCache::Observer:
   void OnAppUpdate(const apps::AppUpdate& update) override;
   void OnAppRegistryCacheWillBeDestroyed(
@@ -135,7 +116,6 @@
 
   std::map<uint32_t, DuplicateGroup> duplication_map_;
   std::map<Entry, uint32_t> entry_to_group_map_;
-  std::map<Entry, EntryStatus> entry_status_;
   raw_ptr<Profile, ExperimentalAsh> profile_;
 
   base::ScopedObservation<AppProvisioningDataManager,
diff --git a/chrome/browser/apps/app_deduplication_service/app_deduplication_service_unittest.cc b/chrome/browser/apps/app_deduplication_service/app_deduplication_service_unittest.cc
index 22eb09b..f960c06 100644
--- a/chrome/browser/apps/app_deduplication_service/app_deduplication_service_unittest.cc
+++ b/chrome/browser/apps/app_deduplication_service/app_deduplication_service_unittest.cc
@@ -31,353 +31,6 @@
 
 namespace apps::deduplication {
 
-class AppDeduplicationServiceTest : public testing::Test {
- protected:
-  AppDeduplicationServiceTest() {
-    scoped_feature_list_.InitAndEnableFeature(
-        features::kAppDeduplicationService);
-  }
-
-  void UpdateAppReadiness(AppServiceProxy* proxy,
-                          const std::string& app_id,
-                          const std::string& publisher_id,
-                          apps::AppType app_type,
-                          Readiness readiness) {
-    AppPtr app = std::make_unique<apps::App>(app_type, app_id);
-    app->publisher_id = publisher_id;
-    app->readiness = readiness;
-    std::vector<AppPtr> apps;
-    apps.push_back(std::move(app));
-    proxy->AppRegistryCache().OnApps(std::move(apps), app_type,
-                                     /*should_notify_initialized=*/false);
-  }
-
-  absl::optional<proto::DuplicatedGroupList> ReadProtoFromFile() {
-    base::FilePath path;
-    if (!base::PathService::Get(chrome::DIR_TEST_DATA, &path)) {
-      return absl::nullopt;
-    }
-    path = path.AppendASCII("app_deduplication_service/binary_test_data.pb");
-
-    std::string dedupe_pb;
-    if (!base::ReadFileToString(path, &dedupe_pb)) {
-      return absl::nullopt;
-    }
-
-    proto::DuplicatedGroupList duplicated_group_list;
-    if (!duplicated_group_list.ParseFromString(dedupe_pb)) {
-      return absl::nullopt;
-    }
-    return duplicated_group_list;
-  }
-
-  base::test::ScopedFeatureList scoped_feature_list_;
-
- private:
-  // BrowserTaskEnvironment has to be the first member or test will break.
-  content::BrowserTaskEnvironment task_environment_;
-};
-
-TEST_F(AppDeduplicationServiceTest, ServiceAccessPerProfile) {
-  TestingProfile::Builder profile_builder;
-
-  // We expect an App Deduplication Service in a regular profile.
-  auto profile = profile_builder.Build();
-  EXPECT_TRUE(AppDeduplicationServiceFactory::
-                  IsAppDeduplicationServiceAvailableForProfile(profile.get()));
-  auto* service = AppDeduplicationServiceFactory::GetForProfile(profile.get());
-  EXPECT_NE(nullptr, service);
-
-  // We expect App Deduplication Service to be unsupported in incognito.
-  TestingProfile::Builder incognito_builder;
-  auto* incognito_profile = incognito_builder.BuildIncognito(profile.get());
-  EXPECT_FALSE(
-      AppDeduplicationServiceFactory::
-          IsAppDeduplicationServiceAvailableForProfile(incognito_profile));
-  EXPECT_EQ(nullptr,
-            AppDeduplicationServiceFactory::GetForProfile(incognito_profile));
-
-  // We expect a different App Deduplication Service in the Guest Session
-  // profile.
-  TestingProfile::Builder guest_builder;
-  guest_builder.SetGuestSession();
-  auto guest_profile = guest_builder.Build();
-
-  // App Deduplication Service is not available for original profile.
-  EXPECT_FALSE(
-      AppDeduplicationServiceFactory::
-          IsAppDeduplicationServiceAvailableForProfile(guest_profile.get()));
-  EXPECT_EQ(nullptr,
-            AppDeduplicationServiceFactory::GetForProfile(guest_profile.get()));
-
-  // App Deduplication Service is available for OTR profile in Guest mode.
-  auto* guest_otr_profile =
-      guest_profile->GetPrimaryOTRProfile(/*create_if_needed=*/true);
-  EXPECT_TRUE(
-      AppDeduplicationServiceFactory::
-          IsAppDeduplicationServiceAvailableForProfile(guest_otr_profile));
-  auto* guest_otr_service =
-      AppDeduplicationServiceFactory::GetForProfile(guest_otr_profile);
-  EXPECT_NE(nullptr, guest_otr_service);
-  EXPECT_NE(guest_otr_service, service);
-}
-
-TEST_F(AppDeduplicationServiceTest, OnDuplicatedGroupListUpdated) {
-  absl::optional<proto::DuplicatedGroupList> duplicated_group_list =
-      ReadProtoFromFile();
-  ASSERT_TRUE(duplicated_group_list.has_value());
-
-  TestingProfile profile;
-  ASSERT_TRUE(AppDeduplicationServiceFactory::
-                  IsAppDeduplicationServiceAvailableForProfile(&profile));
-  auto* service = AppDeduplicationServiceFactory::GetForProfile(&profile);
-  EXPECT_NE(nullptr, service);
-
-  service->OnDuplicatedGroupListUpdated(duplicated_group_list.value());
-
-  uint32_t skype_test_index = 1;
-  std::string skype_arc_app_id = "com.skype.raider";
-  auto it =
-      service->entry_to_group_map_.find(Entry(skype_arc_app_id, AppType::kArc));
-  ASSERT_NE(it, service->entry_to_group_map_.end());
-  EXPECT_EQ(skype_test_index, it->second);
-
-  std::string skype_web_app_id = "https://web.skype.com/";
-  it =
-      service->entry_to_group_map_.find(Entry(skype_web_app_id, AppType::kWeb));
-  ASSERT_NE(it, service->entry_to_group_map_.end());
-  EXPECT_EQ(skype_test_index, it->second);
-
-  auto map_it = service->duplication_map_.find(skype_test_index);
-  ASSERT_FALSE(map_it == service->duplication_map_.end());
-  EXPECT_THAT(map_it->second.entries,
-              ElementsAre(Entry(skype_arc_app_id, AppType::kArc),
-                          Entry(skype_web_app_id, AppType::kWeb)));
-
-  uint32_t whatsapp_test_index = 2;
-  std::string whatsapp_arc_app_id = "com.whatsapp";
-  it = service->entry_to_group_map_.find(
-      Entry(whatsapp_arc_app_id, AppType::kArc));
-  ASSERT_NE(it, service->entry_to_group_map_.end());
-  EXPECT_EQ(whatsapp_test_index, it->second);
-
-  std::string whatsapp_web_app_id = "https://web.whatsapp.com/";
-  it = service->entry_to_group_map_.find(
-      Entry(whatsapp_web_app_id, AppType::kWeb));
-  ASSERT_NE(it, service->entry_to_group_map_.end());
-  EXPECT_EQ(whatsapp_test_index, it->second);
-
-  map_it = service->duplication_map_.find(whatsapp_test_index);
-  ASSERT_FALSE(map_it == service->duplication_map_.end());
-  EXPECT_THAT(map_it->second.entries,
-              ElementsAre(Entry(whatsapp_arc_app_id, AppType::kArc),
-                          Entry(whatsapp_web_app_id, AppType::kWeb)));
-}
-
-// Test that if all apps in the duplicated group are installed, the full list
-// will be returned.
-TEST_F(AppDeduplicationServiceTest, ExactDuplicateAllInstalled) {
-  absl::optional<proto::DuplicatedGroupList> duplicated_group_list =
-      ReadProtoFromFile();
-  ASSERT_TRUE(duplicated_group_list.has_value());
-
-  TestingProfile profile;
-
-  // Set up app installed.
-  auto* proxy = AppServiceProxyFactory::GetForProfile(&profile);
-  std::string skype_arc_app_id = "com.skype.raider";
-  std::string skype_web_app_id = "https://web.skype.com/";
-  std::string whatsapp_arc_app_id = "com.whatsapp";
-  std::string whatsapp_web_app_id = "https://web.whatsapp.com/";
-
-  UpdateAppReadiness(proxy, "app1", skype_arc_app_id, apps::AppType::kArc,
-                     Readiness::kReady);
-  UpdateAppReadiness(proxy, "app2", skype_web_app_id, apps::AppType::kWeb,
-                     Readiness::kReady);
-  UpdateAppReadiness(proxy, "app3", whatsapp_arc_app_id, apps::AppType::kArc,
-                     Readiness::kReady);
-  UpdateAppReadiness(proxy, "app4", whatsapp_web_app_id, apps::AppType::kWeb,
-                     Readiness::kReady);
-
-  ASSERT_TRUE(AppDeduplicationServiceFactory::
-                  IsAppDeduplicationServiceAvailableForProfile(&profile));
-  auto* service = AppDeduplicationServiceFactory::GetForProfile(&profile);
-  EXPECT_NE(nullptr, service);
-
-  service->OnDuplicatedGroupListUpdated(duplicated_group_list.value());
-
-  Entry skype_arc_entry(skype_arc_app_id, apps::AppType::kArc);
-  Entry skype_web_entry(skype_web_app_id, apps::AppType::kWeb);
-  Entry whatsapp_arc_entry(whatsapp_arc_app_id, apps::AppType::kArc);
-  Entry whatsapp_web_entry(whatsapp_web_app_id, apps::AppType::kWeb);
-
-  EXPECT_THAT(service->GetDuplicates(skype_arc_entry),
-              ElementsAre(Entry(skype_arc_entry), Entry(skype_web_entry)));
-  EXPECT_THAT(service->GetDuplicates(skype_web_entry),
-              ElementsAre(Entry(skype_arc_entry), Entry(skype_web_entry)));
-  EXPECT_THAT(
-      service->GetDuplicates(whatsapp_web_entry),
-      ElementsAre(Entry(whatsapp_arc_entry), Entry(whatsapp_web_entry)));
-  EXPECT_THAT(
-      service->GetDuplicates(whatsapp_arc_entry),
-      ElementsAre(Entry(whatsapp_arc_entry), Entry(whatsapp_web_entry)));
-
-  EXPECT_TRUE(service->AreDuplicates(skype_arc_entry, skype_web_entry));
-  EXPECT_TRUE(service->AreDuplicates(whatsapp_arc_entry, whatsapp_web_entry));
-
-  EXPECT_FALSE(service->AreDuplicates(skype_arc_entry, whatsapp_arc_entry));
-  EXPECT_FALSE(service->AreDuplicates(skype_arc_entry, whatsapp_web_entry));
-  EXPECT_FALSE(service->AreDuplicates(skype_web_entry, whatsapp_arc_entry));
-  EXPECT_FALSE(service->AreDuplicates(skype_web_entry, whatsapp_web_entry));
-
-  Entry not_duplicate_app("not_duplicate_app_id", apps::AppType::kWeb);
-  EXPECT_TRUE(service->GetDuplicates(not_duplicate_app).empty());
-  EXPECT_FALSE(service->AreDuplicates(not_duplicate_app, skype_arc_entry));
-  EXPECT_FALSE(service->AreDuplicates(not_duplicate_app, skype_web_entry));
-  EXPECT_FALSE(service->AreDuplicates(not_duplicate_app, whatsapp_arc_entry));
-  EXPECT_FALSE(service->AreDuplicates(not_duplicate_app, whatsapp_web_entry));
-}
-
-TEST_F(AppDeduplicationServiceTest, Installation) {
-  absl::optional<proto::DuplicatedGroupList> duplicated_group_list =
-      ReadProtoFromFile();
-  ASSERT_TRUE(duplicated_group_list.has_value());
-
-  TestingProfile profile;
-
-  auto* proxy = AppServiceProxyFactory::GetForProfile(&profile);
-
-  ASSERT_TRUE(AppDeduplicationServiceFactory::
-                  IsAppDeduplicationServiceAvailableForProfile(&profile));
-  auto* service = AppDeduplicationServiceFactory::GetForProfile(&profile);
-  EXPECT_NE(nullptr, service);
-
-  service->OnDuplicatedGroupListUpdated(duplicated_group_list.value());
-
-  std::string skype_arc_app_id = "com.skype.raider";
-  std::string skype_web_app_id = "https://web.skype.com/";
-  std::string whatsapp_arc_app_id = "com.whatsapp";
-  std::string whatsapp_web_app_id = "https://web.whatsapp.com/";
-
-  Entry skype_arc_entry(skype_arc_app_id, apps::AppType::kArc);
-  Entry skype_web_entry(skype_web_app_id, apps::AppType::kWeb);
-  Entry whatsapp_arc_entry(whatsapp_arc_app_id, apps::AppType::kArc);
-  Entry whatsapp_web_entry(whatsapp_web_app_id, apps::AppType::kWeb);
-
-  // If nothing is installed, should only return phonehub app.
-  EXPECT_THAT(service->GetDuplicates(skype_arc_entry), ElementsAre());
-  EXPECT_THAT(service->GetDuplicates(whatsapp_web_entry), ElementsAre());
-
-  UpdateAppReadiness(proxy, "app1", skype_arc_app_id, apps::AppType::kArc,
-                     Readiness::kReady);
-  EXPECT_THAT(service->GetDuplicates(skype_web_entry),
-              ElementsAre(Entry(skype_arc_entry)));
-
-  UpdateAppReadiness(proxy, "app2", whatsapp_web_app_id, apps::AppType::kWeb,
-                     Readiness::kReady);
-  EXPECT_THAT(service->GetDuplicates(whatsapp_arc_entry),
-              ElementsAre(Entry(whatsapp_web_entry)));
-
-  // Uninstall the app removes it from duplicates.
-  UpdateAppReadiness(proxy, "app1", skype_arc_app_id, apps::AppType::kArc,
-                     Readiness::kUninstalledByUser);
-  EXPECT_THAT(service->GetDuplicates(skype_arc_entry), ElementsAre());
-}
-
-TEST_F(AppDeduplicationServiceTest, Websites) {
-  absl::optional<proto::DuplicatedGroupList> duplicated_group_list =
-      ReadProtoFromFile();
-  ASSERT_TRUE(duplicated_group_list.has_value());
-
-  TestingProfile profile;
-
-  auto* proxy = AppServiceProxyFactory::GetForProfile(&profile);
-
-  ASSERT_TRUE(AppDeduplicationServiceFactory::
-                  IsAppDeduplicationServiceAvailableForProfile(&profile));
-  auto* service = AppDeduplicationServiceFactory::GetForProfile(&profile);
-  EXPECT_NE(nullptr, service);
-
-  service->OnDuplicatedGroupListUpdated(duplicated_group_list.value());
-
-  GURL keep_website = GURL("https://keep.google.com/");
-  GURL keep_website_with_path = GURL("https://keep.google.com/testtesttest");
-  GURL not_keep_website = GURL("https://www.google.com/");
-  std::string keep_arc_app_id = "com.google.android.keep";
-  std::string keep_web_app_id = "https://keep.google.com/?usp=installed_webapp";
-  GURL wrong_scheme_website = GURL("http://www.google.com/");
-
-  Entry keep_website_entry(keep_website);
-  Entry keep_website_with_path_entry(keep_website_with_path);
-  Entry keep_arc_entry(keep_arc_app_id, apps::AppType::kArc);
-  Entry keep_web_entry(keep_web_app_id, apps::AppType::kWeb);
-  Entry not_keep_website_entry(not_keep_website);
-  Entry wrong_scheme_website_entry(wrong_scheme_website);
-
-  UpdateAppReadiness(proxy, "app1", keep_arc_app_id, apps::AppType::kArc,
-                     Readiness::kReady);
-  UpdateAppReadiness(proxy, "app2", keep_web_app_id, apps::AppType::kWeb,
-                     Readiness::kReady);
-
-  EXPECT_THAT(service->GetDuplicates(keep_website_entry),
-              ElementsAre(Entry(keep_arc_entry), Entry(keep_web_entry),
-                          Entry(keep_website_entry)));
-  EXPECT_THAT(service->GetDuplicates(keep_website_with_path_entry),
-              ElementsAre(Entry(keep_arc_entry), Entry(keep_web_entry),
-                          Entry(keep_website_entry)));
-  EXPECT_THAT(service->GetDuplicates(not_keep_website_entry),
-              testing::IsEmpty());
-  EXPECT_THAT(service->GetDuplicates(wrong_scheme_website_entry),
-              testing::IsEmpty());
-
-  EXPECT_TRUE(
-      service->AreDuplicates(keep_website_with_path_entry, keep_arc_entry));
-  EXPECT_FALSE(service->AreDuplicates(not_keep_website_entry, keep_web_entry));
-  EXPECT_FALSE(
-      service->AreDuplicates(wrong_scheme_website_entry, keep_web_entry));
-}
-
-// Test updating duplication data from app provisioning data manager.
-TEST_F(AppDeduplicationServiceTest, AppPromisioningDataManagerUpdate) {
-  TestingProfile profile;
-
-  auto* proxy = AppServiceProxyFactory::GetForProfile(&profile);
-  std::string skype_arc_app_id = "com.skype.raider";
-  std::string skype_web_app_id = "https://web.skype.com/";
-  UpdateAppReadiness(proxy, "app1", skype_arc_app_id, apps::AppType::kArc,
-                     Readiness::kReady);
-  UpdateAppReadiness(proxy, "app2", skype_web_app_id, apps::AppType::kWeb,
-                     Readiness::kReady);
-
-  ASSERT_TRUE(AppDeduplicationServiceFactory::
-                  IsAppDeduplicationServiceAvailableForProfile(&profile));
-  auto* service = AppDeduplicationServiceFactory::GetForProfile(&profile);
-  EXPECT_NE(nullptr, service);
-
-  std::string app_with_locale_pb = "";
-  base::FilePath install_dir("/");
-  base::FilePath path;
-  EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &path));
-  path = path.AppendASCII("app_deduplication_service/binary_test_data.pb");
-  std::string dedupe_pb;
-  ASSERT_TRUE(base::ReadFileToString(path, &dedupe_pb));
-
-  ComponentFileContents component_files = {app_with_locale_pb, dedupe_pb};
-  apps::AppProvisioningDataManager::Get()->PopulateFromDynamicUpdate(
-      component_files, install_dir);
-
-  Entry skype_arc_entry(skype_arc_app_id, apps::AppType::kArc);
-  Entry skype_web_entry(skype_web_app_id, apps::AppType::kWeb);
-
-  EXPECT_THAT(service->GetDuplicates(skype_arc_entry),
-              ElementsAre(Entry(skype_arc_entry), Entry(skype_web_entry)));
-  EXPECT_TRUE(service->AreDuplicates(skype_arc_entry, skype_web_entry));
-
-  Entry not_duplicate_app("not_duplicate_app_id", apps::AppType::kWeb);
-  EXPECT_TRUE(service->GetDuplicates(not_duplicate_app).empty());
-  EXPECT_FALSE(service->AreDuplicates(not_duplicate_app, skype_web_entry));
-}
-
 class AppDeduplicationServiceAlmanacTest : public testing::Test {
  protected:
   AppDeduplicationServiceAlmanacTest() {
diff --git a/chrome/browser/apps/app_deduplication_service/entry_types.cc b/chrome/browser/apps/app_deduplication_service/entry_types.cc
index 8efd8a9..2ed265e 100644
--- a/chrome/browser/apps/app_deduplication_service/entry_types.cc
+++ b/chrome/browser/apps/app_deduplication_service/entry_types.cc
@@ -31,6 +31,10 @@
 }
 
 std::ostream& operator<<(std::ostream& out, const Entry& entry) {
+  out << "EntryStatus: "
+      << static_cast<std::underlying_type<EntryStatus>::type>(
+             entry.entry_status)
+      << std::endl;
   out << "EntryType: "
       << static_cast<std::underlying_type<EntryType>::type>(entry.entry_type)
       << std::endl;
diff --git a/chrome/browser/apps/app_deduplication_service/entry_types.h b/chrome/browser/apps/app_deduplication_service/entry_types.h
index 8d3d8e5..51030ede 100644
--- a/chrome/browser/apps/app_deduplication_service/entry_types.h
+++ b/chrome/browser/apps/app_deduplication_service/entry_types.h
@@ -14,6 +14,13 @@
 
 namespace apps::deduplication {
 
+enum class EntryStatus {
+  // This entry is not an app entry (could be website, etc.).
+  kNonApp = 0,
+  kInstalledApp = 1,
+  kNotInstalledApp = 2
+};
+
 enum class EntryType { kApp, kWebPage };
 
 // Deduplication entry, each entry represents an app or a web page that could be
@@ -35,6 +42,8 @@
   bool operator==(const Entry& other) const;
   bool operator<(const Entry& other) const;
 
+  EntryStatus entry_status;
+
   EntryType entry_type;
 
   // The identifier id. If it is website, the id is the url.spec().
diff --git a/chrome/browser/apps/app_provisioning_service/app_provisioning_data_manager.cc b/chrome/browser/apps/app_provisioning_service/app_provisioning_data_manager.cc
index 425d0f7..abad12b9 100644
--- a/chrome/browser/apps/app_provisioning_service/app_provisioning_data_manager.cc
+++ b/chrome/browser/apps/app_provisioning_service/app_provisioning_data_manager.cc
@@ -14,23 +14,6 @@
 namespace apps {
 
 namespace {
-std::unique_ptr<proto::DuplicatedGroupList> PopulateDuplicatedGroupList(
-    const std::string& binary_pb) {
-  // Parse the proto and do some validation on it.
-  if (binary_pb.empty()) {
-    LOG(ERROR) << "Binary is empty";
-    return nullptr;
-  }
-
-  std::unique_ptr<proto::DuplicatedGroupList> duplicated_group_list =
-      std::make_unique<proto::DuplicatedGroupList>();
-  if (!duplicated_group_list->ParseFromString(binary_pb)) {
-    LOG(ERROR) << "Failed to parse protobuf";
-    return nullptr;
-  }
-  return duplicated_group_list;
-}
-
 std::unique_ptr<proto::AppWithLocaleList> PopulateAppWithLocaleList(
     const std::string& binary_pb) {
   // Parse the proto and do some validation on it.
@@ -66,10 +49,6 @@
   // TODO(melzhang) : Add check that version of |app_with_locale_list| is newer.
   app_with_locale_list_ =
       PopulateAppWithLocaleList(component_files.app_with_locale_pb);
-  if (base::FeatureList::IsEnabled(features::kAppDeduplicationService)) {
-    duplicated_group_list_ =
-        PopulateDuplicatedGroupList(component_files.deduplication_pb);
-  }
   data_dir_ = install_dir;
   OnAppDataUpdated();
 }
@@ -79,7 +58,7 @@
 }
 
 void AppProvisioningDataManager::OnAppDataUpdated() {
-  if (!app_with_locale_list_ && !duplicated_group_list_) {
+  if (!app_with_locale_list_) {
     return;
   }
   for (auto& observer : observers_) {
@@ -89,7 +68,7 @@
 
 void AppProvisioningDataManager::AddObserver(Observer* observer) {
   observers_.AddObserver(observer);
-  if (app_with_locale_list_ || duplicated_group_list_) {
+  if (app_with_locale_list_) {
     NotifyObserver(*observer);
   }
 }
@@ -104,11 +83,6 @@
   if (app_with_locale_list_) {
     observer.OnAppWithLocaleListUpdated(*app_with_locale_list_.get());
   }
-  // TODO(b/238394602): Add version check so that only notify observer when new
-  // version is available.
-  if (duplicated_group_list_) {
-    observer.OnDuplicatedGroupListUpdated(*duplicated_group_list_.get());
-  }
 }
 
 }  // namespace apps
diff --git a/chrome/browser/apps/app_provisioning_service/app_provisioning_data_manager.h b/chrome/browser/apps/app_provisioning_service/app_provisioning_data_manager.h
index 572c320f..bceeb99a 100644
--- a/chrome/browser/apps/app_provisioning_service/app_provisioning_data_manager.h
+++ b/chrome/browser/apps/app_provisioning_service/app_provisioning_data_manager.h
@@ -17,7 +17,6 @@
 
 struct ComponentFileContents {
   std::string app_with_locale_pb;
-  std::string deduplication_pb;
 };
 
 // The AppProvisioningDataManager parses the updates received from the Component
@@ -31,8 +30,6 @@
    public:
     virtual void OnAppWithLocaleListUpdated(
         const proto::AppWithLocaleList& app_with_locale_list) {}
-    virtual void OnDuplicatedGroupListUpdated(
-        const proto::DuplicatedGroupList& duplicated_group_list) {}
   };
 
   static AppProvisioningDataManager* Get();
@@ -70,7 +67,6 @@
 
   // The latest app data. Starts out as null.
   std::unique_ptr<proto::AppWithLocaleList> app_with_locale_list_;
-  std::unique_ptr<proto::DuplicatedGroupList> duplicated_group_list_;
 
   base::ObserverList<Observer> observers_;
 
diff --git a/chrome/browser/apps/app_service/BUILD.gn b/chrome/browser/apps/app_service/BUILD.gn
index e9c6f30..58ab3be 100644
--- a/chrome/browser/apps/app_service/BUILD.gn
+++ b/chrome/browser/apps/app_service/BUILD.gn
@@ -330,6 +330,132 @@
   ]
 }
 
+source_set("unit_tests") {
+  testonly = true
+
+  sources = [
+    "app_icon/app_icon_factory_unittest.cc",
+    "app_icon/app_icon_test_util.cc",
+    "app_icon/app_icon_test_util.h",
+    "app_icon/chrome_apps_icon_unittest.cc",
+    "app_icon/web_app_icon_unittest.cc",
+    "app_service_proxy_unittest.cc",
+    "intent_util_unittest.cc",
+    "launch_utils_unittest.cc",
+    "package_id_unittest.cc",
+    "publishers/publisher_unittest.cc",
+  ]
+
+  deps = [
+    ":app_service",
+    ":constants",
+    ":test_support",
+    "//base",
+    "//base/test:test_support",
+    "//build:chromeos_buildflags",
+    "//cc:test_support",
+    "//chrome/app/theme:chrome_unscaled_resources_grit",
+    "//chrome/browser/apps:icon_standardizer",
+    "//chrome/browser/extensions",
+    "//chrome/browser/profiles:profile",
+    "//chrome/browser/resources:component_extension_resources",
+    "//chrome/browser/ui",
+    "//chrome/browser/web_applications",
+    "//chrome/browser/web_applications:web_applications_test_support",
+    "//chrome/common:chrome_features",
+    "//chrome/common:non_code_constants",
+    "//chrome/test:test_support",
+    "//components/account_id",
+    "//components/app_constants",
+
+    # TODO: Depend on "//components/services/app_service" once
+    # crrev.com/c/4570160 lands.
+    "//components/services/app_service/public/cpp:app_file_handling",
+    "//components/services/app_service/public/cpp:app_types",
+    "//components/services/app_service/public/cpp:app_update",
+    "//components/services/app_service/public/cpp:icon_loader",
+    "//components/services/app_service/public/cpp:icon_types",
+    "//components/services/app_service/public/cpp:intents",
+    "//components/services/app_service/public/cpp:preferred_app",
+    "//components/services/app_service/public/cpp:preferred_apps",
+    "//components/services/app_service/public/cpp:test_support",
+    "//components/user_manager",
+    "//content/test:test_support",
+    "//extensions:test_support",
+    "//extensions/common",
+    "//mojo/public/cpp/bindings:bindings_base",
+    "//net",
+    "//services/data_decoder/public/cpp:test_support",
+    "//skia",
+    "//storage/browser",
+    "//storage/common",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//ui/base",
+    "//ui/display/types",
+    "//ui/gfx",
+    "//ui/gfx:test_support",
+    "//ui/gfx/codec",
+    "//ui/gfx/geometry",
+    "//url",
+  ]
+
+  if (is_chromeos) {
+    deps += [ "//chromeos/crosapi/mojom" ]
+  }
+
+  if (is_chromeos_ash) {
+    sources += [
+      "app_icon/app_icon_decoder_unittest.cc",
+      "app_icon/arc_apps_icon_unittest.cc",
+      "app_icon/guest_os_apps_icon_unittest.cc",
+      "file_utils_unittest.cc",
+      "metrics/app_platform_metrics_service_unittest.cc",
+      "promise_apps/promise_app_almanac_connector_unittest.cc",
+      "promise_apps/promise_app_icon_cache_unittest.cc",
+      "promise_apps/promise_app_registry_cache_unittest.cc",
+      "promise_apps/promise_app_service_unittest.cc",
+      "promise_apps/promise_app_unittest.cc",
+      "promise_apps/promise_app_update_unittest.cc",
+      "promise_apps/promise_app_wrapper_unittest.cc",
+      "publishers/arc_apps_unittest.cc",
+      "publishers/bruschetta_apps_unittest.cc",
+      "publishers/crostini_apps_unittest.cc",
+      "publishers/guest_os_apps_unittest.cc",
+      "publishers/plugin_vm_apps_unittest.cc",
+      "webapk/webapk_install_task_unittest.cc",
+      "webapk/webapk_manager_unittest.cc",
+    ]
+
+    deps += [
+      "//ash/components/arc:arc_test_support",
+      "//ash/constants",
+      "//chrome/browser/apps/app_service/promise_apps/proto",
+      "//chrome/browser/ash",
+      "//chrome/browser/ash:test_support",
+      "//chrome/browser/ash/crosapi:browser_util",
+      "//chrome/browser/ash/crosapi:test_support",
+      "//chrome/browser/metrics/structured:features",
+      "//chromeos/ash/components/dbus/cicerone",
+      "//chromeos/ash/components/login/login_state",
+      "//chromeos/ash/components/standalone_browser",
+      "//components/arc",
+      "//components/arc:arc_test_support",
+      "//components/image_fetcher/core",
+      "//components/image_fetcher/core:test_support",
+      "//components/metrics/structured:common",
+      "//components/metrics/structured:structured_events",
+      "//components/metrics/structured:structured_metrics_features",
+      "//components/metrics/structured:test_support",
+      "//components/webapk:proto",
+    ]
+  }
+
+  if (is_chromeos_lacros) {
+    sources += [ "app_service_proxy_lacros_unittest.cc" ]
+  }
+}
+
 source_set("test_support") {
   testonly = true
 
@@ -351,10 +477,22 @@
 
   if (is_chromeos_ash) {
     sources += [
+      "metrics/app_platform_metrics_service_test_base.cc",
+      "metrics/app_platform_metrics_service_test_base.h",
       "webapk/webapk_test_server.cc",
       "webapk/webapk_test_server.h",
     ]
 
-    deps += [ "//components/webapk:proto" ]
+    deps += [
+      "//chrome/browser/ash:test_support",
+      "//components/webapk:proto",
+    ]
+  }
+
+  if (is_chromeos_lacros) {
+    sources += [
+      "mock_crosapi_app_service_proxy.cc",
+      "mock_crosapi_app_service_proxy.h",
+    ]
   }
 }
diff --git a/chrome/browser/apps/app_service/OWNERS b/chrome/browser/apps/app_service/OWNERS
index 1b3e17d..6ccf175 100644
--- a/chrome/browser/apps/app_service/OWNERS
+++ b/chrome/browser/apps/app_service/OWNERS
@@ -10,11 +10,5 @@
 per-file crostini*=file://chrome/browser/ash/guest_os/OWNERS
 per-file plugin_vm*=file://chrome/browser/ash/guest_os/OWNERS
 
-# For files and intent handling system:
-per-file intent*=mxcai@chromium.org
-per-file file*=mxcai@chromium.org
-per-file intent*=tsergeant@chromium.org
-per-file file*=tsergeant@chromium.org
-
 # For policy_id util:
-per-file policy_util*=greengrape@google.com
\ No newline at end of file
+per-file policy_util*=greengrape@google.com
diff --git a/chrome/browser/apps/app_service/app_icon/web_app_icon_unittest.cc b/chrome/browser/apps/app_service/app_icon/web_app_icon_unittest.cc
index 1e758427..3752fe3 100644
--- a/chrome/browser/apps/app_service/app_icon/web_app_icon_unittest.cc
+++ b/chrome/browser/apps/app_service/app_icon/web_app_icon_unittest.cc
@@ -138,16 +138,17 @@
     EXPECT_TRUE(success);
   }
 
-  void GenerateWebAppIcon(const std::string& app_id,
-                          IconPurpose purpose,
-                          const std::vector<int>& sizes_px,
-                          apps::ScaleToSize scale_to_size_in_px,
-                          gfx::ImageSkia& output_image_skia,
-                          bool skip_icon_effects = false) {
+  gfx::ImageSkia GenerateWebAppIcon(const std::string& app_id,
+                                    IconPurpose purpose,
+                                    const std::vector<int>& sizes_px,
+                                    apps::ScaleToSize scale_to_size_in_px,
+                                    bool skip_icon_effects = false) {
     base::test::TestFuture<std::map<SquareSizePx, SkBitmap>> future;
     icon_manager().ReadIcons(app_id, purpose, sizes_px, future.GetCallback());
     auto icon_bitmaps = future.Take();
 
+    gfx::ImageSkia output_image_skia;
+
     for (auto [scale, size_in_px] : scale_to_size_in_px) {
       int icon_size_in_px =
           gfx::ScaleToFlooredSize(gfx::Size(kSizeInDip, kSizeInDip), scale)
@@ -178,6 +179,8 @@
     }
 
     EnsureRepresentationsLoaded(output_image_skia);
+
+    return output_image_skia;
   }
 
   void GenerateWebAppCompressedIcon(const std::string& app_id,
@@ -185,9 +188,8 @@
                                     const std::vector<int>& sizes_px,
                                     apps::ScaleToSize scale_to_size_in_px,
                                     std::vector<uint8_t>& result) {
-    gfx::ImageSkia image_skia;
-    GenerateWebAppIcon(app_id, purpose, sizes_px, scale_to_size_in_px,
-                       image_skia);
+    gfx::ImageSkia image_skia =
+        GenerateWebAppIcon(app_id, purpose, sizes_px, scale_to_size_in_px);
 
     const float scale = 1.0;
     const gfx::ImageSkiaRep& image_skia_rep =
@@ -207,9 +209,9 @@
                                     apps::ScaleToSize scale_to_size_in_px,
                                     float scale,
                                     std::vector<uint8_t>& result) {
-    gfx::ImageSkia image_skia;
-    GenerateWebAppIcon(app_id, purpose, sizes_px, scale_to_size_in_px,
-                       image_skia, /*skip_icon_effects=*/true);
+    gfx::ImageSkia image_skia =
+        GenerateWebAppIcon(app_id, purpose, sizes_px, scale_to_size_in_px,
+                           /*skip_icon_effects=*/true);
 
     if (icon_effects != apps::IconEffects::kNone) {
       base::test::TestFuture<apps::IconValuePtr> iv_with_icon_effects;
@@ -231,15 +233,14 @@
                                                   &result));
   }
 
-  void LoadIconFromWebApp(const std::string& app_id,
-                          apps::IconEffects icon_effects,
-                          gfx::ImageSkia& output_image_skia) {
+  gfx::ImageSkia LoadIconFromWebApp(const std::string& app_id,
+                                    apps::IconEffects icon_effects) {
     base::test::TestFuture<apps::IconValuePtr> future;
     apps::LoadIconFromWebApp(profile(), apps::IconType::kStandard, kSizeInDip,
                              app_id, icon_effects, future.GetCallback());
     auto icon = future.Take();
-    output_image_skia = icon->uncompressed;
-    EnsureRepresentationsLoaded(output_image_skia);
+    EnsureRepresentationsLoaded(icon->uncompressed);
+    return icon->uncompressed;
   }
 
   apps::IconValuePtr LoadCompressedIconBlockingFromWebApp(
@@ -295,18 +296,17 @@
 
   ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, sizes_px));
 
-  gfx::ImageSkia src_image_skia;
-  GenerateWebAppIcon(app_id, IconPurpose::ANY, sizes_px,
-                     {{1.0, kIconSize1}, {2.0, kIconSize2}}, src_image_skia);
+  gfx::ImageSkia src_image_skia =
+      GenerateWebAppIcon(app_id, IconPurpose::ANY, sizes_px,
+                         {{1.0, kIconSize1}, {2.0, kIconSize2}});
 
-  gfx::ImageSkia dst_image_skia;
   apps::IconEffects icon_effect = apps::IconEffects::kRoundCorners;
 
   icon_effect |= apps::IconEffects::kCrOsStandardIcon;
 
-  LoadIconFromWebApp(app_id, icon_effect, dst_image_skia);
+  gfx::ImageSkia dst = LoadIconFromWebApp(app_id, icon_effect);
 
-  VerifyIcon(src_image_skia, dst_image_skia);
+  VerifyIcon(src_image_skia, dst);
 }
 
 TEST_F(WebAppIconFactoryTest, LoadNonMaskableNonEffectCompressedIcon) {
@@ -406,21 +406,18 @@
 
   RegisterApp(std::move(web_app));
 
-  gfx::ImageSkia src_image_skia;
-  gfx::ImageSkia dst_image_skia;
-
   ASSERT_TRUE(
       icon_manager().HasIcons(app_id, IconPurpose::MASKABLE, {kIconSize2}));
 
-  GenerateWebAppIcon(app_id, IconPurpose::MASKABLE, {kIconSize2},
-                     {{1.0, kIconSize2}, {2.0, kIconSize2}}, src_image_skia);
+  gfx::ImageSkia src_image_skia =
+      GenerateWebAppIcon(app_id, IconPurpose::MASKABLE, {kIconSize2},
+                         {{1.0, kIconSize2}, {2.0, kIconSize2}});
 
-  LoadIconFromWebApp(app_id,
-                     apps::IconEffects::kRoundCorners |
-                         apps::IconEffects::kCrOsStandardBackground |
-                         apps::IconEffects::kCrOsStandardMask,
-                     dst_image_skia);
-  VerifyIcon(src_image_skia, dst_image_skia);
+  gfx::ImageSkia dst = LoadIconFromWebApp(
+      app_id, apps::IconEffects::kRoundCorners |
+                  apps::IconEffects::kCrOsStandardBackground |
+                  apps::IconEffects::kCrOsStandardMask);
+  VerifyIcon(src_image_skia, dst);
 }
 
 TEST_F(WebAppIconFactoryTest, LoadMaskableCompressedIcon) {
@@ -475,18 +472,17 @@
 
   ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, {kIconSize2}));
 
-  gfx::ImageSkia src_image_skia;
-  GenerateWebAppIcon(app_id, IconPurpose::ANY, {kIconSize2},
-                     {{1.0, kIconSize2}, {2.0, kIconSize2}}, src_image_skia);
+  gfx::ImageSkia src_image_skia =
+      GenerateWebAppIcon(app_id, IconPurpose::ANY, {kIconSize2},
+                         {{1.0, kIconSize2}, {2.0, kIconSize2}});
 
-  gfx::ImageSkia dst_image_skia;
   apps::IconEffects icon_effect = apps::IconEffects::kRoundCorners;
 
   icon_effect |= apps::IconEffects::kCrOsStandardIcon;
 
-  LoadIconFromWebApp(app_id, icon_effect, dst_image_skia);
+  gfx::ImageSkia dst = LoadIconFromWebApp(app_id, icon_effect);
 
-  VerifyIcon(src_image_skia, dst_image_skia);
+  VerifyIcon(src_image_skia, dst);
 }
 
 TEST_F(WebAppIconFactoryTest, LoadSmallMaskableIcon) {
@@ -507,18 +503,16 @@
 
   ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::MASKABLE, sizes_px));
 
-  gfx::ImageSkia src_image_skia;
-  GenerateWebAppIcon(app_id, IconPurpose::MASKABLE, sizes_px,
-                     {{1.0, kIconSize1}, {2.0, kIconSize1}}, src_image_skia);
+  gfx::ImageSkia src_image_skia =
+      GenerateWebAppIcon(app_id, IconPurpose::MASKABLE, sizes_px,
+                         {{1.0, kIconSize1}, {2.0, kIconSize1}});
 
-  gfx::ImageSkia dst_image_skia;
-  LoadIconFromWebApp(app_id,
-                     apps::IconEffects::kRoundCorners |
-                         apps::IconEffects::kCrOsStandardBackground |
-                         apps::IconEffects::kCrOsStandardMask,
-                     dst_image_skia);
+  gfx::ImageSkia dst = LoadIconFromWebApp(
+      app_id, apps::IconEffects::kRoundCorners |
+                  apps::IconEffects::kCrOsStandardBackground |
+                  apps::IconEffects::kCrOsStandardMask);
 
-  VerifyIcon(src_image_skia, dst_image_skia);
+  VerifyIcon(src_image_skia, dst);
 }
 
 TEST_F(WebAppIconFactoryTest, LoadExactSizeIcon) {
@@ -541,18 +535,17 @@
 
   ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, sizes_px));
 
-  gfx::ImageSkia src_image_skia;
-  GenerateWebAppIcon(app_id, IconPurpose::ANY, sizes_px,
-                     {{1.0, kIconSize2}, {2.0, kIconSize4}}, src_image_skia);
+  gfx::ImageSkia src_image_skia =
+      GenerateWebAppIcon(app_id, IconPurpose::ANY, sizes_px,
+                         {{1.0, kIconSize2}, {2.0, kIconSize4}});
 
-  gfx::ImageSkia dst_image_skia;
   apps::IconEffects icon_effect = apps::IconEffects::kRoundCorners;
 
   icon_effect |= apps::IconEffects::kCrOsStandardIcon;
 
-  LoadIconFromWebApp(app_id, icon_effect, dst_image_skia);
+  gfx::ImageSkia dst = LoadIconFromWebApp(app_id, icon_effect);
 
-  VerifyIcon(src_image_skia, dst_image_skia);
+  VerifyIcon(src_image_skia, dst);
 }
 
 TEST_F(WebAppIconFactoryTest, LoadIconFailed) {
@@ -575,13 +568,11 @@
   gfx::ImageSkia src_image_skia;
   LoadDefaultIcon(src_image_skia);
 
-  gfx::ImageSkia dst_image_skia;
-  LoadIconFromWebApp(
-      app_id,
-      apps::IconEffects::kRoundCorners | apps::IconEffects::kCrOsStandardIcon,
-      dst_image_skia);
+  gfx::ImageSkia dst =
+      LoadIconFromWebApp(app_id, apps::IconEffects::kRoundCorners |
+                                     apps::IconEffects::kCrOsStandardIcon);
 
-  VerifyIcon(src_image_skia, dst_image_skia);
+  VerifyIcon(src_image_skia, dst);
 }
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
@@ -1172,9 +1163,8 @@
 
   apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1},
                                            {2.0, kIconSize2}};
-  gfx::ImageSkia src_image_skia;
-  GenerateWebAppIcon(app_id, IconPurpose::ANY, sizes_px, scale_to_size_in_px,
-                     src_image_skia);
+  gfx::ImageSkia src_image_skia = GenerateWebAppIcon(
+      app_id, IconPurpose::ANY, sizes_px, scale_to_size_in_px);
 
   // Verify the icon reading and writing function in AppService for the
   // kStandard icon.
@@ -1231,9 +1221,9 @@
   VerifyCompressedIcon(
       src_data, *LoadIconFromIconKey(app_id, icon_key, IconType::kCompressed));
 
-  gfx::ImageSkia src_image_skia;
-  GenerateWebAppIcon(app_id, IconPurpose::ANY, sizes_px, scale_to_size_in_px,
-                     src_image_skia, /*skip_icon_effects=*/true);
+  gfx::ImageSkia src_image_skia = GenerateWebAppIcon(
+      app_id, IconPurpose::ANY, sizes_px, scale_to_size_in_px,
+      /*skip_icon_effects=*/true);
 
   // Verify the icon reading and writing function in AppService for the
   // kUncompressed icon.
@@ -1266,9 +1256,8 @@
 
   apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1},
                                            {2.0, kIconSize2}};
-  gfx::ImageSkia src_image_skia;
-  GenerateWebAppIcon(app_id, IconPurpose::ANY, sizes_px, scale_to_size_in_px,
-                     src_image_skia);
+  gfx::ImageSkia src_image_skia = GenerateWebAppIcon(
+      app_id, IconPurpose::ANY, sizes_px, scale_to_size_in_px);
 
   // Verify the icon reading and writing function in AppService for the
   // kStandard icon.
@@ -1337,9 +1326,9 @@
 
   VerifyCompressedIcon(src_data, *LoadIcon(app_id, IconType::kCompressed));
 
-  gfx::ImageSkia src_image_skia;
-  GenerateWebAppIcon(app_id, IconPurpose::ANY, sizes_px, scale_to_size_in_px,
-                     src_image_skia, /*skip_icon_effects=*/true);
+  gfx::ImageSkia src_image_skia = GenerateWebAppIcon(
+      app_id, IconPurpose::ANY, sizes_px, scale_to_size_in_px,
+      /*skip_icon_effects=*/true);
 
   // Verify the icon reading and writing function in AppService for the
   // kUncompressed icon.
@@ -1379,10 +1368,9 @@
 
   VerifyCompressedIcon(src_data, *LoadIcon(app_id, IconType::kCompressed));
 
-  gfx::ImageSkia src_image_skia;
-  GenerateWebAppIcon(app_id, IconPurpose::MASKABLE, {kIconSize2},
-                     scale_to_size_in_px, src_image_skia,
-                     /*skip_icon_effects=*/true);
+  gfx::ImageSkia src_image_skia = GenerateWebAppIcon(
+      app_id, IconPurpose::MASKABLE, {kIconSize2}, scale_to_size_in_px,
+      /*skip_icon_effects=*/true);
 
   // Verify the icon reading and writing function in AppService for the
   // kUncompressed icon.
@@ -1415,9 +1403,8 @@
 
   apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize2},
                                            {2.0, kIconSize2}};
-  gfx::ImageSkia src_image_skia;
-  GenerateWebAppIcon(app_id, IconPurpose::MASKABLE, {kIconSize2},
-                     scale_to_size_in_px, src_image_skia);
+  gfx::ImageSkia src_image_skia = GenerateWebAppIcon(
+      app_id, IconPurpose::MASKABLE, {kIconSize2}, scale_to_size_in_px);
 
   // Verify the icon reading and writing function in AppService for the
   // kStandard icon.
@@ -1456,9 +1443,8 @@
 
   apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1},
                                            {2.0, kIconSize2}};
-  gfx::ImageSkia src_image_skia1;
-  GenerateWebAppIcon(app_id, IconPurpose::ANY, sizes_px, scale_to_size_in_px,
-                     src_image_skia1);
+  gfx::ImageSkia src_image_skia1 = GenerateWebAppIcon(
+      app_id, IconPurpose::ANY, sizes_px, scale_to_size_in_px);
 
   // Load the kStandard icon to generate the icon file in the AppService
   // directory.
@@ -1474,9 +1460,8 @@
   // Update the icon
   const std::vector<SkColor> colors2{SK_ColorRED, SK_ColorBLUE};
   WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors2);
-  gfx::ImageSkia src_image_skia2;
-  GenerateWebAppIcon(app_id, IconPurpose::ANY, sizes_px, scale_to_size_in_px,
-                     src_image_skia2);
+  gfx::ImageSkia src_image_skia2 = GenerateWebAppIcon(
+      app_id, IconPurpose::ANY, sizes_px, scale_to_size_in_px);
 
   UpdateIcon(app_id, icon_key);
 
@@ -1519,12 +1504,10 @@
 
   apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1},
                                            {2.0, kIconSize2}};
-  gfx::ImageSkia src_image_skia1;
-  GenerateWebAppIcon(app_id1, IconPurpose::ANY, sizes_px, scale_to_size_in_px,
-                     src_image_skia1);
-  gfx::ImageSkia src_image_skia2;
-  GenerateWebAppIcon(app_id2, IconPurpose::ANY, sizes_px, scale_to_size_in_px,
-                     src_image_skia2);
+  gfx::ImageSkia src_image_skia1 = GenerateWebAppIcon(
+      app_id1, IconPurpose::ANY, sizes_px, scale_to_size_in_px);
+  gfx::ImageSkia src_image_skia2 = GenerateWebAppIcon(
+      app_id2, IconPurpose::ANY, sizes_px, scale_to_size_in_px);
 
   // Load the kStandard icon to generate the icon files in the AppService
   // directory.
@@ -1546,12 +1529,10 @@
   WriteIcons(app_id1, {IconPurpose::ANY}, sizes_px, colors3);
   WriteIcons(app_id2, {IconPurpose::ANY}, sizes_px, colors4);
 
-  gfx::ImageSkia src_image_skia3;
-  GenerateWebAppIcon(app_id1, IconPurpose::ANY, sizes_px, scale_to_size_in_px,
-                     src_image_skia3);
-  gfx::ImageSkia src_image_skia4;
-  GenerateWebAppIcon(app_id2, IconPurpose::ANY, sizes_px, scale_to_size_in_px,
-                     src_image_skia4);
+  gfx::ImageSkia src_image_skia3 = GenerateWebAppIcon(
+      app_id1, IconPurpose::ANY, sizes_px, scale_to_size_in_px);
+  gfx::ImageSkia src_image_skia4 = GenerateWebAppIcon(
+      app_id2, IconPurpose::ANY, sizes_px, scale_to_size_in_px);
 
   // Uninstall and reinstall apps
   ReinstallApps({app_id1, app_id2});
diff --git a/chrome/browser/ash/BUILD.gn b/chrome/browser/ash/BUILD.gn
index b098aa7..3072606e2 100644
--- a/chrome/browser/ash/BUILD.gn
+++ b/chrome/browser/ash/BUILD.gn
@@ -1162,6 +1162,8 @@
     "file_manager/uma_enums.gen.h",
     "file_manager/url_util.cc",
     "file_manager/url_util.h",
+    "file_manager/virtual_file_tasks.cc",
+    "file_manager/virtual_file_tasks.h",
     "file_manager/volume.cc",
     "file_manager/volume.h",
     "file_manager/volume_manager.cc",
@@ -4496,6 +4498,8 @@
     "platform_keys/platform_keys_service_test_util.h",
     "plugin_vm/fake_plugin_vm_features.cc",
     "plugin_vm/fake_plugin_vm_features.h",
+    "plugin_vm/mock_plugin_vm_manager.cc",
+    "plugin_vm/mock_plugin_vm_manager.h",
     "plugin_vm/plugin_vm_test_helper.cc",
     "plugin_vm/plugin_vm_test_helper.h",
     "policy/arc/fake_android_management_client.cc",
@@ -5164,6 +5168,7 @@
     "file_manager/trash_unittest_base.h",
     "file_manager/uma_enums_unittest.cc",
     "file_manager/url_util_unittest.cc",
+    "file_manager/virtual_file_tasks_unittest.cc",
     "file_manager/volume_manager_unittest.cc",
     "file_suggest/file_suggest_keyed_service_unittest.cc",
     "file_suggest/item_suggest_cache_unittest.cc",
@@ -5419,8 +5424,6 @@
     "phonehub/camera_roll_download_manager_impl_unittest.cc",
     "platform_keys/key_permissions/arc_key_permissions_manager_delegate_unittest.cc",
     "platform_keys/key_permissions/key_permissions_service_impl_unittest.cc",
-    "plugin_vm/mock_plugin_vm_manager.cc",
-    "plugin_vm/mock_plugin_vm_manager.h",
     "plugin_vm/plugin_vm_features_unittest.cc",
     "plugin_vm/plugin_vm_files_unittest.cc",
     "plugin_vm/plugin_vm_installer_unittest.cc",
diff --git a/chrome/browser/ash/arc/vmm/arc_system_state_observation.cc b/chrome/browser/ash/arc/vmm/arc_system_state_observation.cc
index cefb6a43..3b789f9 100644
--- a/chrome/browser/ash/arc/vmm/arc_system_state_observation.cc
+++ b/chrome/browser/ash/arc/vmm/arc_system_state_observation.cc
@@ -49,6 +49,7 @@
   // ARC system or app is active.
   if (!should_throttle) {
     last_peace_timestamp_.reset();
+    DVLOG(1) << "ARC is active, reset peace timestamp.";
     if (!active_callback_.is_null()) {
       active_callback_.Run();
     }
@@ -60,6 +61,8 @@
   if (arc_connected_) {
     // ARC system and app is not active.
     last_peace_timestamp_ = base::Time::Now();
+    DVLOG(1) << "ARC is not active, time recording start at "
+             << last_peace_timestamp_.value();
   }
 }
 
diff --git a/chrome/browser/ash/arc/vmm/arc_vmm_manager.cc b/chrome/browser/ash/arc/vmm/arc_vmm_manager.cc
index 64fd4ee..62566f6 100644
--- a/chrome/browser/ash/arc/vmm/arc_vmm_manager.cc
+++ b/chrome/browser/ash/arc/vmm/arc_vmm_manager.cc
@@ -104,6 +104,7 @@
     LOG(ERROR) << "Failed to SetSwapState, ARCVM not enabled or connected.";
     return;
   }
+  DVLOG(1) << "SetSwapState " << static_cast<int>(state);
   vm_tools::concierge::SwapOperation op;
   switch (state) {
     case SwapState::ENABLE:
@@ -191,6 +192,8 @@
     return;
   }
 
+  DVLOG(1) << "SendSwapRequest " << static_cast<int>(operation)
+           << " to concierge.";
   vm_tools::concierge::SwapVmRequest request;
   request.set_name(kArcVmName);
   request.set_owner_id(user_id_hash_);
@@ -220,6 +223,8 @@
     return;
   }
 
+  DVLOG(1) << "SendAggressiveBalloon state change " << enable
+           << " request to concierge";
   vm_tools::concierge::AggressiveBalloonRequest request;
   request.set_name(kArcVmName);
   request.set_owner_id(user_id_hash_);
@@ -251,6 +256,8 @@
   // Trim ARCVM memory before enable vmm swap in order to squeeze the vm
   // memory. Send enable operation if trim success.
   DCHECK(!trim_call_.is_null());
+  DVLOG(1) << "ShrinkArcVmMemoryAndEnableSwap with request "
+           << static_cast<int>(requested_operation);
   trim_call_.Run(
       base::BindOnce(
           [](base::OnceClosure success_closure, bool success,
diff --git a/chrome/browser/ash/arc/vmm/arc_vmm_swap_scheduler.cc b/chrome/browser/ash/arc/vmm/arc_vmm_swap_scheduler.cc
index b4bf5cc..ef6fb062 100644
--- a/chrome/browser/ash/arc/vmm/arc_vmm_swap_scheduler.cc
+++ b/chrome/browser/ash/arc/vmm/arc_vmm_swap_scheduler.cc
@@ -96,6 +96,9 @@
     if (!last_swap_out_time.is_null()) {
       auto past = base::Time::Now() - last_swap_out_time;
       if (past < minimum_swapout_interval_) {
+        DVLOG(1) << "Swappable checking be throttled due to last swap on "
+                 << last_swap_out_time
+                 << " is not meet time interval requirement.";
         return;
       }
     }
diff --git a/chrome/browser/ash/crostini/crostini_util.cc b/chrome/browser/ash/crostini/crostini_util.cc
index 8c9b62e4..069d2c2 100644
--- a/chrome/browser/ash/crostini/crostini_util.cc
+++ b/chrome/browser/ash/crostini/crostini_util.cc
@@ -30,6 +30,7 @@
 #include "chrome/browser/ash/guest_os/guest_os_registry_service_factory.h"
 #include "chrome/browser/ash/guest_os/guest_os_session_tracker.h"
 #include "chrome/browser/ash/guest_os/guest_os_share_path.h"
+#include "chrome/browser/ash/guest_os/guest_os_terminal.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/ash/shelf/app_service/app_service_app_window_crostini_tracker.h"
@@ -104,26 +105,44 @@
 
 void OnSharePathForLaunchApplication(
     Profile* profile,
-    const std::string& desktop_file_id,
+    const std::string& app_id,
     guest_os::GuestOsRegistryService::Registration registration,
+    const guest_os::GuestId& container_id,
     int64_t display_id,
     const std::vector<std::string>& args,
     crostini::CrostiniSuccessCallback callback,
     bool success,
     const std::string& failure_reason) {
   if (!success) {
-    return OnLaunchFailed(desktop_file_id, std::move(callback),
-                          "Failed to share paths to launch " + desktop_file_id +
-                              ": " + failure_reason,
-                          CrostiniResult::SHARE_PATHS_FAILED);
+    return OnLaunchFailed(
+        app_id, std::move(callback),
+        "Failed to share paths to launch " + app_id + ": " + failure_reason,
+        CrostiniResult::SHARE_PATHS_FAILED);
   }
-  const guest_os::GuestId guest_id(registration.VmType(), registration.VmName(),
-                                   registration.ContainerName());
+
+  if (registration.Terminal()) {
+    // TODO(crbug.com/853560): This could be improved by using garcon
+    // DesktopFile::GenerateArgvWithFiles().
+    std::vector<std::string> terminal_args = {
+        registration.ExecutableFileName()};
+    terminal_args.insert(terminal_args.end(), args.begin(), args.end());
+    guest_os::LaunchTerminal(profile, display_id, container_id,
+                             /*cwd=*/std::string(), terminal_args);
+    OnApplicationLaunched(app_id, std::move(callback),
+                          crostini::CrostiniResult::SUCCESS, true,
+                          std::string());
+    // The spinner for the app may start, but since terminal will launch rather
+    // that the GUI app with `app_id`, we must close the spinner.
+    if (auto* chrome_controller = ChromeShelfController::instance()) {
+      chrome_controller->GetShelfSpinnerController()->CloseSpinner(app_id);
+    }
+    return;
+  }
+
   guest_os::launcher::LaunchApplication(
-      profile, guest_id, registration.DesktopFileId(), args,
+      profile, container_id, registration.DesktopFileId(), args,
       registration.IsScaled(),
-      base::BindOnce(OnApplicationLaunched, desktop_file_id,
-                     std::move(callback),
+      base::BindOnce(OnApplicationLaunched, app_id, std::move(callback),
                      crostini::CrostiniResult::UNKNOWN_ERROR));
 }
 
@@ -131,6 +150,7 @@
     Profile* profile,
     const std::string& app_id,
     guest_os::GuestOsRegistryService::Registration registration,
+    const guest_os::GuestId& container_id,
     int64_t display_id,
     const std::vector<LaunchArg>& args,
     crostini::CrostiniSuccessCallback callback) {
@@ -189,7 +209,7 @@
       vm_name, vm_info->info.seneschal_server_handle(),
       std::move(paths_to_share),
       base::BindOnce(OnSharePathForLaunchApplication, profile, app_id,
-                     std::move(registration), display_id,
+                     std::move(registration), container_id, display_id,
                      std::move(launch_args), std::move(callback)));
 }
 
@@ -245,7 +265,7 @@
     Profile* profile,
     const std::string& app_id,
     guest_os::GuestOsRegistryService::Registration registration,
-    const guest_os::GuestId container_id,
+    const guest_os::GuestId& container_id,
     int64_t display_id,
     const std::vector<LaunchArg>& args,
     CrostiniSuccessCallback callback) {
@@ -263,7 +283,8 @@
       base::BindOnce(
           [](Profile* profile, const std::string& app_id,
              guest_os::GuestOsRegistryService::Registration registration,
-             int64_t display_id, const std::vector<LaunchArg> args,
+             const guest_os::GuestId& container_id, int64_t display_id,
+             const std::vector<LaunchArg> args,
              crostini::CrostiniSuccessCallback callback,
              crostini::CrostiniResult result) {
             if (result != crostini::CrostiniResult::SUCCESS) {
@@ -276,10 +297,11 @@
             }
 
             LaunchApplication(profile, app_id, std::move(registration),
-                              display_id, args, std::move(callback));
+                              container_id, display_id, args,
+                              std::move(callback));
           },
-          profile, app_id, std::move(registration), display_id, args,
-          std::move(callback)));
+          profile, app_id, std::move(registration), container_id, display_id,
+          args, std::move(callback)));
 
   base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
       FROM_HERE, base::BindOnce(&AddSpinner, restart_id, app_id, profile),
diff --git a/chrome/browser/ash/extensions/file_manager/system_notification_manager.cc b/chrome/browser/ash/extensions/file_manager/system_notification_manager.cc
index f8ad2a6..926c0eb 100644
--- a/chrome/browser/ash/extensions/file_manager/system_notification_manager.cc
+++ b/chrome/browser/ash/extensions/file_manager/system_notification_manager.cc
@@ -513,10 +513,11 @@
   if (button_index.has_value()) {
     VLOG(1) << "Click on button #" << *button_index;
     DCHECK_EQ(*button_index, 0);
+    drive_settings_open_count_++;
     chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(
         profile_, chromeos::settings::mojom::kGoogleDriveSubpagePath);
   } else {
-    VLOG(1) << "Click on notification";
+    VLOG(1) << "Click on notification body";
   }
 
   GetNotificationDisplayService()->Close(NotificationHandler::Type::TRANSIENT,
diff --git a/chrome/browser/ash/extensions/file_manager/system_notification_manager.h b/chrome/browser/ash/extensions/file_manager/system_notification_manager.h
index 2a7412d..c1ae1743 100644
--- a/chrome/browser/ash/extensions/file_manager/system_notification_manager.h
+++ b/chrome/browser/ash/extensions/file_manager/system_notification_manager.h
@@ -7,6 +7,7 @@
 
 #include "ash/public/cpp/notification_utils.h"
 #include "base/functional/callback_forward.h"
+#include "base/gtest_prod_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/app/vector_icons/vector_icons.h"
@@ -294,8 +295,15 @@
   using BulkPinStage = file_manager_private::BulkPinStage;
   BulkPinStage bulk_pin_stage_ = BulkPinStage::BULK_PIN_STAGE_NONE;
 
+  // Number of times the Google Drive settings page was opened from a system
+  // notification. Used in tests.
+  int drive_settings_open_count_ = 0;
+
   // base::WeakPtr{this} factory.
   base::WeakPtrFactory<SystemNotificationManager> weak_ptr_factory_{this};
+
+  FRIEND_TEST_ALL_PREFIXES(SystemNotificationManagerTest,
+                           BulkPinningNotification);
 };
 
 }  // namespace file_manager
diff --git a/chrome/browser/ash/extensions/file_manager/system_notification_manager_unittest.cc b/chrome/browser/ash/extensions/file_manager/system_notification_manager_unittest.cc
index e077ea0b..827f672 100644
--- a/chrome/browser/ash/extensions/file_manager/system_notification_manager_unittest.cc
+++ b/chrome/browser/ash/extensions/file_manager/system_notification_manager_unittest.cc
@@ -4,11 +4,15 @@
 
 #include "chrome/browser/ash/extensions/file_manager/system_notification_manager.h"
 
+#include <set>
+#include <unordered_map>
+
 #include "ash/components/arc/arc_prefs.h"
 #include "ash/webui/file_manager/url_constants.h"
 #include "base/files/file.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/raw_ptr.h"
+#include "base/strings/string_piece.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
@@ -33,16 +37,37 @@
 #include "storage/browser/quota/quota_manager_proxy.h"
 #include "storage/browser/test/async_file_test_helper.h"
 #include "storage/browser/test/test_file_system_context.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/public/common/storage_key/storage_key.h"
 
 namespace file_manager {
+namespace {
 
 namespace file_manager_private = extensions::api::file_manager_private;
 
-// Struct to reference notification strings for testing.
-struct TestNotificationStrings {
+using ash::DeviceType;
+using ash::disks::Disk;
+using base::BindOnce;
+using base::FilePath;
+using extensions::Event;
+using file_manager_private::DriveSyncErrorEvent;
+using file_manager_private::FileTransferStatus;
+using file_manager_private::MountCompletedEvent;
+using file_manager_private::ToString;
+using message_center::NotificationDelegate;
+using testing::ElementsAre;
+
+using enum extensions::events::HistogramValue;
+using enum file_manager_private::BulkPinStage;
+using enum file_manager_private::DriveSyncErrorType;
+using enum file_manager_private::MountCompletedEventType;
+using enum file_manager_private::MountError;
+using enum file_manager_private::TransferState;
+
+// Strings that would be seen on a notification.
+struct Strings {
   std::u16string title;
   std::u16string message;
   std::vector<std::u16string> buttons;
@@ -61,14 +86,14 @@
       NotificationHandler::Type notification_type,
       const message_center::Notification& notification,
       std::unique_ptr<NotificationCommon::Metadata> metadata) override {
-    TestNotificationStrings strings;
+    Strings strings;
     notification_ids_.insert(notification.id());
     strings.title = notification.title();
     strings.message = notification.message();
     for (const message_center::ButtonInfo& button : notification.buttons()) {
       strings.buttons.push_back(button.title);
     }
-    notifications_[notification.id()] = strings;
+    notifications_[notification.id()] = std::move(strings);
     delegates_[notification.id()] = notification.delegate();
   }
 
@@ -83,34 +108,48 @@
     std::move(callback).Run(notification_ids_, /*supports_sync=*/true);
   }
 
-  // Helper to get the strings that would have bee seen on the notification.
-  TestNotificationStrings GetNotificationStringsById(
-      const std::string& notification_id) {
-    TestNotificationStrings result;
-    auto strings = notifications_.find(notification_id);
-    if (strings != notifications_.end()) {
-      result = strings->second;
+  // Gets the strings that would have been seen on the notification.
+  Strings GetStrings(const std::string& notification_id) {
+    const auto it = notifications_.find(notification_id);
+    if (it == notifications_.end()) {
+      LOG(ERROR) << "Cannot find notification " << notification_id;
+      return {};
     }
-    return result;
+
+    return it->second;
   }
 
-  void ClickButtonIndexById(const std::string& notification_id,
-                            int button_index) {
-    absl::optional<int> index(button_index);
-    absl::optional<std::u16string> empty_reply(u"");
-
-    const auto& notification = delegates_.find(notification_id);
-    if (notification != delegates_.end()) {
-      notification->second->Click(index, empty_reply);
+  // Clicks a notification button.
+  void ClickButton(const std::string& notification_id, int button_index) {
+    const auto it = delegates_.find(notification_id);
+    if (it == delegates_.end()) {
+      LOG(ERROR) << "Cannot find delegate " << notification_id;
+      return;
     }
+
+    it->second->Click(button_index, absl::nullopt);
+  }
+
+  // Clicks a notification body.
+  void ClickNotification(const std::string& notification_id) {
+    const auto it = delegates_.find(notification_id);
+    if (it == delegates_.end()) {
+      LOG(ERROR) << "Cannot find delegate " << notification_id;
+      return;
+    }
+
+    it->second->Click(absl::nullopt, absl::nullopt);
   }
 
  private:
+  // Notification IDs.
   std::set<std::string> notification_ids_;
-  // Used to map a notification id to its displayed title and message.
-  std::map<std::string, TestNotificationStrings> notifications_;
-  // Used to map a notification id to its delegate to verify click handlers.
-  std::map<std::string, scoped_refptr<message_center::NotificationDelegate>>
+
+  // Maps a notification ID to its displayed title and message.
+  std::unordered_map<std::string, Strings> notifications_;
+
+  // Maps a notification ID to its delegate to verify click handlers.
+  std::unordered_map<std::string, scoped_refptr<NotificationDelegate>>
       delegates_;
 };
 
@@ -138,29 +177,30 @@
   bool IsExternalStorageDisabled() override { return true; }
 };
 
+constexpr char kDevicePath[] = "/device/test";
+constexpr char kMountPath[] = "/mnt/media/sda1";
+std::u16string kRemovableDeviceTitle = u"Removable device detected";
+
+}  // namespace
+
 class SystemNotificationManagerTest
     : public io_task::IOTaskController::Observer,
       public ::testing::Test {
  public:
-  SystemNotificationManagerTest() {}
-
   void SetUp() override {
     testing::Test::SetUp();
-    profile_manager_ = std::make_unique<TestingProfileManager>(
-        TestingBrowserProcess::GetGlobal());
-    ASSERT_TRUE(profile_manager_->SetUp());
-    profile_ = profile_manager_->CreateTestingProfile("testing_profile");
-    notification_display_service_ =
-        reinterpret_cast<NotificationDisplayServiceImpl*>(
-            NotificationDisplayServiceFactory::GetForProfile(profile_));
+    ASSERT_TRUE(profile_manager_.SetUp());
+    profile_ = profile_manager_.CreateTestingProfile("testing_profile");
+    display_service_ = static_cast<NotificationDisplayServiceImpl*>(
+        NotificationDisplayServiceFactory::GetForProfile(profile_));
     auto bridge =
         std::make_unique<TestNotificationPlatformBridgeDelegator>(profile_);
-    notification_platform_bridge = bridge.get();
-    notification_display_service_
-        ->SetNotificationPlatformBridgeDelegatorForTesting(std::move(bridge));
+    bridge_ = bridge.get();
+    display_service_->SetNotificationPlatformBridgeDelegatorForTesting(
+        std::move(bridge));
     notification_manager_ =
         std::make_unique<SystemNotificationManager>(profile_);
-    device_event_router_ = std::make_unique<DeviceEventRouterImpl>(
+    event_router_ = std::make_unique<DeviceEventRouterImpl>(
         notification_manager_.get(), profile_);
 
     VolumeManagerFactory::GetInstance()->SetTestingFactory(
@@ -171,7 +211,7 @@
               &disk_mount_manager_, nullptr,
               VolumeManager::GetMtpStorageInfoCallback()));
         }));
-    auto* volume_manager = VolumeManager::Get(profile_);
+    VolumeManager* const volume_manager = VolumeManager::Get(profile_);
 
     // SystemNotificationManager needs the IOTaskController to be able to cancel
     // the task.
@@ -181,72 +221,38 @@
 
     ASSERT_TRUE(dir_.CreateUniqueTempDir());
     ASSERT_TRUE(dir_.GetPath().IsAbsolute());
-    file_system_context = storage::CreateFileSystemContextForTesting(
+    file_system_context_ = storage::CreateFileSystemContextForTesting(
         /*quota_manager_proxy=*/nullptr, dir_.GetPath());
 
     volume_manager->AddVolumeForTesting(
         CreateTestFile("volume/").path(), VOLUME_TYPE_DOWNLOADS_DIRECTORY,
-        ash::DeviceType::kUnknown, false /* read only */);
+        DeviceType::kUnknown, false /* read only */);
   }
 
   void TearDown() override {
     io_task_controller->RemoveObserver(this);
-
-    profile_manager_->DeleteAllTestingProfiles();
     profile_ = nullptr;
-    profile_manager_.reset();
+    profile_manager_.DeleteAllTestingProfiles();
   }
 
   // IOTaskController::Observer override:
   // In production code the observer is EventRouter which forwards the status to
   // SystemNotificationManager.
   void OnIOTaskStatus(const io_task::ProgressStatus& status) override {
-    task_statuses[status.task_id].push_back(status.state);
+    task_statuses_[status.task_id].push_back(status.state);
     notification_manager_->HandleIOTaskProgress(status);
   }
 
-  TestingProfile* GetProfile() { return profile_; }
-
-  DeviceEventRouterImpl* GetDeviceEventRouter() {
-    return device_event_router_.get();
-  }
-
-  SystemNotificationManager* GetSystemNotificationManager() {
-    return notification_manager_.get();
-  }
-
-  NotificationDisplayService* GetNotificationDisplayService() {
-    return static_cast<NotificationDisplayService*>(
-        notification_display_service_);
-  }
-
   size_t GetNotificationCount() {
-    auto* notification_display_service = GetNotificationDisplayService();
-    notification_display_service->GetDisplayed(
-        base::BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
-                       weak_ptr_factory_.GetWeakPtr()));
-    return notification_count;
+    display_service_->GetDisplayed(
+        BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+                 weak_ptr_factory_.GetWeakPtr()));
+    return notification_count_;
   }
 
   void GetNotificationsCallback(std::set<std::string> displayed_notifications,
                                 bool supports_synchronization) {
-    notification_count = displayed_notifications.size();
-  }
-
-  // Creates a disk instance with |device_path| and |mount_path| for testing.
-  std::unique_ptr<ash::disks::Disk> CreateTestDisk(
-      const std::string& device_path,
-      const std::string& mount_path,
-      bool is_read_only_hardware,
-      bool is_mounted) {
-    return ash::disks::Disk::Builder()
-        .SetDevicePath(device_path)
-        .SetMountPath(mount_path)
-        .SetStorageDevicePath(device_path)
-        .SetIsReadOnlyHardware(is_read_only_hardware)
-        .SetFileSystemType("vfat")
-        .SetIsMounted(is_mounted)
-        .Build();
+    notification_count_ = displayed_notifications.size();
   }
 
   // Creates a file or directory to use in the test.
@@ -255,79 +261,70 @@
         blink::StorageKey::CreateFromStringForTesting(
             ash::file_manager::kChromeUIFileManagerURL);
 
-    auto file_url = file_system_context->CreateCrackedFileSystemURL(
+    auto file_url = file_system_context_->CreateCrackedFileSystemURL(
         storage_key, storage::kFileSystemTypeTest,
-        base::FilePath::FromUTF8Unsafe(path));
+        FilePath::FromUTF8Unsafe(path));
 
     if (base::EndsWith(path, "/")) {
       CHECK(base::File::FILE_OK ==
             storage::AsyncFileTestHelper::CreateDirectory(
-                file_system_context.get(), file_url));
+                file_system_context_.get(), file_url));
     } else {
       CHECK(base::File::FILE_OK == storage::AsyncFileTestHelper::CreateFile(
-                                       file_system_context.get(), file_url));
+                                       file_system_context_.get(), file_url));
     }
 
     return file_url;
   }
 
- private:
   content::BrowserTaskEnvironment task_environment_;
   file_manager::FakeDiskMountManager disk_mount_manager_;
-  std::unique_ptr<TestingProfileManager> profile_manager_;
+  TestingProfileManager profile_manager_{TestingBrowserProcess::GetGlobal()};
   // Externally owned raw pointers:
   // profile_ is owned by TestingProfileManager.
   raw_ptr<TestingProfile, ExperimentalAsh> profile_;
   // notification_display_service is owned by NotificationDisplayServiceFactory.
-  raw_ptr<NotificationDisplayServiceImpl, ExperimentalAsh>
-      notification_display_service_;
+  raw_ptr<NotificationDisplayServiceImpl, ExperimentalAsh> display_service_;
   std::unique_ptr<SystemNotificationManager> notification_manager_;
-  std::unique_ptr<DeviceEventRouterImpl> device_event_router_;
+  std::unique_ptr<DeviceEventRouterImpl> event_router_;
 
   // Temporary directory used to test IOTask progress.
   base::ScopedTempDir dir_;
 
- public:
-  size_t notification_count;
+  size_t notification_count_ = 0;
+
   // notification_platform_bridge is owned by NotificationDisplayService.
-  raw_ptr<TestNotificationPlatformBridgeDelegator, ExperimentalAsh>
-      notification_platform_bridge;
+  raw_ptr<TestNotificationPlatformBridgeDelegator, ExperimentalAsh> bridge_;
 
   // Used for tests with IOTask:
   raw_ptr<io_task::IOTaskController, ExperimentalAsh> io_task_controller;
-  scoped_refptr<storage::FileSystemContext> file_system_context;
+  scoped_refptr<storage::FileSystemContext> file_system_context_;
 
   // Keep track of the task state transitions.
-  std::map<io_task::IOTaskId, std::vector<io_task::State>> task_statuses;
+  std::unordered_map<io_task::IOTaskId, std::vector<io_task::State>>
+      task_statuses_;
 
   base::WeakPtrFactory<SystemNotificationManagerTest> weak_ptr_factory_{this};
 };
 
-constexpr char kDevicePath[] = "/device/test";
-constexpr char kMountPath[] = "/mnt/media/sda1";
-std::u16string kRemovableDeviceTitle = u"Removable device detected";
-
 TEST_F(SystemNotificationManagerTest, ExternalStorageDisabled) {
   base::HistogramTester histogram_tester;
   // Send a removable volume mounted event.
-  GetDeviceEventRouter()->OnDeviceAdded(kDevicePath);
+  event_router_->OnDeviceAdded(kDevicePath);
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings;
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById("disabled");
+  Strings strings = bridge_->GetStrings("disabled");
   // Check: the expected strings match.
   std::u16string kExternalStorageDisabledMesssage =
       u"Sorry, your administrator has disabled external storage on your "
       u"account.";
-  EXPECT_EQ(notification_strings.title, kRemovableDeviceTitle);
-  EXPECT_EQ(notification_strings.message, kExternalStorageDisabledMesssage);
+  EXPECT_EQ(strings.title, kRemovableDeviceTitle);
+  EXPECT_EQ(strings.message, kExternalStorageDisabledMesssage);
   // Check that the correct UMA was emitted.
   histogram_tester.ExpectUniqueSample(
       kNotificationShowHistogramName,
@@ -339,23 +336,20 @@
 
 TEST_F(SystemNotificationManagerTest, FormatStart) {
   base::HistogramTester histogram_tester;
-  GetDeviceEventRouter()->OnFormatStarted(kDevicePath, kDeviceLabel,
-                                          /*success=*/true);
+  event_router_->OnFormatStarted(kDevicePath, kDeviceLabel,
+                                 /*success=*/true);
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings;
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById("format_start");
+  Strings strings = bridge_->GetStrings("format_start");
   // Check: the expected strings match.
   std::u16string kFormatStartMesssage = u"Formatting MyUSB\x2026";
-  EXPECT_EQ(notification_strings.title, kFormatTitle);
-  EXPECT_EQ(notification_strings.message, kFormatStartMesssage);
+  EXPECT_EQ(strings.title, kFormatTitle);
+  EXPECT_EQ(strings.message, kFormatStartMesssage);
   histogram_tester.ExpectUniqueSample(kNotificationShowHistogramName,
                                       DeviceNotificationUmaType::FORMAT_START,
                                       1);
@@ -363,24 +357,20 @@
 
 TEST_F(SystemNotificationManagerTest, FormatSuccess) {
   base::HistogramTester histogram_tester;
-  GetDeviceEventRouter()->OnFormatCompleted(kDevicePath, kDeviceLabel,
-                                            /*success=*/true);
+  event_router_->OnFormatCompleted(kDevicePath, kDeviceLabel,
+                                   /*success=*/true);
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings;
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          "format_success");
+  Strings strings = bridge_->GetStrings("format_success");
   // Check: the expected strings match.
   std::u16string kFormatSuccessMesssage = u"Formatted MyUSB";
-  EXPECT_EQ(notification_strings.title, kFormatTitle);
-  EXPECT_EQ(notification_strings.message, kFormatSuccessMesssage);
+  EXPECT_EQ(strings.title, kFormatTitle);
+  EXPECT_EQ(strings.message, kFormatSuccessMesssage);
   histogram_tester.ExpectUniqueSample(kNotificationShowHistogramName,
                                       DeviceNotificationUmaType::FORMAT_SUCCESS,
                                       1);
@@ -388,23 +378,20 @@
 
 TEST_F(SystemNotificationManagerTest, FormatFail) {
   base::HistogramTester histogram_tester;
-  GetDeviceEventRouter()->OnFormatCompleted(kDevicePath, kDeviceLabel,
-                                            /*success=*/false);
+  event_router_->OnFormatCompleted(kDevicePath, kDeviceLabel,
+                                   /*success=*/false);
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings;
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById("format_fail");
+  Strings strings = bridge_->GetStrings("format_fail");
   // Check: the expected strings match.
   std::u16string kFormatFailedMesssage = u"Could not format MyUSB";
-  EXPECT_EQ(notification_strings.title, kFormatTitle);
-  EXPECT_EQ(notification_strings.message, kFormatFailedMesssage);
+  EXPECT_EQ(strings.title, kFormatTitle);
+  EXPECT_EQ(strings.message, kFormatFailedMesssage);
   histogram_tester.ExpectUniqueSample(kNotificationShowHistogramName,
                                       DeviceNotificationUmaType::FORMAT_FAIL,
                                       1);
@@ -415,24 +402,20 @@
 
 TEST_F(SystemNotificationManagerTest, PartitionFail) {
   base::HistogramTester histogram_tester;
-  GetDeviceEventRouter()->OnPartitionCompleted(kDevicePath, kPartitionLabel,
-                                               /*success=*/false);
+  event_router_->OnPartitionCompleted(kDevicePath, kPartitionLabel,
+                                      /*success=*/false);
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings;
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          "partition_fail");
+  Strings strings = bridge_->GetStrings("partition_fail");
   // Check: the expected strings match.
   std::u16string kPartitionFailMesssage = u"Could not format OEM";
-  EXPECT_EQ(notification_strings.title, kPartitionTitle);
-  EXPECT_EQ(notification_strings.message, kPartitionFailMesssage);
+  EXPECT_EQ(strings.title, kPartitionTitle);
+  EXPECT_EQ(strings.message, kPartitionFailMesssage);
   histogram_tester.ExpectUniqueSample(kNotificationShowHistogramName,
                                       DeviceNotificationUmaType::PARTITION_FAIL,
                                       1);
@@ -440,23 +423,19 @@
 
 TEST_F(SystemNotificationManagerTest, RenameFail) {
   base::HistogramTester histogram_tester;
-  GetDeviceEventRouter()->OnRenameCompleted(kDevicePath, kPartitionLabel,
-                                            /*success=*/false);
+  event_router_->OnRenameCompleted(kDevicePath, kPartitionLabel,
+                                   /*success=*/false);
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings;
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById("rename_fail");
+  Strings strings = bridge_->GetStrings("rename_fail");
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, u"Renaming failed");
-  EXPECT_EQ(notification_strings.message,
-            u"Aw, Snap! There was an error during renaming.");
+  EXPECT_EQ(strings.title, u"Renaming failed");
+  EXPECT_EQ(strings.message, u"Aw, Snap! There was an error during renaming.");
   // Check that the correct UMA was emitted.
   histogram_tester.ExpectUniqueSample(kNotificationShowHistogramName,
                                       DeviceNotificationUmaType::RENAME_FAIL,
@@ -465,25 +444,27 @@
 
 TEST_F(SystemNotificationManagerTest, DeviceHardUnplugged) {
   base::HistogramTester histogram_tester;
-  std::unique_ptr<ash::disks::Disk> disk =
-      CreateTestDisk(kDevicePath, kMountPath, /*is_read_only_hardware=*/false,
-                     /*is_mounted=*/true);
-  GetDeviceEventRouter()->OnDiskRemoved(*disk);
+  const std::unique_ptr<const Disk> disk =
+      Disk::Builder()
+          .SetDevicePath(kDevicePath)
+          .SetMountPath(kMountPath)
+          .SetStorageDevicePath(kDevicePath)
+          .SetIsReadOnlyHardware(false)
+          .SetFileSystemType("vfat")
+          .SetIsMounted(true)
+          .Build();
+  event_router_->OnDiskRemoved(*disk);
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings;
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          "hard_unplugged");
+  Strings strings = bridge_->GetStrings("hard_unplugged");
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, u"Whoa, there. Be careful.");
-  EXPECT_EQ(notification_strings.message,
+  EXPECT_EQ(strings.title, u"Whoa, there. Be careful.");
+  EXPECT_EQ(strings.message,
             u"In the future, be sure to eject your removable device in the "
             u"Files app before unplugging it. Otherwise, you might lose data.");
   // Check that the correct UMA was emitted.
@@ -497,34 +478,27 @@
 TEST_F(SystemNotificationManagerTest, DeviceNavigation) {
   base::HistogramTester histogram_tester;
   std::unique_ptr<Volume> volume(Volume::CreateForTesting(
-      base::FilePath(FILE_PATH_LITERAL("/mount/path1")),
-      VolumeType::VOLUME_TYPE_TESTING, ash::DeviceType::kUSB,
-      /*read_only=*/false, base::FilePath(FILE_PATH_LITERAL("/device/test")),
+      FilePath(FILE_PATH_LITERAL("/mount/path1")),
+      VolumeType::VOLUME_TYPE_TESTING, DeviceType::kUSB,
+      /*read_only=*/false, FilePath(FILE_PATH_LITERAL("/device/test")),
       kDeviceLabel, "FAT32"));
-  file_manager_private::MountCompletedEvent event;
-  event.event_type = file_manager_private::MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
+  MountCompletedEvent event;
+  event.event_type = MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
   event.should_notify = true;
-  event.status = file_manager_private::MOUNT_ERROR_SUCCESS;
-  GetSystemNotificationManager()->HandleMountCompletedEvent(event,
-                                                            *volume.get());
+  event.status = MOUNT_ERROR_SUCCESS;
+  notification_manager_->HandleMountCompletedEvent(event, *volume.get());
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings;
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          kRemovableDeviceNotificationId);
-  notification_platform_bridge->ClickButtonIndexById(
-      kRemovableDeviceNotificationId,
-      /*button_index=*/0);
+  Strings strings = bridge_->GetStrings(kRemovableDeviceNotificationId);
+  bridge_->ClickButton(kRemovableDeviceNotificationId, /*button_index=*/0);
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, kRemovableDeviceTitle);
-  EXPECT_EQ(notification_strings.message,
+  EXPECT_EQ(strings.title, kRemovableDeviceTitle);
+  EXPECT_EQ(strings.message,
             u"Explore the device\x2019s content in the Files app.");
   // Check that the correct UMA was emitted.
   histogram_tester.ExpectUniqueSample(
@@ -541,34 +515,27 @@
 TEST_F(SystemNotificationManagerTest, DeviceNavigationReadOnlyPolicy) {
   base::HistogramTester histogram_tester;
   std::unique_ptr<Volume> volume(Volume::CreateForTesting(
-      base::FilePath(FILE_PATH_LITERAL("/mount/path1")),
-      VolumeType::VOLUME_TYPE_TESTING, ash::DeviceType::kUSB,
-      /*read_only=*/true, base::FilePath(FILE_PATH_LITERAL("/device/test")),
+      FilePath(FILE_PATH_LITERAL("/mount/path1")),
+      VolumeType::VOLUME_TYPE_TESTING, DeviceType::kUSB,
+      /*read_only=*/true, FilePath(FILE_PATH_LITERAL("/device/test")),
       kDeviceLabel, "FAT32"));
-  file_manager_private::MountCompletedEvent event;
-  event.event_type = file_manager_private::MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
+  MountCompletedEvent event;
+  event.event_type = MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
   event.should_notify = true;
-  event.status = file_manager_private::MOUNT_ERROR_SUCCESS;
-  GetSystemNotificationManager()->HandleMountCompletedEvent(event,
-                                                            *volume.get());
+  event.status = MOUNT_ERROR_SUCCESS;
+  notification_manager_->HandleMountCompletedEvent(event, *volume.get());
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings;
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          kRemovableDeviceNotificationId);
-  notification_platform_bridge->ClickButtonIndexById(
-      kRemovableDeviceNotificationId,
-      /*button_index=*/0);
+  Strings strings = bridge_->GetStrings(kRemovableDeviceNotificationId);
+  bridge_->ClickButton(kRemovableDeviceNotificationId, /*button_index=*/0);
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, kRemovableDeviceTitle);
-  EXPECT_EQ(notification_strings.message,
+  EXPECT_EQ(strings.title, kRemovableDeviceTitle);
+  EXPECT_EQ(strings.message,
             u"Explore the device's content in the Files app. The content is "
             u"restricted by an admin and can\x2019t be modified.");
   // Check that the correct UMA was emitted.
@@ -586,37 +553,30 @@
 TEST_F(SystemNotificationManagerTest, DeviceNavigationAllowAppAccess) {
   base::HistogramTester histogram_tester;
   // Set the ARC++ enbled preference on the testing profile.
-  PrefService* const service = GetProfile()->GetPrefs();
+  PrefService* const service = profile_->GetPrefs();
   service->SetBoolean(arc::prefs::kArcEnabled, true);
   std::unique_ptr<Volume> volume(Volume::CreateForTesting(
-      base::FilePath(FILE_PATH_LITERAL("/mount/path1")),
-      VolumeType::VOLUME_TYPE_TESTING, ash::DeviceType::kUSB,
-      /*read_only=*/false, base::FilePath(FILE_PATH_LITERAL("/device/test")),
+      FilePath(FILE_PATH_LITERAL("/mount/path1")),
+      VolumeType::VOLUME_TYPE_TESTING, DeviceType::kUSB,
+      /*read_only=*/false, FilePath(FILE_PATH_LITERAL("/device/test")),
       kDeviceLabel, "FAT32"));
-  file_manager_private::MountCompletedEvent event;
-  event.event_type = file_manager_private::MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
+  MountCompletedEvent event;
+  event.event_type = MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
   event.should_notify = true;
-  event.status = file_manager_private::MOUNT_ERROR_SUCCESS;
-  GetSystemNotificationManager()->HandleMountCompletedEvent(event,
-                                                            *volume.get());
+  event.status = MOUNT_ERROR_SUCCESS;
+  notification_manager_->HandleMountCompletedEvent(event, *volume.get());
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings;
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          kRemovableDeviceNotificationId);
-  notification_platform_bridge->ClickButtonIndexById(
-      kRemovableDeviceNotificationId,
-      /*button_index=*/0);
+  Strings strings = bridge_->GetStrings(kRemovableDeviceNotificationId);
+  bridge_->ClickButton(kRemovableDeviceNotificationId, /*button_index=*/0);
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, kRemovableDeviceTitle);
-  EXPECT_EQ(notification_strings.message,
+  EXPECT_EQ(strings.title, kRemovableDeviceTitle);
+  EXPECT_EQ(strings.message,
             u"Explore the device\x2019s content in the Files app. For device "
             u"preferences, go to Settings.");
   // Check that the correct UMA was emitted.
@@ -632,29 +592,25 @@
        DeviceNavigationAllowAppAccessSecondButton) {
   base::HistogramTester histogram_tester;
   // Set the ARC++ enbled preference on the testing profile.
-  PrefService* const service = GetProfile()->GetPrefs();
+  PrefService* const service = profile_->GetPrefs();
   service->SetBoolean(arc::prefs::kArcEnabled, true);
   std::unique_ptr<Volume> volume(Volume::CreateForTesting(
-      base::FilePath(FILE_PATH_LITERAL("/mount/path1")),
-      VolumeType::VOLUME_TYPE_TESTING, ash::DeviceType::kUSB,
-      /*read_only=*/false, base::FilePath(FILE_PATH_LITERAL("/device/test")),
+      FilePath(FILE_PATH_LITERAL("/mount/path1")),
+      VolumeType::VOLUME_TYPE_TESTING, DeviceType::kUSB,
+      /*read_only=*/false, FilePath(FILE_PATH_LITERAL("/device/test")),
       kDeviceLabel, "FAT32"));
-  file_manager_private::MountCompletedEvent event;
-  event.event_type = file_manager_private::MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
+  MountCompletedEvent event;
+  event.event_type = MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
   event.should_notify = true;
-  event.status = file_manager_private::MOUNT_ERROR_SUCCESS;
-  GetSystemNotificationManager()->HandleMountCompletedEvent(event,
-                                                            *volume.get());
+  event.status = MOUNT_ERROR_SUCCESS;
+  notification_manager_->HandleMountCompletedEvent(event, *volume.get());
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
-  notification_platform_bridge->ClickButtonIndexById(
-      kRemovableDeviceNotificationId,
-      /*button_index=*/1);
+  ASSERT_EQ(1u, notification_count_);
+  bridge_->ClickButton(kRemovableDeviceNotificationId, /*button_index=*/1);
   // Check that the correct UMA was emitted.
   histogram_tester.ExpectUniqueSample(
       kNotificationUserActionHistogramName,
@@ -667,35 +623,30 @@
 TEST_F(SystemNotificationManagerTest, DeviceNavigationAppsHaveAccess) {
   base::HistogramTester histogram_tester;
   // Set the ARC++ enbled preference on the testing profile.
-  PrefService* const service = GetProfile()->GetPrefs();
+  PrefService* const service = profile_->GetPrefs();
   service->SetBoolean(arc::prefs::kArcEnabled, true);
   service->SetBoolean(arc::prefs::kArcHasAccessToRemovableMedia, true);
   std::unique_ptr<Volume> volume(Volume::CreateForTesting(
-      base::FilePath(FILE_PATH_LITERAL("/mount/path1")),
-      VolumeType::VOLUME_TYPE_TESTING, ash::DeviceType::kUSB,
-      /*read_only=*/false, base::FilePath(FILE_PATH_LITERAL("/device/test")),
+      FilePath(FILE_PATH_LITERAL("/mount/path1")),
+      VolumeType::VOLUME_TYPE_TESTING, DeviceType::kUSB,
+      /*read_only=*/false, FilePath(FILE_PATH_LITERAL("/device/test")),
       kDeviceLabel, "FAT32"));
-  file_manager_private::MountCompletedEvent event;
-  event.event_type = file_manager_private::MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
+  MountCompletedEvent event;
+  event.event_type = MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
   event.should_notify = true;
-  event.status = file_manager_private::MOUNT_ERROR_SUCCESS;
-  GetSystemNotificationManager()->HandleMountCompletedEvent(event,
-                                                            *volume.get());
+  event.status = MOUNT_ERROR_SUCCESS;
+  notification_manager_->HandleMountCompletedEvent(event, *volume.get());
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings;
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          kRemovableDeviceNotificationId);
+  Strings strings = bridge_->GetStrings(kRemovableDeviceNotificationId);
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, kRemovableDeviceTitle);
-  EXPECT_EQ(notification_strings.message,
+  EXPECT_EQ(strings.title, kRemovableDeviceTitle);
+  EXPECT_EQ(strings.message,
             u"Explore the device\x2019s content in the Files app. Play Store "
             u"applications have access to this device.");
   // Check that the correct UMA was emitted.
@@ -716,32 +667,27 @@
 TEST_F(SystemNotificationManagerTest, DeviceUnsupportedDefault) {
   base::HistogramTester histogram_tester;
   std::unique_ptr<Volume> volume(Volume::CreateForTesting(
-      base::FilePath(FILE_PATH_LITERAL("/mount/path1")),
-      VolumeType::VOLUME_TYPE_TESTING, ash::DeviceType::kUSB,
-      /*read_only=*/false, base::FilePath(FILE_PATH_LITERAL("/device/test")),
-      "", "FAT32"));
-  file_manager_private::MountCompletedEvent event;
-  event.event_type = file_manager_private::MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
+      FilePath(FILE_PATH_LITERAL("/mount/path1")),
+      VolumeType::VOLUME_TYPE_TESTING, DeviceType::kUSB,
+      /*read_only=*/false, FilePath(FILE_PATH_LITERAL("/device/test")), "",
+      "FAT32"));
+  MountCompletedEvent event;
+  event.event_type = MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
   event.should_notify = true;
-  event.status = file_manager_private::MOUNT_ERROR_UNSUPPORTED_FILESYSTEM;
-  GetSystemNotificationManager()->HandleMountCompletedEvent(event,
-                                                            *volume.get());
+  event.status = MOUNT_ERROR_UNSUPPORTED_FILESYSTEM;
+  notification_manager_->HandleMountCompletedEvent(event, *volume.get());
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings;
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          kDeviceFailNotificationId);
+  Strings strings = bridge_->GetStrings(kDeviceFailNotificationId);
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, kRemovableDeviceTitle);
+  EXPECT_EQ(strings.title, kRemovableDeviceTitle);
   EXPECT_EQ(
-      notification_strings.message,
+      strings.message,
       u"Sorry, your external storage device is not supported at this time.");
   // Check that the correct UMA was emitted.
   histogram_tester.ExpectUniqueSample(kNotificationShowHistogramName,
@@ -754,31 +700,26 @@
 TEST_F(SystemNotificationManagerTest, DeviceUnsupportedNamed) {
   base::HistogramTester histogram_tester;
   std::unique_ptr<Volume> volume(Volume::CreateForTesting(
-      base::FilePath(FILE_PATH_LITERAL("/mount/path1")),
-      VolumeType::VOLUME_TYPE_TESTING, ash::DeviceType::kUSB,
-      /*read_only=*/false, base::FilePath(FILE_PATH_LITERAL("/device/test")),
+      FilePath(FILE_PATH_LITERAL("/mount/path1")),
+      VolumeType::VOLUME_TYPE_TESTING, DeviceType::kUSB,
+      /*read_only=*/false, FilePath(FILE_PATH_LITERAL("/device/test")),
       kDeviceLabel, "FAT32"));
-  file_manager_private::MountCompletedEvent event;
-  event.event_type = file_manager_private::MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
+  MountCompletedEvent event;
+  event.event_type = MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
   event.should_notify = true;
-  event.status = file_manager_private::MOUNT_ERROR_UNSUPPORTED_FILESYSTEM;
-  GetSystemNotificationManager()->HandleMountCompletedEvent(event,
-                                                            *volume.get());
+  event.status = MOUNT_ERROR_UNSUPPORTED_FILESYSTEM;
+  notification_manager_->HandleMountCompletedEvent(event, *volume.get());
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings;
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          kDeviceFailNotificationId);
+  Strings strings = bridge_->GetStrings(kDeviceFailNotificationId);
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, kRemovableDeviceTitle);
-  EXPECT_EQ(notification_strings.message,
+  EXPECT_EQ(strings.title, kRemovableDeviceTitle);
+  EXPECT_EQ(strings.message,
             u"Sorry, the device MyUSB is not supported at this time.");
   // Check that the correct UMA was emitted.
   histogram_tester.ExpectUniqueSample(kNotificationShowHistogramName,
@@ -796,54 +737,46 @@
   base::HistogramTester histogram_tester;
   // Build a supported file system volume and mount it.
   std::unique_ptr<Volume> volume1(Volume::CreateForTesting(
-      base::FilePath(FILE_PATH_LITERAL("/mount/path1")),
-      VolumeType::VOLUME_TYPE_TESTING, ash::DeviceType::kUSB,
-      /*read_only=*/false, base::FilePath(FILE_PATH_LITERAL("/device/test")),
-      "", "FAT32"));
-  file_manager_private::MountCompletedEvent event;
-  event.event_type = file_manager_private::MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
+      FilePath(FILE_PATH_LITERAL("/mount/path1")),
+      VolumeType::VOLUME_TYPE_TESTING, DeviceType::kUSB,
+      /*read_only=*/false, FilePath(FILE_PATH_LITERAL("/device/test")), "",
+      "FAT32"));
+  MountCompletedEvent event;
+  event.event_type = MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
   event.should_notify = true;
-  event.status = file_manager_private::MOUNT_ERROR_SUCCESS;
-  GetSystemNotificationManager()->HandleMountCompletedEvent(event,
-                                                            *volume1.get());
+  event.status = MOUNT_ERROR_SUCCESS;
+  notification_manager_->HandleMountCompletedEvent(event, *volume1.get());
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          kRemovableDeviceNotificationId);
+  Strings strings = bridge_->GetStrings(kRemovableDeviceNotificationId);
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, kRemovableDeviceTitle);
-  EXPECT_EQ(notification_strings.message,
+  EXPECT_EQ(strings.title, kRemovableDeviceTitle);
+  EXPECT_EQ(strings.message,
             u"Explore the device\x2019s content in the Files app.");
   // Build an unsupported file system volume and mount it on the same device.
   std::unique_ptr<Volume> volume2(Volume::CreateForTesting(
-      base::FilePath(FILE_PATH_LITERAL("/mount/path2")),
-      VolumeType::VOLUME_TYPE_TESTING, ash::DeviceType::kUSB,
-      /*read_only=*/false, base::FilePath(FILE_PATH_LITERAL("/device/test")),
-      "", "unsupported"));
-  event.status = file_manager_private::MOUNT_ERROR_UNSUPPORTED_FILESYSTEM;
-  GetSystemNotificationManager()->HandleMountCompletedEvent(event,
-                                                            *volume2.get());
+      FilePath(FILE_PATH_LITERAL("/mount/path2")),
+      VolumeType::VOLUME_TYPE_TESTING, DeviceType::kUSB,
+      /*read_only=*/false, FilePath(FILE_PATH_LITERAL("/device/test")), "",
+      "unsupported"));
+  event.status = MOUNT_ERROR_UNSUPPORTED_FILESYSTEM;
+  notification_manager_->HandleMountCompletedEvent(event, *volume2.get());
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have two notifications.
-  ASSERT_EQ(2u, notification_count);
+  ASSERT_EQ(2u, notification_count_);
   // Get the strings for the displayed notification.
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          kDeviceFailNotificationId);
+  strings = bridge_->GetStrings(kDeviceFailNotificationId);
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, kRemovableDeviceTitle);
-  EXPECT_EQ(notification_strings.message,
+  EXPECT_EQ(strings.title, kRemovableDeviceTitle);
+  EXPECT_EQ(strings.message,
             u"Sorry, at least one partition on your external storage device "
             u"could not be mounted.");
   // A DEVICE_NAVIGATION UMA is emitted during the setup so just check for the
@@ -859,40 +792,35 @@
   base::HistogramTester histogram_tester;
   // Build a supported file system volume and mount it.
   std::unique_ptr<Volume> volume1(Volume::CreateForTesting(
-      base::FilePath(FILE_PATH_LITERAL("/mount/path1")),
-      VolumeType::VOLUME_TYPE_TESTING, ash::DeviceType::kUSB,
-      /*read_only=*/false, base::FilePath(FILE_PATH_LITERAL("/device/test")),
+      FilePath(FILE_PATH_LITERAL("/mount/path1")),
+      VolumeType::VOLUME_TYPE_TESTING, DeviceType::kUSB,
+      /*read_only=*/false, FilePath(FILE_PATH_LITERAL("/device/test")),
       kDeviceLabel, "FAT32"));
-  file_manager_private::MountCompletedEvent event;
-  event.event_type = file_manager_private::MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
+  MountCompletedEvent event;
+  event.event_type = MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
   event.should_notify = true;
-  event.status = file_manager_private::MOUNT_ERROR_SUCCESS;
-  GetSystemNotificationManager()->HandleMountCompletedEvent(event,
-                                                            *volume1.get());
+  event.status = MOUNT_ERROR_SUCCESS;
+  notification_manager_->HandleMountCompletedEvent(event, *volume1.get());
   // Ignore checking for the device navigation notification.
   // Build an unsupported file system volume and mount it on the same device.
   std::unique_ptr<Volume> volume2(Volume::CreateForTesting(
-      base::FilePath(FILE_PATH_LITERAL("/mount/path2")),
-      VolumeType::VOLUME_TYPE_TESTING, ash::DeviceType::kUSB,
-      /*read_only=*/false, base::FilePath(FILE_PATH_LITERAL("/device/test")),
+      FilePath(FILE_PATH_LITERAL("/mount/path2")),
+      VolumeType::VOLUME_TYPE_TESTING, DeviceType::kUSB,
+      /*read_only=*/false, FilePath(FILE_PATH_LITERAL("/device/test")),
       kDeviceLabel, "unsupported"));
-  event.status = file_manager_private::MOUNT_ERROR_UNSUPPORTED_FILESYSTEM;
-  GetSystemNotificationManager()->HandleMountCompletedEvent(event,
-                                                            *volume2.get());
+  event.status = MOUNT_ERROR_UNSUPPORTED_FILESYSTEM;
+  notification_manager_->HandleMountCompletedEvent(event, *volume2.get());
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have two notifications.
-  ASSERT_EQ(2u, notification_count);
+  ASSERT_EQ(2u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          kDeviceFailNotificationId);
+  Strings strings = bridge_->GetStrings(kDeviceFailNotificationId);
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, kRemovableDeviceTitle);
-  EXPECT_EQ(notification_strings.message,
+  EXPECT_EQ(strings.title, kRemovableDeviceTitle);
+  EXPECT_EQ(strings.message,
             u"Sorry, at least one partition on the device MyUSB could not be "
             u"mounted.");
   // A DEVICE_NAVIGATION UMA is emitted during the setup so just check for the
@@ -910,36 +838,30 @@
 TEST_F(SystemNotificationManagerTest, DeviceFailUnknownDefault) {
   base::HistogramTester histogram_tester;
   std::unique_ptr<Volume> volume(Volume::CreateForTesting(
-      base::FilePath(FILE_PATH_LITERAL("/mount/path1")),
-      VolumeType::VOLUME_TYPE_TESTING, ash::DeviceType::kUSB,
-      /*read_only=*/false, base::FilePath(FILE_PATH_LITERAL("/device/test")),
-      "", "unknown"));
-  file_manager_private::MountCompletedEvent event;
-  event.event_type = file_manager_private::MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
+      FilePath(FILE_PATH_LITERAL("/mount/path1")),
+      VolumeType::VOLUME_TYPE_TESTING, DeviceType::kUSB,
+      /*read_only=*/false, FilePath(FILE_PATH_LITERAL("/device/test")), "",
+      "unknown"));
+  MountCompletedEvent event;
+  event.event_type = MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
   event.should_notify = true;
-  event.status = file_manager_private::MOUNT_ERROR_UNKNOWN_FILESYSTEM;
-  GetSystemNotificationManager()->HandleMountCompletedEvent(event,
-                                                            *volume.get());
+  event.status = MOUNT_ERROR_UNKNOWN_FILESYSTEM;
+  notification_manager_->HandleMountCompletedEvent(event, *volume.get());
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings;
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          kDeviceFailNotificationId);
-  notification_platform_bridge->ClickButtonIndexById(kDeviceFailNotificationId,
-                                                     /*button_index=*/0);
+  Strings strings = bridge_->GetStrings(kDeviceFailNotificationId);
+  bridge_->ClickButton(kDeviceFailNotificationId, /*button_index=*/0);
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, kRemovableDeviceTitle);
-  EXPECT_EQ(notification_strings.message,
+  EXPECT_EQ(strings.title, kRemovableDeviceTitle);
+  EXPECT_EQ(strings.message,
             u"Sorry, your external storage device could not be recognized.");
-  EXPECT_EQ(notification_strings.buttons.size(), 1u);
-  EXPECT_EQ(notification_strings.buttons[0], u"Format this device");
+  EXPECT_EQ(strings.buttons.size(), 1u);
+  EXPECT_EQ(strings.buttons[0], u"Format this device");
   histogram_tester.ExpectUniqueSample(
       kNotificationShowHistogramName,
       DeviceNotificationUmaType::DEVICE_FAIL_UNKNOWN, 1);
@@ -953,36 +875,30 @@
 TEST_F(SystemNotificationManagerTest, DeviceFailUnknownNamed) {
   base::HistogramTester histogram_tester;
   std::unique_ptr<Volume> volume(Volume::CreateForTesting(
-      base::FilePath(FILE_PATH_LITERAL("/mount/path1")),
-      VolumeType::VOLUME_TYPE_TESTING, ash::DeviceType::kUSB,
-      /*read_only=*/false, base::FilePath(FILE_PATH_LITERAL("/device/test")),
+      FilePath(FILE_PATH_LITERAL("/mount/path1")),
+      VolumeType::VOLUME_TYPE_TESTING, DeviceType::kUSB,
+      /*read_only=*/false, FilePath(FILE_PATH_LITERAL("/device/test")),
       kDeviceLabel, "unknown"));
-  file_manager_private::MountCompletedEvent event;
-  event.event_type = file_manager_private::MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
+  MountCompletedEvent event;
+  event.event_type = MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
   event.should_notify = true;
-  event.status = file_manager_private::MOUNT_ERROR_UNKNOWN_FILESYSTEM;
-  GetSystemNotificationManager()->HandleMountCompletedEvent(event,
-                                                            *volume.get());
+  event.status = MOUNT_ERROR_UNKNOWN_FILESYSTEM;
+  notification_manager_->HandleMountCompletedEvent(event, *volume.get());
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings;
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          kDeviceFailNotificationId);
-  notification_platform_bridge->ClickButtonIndexById(kDeviceFailNotificationId,
-                                                     /*button_index=*/0);
+  Strings strings = bridge_->GetStrings(kDeviceFailNotificationId);
+  bridge_->ClickButton(kDeviceFailNotificationId, /*button_index=*/0);
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, kRemovableDeviceTitle);
-  EXPECT_EQ(notification_strings.message,
+  EXPECT_EQ(strings.title, kRemovableDeviceTitle);
+  EXPECT_EQ(strings.message,
             u"Sorry, the device MyUSB could not be recognized.");
-  EXPECT_EQ(notification_strings.buttons.size(), 1u);
-  EXPECT_EQ(notification_strings.buttons[0], u"Format this device");
+  EXPECT_EQ(strings.buttons.size(), 1u);
+  EXPECT_EQ(strings.buttons[0], u"Format this device");
   histogram_tester.ExpectUniqueSample(
       kNotificationShowHistogramName,
       DeviceNotificationUmaType::DEVICE_FAIL_UNKNOWN, 1);
@@ -998,34 +914,29 @@
 TEST_F(SystemNotificationManagerTest, DeviceFailUnknownReadOnlyDefault) {
   base::HistogramTester histogram_tester;
   std::unique_ptr<Volume> volume(Volume::CreateForTesting(
-      base::FilePath(FILE_PATH_LITERAL("/mount/path1")),
-      VolumeType::VOLUME_TYPE_TESTING, ash::DeviceType::kUSB,
-      /*read_only=*/true, base::FilePath(FILE_PATH_LITERAL("/device/test")), "",
+      FilePath(FILE_PATH_LITERAL("/mount/path1")),
+      VolumeType::VOLUME_TYPE_TESTING, DeviceType::kUSB,
+      /*read_only=*/true, FilePath(FILE_PATH_LITERAL("/device/test")), "",
       "unknown"));
-  file_manager_private::MountCompletedEvent event;
-  event.event_type = file_manager_private::MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
+  MountCompletedEvent event;
+  event.event_type = MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
   event.should_notify = true;
-  event.status = file_manager_private::MOUNT_ERROR_UNKNOWN_FILESYSTEM;
-  GetSystemNotificationManager()->HandleMountCompletedEvent(event,
-                                                            *volume.get());
+  event.status = MOUNT_ERROR_UNKNOWN_FILESYSTEM;
+  notification_manager_->HandleMountCompletedEvent(event, *volume.get());
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings;
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          kDeviceFailNotificationId);
+  Strings strings = bridge_->GetStrings(kDeviceFailNotificationId);
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, kRemovableDeviceTitle);
-  EXPECT_EQ(notification_strings.message,
+  EXPECT_EQ(strings.title, kRemovableDeviceTitle);
+  EXPECT_EQ(strings.message,
             u"Sorry, your external storage device could not be recognized.");
   // Device is read-only, expect no buttons present.
-  EXPECT_EQ(notification_strings.buttons.size(), 0u);
+  EXPECT_EQ(strings.buttons.size(), 0u);
   histogram_tester.ExpectUniqueSample(
       kNotificationShowHistogramName,
       DeviceNotificationUmaType::DEVICE_FAIL_UNKNOWN_READONLY, 1);
@@ -1036,41 +947,32 @@
 TEST_F(SystemNotificationManagerTest, DeviceFailUnknownReadOnlyNamed) {
   base::HistogramTester histogram_tester;
   std::unique_ptr<Volume> volume(Volume::CreateForTesting(
-      base::FilePath(FILE_PATH_LITERAL("/mount/path1")),
-      VolumeType::VOLUME_TYPE_TESTING, ash::DeviceType::kUSB,
-      /*read_only=*/true, base::FilePath(FILE_PATH_LITERAL("/device/test")),
+      FilePath(FILE_PATH_LITERAL("/mount/path1")),
+      VolumeType::VOLUME_TYPE_TESTING, DeviceType::kUSB,
+      /*read_only=*/true, FilePath(FILE_PATH_LITERAL("/device/test")),
       kDeviceLabel, "unknown"));
-  file_manager_private::MountCompletedEvent event;
-  event.event_type = file_manager_private::MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
+  MountCompletedEvent event;
+  event.event_type = MOUNT_COMPLETED_EVENT_TYPE_MOUNT;
   event.should_notify = true;
-  event.status = file_manager_private::MOUNT_ERROR_UNKNOWN_FILESYSTEM;
-  GetSystemNotificationManager()->HandleMountCompletedEvent(event,
-                                                            *volume.get());
+  event.status = MOUNT_ERROR_UNKNOWN_FILESYSTEM;
+  notification_manager_->HandleMountCompletedEvent(event, *volume.get());
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings;
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          kDeviceFailNotificationId);
+  Strings strings = bridge_->GetStrings(kDeviceFailNotificationId);
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, kRemovableDeviceTitle);
-  EXPECT_EQ(notification_strings.message,
+  EXPECT_EQ(strings.title, kRemovableDeviceTitle);
+  EXPECT_EQ(strings.message,
             u"Sorry, the device MyUSB could not be recognized.");
   histogram_tester.ExpectUniqueSample(
       kNotificationShowHistogramName,
       DeviceNotificationUmaType::DEVICE_FAIL_UNKNOWN_READONLY, 1);
 }
 
-storage::FileSystemURL CreateFileSystemURL(std::string url) {
-  return storage::FileSystemURL::CreateForTest(GURL(url));
-}
-
 TEST_F(SystemNotificationManagerTest, HandleIOTaskProgressCopy) {
   // The system notification only sees the IOTask ProgressStatus.
   file_manager::io_task::ProgressStatus status;
@@ -1084,37 +986,32 @@
   status.SetDestinationFolder(CreateTestFile("volume/dest_dir/"));
 
   // Send the copy begin/queued progress.
-  auto* notification_manager = GetSystemNotificationManager();
-  notification_manager->HandleIOTaskProgress(status);
+  notification_manager_->HandleIOTaskProgress(status);
 
   // Check: We have the 1 notification.
   ASSERT_EQ(1u, GetNotificationCount());
 
-  TestNotificationStrings notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          "swa-file-operation-1");
+  Strings strings = bridge_->GetStrings("swa-file-operation-1");
 
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, u"Files");
-  EXPECT_EQ(notification_strings.message, u"Copying src_file.txt\x2026");
+  EXPECT_EQ(strings.title, u"Files");
+  EXPECT_EQ(strings.message, u"Copying src_file.txt\x2026");
 
   // Send the copy progress.
   status.bytes_transferred = 30;
   status.state = file_manager::io_task::State::kInProgress;
-  notification_manager->HandleIOTaskProgress(status);
+  notification_manager_->HandleIOTaskProgress(status);
 
   // Check: We have the same notification.
   ASSERT_EQ(1u, GetNotificationCount());
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          "swa-file-operation-1");
-  EXPECT_EQ(notification_strings.title, u"Files");
-  EXPECT_EQ(notification_strings.message, u"Copying src_file.txt\x2026");
+  strings = bridge_->GetStrings("swa-file-operation-1");
+  EXPECT_EQ(strings.title, u"Files");
+  EXPECT_EQ(strings.message, u"Copying src_file.txt\x2026");
 
   // Send the success progress status.
   status.bytes_transferred = 100;
   status.state = file_manager::io_task::State::kSuccess;
-  notification_manager->HandleIOTaskProgress(status);
+  notification_manager_->HandleIOTaskProgress(status);
 
   // Notification should disappear.
   ASSERT_EQ(0u, GetNotificationCount());
@@ -1133,37 +1030,32 @@
   status.SetDestinationFolder(CreateTestFile("volume/src_file/"));
 
   // Send the copy begin/queued progress.
-  auto* notification_manager = GetSystemNotificationManager();
-  notification_manager->HandleIOTaskProgress(status);
+  notification_manager_->HandleIOTaskProgress(status);
 
   // Check: We have the 1 notification.
   ASSERT_EQ(1u, GetNotificationCount());
 
-  TestNotificationStrings notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          "swa-file-operation-1");
+  Strings strings = bridge_->GetStrings("swa-file-operation-1");
 
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, u"Files");
-  EXPECT_EQ(notification_strings.message, u"Extracting src_file.zip\x2026");
+  EXPECT_EQ(strings.title, u"Files");
+  EXPECT_EQ(strings.message, u"Extracting src_file.zip\x2026");
 
   // Send the copy progress.
   status.bytes_transferred = 30;
   status.state = file_manager::io_task::State::kInProgress;
-  notification_manager->HandleIOTaskProgress(status);
+  notification_manager_->HandleIOTaskProgress(status);
 
   // Check: We have the same notification.
   ASSERT_EQ(1u, GetNotificationCount());
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          "swa-file-operation-1");
-  EXPECT_EQ(notification_strings.title, u"Files");
-  EXPECT_EQ(notification_strings.message, u"Extracting src_file.zip\x2026");
+  strings = bridge_->GetStrings("swa-file-operation-1");
+  EXPECT_EQ(strings.title, u"Files");
+  EXPECT_EQ(strings.message, u"Extracting src_file.zip\x2026");
 
   // Send the success progress status.
   status.bytes_transferred = 100;
   status.state = file_manager::io_task::State::kSuccess;
-  notification_manager->HandleIOTaskProgress(status);
+  notification_manager_->HandleIOTaskProgress(status);
 
   // Notification should disappear.
   ASSERT_EQ(0u, GetNotificationCount());
@@ -1184,8 +1076,8 @@
 
   auto task = std::make_unique<file_manager::io_task::CopyOrMoveIOTask>(
       file_manager::io_task::OperationType::kCopy,
-      std::vector<storage::FileSystemURL>({src}), dst, GetProfile(),
-      file_system_context);
+      std::vector<storage::FileSystemURL>({src}), dst, profile_,
+      file_system_context_);
 
   // Send the copy begin/queued progress.
   const io_task::IOTaskId task_id = io_task_controller->Add(std::move(task));
@@ -1194,14 +1086,13 @@
   ASSERT_EQ(1u, GetNotificationCount());
 
   // Click on the cancel button.
-  notification_platform_bridge->ClickButtonIndexById("swa-file-operation-1",
-                                                     /*button_index=*/0);
+  bridge_->ClickButton("swa-file-operation-1", /*button_index=*/0);
 
   // Notification should disappear.
   ASSERT_EQ(0u, GetNotificationCount());
 
   // The last status observed should be Cancelled.
-  ASSERT_EQ(io_task::State::kCancelled, task_statuses[task_id].back());
+  ASSERT_EQ(io_task::State::kCancelled, task_statuses_[task_id].back());
 }
 
 TEST_F(SystemNotificationManagerTest, HandleIOTaskProgressWarning) {
@@ -1219,39 +1110,33 @@
   status.SetDestinationFolder(CreateTestFile("volume/dest_dir/"));
 
   // Send the copy begin/queued progress.
-  auto* notification_manager = GetSystemNotificationManager();
-  notification_manager->HandleIOTaskProgress(status);
+  notification_manager_->HandleIOTaskProgress(status);
 
   // Check: We have the 1 notification.
   ASSERT_EQ(1u, GetNotificationCount());
 
-  TestNotificationStrings notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          "swa-file-operation-1");
+  Strings strings = bridge_->GetStrings("swa-file-operation-1");
 
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, u"Files");
-  EXPECT_EQ(notification_strings.message, u"Copying 2 items\x2026");
+  EXPECT_EQ(strings.title, u"Files");
+  EXPECT_EQ(strings.message, u"Copying 2 items\x2026");
 
   // Set the status to warning.
   status.state = file_manager::io_task::State::kPaused;
   status.pause_params.policy_params =
       io_task::PolicyPauseParams(policy::Policy::kDlp);
-  notification_manager->HandleIOTaskProgress(status);
+  notification_manager_->HandleIOTaskProgress(status);
 
   // Check: We have the same notification.
   ASSERT_EQ(1u, GetNotificationCount());
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          "swa-file-operation-1");
-  EXPECT_EQ(notification_strings.title, u"Confirmation required");
-  EXPECT_EQ(notification_strings.message,
-            u"files may contain sensitive content");
+  strings = bridge_->GetStrings("swa-file-operation-1");
+  EXPECT_EQ(strings.title, u"Confirmation required");
+  EXPECT_EQ(strings.message, u"files may contain sensitive content");
 
   // Send the success progress status.
   status.bytes_transferred = 100;
   status.state = file_manager::io_task::State::kSuccess;
-  notification_manager->HandleIOTaskProgress(status);
+  notification_manager_->HandleIOTaskProgress(status);
 
   // Notification should disappear.
   ASSERT_EQ(0u, GetNotificationCount());
@@ -1270,38 +1155,33 @@
   status.SetDestinationFolder(CreateTestFile("volume/dest_dir/"));
 
   // Send the copy begin/queued progress.
-  auto* notification_manager = GetSystemNotificationManager();
-  notification_manager->HandleIOTaskProgress(status);
+  notification_manager_->HandleIOTaskProgress(status);
 
   // Check: We have the 1 notification.
   ASSERT_EQ(1u, GetNotificationCount());
 
-  TestNotificationStrings notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          "swa-file-operation-1");
+  Strings strings = bridge_->GetStrings("swa-file-operation-1");
 
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, u"Files");
-  EXPECT_EQ(notification_strings.message, u"Copying src_file.txt\x2026");
+  EXPECT_EQ(strings.title, u"Files");
+  EXPECT_EQ(strings.message, u"Copying src_file.txt\x2026");
 
   // Set the security error value.
   status.state = file_manager::io_task::State::kError;
   status.policy_error =
       file_manager::io_task::PolicyErrorType::kEnterpriseConnectors;
-  notification_manager->HandleIOTaskProgress(status);
+  notification_manager_->HandleIOTaskProgress(status);
 
   // Check: We have the same notification.
   ASSERT_EQ(1u, GetNotificationCount());
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          "swa-file-operation-1");
-  EXPECT_EQ(notification_strings.title, u"files blocked");
-  EXPECT_EQ(notification_strings.message, u"File was blocked");
+  strings = bridge_->GetStrings("swa-file-operation-1");
+  EXPECT_EQ(strings.title, u"files blocked");
+  EXPECT_EQ(strings.message, u"File was blocked");
 
   // Send the success progress status.
   status.bytes_transferred = 100;
   status.state = file_manager::io_task::State::kSuccess;
-  notification_manager->HandleIOTaskProgress(status);
+  notification_manager_->HandleIOTaskProgress(status);
 
   // Notification should disappear.
   ASSERT_EQ(0u, GetNotificationCount());
@@ -1321,25 +1201,22 @@
   status.SetDestinationFolder(CreateTestFile("volume/dest_dir/"));
 
   // Send the scanning progress.
-  auto* notification_manager = GetSystemNotificationManager();
-  notification_manager->HandleIOTaskProgress(status);
+  notification_manager_->HandleIOTaskProgress(status);
 
   // Check: We have the 1 notification.
   ASSERT_EQ(1u, GetNotificationCount());
 
-  TestNotificationStrings notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          "swa-file-operation-1");
+  Strings strings = bridge_->GetStrings("swa-file-operation-1");
 
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, u"Files");
-  EXPECT_EQ(notification_strings.message,
+  EXPECT_EQ(strings.title, u"Files");
+  EXPECT_EQ(strings.message,
             u"Checking files with your organization's security policies.");
 
   // Send the success progress status.
   status.bytes_transferred = 100;
   status.state = file_manager::io_task::State::kSuccess;
-  notification_manager->HandleIOTaskProgress(status);
+  notification_manager_->HandleIOTaskProgress(status);
 
   // Notification should disappear.
   ASSERT_EQ(0u, GetNotificationCount());
@@ -1347,137 +1224,252 @@
 
 std::u16string kGoogleDrive = u"Google Drive";
 
+// Tests the bulk-pinning notifications.
+TEST_F(SystemNotificationManagerTest, BulkPinningNotification) {
+  using List = base::Value::List;
+  const base::StringPiece event_name = "unused-event-name";
+
+  // Event with no args should be ignored.
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_BULK_PIN_PROGRESS, event_name, List()));
+
+  // There should be no notification.
+  display_service_->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
+  EXPECT_EQ(0u, notification_count_);
+
+  file_manager_private::BulkPinProgress progress;
+
+  // Handle an unparsable event.
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_BULK_PIN_PROGRESS, event_name,
+            List().Append(progress.ToValue())));
+
+  // There should be no notification.
+  display_service_->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
+  EXPECT_EQ(0u, notification_count_);
+
+  // Not enough space without going through syncing phase.
+  progress.stage = BULK_PIN_STAGE_NOT_ENOUGH_SPACE;
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_BULK_PIN_PROGRESS, event_name,
+            List().Append(progress.ToValue())));
+
+  // There should be no notification.
+  display_service_->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
+  EXPECT_EQ(0u, notification_count_);
+
+  // Syncing.
+  progress.stage = BULK_PIN_STAGE_SYNCING;
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_BULK_PIN_PROGRESS, event_name,
+            List().Append(progress.ToValue())));
+
+  // There should be no notification.
+  display_service_->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
+  EXPECT_EQ(0u, notification_count_);
+
+  // Not enough space after syncing phase.
+  progress.stage = BULK_PIN_STAGE_NOT_ENOUGH_SPACE;
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_BULK_PIN_PROGRESS, event_name,
+            List().Append(progress.ToValue())));
+
+  // There should be one notification.
+  display_service_->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
+  EXPECT_EQ(1u, notification_count_);
+
+  // Get the strings for the displayed notification.
+  const std::string notification_id = "drive-bulk-pinning-error";
+  Strings strings = bridge_->GetStrings(notification_id);
+  EXPECT_EQ(strings.title, u"Sync error");
+  EXPECT_EQ(
+      strings.message,
+      u"We couldn't sync all of your My Drive files because you don't have "
+      u"enough storage available. Files that were already synced will stay "
+      u"available offline, but automatic syncing has been turned off.");
+  EXPECT_THAT(strings.buttons, ElementsAre(u"Settings"));
+
+  // Click the notification body.
+  bridge_->ClickNotification(notification_id);
+
+  // The notification should have been closed.
+  display_service_->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
+  EXPECT_EQ(0u, notification_count_);
+  EXPECT_EQ(0, notification_manager_->drive_settings_open_count_);
+
+  // Not enough space without going through syncing phase.
+  progress.stage = BULK_PIN_STAGE_NOT_ENOUGH_SPACE;
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_BULK_PIN_PROGRESS, event_name,
+            List().Append(progress.ToValue())));
+
+  // There should be no notification.
+  display_service_->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
+  EXPECT_EQ(0u, notification_count_);
+
+  // Syncing.
+  progress.stage = BULK_PIN_STAGE_SYNCING;
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_BULK_PIN_PROGRESS, event_name,
+            List().Append(progress.ToValue())));
+
+  // There should be no notification.
+  display_service_->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
+  EXPECT_EQ(0u, notification_count_);
+
+  // Not enough space after syncing phase.
+  progress.stage = BULK_PIN_STAGE_NOT_ENOUGH_SPACE;
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_BULK_PIN_PROGRESS, event_name,
+            List().Append(progress.ToValue())));
+
+  // There should be one notification.
+  display_service_->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
+  EXPECT_EQ(1u, notification_count_);
+
+  // Click the notification button #0.
+  bridge_->ClickButton(notification_id, 0);
+
+  // The notification should have been closed.
+  display_service_->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
+  EXPECT_EQ(0u, notification_count_);
+  EXPECT_EQ(1, notification_manager_->drive_settings_open_count_);
+}
+
 // Tests all the various error notifications.
 TEST_F(SystemNotificationManagerTest, Errors) {
   // Build a Drive sync error object.
-  file_manager_private::DriveSyncErrorEvent sync_error;
-  sync_error.type =
-      file_manager_private::DRIVE_SYNC_ERROR_TYPE_DELETE_WITHOUT_PERMISSION;
+  DriveSyncErrorEvent sync_error;
+  sync_error.type = DRIVE_SYNC_ERROR_TYPE_DELETE_WITHOUT_PERMISSION;
   sync_error.file_url = "drivefs://fake.txt";
-  std::unique_ptr<extensions::Event> event =
-      std::make_unique<extensions::Event>(
-          extensions::events::FILE_MANAGER_PRIVATE_ON_DRIVE_SYNC_ERROR,
-          file_manager_private::OnDriveSyncError::kEventName,
-          file_manager_private::OnDriveSyncError::Create(sync_error));
 
   // Send the delete without permission sync error event.
-  SystemNotificationManager* notification_manager =
-      GetSystemNotificationManager();
-  notification_manager->HandleEvent(*event.get());
-  NotificationDisplayService* notification_display_service =
-      GetNotificationDisplayService();
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_DRIVE_SYNC_ERROR,
+            file_manager_private::OnDriveSyncError::kEventName,
+            file_manager_private::OnDriveSyncError::Create(sync_error)));
   // Get the number of notifications from the NotificationDisplayService.
-  notification_display_service->GetDisplayed(
-      base::BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
-                     weak_ptr_factory_.GetWeakPtr()));
+  display_service_->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
-  const char* id = file_manager_private::ToString(sync_error.type);
+  ASSERT_EQ(1u, notification_count_);
+  const char* id = ToString(sync_error.type);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(id);
+  Strings strings = bridge_->GetStrings(id);
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, kGoogleDrive);
-  EXPECT_EQ(notification_strings.message,
+  EXPECT_EQ(strings.title, kGoogleDrive);
+  EXPECT_EQ(strings.message,
             u"\"fake.txt\" has been shared with you. You cannot delete it "
             u"because you do not own it.");
 
   // Setup for the service unavailable error.
-  sync_error.type =
-      file_manager_private::DRIVE_SYNC_ERROR_TYPE_SERVICE_UNAVAILABLE;
-  event = std::make_unique<extensions::Event>(
-      extensions::events::FILE_MANAGER_PRIVATE_ON_DRIVE_SYNC_ERROR,
-      file_manager_private::OnDriveSyncError::kEventName,
-      file_manager_private::OnDriveSyncError::Create(sync_error));
+  sync_error.type = DRIVE_SYNC_ERROR_TYPE_SERVICE_UNAVAILABLE;
 
   // Send the service unavailable sync error event.
-  notification_manager->HandleEvent(*event.get());
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_DRIVE_SYNC_ERROR,
+            file_manager_private::OnDriveSyncError::kEventName,
+            file_manager_private::OnDriveSyncError::Create(sync_error)));
   // Get the number of notifications from the NotificationDisplayService.
-  notification_display_service->GetDisplayed(
-      base::BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
-                     weak_ptr_factory_.GetWeakPtr()));
+  display_service_->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have two notifications.
-  ASSERT_EQ(2u, notification_count);
-  id = file_manager_private::ToString(sync_error.type);
+  ASSERT_EQ(2u, notification_count_);
+  id = ToString(sync_error.type);
   // Get the strings for the displayed notification.
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(id);
+  strings = bridge_->GetStrings(id);
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, kGoogleDrive);
-  EXPECT_EQ(notification_strings.message,
+  EXPECT_EQ(strings.title, kGoogleDrive);
+  EXPECT_EQ(strings.message,
             u"Google Drive is not available right now. Uploading will "
             u"automatically restart once Google Drive is back.");
 
   // Setup for the no server space error.
-  sync_error.type = file_manager_private::DRIVE_SYNC_ERROR_TYPE_NO_SERVER_SPACE;
-  event = std::make_unique<extensions::Event>(
-      extensions::events::FILE_MANAGER_PRIVATE_ON_DRIVE_SYNC_ERROR,
-      file_manager_private::OnDriveSyncError::kEventName,
-      file_manager_private::OnDriveSyncError::Create(sync_error));
+  sync_error.type = DRIVE_SYNC_ERROR_TYPE_NO_SERVER_SPACE;
 
   // Send the service unavailable sync error event.
-  notification_manager->HandleEvent(*event.get());
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_DRIVE_SYNC_ERROR,
+            file_manager_private::OnDriveSyncError::kEventName,
+            file_manager_private::OnDriveSyncError::Create(sync_error)));
   // Get the number of notifications from the NotificationDisplayService.
-  notification_display_service->GetDisplayed(
-      base::BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
-                     weak_ptr_factory_.GetWeakPtr()));
+  display_service_->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have three notifications.
-  ASSERT_EQ(3u, notification_count);
-  id = file_manager_private::ToString(sync_error.type);
+  ASSERT_EQ(3u, notification_count_);
+  id = ToString(sync_error.type);
   // Get the strings for the displayed notification.
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(id);
+  strings = bridge_->GetStrings(id);
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, kGoogleDrive);
-  EXPECT_EQ(notification_strings.message,
+  EXPECT_EQ(strings.title, kGoogleDrive);
+  EXPECT_EQ(strings.message,
             u"There is not enough free space in your Google Drive to complete "
             u"the upload.");
 
   // Setup for the no local space error.
-  sync_error.type = file_manager_private::DRIVE_SYNC_ERROR_TYPE_NO_LOCAL_SPACE;
-  event = std::make_unique<extensions::Event>(
-      extensions::events::FILE_MANAGER_PRIVATE_ON_DRIVE_SYNC_ERROR,
-      file_manager_private::OnDriveSyncError::kEventName,
-      file_manager_private::OnDriveSyncError::Create(sync_error));
+  sync_error.type = DRIVE_SYNC_ERROR_TYPE_NO_LOCAL_SPACE;
 
   // Send the service unavailable sync error event.
-  notification_manager->HandleEvent(*event.get());
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_DRIVE_SYNC_ERROR,
+            file_manager_private::OnDriveSyncError::kEventName,
+            file_manager_private::OnDriveSyncError::Create(sync_error)));
   // Get the number of notifications from the NotificationDisplayService.
-  notification_display_service->GetDisplayed(
-      base::BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
-                     weak_ptr_factory_.GetWeakPtr()));
+  display_service_->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have four notifications.
-  ASSERT_EQ(4u, notification_count);
-  id = file_manager_private::ToString(sync_error.type);
+  ASSERT_EQ(4u, notification_count_);
+  id = ToString(sync_error.type);
   // Get the strings for the displayed notification.
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(id);
+  strings = bridge_->GetStrings(id);
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, kGoogleDrive);
-  EXPECT_EQ(notification_strings.message, u"You have run out of space");
+  EXPECT_EQ(strings.title, kGoogleDrive);
+  EXPECT_EQ(strings.message, u"You have run out of space");
 
   // Setup for the miscellaneous sync error.
-  sync_error.type = file_manager_private::DRIVE_SYNC_ERROR_TYPE_MISC;
-  event = std::make_unique<extensions::Event>(
-      extensions::events::FILE_MANAGER_PRIVATE_ON_DRIVE_SYNC_ERROR,
-      file_manager_private::OnDriveSyncError::kEventName,
-      file_manager_private::OnDriveSyncError::Create(sync_error));
+  sync_error.type = DRIVE_SYNC_ERROR_TYPE_MISC;
 
   // Send the service unavailable sync error event.
-  notification_manager->HandleEvent(*event.get());
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_DRIVE_SYNC_ERROR,
+            file_manager_private::OnDriveSyncError::kEventName,
+            file_manager_private::OnDriveSyncError::Create(sync_error)));
   // Get the number of notifications from the NotificationDisplayService.
-  notification_display_service->GetDisplayed(
-      base::BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
-                     weak_ptr_factory_.GetWeakPtr()));
+  display_service_->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have five notifications.
-  ASSERT_EQ(5u, notification_count);
-  id = file_manager_private::ToString(sync_error.type);
+  ASSERT_EQ(5u, notification_count_);
+  id = ToString(sync_error.type);
   // Get the strings for the displayed notification.
-  notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(id);
+  strings = bridge_->GetStrings(id);
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, kGoogleDrive);
-  EXPECT_EQ(notification_strings.message,
+  EXPECT_EQ(strings.title, kGoogleDrive);
+  EXPECT_EQ(strings.message,
             u"Google Drive was unable to sync \"fake.txt\" right now. Google "
             u"Drive will try again later.");
 }
@@ -1490,320 +1482,271 @@
   drive_event.type =
       file_manager_private::DRIVE_CONFIRM_DIALOG_TYPE_ENABLE_DOCS_OFFLINE;
   drive_event.file_url = "drivefs://fake";
-  std::unique_ptr<extensions::Event> event =
-      std::make_unique<extensions::Event>(
-          extensions::events::FILE_MANAGER_PRIVATE_ON_DRIVE_CONFIRM_DIALOG,
-          file_manager_private::OnDriveConfirmDialog::kEventName,
-          file_manager_private::OnDriveConfirmDialog::Create(drive_event));
-  GetSystemNotificationManager()->HandleEvent(*event.get());
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_DRIVE_CONFIRM_DIALOG,
+            file_manager_private::OnDriveConfirmDialog::kEventName,
+            file_manager_private::OnDriveConfirmDialog::Create(drive_event)));
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          "swa-drive-confirm-dialog");
+  Strings strings = bridge_->GetStrings("swa-drive-confirm-dialog");
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, kGoogleDrive);
-  EXPECT_EQ(notification_strings.message,
+  EXPECT_EQ(strings.title, kGoogleDrive);
+  EXPECT_EQ(strings.message,
             u"Enable Google Docs Offline to make Docs, Sheets and Slides "
             u"available offline.");
 }
 
 TEST_F(SystemNotificationManagerTest, SyncProgressSingle) {
   // Setup a sync progress status object.
-  file_manager_private::FileTransferStatus transfer_status;
-  transfer_status.transfer_state =
-      file_manager_private::TRANSFER_STATE_IN_PROGRESS;
-  transfer_status.num_total_jobs = 1;
-  transfer_status.file_url =
+  FileTransferStatus status;
+  status.transfer_state = TRANSFER_STATE_IN_PROGRESS;
+  status.num_total_jobs = 1;
+  status.file_url =
       "filesystem:chrome://file-manager/drive/MyDrive-test-user/file.txt";
-  transfer_status.processed = 0;
-  transfer_status.total = 100;
-  transfer_status.show_notification = true;
-  std::unique_ptr<extensions::Event> event =
-      std::make_unique<extensions::Event>(
-          extensions::events::FILE_MANAGER_PRIVATE_ON_FILE_TRANSFERS_UPDATED,
-          file_manager_private::OnFileTransfersUpdated::kEventName,
-          file_manager_private::OnFileTransfersUpdated::Create(
-              transfer_status));
+  status.processed = 0;
+  status.total = 100;
+  status.show_notification = true;
 
   // Send the transfers updated event.
-  GetSystemNotificationManager()->HandleEvent(*event.get());
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_FILE_TRANSFERS_UPDATED,
+            file_manager_private::OnFileTransfersUpdated::kEventName,
+            file_manager_private::OnFileTransfersUpdated::Create(status)));
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          "swa-drive-sync");
+  Strings strings = bridge_->GetStrings("swa-drive-sync");
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, u"Files");
-  EXPECT_EQ(notification_strings.message, u"Syncing file.txt\x2026");
+  EXPECT_EQ(strings.title, u"Files");
+  EXPECT_EQ(strings.message, u"Syncing file.txt\x2026");
   // Setup an completed transfer event.
-  transfer_status.transfer_state =
-      file_manager_private::TRANSFER_STATE_COMPLETED;
-  transfer_status.num_total_jobs = 0;
-  event = std::make_unique<extensions::Event>(
-      extensions::events::FILE_MANAGER_PRIVATE_ON_FILE_TRANSFERS_UPDATED,
-      file_manager_private::OnFileTransfersUpdated::kEventName,
-      file_manager_private::OnFileTransfersUpdated::Create(transfer_status));
+  status.transfer_state = TRANSFER_STATE_COMPLETED;
+  status.num_total_jobs = 0;
 
   // Send the completed transfer event.
-  GetSystemNotificationManager()->HandleEvent(*event.get());
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_FILE_TRANSFERS_UPDATED,
+            file_manager_private::OnFileTransfersUpdated::kEventName,
+            file_manager_private::OnFileTransfersUpdated::Create(status)));
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have 0 notifications (notification closed on end).
-  ASSERT_EQ(0u, notification_count);
+  ASSERT_EQ(0u, notification_count_);
   // Start another transfer that ends in error.
-  transfer_status.transfer_state =
-      file_manager_private::TRANSFER_STATE_IN_PROGRESS;
-  event = std::make_unique<extensions::Event>(
-      extensions::events::FILE_MANAGER_PRIVATE_ON_FILE_TRANSFERS_UPDATED,
-      file_manager_private::OnFileTransfersUpdated::kEventName,
-      file_manager_private::OnFileTransfersUpdated::Create(transfer_status));
+  status.transfer_state = TRANSFER_STATE_IN_PROGRESS;
 
   // Send the transfers updated event.
-  GetSystemNotificationManager()->HandleEvent(*event.get());
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_FILE_TRANSFERS_UPDATED,
+            file_manager_private::OnFileTransfersUpdated::kEventName,
+            file_manager_private::OnFileTransfersUpdated::Create(status)));
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Setup an completed transfer event.
-  transfer_status.transfer_state = file_manager_private::TRANSFER_STATE_FAILED;
-  transfer_status.num_total_jobs = 0;
-  event = std::make_unique<extensions::Event>(
-      extensions::events::FILE_MANAGER_PRIVATE_ON_FILE_TRANSFERS_UPDATED,
-      file_manager_private::OnFileTransfersUpdated::kEventName,
-      file_manager_private::OnFileTransfersUpdated::Create(transfer_status));
+  status.transfer_state = TRANSFER_STATE_FAILED;
+  status.num_total_jobs = 0;
 
   // Send the completed transfer event.
-  GetSystemNotificationManager()->HandleEvent(*event.get());
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_FILE_TRANSFERS_UPDATED,
+            file_manager_private::OnFileTransfersUpdated::kEventName,
+            file_manager_private::OnFileTransfersUpdated::Create(status)));
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have 0 notifications (notification closed on end).
-  ASSERT_EQ(0u, notification_count);
+  ASSERT_EQ(0u, notification_count_);
 }
 
 TEST_F(SystemNotificationManagerTest, SyncProgressIgnoreNotification) {
   // Setup a sync progress status.
-  file_manager_private::FileTransferStatus transfer_status;
-  transfer_status.transfer_state =
-      file_manager_private::TRANSFER_STATE_IN_PROGRESS;
-  transfer_status.num_total_jobs = 1;
-  transfer_status.file_url =
+  FileTransferStatus status;
+  status.transfer_state = TRANSFER_STATE_IN_PROGRESS;
+  status.num_total_jobs = 1;
+  status.file_url =
       "filesystem:chrome://file-manager/drive/MyDrive-test-user/file.txt";
-  transfer_status.processed = 25;
-  transfer_status.total = 100;
-  transfer_status.show_notification = true;
-  std::unique_ptr<extensions::Event> event =
-      std::make_unique<extensions::Event>(
-          extensions::events::FILE_MANAGER_PRIVATE_ON_FILE_TRANSFERS_UPDATED,
-          file_manager_private::OnFileTransfersUpdated::kEventName,
-          file_manager_private::OnFileTransfersUpdated::Create(
-              transfer_status));
+  status.processed = 25;
+  status.total = 100;
+  status.show_notification = true;
 
   // Send the transfers updated event.
-  GetSystemNotificationManager()->HandleEvent(*event.get());
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_FILE_TRANSFERS_UPDATED,
+            file_manager_private::OnFileTransfersUpdated::kEventName,
+            file_manager_private::OnFileTransfersUpdated::Create(status)));
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
 
   // Update the transfer event to hide the notification.
-  transfer_status.transfer_state =
-      file_manager_private::TRANSFER_STATE_COMPLETED;
-  transfer_status.num_total_jobs = 0;
-  transfer_status.processed = 0;
-  transfer_status.total = 0;
-  transfer_status.show_notification = false;
-  event = std::make_unique<extensions::Event>(
-      extensions::events::FILE_MANAGER_PRIVATE_ON_FILE_TRANSFERS_UPDATED,
-      file_manager_private::OnFileTransfersUpdated::kEventName,
-      file_manager_private::OnFileTransfersUpdated::Create(transfer_status));
+  status.transfer_state = TRANSFER_STATE_COMPLETED;
+  status.num_total_jobs = 0;
+  status.processed = 0;
+  status.total = 0;
+  status.show_notification = false;
 
   // Send the transfers updated event.
-  GetSystemNotificationManager()->HandleEvent(*event.get());
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_FILE_TRANSFERS_UPDATED,
+            file_manager_private::OnFileTransfersUpdated::kEventName,
+            file_manager_private::OnFileTransfersUpdated::Create(status)));
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have no notification.
-  ASSERT_EQ(0u, notification_count);
+  ASSERT_EQ(0u, notification_count_);
 }
 
 TEST_F(SystemNotificationManagerTest, SyncProgressMultiple) {
   // Setup a sync progress status object.
-  file_manager_private::FileTransferStatus transfer_status;
-  transfer_status.transfer_state =
-      file_manager_private::TRANSFER_STATE_IN_PROGRESS;
-  transfer_status.num_total_jobs = 10;
-  transfer_status.file_url =
+  FileTransferStatus status;
+  status.transfer_state = TRANSFER_STATE_IN_PROGRESS;
+  status.num_total_jobs = 10;
+  status.file_url =
       "filesystem:chrome://file-manager/drive/MyDrive-test-user/file.txt";
-  transfer_status.processed = 0;
-  transfer_status.total = 100;
-  transfer_status.show_notification = true;
-  std::unique_ptr<extensions::Event> event =
-      std::make_unique<extensions::Event>(
-          extensions::events::FILE_MANAGER_PRIVATE_ON_FILE_TRANSFERS_UPDATED,
-          file_manager_private::OnFileTransfersUpdated::kEventName,
-          file_manager_private::OnFileTransfersUpdated::Create(
-              transfer_status));
+  status.processed = 0;
+  status.total = 100;
+  status.show_notification = true;
 
   // Send the transfers updated event.
-  GetSystemNotificationManager()->HandleEvent(*event.get());
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_FILE_TRANSFERS_UPDATED,
+            file_manager_private::OnFileTransfersUpdated::kEventName,
+            file_manager_private::OnFileTransfersUpdated::Create(status)));
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings =
-      notification_platform_bridge->GetNotificationStringsById(
-          "swa-drive-sync");
+  Strings strings = bridge_->GetStrings("swa-drive-sync");
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, u"Files");
-  EXPECT_EQ(notification_strings.message, u"Syncing 10 items\x2026");
+  EXPECT_EQ(strings.title, u"Files");
+  EXPECT_EQ(strings.message, u"Syncing 10 items\x2026");
 }
 
 TEST_F(SystemNotificationManagerTest, PinProgressSingle) {
   // Setup a pin progress status object.
-  file_manager_private::FileTransferStatus pin_status;
-  pin_status.transfer_state = file_manager_private::TRANSFER_STATE_IN_PROGRESS;
-  pin_status.num_total_jobs = 1;
-  pin_status.file_url =
+  FileTransferStatus status;
+  status.transfer_state = TRANSFER_STATE_IN_PROGRESS;
+  status.num_total_jobs = 1;
+  status.file_url =
       "filesystem:chrome://file-manager/drive/MyDrive-test-user/file.txt";
-  pin_status.processed = 0;
-  pin_status.total = 100;
-  pin_status.show_notification = true;
-  std::unique_ptr<extensions::Event> event =
-      std::make_unique<extensions::Event>(
-          extensions::events::FILE_MANAGER_PRIVATE_ON_PIN_TRANSFERS_UPDATED,
-          file_manager_private::OnFileTransfersUpdated::kEventName,
-          file_manager_private::OnFileTransfersUpdated::Create(pin_status));
+  status.processed = 0;
+  status.total = 100;
+  status.show_notification = true;
 
   // Send the transfers updated event.
-  GetSystemNotificationManager()->HandleEvent(*event.get());
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_PIN_TRANSFERS_UPDATED,
+            file_manager_private::OnFileTransfersUpdated::kEventName,
+            file_manager_private::OnFileTransfersUpdated::Create(status)));
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings =
-      notification_platform_bridge->GetNotificationStringsById("swa-drive-pin");
+  Strings strings = bridge_->GetStrings("swa-drive-pin");
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, u"Files");
-  EXPECT_EQ(notification_strings.message, u"Making file.txt available offline");
+  EXPECT_EQ(strings.title, u"Files");
+  EXPECT_EQ(strings.message, u"Making file.txt available offline");
   // Setup an completed transfer event.
-  pin_status.transfer_state = file_manager_private::TRANSFER_STATE_COMPLETED;
-  pin_status.num_total_jobs = 0;
-  event = std::make_unique<extensions::Event>(
-      extensions::events::FILE_MANAGER_PRIVATE_ON_PIN_TRANSFERS_UPDATED,
-      file_manager_private::OnFileTransfersUpdated::kEventName,
-      file_manager_private::OnFileTransfersUpdated::Create(pin_status));
+  status.transfer_state = TRANSFER_STATE_COMPLETED;
+  status.num_total_jobs = 0;
 
   // Send the completed transfer event.
-  GetSystemNotificationManager()->HandleEvent(*event.get());
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_PIN_TRANSFERS_UPDATED,
+            file_manager_private::OnFileTransfersUpdated::kEventName,
+            file_manager_private::OnFileTransfersUpdated::Create(status)));
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have 0 notifications (notification closed on end).
-  ASSERT_EQ(0u, notification_count);
+  ASSERT_EQ(0u, notification_count_);
 
   // Start another transfer that ends in error.
-  pin_status.transfer_state = file_manager_private::TRANSFER_STATE_IN_PROGRESS;
-  event = std::make_unique<extensions::Event>(
-      extensions::events::FILE_MANAGER_PRIVATE_ON_PIN_TRANSFERS_UPDATED,
-      file_manager_private::OnFileTransfersUpdated::kEventName,
-      file_manager_private::OnFileTransfersUpdated::Create(pin_status));
+  status.transfer_state = TRANSFER_STATE_IN_PROGRESS;
 
   // Send the transfers updated event.
-  GetSystemNotificationManager()->HandleEvent(*event.get());
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_PIN_TRANSFERS_UPDATED,
+            file_manager_private::OnFileTransfersUpdated::kEventName,
+            file_manager_private::OnFileTransfersUpdated::Create(status)));
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Setup an completed transfer event.
-  pin_status.transfer_state = file_manager_private::TRANSFER_STATE_FAILED;
-  pin_status.num_total_jobs = 0;
-  event = std::make_unique<extensions::Event>(
-      extensions::events::FILE_MANAGER_PRIVATE_ON_PIN_TRANSFERS_UPDATED,
-      file_manager_private::OnFileTransfersUpdated::kEventName,
-      file_manager_private::OnFileTransfersUpdated::Create(pin_status));
+  status.transfer_state = TRANSFER_STATE_FAILED;
+  status.num_total_jobs = 0;
 
   // Send the completed transfer event.
-  GetSystemNotificationManager()->HandleEvent(*event.get());
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_PIN_TRANSFERS_UPDATED,
+            file_manager_private::OnFileTransfersUpdated::kEventName,
+            file_manager_private::OnFileTransfersUpdated::Create(status)));
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have 0 notifications (notification closed on end).
-  ASSERT_EQ(0u, notification_count);
+  ASSERT_EQ(0u, notification_count_);
 }
 
 TEST_F(SystemNotificationManagerTest, PinProgressMultiple) {
   // Setup a pin progress status object.
-  file_manager_private::FileTransferStatus pin_status;
-  pin_status.transfer_state = file_manager_private::TRANSFER_STATE_IN_PROGRESS;
-  pin_status.num_total_jobs = 10;
-  pin_status.file_url =
+  FileTransferStatus status;
+  status.transfer_state = TRANSFER_STATE_IN_PROGRESS;
+  status.num_total_jobs = 10;
+  status.file_url =
       "filesystem:chrome://file-manager/drive/MyDrive-test-user/file.txt";
-  pin_status.processed = 0;
-  pin_status.total = 100;
-  pin_status.show_notification = true;
-  std::unique_ptr<extensions::Event> event =
-      std::make_unique<extensions::Event>(
-          extensions::events::FILE_MANAGER_PRIVATE_ON_PIN_TRANSFERS_UPDATED,
-          file_manager_private::OnFileTransfersUpdated::kEventName,
-          file_manager_private::OnFileTransfersUpdated::Create(pin_status));
+  status.processed = 0;
+  status.total = 100;
+  status.show_notification = true;
 
   // Send the transfers updated event.
-  GetSystemNotificationManager()->HandleEvent(*event.get());
+  notification_manager_->HandleEvent(
+      Event(FILE_MANAGER_PRIVATE_ON_PIN_TRANSFERS_UPDATED,
+            file_manager_private::OnFileTransfersUpdated::kEventName,
+            file_manager_private::OnFileTransfersUpdated::Create(status)));
   // Get the number of notifications from the NotificationDisplayService.
-  NotificationDisplayServiceFactory::GetForProfile(GetProfile())
-      ->GetDisplayed(base::BindOnce(
-          &SystemNotificationManagerTest::GetNotificationsCallback,
-          weak_ptr_factory_.GetWeakPtr()));
+  NotificationDisplayServiceFactory::GetForProfile(profile_)->GetDisplayed(
+      BindOnce(&SystemNotificationManagerTest::GetNotificationsCallback,
+               weak_ptr_factory_.GetWeakPtr()));
   // Check: We have one notification.
-  ASSERT_EQ(1u, notification_count);
+  ASSERT_EQ(1u, notification_count_);
   // Get the strings for the displayed notification.
-  TestNotificationStrings notification_strings =
-      notification_platform_bridge->GetNotificationStringsById("swa-drive-pin");
+  Strings strings = bridge_->GetStrings("swa-drive-pin");
   // Check: the expected strings match.
-  EXPECT_EQ(notification_strings.title, u"Files");
-  EXPECT_EQ(notification_strings.message, u"Making 10 files available offline");
+  EXPECT_EQ(strings.title, u"Files");
+  EXPECT_EQ(strings.message, u"Making 10 files available offline");
 }
 
 }  // namespace file_manager
diff --git a/chrome/browser/ash/file_manager/file_tasks.h b/chrome/browser/ash/file_manager/file_tasks.h
index 4d01749..359ab47 100644
--- a/chrome/browser/ash/file_manager/file_tasks.h
+++ b/chrome/browser/ash/file_manager/file_tasks.h
@@ -1,7 +1,7 @@
 // Copyright 2012 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 provides utility functions for "file tasks".
 //
 // WHAT ARE FILE TASKS?
@@ -87,6 +87,10 @@
 //  3. Tasks where the browser process opens Files app to a folder or file, e.g.
 //     "open" and "select", through file_manager::util::OpenItem().
 //
+//  "Virtual Tasks" don't belong to any one app, and don't have a JS
+//  implementation. Executing a virtual task simply means running their C++
+//  |Execute()| method. See VirtualTask for more.
+//
 // See also: ui/file_manager/file_manager/foreground/js/file_tasks.js
 //
 
diff --git a/chrome/browser/ash/file_manager/virtual_file_tasks.cc b/chrome/browser/ash/file_manager/virtual_file_tasks.cc
new file mode 100644
index 0000000..fa2cbe7a
--- /dev/null
+++ b/chrome/browser/ash/file_manager/virtual_file_tasks.cc
@@ -0,0 +1,96 @@
+// 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/ash/file_manager/virtual_file_tasks.h"
+
+#include <initializer_list>
+#include <vector>
+
+#include "ash/webui/file_manager/url_constants.h"
+#include "base/no_destructor.h"
+#include "base/strings/strcat.h"
+#include "chrome/browser/ash/file_manager/app_id.h"
+#include "chrome/browser/ash/file_manager/file_tasks.h"
+#include "chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h"
+#include "components/services/app_service/public/cpp/intent_util.h"
+#include "content/public/browser/network_service_instance.h"
+
+namespace file_manager::file_tasks {
+
+std::vector<VirtualTask*>& GetTestVirtualTasks() {
+  static base::NoDestructor<std::vector<VirtualTask*>> virtual_tasks;
+  return *virtual_tasks;
+}
+
+// The set of virtual tasks is statically determined. Tasks can turn themselves
+// on or off dynamically by implementing |IsEnabled()|.
+const std::vector<VirtualTask*> GetVirtualTasks() {
+  static const base::NoDestructor<std::vector<VirtualTask*>> virtual_tasks(
+      std::initializer_list<VirtualTask*>({}));
+  if (!GetTestVirtualTasks().empty()) {
+    return GetTestVirtualTasks();
+  }
+  return *virtual_tasks;
+}
+
+void FindVirtualTasks(Profile* profile,
+                      const std::vector<extensions::EntryInfo>& entries,
+                      const std::vector<GURL>& file_urls,
+                      const std::vector<std::string>& dlp_source_urls,
+                      std::vector<FullTaskDescriptor>* result_list) {
+  DCHECK_EQ(entries.size(), file_urls.size());
+  if (entries.empty()) {
+    return;
+  }
+  for (const VirtualTask* virtual_task : GetVirtualTasks()) {
+    if (virtual_task->IsEnabled(profile) &&
+        virtual_task->Matches(entries, file_urls, dlp_source_urls)) {
+      // TODO(b/284800493): Correct values below.
+      result_list->emplace_back(
+          TaskDescriptor{kFileManagerSwaAppId, TASK_TYPE_WEB_APP,
+                         virtual_task->id()},
+          virtual_task->title(), virtual_task->icon_url(),
+          /* is_default=*/false,
+          /* is_generic_file_handler=*/false,
+          /* is_file_extension_match=*/false,
+          /* is_dlp_blocked=*/false);
+    }
+  }
+}
+
+bool ExecuteVirtualTask(Profile* profile,
+                        const TaskDescriptor& task,
+                        const std::vector<FileSystemURL>& file_urls,
+                        gfx::NativeWindow modal_parent) {
+  if (!IsVirtualTask(task)) {
+    return false;
+  }
+
+  for (const VirtualTask* virtual_task : GetVirtualTasks()) {
+    if (virtual_task->id() == task.action_id &&
+        virtual_task->IsEnabled(profile)) {
+      return virtual_task->Execute(profile, task, file_urls, modal_parent);
+    }
+  }
+  return false;
+}
+
+bool IsVirtualTask(const TaskDescriptor& task) {
+  if (task.app_id != kFileManagerSwaAppId ||
+      task.task_type != TASK_TYPE_WEB_APP) {
+    return false;
+  }
+
+  for (const VirtualTask* virtual_task : GetVirtualTasks()) {
+    if (virtual_task->id() == task.action_id) {
+      return true;
+    }
+  }
+  return false;
+}
+
+VirtualTask::VirtualTask() = default;
+VirtualTask::~VirtualTask() = default;
+
+}  // namespace file_manager::file_tasks
diff --git a/chrome/browser/ash/file_manager/virtual_file_tasks.h b/chrome/browser/ash/file_manager/virtual_file_tasks.h
new file mode 100644
index 0000000..ab08e3bf
--- /dev/null
+++ b/chrome/browser/ash/file_manager/virtual_file_tasks.h
@@ -0,0 +1,86 @@
+// 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_ASH_FILE_MANAGER_VIRTUAL_FILE_TASKS_H_
+#define CHROME_BROWSER_ASH_FILE_MANAGER_VIRTUAL_FILE_TASKS_H_
+
+#include <vector>
+
+#include "chrome/browser/ash/file_manager/file_tasks.h"
+#include "extensions/browser/entry_info.h"
+#include "url/gurl.h"
+
+class Profile;
+
+namespace file_manager::file_tasks {
+
+// VirtualTasks are tasks that are not implemented using any 'app' file handling
+// API, but instead have their implementation in C++. These used to be listed in
+// the Files app manifest, but they were never implemented in Files app. We
+// still use the Files app ID (kFileManagerSwaAppId) to store these tasks in
+// prefs, but this could be migrated in the future. All registered VirtualTasks
+// are listed in |GetVirtualTasks()|.
+class VirtualTask {
+ public:
+  VirtualTask();
+  virtual ~VirtualTask();
+
+  // Disallow copy and assign.
+  VirtualTask(const VirtualTask&) = delete;
+  VirtualTask& operator=(const VirtualTask&) = delete;
+
+  // Execute the task and return an indication of whether it completed, or
+  // started running, if there are async steps.
+  virtual bool Execute(Profile* profile,
+                       const TaskDescriptor& task,
+                       const std::vector<FileSystemURL>& file_urls,
+                       gfx::NativeWindow modal_parent) const = 0;
+  // Whether this task should be included in |FindVirtualTasks()|. This can be
+  // used to disable tasks based on a flag or other runtime conditions.
+  virtual bool IsEnabled(Profile* profile) const = 0;
+  // Whether this task should be available to execute on the supplied files, if
+  // enabled. |Matches()| can return true even if the task is disabled - in this
+  // case the task will not be found by |FindVirtualTasks()|.
+  virtual bool Matches(
+      const std::vector<extensions::EntryInfo>& entries,
+      const std::vector<GURL>& file_urls,
+      const std::vector<std::string>& dlp_source_urls) const = 0;
+
+  // The ID of this task, which is unique across all virtual tasks. Used for
+  // storing in preferences, and referring to this task in a TaskDescriptor.
+  // These values currently match legacy values from the Files app manifest.
+  virtual std::string id() const = 0;
+  // The user-visible icon in Files app. This can be overridden in Files app
+  // frontend in file_tasks.ts, based on action ID.
+  virtual GURL icon_url() const = 0;
+  // The user-visible title in Files app - make sure it's translated. This can
+  // be overridden in Files app frontend in file_tasks.ts, based on action ID.
+  virtual std::string title() const = 0;
+};
+
+// Appends any virtual tasks that are enabled and match |entries|/|file_urls| to
+// |result_list|.
+void FindVirtualTasks(Profile* profile,
+                      const std::vector<extensions::EntryInfo>& entries,
+                      const std::vector<GURL>& file_urls,
+                      const std::vector<std::string>& dlp_source_urls,
+                      std::vector<FullTaskDescriptor>* result_list);
+
+// Run |task| by calling |Execute()| on the associated VirtualTask.
+bool ExecuteVirtualTask(Profile* profile,
+                        const TaskDescriptor& task,
+                        const std::vector<FileSystemURL>& file_urls,
+                        gfx::NativeWindow modal_parent);
+
+// Whether |task| is a virtual task and can be executed using
+// |ExecuteVirtualTask()|. Returns true for disabled tasks, too.
+bool IsVirtualTask(const TaskDescriptor& task);
+
+// Tests can insert into this vector and it will be used instead of the real
+// tasks if it's non-empty.
+std::vector<VirtualTask*>& GetTestVirtualTasks();
+
+}  // namespace file_manager::file_tasks
+
+#endif  // CHROME_BROWSER_ASH_FILE_MANAGER_VIRTUAL_FILE_TASKS_H_
diff --git a/chrome/browser/ash/file_manager/virtual_file_tasks_unittest.cc b/chrome/browser/ash/file_manager/virtual_file_tasks_unittest.cc
new file mode 100644
index 0000000..73bc23b
--- /dev/null
+++ b/chrome/browser/ash/file_manager/virtual_file_tasks_unittest.cc
@@ -0,0 +1,195 @@
+// 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/ash/file_manager/virtual_file_tasks.h"
+
+#include "base/functional/bind.h"
+#include "base/functional/callback_forward.h"
+#include "base/functional/callback_helpers.h"
+#include "base/test/bind.h"
+#include "chrome/browser/ash/file_manager/app_id.h"
+#include "chrome/browser/ash/file_manager/file_tasks.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace file_manager::file_tasks {
+
+class TestVirtualTask : public VirtualTask {
+ public:
+  TestVirtualTask(base::RepeatingClosure execute,
+                  bool execute_result,
+                  bool enabled,
+                  bool matches,
+                  std::string id)
+      : execute_(std::move(execute)),
+        execute_result_(execute_result),
+        enabled_(enabled),
+        matches_(matches),
+        id_(id) {}
+
+  bool Execute(Profile* profile,
+               const TaskDescriptor& task,
+               const std::vector<FileSystemURL>& file_urls,
+               gfx::NativeWindow modal_parent) const override {
+    execute_.Run();
+    return execute_result_;
+  }
+
+  bool IsEnabled(Profile* profile) const override { return enabled_; }
+
+  bool Matches(const std::vector<extensions::EntryInfo>& entries,
+               const std::vector<GURL>& file_urls,
+               const std::vector<std::string>& dlp_source_urls) const override {
+    return matches_;
+  }
+
+  std::string id() const override { return id_; }
+
+  GURL icon_url() const override { return GURL("https://icon_url?"); }
+
+  std::string title() const override { return id() + " title"; }
+
+ private:
+  base::RepeatingClosure execute_;
+  bool execute_result_;
+  bool enabled_;
+  bool matches_;
+  std::string id_;
+};
+
+class VirtualFileTasksTest : public testing::Test {
+ protected:
+  VirtualFileTasksTest() {
+    task1 = std::make_unique<TestVirtualTask>(
+        base::BindLambdaForTesting([this]() { task1_executed_++; }),
+        /*execute_result=*/true,
+        /*enabled=*/true, /*matches=*/true, "https://app/id1");
+    task2 = std::make_unique<TestVirtualTask>(
+        base::BindLambdaForTesting([this]() { task2_executed_++; }),
+        /*execute_result=*/true,
+        /*enabled=*/false, /*matches=*/true, "https://app/id2");
+    task3 = std::make_unique<TestVirtualTask>(
+        base::BindLambdaForTesting([this]() { task3_executed_++; }),
+        /*execute_result=*/false,
+        /*enabled=*/true, /*matches=*/true, "https://app/id3");
+    task4 = std::make_unique<TestVirtualTask>(
+        base::DoNothing(), /*execute_result=*/true,
+        /*enabled=*/true, /*matches=*/false, "https://app/id4");
+  }
+
+  void SetUp() override {
+    std::vector<VirtualTask*>& tasks = GetTestVirtualTasks();
+    tasks.push_back(task1.get());
+    tasks.push_back(task2.get());
+    tasks.push_back(task3.get());
+    tasks.push_back(task4.get());
+  }
+
+  void TearDown() override { GetTestVirtualTasks().clear(); }
+
+  std::unique_ptr<TestVirtualTask> task1;
+  std::unique_ptr<TestVirtualTask> task2;
+  std::unique_ptr<TestVirtualTask> task3;
+  std::unique_ptr<TestVirtualTask> task4;
+  int task1_executed_ = 0;
+  int task2_executed_ = 0;
+  int task3_executed_ = 0;
+};
+
+TEST_F(VirtualFileTasksTest, IsVirtualTask_WrongApp) {
+  TaskDescriptor wrong_app = {"random_app", TASK_TYPE_WEB_APP, task1->id()};
+  ASSERT_FALSE(IsVirtualTask(wrong_app));
+}
+
+TEST_F(VirtualFileTasksTest, IsVirtualTask_WrongType) {
+  TaskDescriptor wrong_type = {kFileManagerSwaAppId, TASK_TYPE_FILE_HANDLER,
+                               task1->id()};
+  ASSERT_FALSE(IsVirtualTask(wrong_type));
+}
+
+TEST_F(VirtualFileTasksTest, IsVirtualTask_WrongActionId) {
+  TaskDescriptor wrong_action_id = {kFileManagerSwaAppId, TASK_TYPE_WEB_APP,
+                                    "https://app/wrongaction"};
+  ASSERT_FALSE(IsVirtualTask(wrong_action_id));
+}
+
+TEST_F(VirtualFileTasksTest, IsVirtualTask_OK) {
+  TaskDescriptor ok_task = {kFileManagerSwaAppId, TASK_TYPE_WEB_APP,
+                            task1->id()};
+  ASSERT_TRUE(IsVirtualTask(ok_task));
+}
+
+TEST_F(VirtualFileTasksTest, ExecuteVirtualTask_WrongApp) {
+  TaskDescriptor wrong_app = {"random_app", TASK_TYPE_WEB_APP, task1->id()};
+  bool result =
+      ExecuteVirtualTask(/*profile=*/nullptr, wrong_app, /*file_urls=*/{},
+                         /*modal_parent=*/nullptr);
+  ASSERT_FALSE(result);
+  ASSERT_EQ(task1_executed_, 0);
+}
+
+TEST_F(VirtualFileTasksTest, ExecuteVirtualTask_WrongActionId) {
+  TaskDescriptor wrong_action_id = {kFileManagerSwaAppId, TASK_TYPE_WEB_APP,
+                                    "https://app/wrongaction"};
+  bool result =
+      ExecuteVirtualTask(/*profile=*/nullptr, wrong_action_id, /*file_urls=*/{},
+                         /*modal_parent=*/nullptr);
+  ASSERT_FALSE(result);
+  ASSERT_EQ(task1_executed_, 0);
+}
+
+TEST_F(VirtualFileTasksTest, ExecuteVirtualTask_OK) {
+  TaskDescriptor ok_task = {kFileManagerSwaAppId, TASK_TYPE_WEB_APP,
+                            task1->id()};
+  bool result =
+      ExecuteVirtualTask(/*profile=*/nullptr, ok_task, /*file_urls=*/{},
+                         /*modal_parent=*/nullptr);
+  ASSERT_TRUE(result);
+  ASSERT_EQ(task1_executed_, 1);
+}
+
+TEST_F(VirtualFileTasksTest, ExecuteVirtualTask_NotEnabled) {
+  TaskDescriptor disabled_task = {kFileManagerSwaAppId, TASK_TYPE_WEB_APP,
+                                  task2->id()};
+  bool result =
+      ExecuteVirtualTask(/*profile=*/nullptr, disabled_task, /*file_urls=*/{},
+                         /*modal_parent=*/nullptr);
+  ASSERT_FALSE(result);
+  ASSERT_EQ(task2_executed_, 0);
+}
+
+TEST_F(VirtualFileTasksTest, ExecuteVirtualTask_ExecuteReturnsFalse) {
+  TaskDescriptor execute_false = {kFileManagerSwaAppId, TASK_TYPE_WEB_APP,
+                                  task3->id()};
+  bool result =
+      ExecuteVirtualTask(/*profile=*/nullptr, execute_false, /*file_urls=*/{},
+                         /*modal_parent=*/nullptr);
+  ASSERT_FALSE(result);
+  ASSERT_EQ(task3_executed_, 1);
+}
+
+TEST_F(VirtualFileTasksTest, FindVirtualTasks_EmptyFileList) {
+  std::vector<FullTaskDescriptor> result_list;
+  FindVirtualTasks(/*profile=*/nullptr, /*entries=*/{},
+                   /*file_urls=*/{}, /*dlp_source_urls=*/{}, &result_list);
+  ASSERT_EQ(result_list.size(), 0UL);
+}
+
+TEST_F(VirtualFileTasksTest, FindVirtualTasks_OneFile) {
+  std::vector<FullTaskDescriptor> result_list;
+  FindVirtualTasks(
+      /*profile=*/nullptr, /*entries=*/
+      {{base::FilePath("/home/chronos/u-123/MyFiles/foo.txt"), "text/plain",
+        /*is_directory=*/false}},
+      /*file_urls=*/
+      {GURL("filesystem:chrome://file-manager/external/Downloads-123/foo.txt")},
+      /*dlp_source_urls=*/{}, &result_list);
+  ASSERT_EQ(result_list.size(), 2UL);
+
+  ASSERT_EQ(result_list[0].task_descriptor.action_id, task1->id());
+  // Task 2 is disabled.
+  ASSERT_EQ(result_list[1].task_descriptor.action_id, task3->id());
+  // Task 4 does not match.
+}
+
+}  // namespace file_manager::file_tasks
diff --git a/chrome/browser/ash/guest_os/guest_os_pref_names.cc b/chrome/browser/ash/guest_os/guest_os_pref_names.cc
index 94ba62c..a35a900 100644
--- a/chrome/browser/ash/guest_os/guest_os_pref_names.cc
+++ b/chrome/browser/ash/guest_os/guest_os_pref_names.cc
@@ -35,6 +35,7 @@
 const char kAppExecutableFileNameKey[] = "executable_file_name";
 const char kAppNameKey[] = "name";
 const char kAppNoDisplayKey[] = "no_display";
+const char kAppTerminalKey[] = "terminal";
 const char kAppScaledKey[] = "scaled";
 const char kAppPackageIdKey[] = "package_id";
 const char kAppStartupWMClassKey[] = "startup_wm_class";
diff --git a/chrome/browser/ash/guest_os/guest_os_pref_names.h b/chrome/browser/ash/guest_os/guest_os_pref_names.h
index a6fd3f7..3cc3a1432 100644
--- a/chrome/browser/ash/guest_os/guest_os_pref_names.h
+++ b/chrome/browser/ash/guest_os/guest_os_pref_names.h
@@ -31,6 +31,7 @@
 extern const char kAppExecutableFileNameKey[];
 extern const char kAppNameKey[];
 extern const char kAppNoDisplayKey[];
+extern const char kAppTerminalKey[];
 extern const char kAppScaledKey[];
 extern const char kAppPackageIdKey[];
 extern const char kAppStartupWMClassKey[];
diff --git a/chrome/browser/ash/guest_os/guest_os_registry_service.cc b/chrome/browser/ash/guest_os/guest_os_registry_service.cc
index e4890cc..36ca88c 100644
--- a/chrome/browser/ash/guest_os/guest_os_registry_service.cc
+++ b/chrome/browser/ash/guest_os/guest_os_registry_service.cc
@@ -191,6 +191,8 @@
                         LocaleStringsProtoToDictionary(app.keywords()));
   pref_registration.Set(guest_os::prefs::kAppNoDisplayKey,
                         base::Value(app.no_display()));
+  pref_registration.Set(guest_os::prefs::kAppTerminalKey,
+                        base::Value(app.terminal()));
   pref_registration.Set(guest_os::prefs::kAppStartupWMClassKey,
                         base::Value(app.startup_wm_class()));
   pref_registration.Set(guest_os::prefs::kAppStartupNotifyKey,
@@ -291,6 +293,7 @@
          ", comment: " + ToString(app.comment()) +
          ", mime_types: " + ToString(app.mime_types()) +
          ", no_display: " + ToString(app.no_display()) +
+         ", terminal: " + ToString(app.terminal()) +
          ", startup_wm_class: " + ToString(app.startup_wm_class()) +
          ", startup_notify: " + ToString(app.startup_notify()) +
          ", keywords: " + ToString(app.keywords()) +
@@ -405,6 +408,9 @@
   return GetBool(guest_os::prefs::kAppNoDisplayKey);
 }
 
+bool GuestOsRegistryService::Registration::Terminal() const {
+  return GetBool(guest_os::prefs::kAppTerminalKey);
+}
 std::string GuestOsRegistryService::Registration::PackageId() const {
   return GetString(guest_os::prefs::kAppPackageIdKey);
 }
diff --git a/chrome/browser/ash/guest_os/guest_os_registry_service.h b/chrome/browser/ash/guest_os/guest_os_registry_service.h
index fe739770..9dc0ed1 100644
--- a/chrome/browser/ash/guest_os/guest_os_registry_service.h
+++ b/chrome/browser/ash/guest_os/guest_os_registry_service.h
@@ -105,6 +105,7 @@
     std::set<std::string> MimeTypes() const;
     std::set<std::string> Keywords() const;
     bool NoDisplay() const;
+    bool Terminal() const;
 
     std::string PackageId() const;
 
diff --git a/chrome/browser/ash/input_method/assistive_suggester.cc b/chrome/browser/ash/input_method/assistive_suggester.cc
index 18b5a01..f9c50e4 100644
--- a/chrome/browser/ash/input_method/assistive_suggester.cc
+++ b/chrome/browser/ash/input_method/assistive_suggester.cc
@@ -545,7 +545,12 @@
   if (IsTopResultMultiWord(suggestions)) {
     current_suggester_ = &multi_word_suggester_;
     current_suggester_->OnExternalSuggestionsUpdated(suggestions, context);
-    RecordAssistiveCoverage(current_suggester_->GetProposeActionType());
+    // The multi word suggester may not show the suggestions we pass to it. The
+    // suggestions received here may be stale and not valid given the current
+    // internal state of the multi word suggester.
+    if (current_suggester_->HasSuggestions()) {
+      RecordAssistiveCoverage(current_suggester_->GetProposeActionType());
+    }
   }
 }
 
diff --git a/chrome/browser/ash/input_method/assistive_suggester_unittest.cc b/chrome/browser/ash/input_method/assistive_suggester_unittest.cc
index 6eaf1fa8..85d27ff 100644
--- a/chrome/browser/ash/input_method/assistive_suggester_unittest.cc
+++ b/chrome/browser/ash/input_method/assistive_suggester_unittest.cc
@@ -1138,13 +1138,13 @@
                                                      TextContext(""));
   assistive_suggester_->OnSurroundingTextChanged(u"h", gfx::Range(1));
   assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
-                                                     TextContext(""));
+                                                     TextContext("h"));
   assistive_suggester_->OnSurroundingTextChanged(u"he", gfx::Range(2));
   assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
-                                                     TextContext(""));
+                                                     TextContext("he"));
   assistive_suggester_->OnSurroundingTextChanged(u"hel", gfx::Range(3));
   assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
-                                                     TextContext(""));
+                                                     TextContext("hel"));
 
   histogram_tester_.ExpectTotalCount("InputMethod.Assistive.Coverage", 1);
   histogram_tester_.ExpectUniqueSample("InputMethod.Assistive.Coverage",
@@ -1169,13 +1169,13 @@
                                                      TextContext(""));
   assistive_suggester_->OnSurroundingTextChanged(u"h", gfx::Range(1));
   assistive_suggester_->OnExternalSuggestionsUpdated(first_suggestions,
-                                                     TextContext(""));
+                                                     TextContext("h"));
   assistive_suggester_->OnSurroundingTextChanged(u"he", gfx::Range(2));
   assistive_suggester_->OnExternalSuggestionsUpdated(first_suggestions,
-                                                     TextContext(""));
+                                                     TextContext("he"));
   assistive_suggester_->OnSurroundingTextChanged(u"he ", gfx::Range(3));
   assistive_suggester_->OnExternalSuggestionsUpdated(second_suggestions,
-                                                     TextContext(""));
+                                                     TextContext("he "));
 
   histogram_tester_.ExpectTotalCount("InputMethod.Assistive.Coverage", 2);
   histogram_tester_.ExpectUniqueSample("InputMethod.Assistive.Coverage",
@@ -1192,7 +1192,7 @@
   assistive_suggester_->OnFocus(5, empty_context);
   assistive_suggester_->OnSurroundingTextChanged(u"why ar", gfx::Range(6));
   assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
-                                                     TextContext(""));
+                                                     TextContext("why ar"));
 
   EXPECT_EQ(assistive_suggester_->OnKeyEvent(PressKey(ui::DomCode::TAB)),
             AssistiveSuggesterKeyResult::kHandled);
@@ -1208,7 +1208,7 @@
   assistive_suggester_->OnFocus(5, empty_context);
   assistive_suggester_->OnSurroundingTextChanged(u"why ar", gfx::Range(6));
   assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
-                                                     TextContext(""));
+                                                     TextContext("why ar"));
 
   EXPECT_EQ(assistive_suggester_->OnKeyEvent(PressKeyWithAlt(ui::DomCode::TAB)),
             AssistiveSuggesterKeyResult::kNotHandled);
@@ -1224,7 +1224,7 @@
   assistive_suggester_->OnFocus(5, empty_context);
   assistive_suggester_->OnSurroundingTextChanged(u"why ar", gfx::Range(6));
   assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
-                                                     TextContext(""));
+                                                     TextContext("why ar"));
 
   EXPECT_EQ(
       assistive_suggester_->OnKeyEvent(PressKeyWithCtrl(ui::DomCode::TAB)),
@@ -1241,7 +1241,7 @@
   assistive_suggester_->OnFocus(5, empty_context);
   assistive_suggester_->OnSurroundingTextChanged(u"why ar", gfx::Range(6));
   assistive_suggester_->OnExternalSuggestionsUpdated(suggestions,
-                                                     TextContext(""));
+                                                     TextContext("why ar"));
 
   EXPECT_EQ(
       assistive_suggester_->OnKeyEvent(PressKeyWithShift(ui::DomCode::TAB)),
diff --git a/chrome/browser/ash/input_method/multi_word_suggester.cc b/chrome/browser/ash/input_method/multi_word_suggester.cc
index 1a9e99d..6056b99 100644
--- a/chrome/browser/ash/input_method/multi_word_suggester.cc
+++ b/chrome/browser/ash/input_method/multi_word_suggester.cc
@@ -119,6 +119,15 @@
       ToSuggestionType(suggestion_mode));
 }
 
+void RecordMultiWordSuggestionState(const MultiWordSuggestionState& state,
+                                    const ime::AssistiveSuggestionMode& mode) {
+  const std::string histogram =
+      mode == ime::AssistiveSuggestionMode::kCompletion
+          ? "InputMethod.Assistive.MultiWord.SuggestionState.Completion"
+          : "InputMethod.Assistive.MultiWord.SuggestionState.Prediction";
+  base::UmaHistogramEnumeration(histogram, state);
+}
+
 absl::optional<int> GetTimeFirstAcceptedSuggestion(Profile* profile) {
   ScopedDictPrefUpdate update(profile->GetPrefs(),
                               prefs::kAssistiveInputFeatureSettings);
@@ -234,6 +243,15 @@
       .mode = multi_word_suggestion->mode,
       .text = base::UTF8ToUTF16(multi_word_suggestion->text),
       .time_first_shown = base::TimeTicks::Now()};
+
+  if (context) {
+    auto suggestion_state = state_.ValidateSuggestion(suggestion, *context);
+    RecordMultiWordSuggestionState(suggestion_state, suggestion.mode);
+    if (suggestion_state != MultiWordSuggestionState::kValid) {
+      return;
+    }
+  }
+
   state_.UpdateSuggestion(suggestion);
   DisplaySuggestionIfAvailable();
 }
@@ -331,7 +349,7 @@
 }
 
 bool MultiWordSuggester::HasSuggestions() {
-  return false;
+  return state_.GetSuggestion().has_value();
 }
 
 std::vector<AssistiveSuggestion> MultiWordSuggester::GetSuggestions() {
@@ -459,6 +477,45 @@
     ReconcileSuggestionWithText();
 }
 
+MultiWordSuggestionState
+MultiWordSuggester::SuggestionState::ValidateSuggestion(
+    const MultiWordSuggester::SuggestionState::Suggestion& suggestion,
+    const ime::SuggestionsTextContext& context) {
+  if (!surrounding_text_) {
+    return MultiWordSuggestionState::kOther;
+  }
+
+  // IME service works with UTF8 whereas here in Chromium surrounding text is
+  // UTF16. The length of the surrounding text from the IME service was
+  // calculated on a UTF8 string, so transforming context.last_n_chars to
+  // UTF16 would invalidate the length sent from IME service.
+  const std::string current_text = base::UTF16ToUTF8(surrounding_text_->text);
+  size_t current_text_length = current_text.length();
+  size_t text_length_when_suggested = context.surrounding_text_length;
+  bool text_matches = base::EndsWith(current_text, context.last_n_chars);
+
+  if (current_text_length == text_length_when_suggested && text_matches) {
+    return MultiWordSuggestionState::kValid;
+  }
+
+  if (current_text_length == text_length_when_suggested && !text_matches) {
+    return MultiWordSuggestionState::kStaleAndUserEditedText;
+  }
+
+  if (current_text_length < text_length_when_suggested) {
+    return MultiWordSuggestionState::kStaleAndUserDeletedText;
+  }
+
+  if (current_text_length > text_length_when_suggested) {
+    return CalculateConfirmedLength(surrounding_text_->text, suggestion.text) >
+                   0
+               ? MultiWordSuggestionState::kStaleAndUserAddedMatchingText
+               : MultiWordSuggestionState::kStaleAndUserAddedDifferentText;
+  }
+
+  return MultiWordSuggestionState::kOther;
+}
+
 void MultiWordSuggester::SuggestionState::ReconcileSuggestionWithText() {
   if (!(suggestion_ && surrounding_text_))
     return;
diff --git a/chrome/browser/ash/input_method/multi_word_suggester.h b/chrome/browser/ash/input_method/multi_word_suggester.h
index 8b13612a..21bc77df 100644
--- a/chrome/browser/ash/input_method/multi_word_suggester.h
+++ b/chrome/browser/ash/input_method/multi_word_suggester.h
@@ -90,6 +90,12 @@
     // Captures new suggestion context.
     void UpdateSuggestion(const Suggestion& suggestion);
 
+    // Validates the given suggestion text context with the current surrounding
+    // text, and returns the state of the given suggestion context.
+    MultiWordSuggestionState ValidateSuggestion(
+        const Suggestion& suggestion,
+        const ime::SuggestionsTextContext& context);
+
     // Takes the current suggestion and surrounding text state, and ensures the
     // confirmed length or any other suggestion details are correct.
     void ReconcileSuggestionWithText();
diff --git a/chrome/browser/ash/input_method/multi_word_suggester_unittest.cc b/chrome/browser/ash/input_method/multi_word_suggester_unittest.cc
index 62213a3..82794048 100644
--- a/chrome/browser/ash/input_method/multi_word_suggester_unittest.cc
+++ b/chrome/browser/ash/input_method/multi_word_suggester_unittest.cc
@@ -410,6 +410,74 @@
   EXPECT_EQ(*pref_after_first_accept, *pref_after_second_accept);
 }
 
+TEST_F(MultiWordSuggesterTest,
+       DropsStaleSuggestionsAfterUserTypesAndTextMismatches) {
+  std::vector<AssistiveSuggestion> suggestions = {
+      AssistiveSuggestion{.mode = AssistiveSuggestionMode::kCompletion,
+                          .type = AssistiveSuggestionType::kMultiWord,
+                          .text = "where are you going"},
+  };
+
+  suggester_->OnFocus(kFocusedContextId);
+  suggester_->OnSurroundingTextChanged(u"wh", gfx::Range(2));
+  suggester_->OnSurroundingTextChanged(u"wha", gfx::Range(3));
+  suggester_->OnSurroundingTextChanged(u"what", gfx::Range(4));
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("wh"));
+
+  EXPECT_FALSE(suggestion_handler_.GetShowingSuggestion());
+}
+
+TEST_F(MultiWordSuggesterTest,
+       DropsStaleSuggestionsAfterUserTypesAndTextMatches) {
+  std::vector<AssistiveSuggestion> suggestions = {
+      AssistiveSuggestion{.mode = AssistiveSuggestionMode::kCompletion,
+                          .type = AssistiveSuggestionType::kMultiWord,
+                          .text = "where are you going"},
+  };
+
+  suggester_->OnFocus(kFocusedContextId);
+  suggester_->OnSurroundingTextChanged(u"wh", gfx::Range(2));
+  suggester_->OnSurroundingTextChanged(u"whe", gfx::Range(3));
+  suggester_->OnSurroundingTextChanged(u"wher", gfx::Range(4));
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("wh"));
+
+  EXPECT_FALSE(suggestion_handler_.GetShowingSuggestion());
+}
+
+TEST_F(MultiWordSuggesterTest,
+       DropsStaleSuggestionsAfterUserUpdatesCurrentText) {
+  std::vector<AssistiveSuggestion> suggestions = {
+      AssistiveSuggestion{.mode = AssistiveSuggestionMode::kCompletion,
+                          .type = AssistiveSuggestionType::kMultiWord,
+                          .text = "where are you going"},
+  };
+
+  suggester_->OnFocus(kFocusedContextId);
+  suggester_->OnSurroundingTextChanged(u"wh", gfx::Range(2));
+  suggester_->OnSurroundingTextChanged(u"w", gfx::Range(1));
+  suggester_->OnSurroundingTextChanged(u"wr", gfx::Range(2));
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("wh"));
+
+  EXPECT_FALSE(suggestion_handler_.GetShowingSuggestion());
+}
+
+TEST_F(MultiWordSuggesterTest,
+       DropsStaleSuggestionsAfterUserDeletesCharacters) {
+  std::vector<AssistiveSuggestion> suggestions = {
+      AssistiveSuggestion{.mode = AssistiveSuggestionMode::kCompletion,
+                          .type = AssistiveSuggestionType::kMultiWord,
+                          .text = "where are you going"},
+  };
+
+  suggester_->OnFocus(kFocusedContextId);
+  suggester_->OnSurroundingTextChanged(u"whe", gfx::Range(3));
+  suggester_->OnSurroundingTextChanged(u"wh", gfx::Range(2));
+  suggester_->OnSurroundingTextChanged(u"w", gfx::Range(1));
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("whe"));
+
+  EXPECT_FALSE(suggestion_handler_.GetShowingSuggestion());
+}
+
 TEST_F(MultiWordSuggesterTest, CalculatesConfirmedLengthForOneWord) {
   std::vector<AssistiveSuggestion> suggestions = {
       AssistiveSuggestion{.mode = AssistiveSuggestionMode::kCompletion,
@@ -1450,6 +1518,259 @@
 }
 
 TEST_F(MultiWordSuggesterTest,
+       RecordsValidCompletionSuggestionWhenTextMatches) {
+  std::vector<AssistiveSuggestion> suggestions = {
+      AssistiveSuggestion{.mode = AssistiveSuggestionMode::kCompletion,
+                          .type = AssistiveSuggestionType::kMultiWord,
+                          .text = "where are you going"},
+  };
+
+  base::HistogramTester histogram_tester;
+  histogram_tester.ExpectTotalCount(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Completion", 0);
+
+  suggester_->OnFocus(kFocusedContextId);
+  suggester_->OnSurroundingTextChanged(u"wh", gfx::Range(2));
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("wh"));
+
+  histogram_tester.ExpectTotalCount(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Completion", 1);
+  histogram_tester.ExpectUniqueSample(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Completion",
+      /*sample=*/MultiWordSuggestionState::kValid,
+      /*expected_bucket_count=*/1);
+}
+
+TEST_F(MultiWordSuggesterTest,
+       RecordsValidPredictionSuggestionWhenTextMatches) {
+  std::vector<AssistiveSuggestion> suggestions = {
+      AssistiveSuggestion{.mode = AssistiveSuggestionMode::kPrediction,
+                          .type = AssistiveSuggestionType::kMultiWord,
+                          .text = "where are you going"},
+  };
+
+  base::HistogramTester histogram_tester;
+  histogram_tester.ExpectTotalCount(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Prediction", 0);
+
+  suggester_->OnFocus(kFocusedContextId);
+  suggester_->OnSurroundingTextChanged(u"hey ", gfx::Range(4));
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("hey "));
+
+  histogram_tester.ExpectTotalCount(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Prediction", 1);
+  histogram_tester.ExpectUniqueSample(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Prediction",
+      /*sample=*/MultiWordSuggestionState::kValid,
+      /*expected_bucket_count=*/1);
+}
+
+TEST_F(MultiWordSuggesterTest,
+       RecordsStaleCompletionSuggestionWhenUserEditsText) {
+  std::vector<AssistiveSuggestion> suggestions = {
+      AssistiveSuggestion{.mode = AssistiveSuggestionMode::kCompletion,
+                          .type = AssistiveSuggestionType::kMultiWord,
+                          .text = "where are you going"},
+  };
+
+  base::HistogramTester histogram_tester;
+  histogram_tester.ExpectTotalCount(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Completion", 0);
+
+  suggester_->OnFocus(kFocusedContextId);
+  suggester_->OnSurroundingTextChanged(u"wh", gfx::Range(2));
+  suggester_->OnSurroundingTextChanged(u"w", gfx::Range(1));
+  suggester_->OnSurroundingTextChanged(u"wr", gfx::Range(2));
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("wh"));
+
+  histogram_tester.ExpectTotalCount(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Completion", 1);
+  histogram_tester.ExpectUniqueSample(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Completion",
+      /*sample=*/MultiWordSuggestionState::kStaleAndUserEditedText,
+      /*expected_bucket_count=*/1);
+}
+
+TEST_F(MultiWordSuggesterTest,
+       RecordsStalePredictionSuggestionWhenUserEditsText) {
+  std::vector<AssistiveSuggestion> suggestions = {
+      AssistiveSuggestion{.mode = AssistiveSuggestionMode::kPrediction,
+                          .type = AssistiveSuggestionType::kMultiWord,
+                          .text = "where are you going"},
+  };
+
+  base::HistogramTester histogram_tester;
+  histogram_tester.ExpectTotalCount(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Prediction", 0);
+
+  suggester_->OnFocus(kFocusedContextId);
+  suggester_->OnSurroundingTextChanged(u"hey ", gfx::Range(4));
+  suggester_->OnSurroundingTextChanged(u"hey", gfx::Range(3));
+  suggester_->OnSurroundingTextChanged(u"he", gfx::Range(2));
+  suggester_->OnSurroundingTextChanged(u"hel", gfx::Range(3));
+  suggester_->OnSurroundingTextChanged(u"hell", gfx::Range(4));
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("hey "));
+
+  histogram_tester.ExpectTotalCount(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Prediction", 1);
+  histogram_tester.ExpectUniqueSample(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Prediction",
+      /*sample=*/MultiWordSuggestionState::kStaleAndUserEditedText,
+      /*expected_bucket_count=*/1);
+}
+
+TEST_F(MultiWordSuggesterTest,
+       RecordsStaleCompletionSuggestionWhenUserDeletesText) {
+  std::vector<AssistiveSuggestion> suggestions = {
+      AssistiveSuggestion{.mode = AssistiveSuggestionMode::kCompletion,
+                          .type = AssistiveSuggestionType::kMultiWord,
+                          .text = "where are you going"},
+  };
+
+  base::HistogramTester histogram_tester;
+  histogram_tester.ExpectTotalCount(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Completion", 0);
+
+  suggester_->OnFocus(kFocusedContextId);
+  suggester_->OnSurroundingTextChanged(u"wh", gfx::Range(2));
+  suggester_->OnSurroundingTextChanged(u"w", gfx::Range(1));
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("wh"));
+
+  histogram_tester.ExpectTotalCount(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Completion", 1);
+  histogram_tester.ExpectUniqueSample(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Completion",
+      /*sample=*/MultiWordSuggestionState::kStaleAndUserDeletedText,
+      /*expected_bucket_count=*/1);
+}
+
+TEST_F(MultiWordSuggesterTest,
+       RecordsStalePredictionSuggestionWhenUserDeletesText) {
+  std::vector<AssistiveSuggestion> suggestions = {
+      AssistiveSuggestion{.mode = AssistiveSuggestionMode::kPrediction,
+                          .type = AssistiveSuggestionType::kMultiWord,
+                          .text = "where are you going"},
+  };
+
+  base::HistogramTester histogram_tester;
+  histogram_tester.ExpectTotalCount(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Prediction", 0);
+
+  suggester_->OnFocus(kFocusedContextId);
+  suggester_->OnSurroundingTextChanged(u"hey ", gfx::Range(4));
+  suggester_->OnSurroundingTextChanged(u"hey", gfx::Range(3));
+  suggester_->OnSurroundingTextChanged(u"he", gfx::Range(2));
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("hey "));
+
+  histogram_tester.ExpectTotalCount(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Prediction", 1);
+  histogram_tester.ExpectUniqueSample(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Prediction",
+      /*sample=*/MultiWordSuggestionState::kStaleAndUserDeletedText,
+      /*expected_bucket_count=*/1);
+}
+
+TEST_F(MultiWordSuggesterTest,
+       RecordsStaleCompletionSuggestionWhenUserAddsMatchingText) {
+  std::vector<AssistiveSuggestion> suggestions = {
+      AssistiveSuggestion{.mode = AssistiveSuggestionMode::kCompletion,
+                          .type = AssistiveSuggestionType::kMultiWord,
+                          .text = "where are you going"},
+  };
+
+  base::HistogramTester histogram_tester;
+  histogram_tester.ExpectTotalCount(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Completion", 0);
+
+  suggester_->OnFocus(kFocusedContextId);
+  suggester_->OnSurroundingTextChanged(u"wh", gfx::Range(2));
+  suggester_->OnSurroundingTextChanged(u"whe", gfx::Range(3));
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("wh"));
+
+  histogram_tester.ExpectTotalCount(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Completion", 1);
+  histogram_tester.ExpectUniqueSample(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Completion",
+      /*sample=*/MultiWordSuggestionState::kStaleAndUserAddedMatchingText,
+      /*expected_bucket_count=*/1);
+}
+
+TEST_F(MultiWordSuggesterTest,
+       RecordsStalePredictionSuggestionWhenUserAddsMatchingText) {
+  std::vector<AssistiveSuggestion> suggestions = {
+      AssistiveSuggestion{.mode = AssistiveSuggestionMode::kPrediction,
+                          .type = AssistiveSuggestionType::kMultiWord,
+                          .text = "where are you going"},
+  };
+
+  base::HistogramTester histogram_tester;
+  histogram_tester.ExpectTotalCount(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Prediction", 0);
+
+  suggester_->OnFocus(kFocusedContextId);
+  suggester_->OnSurroundingTextChanged(u"hey ", gfx::Range(4));
+  suggester_->OnSurroundingTextChanged(u"hey w", gfx::Range(5));
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("hey "));
+
+  histogram_tester.ExpectTotalCount(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Prediction", 1);
+  histogram_tester.ExpectUniqueSample(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Prediction",
+      /*sample=*/MultiWordSuggestionState::kStaleAndUserAddedMatchingText,
+      /*expected_bucket_count=*/1);
+}
+
+TEST_F(MultiWordSuggesterTest,
+       RecordsStaleCompletionSuggestionWhenUserAddsDifferentText) {
+  std::vector<AssistiveSuggestion> suggestions = {
+      AssistiveSuggestion{.mode = AssistiveSuggestionMode::kCompletion,
+                          .type = AssistiveSuggestionType::kMultiWord,
+                          .text = "where are you going"},
+  };
+
+  base::HistogramTester histogram_tester;
+  histogram_tester.ExpectTotalCount(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Completion", 0);
+
+  suggester_->OnFocus(kFocusedContextId);
+  suggester_->OnSurroundingTextChanged(u"wh", gfx::Range(2));
+  suggester_->OnSurroundingTextChanged(u"why", gfx::Range(3));
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("wh"));
+
+  histogram_tester.ExpectTotalCount(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Completion", 1);
+  histogram_tester.ExpectUniqueSample(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Completion",
+      /*sample=*/MultiWordSuggestionState::kStaleAndUserAddedDifferentText,
+      /*expected_bucket_count=*/1);
+}
+
+TEST_F(MultiWordSuggesterTest,
+       RecordsStalePredictionSuggestionWhenUserAddsDifferentText) {
+  std::vector<AssistiveSuggestion> suggestions = {
+      AssistiveSuggestion{.mode = AssistiveSuggestionMode::kPrediction,
+                          .type = AssistiveSuggestionType::kMultiWord,
+                          .text = "where are you going"},
+  };
+
+  base::HistogramTester histogram_tester;
+  histogram_tester.ExpectTotalCount(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Prediction", 0);
+
+  suggester_->OnFocus(kFocusedContextId);
+  suggester_->OnSurroundingTextChanged(u"hey ", gfx::Range(4));
+  suggester_->OnSurroundingTextChanged(u"hey c", gfx::Range(5));
+  suggester_->OnExternalSuggestionsUpdated(suggestions, TextContext("hey "));
+
+  histogram_tester.ExpectTotalCount(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Prediction", 1);
+  histogram_tester.ExpectUniqueSample(
+      "InputMethod.Assistive.MultiWord.SuggestionState.Prediction",
+      /*sample=*/MultiWordSuggestionState::kStaleAndUserAddedDifferentText,
+      /*expected_bucket_count=*/1);
+}
+
+TEST_F(MultiWordSuggesterTest,
        SurroundingTextChangesDoNotTriggerAnnouncements) {
   suggester_->OnFocus(kFocusedContextId);
   suggester_->OnSurroundingTextChanged(u"why are", gfx::Range(7));
diff --git a/chrome/browser/ash/input_method/suggestion_enums.h b/chrome/browser/ash/input_method/suggestion_enums.h
index f11542c..f51508a9 100644
--- a/chrome/browser/ash/input_method/suggestion_enums.h
+++ b/chrome/browser/ash/input_method/suggestion_enums.h
@@ -69,6 +69,20 @@
   kMaxValue = kCompletion,
 };
 
+// Must match with IMEAssistiveMultiWordSuggestionState in enums.xml
+//
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class MultiWordSuggestionState {
+  kOther = 0,
+  kValid = 1,
+  kStaleAndUserEditedText = 2,
+  kStaleAndUserDeletedText = 3,
+  kStaleAndUserAddedMatchingText = 4,
+  kStaleAndUserAddedDifferentText = 5,
+  kMaxValue = kStaleAndUserAddedDifferentText,
+};
+
 }  // namespace ash::input_method
 
 #endif  // CHROME_BROWSER_ASH_INPUT_METHOD_SUGGESTION_ENUMS_H_
diff --git a/chrome/browser/ash/web_applications/crosh_system_web_app_info.cc b/chrome/browser/ash/web_applications/crosh_system_web_app_info.cc
index ecc94bcd..fdb5c55 100644
--- a/chrome/browser/ash/web_applications/crosh_system_web_app_info.cc
+++ b/chrome/browser/ash/web_applications/crosh_system_web_app_info.cc
@@ -55,3 +55,7 @@
 bool CroshSystemAppDelegate::ShouldHaveTabStrip() const {
   return true;
 }
+
+bool CroshSystemAppDelegate::UseSystemThemeColor() const {
+  return false;
+}
diff --git a/chrome/browser/ash/web_applications/crosh_system_web_app_info.h b/chrome/browser/ash/web_applications/crosh_system_web_app_info.h
index 7e55451..ec10af9 100644
--- a/chrome/browser/ash/web_applications/crosh_system_web_app_info.h
+++ b/chrome/browser/ash/web_applications/crosh_system_web_app_info.h
@@ -23,6 +23,7 @@
   Browser* GetWindowForLaunch(Profile* profile, const GURL& url) const override;
   bool ShouldShowInSearch() const override;
   bool ShouldHaveTabStrip() const override;
+  bool UseSystemThemeColor() const override;
 };
 
 // Returns a WebAppInstallInfo used to install the app.
diff --git a/chrome/browser/assist_ranker/assist_ranker_service_factory.cc b/chrome/browser/assist_ranker/assist_ranker_service_factory.cc
index 9b2ced5..ac7290a 100644
--- a/chrome/browser/assist_ranker/assist_ranker_service_factory.cc
+++ b/chrome/browser/assist_ranker/assist_ranker_service_factory.cc
@@ -15,7 +15,8 @@
 
 // static
 AssistRankerServiceFactory* AssistRankerServiceFactory::GetInstance() {
-  return base::Singleton<AssistRankerServiceFactory>::get();
+  static base::NoDestructor<AssistRankerServiceFactory> instance;
+  return instance.get();
 }
 
 // static
@@ -35,7 +36,7 @@
               .WithGuest(ProfileSelection::kRedirectedToOriginal)
               .Build()) {}
 
-AssistRankerServiceFactory::~AssistRankerServiceFactory() {}
+AssistRankerServiceFactory::~AssistRankerServiceFactory() = default;
 
 KeyedService* AssistRankerServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* browser_context) const {
diff --git a/chrome/browser/assist_ranker/assist_ranker_service_factory.h b/chrome/browser/assist_ranker/assist_ranker_service_factory.h
index 5329516..05c604c 100644
--- a/chrome/browser/assist_ranker/assist_ranker_service_factory.h
+++ b/chrome/browser/assist_ranker/assist_ranker_service_factory.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_ASSIST_RANKER_ASSIST_RANKER_SERVICE_FACTORY_H_
 #define CHROME_BROWSER_ASSIST_RANKER_ASSIST_RANKER_SERVICE_FACTORY_H_
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
 
 namespace content {
@@ -29,7 +29,7 @@
       delete;
 
  private:
-  friend struct base::DefaultSingletonTraits<AssistRankerServiceFactory>;
+  friend base::NoDestructor<AssistRankerServiceFactory>;
 
   AssistRankerServiceFactory();
   ~AssistRankerServiceFactory() override;
diff --git a/chrome/browser/autofill/autocomplete_history_manager_factory.cc b/chrome/browser/autofill/autocomplete_history_manager_factory.cc
index a0cd4f6..e7dc811 100644
--- a/chrome/browser/autofill/autocomplete_history_manager_factory.cc
+++ b/chrome/browser/autofill/autocomplete_history_manager_factory.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/autofill/autocomplete_history_manager_factory.h"
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_data_service_factory.h"
 #include "components/autofill/core/browser/autocomplete_history_manager.h"
@@ -22,7 +22,8 @@
 // static
 AutocompleteHistoryManagerFactory*
 AutocompleteHistoryManagerFactory::GetInstance() {
-  return base::Singleton<AutocompleteHistoryManagerFactory>::get();
+  static base::NoDestructor<AutocompleteHistoryManagerFactory> instance;
+  return instance.get();
 }
 
 AutocompleteHistoryManagerFactory::AutocompleteHistoryManagerFactory()
@@ -37,7 +38,8 @@
   DependsOn(WebDataServiceFactory::GetInstance());
 }
 
-AutocompleteHistoryManagerFactory::~AutocompleteHistoryManagerFactory() {}
+AutocompleteHistoryManagerFactory::~AutocompleteHistoryManagerFactory() =
+    default;
 
 KeyedService* AutocompleteHistoryManagerFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
diff --git a/chrome/browser/autofill/autocomplete_history_manager_factory.h b/chrome/browser/autofill/autocomplete_history_manager_factory.h
index b7a48b01..f4d1b9ce 100644
--- a/chrome/browser/autofill/autocomplete_history_manager_factory.h
+++ b/chrome/browser/autofill/autocomplete_history_manager_factory.h
@@ -10,7 +10,7 @@
 
 namespace base {
 template <typename T>
-struct DefaultSingletonTraits;
+class NoDestructor;
 }
 
 class Profile;
@@ -32,7 +32,7 @@
   static AutocompleteHistoryManagerFactory* GetInstance();
 
  private:
-  friend struct base::DefaultSingletonTraits<AutocompleteHistoryManagerFactory>;
+  friend base::NoDestructor<AutocompleteHistoryManagerFactory>;
 
   AutocompleteHistoryManagerFactory();
   ~AutocompleteHistoryManagerFactory() override;
diff --git a/chrome/browser/autofill/autofill_across_iframes_browsertest.cc b/chrome/browser/autofill/autofill_across_iframes_browsertest.cc
index b246205..dda32c8e 100644
--- a/chrome/browser/autofill/autofill_across_iframes_browsertest.cc
+++ b/chrome/browser/autofill/autofill_across_iframes_browsertest.cc
@@ -233,8 +233,7 @@
   AutofillAcrossIframesTest()
       : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
     feature_list_.InitWithFeatures(
-        /*enabled_features=*/{features::kAutofillAcrossIframes,
-                              features::kAutofillSharedAutofill},
+        /*enabled_features=*/{features::kAutofillSharedAutofill},
         /*disabled_features=*/{});
   }
 
diff --git a/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc b/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc
index f821c5b..9fe0764 100644
--- a/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc
+++ b/chrome/browser/autofill/autofill_captured_sites_interactive_uitest.cc
@@ -275,12 +275,10 @@
   // InProcessBrowserTest:
   void SetUpOnMainThread() override {
     AutofillUiTest::SetUpOnMainThread();
-    if (base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-      test_delegate()->SetIgnoreBackToBackMessages(
-          ObservedUiEvents::kPreviewFormData, true);
-      test_delegate()->SetIgnoreBackToBackMessages(
-          ObservedUiEvents::kFormDataFilled, true);
-    }
+    test_delegate()->SetIgnoreBackToBackMessages(
+        ObservedUiEvents::kPreviewFormData, true);
+    test_delegate()->SetIgnoreBackToBackMessages(
+        ObservedUiEvents::kFormDataFilled, true);
     recipe_replayer_ =
         std::make_unique<captured_sites_test_utils::TestRecipeReplayer>(
             browser(), this);
@@ -328,8 +326,7 @@
     // prediction. Test will check this attribute on all the relevant input
     // elements in a form to determine if the form is ready for interaction.
     feature_list_.InitWithFeaturesAndParameters(
-        /*enabled_features=*/{{features::kAutofillAcrossIframes, {}},
-                              {features::test::kAutofillServerCommunication,
+        /*enabled_features=*/{{features::test::kAutofillServerCommunication,
                                {}},
                               {features::test::kAutofillShowTypePredictions,
                                {}},
diff --git a/chrome/browser/autofill/autofill_interactive_uitest.cc b/chrome/browser/autofill/autofill_interactive_uitest.cc
index 93bc3640..087e3b1 100644
--- a/chrome/browser/autofill/autofill_interactive_uitest.cc
+++ b/chrome/browser/autofill/autofill_interactive_uitest.cc
@@ -3136,23 +3136,8 @@
 //   natural delay between fill and refill;
 // - advance by a delta greater than `kLimitBeforeRefill` to simulate that an
 //   event happens too late to actually trigger a refill.
-//
-// The boolean parameter controls whether or not
-// features::kAutofillAcrossIframes is enabled.
-class AutofillInteractiveTestDynamicForm
-    : public AutofillInteractiveTestBase,
-      public testing::WithParamInterface<bool> {
+class AutofillInteractiveTestDynamicForm : public AutofillInteractiveTestBase {
  public:
-  AutofillInteractiveTestDynamicForm() {
-    scoped_feature_list_.InitWithFeatureState(features::kAutofillAcrossIframes,
-                                              GetParam());
-  }
-  AutofillInteractiveTestDynamicForm(
-      const AutofillInteractiveTestDynamicForm&) = delete;
-  AutofillInteractiveTestDynamicForm& operator=(
-      const AutofillInteractiveTestDynamicForm&) = delete;
-  ~AutofillInteractiveTestDynamicForm() override = default;
-
   ValueWaiter ListenForRefill(
       const std::string& id,
       absl::optional<std::string> unblock_variable = "refill") {
@@ -3170,19 +3155,13 @@
   }
 
  protected:
-  base::test::ScopedFeatureList scoped_feature_list_;
-
   TestAutofillClock clock_{AutofillClock::Now()};
   TestAutofillTickClock tick_clock_{AutofillTickClock::NowTicks()};
 };
 
-INSTANTIATE_TEST_SUITE_P(AutofillInteractiveTest,
-                         AutofillInteractiveTestDynamicForm,
-                         testing::Bool());
-
 // Test that we can Autofill dynamically generated forms.
 // TODO(https://crbug.com/1297560): Check back if flakiness is fixed now.
-IN_PROC_BROWSER_TEST_P(AutofillInteractiveTestDynamicForm,
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicChangingFormFill) {
   CreateTestProfile();
   GURL url =
@@ -3205,7 +3184,7 @@
 }
 
 // TODO(https://crbug.com/1297560): Check back if flakiness is fixed now.
-IN_PROC_BROWSER_TEST_P(AutofillInteractiveTestDynamicForm,
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        TwoDynamicChangingFormsFill) {
   CreateTestProfile();
   GURL url = embedded_test_server()->GetURL("a.com",
@@ -3242,7 +3221,7 @@
 }
 
 // Test that forms that dynamically change a second time do not get filled.
-IN_PROC_BROWSER_TEST_P(AutofillInteractiveTestDynamicForm,
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicChangingFormFill_SecondChange) {
   CreateTestProfile();
   GURL url = embedded_test_server()->GetURL(
@@ -3265,7 +3244,7 @@
 }
 
 // Test that forms that dynamically change after a second do not get filled.
-IN_PROC_BROWSER_TEST_P(AutofillInteractiveTestDynamicForm,
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicChangingFormFill_AfterDelay) {
   CreateTestProfile();
   GURL url = embedded_test_server()->GetURL(
@@ -3289,7 +3268,7 @@
 
 // Test that only field of a type group that was filled initially get refilled.
 // TODO(https://crbug.com/1297560): Check back if flakiness is fixed now.
-IN_PROC_BROWSER_TEST_P(AutofillInteractiveTestDynamicForm,
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicChangingFormFill_AddsNewFieldTypeGroups) {
   CreateTestProfile();
   GURL url = embedded_test_server()->GetURL(
@@ -3319,7 +3298,7 @@
 
 // Test that we can autofill forms that dynamically change select fields to text
 // fields by changing the visibilities.
-IN_PROC_BROWSER_TEST_P(AutofillInteractiveTestDynamicForm,
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicFormFill_SelectToText) {
   CreateTestProfile();
 
@@ -3345,7 +3324,7 @@
 // Test that we can autofill forms that dynamically change the visibility of a
 // field after it's autofilled.
 // TODO(https://crbug.com/1297560): Check back if flakiness is fixed now.
-IN_PROC_BROWSER_TEST_P(AutofillInteractiveTestDynamicForm,
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicFormFill_VisibilitySwitch) {
   CreateTestProfile();
   GURL url = embedded_test_server()->GetURL(
@@ -3371,7 +3350,7 @@
 
 // Test that we can autofill forms that dynamically change the element that
 // has been clicked on.
-IN_PROC_BROWSER_TEST_P(AutofillInteractiveTestDynamicForm,
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicFormFill_FirstElementDisappears) {
   CreateTestProfile();
   GURL url = embedded_test_server()->GetURL(
@@ -3395,7 +3374,7 @@
 // Test that we can autofill forms that dynamically change the element that
 // has been clicked on, even though the form has no name.
 // TODO(https://crbug.com/1297560): Check back if flakiness is fixed now.
-IN_PROC_BROWSER_TEST_P(AutofillInteractiveTestDynamicForm,
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicFormFill_FirstElementDisappearsNoNameForm) {
   CreateTestProfile();
 
@@ -3420,7 +3399,7 @@
 // Test that we can autofill forms that dynamically change the element that
 // has been clicked on, even though there are multiple forms with identical
 // names.
-IN_PROC_BROWSER_TEST_P(
+IN_PROC_BROWSER_TEST_F(
     AutofillInteractiveTestDynamicForm,
     DynamicFormFill_FirstElementDisappearsMultipleBadNameForms) {
   CreateTestProfile();
@@ -3448,7 +3427,7 @@
 // Test that we can autofill forms that dynamically change the element that
 // has been clicked on, even though there are multiple forms with identical
 // names.
-IN_PROC_BROWSER_TEST_P(AutofillInteractiveTestDynamicForm,
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicFormFill_FirstElementDisappearsBadnameUnowned) {
   CreateTestProfile();
   GURL url = embedded_test_server()->GetURL(
@@ -3474,7 +3453,7 @@
 // Test that we can autofill forms that dynamically change the element that
 // has been clicked on, even though there are multiple forms with no name.
 // TODO(https://crbug.com/1297560): Check back if flakiness is fixed now.
-IN_PROC_BROWSER_TEST_P(
+IN_PROC_BROWSER_TEST_F(
     AutofillInteractiveTestDynamicForm,
     DynamicFormFill_FirstElementDisappearsMultipleNoNameForms) {
   CreateTestProfile();
@@ -3501,7 +3480,7 @@
 
 // Test that we can autofill forms that dynamically change the element that
 // has been clicked on, even though the elements are unowned.
-IN_PROC_BROWSER_TEST_P(AutofillInteractiveTestDynamicForm,
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicFormFill_FirstElementDisappearsUnowned) {
   CreateTestProfile();
   GURL url = embedded_test_server()->GetURL(
@@ -3523,7 +3502,7 @@
 }
 
 // Test that credit card fields are re-filled.
-IN_PROC_BROWSER_TEST_P(AutofillInteractiveTestDynamicForm,
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicChangingFormFill_AlsoForCreditCard) {
   CreateTestCreditCart();
   GURL url = https_server()->GetURL("a.com",
@@ -3545,7 +3524,7 @@
 
 // Test that we can Autofill dynamically changing selects that have options
 // added and removed.
-IN_PROC_BROWSER_TEST_P(AutofillInteractiveTestDynamicForm,
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicChangingFormFill_SelectUpdated) {
   CreateTestProfile();
   GURL url = embedded_test_server()->GetURL(
@@ -3569,7 +3548,7 @@
 
 // Test that we can Autofill dynamically changing selects that have options
 // added and removed only once.
-IN_PROC_BROWSER_TEST_P(AutofillInteractiveTestDynamicForm,
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicChangingFormFill_DoubleSelectUpdated) {
   CreateTestProfile();
   GURL url = embedded_test_server()->GetURL(
@@ -3597,7 +3576,7 @@
 
 // Test that we can Autofill dynamically generated forms with no name if the
 // NameForAutofill of the first field matches.
-IN_PROC_BROWSER_TEST_P(AutofillInteractiveTestDynamicForm,
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicChangingFormFill_FormWithoutName) {
   CreateTestProfile();
   GURL url = embedded_test_server()->GetURL(
@@ -3623,7 +3602,7 @@
 // added and removed for forms with no names if the NameForAutofill of the first
 // field matches.
 // TODO(https://crbug.com/1297560): Check back if flakiness is fixed now.
-IN_PROC_BROWSER_TEST_P(AutofillInteractiveTestDynamicForm,
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicChangingFormFill_SelectUpdated_FormWithoutName) {
   CreateTestProfile();
   GURL url = embedded_test_server()->GetURL(
@@ -3649,7 +3628,7 @@
 // Test that we can Autofill dynamically generated synthetic forms if the
 // NameForAutofill of the first field matches.
 // TODO(https://crbug.com/1297560): Check back if flakiness is fixed now.
-IN_PROC_BROWSER_TEST_P(AutofillInteractiveTestDynamicForm,
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicChangingFormFill_SyntheticForm) {
   CreateTestProfile();
   GURL url = embedded_test_server()->GetURL(
@@ -3675,7 +3654,7 @@
 // Test that we can Autofill dynamically synthetic forms when the select options
 // change if the NameForAutofill of the first field matches
 // TODO(https://crbug.com/1297560): Check back if flakiness is fixed now.
-IN_PROC_BROWSER_TEST_P(AutofillInteractiveTestDynamicForm,
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        DynamicChangingFormFill_SelectUpdated_SyntheticForm) {
   CreateTestProfile();
   GURL url = embedded_test_server()->GetURL(
@@ -3709,7 +3688,7 @@
 //    09 / 99 instead.
 // 4) The promise waits to see 09 / 99 and resolved.
 // Flaky on Win https://crbug.com/1337757.
-IN_PROC_BROWSER_TEST_P(AutofillInteractiveTestDynamicForm,
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestDynamicForm,
                        FillCardOnReformattingForm) {
   CreateTestCreditCart();
   GURL url = https_server()->GetURL(
diff --git a/chrome/browser/autofill/autofill_offer_manager_factory.cc b/chrome/browser/autofill/autofill_offer_manager_factory.cc
index 2b56477..4e924f4 100644
--- a/chrome/browser/autofill/autofill_offer_manager_factory.cc
+++ b/chrome/browser/autofill/autofill_offer_manager_factory.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/autofill/autofill_offer_manager_factory.h"
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "build/build_config.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "components/autofill/core/browser/payments/autofill_offer_manager.h"
@@ -25,7 +25,8 @@
 
 // static
 AutofillOfferManagerFactory* AutofillOfferManagerFactory::GetInstance() {
-  return base::Singleton<AutofillOfferManagerFactory>::get();
+  static base::NoDestructor<AutofillOfferManagerFactory> instance;
+  return instance.get();
 }
 
 AutofillOfferManagerFactory::AutofillOfferManagerFactory()
diff --git a/chrome/browser/autofill/autofill_offer_manager_factory.h b/chrome/browser/autofill/autofill_offer_manager_factory.h
index dfd3e216..035ac80 100644
--- a/chrome/browser/autofill/autofill_offer_manager_factory.h
+++ b/chrome/browser/autofill/autofill_offer_manager_factory.h
@@ -10,7 +10,7 @@
 
 namespace base {
 template <typename T>
-struct DefaultSingletonTraits;
+class NoDestructor;
 }
 
 namespace autofill {
@@ -31,7 +31,7 @@
   static AutofillOfferManagerFactory* GetInstance();
 
  private:
-  friend struct base::DefaultSingletonTraits<AutofillOfferManagerFactory>;
+  friend base::NoDestructor<AutofillOfferManagerFactory>;
 
   AutofillOfferManagerFactory();
   ~AutofillOfferManagerFactory() override;
diff --git a/chrome/browser/autofill/autofill_optimization_guide_factory.cc b/chrome/browser/autofill/autofill_optimization_guide_factory.cc
index 146c358f..b538351c 100644
--- a/chrome/browser/autofill/autofill_optimization_guide_factory.cc
+++ b/chrome/browser/autofill/autofill_optimization_guide_factory.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/autofill/autofill_optimization_guide_factory.h"
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -24,7 +24,8 @@
 // static
 AutofillOptimizationGuideFactory*
 AutofillOptimizationGuideFactory::GetInstance() {
-  return base::Singleton<AutofillOptimizationGuideFactory>::get();
+  static base::NoDestructor<AutofillOptimizationGuideFactory> instance;
+  return instance.get();
 }
 
 AutofillOptimizationGuideFactory::AutofillOptimizationGuideFactory()
diff --git a/chrome/browser/autofill/autofill_optimization_guide_factory.h b/chrome/browser/autofill/autofill_optimization_guide_factory.h
index 77033185..90df758 100644
--- a/chrome/browser/autofill/autofill_optimization_guide_factory.h
+++ b/chrome/browser/autofill/autofill_optimization_guide_factory.h
@@ -9,7 +9,7 @@
 
 namespace base {
 template <typename T>
-struct DefaultSingletonTraits;
+class NoDestructor;
 }  // namespace base
 
 class KeyedService;
@@ -32,7 +32,7 @@
   static AutofillOptimizationGuideFactory* GetInstance();
 
  private:
-  friend struct base::DefaultSingletonTraits<AutofillOptimizationGuideFactory>;
+  friend base::NoDestructor<AutofillOptimizationGuideFactory>;
 
   AutofillOptimizationGuideFactory();
   ~AutofillOptimizationGuideFactory() override;
diff --git a/chrome/browser/autofill/form_structure_browsertest.cc b/chrome/browser/autofill/form_structure_browsertest.cc
index 69bef35e..2bd22f73 100644
--- a/chrome/browser/autofill/form_structure_browsertest.cc
+++ b/chrome/browser/autofill/form_structure_browsertest.cc
@@ -202,9 +202,7 @@
     : ::testing::DataDrivenTest(GetTestDataDir(), kFeatureName, kTestName) {
   feature_list_.InitWithFeatures(
       // Enabled
-      {// TODO(crbug.com/1187842): Remove once experiment is over.
-       features::kAutofillAcrossIframes,
-       // TODO(crbug.com/1076175) Remove once launched.
+      {// TODO(crbug.com/1076175) Remove once launched.
        features::kAutofillUseNewSectioningMethod,
        // TODO(crbug.com/1157405) Remove once launched.
        features::kAutofillEnableDependentLocalityParsing,
diff --git a/chrome/browser/autofill/iban_manager_factory.cc b/chrome/browser/autofill/iban_manager_factory.cc
index a7502448..3bbbb7a 100644
--- a/chrome/browser/autofill/iban_manager_factory.cc
+++ b/chrome/browser/autofill/iban_manager_factory.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/autofill/iban_manager_factory.h"
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/autofill/core/browser/iban_manager.h"
@@ -19,7 +19,8 @@
 
 // static
 IBANManagerFactory* IBANManagerFactory::GetInstance() {
-  return base::Singleton<IBANManagerFactory>::get();
+  static base::NoDestructor<IBANManagerFactory> instance;
+  return instance.get();
 }
 
 IBANManagerFactory::IBANManagerFactory()
diff --git a/chrome/browser/autofill/iban_manager_factory.h b/chrome/browser/autofill/iban_manager_factory.h
index b669b23..9fff74e 100644
--- a/chrome/browser/autofill/iban_manager_factory.h
+++ b/chrome/browser/autofill/iban_manager_factory.h
@@ -10,7 +10,7 @@
 
 namespace base {
 template <typename T>
-struct DefaultSingletonTraits;
+class NoDestructor;
 }
 
 class Profile;
@@ -29,7 +29,7 @@
   static IBANManagerFactory* GetInstance();
 
  private:
-  friend struct base::DefaultSingletonTraits<IBANManagerFactory>;
+  friend base::NoDestructor<IBANManagerFactory>;
 
   IBANManagerFactory();
   ~IBANManagerFactory() override;
diff --git a/chrome/browser/autofill/merchant_promo_code_manager_factory.cc b/chrome/browser/autofill/merchant_promo_code_manager_factory.cc
index 43bdd9d9..974431f9 100644
--- a/chrome/browser/autofill/merchant_promo_code_manager_factory.cc
+++ b/chrome/browser/autofill/merchant_promo_code_manager_factory.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/autofill/merchant_promo_code_manager_factory.h"
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/autofill/core/browser/merchant_promo_code_manager.h"
@@ -21,7 +21,8 @@
 // static
 MerchantPromoCodeManagerFactory*
 MerchantPromoCodeManagerFactory::GetInstance() {
-  return base::Singleton<MerchantPromoCodeManagerFactory>::get();
+  static base::NoDestructor<MerchantPromoCodeManagerFactory> instance;
+  return instance.get();
 }
 
 MerchantPromoCodeManagerFactory::MerchantPromoCodeManagerFactory()
diff --git a/chrome/browser/autofill/merchant_promo_code_manager_factory.h b/chrome/browser/autofill/merchant_promo_code_manager_factory.h
index 1676284..56454ade 100644
--- a/chrome/browser/autofill/merchant_promo_code_manager_factory.h
+++ b/chrome/browser/autofill/merchant_promo_code_manager_factory.h
@@ -9,7 +9,7 @@
 
 namespace base {
 template <typename T>
-struct DefaultSingletonTraits;
+class NoDestructor;
 }
 
 class Profile;
@@ -30,7 +30,7 @@
   static MerchantPromoCodeManagerFactory* GetInstance();
 
  private:
-  friend struct base::DefaultSingletonTraits<MerchantPromoCodeManagerFactory>;
+  friend base::NoDestructor<MerchantPromoCodeManagerFactory>;
 
   MerchantPromoCodeManagerFactory();
   ~MerchantPromoCodeManagerFactory() override;
diff --git a/chrome/browser/autofill/personal_data_manager_factory.cc b/chrome/browser/autofill/personal_data_manager_factory.cc
index f7d3393e..4d51b84 100644
--- a/chrome/browser/autofill/personal_data_manager_factory.cc
+++ b/chrome/browser/autofill/personal_data_manager_factory.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/autofill/autofill_image_fetcher_factory.h"
 #include "chrome/browser/autofill/strike_database_factory.h"
 #include "chrome/browser/browser_process.h"
@@ -52,7 +52,8 @@
 
 // static
 PersonalDataManagerFactory* PersonalDataManagerFactory::GetInstance() {
-  return base::Singleton<PersonalDataManagerFactory>::get();
+  static base::NoDestructor<PersonalDataManagerFactory> instance;
+  return instance.get();
 }
 
 PersonalDataManagerFactory::PersonalDataManagerFactory()
diff --git a/chrome/browser/autofill/personal_data_manager_factory.h b/chrome/browser/autofill/personal_data_manager_factory.h
index 930c351..07bd946 100644
--- a/chrome/browser/autofill/personal_data_manager_factory.h
+++ b/chrome/browser/autofill/personal_data_manager_factory.h
@@ -8,7 +8,8 @@
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
 
 namespace base {
-template <typename T> struct DefaultSingletonTraits;
+template <typename T>
+class NoDestructor;
 }
 
 class KeyedService;
@@ -39,7 +40,7 @@
       content::BrowserContext* context);
 
  private:
-  friend struct base::DefaultSingletonTraits<PersonalDataManagerFactory>;
+  friend base::NoDestructor<PersonalDataManagerFactory>;
 
   PersonalDataManagerFactory();
   ~PersonalDataManagerFactory() override;
diff --git a/chrome/browser/autofill/strike_database_factory.cc b/chrome/browser/autofill/strike_database_factory.cc
index 0ffa892c..6ccd182 100644
--- a/chrome/browser/autofill/strike_database_factory.cc
+++ b/chrome/browser/autofill/strike_database_factory.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/autofill/strike_database_factory.h"
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/autofill/core/browser/strike_databases/strike_database.h"
 #include "content/public/browser/storage_partition.h"
@@ -19,7 +19,8 @@
 
 // static
 StrikeDatabaseFactory* StrikeDatabaseFactory::GetInstance() {
-  return base::Singleton<StrikeDatabaseFactory>::get();
+  static base::NoDestructor<StrikeDatabaseFactory> instance;
+  return instance.get();
 }
 
 StrikeDatabaseFactory::StrikeDatabaseFactory()
diff --git a/chrome/browser/autofill/strike_database_factory.h b/chrome/browser/autofill/strike_database_factory.h
index c83b73a..21d21c3 100644
--- a/chrome/browser/autofill/strike_database_factory.h
+++ b/chrome/browser/autofill/strike_database_factory.h
@@ -9,7 +9,7 @@
 
 namespace base {
 template <typename T>
-struct DefaultSingletonTraits;
+class NoDestructor;
 }
 
 class Profile;
@@ -32,7 +32,7 @@
   StrikeDatabaseFactory& operator=(const StrikeDatabaseFactory&) = delete;
 
  private:
-  friend struct base::DefaultSingletonTraits<StrikeDatabaseFactory>;
+  friend base::NoDestructor<StrikeDatabaseFactory>;
 
   StrikeDatabaseFactory();
   ~StrikeDatabaseFactory() override;
diff --git a/chrome/browser/background_sync/background_sync_controller_factory.cc b/chrome/browser/background_sync/background_sync_controller_factory.cc
index e8de786..ccd7672 100644
--- a/chrome/browser/background_sync/background_sync_controller_factory.cc
+++ b/chrome/browser/background_sync/background_sync_controller_factory.cc
@@ -20,7 +20,8 @@
 // static
 BackgroundSyncControllerFactory*
 BackgroundSyncControllerFactory::GetInstance() {
-  return base::Singleton<BackgroundSyncControllerFactory>::get();
+  static base::NoDestructor<BackgroundSyncControllerFactory> instance;
+  return instance.get();
 }
 
 BackgroundSyncControllerFactory::BackgroundSyncControllerFactory()
diff --git a/chrome/browser/background_sync/background_sync_controller_factory.h b/chrome/browser/background_sync/background_sync_controller_factory.h
index e6e2f6d..d5afdca9 100644
--- a/chrome/browser/background_sync/background_sync_controller_factory.h
+++ b/chrome/browser/background_sync/background_sync_controller_factory.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_CONTROLLER_FACTORY_H_
 #define CHROME_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_CONTROLLER_FACTORY_H_
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
 
 class BackgroundSyncControllerImpl;
@@ -22,7 +22,7 @@
       const BackgroundSyncControllerFactory&) = delete;
 
  private:
-  friend struct base::DefaultSingletonTraits<BackgroundSyncControllerFactory>;
+  friend base::NoDestructor<BackgroundSyncControllerFactory>;
 
   BackgroundSyncControllerFactory();
   ~BackgroundSyncControllerFactory() override;
diff --git a/chrome/browser/badging/badge_manager_factory.cc b/chrome/browser/badging/badge_manager_factory.cc
index a17d54d1..522f1ba 100644
--- a/chrome/browser/badging/badge_manager_factory.cc
+++ b/chrome/browser/badging/badge_manager_factory.cc
@@ -8,7 +8,7 @@
 
 #include "base/functional/bind.h"
 #include "base/memory/ptr_util.h"
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/badging/badge_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/web_app_provider_factory.h"
@@ -24,7 +24,8 @@
 
 // static
 BadgeManagerFactory* BadgeManagerFactory::GetInstance() {
-  return base::Singleton<BadgeManagerFactory>::get();
+  static base::NoDestructor<BadgeManagerFactory> instance;
+  return instance.get();
 }
 
 BadgeManagerFactory::BadgeManagerFactory()
@@ -39,7 +40,7 @@
   DependsOn(web_app::WebAppProviderFactory::GetInstance());
 }
 
-BadgeManagerFactory::~BadgeManagerFactory() {}
+BadgeManagerFactory::~BadgeManagerFactory() = default;
 
 KeyedService* BadgeManagerFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
diff --git a/chrome/browser/badging/badge_manager_factory.h b/chrome/browser/badging/badge_manager_factory.h
index 147b27d..b2c0258 100644
--- a/chrome/browser/badging/badge_manager_factory.h
+++ b/chrome/browser/badging/badge_manager_factory.h
@@ -9,7 +9,7 @@
 
 namespace base {
 template <typename T>
-struct DefaultSingletonTraits;
+class NoDestructor;
 }
 
 class Profile;
@@ -32,7 +32,7 @@
   BadgeManagerFactory& operator=(const BadgeManagerFactory&) = delete;
 
  private:
-  friend struct base::DefaultSingletonTraits<BadgeManagerFactory>;
+  friend base::NoDestructor<BadgeManagerFactory>;
 
   BadgeManagerFactory();
   ~BadgeManagerFactory() override;
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
index 609906f..ad7ec7a 100644
--- a/chrome/browser/chrome_browser_interface_binders.cc
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -749,10 +749,6 @@
 void BindScreenAIAnnotator(
     content::RenderFrameHost* frame_host,
     mojo::PendingReceiver<screen_ai::mojom::ScreenAIAnnotator> receiver) {
-  // TODO(https://crbug.com/1278249): After user settings are added, add extra
-  // checking here to ensure the service is bound only when user has explicitly
-  // requested it.
-
   content::BrowserContext* browser_context =
       frame_host->GetProcess()->GetBrowserContext();
 
@@ -764,9 +760,6 @@
     content::RenderFrameHost* frame_host,
     mojo::PendingReceiver<screen_ai::mojom::Screen2xMainContentExtractor>
         receiver) {
-  // TODO(https://crbug.com/1278249): After user settings are added, add extra
-  // checking here to ensure the service is bound only when user has explicitly
-  // requested it.
   screen_ai::ScreenAIServiceRouterFactory::GetForBrowserContext(
       frame_host->GetProcess()->GetBrowserContext())
       ->BindMainContentExtractor(std::move(receiver));
diff --git a/chrome/browser/component_updater/app_provisioning_component_installer.cc b/chrome/browser/component_updater/app_provisioning_component_installer.cc
index 4c920a5..db95931 100644
--- a/chrome/browser/component_updater/app_provisioning_component_installer.cc
+++ b/chrome/browser/component_updater/app_provisioning_component_installer.cc
@@ -36,8 +36,6 @@
 
 constexpr base::FilePath::CharType kAppWithLocaleBinaryPbFileName[] =
     FILE_PATH_LITERAL("app_data.textproto");
-constexpr base::FilePath::CharType kDeduplicationBinaryPbFileName[] =
-    FILE_PATH_LITERAL("deduplication_data.pb");
 
 // The SHA256 of the SubjectPublicKeyInfo used to sign the extension.
 // The extension id is: fellaebeeieagcalnmmpapfioejgihci
@@ -49,31 +47,21 @@
 constexpr char kAppProvisioningManifestName[] = "App Provisioning";
 
 absl::optional<apps::ComponentFileContents> LoadAppMetadataFromDisk(
-    const base::FilePath& app_with_locale_pb_path,
-    const base::FilePath& deduplication_pb_path) {
-  if (app_with_locale_pb_path.empty() || deduplication_pb_path.empty())
+    const base::FilePath& app_with_locale_pb_path) {
+  if (app_with_locale_pb_path.empty()) {
     return absl::nullopt;
+  }
 
   VLOG(1) << "Reading Download App Metadata from file: "
-          << app_with_locale_pb_path.value()
-          << " and file: " << deduplication_pb_path.value();
+          << app_with_locale_pb_path.value();
   std::string app_with_locale_binary_pb;
-  std::string deduplication_binary_pb;
   if (!base::ReadFileToString(app_with_locale_pb_path,
                               &app_with_locale_binary_pb)) {
     VLOG(1) << "Failed reading from " << app_with_locale_pb_path.value();
     return absl::nullopt;
   }
 
-  if (base::FeatureList::IsEnabled(features::kAppDeduplicationService) &&
-      !base::ReadFileToString(deduplication_pb_path,
-                              &deduplication_binary_pb)) {
-    VLOG(1) << "Failed reading from " << deduplication_pb_path.value();
-    return absl::nullopt;
-  }
-
-  return apps::ComponentFileContents{app_with_locale_binary_pb,
-                                     deduplication_binary_pb};
+  return apps::ComponentFileContents{app_with_locale_binary_pb};
 }
 
 void UpdateAppMetadataOnUI(
@@ -96,9 +84,7 @@
     const base::FilePath& install_dir) const {
   // No need to actually validate the proto here, since we'll do the checking
   // in `PopulateFromDynamicUpdate()`.
-  return base::PathExists(GetAppWithLocaleInstalledPath(install_dir)) &&
-         (!base::FeatureList::IsEnabled(features::kAppDeduplicationService) ||
-          base::PathExists(GetDeduplicationInstalledPath(install_dir)));
+  return base::PathExists(GetAppWithLocaleInstalledPath(install_dir));
 }
 
 bool AppProvisioningComponentInstallerPolicy::
@@ -129,8 +115,7 @@
   base::ThreadPool::PostTaskAndReplyWithResult(
       FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
       base::BindOnce(&LoadAppMetadataFromDisk,
-                     GetAppWithLocaleInstalledPath(install_dir),
-                     GetDeduplicationInstalledPath(install_dir)),
+                     GetAppWithLocaleInstalledPath(install_dir)),
       base::BindOnce(&UpdateAppMetadataOnUI, install_dir));
 }
 
@@ -160,12 +145,6 @@
   return base.Append(kAppWithLocaleBinaryPbFileName);
 }
 
-base::FilePath
-AppProvisioningComponentInstallerPolicy::GetDeduplicationInstalledPath(
-    const base::FilePath& base) {
-  return base.Append(kDeduplicationBinaryPbFileName);
-}
-
 void RegisterAppProvisioningComponent(component_updater::ComponentUpdateService* cus) {
   if (chromeos::features::IsCloudGamingDeviceEnabled()) {
     VLOG(1) << "Registering App Provisioning component.";
diff --git a/chrome/browser/component_updater/app_provisioning_component_installer.h b/chrome/browser/component_updater/app_provisioning_component_installer.h
index 12afc9b..ab815e7 100644
--- a/chrome/browser/component_updater/app_provisioning_component_installer.h
+++ b/chrome/browser/component_updater/app_provisioning_component_installer.h
@@ -52,8 +52,6 @@
 
   static base::FilePath GetAppWithLocaleInstalledPath(
       const base::FilePath& base);
-  static base::FilePath GetDeduplicationInstalledPath(
-      const base::FilePath& base);
 };
 
 // Call once during startup to make the component update service aware of
diff --git a/chrome/browser/devtools/protocol/devtools_autofill_browsertest.cc b/chrome/browser/devtools/protocol/devtools_autofill_browsertest.cc
index 0cdc9a99..4af8aae 100644
--- a/chrome/browser/devtools/protocol/devtools_autofill_browsertest.cc
+++ b/chrome/browser/devtools/protocol/devtools_autofill_browsertest.cc
@@ -128,8 +128,6 @@
  private:
   autofill::TestAutofillManagerInjector<TestAutofillManager>
       autofill_manager_injector_;
-  base::test::ScopedFeatureList feature_list_{
-      autofill::features::kAutofillAcrossIframes};
 };
 
 IN_PROC_BROWSER_TEST_F(DevToolsAutofillTest, TriggerCreditCard) {
diff --git a/chrome/browser/extensions/api/terminal/terminal_private_api.cc b/chrome/browser/extensions/api/terminal/terminal_private_api.cc
index b64fd6d..2872ac2f 100644
--- a/chrome/browser/extensions/api/terminal/terminal_private_api.cc
+++ b/chrome/browser/extensions/api/terminal/terminal_private_api.cc
@@ -344,6 +344,14 @@
     if (!container_features.empty())
       cmdline.AppendSwitchASCII(kSwitchContainerFeatures, container_features);
 
+    // Append trailing passthrough args if any.  E.g. `-- vim file.txt`
+    auto passthrough_args = params_args.GetArgs();
+    if (!passthrough_args.empty()) {
+      cmdline.AppendArg("--");
+      for (const auto& arg : passthrough_args) {
+        cmdline.AppendArg(arg);
+      }
+    }
     VLOG(1) << "Starting " << *guest_id_
             << ", cmdline=" << cmdline.GetCommandLineString();
 
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index e980207..d72e0dd4 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2455,6 +2455,11 @@
     "expiry_milestone": 115
   },
   {
+    "name": "enable-federated-service",
+    "owners": [ "alanlxl", "amoylan"],
+    "expiry_milestone": 120
+  },
+  {
     "name": "enable-feed-ablation",
     "owners": [ "adamta", "sczs" ],
     "expiry_milestone": 118
@@ -3269,6 +3274,11 @@
     "expiry_milestone": 118
   },
   {
+    "name": "enable-surface-polish",
+    "owners": [ "hanxi", "xinyiji", "clank-start" ],
+    "expiry_milestone": 130
+  },
+  {
     "name": "enable-sync-history-datatype",
     "owners": [ "treib", "chrome-sync-dev@google.com" ],
     "expiry_milestone": 116
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 125aa29d..5b10673 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -4250,6 +4250,10 @@
     "Slim compositor, and Android OS support. No effect if enabled on "
     "unsupported environment.";
 
+const char kSurfacePolishName[] = "Surface Polish";
+const char kSurfacePolishDescription[] =
+    "Enable clank home surface polish for Start surface and NTP.";
+
 const char kTabGroupsForTabletsName[] = "Tab groups on tablets";
 const char kTabGroupsForTabletsDescription[] = "Enable tab groups on tablets.";
 
@@ -5861,6 +5865,11 @@
     "Accept media.stable.mojom.StableVideoDecoderFactory connection requests "
     "from LaCrOS and host said factories in utility processes.";
 
+const char kFederatedServiceName[] =
+    "Enable Federated Service on ChromeOS login";
+const char kFederatedServiceDescription[] =
+    "If disalbed, all federated service activities are stopped.";
+
 const char kFileTransferEnterpriseConnectorName[] =
     "Enable Files Transfer Enterprise Connector.";
 const char kFileTransferEnterpriseConnectorDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index d7ab9adf..b3257e9f 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2478,6 +2478,9 @@
 extern const char kSurfaceControlMagnifierName[];
 extern const char kSurfaceControlMagnifierDescription[];
 
+extern const char kSurfacePolishName[];
+extern const char kSurfacePolishDescription[];
+
 extern const char kTabGroupsForTabletsName[];
 extern const char kTabGroupsForTabletsDescription[];
 
@@ -3355,6 +3358,9 @@
 extern const char kExposeOutOfProcessVideoDecodingToLacrosName[];
 extern const char kExposeOutOfProcessVideoDecodingToLacrosDescription[];
 
+extern const char kFederatedServiceName[];
+extern const char kFederatedServiceDescription[];
+
 extern const char kFileTransferEnterpriseConnectorName[];
 extern const char kFileTransferEnterpriseConnectorDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 0d708d5a2..0827d04f 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -317,6 +317,7 @@
     &kStartSurfaceSpareTab,
     &kStartSurfaceDisabledFeedImprovement,
     &kStartSurfaceWithAccessibility,
+    &kSurfacePolish,
     &kUmaBackgroundSessions,
     &kUpdateNotificationScheduleServiceImmediateShowOption,
     &kUseLibunwindstackNativeUnwinderAndroid,
@@ -1083,6 +1084,10 @@
              "StartSurfaceWithAccessibility",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kSurfacePolish,
+             "SurfacePolish",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // If enabled, keep logging and reporting UMA while chrome is backgrounded.
 BASE_FEATURE(kUmaBackgroundSessions,
              "UMABackgroundSessions",
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index c61bd96..db2c07f 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -190,6 +190,7 @@
 BASE_DECLARE_FEATURE(kStartSurfaceRefactor);
 BASE_DECLARE_FEATURE(kStartSurfaceDisabledFeedImprovement);
 BASE_DECLARE_FEATURE(kStartSurfaceWithAccessibility);
+BASE_DECLARE_FEATURE(kSurfacePolish);
 BASE_DECLARE_FEATURE(kUmaBackgroundSessions);
 BASE_DECLARE_FEATURE(kUpdateNotificationScheduleServiceImmediateShowOption);
 BASE_DECLARE_FEATURE(kUseLibunwindstackNativeUnwinderAndroid);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index d9d3d2c17..d8837716 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -422,6 +422,7 @@
     public static final String STORE_HOURS = "StoreHoursAndroid";
     public static final String SUGGESTION_ANSWERS_COLOR_REVERSE = "SuggestionAnswersColorReverse";
     public static final String SUPPRESS_TOOLBAR_CAPTURES = "SuppressToolbarCaptures";
+    public static final String SURFACE_POLISH = "SurfacePolish";
     public static final String SWAP_PIXEL_FORMAT_TO_FIX_CONVERT_FROM_TRANSLUCENT =
             "SwapPixelFormatToFixConvertFromTranslucent";
     public static final String SYNC_ANDROID_LIMIT_NTP_PROMO_IMPRESSIONS =
@@ -564,6 +565,7 @@
     public static final CachedFlag sStartSurfaceWithAccessibility =
             new CachedFlag(START_SURFACE_WITH_ACCESSIBILITY, false);
     public static final CachedFlag sStoreHoursAndroid = new CachedFlag(STORE_HOURS, false);
+    public static final CachedFlag sSurfacePolish = new CachedFlag(SURFACE_POLISH, false);
     public static final CachedFlag sSwapPixelFormatToFixConvertFromTranslucent = new CachedFlag(
             SWAP_PIXEL_FORMAT_TO_FIX_CONVERT_FROM_TRANSLUCENT,
             ChromePreferenceKeys.FLAGS_CACHED_SWAP_PIXEL_FORMAT_TO_FIX_CONVERT_FROM_TRANSLUCENT,
@@ -646,6 +648,7 @@
         sStartSurfaceReturnTime,
         sStartSurfaceWithAccessibility,
         sStoreHoursAndroid,
+        sSurfacePolish,
         sSwapPixelFormatToFixConvertFromTranslucent,
         sTabGridLayoutAndroid,
         sTabGroupsAndroid,
diff --git a/chrome/browser/lacros/input_method_lacros_browsertest.cc b/chrome/browser/lacros/input_method_lacros_browsertest.cc
index 9b49345..71a9fc00 100644
--- a/chrome/browser/lacros/input_method_lacros_browsertest.cc
+++ b/chrome/browser/lacros/input_method_lacros_browsertest.cc
@@ -44,18 +44,25 @@
 
 // Used to parameterize these tests.
 struct TestParam {
-  // Enables fixes for b/265853952.
-  // Enables the following feature flags:
-  // - WaylandKeepSelectionFix (Lacros),
-  // - AlwaysConfirmComposition (Ash).
-  // - WaylandCancelComposition (Lacros).
-  //
-  // Will not be true if `extended_confirm_composition` is false.
-  bool fix_265853952 = false;
-
   // Enables kExoExtendedConfirmComposition, which uses an extended Wayland API
   // for ConfirmCompositionText.
   bool extended_confirm_composition = false;
+
+  // Enables fixes for b/268467697.
+  // Enables the following Lacros feature flags:
+  // - WaylandKeepSelectionFix
+  // - WaylandCancelComposition
+  //
+  // Will not be true if `extended_confirm_composition` is false.
+  bool fix_268467697 = false;
+
+  // Enables fixes for b/265853952.
+  // Enables the following Ash feature flags:
+  // - AlwaysConfirmComposition
+  //
+  // Will not be true if `extended_confirm_composition` or `fix_268467697` are
+  // false.
+  bool fix_265853952 = false;
 };
 
 // Binds an InputMethodTestInterface to Ash-Chrome, which allows these tests to
@@ -537,7 +544,7 @@
  public:
   InputMethodLacrosBrowserTest() {
     std::vector<base::test::FeatureRef> enabled_lacros_features;
-    if (GetParam().fix_265853952) {
+    if (GetParam().fix_268467697) {
       enabled_lacros_features.push_back(features::kWaylandKeepSelectionFix);
       enabled_lacros_features.push_back(features::kWaylandCancelComposition);
     }
@@ -566,14 +573,20 @@
   base::test::ScopedFeatureList feature_list_override_;
 };
 
-INSTANTIATE_TEST_SUITE_P(
-    InputMethodLacrosBrowserTestAllParams,
-    InputMethodLacrosBrowserTest,
-    ::testing::Values(
-        TestParam{.fix_265853952 = true, .extended_confirm_composition = true},
-        TestParam{.fix_265853952 = false, .extended_confirm_composition = true},
-        TestParam{.fix_265853952 = false,
-                  .extended_confirm_composition = false}));
+INSTANTIATE_TEST_SUITE_P(InputMethodLacrosBrowserTestAllParams,
+                         InputMethodLacrosBrowserTest,
+                         ::testing::Values(
+                             // All features off.
+                             TestParam{},
+                             // Enable `extended_confirm_composition` first.
+                             TestParam{.extended_confirm_composition = true},
+                             // Enable `fix_268467697` next.
+                             TestParam{.extended_confirm_composition = true,
+                                       .fix_268467697 = true},
+                             // Enable `fix_265853952` last.
+                             TestParam{.extended_confirm_composition = true,
+                                       .fix_268467697 = true,
+                                       .fix_265853952 = true}));
 
 IN_PROC_BROWSER_TEST_P(InputMethodLacrosBrowserTest,
                        FocusingInputFieldSendsFocus) {
diff --git a/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_service_factory.cc b/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_service_factory.cc
index 2d1b4b9..95307059 100644
--- a/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_service_factory.cc
+++ b/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_service_factory.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_service_factory.h"
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_service.h"
 
 // static
@@ -16,7 +16,8 @@
 
 // static
 HttpsEngagementServiceFactory* HttpsEngagementServiceFactory::GetInstance() {
-  return base::Singleton<HttpsEngagementServiceFactory>::get();
+  static base::NoDestructor<HttpsEngagementServiceFactory> instance;
+  return instance.get();
 }
 
 HttpsEngagementServiceFactory::HttpsEngagementServiceFactory()
@@ -29,7 +30,7 @@
               .WithGuest(ProfileSelection::kRedirectedToOriginal)
               .Build()) {}
 
-HttpsEngagementServiceFactory::~HttpsEngagementServiceFactory() {}
+HttpsEngagementServiceFactory::~HttpsEngagementServiceFactory() = default;
 
 KeyedService* HttpsEngagementServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
diff --git a/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_service_factory.h b/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_service_factory.h
index 8e1a4e6d..cafdc8f 100644
--- a/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_service_factory.h
+++ b/chrome/browser/page_load_metrics/observers/https_engagement_metrics/https_engagement_service_factory.h
@@ -13,7 +13,7 @@
 
 namespace base {
 template <typename T>
-struct DefaultSingletonTraits;
+class NoDestructor;
 }
 
 class HttpsEngagementService;
@@ -31,7 +31,7 @@
       const HttpsEngagementServiceFactory&) = delete;
 
  private:
-  friend struct base::DefaultSingletonTraits<HttpsEngagementServiceFactory>;
+  friend base::NoDestructor<HttpsEngagementServiceFactory>;
 
   HttpsEngagementServiceFactory();
   ~HttpsEngagementServiceFactory() override;
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_memory_tracker_factory.cc b/chrome/browser/page_load_metrics/page_load_metrics_memory_tracker_factory.cc
index 34a4465a..bf6407a 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_memory_tracker_factory.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_memory_tracker_factory.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/page_load_metrics/page_load_metrics_memory_tracker_factory.h"
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "components/page_load_metrics/browser/page_load_metrics_memory_tracker.h"
 
 namespace page_load_metrics {
@@ -18,7 +18,8 @@
 
 PageLoadMetricsMemoryTrackerFactory*
 PageLoadMetricsMemoryTrackerFactory::GetInstance() {
-  return base::Singleton<PageLoadMetricsMemoryTrackerFactory>::get();
+  static base::NoDestructor<PageLoadMetricsMemoryTrackerFactory> instance;
+  return instance.get();
 }
 
 PageLoadMetricsMemoryTrackerFactory::PageLoadMetricsMemoryTrackerFactory()
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_image.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_image.html
index e1365b4a..4b29f3a9 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_image.html
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_image.html
@@ -76,6 +76,7 @@
   on-contextmenu="handleContextMenu"
   on-mouseleave="handleMouseLeave"
   style$="[[getStyles(item)]]">
+
   <img data-index$="[[index]]"
     class$="[[getImageClassName(loading)]]"
     is="cr-auto-img"
@@ -85,7 +86,10 @@
     on-mouseenter="handleMouseEnter"
     on-focus="handleFocus"
     on-click="handleClick"
-    on-load="handleLoad">
+    on-keydown="handleKeydown"
+    on-load="handleLoad"
+    role="button"
+    tabindex="0">
 
   <template is="dom-if" if="[[showClearButton]]">
     <button class="emoji-image-clear" on-click="handleClear">
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_image.ts b/chrome/browser/resources/chromeos/emoji_picker/emoji_image.ts
index a2e6996..f04d064 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_image.ts
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_image.ts
@@ -52,6 +52,49 @@
     this.emojiClick(event);
   }
 
+  private findSiblingEmojiImageByIndex(index: number):
+      EmojiImageComponent|null {
+    // The shadow root of emoji-group.
+    const parentShadowRoot = this.shadowRoot!.host.getRootNode() as ShadowRoot;
+
+    for (const emojiImage of parentShadowRoot.querySelectorAll('emoji-image')) {
+      if (emojiImage.index === index) {
+        return emojiImage;
+      }
+    }
+
+    return null;
+  }
+
+  private handleKeydown(event: KeyboardEvent): void {
+    // The img element where the keyboard event is triggered.
+    const target = event.target as HTMLImageElement;
+
+    // Triggers click event to insert the current GIF image.
+    if (event.code === 'Enter') {
+      event.stopPropagation();
+      target.click();
+      return;
+    }
+
+    // Moves focus to the correct sibling.
+    if (event.code === 'Tab') {
+      const siblingIndex = this.index + (event.shiftKey ? -1 : +1);
+      const sibling = this.findSiblingEmojiImageByIndex(siblingIndex);
+
+      if (sibling !== null) {
+        event.preventDefault();
+        event.stopPropagation();
+        sibling.focus();
+        return;
+      }
+    }
+  }
+
+  override focus() {
+    this.shadowRoot?.querySelector('img')?.focus();
+  }
+
   private handleLoad(): void {
     this.loading = false;
   }
diff --git a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/read_only_permission_item.html b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/read_only_permission_item.html
index f0febec..c0cb52c 100644
--- a/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/read_only_permission_item.html
+++ b/chrome/browser/resources/settings/chromeos/os_apps_page/app_management_page/read_only_permission_item.html
@@ -18,8 +18,12 @@
   <div class="horizontal-align">
     <iron-icon id="icon" icon="[[icon]]"></iron-icon>
     <div class="vertical-align">
-      <div id="label">[[permissionLabel]]</div>
-      <div id="description" class="secondary-text">
+      <!--
+        permission-name and permission-state classes are used by tast tests to
+        find permission elements.
+      -->
+      <div id="label" class="permission-name">[[permissionLabel]]</div>
+      <div id="description" class="permission-state secondary-text">
         [[getPermissionDescriptionString_(app, permissionType)]]
       </div>
     </div>
diff --git a/chrome/browser/serial/serial_chooser_context_factory.cc b/chrome/browser/serial/serial_chooser_context_factory.cc
index ce4c309..733d28d 100644
--- a/chrome/browser/serial/serial_chooser_context_factory.cc
+++ b/chrome/browser/serial/serial_chooser_context_factory.cc
@@ -20,7 +20,7 @@
   DependsOn(HostContentSettingsMapFactory::GetInstance());
 }
 
-SerialChooserContextFactory::~SerialChooserContextFactory() {}
+SerialChooserContextFactory::~SerialChooserContextFactory() = default;
 
 KeyedService* SerialChooserContextFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
@@ -29,7 +29,8 @@
 
 // static
 SerialChooserContextFactory* SerialChooserContextFactory::GetInstance() {
-  return base::Singleton<SerialChooserContextFactory>::get();
+  static base::NoDestructor<SerialChooserContextFactory> instance;
+  return instance.get();
 }
 
 // static
diff --git a/chrome/browser/serial/serial_chooser_context_factory.h b/chrome/browser/serial/serial_chooser_context_factory.h
index fa83223..65b56de 100644
--- a/chrome/browser/serial/serial_chooser_context_factory.h
+++ b/chrome/browser/serial/serial_chooser_context_factory.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_SERIAL_SERIAL_CHOOSER_CONTEXT_FACTORY_H_
 #define CHROME_BROWSER_SERIAL_SERIAL_CHOOSER_CONTEXT_FACTORY_H_
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
 
 class SerialChooserContext;
@@ -22,7 +22,7 @@
       delete;
 
  private:
-  friend struct base::DefaultSingletonTraits<SerialChooserContextFactory>;
+  friend base::NoDestructor<SerialChooserContextFactory>;
 
   SerialChooserContextFactory();
   ~SerialChooserContextFactory() override;
diff --git a/chrome/browser/sharesheet/sharesheet_service_factory.cc b/chrome/browser/sharesheet/sharesheet_service_factory.cc
index 5a4da59f..71e8767 100644
--- a/chrome/browser/sharesheet/sharesheet_service_factory.cc
+++ b/chrome/browser/sharesheet/sharesheet_service_factory.cc
@@ -25,7 +25,8 @@
 
 // static
 SharesheetServiceFactory* SharesheetServiceFactory::GetInstance() {
-  return base::Singleton<SharesheetServiceFactory>::get();
+  static base::NoDestructor<SharesheetServiceFactory> instance;
+  return instance.get();
 }
 
 SharesheetServiceFactory::SharesheetServiceFactory()
diff --git a/chrome/browser/sharesheet/sharesheet_service_factory.h b/chrome/browser/sharesheet/sharesheet_service_factory.h
index 434b028..f64584da 100644
--- a/chrome/browser/sharesheet/sharesheet_service_factory.h
+++ b/chrome/browser/sharesheet/sharesheet_service_factory.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_SHARESHEET_SHARESHEET_SERVICE_FACTORY_H_
 #define CHROME_BROWSER_SHARESHEET_SHARESHEET_SERVICE_FACTORY_H_
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
 
 class Profile;
@@ -25,7 +25,7 @@
   SharesheetServiceFactory& operator=(const SharesheetServiceFactory&) = delete;
 
  private:
-  friend struct base::DefaultSingletonTraits<SharesheetServiceFactory>;
+  friend base::NoDestructor<SharesheetServiceFactory>;
 
   SharesheetServiceFactory();
   ~SharesheetServiceFactory() override;
diff --git a/chrome/browser/storage/storage_notification_service_factory.cc b/chrome/browser/storage/storage_notification_service_factory.cc
index cb3921d..cc169a6 100644
--- a/chrome/browser/storage/storage_notification_service_factory.cc
+++ b/chrome/browser/storage/storage_notification_service_factory.cc
@@ -13,7 +13,8 @@
               // Guest mode.
               .WithGuest(ProfileSelection::kOwnInstance)
               .Build()) {}
-StorageNotificationServiceFactory::~StorageNotificationServiceFactory() {}
+StorageNotificationServiceFactory::~StorageNotificationServiceFactory() =
+    default;
 
 // static
 StorageNotificationServiceImpl*
@@ -26,7 +27,8 @@
 // static
 StorageNotificationServiceFactory*
 StorageNotificationServiceFactory::GetInstance() {
-  return base::Singleton<StorageNotificationServiceFactory>::get();
+  static base::NoDestructor<StorageNotificationServiceFactory> instance;
+  return instance.get();
 }
 
 // static
diff --git a/chrome/browser/storage/storage_notification_service_factory.h b/chrome/browser/storage/storage_notification_service_factory.h
index 0822777de0..1b40ae5e 100644
--- a/chrome/browser/storage/storage_notification_service_factory.h
+++ b/chrome/browser/storage/storage_notification_service_factory.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_STORAGE_STORAGE_NOTIFICATION_SERVICE_FACTORY_H_
 #define CHROME_BROWSER_STORAGE_STORAGE_NOTIFICATION_SERVICE_FACTORY_H_
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
 #include "chrome/browser/storage/storage_notification_service_impl.h"
 
@@ -23,7 +23,7 @@
   bool ServiceIsCreatedWithBrowserContext() const override;
 
  private:
-  friend struct base::DefaultSingletonTraits<StorageNotificationServiceFactory>;
+  friend base::NoDestructor<StorageNotificationServiceFactory>;
 
   StorageNotificationServiceFactory();
   ~StorageNotificationServiceFactory() override;
diff --git a/chrome/browser/supervised_user/child_accounts/child_account_service_factory.cc b/chrome/browser/supervised_user/child_accounts/child_account_service_factory.cc
index cb2690db7..854d8186 100644
--- a/chrome/browser/supervised_user/child_accounts/child_account_service_factory.cc
+++ b/chrome/browser/supervised_user/child_accounts/child_account_service_factory.cc
@@ -24,7 +24,8 @@
 
 // static
 ChildAccountServiceFactory* ChildAccountServiceFactory::GetInstance() {
-  return base::Singleton<ChildAccountServiceFactory>::get();
+  static base::NoDestructor<ChildAccountServiceFactory> instance;
+  return instance.get();
 }
 
 ChildAccountServiceFactory::ChildAccountServiceFactory()
diff --git a/chrome/browser/supervised_user/child_accounts/child_account_service_factory.h b/chrome/browser/supervised_user/child_accounts/child_account_service_factory.h
index a65cf163..d626729 100644
--- a/chrome/browser/supervised_user/child_accounts/child_account_service_factory.h
+++ b/chrome/browser/supervised_user/child_accounts/child_account_service_factory.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_SUPERVISED_USER_CHILD_ACCOUNTS_CHILD_ACCOUNT_SERVICE_FACTORY_H_
 #define CHROME_BROWSER_SUPERVISED_USER_CHILD_ACCOUNTS_CHILD_ACCOUNT_SERVICE_FACTORY_H_
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
 #include "chrome/browser/supervised_user/child_accounts/child_account_service.h"
 
@@ -22,7 +22,7 @@
       delete;
 
  private:
-  friend struct base::DefaultSingletonTraits<ChildAccountServiceFactory>;
+  friend base::NoDestructor<ChildAccountServiceFactory>;
 
   ChildAccountServiceFactory();
   ~ChildAccountServiceFactory() override;
diff --git a/chrome/browser/supervised_user/child_accounts/family_preferences_service_factory.cc b/chrome/browser/supervised_user/child_accounts/family_preferences_service_factory.cc
index 2c29a1c..e464db0 100644
--- a/chrome/browser/supervised_user/child_accounts/family_preferences_service_factory.cc
+++ b/chrome/browser/supervised_user/child_accounts/family_preferences_service_factory.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/supervised_user/child_accounts/family_preferences_service_factory.h"
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/supervised_user/supervised_user_browser_utils.h"
 #include "chrome/browser/sync/sync_service_factory.h"
@@ -23,7 +23,8 @@
 // static
 FamilyPreferencesServiceFactory*
 FamilyPreferencesServiceFactory::GetInstance() {
-  return base::Singleton<FamilyPreferencesServiceFactory>::get();
+  static base::NoDestructor<FamilyPreferencesServiceFactory> instance;
+  return instance.get();
 }
 
 FamilyPreferencesServiceFactory::FamilyPreferencesServiceFactory()
diff --git a/chrome/browser/supervised_user/child_accounts/family_preferences_service_factory.h b/chrome/browser/supervised_user/child_accounts/family_preferences_service_factory.h
index 682c81b0..972a744 100644
--- a/chrome/browser/supervised_user/child_accounts/family_preferences_service_factory.h
+++ b/chrome/browser/supervised_user/child_accounts/family_preferences_service_factory.h
@@ -6,7 +6,7 @@
 #ifndef CHROME_BROWSER_SUPERVISED_USER_CHILD_ACCOUNTS_FAMILY_PREFERENCES_SERVICE_FACTORY_H_
 #define CHROME_BROWSER_SUPERVISED_USER_CHILD_ACCOUNTS_FAMILY_PREFERENCES_SERVICE_FACTORY_H_
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -26,7 +26,7 @@
       const FamilyPreferencesServiceFactory&) = delete;
 
  private:
-  friend struct base::DefaultSingletonTraits<FamilyPreferencesServiceFactory>;
+  friend base::NoDestructor<FamilyPreferencesServiceFactory>;
 
   FamilyPreferencesServiceFactory();
   ~FamilyPreferencesServiceFactory() override;
diff --git a/chrome/browser/supervised_user/child_accounts/list_family_members_service_factory.cc b/chrome/browser/supervised_user/child_accounts/list_family_members_service_factory.cc
index 8491a47..7db0396 100644
--- a/chrome/browser/supervised_user/child_accounts/list_family_members_service_factory.cc
+++ b/chrome/browser/supervised_user/child_accounts/list_family_members_service_factory.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/supervised_user/child_accounts/list_family_members_service_factory.h"
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/supervised_user/supervised_user_browser_utils.h"
@@ -23,7 +23,8 @@
 // static
 ListFamilyMembersServiceFactory*
 ListFamilyMembersServiceFactory::GetInstance() {
-  return base::Singleton<ListFamilyMembersServiceFactory>::get();
+  static base::NoDestructor<ListFamilyMembersServiceFactory> instance;
+  return instance.get();
 }
 
 ListFamilyMembersServiceFactory::ListFamilyMembersServiceFactory()
diff --git a/chrome/browser/supervised_user/child_accounts/list_family_members_service_factory.h b/chrome/browser/supervised_user/child_accounts/list_family_members_service_factory.h
index 1f89e16..1e7a95d 100644
--- a/chrome/browser/supervised_user/child_accounts/list_family_members_service_factory.h
+++ b/chrome/browser/supervised_user/child_accounts/list_family_members_service_factory.h
@@ -6,7 +6,7 @@
 #ifndef CHROME_BROWSER_SUPERVISED_USER_CHILD_ACCOUNTS_LIST_FAMILY_MEMBERS_SERVICE_FACTORY_H_
 #define CHROME_BROWSER_SUPERVISED_USER_CHILD_ACCOUNTS_LIST_FAMILY_MEMBERS_SERVICE_FACTORY_H_
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -26,7 +26,7 @@
       const ListFamilyMembersServiceFactory&) = delete;
 
  private:
-  friend struct base::DefaultSingletonTraits<ListFamilyMembersServiceFactory>;
+  friend base::NoDestructor<ListFamilyMembersServiceFactory>;
 
   ListFamilyMembersServiceFactory();
   ~ListFamilyMembersServiceFactory() override;
diff --git a/chrome/browser/supervised_user/supervised_user_service_factory.cc b/chrome/browser/supervised_user/supervised_user_service_factory.cc
index cac366d..7414706 100644
--- a/chrome/browser/supervised_user/supervised_user_service_factory.cc
+++ b/chrome/browser/supervised_user/supervised_user_service_factory.cc
@@ -65,7 +65,8 @@
 
 // static
 SupervisedUserServiceFactory* SupervisedUserServiceFactory::GetInstance() {
-  return base::Singleton<SupervisedUserServiceFactory>::get();
+  static base::NoDestructor<SupervisedUserServiceFactory> instance;
+  return instance.get();
 }
 
 // static
@@ -102,7 +103,7 @@
   DependsOn(SupervisedUserSettingsServiceFactory::GetInstance());
 }
 
-SupervisedUserServiceFactory::~SupervisedUserServiceFactory() {}
+SupervisedUserServiceFactory::~SupervisedUserServiceFactory() = default;
 
 KeyedService* SupervisedUserServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* profile) const {
diff --git a/chrome/browser/supervised_user/supervised_user_service_factory.h b/chrome/browser/supervised_user/supervised_user_service_factory.h
index 569c5fb6..4c8b8f8 100644
--- a/chrome/browser/supervised_user/supervised_user_service_factory.h
+++ b/chrome/browser/supervised_user/supervised_user_service_factory.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_SUPERVISED_USER_SUPERVISED_USER_SERVICE_FACTORY_H_
 #define CHROME_BROWSER_SUPERVISED_USER_SUPERVISED_USER_SERVICE_FACTORY_H_
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
 #include "components/supervised_user/core/common/supervised_users.h"
 
@@ -35,7 +35,7 @@
   static KeyedService* BuildInstanceFor(Profile* profile);
 
  private:
-  friend struct base::DefaultSingletonTraits<SupervisedUserServiceFactory>;
+  friend base::NoDestructor<SupervisedUserServiceFactory>;
 
   SupervisedUserServiceFactory();
   ~SupervisedUserServiceFactory() override;
diff --git a/chrome/browser/supervised_user/supervised_user_settings_service_factory.cc b/chrome/browser/supervised_user/supervised_user_settings_service_factory.cc
index 24b7528..91f16561 100644
--- a/chrome/browser/supervised_user/supervised_user_settings_service_factory.cc
+++ b/chrome/browser/supervised_user/supervised_user_settings_service_factory.cc
@@ -18,15 +18,16 @@
 // static
 SupervisedUserSettingsServiceFactory*
 SupervisedUserSettingsServiceFactory::GetInstance() {
-  return base::Singleton<SupervisedUserSettingsServiceFactory>::get();
+  static base::NoDestructor<SupervisedUserSettingsServiceFactory> instance;
+  return instance.get();
 }
 
 SupervisedUserSettingsServiceFactory::SupervisedUserSettingsServiceFactory()
     : SimpleKeyedServiceFactory("SupervisedUserSettingsService",
                                 SimpleDependencyManager::GetInstance()) {}
 
-SupervisedUserSettingsServiceFactory::
-    ~SupervisedUserSettingsServiceFactory() {}
+SupervisedUserSettingsServiceFactory::~SupervisedUserSettingsServiceFactory() =
+    default;
 
 std::unique_ptr<KeyedService>
 SupervisedUserSettingsServiceFactory::BuildServiceInstanceFor(
diff --git a/chrome/browser/supervised_user/supervised_user_settings_service_factory.h b/chrome/browser/supervised_user/supervised_user_settings_service_factory.h
index 1e956afe..52fd2c2 100644
--- a/chrome/browser/supervised_user/supervised_user_settings_service_factory.h
+++ b/chrome/browser/supervised_user/supervised_user_settings_service_factory.h
@@ -7,7 +7,7 @@
 
 #include <memory>
 
-#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
 #include "components/keyed_service/core/simple_keyed_service_factory.h"
 #include "components/supervised_user/core/common/supervised_users.h"
 
@@ -25,8 +25,7 @@
   static SupervisedUserSettingsServiceFactory* GetInstance();
 
  private:
-  friend struct base::DefaultSingletonTraits<
-      SupervisedUserSettingsServiceFactory>;
+  friend base::NoDestructor<SupervisedUserSettingsServiceFactory>;
 
   SupervisedUserSettingsServiceFactory();
   ~SupervisedUserSettingsServiceFactory() override;
diff --git a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardControllerRobolectricTest.java b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardControllerRobolectricTest.java
index 2305809..e1fa23d2 100644
--- a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardControllerRobolectricTest.java
+++ b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardControllerRobolectricTest.java
@@ -221,10 +221,8 @@
     }
 
     @Test
-    @EnableFeatures({AutofillFeatures.AUTOFILL_TOUCH_TO_FILL_FOR_CREDIT_CARDS_ANDROID,
-            AutofillFeatures.AUTOFILL_ACROSS_IFRAMES})
-    public void
-    testCallsCallbackForCreditCardOnSelectingItem() {
+    @EnableFeatures({AutofillFeatures.AUTOFILL_TOUCH_TO_FILL_FOR_CREDIT_CARDS_ANDROID})
+    public void testCallsCallbackForCreditCardOnSelectingItem() {
         mCoordinator.showSheet(new CreditCard[] {VISA}, false);
         assertThat(mTouchToFillCreditCardModel.get(VISIBLE), is(true));
 
@@ -246,10 +244,8 @@
     }
 
     @Test
-    @EnableFeatures({AutofillFeatures.AUTOFILL_TOUCH_TO_FILL_FOR_CREDIT_CARDS_ANDROID,
-            AutofillFeatures.AUTOFILL_ACROSS_IFRAMES})
-    public void
-    testCallsCallbackForVirtualCardOnSelectingItem() {
+    @EnableFeatures({AutofillFeatures.AUTOFILL_TOUCH_TO_FILL_FOR_CREDIT_CARDS_ANDROID})
+    public void testCallsCallbackForVirtualCardOnSelectingItem() {
         mCoordinator.showSheet(new CreditCard[] {VIRTUAL_CARD}, false);
         assertThat(mTouchToFillCreditCardModel.get(VISIBLE), is(true));
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 45e3427..05dd17a 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2730,6 +2730,8 @@
       "views/apps/chrome_native_app_window_views_aura_ash.h",
       "views/arc_app_dialog_view.cc",
       "views/arc_data_removal_dialog_view.cc",
+      "views/borealis/borealis_beta_badge.cc",
+      "views/borealis/borealis_beta_badge.h",
       "views/borealis/borealis_installer_disallowed_dialog.cc",
       "views/borealis/borealis_installer_disallowed_dialog.h",
       "views/borealis/borealis_installer_error_dialog.cc",
diff --git a/chrome/browser/ui/toolbar/app_menu_model.cc b/chrome/browser/ui/toolbar/app_menu_model.cc
index 2ea15fd..ed688205 100644
--- a/chrome/browser/ui/toolbar/app_menu_model.cc
+++ b/chrome/browser/ui/toolbar/app_menu_model.cc
@@ -324,7 +324,7 @@
                                      ui::kColorMenuIcon, kDefaultIconSize));
   AddItemWithStringIdAndIcon(
       IDC_SHOW_ADDRESSES, IDS_ADDRESSES_AND_MORE_SUBMENU_OPTION,
-      ui::ImageModel::FromVectorIcon(kLocationOnChromeRefreshIcon,
+      ui::ImageModel::FromVectorIcon(vector_icons::kLocationOnChromeRefreshIcon,
                                      ui::kColorMenuIcon, kDefaultIconSize));
 }
 
diff --git a/chrome/browser/ui/views/borealis/borealis_beta_badge.cc b/chrome/browser/ui/views/borealis/borealis_beta_badge.cc
new file mode 100644
index 0000000..786e3a6
--- /dev/null
+++ b/chrome/browser/ui/views/borealis/borealis_beta_badge.cc
@@ -0,0 +1,90 @@
+// 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/views/borealis/borealis_beta_badge.h"
+
+#include <string>
+
+#include "base/i18n/rtl.h"
+#include "cc/paint/paint_flags.h"
+#include "chrome/grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
+#include "ui/color/color_id.h"
+#include "ui/color/color_provider.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/font_list.h"
+#include "ui/gfx/geometry/outsets.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/text_utils.h"
+
+namespace views {
+
+namespace {
+// Padding that appears around the "Beta" label.
+gfx::Outsets kInternalPadding = gfx::Outsets::VH(4, 10);
+
+// The corners of the label are rounded,
+int kCornerRadius = 10;
+
+// Colors used by the badge.
+ui::ColorId kTextColor = cros_tokens::LegacySemanticColorIds::kColorSelection;
+ui::ColorId kBackgroundColor =
+    cros_tokens::LegacySemanticColorIds::kHighlightColor;
+
+gfx::FontList GetFont() {
+  // TODO(b/284389804): Use TypographyToken::kCrosButton1
+  return gfx::FontList({"Google Sans", "Roboto"}, gfx::Font::NORMAL, 14,
+                       gfx::Font::Weight::MEDIUM);
+}
+
+}  // namespace
+
+BorealisBetaBadge::BorealisBetaBadge() = default;
+
+BorealisBetaBadge::~BorealisBetaBadge() = default;
+
+std::u16string BorealisBetaBadge::GetText() const {
+  return l10n_util::GetStringUTF16(IDS_BOREALIS_BETA_BADGE);
+}
+
+gfx::Size BorealisBetaBadge::CalculatePreferredSize() const {
+  gfx::Rect preferred(gfx::GetStringSize(GetText(), GetFont()));
+  preferred.Outset(kInternalPadding);
+  return preferred.size();
+}
+
+void BorealisBetaBadge::OnPaint(gfx::Canvas* canvas) {
+  gfx::Size text_size = gfx::GetStringSize(GetText(), GetFont());
+  // The text is offset from the top-left corner by the inset amount
+  gfx::Rect badge_text_bounds{
+      gfx::Point(kInternalPadding.left(), kInternalPadding.top()), text_size};
+  // ...depending on the side text is written on.
+  if (base::i18n::IsRTL()) {
+    badge_text_bounds.set_x(GetMirroredXForRect(badge_text_bounds));
+  }
+
+  const ui::ColorProvider* color_provider = GetColorProvider();
+
+  // Render the badge itself.
+  gfx::Rect surrounding(badge_text_bounds);
+  surrounding.Outset(kInternalPadding);
+  cc::PaintFlags flags;
+  flags.setColor(color_provider->GetColor(kBackgroundColor));
+  canvas->DrawRoundRect(surrounding, kCornerRadius, flags);
+
+  // Render the badge text.
+  canvas->DrawStringRect(GetText(), GetFont(),
+                         color_provider->GetColor(kTextColor),
+                         badge_text_bounds);
+}
+
+BEGIN_METADATA(BorealisBetaBadge, View)
+ADD_READONLY_PROPERTY_METADATA(std::u16string, Text)
+END_METADATA
+
+}  // namespace views
diff --git a/chrome/browser/ui/views/borealis/borealis_beta_badge.h b/chrome/browser/ui/views/borealis/borealis_beta_badge.h
new file mode 100644
index 0000000..cb20449
--- /dev/null
+++ b/chrome/browser/ui/views/borealis/borealis_beta_badge.h
@@ -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.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_BOREALIS_BOREALIS_BETA_BADGE_H_
+#define CHROME_BROWSER_UI_VIEWS_BOREALIS_BOREALIS_BETA_BADGE_H_
+
+#include <string>
+
+#include "ui/views/view.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+
+// Badge used to signify borealis' beta-ness on various UI surfaces.
+class VIEWS_EXPORT BorealisBetaBadge : public View {
+ public:
+  METADATA_HEADER(BorealisBetaBadge);
+
+  BorealisBetaBadge();
+  ~BorealisBetaBadge() override;
+
+  // Not copyable or movable.
+  BorealisBetaBadge(const BorealisBetaBadge&) = delete;
+  BorealisBetaBadge& operator=(const BorealisBetaBadge&) = delete;
+
+  std::u16string GetText() const;
+
+  // View overrides.
+  gfx::Size CalculatePreferredSize() const override;
+  void OnPaint(gfx::Canvas* canvas) override;
+};
+
+}  // namespace views
+
+#endif  // CHROME_BROWSER_UI_VIEWS_BOREALIS_BOREALIS_BETA_BADGE_H_
diff --git a/chrome/browser/ui/views/borealis/borealis_installer_view.cc b/chrome/browser/ui/views/borealis/borealis_installer_view.cc
index f27fc3501..44a14175a 100644
--- a/chrome/browser/ui/views/borealis/borealis_installer_view.cc
+++ b/chrome/browser/ui/views/borealis/borealis_installer_view.cc
@@ -25,6 +25,7 @@
 #include "chrome/browser/ash/borealis/borealis_util.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
+#include "chrome/browser/ui/views/borealis/borealis_beta_badge.h"
 #include "chrome/browser/ui/views/borealis/borealis_installer_disallowed_dialog.h"
 #include "chrome/browser/ui/views/borealis/borealis_installer_error_dialog.h"
 #include "chrome/browser/ui/views/borealis/borealis_splash_screen_view.h"
@@ -161,6 +162,10 @@
   primary_message_label_->SetMaximumWidth(264);
   left_container_view->AddChildView(primary_message_label_.get());
 
+  beta_badge_ = left_container_view->AddChildView(
+      std::make_unique<views::BorealisBetaBadge>());
+  beta_badge_->SetProperty(views::kMarginsKey, gfx::Insets::TLBR(16, 0, 0, 0));
+
   secondary_message_label_ = new views::Label(
       GetSecondaryMessage(), views::style::CONTEXT_DIALOG_BODY_TEXT,
       views::style::STYLE_SECONDARY);
@@ -416,6 +421,9 @@
   const bool progress_bar_visible = state_ == State::kInstalling;
   progress_bar_->SetVisible(progress_bar_visible);
 
+  const bool beta_badge_visible = state_ != State::kCompleted;
+  beta_badge_->SetVisible(beta_badge_visible);
+
   DialogModelChanged();
   primary_message_label_->NotifyAccessibilityEvent(
       ax::mojom::Event::kLiveRegionChanged,
diff --git a/chrome/browser/ui/views/borealis/borealis_installer_view.h b/chrome/browser/ui/views/borealis/borealis_installer_view.h
index 472b932..4538bf58 100644
--- a/chrome/browser/ui/views/borealis/borealis_installer_view.h
+++ b/chrome/browser/ui/views/borealis/borealis_installer_view.h
@@ -17,6 +17,7 @@
 #include "ui/views/window/dialog_delegate.h"
 
 namespace views {
+class BorealisBetaBadge;
 class BoxLayout;
 class ImageView;
 class Label;
@@ -108,6 +109,7 @@
   raw_ptr<Profile, ExperimentalAsh> profile_ = nullptr;
   raw_ptr<views::Label, ExperimentalAsh> primary_message_label_ = nullptr;
   raw_ptr<views::Label, ExperimentalAsh> secondary_message_label_ = nullptr;
+  raw_ptr<views::BorealisBetaBadge, ExperimentalAsh> beta_badge_ = nullptr;
   raw_ptr<views::ProgressBar, ExperimentalAsh> progress_bar_ = nullptr;
   raw_ptr<views::Label, ExperimentalAsh>
       installation_progress_percentage_label_ = nullptr;
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view.cc b/chrome/browser/ui/views/profiles/profile_menu_view.cc
index 2b22dcd..be7fc7f 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view.cc
@@ -564,8 +564,9 @@
                           base::Unretained(this)));
 
   AddShortcutFeatureButton(
-      features::IsChromeRefresh2023() ? kLocationOnChromeRefreshIcon
-                                      : vector_icons::kLocationOnIcon,
+      features::IsChromeRefresh2023()
+          ? vector_icons::kLocationOnChromeRefreshIcon
+          : vector_icons::kLocationOnIcon,
       l10n_util::GetStringUTF16(IDS_PROFILES_ADDRESSES_LINK),
       base::BindRepeating(&ProfileMenuView::OnAddressesButtonClicked,
                           base::Unretained(this)));
diff --git a/chrome/browser/ui/webui/ash/sys_internals/sys_internals_ui.cc b/chrome/browser/ui/webui/ash/sys_internals/sys_internals_ui.cc
index a51eac1..ea68f3c 100644
--- a/chrome/browser/ui/webui/ash/sys_internals/sys_internals_ui.cc
+++ b/chrome/browser/ui/webui/ash/sys_internals/sys_internals_ui.cc
@@ -9,6 +9,7 @@
 #include "base/feature_list.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/ash/sys_internals/sys_internals_message_handler.h"
+#include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/browser_resources.h"
 #include "content/public/browser/web_ui.h"
@@ -25,7 +26,8 @@
   content::WebUIDataSource* html_source =
       content::WebUIDataSource::CreateAndAdd(Profile::FromWebUI(web_ui),
                                              chrome::kChromeUISysInternalsHost);
-  html_source->DisableTrustedTypesCSP();
+  webui::EnableTrustedTypesCSP(html_source);
+
   html_source->OverrideContentSecurityPolicy(
       network::mojom::CSPDirectiveName::ScriptSrc,
       "script-src chrome://resources chrome://test 'self';");
diff --git a/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc b/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc
index 7b4fac1..bbe6f3e 100644
--- a/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc
+++ b/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc
@@ -403,6 +403,7 @@
     "chrome://slow",
     "chrome://smb-credentials-dialog/",
     "chrome://smb-share-dialog/",
+    "chrome://sys-internals",
 #endif
 #if !BUILDFLAG(IS_CHROMEOS)
     "chrome://apps",
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 3e23262..4e0f49b2 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -744,11 +744,10 @@
   if (url.host_piece() == chrome::kChromeUIPrintHost) {
     if (profile->GetPrefs()->GetBoolean(prefs::kPrintPreviewDisabled))
       return nullptr;
-    // Filter out iframes that just display the preview PDF. Ideally, this would
-    // filter out anything other than chrome://print/, but that does not work
-    // for PrintPreviewUI tests that inject test_loader.html.
-    if (url.path() == "/pdf/index.html")
+    // Filter out everything except chrome://print/ and test_loader.html.
+    if (url.path() != "/" && url.path() != "/test_loader.html") {
       return nullptr;
+    }
     return &NewWebUI<printing::PrintPreviewUI>;
   }
 #endif
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui_browsertest.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui_browsertest.cc
index 1b38a45b..3b2a228 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui_browsertest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
@@ -12,6 +13,7 @@
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/webui/print_preview/print_preview_metrics.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -41,7 +43,8 @@
 
 class PrintPreviewBrowserTest : public InProcessBrowserTest {
  public:
-  PrintPreviewBrowserTest() {}
+  PrintPreviewBrowserTest() = default;
+  ~PrintPreviewBrowserTest() override = default;
 
   void Print() {
     content::TestNavigationObserver nav_observer(nullptr);
@@ -49,6 +52,7 @@
     chrome::ExecuteCommand(browser(), IDC_PRINT);
     nav_observer.Wait();
     nav_observer.StopWatchingNewWebContents();
+    EXPECT_EQ(GURL("chrome://print/"), nav_observer.last_navigation_url());
   }
 };
 
@@ -144,4 +148,27 @@
 }
 #endif  // BUILDFLAG(IS_WIN)
 
+IN_PROC_BROWSER_TEST_F(PrintPreviewBrowserTest, PreviewStartedMetric) {
+  base::HistogramTester histogram_tester;
+  histogram_tester.ExpectBucketCount(
+      "PrintPreview.UserAction", printing::UserActionBuckets::kPreviewStarted,
+      /*expected_count=*/0);
+
+  Print();
+  histogram_tester.ExpectBucketCount(
+      "PrintPreview.UserAction", printing::UserActionBuckets::kPreviewStarted,
+      /*expected_count=*/1);
+
+  // Watch for the next navigation in the print preview dialog. The metric
+  // shouldn't change. See crbug.com/1075795 and crbug.com/1448984.
+  content::TestNavigationObserver nav_observer(nullptr);
+  nav_observer.WatchExistingWebContents();
+  nav_observer.Wait();
+  EXPECT_EQ(GURL("chrome-untrusted://print/1/0/print.pdf"),
+            nav_observer.last_navigation_url());
+  histogram_tester.ExpectBucketCount(
+      "PrintPreview.UserAction", printing::UserActionBuckets::kPreviewStarted,
+      /*expected_count=*/1);
+}
+
 }  // namespace
diff --git a/chrome/build/lacros-arm.pgo.txt b/chrome/build/lacros-arm.pgo.txt
index 344481a..d0485182 100644
--- a/chrome/build/lacros-arm.pgo.txt
+++ b/chrome/build/lacros-arm.pgo.txt
@@ -1 +1 @@
-chrome-chromeos-arm-generic-main-1685361733-219ee847012e87d015076d40f301b2fa896143bd.profdata
+chrome-chromeos-arm-generic-main-1685404062-63958cc5ac4c6c08caac9dba4f8a97dd7d344272.profdata
diff --git a/chrome/build/lacros-arm64.pgo.txt b/chrome/build/lacros-arm64.pgo.txt
index 92eb6e6..4e7434f9 100644
--- a/chrome/build/lacros-arm64.pgo.txt
+++ b/chrome/build/lacros-arm64.pgo.txt
@@ -1 +1 @@
-chrome-chromeos-arm64-generic-main-1685361464-198ff457699fca56c0c11d3eeaf30cef5974dff0.profdata
+chrome-chromeos-arm64-generic-main-1685404062-a3214cb91d61e614c4c2a964129a8d65ce2f9859.profdata
diff --git a/chrome/build/lacros64.pgo.txt b/chrome/build/lacros64.pgo.txt
index 5a1b3fa7..87eb0807 100644
--- a/chrome/build/lacros64.pgo.txt
+++ b/chrome/build/lacros64.pgo.txt
@@ -1 +1 @@
-chrome-chromeos-amd64-generic-main-1685361733-1738c63c1f0092e1dad3a7b9d7c7e2b8c8f83f0c.profdata
+chrome-chromeos-amd64-generic-main-1685404062-6801b70fe5996c28df039637a7229f742788bf5d.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 90ad5e9..e335cb920 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1685361464-0c6d04bd4ea005110f1425106ab44b74c552ce55.profdata
+chrome-linux-main-1685426376-d91fac2f63e20353f3f6065fe3168ff8dab8ef36.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 2239d09..073668d 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1685375491-472fba9d98016abc9eed797bbf3814d111735d5e.profdata
+chrome-mac-arm-main-1685419185-4c95dbcb5ada8cc714a7a25a28efab083a7375b3.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 0434411..b9505e4 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1685361464-c6f16837da0f1153c15a36f1d2e4679151a7217d.profdata
+chrome-mac-main-1685404062-6d4a137d28cc687789353fa1bcff644e3d0dd9fe.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index cc43754..fd1abe8 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1685350737-8f70fa742ce21be0ab6d4476190c84734b1c9342.profdata
+chrome-win32-main-1685415232-36853179f545d75da4bce089a2758d35880a08ec.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 40af9e1..b4e75db 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1685361464-946961b07a0c36db2c1ec7c58f70385a51b01078.profdata
+chrome-win64-main-1685415232-ccbf2a75ab9e9fb08ba897ec8dc86d92b796aeb6.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 8d7b55e..a98f4f3 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -623,8 +623,6 @@
 
   if (is_chromeos_ash) {
     sources += [
-      "../browser/apps/app_service/metrics/app_platform_metrics_service_test_base.cc",
-      "../browser/apps/app_service/metrics/app_platform_metrics_service_test_base.h",
       "../browser/ash/login/app_mode/test/ash_accelerator_helpers.cc",
       "../browser/ash/login/lock/screen_locker_tester.cc",
       "../browser/ash/login/lock/screen_locker_tester.h",
@@ -6980,16 +6978,6 @@
   } else {
     # !is_android
     sources += [
-      "../browser/apps/app_service/app_icon/app_icon_factory_unittest.cc",
-      "../browser/apps/app_service/app_icon/app_icon_test_util.cc",
-      "../browser/apps/app_service/app_icon/app_icon_test_util.h",
-      "../browser/apps/app_service/app_icon/chrome_apps_icon_unittest.cc",
-      "../browser/apps/app_service/app_icon/web_app_icon_unittest.cc",
-      "../browser/apps/app_service/app_service_proxy_unittest.cc",
-      "../browser/apps/app_service/intent_util_unittest.cc",
-      "../browser/apps/app_service/launch_utils_unittest.cc",
-      "../browser/apps/app_service/package_id_unittest.cc",
-      "../browser/apps/app_service/publishers/publisher_unittest.cc",
       "../browser/apps/intent_helper/intent_picker_auto_display_prefs_unittest.cc",
       "../browser/apps/intent_helper/intent_picker_internal_unittest.cc",
       "../browser/apps/intent_helper/page_transition_util_unittest.cc",
@@ -7556,6 +7544,7 @@
       "//chrome/browser/apps:icon_standardizer",
       "//chrome/browser/apps/app_service",
       "//chrome/browser/apps/app_service:test_support",
+      "//chrome/browser/apps/app_service:unit_tests",
       "//chrome/browser/companion/core",
       "//chrome/browser/companion/core/mojom:mojo_bindings",
       "//chrome/browser/companion/core/proto",
@@ -7713,25 +7702,6 @@
       "../browser/apps/app_discovery_service/app_discovery_service_unittest.cc",
       "../browser/apps/app_discovery_service/game_fetcher_unittest.cc",
       "../browser/apps/app_discovery_service/recommended_arc_app_fetcher_unittest.cc",
-      "../browser/apps/app_service/app_icon/app_icon_decoder_unittest.cc",
-      "../browser/apps/app_service/app_icon/arc_apps_icon_unittest.cc",
-      "../browser/apps/app_service/app_icon/guest_os_apps_icon_unittest.cc",
-      "../browser/apps/app_service/file_utils_unittest.cc",
-      "../browser/apps/app_service/metrics/app_platform_metrics_service_unittest.cc",
-      "../browser/apps/app_service/promise_apps/promise_app_almanac_connector_unittest.cc",
-      "../browser/apps/app_service/promise_apps/promise_app_icon_cache_unittest.cc",
-      "../browser/apps/app_service/promise_apps/promise_app_registry_cache_unittest.cc",
-      "../browser/apps/app_service/promise_apps/promise_app_service_unittest.cc",
-      "../browser/apps/app_service/promise_apps/promise_app_unittest.cc",
-      "../browser/apps/app_service/promise_apps/promise_app_update_unittest.cc",
-      "../browser/apps/app_service/promise_apps/promise_app_wrapper_unittest.cc",
-      "../browser/apps/app_service/publishers/arc_apps_unittest.cc",
-      "../browser/apps/app_service/publishers/bruschetta_apps_unittest.cc",
-      "../browser/apps/app_service/publishers/crostini_apps_unittest.cc",
-      "../browser/apps/app_service/publishers/guest_os_apps_unittest.cc",
-      "../browser/apps/app_service/publishers/plugin_vm_apps_unittest.cc",
-      "../browser/apps/app_service/webapk/webapk_install_task_unittest.cc",
-      "../browser/apps/app_service/webapk/webapk_manager_unittest.cc",
       "../browser/browser_process_platform_part_ash_unittest.cc",
       "../browser/component_updater/cros_component_installer_chromeos_unittest.cc",
       "../browser/component_updater/metadata_table_chromeos_unittest.cc",
@@ -8038,9 +8008,6 @@
   if (is_chromeos_lacros) {
     assert(enable_system_notifications)
     sources += [
-      "../browser/apps/app_service/app_service_proxy_lacros_unittest.cc",
-      "../browser/apps/app_service/mock_crosapi_app_service_proxy.cc",
-      "../browser/apps/app_service/mock_crosapi_app_service_proxy.h",
       "../browser/lacros/account_manager/account_manager_util_unittest.cc",
       "../browser/lacros/account_manager/account_profile_mapper_unittest.cc",
       "../browser/lacros/account_manager/get_account_information_helper_unittest.cc",
diff --git a/chrome/test/data/extensions/api_test/activity_log_private/PRESUBMIT.py b/chrome/test/data/extensions/api_test/activity_log_private/PRESUBMIT.py
index 63b9ce0..3e0de02 100644
--- a/chrome/test/data/extensions/api_test/activity_log_private/PRESUBMIT.py
+++ b/chrome/test/data/extensions/api_test/activity_log_private/PRESUBMIT.py
@@ -12,7 +12,6 @@
 
 import os
 
-USE_PYTHON3 = True
 
 
 def GetPathsToPrepend(input_api):
diff --git a/chrome/test/data/pdf/PRESUBMIT.py b/chrome/test/data/pdf/PRESUBMIT.py
index ca902c1e..9e3aabd 100644
--- a/chrome/test/data/pdf/PRESUBMIT.py
+++ b/chrome/test/data/pdf/PRESUBMIT.py
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-USE_PYTHON3 = True
 
 
 def _CommonChecks(input_api, output_api):
diff --git a/chrome/test/data/webui/PRESUBMIT.py b/chrome/test/data/webui/PRESUBMIT.py
index f6d3a443..721018d 100644
--- a/chrome/test/data/webui/PRESUBMIT.py
+++ b/chrome/test/data/webui/PRESUBMIT.py
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-USE_PYTHON3 = True
 PRESUBMIT_VERSION = '2.0.0'
 
 
diff --git a/chrome/test/data/webui/settings/PRESUBMIT.py b/chrome/test/data/webui/settings/PRESUBMIT.py
index c0f6e7fc..66781f63 100644
--- a/chrome/test/data/webui/settings/PRESUBMIT.py
+++ b/chrome/test/data/webui/settings/PRESUBMIT.py
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-USE_PYTHON3 = True
 
 
 def _CommonChecks(input_api, output_api):
diff --git a/components/autofill/content/browser/content_autofill_driver_factory_unittest.cc b/components/autofill/content/browser/content_autofill_driver_factory_unittest.cc
index a73e664..68b83df 100644
--- a/components/autofill/content/browser/content_autofill_driver_factory_unittest.cc
+++ b/components/autofill/content/browser/content_autofill_driver_factory_unittest.cc
@@ -281,26 +281,23 @@
   factory_->OnVisibilityChanged(content::Visibility::HIDDEN);
 }
 
-// Test case with one frame, with BFcache and AutofillAcrossIframes enabled or
-// disabled depending on the parameter.
+// Test case with one frame, with BFcache enabled or disabled depending on the
+// parameter.
 class ContentAutofillDriverFactoryTest_WithOrWithoutBfCacheAndIframes
     : public ContentAutofillDriverFactoryTest,
-      public ::testing::WithParamInterface<std::tuple<bool, bool>> {
+      public ::testing::WithParamInterface<std::tuple<bool>> {
  public:
   ContentAutofillDriverFactoryTest_WithOrWithoutBfCacheAndIframes() {
     std::vector<base::test::FeatureRef> enabled;
     // Allow BackForwardCache for all devices regardless of their memory.
     std::vector<base::test::FeatureRef> disabled =
         content::GetDefaultDisabledBackForwardCacheFeaturesForTesting();
-    (autofill_across_iframes() ? enabled : disabled)
-        .push_back(features::kAutofillAcrossIframes);
     (use_bfcache() ? enabled : disabled)
         .push_back(::features::kBackForwardCache);
     scoped_feature_list_.InitWithFeatures(enabled, disabled);
   }
 
   bool use_bfcache() { return std::get<0>(GetParam()); }
-  bool autofill_across_iframes() { return std::get<1>(GetParam()); }
 
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
@@ -309,7 +306,7 @@
 INSTANTIATE_TEST_SUITE_P(
     ContentAutofillDriverFactoryTest,
     ContentAutofillDriverFactoryTest_WithOrWithoutBfCacheAndIframes,
-    testing::Combine(testing::Bool(), testing::Bool()));
+    testing::Combine(testing::Bool()));
 
 // Tests that that a same-documentation navigation does not touch the factory's
 // router.
diff --git a/components/autofill/content/browser/content_autofill_driver_unittest.cc b/components/autofill/content/browser/content_autofill_driver_unittest.cc
index 20e78de..fee121a 100644
--- a/components/autofill/content/browser/content_autofill_driver_unittest.cc
+++ b/components/autofill/content/browser/content_autofill_driver_unittest.cc
@@ -309,8 +309,7 @@
               ());
 };
 
-class ContentAutofillDriverTest : public content::RenderViewHostTestHarness,
-                                  public ::testing::WithParamInterface<bool> {
+class ContentAutofillDriverTest : public content::RenderViewHostTestHarness {
  public:
   enum class NavigationType {
     kNormal,
@@ -319,14 +318,6 @@
     kPrerenderedPageActivation,
   };
 
-  ContentAutofillDriverTest() : autofill_across_iframes_(GetParam()) {
-    std::vector<base::test::FeatureRef> enabled;
-    std::vector<base::test::FeatureRef> disabled;
-    (autofill_across_iframes_ ? enabled : disabled)
-        .push_back(features::kAutofillAcrossIframes);
-    scoped_feature_list_.InitWithFeatures(enabled, disabled);
-  }
-
   void SetUp() override {
     content::RenderViewHostTestHarness::SetUp();
     // This needed to keep the WebContentsObserverConsistencyChecker checks
@@ -398,8 +389,6 @@
         web_contents()->GetPrimaryMainFrame()->GetFrameToken().value());
   }
 
-  bool autofill_across_iframes_ = false;
-  base::test::ScopedFeatureList scoped_feature_list_;
   test::AutofillUnitTestEnvironment autofill_test_environment_;
 
   TestAutofillClientInjector<TestContentAutofillClient>
@@ -410,27 +399,27 @@
   FakeAutofillAgent fake_agent_;
 };
 
-TEST_P(ContentAutofillDriverTest, NavigatedMainFrameDifferentDocument) {
+TEST_F(ContentAutofillDriverTest, NavigatedMainFrameDifferentDocument) {
   EXPECT_CALL(*manager(), Reset());
   Navigate(NavigationType::kNormal);
 }
 
-TEST_P(ContentAutofillDriverTest, NavigatedMainFrameSameDocument) {
+TEST_F(ContentAutofillDriverTest, NavigatedMainFrameSameDocument) {
   EXPECT_CALL(*manager(), Reset()).Times(0);
   Navigate(NavigationType::kSameDocument);
 }
 
-TEST_P(ContentAutofillDriverTest, NavigatedMainFrameFromBackForwardCache) {
+TEST_F(ContentAutofillDriverTest, NavigatedMainFrameFromBackForwardCache) {
   EXPECT_CALL(*manager(), Reset()).Times(0);
   Navigate(NavigationType::kServedFromBackForwardCache);
 }
 
-TEST_P(ContentAutofillDriverTest, NavigatedMainFramePrerenderedPageActivation) {
+TEST_F(ContentAutofillDriverTest, NavigatedMainFramePrerenderedPageActivation) {
   EXPECT_CALL(*manager(), Reset()).Times(0);
   Navigate(NavigationType::kPrerenderedPageActivation);
 }
 
-TEST_P(ContentAutofillDriverTest, SetFrameAndFormMetaDataOfForm) {
+TEST_F(ContentAutofillDriverTest, SetFrameAndFormMetaDataOfForm) {
   NavigateAndCommit(GURL("https://username:password@hostname/path?query#hash"));
   FormData form;
   form.fields.emplace_back();
@@ -456,7 +445,7 @@
 }
 
 // Test that forms in "about:" without parents have an empty FormData::url.
-TEST_P(ContentAutofillDriverTest, SetFrameAndFormMetaDataOfForm_AboutScheme) {
+TEST_F(ContentAutofillDriverTest, SetFrameAndFormMetaDataOfForm_AboutScheme) {
   NavigateAndCommit(GURL("about:blank"));
   ASSERT_TRUE(main_rfh()->GetLastCommittedURL().IsAboutBlank());
 
@@ -468,7 +457,7 @@
 
 // Tests that the FormData::version of forms passed to AutofillManager
 // increases.
-TEST_P(ContentAutofillDriverTest, SetFrameAndFormMetaDataOfForm_Version) {
+TEST_F(ContentAutofillDriverTest, SetFrameAndFormMetaDataOfForm_Version) {
   FormData form;
   test::CreateTestAddressFormData(&form);
 
@@ -489,7 +478,7 @@
 
 // Test that forms in "about:" subframes inherit the URL of their next
 // non-"about:" ancestor in FormData::url.
-TEST_P(ContentAutofillDriverTest,
+TEST_F(ContentAutofillDriverTest,
        SetFrameAndFormMetaDataOfForm_AboutSchemeInheritsFromGrandParent) {
   NavigateAndCommit(GURL("https://username:password@hostname/path?query#hash"));
   content::RenderFrameHost* child_rfh =
@@ -515,7 +504,7 @@
   EXPECT_EQ(form.url, GURL("https://hostname"));
 }
 
-TEST_P(ContentAutofillDriverTest, SetFrameAndFormMetaDataOfField) {
+TEST_F(ContentAutofillDriverTest, SetFrameAndFormMetaDataOfField) {
   NavigateAndCommit(GURL("https://username:password@hostname/path?query#hash"));
   // We test that `SetFrameAndFormMetaData(form, &field) sets the meta data not
   // just of |form|'s fields but also of an additional individual |field|.
@@ -537,7 +526,7 @@
 
 // Tests that FormsSeen() for an updated form arrives in the AutofillManager.
 // Does not test multiple frames.
-TEST_P(ContentAutofillDriverTest, FormsSeen_UpdatedForm) {
+TEST_F(ContentAutofillDriverTest, FormsSeen_UpdatedForm) {
   FormData form;
   test::CreateTestAddressFormData(&form);
   EXPECT_CALL(*manager(),
@@ -558,7 +547,7 @@
 
 // Tests that FormsSeen() for a removed form arrives in the AutofillManager.
 // Does not test multiple frames.
-TEST_P(ContentAutofillDriverTest, FormsSeen_RemovedForm) {
+TEST_F(ContentAutofillDriverTest, FormsSeen_RemovedForm) {
   FormRendererId form_renderer_id = test::MakeFormRendererId();
   EXPECT_CALL(*manager(),
               OnFormsSeen(IsEmpty(), ElementsAre(FormGlobalId(
@@ -570,7 +559,7 @@
 // Tests that FormsSeen() for one updated and one removed form arrives in the
 // AutofillManager.
 // Does not test multiple frames.
-TEST_P(ContentAutofillDriverTest, FormsSeen_UpdatedAndRemovedForm) {
+TEST_F(ContentAutofillDriverTest, FormsSeen_UpdatedAndRemovedForm) {
   FormData form;
   test::CreateTestAddressFormData(&form);
   FormRendererId other_form_renderer_id = test::MakeFormRendererId();
@@ -592,7 +581,7 @@
       /*removed_forms=*/{other_form_renderer_id});
 }
 
-TEST_P(ContentAutofillDriverTest, FormDataSentToRenderer_FillForm) {
+TEST_F(ContentAutofillDriverTest, FormDataSentToRenderer_FillForm) {
   url::Origin triggered_origin;
   FormData input_form_data = SeeAddressFormData();
   for (FormFieldData& field : input_form_data.fields) {
@@ -614,7 +603,7 @@
                   .SameFormAs(output_form_data));
 }
 
-TEST_P(ContentAutofillDriverTest, FormDataSentToRenderer_PreviewForm) {
+TEST_F(ContentAutofillDriverTest, FormDataSentToRenderer_PreviewForm) {
   url::Origin triggered_origin;
   FormData input_form_data = SeeAddressFormData();
   for (FormFieldData& field : input_form_data.fields) {
@@ -639,7 +628,7 @@
                   .SameFormAs(output_form_data));
 }
 
-TEST_P(ContentAutofillDriverTest, TypePredictionsSentToRendererWhenEnabled) {
+TEST_F(ContentAutofillDriverTest, TypePredictionsSentToRendererWhenEnabled) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kShowAutofillTypePredictions);
 
@@ -673,7 +662,7 @@
   EXPECT_EQ(expected_type_predictions, output_type_predictions);
 }
 
-TEST_P(ContentAutofillDriverTest, AcceptDataListSuggestion) {
+TEST_F(ContentAutofillDriverTest, AcceptDataListSuggestion) {
   FieldGlobalId field = SeeAddressFormData().fields.front().global_id();
   std::u16string input_value(u"barfoo");
   std::u16string output_value;
@@ -689,7 +678,7 @@
   EXPECT_EQ(input_value, output_value);
 }
 
-TEST_P(ContentAutofillDriverTest, ClearFilledSectionSentToRenderer) {
+TEST_F(ContentAutofillDriverTest, ClearFilledSectionSentToRenderer) {
   SeeAddressFormData();
   base::RunLoop run_loop;
   fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
@@ -699,7 +688,7 @@
   EXPECT_TRUE(fake_agent_.GetCalledClearSection());
 }
 
-TEST_P(ContentAutofillDriverTest, ClearPreviewedFormSentToRenderer) {
+TEST_F(ContentAutofillDriverTest, ClearPreviewedFormSentToRenderer) {
   SeeAddressFormData();
   base::RunLoop run_loop;
   fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
@@ -709,7 +698,7 @@
   EXPECT_TRUE(fake_agent_.GetCalledClearPreviewedForm());
 }
 
-TEST_P(ContentAutofillDriverTest, FillFieldWithValue) {
+TEST_F(ContentAutofillDriverTest, FillFieldWithValue) {
   FieldGlobalId field = SeeAddressFormData().fields.front().global_id();
   std::u16string input_value(u"barqux");
   std::u16string output_value;
@@ -724,7 +713,7 @@
   EXPECT_EQ(input_value, output_value);
 }
 
-TEST_P(ContentAutofillDriverTest, PreviewFieldWithValue) {
+TEST_F(ContentAutofillDriverTest, PreviewFieldWithValue) {
   FieldGlobalId field = SeeAddressFormData().fields.front().global_id();
   std::u16string input_value(u"barqux");
   std::u16string output_value;
@@ -740,7 +729,7 @@
   EXPECT_EQ(input_value, output_value);
 }
 
-TEST_P(ContentAutofillDriverTest, SetShouldSuppressKeyboard) {
+TEST_F(ContentAutofillDriverTest, SetShouldSuppressKeyboard) {
   ASSERT_FALSE(test_api(driver()).should_suppress_keyboard());
   test_api(&router()).set_last_queried_source(driver());
 
@@ -748,7 +737,7 @@
   EXPECT_TRUE(test_api(driver()).should_suppress_keyboard());
 }
 
-TEST_P(ContentAutofillDriverTest, TriggerFormExtractionInAllFrames) {
+TEST_F(ContentAutofillDriverTest, TriggerFormExtractionInAllFrames) {
   base::RunLoop run_loop;
   fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
   base::OnceCallback<void(bool)> form_extraction_finished_callback;
@@ -764,7 +753,7 @@
   std::move(form_extraction_finished_callback).Run(true);
 }
 
-TEST_P(ContentAutofillDriverTest, GetFourDigitCombinationsFromDOM_NoMatches) {
+TEST_F(ContentAutofillDriverTest, GetFourDigitCombinationsFromDOM_NoMatches) {
   base::RunLoop run_loop;
   auto cb =
       [](base::OnceCallback<void(const std::vector<std::string>&)> callback) {
@@ -784,7 +773,7 @@
   EXPECT_TRUE(matches.empty());
 }
 
-TEST_P(ContentAutofillDriverTest,
+TEST_F(ContentAutofillDriverTest,
        GetFourDigitCombinationsFromDOM_SuccessfulMatches) {
   base::RunLoop run_loop;
   auto cb =
@@ -804,8 +793,4 @@
   EXPECT_THAT(matches, ElementsAre("1234"));
 }
 
-INSTANTIATE_TEST_SUITE_P(ContentAutofillDriverTest,
-                         ContentAutofillDriverTest,
-                         testing::Bool());
-
 }  // namespace autofill
diff --git a/components/autofill/content/browser/content_autofill_router.cc b/components/autofill/content/browser/content_autofill_router.cc
index 06e379e7..e8a88dd 100644
--- a/components/autofill/content/browser/content_autofill_router.cc
+++ b/components/autofill/content/browser/content_autofill_router.cc
@@ -43,7 +43,6 @@
 // Calls |fun| for all drivers in |form_forest|.
 template <typename UnaryFunction>
 void ForEachFrame(internal::FormForest& form_forest, UnaryFunction fun) {
-  DCHECK(base::FeatureList::IsEnabled(features::kAutofillAcrossIframes));
   for (const std::unique_ptr<internal::FormForest::FrameData>& some_frame :
        form_forest.frame_datas()) {
     // Required for AFCHECK().
@@ -78,7 +77,6 @@
 
 ContentAutofillDriver* ContentAutofillRouter::DriverOfFrame(
     LocalFrameToken frame) {
-  DCHECK(base::FeatureList::IsEnabled(features::kAutofillAcrossIframes));
   const auto& frames = form_forest_.frame_datas();
   auto it = frames.find(frame);
   return it != frames.end()
@@ -88,9 +86,6 @@
 
 void ContentAutofillRouter::UnregisterDriver(ContentAutofillDriver* driver,
                                              bool driver_is_dying) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes))
-    return;
-
   some_rfh_for_debugging_ = content::GlobalRenderFrameHostId();
 
   AFCHECK(driver, return );
@@ -131,11 +126,6 @@
     void (*callback)(
         ContentAutofillDriver* target,
         const content::RenderWidgetHost::KeyPressEventCallback& handler)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, handler);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   // The asynchronous AutocompleteHistoryManager::OnAutofillValuesReturned()
@@ -152,11 +142,6 @@
 void ContentAutofillRouter::UnsetKeyPressHandler(
     ContentAutofillDriver* source,
     void (*callback)(ContentAutofillDriver* target)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   // When AutofillPopupControllerImpl::Hide() calls this function,
@@ -172,11 +157,6 @@
     ContentAutofillDriver* source,
     bool suppress,
     void (*callback)(ContentAutofillDriver* target, bool suppress)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, suppress);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   // TODO(crbug.com/1247698): Double check if this could happen.
@@ -203,7 +183,6 @@
 // TriggerFormExtractionExcept(source).
 void ContentAutofillRouter::TriggerFormExtractionExcept(
     ContentAutofillDriver* exception) {
-  DCHECK(base::FeatureList::IsEnabled(features::kAutofillAcrossIframes));
   base::flat_set<AutofillDriver*> already_triggered;
   ForEachFrame(form_forest_, [&](AutofillDriver* driver) mutable {
     do {
@@ -227,11 +206,6 @@
     void (*callback)(ContentAutofillDriver* target,
                      const std::vector<FormData>& updated_forms,
                      const std::vector<FormGlobalId>& removed_forms)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, renderer_forms, removed_forms);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   base::flat_set<FormGlobalId> forms_with_removed_fields =
@@ -294,11 +268,6 @@
     absl::optional<FormData> form,
     void (*callback)(ContentAutofillDriver* target,
                      const FormData* optional_form)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, form ? &*form : nullptr);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   if (!form) {
@@ -325,11 +294,6 @@
                      const FormData& form,
                      bool known_success,
                      mojom::SubmissionSource submission_source)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, form, known_success, submission_source);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   FormGlobalId form_id = form.global_id();
@@ -353,11 +317,6 @@
                      const FormFieldData& field,
                      const gfx::RectF& bounding_box,
                      base::TimeTicks timestamp)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, std::move(form), field, bounding_box, timestamp);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   FormGlobalId form_id = form.global_id();
@@ -381,11 +340,6 @@
                      const FormData& form,
                      const FormFieldData& field,
                      const gfx::RectF& bounding_box)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, std::move(form), field, bounding_box);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   FormGlobalId form_id = form.global_id();
@@ -409,11 +363,6 @@
                      const FormData& form,
                      const FormFieldData& field,
                      const gfx::RectF& bounding_box)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, std::move(form), field, bounding_box);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   FormGlobalId form_id = form.global_id();
@@ -441,12 +390,6 @@
                      const gfx::RectF& bounding_box,
                      AutoselectFirstSuggestion autoselect_first_suggestion,
                      FormElementWasClicked form_element_was_clicked)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, std::move(form), field, bounding_box,
-             autoselect_first_suggestion, form_element_was_clicked);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   FormGlobalId form_id = form.global_id();
@@ -467,11 +410,6 @@
 void ContentAutofillRouter::HidePopup(
     ContentAutofillDriver* source,
     void (*callback)(ContentAutofillDriver* target)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   // For Password Manager forms, |last_queried_target_| is not set. Since these
@@ -487,11 +425,6 @@
     ContentAutofillDriver* source,
     bool had_interacted_form,
     void (*callback)(ContentAutofillDriver* target, bool had_interacted_form)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, had_interacted_form);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   // Suppresses FocusNoLongerOnForm() if the focus has already moved to a
@@ -522,11 +455,6 @@
                      const FormData& form,
                      const FormFieldData& field,
                      const gfx::RectF& bounding_box)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, std::move(form), field, bounding_box);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   FormGlobalId form_id = form.global_id();
@@ -562,11 +490,6 @@
     void (*callback)(ContentAutofillDriver* target,
                      const FormData& form,
                      base::TimeTicks timestamp)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, std::move(form), timestamp);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   FormGlobalId form_id = form.global_id();
@@ -585,11 +508,6 @@
 void ContentAutofillRouter::DidPreviewAutofillFormData(
     ContentAutofillDriver* source,
     void (*callback)(ContentAutofillDriver* target)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   if (last_queried_target_)
@@ -599,11 +517,6 @@
 void ContentAutofillRouter::DidEndTextFieldEditing(
     ContentAutofillDriver* source,
     void (*callback)(ContentAutofillDriver* target)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   TriggerFormExtractionExcept(source);
@@ -617,11 +530,6 @@
     ContentAutofillDriver* source,
     FormData form,
     void (*callback)(ContentAutofillDriver* target, const FormData& form)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, std::move(form));
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   FormGlobalId form_id = form.global_id();
@@ -645,11 +553,6 @@
                      const FormData& form,
                      const FormFieldData& field,
                      const std::u16string& old_value)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, std::move(form), field, old_value);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   FormGlobalId form_id = form.global_id();
@@ -671,11 +574,6 @@
     void (*callback)(ContentAutofillDriver* target,
                      const FormGlobalId& form_global_id,
                      const FieldGlobalId& field_global_id)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, form_global_id, field_global_id);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   TriggerFormExtractionExcept(source);
@@ -701,15 +599,6 @@
     void (*callback)(ContentAutofillDriver* target,
                      mojom::RendererFormDataAction action,
                      const FormData& form)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, action, data);
-    std::vector<FieldGlobalId> safe_fields;
-    safe_fields.reserve(data.fields.size());
-    for (const auto& field : data.fields)
-      safe_fields.push_back(field.global_id());
-    return safe_fields;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   internal::FormForest::RendererForms renderer_forms =
@@ -733,11 +622,6 @@
     const std::vector<FormDataPredictions>& browser_fdps,
     void (*callback)(ContentAutofillDriver* target,
                      const std::vector<FormDataPredictions>& predictions)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, browser_fdps);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   // Splits each FrameDataPredictions according to the respective FormData's
@@ -787,15 +671,6 @@
     const std::vector<FieldGlobalId>& fields,
     void (*callback)(ContentAutofillDriver* target,
                      const std::vector<FieldRendererId>& fields)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    std::vector<FieldRendererId> renderer_ids;
-    renderer_ids.reserve(renderer_ids.size());
-    for (FieldGlobalId field : fields)
-      renderer_ids.push_back(field.renderer_id);
-    callback(source, renderer_ids);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   // Splits FieldGlobalIds by their frames and reduce them to the
@@ -820,11 +695,6 @@
     void (*callback)(ContentAutofillDriver* target,
                      const FieldRendererId& field,
                      const std::u16string& value)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, field.renderer_id, value);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   if (auto* target = DriverOfFrame(field.frame_token)) {
@@ -835,11 +705,6 @@
 void ContentAutofillRouter::RendererShouldClearFilledSection(
     ContentAutofillDriver* source,
     void (*callback)(ContentAutofillDriver* target)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   ForEachFrame(form_forest_, callback);
@@ -848,11 +713,6 @@
 void ContentAutofillRouter::RendererShouldClearPreviewedForm(
     ContentAutofillDriver* source,
     void (*callback)(ContentAutofillDriver* target)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   ForEachFrame(form_forest_, callback);
@@ -865,11 +725,6 @@
     void (*callback)(ContentAutofillDriver* target,
                      const FieldRendererId& field,
                      const std::u16string& value)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, field.renderer_id, value);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   if (auto* target = DriverOfFrame(field.frame_token))
@@ -883,11 +738,6 @@
     void (*callback)(ContentAutofillDriver* target,
                      const FieldRendererId& field,
                      const std::u16string& value)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, field.renderer_id, value);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   if (auto* target = DriverOfFrame(field.frame_token))
@@ -901,11 +751,6 @@
     void (*callback)(ContentAutofillDriver* target,
                      const FieldRendererId& field,
                      const mojom::AutofillState state)) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    callback(source, field.renderer_id, state);
-    return;
-  }
-
   some_rfh_for_debugging_ = source->render_frame_host()->GetGlobalId();
 
   if (auto* target = DriverOfFrame(field.frame_token)) {
diff --git a/components/autofill/content/renderer/autofill_agent_browsertest.cc b/components/autofill/content/renderer/autofill_agent_browsertest.cc
index d5be4fa..fb4c87d 100644
--- a/components/autofill/content/renderer/autofill_agent_browsertest.cc
+++ b/components/autofill/content/renderer/autofill_agent_browsertest.cc
@@ -209,14 +209,11 @@
   std::unique_ptr<PasswordGenerationAgent> password_generation_;
 };
 
-// Enables AutofillAcrossIframes.
 class AutofillAgentTestWithFeatures : public AutofillAgentTest {
  public:
   AutofillAgentTestWithFeatures() {
     scoped_features_.InitWithFeatures(
-        {features::kAutofillAcrossIframes,
-         blink::features::kAutofillDetectRemovedFormControls},
-        {});
+        {blink::features::kAutofillDetectRemovedFormControls}, {});
   }
 
  private:
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc
index c8c48d8..cd81a36 100644
--- a/components/autofill/content/renderer/form_autofill_util.cc
+++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -1608,13 +1608,10 @@
   //   `form->child_frames[i].predecessor` is set to the correct value, but
   //   `form->child_frames[i].token` is not initialized yet.
   form->fields.reserve(control_elements.size());
-  if (base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    form->child_frames.resize(iframe_elements.size());
-  }
+  form->child_frames.resize(iframe_elements.size());
+
   std::vector<bool> fields_extracted(control_elements.size(), false);
-
   std::vector<ShadowFieldData> shadow_fields;
-
   for (size_t i = 0, next_iframe = 0; i < control_elements.size(); ++i) {
     const WebFormControlElement& control_element = control_elements[i];
 
@@ -1634,20 +1631,19 @@
           control_element);
     }
 
-    if (base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-      // Finds the last frame that precedes |control_element|.
-      while (next_iframe < iframe_elements.size() &&
-             !IsDOMPredecessor(control_element, iframe_elements[next_iframe],
-                               form_element)) {
-        ++next_iframe;
-      }
-      // The |next_frame|th frame precedes `control_element` and thus the last
-      // added FormFieldData. The |k|th frames for |k| > |next_frame| may also
-      // precede that FormFieldData. If they do not,
-      // `form->child_frames[i].predecessor` will be updated in a later
-      // iteration.
-      for (size_t k = next_iframe; k < iframe_elements.size(); ++k)
-        form->child_frames[k].predecessor = form->fields.size() - 1;
+    // Finds the last frame that precedes |control_element|.
+    while (next_iframe < iframe_elements.size() &&
+           !IsDOMPredecessor(control_element, iframe_elements[next_iframe],
+                             form_element)) {
+      ++next_iframe;
+    }
+    // The |next_frame|th frame precedes `control_element` and thus the last
+    // added FormFieldData. The |k|th frames for |k| > |next_frame| may also
+    // precede that FormFieldData. If they do not,
+    // `form->child_frames[i].predecessor` will be updated in a later
+    // iteration.
+    for (size_t k = next_iframe; k < iframe_elements.size(); ++k) {
+      form->child_frames[k].predecessor = form->fields.size() - 1;
     }
 
     if (form->fields.size() > kMaxExtractableFields) {
@@ -1717,23 +1713,21 @@
   }
 
   // Extracts the frame tokens of |iframe_elements|.
-  if (base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    DCHECK_EQ(form->child_frames.size(), iframe_elements.size());
-    for (size_t i = 0; i < iframe_elements.size(); ++i) {
-      WebFrame* iframe = WebFrame::FromFrameOwnerElement(iframe_elements[i]);
-      if (iframe && iframe->IsWebLocalFrame()) {
-        form->child_frames[i].token = LocalFrameToken(
-            iframe->ToWebLocalFrame()->GetLocalFrameToken().value());
-      } else if (iframe && iframe->IsWebRemoteFrame()) {
-        form->child_frames[i].token = RemoteFrameToken(
-            iframe->ToWebRemoteFrame()->GetRemoteFrameToken().value());
-      }
+  DCHECK_EQ(form->child_frames.size(), iframe_elements.size());
+  for (size_t i = 0; i < iframe_elements.size(); ++i) {
+    WebFrame* iframe = WebFrame::FromFrameOwnerElement(iframe_elements[i]);
+    if (iframe && iframe->IsWebLocalFrame()) {
+      form->child_frames[i].token = LocalFrameToken(
+          iframe->ToWebLocalFrame()->GetLocalFrameToken().value());
+    } else if (iframe && iframe->IsWebRemoteFrame()) {
+      form->child_frames[i].token = RemoteFrameToken(
+          iframe->ToWebRemoteFrame()->GetRemoteFrameToken().value());
     }
-    base::EraseIf(form->child_frames, [](const auto& child_frame) {
-      return absl::visit([](const auto& token) { return token.is_empty(); },
-                         child_frame.token);
-    });
   }
+  base::EraseIf(form->child_frames, [](const auto& child_frame) {
+    return absl::visit([](const auto& token) { return token.is_empty(); },
+                       child_frame.token);
+  });
 
   if (form->child_frames.size() > kMaxExtractableChildFrames) {
     form->child_frames.clear();
@@ -2348,15 +2342,13 @@
     form->action = blink::WebStringToGURL(form_element.Action());
 
   std::vector<WebElement> owned_iframes;
-  if (base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    WebElementCollection iframes =
-        form_element.GetElementsByHTMLTagName("iframe");
-    for (WebElement iframe = iframes.FirstItem(); !iframe.IsNull();
-         iframe = iframes.NextItem()) {
-      if (GetClosestAncestorFormElement(iframe) == form_element &&
-          IsRelevantChildFrame(iframe)) {
-        owned_iframes.push_back(iframe);
-      }
+  WebElementCollection iframes =
+      form_element.GetElementsByHTMLTagName("iframe");
+  for (WebElement iframe = iframes.FirstItem(); !iframe.IsNull();
+       iframe = iframes.NextItem()) {
+    if (GetClosestAncestorFormElement(iframe) == form_element &&
+        IsRelevantChildFrame(iframe)) {
+      owned_iframes.push_back(iframe);
     }
   }
 
@@ -2403,9 +2395,6 @@
 }
 
 std::vector<WebElement> GetUnownedIframeElements(const WebDocument& document) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes))
-    return {};
-
   std::vector<WebElement> unowned_iframes;
   WebElementCollection iframes = document.GetElementsByHTMLTagName("iframe");
   for (WebElement iframe = iframes.FirstItem(); !iframe.IsNull();
@@ -2555,8 +2544,6 @@
 }
 
 bool IsOwnedByFrame(const WebNode& node, content::RenderFrame* frame) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillAcrossIframes))
-    return true;
   if (node.IsNull() || !frame)
     return false;
   const blink::WebDocument& doc = node.GetDocument();
diff --git a/components/autofill/content/renderer/form_autofill_util_browsertest.cc b/components/autofill/content/renderer/form_autofill_util_browsertest.cc
index 0fa79f2..d1c2fc31 100644
--- a/components/autofill/content/renderer/form_autofill_util_browsertest.cc
+++ b/components/autofill/content/renderer/form_autofill_util_browsertest.cc
@@ -105,17 +105,6 @@
   base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-class FormAutofillUtilsTestWithIframesEnabled : public FormAutofillUtilsTest {
- public:
-  FormAutofillUtilsTestWithIframesEnabled() {
-    scoped_feature_list_.InitAndEnableFeature(features::kAutofillAcrossIframes);
-  }
-  ~FormAutofillUtilsTestWithIframesEnabled() override = default;
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
 // Tests that large option values/contents are truncated while building the
 // FormData.
 TEST_F(FormAutofillUtilsTest, TruncateLargeOptionValuesAndContents) {
@@ -795,7 +784,7 @@
 }
 
 // Tests IsOwnedByFrame().
-TEST_F(FormAutofillUtilsTestWithIframesEnabled, IsOwnedByFrame) {
+TEST_F(FormAutofillUtilsTest, IsOwnedByFrame) {
   LoadHTML(R"(
     <body>
       <div id="div"></div>
@@ -1313,7 +1302,7 @@
 };
 
 class FieldFramesTest
-    : public FormAutofillUtilsTestWithIframesEnabled,
+    : public FormAutofillUtilsTest,
       public testing::WithParamInterface<FieldFramesTestParam> {
  public:
   FieldFramesTest() = default;
@@ -1599,8 +1588,7 @@
 
 // Tests that if the number of iframes exceeds kMaxExtractableChildFrames,
 // child frames of that form are not extracted.
-TEST_F(FormAutofillUtilsTestWithIframesEnabled,
-       ExtractNoFramesIfTooManyIframes) {
+TEST_F(FormAutofillUtilsTest, ExtractNoFramesIfTooManyIframes) {
   auto CreateFormElement = [this](const char* element) {
     std::string js = base::StringPrintf(
         "document.forms[0].appendChild(document.createElement('%s'))", element);
@@ -1643,8 +1631,7 @@
 
 // Tests that if the number of fields exceeds |kMaxExtractableFields|, neither
 // fields nor child frames of that form are extracted.
-TEST_F(FormAutofillUtilsTestWithIframesEnabled,
-       ExtractNoFieldsOrFramesIfTooManyFields) {
+TEST_F(FormAutofillUtilsTest, ExtractNoFieldsOrFramesIfTooManyFields) {
   auto CreateFormElement = [this](const char* element) {
     std::string js = base::StringPrintf(
         "document.forms[0].appendChild(document.createElement('%s'))", element);
diff --git a/components/autofill/content/renderer/form_cache_browsertest.cc b/components/autofill/content/renderer/form_cache_browsertest.cc
index bd50edc..da37ff3d 100644
--- a/components/autofill/content/renderer/form_cache_browsertest.cc
+++ b/components/autofill/content/renderer/form_cache_browsertest.cc
@@ -208,18 +208,7 @@
   EXPECT_TRUE(forms.removed_forms.empty());
 }
 
-class FormCacheIframeBrowserTest : public FormCacheBrowserTest {
- public:
-  FormCacheIframeBrowserTest() {
-    scoped_feature_list_.InitAndEnableFeature(features::kAutofillAcrossIframes);
-  }
-  ~FormCacheIframeBrowserTest() override = default;
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-TEST_F(FormCacheIframeBrowserTest, ExtractFrames) {
+TEST_F(FormCacheBrowserTest, ExtractFrames) {
   LoadHTML(R"(
     <form id="form1">
       <iframe id="frame1"></iframe>
@@ -276,7 +265,7 @@
   EXPECT_TRUE(forms.removed_forms.empty());
 }
 
-TEST_F(FormCacheIframeBrowserTest, ExtractFramesTwice) {
+TEST_F(FormCacheBrowserTest, ExtractFramesTwice) {
   LoadHTML(R"(
     <form id="form1">
       <iframe></iframe>
@@ -299,7 +288,7 @@
 }
 
 // TODO(crbug.com/1117028) Adjust expectations when we omit invisible iframes.
-TEST_F(FormCacheIframeBrowserTest, ExtractFramesAfterVisibilityChange) {
+TEST_F(FormCacheBrowserTest, ExtractFramesAfterVisibilityChange) {
   LoadHTML(R"(
     <form id="form1">
       <iframe id="frame1" style="display: none;"></iframe>
@@ -775,7 +764,7 @@
 
 // Test that FormCache::UpdateFormCache() limits the number of total frames by
 // clearing their frames and skipping the then-empty forms.
-TEST_F(FormCacheIframeBrowserTest, FrameLimit) {
+TEST_F(FormCacheBrowserTest, FrameLimit) {
   std::string html;
   for (unsigned int i = 0; i < kMaxExtractableChildFrames + 1; i++) {
     html += "<form><iframe></iframe></form>";
@@ -805,7 +794,7 @@
 #else
 #define MAYBE_FieldAndFrameLimit FieldAndFrameLimit
 #endif
-TEST_F(FormCacheIframeBrowserTest, MAYBE_FieldAndFrameLimit) {
+TEST_F(FormCacheBrowserTest, MAYBE_FieldAndFrameLimit) {
   ASSERT_LE(kMaxExtractableChildFrames, kMaxExtractableFields);
 
   std::string html;
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index e15a7c77..d8466d8e 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -639,8 +639,7 @@
       };
       if (field->host_form_signature &&
           field->host_form_signature != form->form_signature() &&
-          !is_override(current_field) &&
-          base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
+          !is_override(current_field)) {
         // Retrieves the alternative prediction even if it is not used so that
         // the alternative predictions are popped.
         absl::optional<FieldSuggestion> alternative_field = GetPrediction(
@@ -1245,13 +1244,11 @@
 
   AddFormIf(form_signature(), [](auto& f) { return true; });
 
-  if (base::FeatureList::IsEnabled(features::kAutofillAcrossIframes)) {
-    for (const auto& field : fields_) {
-      if (field->host_form_signature) {
-        AddFormIf(field->host_form_signature, [&](const auto& f) {
-          return f->host_form_signature == field->host_form_signature;
-        });
-      }
+  for (const auto& field : fields_) {
+    if (field->host_form_signature) {
+      AddFormIf(field->host_form_signature, [&](const auto& f) {
+        return f->host_form_signature == field->host_form_signature;
+      });
     }
   }
 }
diff --git a/components/autofill/core/browser/form_structure_unittest.cc b/components/autofill/core/browser/form_structure_unittest.cc
index b701b1f..cc57890 100644
--- a/components/autofill/core/browser/form_structure_unittest.cc
+++ b/components/autofill/core/browser/form_structure_unittest.cc
@@ -170,10 +170,6 @@
   test::AutofillUnitTestEnvironment autofill_test_environment_;
 };
 
-class ParameterizedFormStructureTest
-    : public FormStructureTestImpl,
-      public testing::WithParamInterface<bool> {};
-
 class FormStructureTest_ForPatternSource
     : public FormStructureTestImpl,
       public testing::WithParamInterface<PatternSource> {
@@ -2177,15 +2173,7 @@
             form_structure->field(5)->heuristic_type());
 }
 
-TEST_P(ParameterizedFormStructureTest, EncodeQueryRequest) {
-  bool autofill_across_iframes = GetParam();
-  base::test::ScopedFeatureList scoped_features;
-  std::vector<base::test::FeatureRef> enabled;
-  std::vector<base::test::FeatureRef> disabled;
-  (autofill_across_iframes ? &enabled : &disabled)
-      ->push_back(features::kAutofillAcrossIframes);
-  scoped_features.InitWithFeatures(enabled, disabled);
-
+TEST_F(FormStructureTestImpl, EncodeQueryRequest) {
   FormSignature form_signature(16692857476255362434UL);
 
   FormData form;
@@ -2241,10 +2229,8 @@
 
   std::vector<FormSignature> expected_signatures;
   expected_signatures.emplace_back(form_signature.value());
-  if (autofill_across_iframes) {
-    expected_signatures.emplace_back(12345UL);
-    expected_signatures.emplace_back(67890UL);
-  }
+  expected_signatures.emplace_back(12345UL);
+  expected_signatures.emplace_back(67890UL);
 
   // Prepare the expected proto string.
   AutofillPageQueryRequest query;
@@ -2257,17 +2243,16 @@
     query_form->add_fields()->set_signature(2226358947U);
     query_form->add_fields()->set_signature(747221617U);
     query_form->add_fields()->set_signature(4108155786U);
-    if (autofill_across_iframes) {
-      query_form = query.add_forms();
-      query_form->set_signature(12345UL);
-      query_form->add_fields()->set_signature(1917667676U);
-      query_form->add_fields()->set_signature(747221617U);
-      query_form->add_fields()->set_signature(4108155786U);
 
-      query_form = query.add_forms();
-      query_form->set_signature(67890UL);
-      query_form->add_fields()->set_signature(2226358947U);
-    }
+    query_form = query.add_forms();
+    query_form->set_signature(12345UL);
+    query_form->add_fields()->set_signature(1917667676U);
+    query_form->add_fields()->set_signature(747221617U);
+    query_form->add_fields()->set_signature(4108155786U);
+
+    query_form = query.add_forms();
+    query_form->set_signature(67890UL);
+    query_form->add_fields()->set_signature(2226358947U);
   }
 
   AutofillPageQueryRequest encoded_query;
@@ -5348,9 +5333,6 @@
 // crowdsourcing
 TEST_F(FormStructureTestImpl,
        ParseApiQueryResponse_PrecedenceRulesBetweenMainFrameAndIframe) {
-  base::test::ScopedFeatureList scoped_features;
-  scoped_features.InitAndEnableFeature(features::kAutofillAcrossIframes);
-
   struct TestCase {
     bool main_frame_has_override;
     bool iframe_has_override;
@@ -5435,9 +5417,6 @@
 // predictions.
 TEST_F(FormStructureTestImpl,
        ParseApiQueryResponse_FallbackToHostFormSignature) {
-  base::test::ScopedFeatureList scoped_features;
-  scoped_features.InitAndEnableFeature(features::kAutofillAcrossIframes);
-
   std::vector<ServerFieldType> expected_types;
 
   // Create a form whose fields have FormFieldData::host_form_signature either
@@ -5763,10 +5742,6 @@
   EXPECT_EQ(UNKNOWN_TYPE, forms[0]->field(1)->Type().GetStorableType());
 }
 
-INSTANTIATE_TEST_SUITE_P(FormStructureTest,
-                         ParameterizedFormStructureTest,
-                         testing::Bool());
-
 // Tests that, when the flag is off, we will not set the predicted type to
 // unknown for fields that have no server data and autocomplete off, and when
 // the flag is ON, we will overwrite the predicted type.
diff --git a/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc b/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
index a342fef..441abd9 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
+++ b/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
@@ -8042,8 +8042,7 @@
 
   AutofillMetricsCrossFrameFormTest() {
     scoped_feature_list_.InitWithFeaturesAndParameters(
-        {base::test::FeatureRefAndParams(features::kAutofillAcrossIframes, {}),
-         base::test::FeatureRefAndParams(features::kAutofillSharedAutofill,
+        {base::test::FeatureRefAndParams(features::kAutofillSharedAutofill,
                                          {{"relax_shared_autofill", "true"}})},
         {});
   }
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index 61f0b15..22b631c 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -10,12 +10,6 @@
 
 namespace autofill::features {
 
-// Controls whether to flatten and fill cross-iframe forms.
-// TODO(crbug.com/1187842) Remove once launched.
-BASE_FEATURE(kAutofillAcrossIframes,
-             "AutofillAcrossIframes",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 // Controls whether to flatten and fill cross-iframe forms on iOS.
 // TODO(crbug.com/1441921) Remove once launched.
 BASE_FEATURE(kAutofillAcrossIframesIos,
@@ -465,8 +459,7 @@
 const base::FeatureParam<int> kAutofillServerBehaviorsParam{
     &kAutofillServerBehaviors, "server_prediction_source", 0};
 
-// Controls whether Autofill may fill across origins as part of the
-// AutofillAcrossIframes experiment.
+// Controls whether Autofill may fill across origins.
 // TODO(crbug.com/1304721): Clean up when launched.
 BASE_FEATURE(kAutofillSharedAutofill,
              "AutofillSharedAutofill",
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index d250808..0af2e803 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -14,7 +14,6 @@
 namespace autofill::features {
 
 // All features in alphabetical order.
-COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillAcrossIframes);
 COMPONENT_EXPORT(AUTOFILL) BASE_DECLARE_FEATURE(kAutofillAcrossIframesIos);
 COMPONENT_EXPORT(AUTOFILL)
 BASE_DECLARE_FEATURE(
diff --git a/components/page_load_metrics/browser/page_load_tracker.cc b/components/page_load_metrics/browser/page_load_tracker.cc
index 7c45a94..5b33949bf 100644
--- a/components/page_load_metrics/browser/page_load_tracker.cc
+++ b/components/page_load_metrics/browser/page_load_tracker.cc
@@ -691,8 +691,15 @@
 
 void PageLoadTracker::OnLoadedResource(
     const ExtraRequestCompleteInfo& extra_request_complete_info) {
-  receive_headers_start_ =
-      extra_request_complete_info.load_timing_info->receive_headers_start;
+  // The main_frame_receive_headers_start_ should be only set once during a
+  // page load. A new page load would have a new PageLoadTracker object.
+  if (extra_request_complete_info.request_destination ==
+          network::mojom::RequestDestination::kDocument &&
+      !main_frame_receive_headers_start_.has_value()) {
+    main_frame_receive_headers_start_ =
+        extra_request_complete_info.load_timing_info->receive_headers_start;
+  }
+
   for (const auto& observer : observers_) {
     observer->OnLoadedResource(extra_request_complete_info);
   }
@@ -938,10 +945,11 @@
                .value());
 
   if (largest_contentful_image_changed) {
-    if (receive_headers_start_.has_value() && !GetNavigationStart().is_null()) {
+    if (main_frame_receive_headers_start_.has_value() &&
+        !GetNavigationStart().is_null()) {
       RecordLargestContentfulPaintImageLoadTiming(
           *paint_timing->largest_contentful_paint,
-          receive_headers_start_.value() - GetNavigationStart());
+          main_frame_receive_headers_start_.value() - GetNavigationStart());
     }
   }
 
diff --git a/components/page_load_metrics/browser/page_load_tracker.h b/components/page_load_metrics/browser/page_load_tracker.h
index 0737d39..75767c4 100644
--- a/components/page_load_metrics/browser/page_load_tracker.h
+++ b/components/page_load_metrics/browser/page_load_tracker.h
@@ -572,7 +572,7 @@
 
   uint32_t soft_navigation_count_ = 0;
 
-  absl::optional<base::TimeTicks> receive_headers_start_;
+  absl::optional<base::TimeTicks> main_frame_receive_headers_start_;
 
   const internal::PageLoadTrackerPageType page_type_;
 
diff --git a/components/page_load_metrics/browser/page_load_tracker_unittest.cc b/components/page_load_metrics/browser/page_load_tracker_unittest.cc
index 7e3818e..d9cdd03c 100644
--- a/components/page_load_metrics/browser/page_load_tracker_unittest.cc
+++ b/components/page_load_metrics/browser/page_load_tracker_unittest.cc
@@ -494,10 +494,30 @@
       /*load_timing_info=*/
       std::make_unique<net::LoadTimingInfo>(load_timing_info));
 
-  // Set document receive_headers_start.
+  // Set main frame document receive_headers_start. This field should be set
+  // only once.
   const auto request_id = navigation_simulator->GetGlobalRequestID();
   tester()->SimulateLoadedResource(request_info, request_id);
 
+  // Simulate the invocation of PageLoadTracker::OnLoadedResource() again with
+  // a ttfb earlier than the image load start and a request destination that is
+  // not of type Document. This should not overwrite the
+  // receive_headers_start that is already set.
+  load_timing_info.receive_headers_start =
+      reference_time + base::Milliseconds(29);
+
+  ExtraRequestCompleteInfo request_info1(
+      /*final_url=*/url::SchemeHostPort(GURL(kTestUrl)),
+      /*remote_endpoint=*/net::IPEndPoint(),
+      /*frame_tree_node_id=*/-1, /*was_cached=*/false, /*raw_body_bytes=*/0,
+      /*original_network_content_length=*/0,
+      /*request_destination=*/network::mojom::RequestDestination::kFrame,
+      /*net_error=*/0,
+      /*load_timing_info=*/
+      std::make_unique<net::LoadTimingInfo>(load_timing_info));
+
+  tester()->SimulateLoadedResource(request_info1, request_id);
+
   // Set largest contentful paint timings.
   tester()->SimulateTimingUpdate(timing);
 
diff --git a/components/performance_manager/prerendering_browsertest.cc b/components/performance_manager/prerendering_browsertest.cc
index 05239912..2f0b08f 100644
--- a/components/performance_manager/prerendering_browsertest.cc
+++ b/components/performance_manager/prerendering_browsertest.cc
@@ -209,9 +209,12 @@
   RunInGraph([&](Graph*) {
     ASSERT_TRUE(page_node);
     EXPECT_EQ(page_node->GetMainFrameNodes().size(), 1U);
-    EXPECT_EQ(page_node->GetMainFrameNode(), initial_main_frame_node);
+    // The RenderFrameHost might change after the navigation if RenderDocument
+    // is enabled.
+    EXPECT_EQ(content::WillSameSiteNavigationsChangeRenderFrameHosts(),
+              page_node->GetMainFrameNode() != initial_main_frame_node);
     EXPECT_EQ(page_node->GetMainFrameUrl(), kFinalUrl);
-    EXPECT_TRUE(initial_main_frame_node->IsCurrent());
+    EXPECT_TRUE(page_node->GetMainFrameNode()->IsCurrent());
   });
 }
 
diff --git a/components/performance_manager/v8_memory/v8_context_tracker_browsertest.cc b/components/performance_manager/v8_memory/v8_context_tracker_browsertest.cc
index e17d0e7..99dca2f1a 100644
--- a/components/performance_manager/v8_memory/v8_context_tracker_browsertest.cc
+++ b/components/performance_manager/v8_memory/v8_context_tracker_browsertest.cc
@@ -110,7 +110,7 @@
   });
 }
 
-IN_PROC_BROWSER_TEST_F(V8ContextTrackerTest, SameDocNavigation) {
+IN_PROC_BROWSER_TEST_F(V8ContextTrackerTest, SameSiteNavigation) {
   ExpectCounts(0, 0, 0, 0);
   auto* contents = shell()->web_contents();
   GURL urla(embedded_test_server()->GetURL("a.com", "/a_embeds_b.html"));
@@ -122,16 +122,29 @@
   content::RenderFrameHost* rfha = contents->GetPrimaryMainFrame();
   content::RenderFrameHost* rfhb = ChildFrameAt(rfha, 0);
 
-  // Execute a same document navigation in the child frame. This causes a
+  // Execute a same site navigation in the child frame. This causes a
   // v8 context to be detached, and new context attached to the execution
-  // context. So there will remain 2 execution contexts, there will be 3
-  // v8 contexts, 1 one of which is detached.
+  // context.
   GURL urlb(embedded_test_server()->GetURL("b.com", "/b.html?foo=bar"));
   ASSERT_TRUE(ExecJs(
       rfhb, base::StringPrintf("location.href = \"%s\"", urlb.spec().c_str())));
   WaitForLoad(contents);
 
-  ExpectCounts(3, 2, 1, 0);
+  if (content::WillSameSiteNavigationsChangeRenderFrameHosts()) {
+    // When RenderDocument is enabled, a new RenderFrameHost will be created for
+    // the navigation to `urlb`. Both a new V8 context and ExecutionContext are
+    // created, and the old ExecutionContext is destroyed.
+    ExpectCounts(/*v8_context_count=*/3, /*execution_context_count=*/3,
+                 /*detached_v8_context_count=*/1,
+                 /*destroyed_execution_context_count=*/1);
+  } else {
+    // When RenderDocument is disabled, the same RenderFrameHost will be reused
+    // for the navigation to `urlb`. So only a new V8 context will be created,
+    // not a new ExecutionContext.
+    ExpectCounts(/*v8_context_count=*/3, /*execution_context_count=*/2,
+                 /*detached_v8_context_count=*/1,
+                 /*destroyed_execution_context_count=*/0);
+  }
 }
 
 IN_PROC_BROWSER_TEST_F(V8ContextTrackerTest, DetachedContext) {
diff --git a/components/permissions/request_type.cc b/components/permissions/request_type.cc
index 8d636d95..f62c0f6 100644
--- a/components/permissions/request_type.cc
+++ b/components/permissions/request_type.cc
@@ -13,6 +13,7 @@
 #include "components/permissions/features.h"
 #include "components/permissions/permission_request.h"
 #include "components/permissions/permissions_client.h"
+#include "ui/base/ui_base_features.h"
 
 #if BUILDFLAG(IS_ANDROID)
 #include "components/resources/android/theme_resources.h"
@@ -68,33 +69,45 @@
 
 #if !BUILDFLAG(IS_ANDROID)
 const gfx::VectorIcon& GetIconIdDesktop(RequestType type) {
+  const bool cr23 = ::features::IsChromeRefresh2023();
   switch (type) {
     case RequestType::kAccessibilityEvents:
       return kAccessibilityIcon;
     case RequestType::kArSession:
     case RequestType::kVrSession:
-      return vector_icons::kVrHeadsetIcon;
+      return cr23 ? vector_icons::kVrHeadsetChromeRefreshIcon
+                  : vector_icons::kVrHeadsetIcon;
     case RequestType::kCameraPanTiltZoom:
     case RequestType::kCameraStream:
-      return vector_icons::kVideocamIcon;
+      return cr23 ? vector_icons::kVideocamChromeRefreshIcon
+                  : vector_icons::kVideocamIcon;
     case RequestType::kClipboard:
-      return vector_icons::kContentPasteIcon;
+      return cr23 ? vector_icons::kContentPasteChromeRefreshIcon
+                  : vector_icons::kContentPasteIcon;
     case RequestType::kDiskQuota:
-      return vector_icons::kFolderIcon;
+      return cr23 ? vector_icons::kFolderChromeRefreshIcon
+                  : vector_icons::kFolderIcon;
     case RequestType::kGeolocation:
-      return vector_icons::kLocationOnIcon;
+      return cr23 ? vector_icons::kLocationOnChromeRefreshIcon
+                  : vector_icons::kLocationOnIcon;
     case RequestType::kIdleDetection:
-      return vector_icons::kDevicesIcon;
+      return cr23 ? vector_icons::kDevicesChromeRefreshIcon
+                  : vector_icons::kDevicesIcon;
     case RequestType::kLocalFonts:
-      return vector_icons::kFontDownloadIcon;
+      return cr23 ? vector_icons::kFontDownloadChromeRefreshIcon
+                  : vector_icons::kFontDownloadIcon;
     case RequestType::kMicStream:
-      return vector_icons::kMicIcon;
+      return cr23 ? vector_icons::kMicChromeRefreshIcon
+                  : vector_icons::kMicIcon;
     case RequestType::kMidiSysex:
-      return vector_icons::kMidiIcon;
+      return cr23 ? vector_icons::kMidiChromeRefreshIcon
+                  : vector_icons::kMidiIcon;
     case RequestType::kMultipleDownloads:
-      return vector_icons::kFileDownloadIcon;
+      return cr23 ? vector_icons::kFileDownloadChromeRefreshIcon
+                  : vector_icons::kFileDownloadIcon;
     case RequestType::kNotifications:
-      return vector_icons::kNotificationsIcon;
+      return cr23 ? vector_icons::kNotificationsChromeRefreshIcon
+                  : vector_icons::kNotificationsIcon;
 #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
     case RequestType::kProtectedMediaIdentifier:
       // This icon is provided by ChromePermissionsClient::GetOverrideIconId.
@@ -109,33 +122,44 @@
       return kUsbSecurityKeyIcon;
     case RequestType::kStorageAccess:
     case RequestType::kTopLevelStorageAccess:
-      return vector_icons::kCookieIcon;
+      return cr23 ? vector_icons::kCookieChromeRefreshIcon
+                  : vector_icons::kCookieIcon;
     case RequestType::kWindowManagement:
-      return vector_icons::kSelectWindowIcon;
+      return cr23 ? vector_icons::kSelectWindowChromeRefreshIcon
+                  : vector_icons::kSelectWindowIcon;
   }
   NOTREACHED();
   return gfx::kNoneIcon;
 }
 
 const gfx::VectorIcon& GetBlockedIconIdDesktop(RequestType type) {
+  const bool cr23 = ::features::IsChromeRefresh2023();
   switch (type) {
     case RequestType::kGeolocation:
-      return vector_icons::kLocationOffIcon;
+      return cr23 ? vector_icons::kLocationOffChromeRefreshIcon
+                  : vector_icons::kLocationOffIcon;
     case RequestType::kNotifications:
-      return vector_icons::kNotificationsOffIcon;
+      return cr23 ? vector_icons::kNotificationsOffChromeRefreshIcon
+                  : vector_icons::kNotificationsOffIcon;
     case RequestType::kArSession:
     case RequestType::kVrSession:
-      return vector_icons::kVrHeadsetOffIcon;
+      return cr23 ? vector_icons::kVrHeadsetOffChromeRefreshIcon
+                  : vector_icons::kVrHeadsetOffIcon;
     case RequestType::kCameraStream:
-      return vector_icons::kVideocamOffIcon;
+      return cr23 ? vector_icons::kVideocamOffChromeRefreshIcon
+                  : vector_icons::kVideocamOffIcon;
     case RequestType::kClipboard:
-      return vector_icons::kContentPasteOffIcon;
+      return cr23 ? vector_icons::kContentPasteOffChromeRefreshIcon
+                  : vector_icons::kContentPasteOffIcon;
     case RequestType::kIdleDetection:
-      return vector_icons::kDevicesOffIcon;
+      return cr23 ? vector_icons::kDevicesOffChromeRefreshIcon
+                  : vector_icons::kDevicesOffIcon;
     case RequestType::kMicStream:
-      return vector_icons::kMicOffIcon;
+      return cr23 ? vector_icons::kMicOffChromeRefreshIcon
+                  : vector_icons::kMicOffIcon;
     case RequestType::kMidiSysex:
-      return vector_icons::kMidiOffIcon;
+      return cr23 ? vector_icons::kMidiOffChromeRefreshIcon
+                  : vector_icons::kMidiOffIcon;
     case RequestType::kStorageAccess:
       return vector_icons::kCookieOffChromeRefreshIcon;
     default:
diff --git a/components/services/app_service/public/cpp/shortcut/BUILD.gn b/components/services/app_service/public/cpp/shortcut/BUILD.gn
index 7f05d2e..6a287f40 100644
--- a/components/services/app_service/public/cpp/shortcut/BUILD.gn
+++ b/components/services/app_service/public/cpp/shortcut/BUILD.gn
@@ -36,6 +36,7 @@
 
   deps = [
     ":shortcut",
+    "//base",
     "//testing/gtest",
   ]
 }
diff --git a/components/services/app_service/public/cpp/shortcut/shortcut.cc b/components/services/app_service/public/cpp/shortcut/shortcut.cc
index 61cb91f..4863a19f 100644
--- a/components/services/app_service/public/cpp/shortcut/shortcut.cc
+++ b/components/services/app_service/public/cpp/shortcut/shortcut.cc
@@ -22,6 +22,13 @@
 
 Shortcut::~Shortcut() = default;
 
+bool Shortcut::operator==(const Shortcut& rhs) const {
+  return this->shortcut_id == rhs.shortcut_id &&
+         this->host_app_id == rhs.host_app_id &&
+         this->local_id == rhs.local_id && this->name == rhs.name &&
+         this->shortcut_source == rhs.shortcut_source;
+}
+
 std::unique_ptr<Shortcut> Shortcut::Clone() const {
   auto shortcut = std::make_unique<Shortcut>(host_app_id, local_id);
 
diff --git a/components/services/app_service/public/cpp/shortcut/shortcut.h b/components/services/app_service/public/cpp/shortcut/shortcut.h
index 3020da43..c4b52c19 100644
--- a/components/services/app_service/public/cpp/shortcut/shortcut.h
+++ b/components/services/app_service/public/cpp/shortcut/shortcut.h
@@ -35,6 +35,8 @@
   Shortcut(Shortcut&&) = delete;
   Shortcut& operator=(Shortcut&&) = delete;
 
+  bool operator==(const Shortcut&) const;
+
   ~Shortcut();
 
   std::unique_ptr<Shortcut> Clone() const;
diff --git a/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache.cc b/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache.cc
index c03d77c..5005a8c 100644
--- a/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache.cc
+++ b/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache.cc
@@ -9,13 +9,27 @@
 
 #include "base/check.h"
 #include "base/containers/contains.h"
+#include "base/observer_list.h"
 #include "components/services/app_service/public/cpp/shortcut/shortcut_update.h"
 
 namespace apps {
 
 ShortcutRegistryCache::ShortcutRegistryCache() = default;
 
-ShortcutRegistryCache::~ShortcutRegistryCache() = default;
+ShortcutRegistryCache::~ShortcutRegistryCache() {
+  for (auto& obs : observers_) {
+    obs.OnShortcutRegistryCacheWillBeDestroyed(this);
+  }
+  CHECK(observers_.empty());
+}
+
+void ShortcutRegistryCache::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void ShortcutRegistryCache::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
 
 void ShortcutRegistryCache::UpdateShortcut(ShortcutPtr delta) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -24,12 +38,19 @@
   is_updating_ = true;
   const ShortcutId shortcut_id = delta->shortcut_id;
 
-  if (HasShortcut(shortcut_id)) {
-    ShortcutUpdate::Merge(states_[shortcut_id].get(), delta.get());
+  Shortcut* state =
+      HasShortcut(shortcut_id) ? states_[shortcut_id].get() : nullptr;
+
+  for (auto& obs : observers_) {
+    obs.OnShortcutUpdated(ShortcutUpdate(state, delta.get()));
+  }
+
+  if (state) {
+    ShortcutUpdate::Merge(state, delta.get());
   } else {
     states_.emplace(shortcut_id, delta->Clone());
   }
-  // TODO(crbug.com/1412708): Update observer.
+
   is_updating_ = false;
 }
 
@@ -54,4 +75,4 @@
   return shortcuts;
 }
 
-}  // namespace apps
\ No newline at end of file
+}  // namespace apps
diff --git a/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache.h b/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache.h
index 604e7f1..944d94f 100644
--- a/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache.h
+++ b/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache.h
@@ -13,8 +13,11 @@
 #include "base/containers/contains.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/stack_allocated.h"
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
 #include "base/sequence_checker.h"
 #include "components/services/app_service/public/cpp/shortcut/shortcut.h"
+#include "components/services/app_service/public/cpp/shortcut/shortcut_update.h"
 
 namespace apps {
 
@@ -34,6 +37,21 @@
     STACK_ALLOCATED();
   };
 
+  class COMPONENT_EXPORT(SHORTCUT) Observer : public base::CheckedObserver {
+   public:
+    // Called when a shortcut been updated (including added). `update` contains
+    // the shortcut updating information to let the clients know which shortcut
+    // has been updated and what changes have been made.
+    virtual void OnShortcutUpdated(const ShortcutUpdate& update) {}
+
+    // Called when the ShortcutRegistryCache object (the thing that this
+    // observer observes) will be destroyed. In response, the observer, |this|,
+    // should call "cache->RemoveObserver(this)", whether directly or indirectly
+    // (e.g. via base::ScopedObservation::Reset).
+    virtual void OnShortcutRegistryCacheWillBeDestroyed(
+        ShortcutRegistryCache* cache) = 0;
+  };
+
   ShortcutRegistryCache();
 
   ShortcutRegistryCache(const ShortcutRegistryCache&) = delete;
@@ -41,6 +59,9 @@
 
   ~ShortcutRegistryCache();
 
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
   // Apply the shortcut update `delta` to an existing shortcut, or create a new
   // shortcut if it doesn't exists.
   void UpdateShortcut(ShortcutPtr delta);
@@ -67,6 +88,8 @@
   // TODO(crbug.com/1412708): Handle observer updates if proved to be necessary.
   bool is_updating_ = false;
 
+  base::ObserverList<Observer> observers_;
+
   SEQUENCE_CHECKER(sequence_checker_);
 };
 using ShortcutView = ShortcutRegistryCache::ShortcutView;
diff --git a/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache_unittest.cc b/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache_unittest.cc
index e192fec..68e148b57 100644
--- a/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache_unittest.cc
+++ b/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache_unittest.cc
@@ -7,17 +7,43 @@
 #include <memory>
 #include <utility>
 
+#include "base/scoped_observation.h"
 #include "components/services/app_service/public/cpp/shortcut/shortcut.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace apps {
 
-class ShortcutRegistryCacheTest : public testing::Test {
+class ShortcutRegistryCacheTest : public testing::Test,
+                                  public ShortcutRegistryCache::Observer {
  public:
   ShortcutRegistryCache& cache() { return cache_; }
 
+ protected:
+  void ExpectShortcutUpdate(std::unique_ptr<ShortcutUpdate> update) {
+    expected_update_ = std::move(update);
+    if (!obs_.IsObserving()) {
+      obs_.Observe(&cache());
+    }
+    on_shortcut_updated_called_ = false;
+  }
+  bool OnShortcutUpdatedCalled() { return on_shortcut_updated_called_; }
+
  private:
+  void OnShortcutUpdated(const ShortcutUpdate& update) override {
+    on_shortcut_updated_called_ = true;
+    EXPECT_EQ(update, *expected_update_);
+  }
+
+  void OnShortcutRegistryCacheWillBeDestroyed(
+      ShortcutRegistryCache* cache) override {
+    obs_.Reset();
+  }
   ShortcutRegistryCache cache_;
+  std::unique_ptr<ShortcutUpdate> expected_update_;
+  bool on_shortcut_updated_called_ = false;
+  base::ScopedObservation<ShortcutRegistryCache,
+                          ShortcutRegistryCache::Observer>
+      obs_{this};
 };
 
 TEST_F(ShortcutRegistryCacheTest, AddShortcut) {
@@ -75,4 +101,34 @@
   EXPECT_EQ(stored_shortcut->host_app_id, host_app_id);
   EXPECT_EQ(stored_shortcut->local_id, local_id);
 }
+
+TEST_F(ShortcutRegistryCacheTest, Observer) {
+  std::string host_app_id = "host_app_id";
+  std::string local_id = "local_id";
+  auto shortcut = std::make_unique<Shortcut>(host_app_id, local_id);
+  ShortcutId shortcut_id = shortcut->shortcut_id;
+  shortcut->name = "name";
+  shortcut->shortcut_source = ShortcutSource::kUser;
+  ExpectShortcutUpdate(
+      std::make_unique<ShortcutUpdate>(nullptr, shortcut.get()));
+  cache().UpdateShortcut(std::move(shortcut));
+  EXPECT_TRUE(OnShortcutUpdatedCalled());
+
+  auto shortcut_delta = std::make_unique<Shortcut>(host_app_id, local_id);
+  shortcut_delta->name = "new name";
+  shortcut_delta->shortcut_source = ShortcutSource::kDeveloper;
+  std::unique_ptr<Shortcut> current_state =
+      cache().GetShortcut(shortcut_id)->Clone();
+  ExpectShortcutUpdate(std::make_unique<ShortcutUpdate>(current_state.get(),
+                                                        shortcut_delta.get()));
+  cache().UpdateShortcut(std::move(shortcut_delta));
+  EXPECT_TRUE(OnShortcutUpdatedCalled());
+
+  auto shortcut_nochange = std::make_unique<Shortcut>(host_app_id, local_id);
+  current_state = cache().GetShortcut(shortcut_id)->Clone();
+  ExpectShortcutUpdate(std::make_unique<ShortcutUpdate>(
+      current_state.get(), shortcut_nochange.get()));
+  cache().UpdateShortcut(std::move(shortcut_nochange));
+  EXPECT_TRUE(OnShortcutUpdatedCalled());
+}
 }  // namespace apps
diff --git a/components/services/app_service/public/cpp/shortcut/shortcut_update.cc b/components/services/app_service/public/cpp/shortcut/shortcut_update.cc
index 7f9a6ad..5e020f0 100644
--- a/components/services/app_service/public/cpp/shortcut/shortcut_update.cc
+++ b/components/services/app_service/public/cpp/shortcut/shortcut_update.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "components/services/app_service/public/cpp/shortcut/shortcut_update.h"
+#include <type_traits>
 
 #include "base/check.h"
 #include "base/check_op.h"
@@ -23,6 +24,25 @@
   }
 }
 
+bool ShortcutUpdate::operator==(const ShortcutUpdate& rhs) const {
+  bool states_are_same = false;
+  bool deltas_are_same = false;
+  if (!this->state_ && !rhs.state_) {
+    states_are_same = true;
+  }
+  if (this->state_ && rhs.state_) {
+    states_are_same = *(this->state_) == *(rhs.state_);
+  }
+
+  if (!this->delta_ && !rhs.delta_) {
+    deltas_are_same = true;
+  }
+  if (this->delta_ && rhs.delta_) {
+    deltas_are_same = *(this->delta_) == *(rhs.delta_);
+  }
+  return states_are_same && deltas_are_same;
+}
+
 void ShortcutUpdate::Merge(Shortcut* state, const Shortcut* delta) {
   CHECK(state);
   if (!delta) {
@@ -83,4 +103,17 @@
                                       ShortcutSource::kUnknown);
 }
 
+// For logging and debug purposes.
+COMPONENT_EXPORT(SHORTCUT)
+std::ostream& operator<<(std::ostream& out,
+                         const ShortcutUpdate& shortcut_update) {
+  out << "ShortcutId: " << shortcut_update.ShortcutId() << std::endl;
+  out << "HostAppId: " << shortcut_update.HostAppId() << std::endl;
+  out << "LocalId: " << shortcut_update.LocalId() << std::endl;
+  out << "Name: " << shortcut_update.Name() << std::endl;
+  out << "ShortcutSource: " << EnumToString(shortcut_update.ShortcutSource())
+      << std::endl;
+  return out;
+}
+
 }  // namespace apps
diff --git a/components/services/app_service/public/cpp/shortcut/shortcut_update.h b/components/services/app_service/public/cpp/shortcut/shortcut_update.h
index 4007607..d362613 100644
--- a/components/services/app_service/public/cpp/shortcut/shortcut_update.h
+++ b/components/services/app_service/public/cpp/shortcut/shortcut_update.h
@@ -26,6 +26,8 @@
   ShortcutUpdate(const ShortcutUpdate&) = delete;
   ShortcutUpdate& operator=(const ShortcutUpdate&) = delete;
 
+  bool operator==(const ShortcutUpdate&) const;
+
   const ShortcutId& ShortcutId() const;
   const std::string& HostAppId() const;
   const std::string& LocalId() const;
diff --git a/components/services/app_service/public/cpp/shortcut/shortcut_update_unittest.cc b/components/services/app_service/public/cpp/shortcut/shortcut_update_unittest.cc
index 64e853f1..98f898e 100644
--- a/components/services/app_service/public/cpp/shortcut/shortcut_update_unittest.cc
+++ b/components/services/app_service/public/cpp/shortcut/shortcut_update_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "components/services/app_service/public/cpp/shortcut/shortcut_update.h"
 
+#include <memory>
+
 #include "components/services/app_service/public/cpp/shortcut/shortcut.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -91,4 +93,54 @@
   EXPECT_EQ(shortcut_state.local_id, local_id_);
 }
 
+TEST_F(ShortcutUpdateTest, Equal) {
+  std::unique_ptr<Shortcut> state_1 = std::make_unique<Shortcut>("a", "b");
+  state_1->name = "name";
+  std::unique_ptr<Shortcut> state_same_as_1 =
+      std::make_unique<Shortcut>("a", "b");
+  state_same_as_1->name = "name";
+  std::unique_ptr<Shortcut> state_2 = std::make_unique<Shortcut>("a", "b");
+  state_2->name = "different name";
+
+  std::unique_ptr<Shortcut> delta_1 = std::make_unique<Shortcut>("a", "b");
+  delta_1->name = "new name";
+  std::unique_ptr<Shortcut> delta_same_as_1 =
+      std::make_unique<Shortcut>("a", "b");
+  delta_same_as_1->name = "new name";
+  std::unique_ptr<Shortcut> delta_2 = std::make_unique<Shortcut>("a", "b");
+  delta_2->name = "new new name";
+
+  // Test nullptr handling.
+  EXPECT_EQ(ShortcutUpdate(nullptr, delta_1.get()),
+            ShortcutUpdate(nullptr, delta_1.get()));
+  EXPECT_NE(ShortcutUpdate(nullptr, delta_1.get()),
+            ShortcutUpdate(state_1.get(), nullptr));
+  EXPECT_NE(ShortcutUpdate(nullptr, delta_1.get()),
+            ShortcutUpdate(state_1.get(), delta_1.get()));
+  EXPECT_NE(ShortcutUpdate(state_1.get(), nullptr),
+            ShortcutUpdate(nullptr, delta_1.get()));
+  EXPECT_EQ(ShortcutUpdate(state_1.get(), nullptr),
+            ShortcutUpdate(state_1.get(), nullptr));
+  EXPECT_NE(ShortcutUpdate(state_1.get(), nullptr),
+            ShortcutUpdate(state_1.get(), delta_1.get()));
+  EXPECT_NE(ShortcutUpdate(state_1.get(), delta_1.get()),
+            ShortcutUpdate(nullptr, delta_1.get()));
+  EXPECT_NE(ShortcutUpdate(state_1.get(), delta_1.get()),
+            ShortcutUpdate(state_1.get(), nullptr));
+  EXPECT_EQ(ShortcutUpdate(state_1.get(), delta_1.get()),
+            ShortcutUpdate(state_1.get(), delta_1.get()));
+
+  // Test deep equal.
+  EXPECT_EQ(ShortcutUpdate(state_1.get(), delta_1.get()),
+            ShortcutUpdate(state_same_as_1.get(), delta_same_as_1.get()));
+
+  // Test not equal.
+  EXPECT_NE(ShortcutUpdate(state_1.get(), delta_1.get()),
+            ShortcutUpdate(state_2.get(), delta_1.get()));
+  EXPECT_NE(ShortcutUpdate(state_1.get(), delta_1.get()),
+            ShortcutUpdate(state_1.get(), delta_2.get()));
+  EXPECT_NE(ShortcutUpdate(state_1.get(), delta_1.get()),
+            ShortcutUpdate(state_2.get(), delta_2.get()));
+}
+
 }  // namespace apps
diff --git a/components/vector_icons/BUILD.gn b/components/vector_icons/BUILD.gn
index 14dd2f3..f35bcec 100644
--- a/components/vector_icons/BUILD.gn
+++ b/components/vector_icons/BUILD.gn
@@ -51,7 +51,9 @@
     "code_off.icon",
     "content_copy.icon",
     "content_paste.icon",
+    "content_paste_chrome_refresh.icon",
     "content_paste_off.icon",
+    "content_paste_off_chrome_refresh.icon",
     "cookie.icon",
     "cookie_chrome_refresh.icon",
     "cookie_off_chrome_refresh.icon",
@@ -59,7 +61,9 @@
     "dangerous_chrome_refresh.icon",
     "description.icon",
     "devices.icon",
+    "devices_chrome_refresh.icon",
     "devices_off.icon",
+    "devices_off_chrome_refresh.icon",
     "dogfood.icon",
     "edit.icon",
     "email.icon",
@@ -131,7 +135,9 @@
     "mic_off.icon",
     "mic_off_chrome_refresh.icon",
     "midi.icon",
+    "midi_chrome_refresh.icon",
     "midi_off.icon",
+    "midi_off_chrome_refresh.icon",
     "not_secure_warning.icon",
     "not_secure_warning_chrome_refresh.icon",
     "notification_warning.icon",
diff --git a/components/vector_icons/content_paste_chrome_refresh.icon b/components/vector_icons/content_paste_chrome_refresh.icon
new file mode 100644
index 0000000..c2eb0dc
--- /dev/null
+++ b/components/vector_icons/content_paste_chrome_refresh.icon
@@ -0,0 +1,81 @@
+// 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, 24,
+MOVE_TO, 5.07f, 21.22f,
+R_ARC_TO, 2.19f, 2.19f, 0, 0, 1, -1.6f, -0.67f,
+R_ARC_TO, 2.2f, 2.2f, 0, 0, 1, -0.67f, -1.61f,
+V_LINE_TO, 5.09f,
+R_CUBIC_TO, 0, -0.62f, 0.22f, -1.16f, 0.67f, -1.61f,
+R_ARC_TO, 2.19f, 2.19f, 0, 0, 1, 1.61f, -0.67f,
+R_H_LINE_TO, 3.95f,
+R_CUBIC_TO, 0.21f, -0.6f, 0.59f, -1.09f, 1.15f, -1.46f,
+ARC_TO, 3.19f, 3.19f, 0, 0, 1, 12, 0.79f,
+R_CUBIC_TO, 0.69f, 0, 1.31f, 0.19f, 1.86f, 0.57f,
+R_CUBIC_TO, 0.55f, 0.38f, 0.93f, 0.87f, 1.14f, 1.46f,
+R_H_LINE_TO, 3.93f,
+R_CUBIC_TO, 0.63f, 0, 1.16f, 0.22f, 1.61f, 0.67f,
+R_CUBIC_TO, 0.45f, 0.45f, 0.67f, 0.98f, 0.67f, 1.61f,
+R_V_LINE_TO, 13.86f,
+R_CUBIC_TO, 0, 0.63f, -0.22f, 1.16f, -0.67f, 1.61f,
+R_ARC_TO, 2.19f, 2.19f, 0, 0, 1, -1.6f, 0.67f,
+CLOSE,
+R_MOVE_TO, 0, -2.28f,
+R_H_LINE_TO, 13.86f,
+V_LINE_TO, 5.09f,
+R_H_LINE_TO, -1.96f,
+R_V_LINE_TO, 3.09f,
+H_LINE_TO, 7.03f,
+V_LINE_TO, 5.09f,
+R_H_LINE_TO, -1.96f,
+CLOSE,
+MOVE_TO, 12, 5,
+R_CUBIC_TO, 0.28f, 0, 0.52f, -0.1f, 0.71f, -0.29f,
+ARC_TO, 0.96f, 0.96f, 0, 0, 0, 13, 4,
+R_ARC_TO, 0.96f, 0.96f, 0, 0, 0, -0.29f, -0.71f,
+ARC_TO, 0.96f, 0.96f, 0, 0, 0, 12, 3,
+R_ARC_TO, 0.96f, 0.96f, 0, 0, 0, -0.71f, 0.29f,
+ARC_TO, 0.96f, 0.96f, 0, 0, 0, 11, 4,
+R_CUBIC_TO, 0, 0.28f, 0.1f, 0.52f, 0.29f, 0.71f,
+R_CUBIC_TO, 0.19f, 0.19f, 0.43f, 0.29f, 0.71f, 0.29f,
+CLOSE
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 4.56f, 17.18f,
+R_CUBIC_TO, -0.47f, 0, -0.88f, -0.17f, -1.22f, -0.51f,
+R_ARC_TO, 1.66f, 1.66f, 0, 0, 1, -0.51f, -1.22f,
+V_LINE_TO, 4.57f,
+R_CUBIC_TO, 0, -0.48f, 0.17f, -0.88f, 0.51f, -1.22f,
+R_ARC_TO, 1.67f, 1.67f, 0, 0, 1, 1.22f, -0.51f,
+R_H_LINE_TO, 3.38f,
+R_CUBIC_TO, 0.13f, -0.44f, 0.38f, -0.8f, 0.76f, -1.09f,
+R_CUBIC_TO, 0.38f, -0.29f, 0.81f, -0.43f, 1.31f, -0.43f,
+R_CUBIC_TO, 0.49f, 0, 0.92f, 0.14f, 1.3f, 0.43f,
+R_CUBIC_TO, 0.38f, 0.28f, 0.63f, 0.65f, 0.77f, 1.09f,
+R_H_LINE_TO, 3.38f,
+R_CUBIC_TO, 0.47f, 0, 0.88f, 0.17f, 1.22f, 0.51f,
+R_CUBIC_TO, 0.34f, 0.34f, 0.51f, 0.75f, 0.51f, 1.22f,
+R_V_LINE_TO, 10.88f,
+R_CUBIC_TO, 0, 0.47f, -0.17f, 0.88f, -0.51f, 1.22f,
+R_CUBIC_TO, -0.34f, 0.34f, -0.75f, 0.51f, -1.22f, 0.51f,
+CLOSE,
+R_MOVE_TO, 0, -1.73f,
+H_LINE_TO, 15.44f,
+V_LINE_TO, 4.57f,
+R_H_LINE_TO, -1.46f,
+R_V_LINE_TO, 2.58f,
+H_LINE_TO, 6.02f,
+V_LINE_TO, 4.57f,
+H_LINE_TO, 4.56f,
+CLOSE,
+MOVE_TO, 10, 4.5f,
+R_CUBIC_TO, 0.21f, 0, 0.39f, -0.07f, 0.54f, -0.21f,
+R_ARC_TO, 0.72f, 0.72f, 0, 0, 0, 0.22f, -0.53f,
+R_CUBIC_TO, 0, -0.21f, -0.07f, -0.39f, -0.21f, -0.53f,
+ARC_TO, 0.72f, 0.72f, 0, 0, 0, 10, 3,
+R_CUBIC_TO, -0.21f, 0, -0.39f, 0.07f, -0.53f, 0.22f,
+R_ARC_TO, 0.72f, 0.72f, 0, 0, 0, -0.22f, 0.53f,
+R_CUBIC_TO, 0, 0.21f, 0.07f, 0.39f, 0.22f, 0.54f,
+R_CUBIC_TO, 0.14f, 0.14f, 0.32f, 0.22f, 0.53f, 0.22f,
+CLOSE
\ No newline at end of file
diff --git a/components/vector_icons/content_paste_off_chrome_refresh.icon b/components/vector_icons/content_paste_off_chrome_refresh.icon
new file mode 100644
index 0000000..74bab4d5
--- /dev/null
+++ b/components/vector_icons/content_paste_off_chrome_refresh.icon
@@ -0,0 +1,87 @@
+// 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, 24,
+R_MOVE_TO, 21.2f, 18.14f,
+R_LINE_TO, -2.27f, -2.27f,
+V_LINE_TO, 5.09f,
+R_H_LINE_TO, -1.96f,
+R_V_LINE_TO, 3.09f,
+R_H_LINE_TO, -5.72f,
+LINE_TO, 5.88f, 2.82f,
+R_H_LINE_TO, 3.14f,
+R_CUBIC_TO, 0.21f, -0.6f, 0.59f, -1.09f, 1.15f, -1.46f,
+ARC_TO, 3.19f, 3.19f, 0, 0, 1, 12, 0.79f,
+R_CUBIC_TO, 0.69f, 0, 1.31f, 0.19f, 1.86f, 0.57f,
+R_CUBIC_TO, 0.55f, 0.38f, 0.93f, 0.87f, 1.14f, 1.46f,
+R_H_LINE_TO, 3.93f,
+R_CUBIC_TO, 0.63f, 0, 1.16f, 0.22f, 1.61f, 0.67f,
+R_CUBIC_TO, 0.45f, 0.45f, 0.67f, 0.98f, 0.67f, 1.61f,
+CLOSE,
+MOVE_TO, 12, 5,
+R_CUBIC_TO, 0.28f, 0, 0.52f, -0.1f, 0.71f, -0.29f,
+ARC_TO, 0.96f, 0.96f, 0, 0, 0, 13, 4,
+R_ARC_TO, 0.96f, 0.96f, 0, 0, 0, -0.29f, -0.71f,
+ARC_TO, 0.96f, 0.96f, 0, 0, 0, 12, 3,
+R_ARC_TO, 0.96f, 0.96f, 0, 0, 0, -0.71f, 0.29f,
+ARC_TO, 0.96f, 0.96f, 0, 0, 0, 11, 4,
+R_CUBIC_TO, 0, 0.28f, 0.1f, 0.52f, 0.29f, 0.71f,
+R_CUBIC_TO, 0.19f, 0.19f, 0.43f, 0.29f, 0.71f, 0.29f,
+CLOSE,
+R_MOVE_TO, 4.07f, 13.95f,
+R_LINE_TO, -11, -11,
+R_V_LINE_TO, 11,
+CLOSE,
+MOVE_TO, 5.07f, 21.22f,
+R_ARC_TO, 2.19f, 2.19f, 0, 0, 1, -1.6f, -0.67f,
+R_ARC_TO, 2.2f, 2.2f, 0, 0, 1, -0.67f, -1.61f,
+V_LINE_TO, 5.67f,
+LINE_TO, 1.13f, 4,
+R_LINE_TO, 1.48f, -1.48f,
+LINE_TO, 21.49f, 21.39f,
+R_LINE_TO, -1.48f, 1.48f,
+R_LINE_TO, -1.66f, -1.65f,
+CLOSE
+
+CANVAS_DIMENSIONS, 20,
+R_MOVE_TO, 17.17f, 14.86f,
+R_LINE_TO, -1.73f, -1.73f,
+V_LINE_TO, 4.57f,
+R_H_LINE_TO, -1.46f,
+R_V_LINE_TO, 2.58f,
+H_LINE_TO, 9.45f,
+LINE_TO, 5.15f, 2.84f,
+R_LINE_TO, 2.79f, 0.02f,
+R_CUBIC_TO, 0.17f, -0.47f, 0.43f, -0.84f, 0.78f, -1.12f,
+R_CUBIC_TO, 0.35f, -0.28f, 0.78f, -0.42f, 1.29f, -0.42f,
+R_CUBIC_TO, 0.5f, 0, 0.93f, 0.14f, 1.29f, 0.41f,
+R_CUBIC_TO, 0.36f, 0.28f, 0.62f, 0.65f, 0.78f, 1.11f,
+R_H_LINE_TO, 3.38f,
+R_CUBIC_TO, 0.47f, 0, 0.88f, 0.17f, 1.22f, 0.51f,
+R_CUBIC_TO, 0.34f, 0.34f, 0.51f, 0.75f, 0.51f, 1.22f,
+CLOSE,
+MOVE_TO, 10, 4.5f,
+R_CUBIC_TO, 0.21f, 0, 0.39f, -0.07f, 0.54f, -0.21f,
+R_ARC_TO, 0.72f, 0.72f, 0, 0, 0, 0.22f, -0.53f,
+R_CUBIC_TO, 0, -0.21f, -0.07f, -0.39f, -0.21f, -0.53f,
+ARC_TO, 0.72f, 0.72f, 0, 0, 0, 10, 3,
+R_CUBIC_TO, -0.21f, 0, -0.39f, 0.07f, -0.53f, 0.22f,
+R_ARC_TO, 0.72f, 0.72f, 0, 0, 0, -0.22f, 0.53f,
+R_CUBIC_TO, 0, 0.21f, 0.07f, 0.39f, 0.22f, 0.54f,
+R_CUBIC_TO, 0.14f, 0.14f, 0.32f, 0.22f, 0.53f, 0.22f,
+CLOSE,
+R_MOVE_TO, 3.31f, 10.96f,
+R_LINE_TO, -8.75f, -8.75f,
+R_V_LINE_TO, 8.75f,
+CLOSE,
+R_MOVE_TO, -8.75f, 1.73f,
+R_CUBIC_TO, -0.47f, 0, -0.88f, -0.17f, -1.22f, -0.51f,
+R_ARC_TO, 1.66f, 1.66f, 0, 0, 1, -0.51f, -1.22f,
+V_LINE_TO, 4.98f,
+LINE_TO, 1.66f, 3.81f,
+LINE_TO, 2.78f, 2.7f,
+R_LINE_TO, 14.52f, 14.52f,
+R_LINE_TO, -1.11f, 1.11f,
+R_LINE_TO, -1.15f, -1.15f,
+CLOSE
\ No newline at end of file
diff --git a/components/vector_icons/cookie_chrome_refresh.icon b/components/vector_icons/cookie_chrome_refresh.icon
index 9a7c5760..79c4865 100644
--- a/components/vector_icons/cookie_chrome_refresh.icon
+++ b/components/vector_icons/cookie_chrome_refresh.icon
@@ -2,6 +2,73 @@
 // 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, 8.75f, 8.5f,
+R_CUBIC_TO, 0.35f, 0, 0.64f, -0.12f, 0.89f, -0.36f,
+R_CUBIC_TO, 0.24f, -0.25f, 0.36f, -0.54f, 0.36f, -0.89f,
+R_CUBIC_TO, 0, -0.35f, -0.12f, -0.64f, -0.36f, -0.89f,
+ARC_TO, 1.22f, 1.22f, 0, 0, 0, 8.75f, 6,
+R_CUBIC_TO, -0.35f, 0, -0.64f, 0.12f, -0.89f, 0.36f,
+R_CUBIC_TO, -0.24f, 0.25f, -0.36f, 0.54f, -0.36f, 0.89f,
+R_CUBIC_TO, 0, 0.35f, 0.12f, 0.64f, 0.36f, 0.89f,
+R_CUBIC_TO, 0.25f, 0.24f, 0.54f, 0.36f, 0.89f, 0.36f,
+CLOSE,
+R_MOVE_TO, -2, 4,
+R_CUBIC_TO, 0.35f, 0, 0.64f, -0.12f, 0.89f, -0.36f,
+R_CUBIC_TO, 0.24f, -0.25f, 0.36f, -0.54f, 0.36f, -0.89f,
+R_CUBIC_TO, 0, -0.35f, -0.12f, -0.64f, -0.36f, -0.89f,
+ARC_TO, 1.22f, 1.22f, 0, 0, 0, 6.75f, 10,
+R_CUBIC_TO, -0.35f, 0, -0.64f, 0.12f, -0.89f, 0.36f,
+R_CUBIC_TO, -0.24f, 0.25f, -0.36f, 0.54f, -0.36f, 0.89f,
+R_CUBIC_TO, 0, 0.35f, 0.12f, 0.64f, 0.36f, 0.89f,
+R_CUBIC_TO, 0.25f, 0.24f, 0.54f, 0.36f, 0.89f, 0.36f,
+CLOSE,
+R_MOVE_TO, 5.75f, 0.75f,
+R_CUBIC_TO, 0.21f, 0, 0.39f, -0.07f, 0.54f, -0.21f,
+R_ARC_TO, 0.72f, 0.72f, 0, 0, 0, 0.22f, -0.53f,
+R_CUBIC_TO, 0, -0.21f, -0.07f, -0.39f, -0.21f, -0.53f,
+R_ARC_TO, 0.72f, 0.72f, 0, 0, 0, -0.53f, -0.22f,
+R_CUBIC_TO, -0.21f, 0, -0.39f, 0.07f, -0.53f, 0.22f,
+R_ARC_TO, 0.72f, 0.72f, 0, 0, 0, -0.22f, 0.53f,
+R_CUBIC_TO, 0, 0.21f, 0.07f, 0.39f, 0.22f, 0.54f,
+R_CUBIC_TO, 0.14f, 0.14f, 0.32f, 0.22f, 0.53f, 0.22f,
+CLOSE,
+MOVE_TO, 10, 18.11f,
+R_ARC_TO, 7.92f, 7.92f, 0, 0, 1, -3.15f, -0.63f,
+R_ARC_TO, 8.16f, 8.16f, 0, 0, 1, -4.33f, -4.33f,
+ARC_TO, 7.92f, 7.92f, 0, 0, 1, 1.89f, 10,
+R_CUBIC_TO, 0, -1.35f, 0.29f, -2.59f, 0.89f, -3.72f,
+R_CUBIC_TO, 0.59f, -1.12f, 1.36f, -2.05f, 2.31f, -2.79f,
+ARC_TO, 8.23f, 8.23f, 0, 0, 1, 8.27f, 1.98f,
+R_ARC_TO, 6.82f, 6.82f, 0, 0, 1, 3.53f, 0.1f,
+R_CUBIC_TO, -0.11f, 0.62f, -0.09f, 1.19f, 0.08f, 1.7f,
+R_CUBIC_TO, 0.16f, 0.51f, 0.44f, 0.94f, 0.82f, 1.27f,
+R_CUBIC_TO, 0.38f, 0.33f, 0.84f, 0.57f, 1.4f, 0.7f,
+R_CUBIC_TO, 0.56f, 0.13f, 1.15f, 0.13f, 1.8f, -0.02f,
+R_CUBIC_TO, -0.32f, 0.79f, -0.26f, 1.55f, 0.16f, 2.27f,
+R_CUBIC_TO, 0.43f, 0.72f, 1.1f, 1.08f, 2.01f, 1.09f,
+R_ARC_TO, 7.82f, 7.82f, 0, 0, 1, -0.36f, 3.44f,
+R_ARC_TO, 8.37f, 8.37f, 0, 0, 1, -1.66f, 2.88f,
+R_ARC_TO, 8.21f, 8.21f, 0, 0, 1, -2.66f, 1.98f,
+R_CUBIC_TO, -1.04f, 0.49f, -2.17f, 0.74f, -3.39f, 0.74f,
+CLOSE,
+R_MOVE_TO, 0, -1.73f,
+R_CUBIC_TO, 1.7f, 0, 3.15f, -0.57f, 4.36f, -1.71f,
+R_CUBIC_TO, 1.21f, -1.14f, 1.88f, -2.55f, 2.01f, -4.24f,
+R_ARC_TO, 3.8f, 3.8f, 0, 0, 1, -1.53f, -1.16f,
+R_ARC_TO, 3.86f, 3.86f, 0, 0, 1, -0.79f, -1.75f,
+R_ARC_TO, 4.86f, 4.86f, 0, 0, 1, -2.67f, -1.31f,
+R_ARC_TO, 4.42f, 4.42f, 0, 0, 1, -1.34f, -2.6f,
+R_ARC_TO, 5.58f, 5.58f, 0, 0, 0, -2.37f, 0.41f,
+R_CUBIC_TO, -0.77f, 0.31f, -1.46f, 0.75f, -2.06f, 1.32f,
+R_ARC_TO, 6.35f, 6.35f, 0, 0, 0, -1.45f, 2.05f,
+ARC_TO, 6.23f, 6.23f, 0, 0, 0, 3.61f, 10,
+R_CUBIC_TO, 0, 1.77f, 0.63f, 3.28f, 1.87f, 4.52f,
+R_CUBIC_TO, 1.24f, 1.24f, 2.75f, 1.87f, 4.52f, 1.87f,
+CLOSE,
+R_MOVE_TO, -0.01f, -6.35f,
+CLOSE
+
 CANVAS_DIMENSIONS, 16,
 MOVE_TO, 14.97f, 7.48f,
 R_CUBIC_TO, -0.07f, 0, -0.15f, 0.02f, -0.22f, 0.02f,
diff --git a/components/vector_icons/devices_chrome_refresh.icon b/components/vector_icons/devices_chrome_refresh.icon
new file mode 100644
index 0000000..13c0027
--- /dev/null
+++ b/components/vector_icons/devices_chrome_refresh.icon
@@ -0,0 +1,69 @@
+// 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, 24,
+MOVE_TO, 1.91f, 20.27f,
+V_LINE_TO, 17,
+R_H_LINE_TO, 2,
+V_LINE_TO, 6,
+R_CUBIC_TO, 0, -0.63f, 0.22f, -1.17f, 0.66f, -1.61f,
+R_CUBIC_TO, 0.45f, -0.44f, 0.98f, -0.66f, 1.61f, -0.66f,
+H_LINE_TO, 21,
+V_LINE_TO, 6,
+H_LINE_TO, 6.18f,
+R_V_LINE_TO, 11,
+R_H_LINE_TO, 5.73f,
+R_V_LINE_TO, 3.27f,
+CLOSE,
+R_MOVE_TO, 12.95f, 0,
+R_CUBIC_TO, -0.3f, 0, -0.55f, -0.1f, -0.75f, -0.3f,
+R_CUBIC_TO, -0.2f, -0.2f, -0.3f, -0.45f, -0.3f, -0.75f,
+V_LINE_TO, 8.95f,
+R_CUBIC_TO, 0, -0.3f, 0.1f, -0.54f, 0.3f, -0.74f,
+R_CUBIC_TO, 0.2f, -0.2f, 0.45f, -0.3f, 0.75f, -0.3f,
+R_H_LINE_TO, 6.18f,
+R_CUBIC_TO, 0.3f, 0, 0.54f, 0.1f, 0.74f, 0.3f,
+R_CUBIC_TO, 0.2f, 0.2f, 0.3f, 0.45f, 0.3f, 0.74f,
+R_V_LINE_TO, 10.27f,
+R_CUBIC_TO, 0, 0.3f, -0.1f, 0.55f, -0.3f, 0.75f,
+R_CUBIC_TO, -0.2f, 0.2f, -0.44f, 0.3f, -0.74f, 0.3f,
+CLOSE,
+MOVE_TO, 15.91f, 17,
+H_LINE_TO, 20,
+R_V_LINE_TO, -7,
+R_H_LINE_TO, -4.09f,
+CLOSE
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 1.93f, 16.23f,
+V_LINE_TO, 14,
+R_H_LINE_TO, 2,
+V_LINE_TO, 5.5f,
+R_CUBIC_TO, 0, -0.48f, 0.17f, -0.89f, 0.5f, -1.22f,
+R_CUBIC_TO, 0.34f, -0.34f, 0.75f, -0.51f, 1.23f, -0.51f,
+H_LINE_TO, 17,
+V_LINE_TO, 5.5f,
+H_LINE_TO, 5.66f,
+V_LINE_TO, 14,
+R_H_LINE_TO, 4.27f,
+R_V_LINE_TO, 2.23f,
+CLOSE,
+R_MOVE_TO, 10.96f, 0,
+R_CUBIC_TO, -0.3f, 0, -0.54f, -0.1f, -0.74f, -0.3f,
+R_CUBIC_TO, -0.2f, -0.2f, -0.3f, -0.45f, -0.3f, -0.74f,
+V_LINE_TO, 7.96f,
+R_CUBIC_TO, 0, -0.29f, 0.1f, -0.54f, 0.3f, -0.74f,
+R_CUBIC_TO, 0.2f, -0.2f, 0.45f, -0.3f, 0.74f, -0.3f,
+R_H_LINE_TO, 4.15f,
+R_CUBIC_TO, 0.29f, 0, 0.54f, 0.1f, 0.74f, 0.3f,
+R_CUBIC_TO, 0.2f, 0.2f, 0.3f, 0.45f, 0.3f, 0.74f,
+R_V_LINE_TO, 7.23f,
+R_CUBIC_TO, 0, 0.3f, -0.1f, 0.54f, -0.3f, 0.74f,
+R_CUBIC_TO, -0.2f, 0.2f, -0.44f, 0.3f, -0.74f, 0.3f,
+CLOSE,
+R_MOVE_TO, 0.54f, -2.23f,
+H_LINE_TO, 16.5f,
+V_LINE_TO, 8.5f,
+R_H_LINE_TO, -3.07f,
+CLOSE
diff --git a/components/vector_icons/devices_off_chrome_refresh.icon b/components/vector_icons/devices_off_chrome_refresh.icon
new file mode 100644
index 0000000..fd63c3c
--- /dev/null
+++ b/components/vector_icons/devices_off_chrome_refresh.icon
@@ -0,0 +1,77 @@
+// 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, 24,
+MOVE_TO, 8.97f, 6,
+LINE_TO, 6.7f, 3.73f,
+R_H_LINE_TO, 14.39f,
+V_LINE_TO, 6,
+CLOSE,
+R_MOVE_TO, 13.2f, 13.2f,
+R_LINE_TO, -2.09f, -2.09f,
+V_LINE_TO, 10,
+R_H_LINE_TO, -4.09f,
+R_V_LINE_TO, 3.02f,
+R_LINE_TO, -2.09f, -2.09f,
+V_LINE_TO, 8.95f,
+R_ARC_TO, 1.03f, 1.03f, 0, 0, 1, 1.05f, -1.04f,
+R_H_LINE_TO, 6.18f,
+R_CUBIC_TO, 0.3f, 0, 0.54f, 0.1f, 0.75f, 0.3f,
+R_CUBIC_TO, 0.2f, 0.2f, 0.3f, 0.45f, 0.3f, 0.74f,
+CLOSE,
+R_MOVE_TO, -2.18f, 3.74f,
+R_LINE_TO, -2.7f, -2.67f,
+R_H_LINE_TO, -2.34f,
+R_ARC_TO, 1.02f, 1.02f, 0, 0, 1, -1.05f, -1.05f,
+R_V_LINE_TO, -2.38f,
+LINE_TO, 6.26f, 9.21f,
+V_LINE_TO, 17,
+R_H_LINE_TO, 5.73f,
+R_V_LINE_TO, 3.27f,
+R_H_LINE_TO, -10,
+V_LINE_TO, 17,
+R_H_LINE_TO, 2,
+V_LINE_TO, 6.94f,
+LINE_TO, 1.23f, 4.17f,
+LINE_TO, 2.69f, 2.71f,
+R_LINE_TO, 18.77f, 18.77f,
+CLOSE
+
+CANVAS_DIMENSIONS, 20,
+R_MOVE_TO, 7.73f, 5.5f,
+R_LINE_TO, -1.73f, -1.73f,
+H_LINE_TO, 17.07f,
+V_LINE_TO, 5.5f,
+CLOSE,
+R_MOVE_TO, 10.42f, 10.4f,
+R_LINE_TO, -1.57f, -1.55f,
+V_LINE_TO, 8.5f,
+R_H_LINE_TO, -3.08f,
+R_V_LINE_TO, 2.77f,
+LINE_TO, 11.91f, 9.69f,
+R_V_LINE_TO, -1.73f,
+R_CUBIC_TO, 0, -0.29f, 0.1f, -0.53f, 0.31f, -0.73f,
+R_CUBIC_TO, 0.2f, -0.2f, 0.45f, -0.3f, 0.74f, -0.3f,
+R_H_LINE_TO, 4.15f,
+R_CUBIC_TO, 0.29f, 0, 0.53f, 0.1f, 0.74f, 0.3f,
+R_ARC_TO, 1, 1, 0, 0, 1, 0.31f, 0.74f,
+CLOSE,
+MOVE_TO, 16.16f, 18.41f,
+R_LINE_TO, -2.17f, -2.18f,
+R_H_LINE_TO, -1.03f,
+R_ARC_TO, 0.93f, 0.93f, 0, 0, 1, -0.76f, -0.27f,
+R_ARC_TO, 0.9f, 0.9f, 0, 0, 1, -0.28f, -0.77f,
+R_V_LINE_TO, -1.02f,
+LINE_TO, 5.72f, 7.97f,
+V_LINE_TO, 14,
+R_H_LINE_TO, 4.27f,
+R_V_LINE_TO, 2.23f,
+R_H_LINE_TO, -8,
+V_LINE_TO, 14,
+R_H_LINE_TO, 2,
+V_LINE_TO, 6.24f,
+LINE_TO, 1.73f, 3.98f,
+R_LINE_TO, 1.12f, -1.11f,
+R_LINE_TO, 14.43f, 14.43f,
+CLOSE
diff --git a/components/vector_icons/file_download_chrome_refresh.icon b/components/vector_icons/file_download_chrome_refresh.icon
index 35772217..b837da24 100644
--- a/components/vector_icons/file_download_chrome_refresh.icon
+++ b/components/vector_icons/file_download_chrome_refresh.icon
@@ -2,6 +2,31 @@
 // 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, 5.4f, 16.32f,
+R_CUBIC_TO, -0.48f, 0, -0.89f, -0.17f, -1.22f, -0.51f,
+R_ARC_TO, 1.67f, 1.67f, 0, 0, 1, -0.5f, -1.22f,
+R_V_LINE_TO, -1.8f,
+R_H_LINE_TO, 1.73f,
+R_V_LINE_TO, 1.81f,
+R_H_LINE_TO, 9.19f,
+R_V_LINE_TO, -1.8f,
+R_H_LINE_TO, 1.73f,
+R_V_LINE_TO, 1.81f,
+R_CUBIC_TO, 0, 0.48f, -0.17f, 0.89f, -0.51f, 1.22f,
+R_ARC_TO, 1.67f, 1.67f, 0, 0, 1, -1.22f, 0.51f,
+CLOSE,
+MOVE_TO, 10, 12.86f,
+LINE_TO, 5.76f, 8.62f,
+LINE_TO, 6.99f, 7.41f,
+R_LINE_TO, 2.15f, 2.15f,
+R_V_LINE_TO, -7.03f,
+R_H_LINE_TO, 1.73f,
+R_V_LINE_TO, 7.03f,
+R_LINE_TO, 2.15f, -2.15f,
+R_LINE_TO, 1.23f, 1.22f,
+CLOSE
+
 CANVAS_DIMENSIONS, 16,
 MOVE_TO, 4.32f, 13.06f,
 R_ARC_TO, 1.32f, 1.32f, 0, 0, 1, -0.98f, -0.4f,
diff --git a/components/vector_icons/font_download_chrome_refresh.icon b/components/vector_icons/font_download_chrome_refresh.icon
index 46bab383..ee40938 100644
--- a/components/vector_icons/font_download_chrome_refresh.icon
+++ b/components/vector_icons/font_download_chrome_refresh.icon
@@ -37,4 +37,41 @@
 CLOSE,
 R_MOVE_TO, 0, -15.86f,
 R_V_LINE_TO, 15.86f,
-CLOSE
\ No newline at end of file
+CLOSE
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 5.28f, 15,
+R_H_LINE_TO, 1.82f,
+LINE_TO, 8, 12.48f,
+R_H_LINE_TO, 4.01f,
+R_LINE_TO, 0.88f, 2.52f,
+R_H_LINE_TO, 1.82f,
+LINE_TO, 10.96f, 5,
+H_LINE_TO, 9.04f,
+CLOSE,
+R_MOVE_TO, 3.23f, -4.02f,
+R_LINE_TO, 1.45f, -4.12f,
+R_H_LINE_TO, 0.06f,
+R_LINE_TO, 1.44f, 4.12f,
+CLOSE,
+MOVE_TO, 3.56f, 18.17f,
+R_CUBIC_TO, -0.48f, 0, -0.89f, -0.17f, -1.22f, -0.5f,
+R_ARC_TO, 1.67f, 1.67f, 0, 0, 1, -0.5f, -1.22f,
+V_LINE_TO, 3.56f,
+R_CUBIC_TO, 0, -0.48f, 0.17f, -0.89f, 0.5f, -1.22f,
+R_ARC_TO, 1.67f, 1.67f, 0, 0, 1, 1.22f, -0.5f,
+H_LINE_TO, 16.44f,
+R_CUBIC_TO, 0.48f, 0, 0.89f, 0.17f, 1.22f, 0.5f,
+R_CUBIC_TO, 0.34f, 0.34f, 0.5f, 0.75f, 0.5f, 1.22f,
+V_LINE_TO, 16.44f,
+R_CUBIC_TO, 0, 0.48f, -0.17f, 0.89f, -0.5f, 1.22f,
+R_ARC_TO, 1.67f, 1.67f, 0, 0, 1, -1.22f, 0.5f,
+CLOSE,
+R_MOVE_TO, 0, -1.73f,
+H_LINE_TO, 16.44f,
+V_LINE_TO, 3.56f,
+H_LINE_TO, 3.56f,
+CLOSE,
+R_MOVE_TO, 0, -12.88f,
+V_LINE_TO, 16.44f,
+CLOSE
diff --git a/components/vector_icons/location_off_chrome_refresh.icon b/components/vector_icons/location_off_chrome_refresh.icon
index 25d60e8..f0b65d6e 100644
--- a/components/vector_icons/location_off_chrome_refresh.icon
+++ b/components/vector_icons/location_off_chrome_refresh.icon
@@ -2,6 +2,63 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+CANVAS_DIMENSIONS, 20,
+R_MOVE_TO, 14.22f, 11.97f,
+R_LINE_TO, -1.25f, -1.25f,
+R_CUBIC_TO, 0.3f, -0.48f, 0.54f, -1, 0.71f, -1.54f,
+R_ARC_TO, 5.55f, 5.55f, 0, 0, 0, 0.26f, -1.68f,
+R_CUBIC_TO, 0, -1.09f, -0.39f, -2.02f, -1.15f, -2.79f,
+ARC_TO, 3.81f, 3.81f, 0, 0, 0, 10, 3.56f,
+R_ARC_TO, 3.75f, 3.75f, 0, 0, 0, -1.59f, 0.35f,
+R_CUBIC_TO, -0.5f, 0.23f, -0.93f, 0.55f, -1.32f, 0.96f,
+LINE_TO, 5.88f, 3.64f,
+ARC_TO, 5.82f, 5.82f, 0, 0, 1, 7.76f, 2.3f,
+ARC_TO, 5.48f, 5.48f, 0, 0, 1, 10, 1.83f,
+R_CUBIC_TO, 1.58f, 0, 2.92f, 0.55f, 4.02f, 1.65f,
+R_CUBIC_TO, 1.1f, 1.1f, 1.65f, 2.44f, 1.65f, 4.02f,
+R_CUBIC_TO, 0, 0.81f, -0.12f, 1.59f, -0.38f, 2.34f,
+R_CUBIC_TO, -0.25f, 0.75f, -0.61f, 1.46f, -1.06f, 2.14f,
+CLOSE,
+MOVE_TO, 11.44f, 9.19f,
+R_CUBIC_TO, 0.17f, -0.19f, 0.31f, -0.41f, 0.41f, -0.64f,
+R_CUBIC_TO, 0.1f, -0.24f, 0.15f, -0.49f, 0.15f, -0.75f,
+R_ARC_TO, 1.93f, 1.93f, 0, 0, 0, -0.58f, -1.42f,
+ARC_TO, 1.94f, 1.94f, 0, 0, 0, 10, 5.79f,
+R_CUBIC_TO, -0.26f, 0, -0.52f, 0.04f, -0.76f, 0.13f,
+R_CUBIC_TO, -0.25f, 0.09f, -0.46f, 0.23f, -0.64f, 0.44f,
+CLOSE,
+R_MOVE_TO, 4.62f, 9.09f,
+R_LINE_TO, -3.66f, -3.68f,
+R_ARC_TO, 72.08f, 72.08f, 0, 0, 0, -0.67f, 1.13f,
+R_CUBIC_TO, -0.22f, 0.39f, -0.43f, 0.79f, -0.62f, 1.2f,
+R_CUBIC_TO, -0.12f, 0.3f, -0.26f, 0.58f, -0.41f, 0.85f,
+R_ARC_TO, 0.75f, 0.75f, 0, 0, 1, -0.68f, 0.4f,
+R_ARC_TO, 0.74f, 0.74f, 0, 0, 1, -0.68f, -0.39f,
+R_ARC_TO, 6.86f, 6.86f, 0, 0, 1, -0.42f, -0.85f,
+R_CUBIC_TO, -0.34f, -0.75f, -0.74f, -1.43f, -1.19f, -2.06f,
+R_CUBIC_TO, -0.46f, -0.62f, -0.93f, -1.25f, -1.4f, -1.9f,
+R_ARC_TO, 14.93f, 14.93f, 0, 0, 1, -1.41f, -2.6f,
+R_ARC_TO, 7.39f, 7.39f, 0, 0, 1, -0.57f, -2.86f,
+R_CUBIC_TO, 0, -0.15f, 0, -0.3f, 0.01f, -0.44f,
+R_CUBIC_TO, 0.01f, -0.14f, 0.03f, -0.28f, 0.06f, -0.42f,
+LINE_TO, 1.72f, 3.93f,
+R_LINE_TO, 1.12f, -1.11f,
+R_LINE_TO, 14.34f, 14.36f,
+CLOSE,
+MOVE_TO, 10, 15.24f,
+R_CUBIC_TO, 0.16f, -0.33f, 0.34f, -0.65f, 0.55f, -0.95f,
+R_CUBIC_TO, 0.21f, -0.3f, 0.41f, -0.6f, 0.62f, -0.91f,
+LINE_TO, 6.18f, 8.39f,
+R_CUBIC_TO, 0.09f, 0.72f, 0.32f, 1.39f, 0.7f, 2.02f,
+R_CUBIC_TO, 0.37f, 0.62f, 0.76f, 1.23f, 1.17f, 1.82f,
+R_CUBIC_TO, 0.37f, 0.49f, 0.72f, 0.97f, 1.05f, 1.46f,
+R_CUBIC_TO, 0.33f, 0.49f, 0.64f, 1, 0.91f, 1.55f,
+CLOSE,
+R_MOVE_TO, -1.32f, -4.11f,
+CLOSE,
+R_MOVE_TO, 1.4f, -3.27f,
+CLOSE
+
 CANVAS_DIMENSIONS, 16,
 MOVE_TO, 8, 2.5f,
 R_CUBIC_TO, 1.93f, 0, 3.5f, 1.57f, 3.5f, 3.5f,
diff --git a/components/vector_icons/location_on_chrome_refresh.icon b/components/vector_icons/location_on_chrome_refresh.icon
index aa2bd3b2..94f8c58 100644
--- a/components/vector_icons/location_on_chrome_refresh.icon
+++ b/components/vector_icons/location_on_chrome_refresh.icon
@@ -2,6 +2,50 @@
 // 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, 10.01f, 18.15f,
+R_CUBIC_TO, -0.22f, 0, -0.41f, -0.06f, -0.57f, -0.18f,
+R_CUBIC_TO, -0.16f, -0.12f, -0.28f, -0.29f, -0.36f, -0.49f,
+R_CUBIC_TO, -0.32f, -0.8f, -0.65f, -1.52f, -1.01f, -2.15f,
+R_CUBIC_TO, -0.36f, -0.64f, -0.86f, -1.37f, -1.5f, -2.2f,
+R_CUBIC_TO, -0.69f, -0.88f, -1.25f, -1.74f, -1.68f, -2.56f,
+R_CUBIC_TO, -0.43f, -0.82f, -0.65f, -1.81f, -0.65f, -2.97f,
+R_CUBIC_TO, 0, -1.6f, 0.56f, -2.96f, 1.68f, -4.08f,
+CUBIC_TO, 7.04f, 2.4f, 8.4f, 1.84f, 10.01f, 1.84f,
+R_CUBIC_TO, 1.61f, 0, 2.97f, 0.56f, 4.09f, 1.68f,
+R_CUBIC_TO, 1.12f, 1.12f, 1.68f, 2.49f, 1.68f, 4.1f,
+R_CUBIC_TO, 0, 1.24f, -0.24f, 2.27f, -0.71f, 3.09f,
+R_CUBIC_TO, -0.47f, 0.82f, -1.01f, 1.62f, -1.62f, 2.43f,
+R_CUBIC_TO, -0.67f, 0.86f, -1.18f, 1.61f, -1.54f, 2.24f,
+R_CUBIC_TO, -0.36f, 0.63f, -0.68f, 1.33f, -0.97f, 2.11f,
+R_CUBIC_TO, -0.09f, 0.2f, -0.21f, 0.37f, -0.37f, 0.49f,
+R_CUBIC_TO, -0.16f, 0.12f, -0.34f, 0.19f, -0.55f, 0.19f,
+CLOSE,
+R_MOVE_TO, 0, -2.89f,
+R_CUBIC_TO, 0.23f, -0.47f, 0.5f, -0.94f, 0.79f, -1.4f,
+R_CUBIC_TO, 0.3f, -0.46f, 0.72f, -1.06f, 1.28f, -1.8f,
+R_CUBIC_TO, 0.58f, -0.74f, 1.05f, -1.43f, 1.42f, -2.07f,
+R_CUBIC_TO, 0.37f, -0.64f, 0.55f, -1.43f, 0.55f, -2.39f,
+R_CUBIC_TO, 0, -1.11f, -0.4f, -2.06f, -1.19f, -2.85f,
+R_CUBIC_TO, -0.79f, -0.79f, -1.75f, -1.19f, -2.86f, -1.19f,
+R_CUBIC_TO, -1.11f, 0, -2.07f, 0.4f, -2.85f, 1.19f,
+R_CUBIC_TO, -0.79f, 0.79f, -1.18f, 1.75f, -1.18f, 2.85f,
+R_CUBIC_TO, 0, 0.95f, 0.19f, 1.75f, 0.56f, 2.39f,
+R_CUBIC_TO, 0.37f, 0.64f, 0.84f, 1.33f, 1.41f, 2.07f,
+R_CUBIC_TO, 0.56f, 0.74f, 0.99f, 1.34f, 1.28f, 1.8f,
+R_CUBIC_TO, 0.29f, 0.46f, 0.56f, 0.93f, 0.79f, 1.4f,
+CLOSE,
+R_MOVE_TO, 0, -5.64f,
+R_CUBIC_TO, 0.56f, 0, 1.04f, -0.19f, 1.43f, -0.58f,
+R_CUBIC_TO, 0.39f, -0.39f, 0.59f, -0.86f, 0.59f, -1.43f,
+R_CUBIC_TO, 0, -0.57f, -0.19f, -1.04f, -0.58f, -1.43f,
+R_CUBIC_TO, -0.39f, -0.39f, -0.86f, -0.59f, -1.43f, -0.59f,
+R_CUBIC_TO, -0.57f, 0, -1.04f, 0.19f, -1.43f, 0.58f,
+CUBIC_TO, 8.2f, 6.56f, 8, 7.03f, 8, 7.6f,
+R_CUBIC_TO, 0, 0.57f, 0.19f, 1.04f, 0.58f, 1.43f,
+R_CUBIC_TO, 0.39f, 0.39f, 0.86f, 0.59f, 1.43f, 0.59f,
+CLOSE
+
 CANVAS_DIMENSIONS, 16,
 MOVE_TO, 8, 2.5f,
 R_CUBIC_TO, 1.93f, 0, 3.5f, 1.57f, 3.5f, 3.5f,
diff --git a/components/vector_icons/mic_chrome_refresh.icon b/components/vector_icons/mic_chrome_refresh.icon
index 8c95784..3c61761 100644
--- a/components/vector_icons/mic_chrome_refresh.icon
+++ b/components/vector_icons/mic_chrome_refresh.icon
@@ -40,6 +40,48 @@
 ARC_TO, 0.94f, 0.94f, 0, 0, 0, 12, 12,
 CLOSE
 
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 10, 12.23f,
+R_ARC_TO, 2.6f, 2.6f, 0, 0, 1, -1.91f, -0.78f,
+R_ARC_TO, 2.59f, 2.59f, 0, 0, 1, -0.78f, -1.91f,
+V_LINE_TO, 4.57f,
+R_CUBIC_TO, 0, -0.75f, 0.26f, -1.38f, 0.78f, -1.91f,
+ARC_TO, 2.61f, 2.61f, 0, 0, 1, 10, 1.89f,
+R_ARC_TO, 2.61f, 2.61f, 0, 0, 1, 1.91f, 0.78f,
+R_CUBIC_TO, 0.52f, 0.52f, 0.78f, 1.16f, 0.78f, 1.91f,
+V_LINE_TO, 9.54f,
+R_CUBIC_TO, 0, 0.75f, -0.26f, 1.38f, -0.78f, 1.91f,
+ARC_TO, 2.6f, 2.6f, 0, 0, 1, 10, 12.23f,
+CLOSE,
+R_MOVE_TO, 0, -5.17f,
+CLOSE,
+R_MOVE_TO, -0.82f, 10.25f,
+R_V_LINE_TO, -2.08f,
+R_CUBIC_TO, -1.43f, -0.19f, -2.61f, -0.82f, -3.54f, -1.89f,
+R_CUBIC_TO, -0.93f, -1.07f, -1.39f, -2.34f, -1.39f, -3.79f,
+R_H_LINE_TO, 1.65f,
+R_CUBIC_TO, 0, 1.14f, 0.4f, 2.11f, 1.2f, 2.91f,
+R_CUBIC_TO, 0.8f, 0.8f, 1.77f, 1.2f, 2.91f, 1.2f,
+R_CUBIC_TO, 1.14f, 0, 2.11f, -0.4f, 2.9f, -1.2f,
+R_CUBIC_TO, 0.8f, -0.8f, 1.2f, -1.77f, 1.2f, -2.91f,
+R_H_LINE_TO, 1.65f,
+R_CUBIC_TO, 0, 1.45f, -0.46f, 2.72f, -1.39f, 3.79f,
+R_CUBIC_TO, -0.93f, 1.07f, -2.11f, 1.7f, -3.54f, 1.89f,
+R_V_LINE_TO, 2.08f,
+CLOSE,
+MOVE_TO, 10, 10.5f,
+R_CUBIC_TO, 0.27f, 0, 0.5f, -0.09f, 0.68f, -0.28f,
+R_ARC_TO, 0.93f, 0.93f, 0, 0, 0, 0.28f, -0.68f,
+V_LINE_TO, 4.57f,
+R_CUBIC_TO, 0, -0.27f, -0.09f, -0.5f, -0.28f, -0.68f,
+ARC_TO, 0.93f, 0.93f, 0, 0, 0, 10, 3.61f,
+R_CUBIC_TO, -0.27f, 0, -0.5f, 0.09f, -0.68f, 0.28f,
+R_ARC_TO, 0.93f, 0.93f, 0, 0, 0, -0.28f, 0.68f,
+V_LINE_TO, 9.54f,
+R_CUBIC_TO, 0, 0.27f, 0.09f, 0.5f, 0.28f, 0.68f,
+R_CUBIC_TO, 0.18f, 0.18f, 0.41f, 0.28f, 0.68f, 0.28f,
+CLOSE
+
 CANVAS_DIMENSIONS, 16,
 MOVE_TO, 8, 9.79f,
 R_CUBIC_TO, -0.6f, 0, -1.1f, -0.21f, -1.52f, -0.63f,
diff --git a/components/vector_icons/mic_off_chrome_refresh.icon b/components/vector_icons/mic_off_chrome_refresh.icon
index 8645d1e..aca30b9 100644
--- a/components/vector_icons/mic_off_chrome_refresh.icon
+++ b/components/vector_icons/mic_off_chrome_refresh.icon
@@ -50,6 +50,55 @@
 LINE_TO, 21.23f, 21.09f,
 CLOSE
 
+CANVAS_DIMENSIONS, 20,
+R_MOVE_TO, 14.91f, 12.56f,
+R_LINE_TO, -1.23f, -1.22f,
+R_CUBIC_TO, 0.14f, -0.28f, 0.25f, -0.56f, 0.32f, -0.85f,
+R_CUBIC_TO, 0.08f, -0.29f, 0.12f, -0.61f, 0.12f, -0.94f,
+R_H_LINE_TO, 1.66f,
+R_CUBIC_TO, 0, 0.53f, -0.07f, 1.05f, -0.22f, 1.57f,
+R_CUBIC_TO, -0.15f, 0.52f, -0.37f, 1, -0.65f, 1.45f,
+CLOSE,
+MOVE_TO, 9.96f, 7.66f,
+CLOSE,
+R_MOVE_TO, 2.65f, 2.61f,
+R_LINE_TO, -1.62f, -1.62f,
+V_LINE_TO, 4.57f,
+R_CUBIC_TO, 0, -0.27f, -0.09f, -0.5f, -0.28f, -0.68f,
+R_ARC_TO, 0.94f, 0.94f, 0, 0, 0, -0.69f, -0.28f,
+R_CUBIC_TO, -0.27f, 0, -0.5f, 0.09f, -0.68f, 0.28f,
+R_ARC_TO, 0.94f, 0.94f, 0, 0, 0, -0.27f, 0.68f,
+R_V_LINE_TO, 2.14f,
+LINE_TO, 7.38f, 5.03f,
+R_V_LINE_TO, -0.69f,
+R_CUBIC_TO, 0.04f, -0.68f, 0.32f, -1.25f, 0.82f, -1.73f,
+R_ARC_TO, 2.57f, 2.57f, 0, 0, 1, 1.82f, -0.71f,
+R_CUBIC_TO, 0.75f, 0, 1.39f, 0.26f, 1.91f, 0.78f,
+R_CUBIC_TO, 0.52f, 0.52f, 0.79f, 1.16f, 0.79f, 1.91f,
+V_LINE_TO, 9.54f,
+R_CUBIC_TO, 0, 0.12f, -0.01f, 0.24f, -0.03f, 0.37f,
+R_ARC_TO, 2.05f, 2.05f, 0, 0, 1, -0.08f, 0.36f,
+CLOSE,
+MOVE_TO, 9.2f, 17.31f,
+R_V_LINE_TO, -2.08f,
+R_CUBIC_TO, -1.43f, -0.18f, -2.61f, -0.8f, -3.54f, -1.88f,
+R_CUBIC_TO, -0.93f, -1.08f, -1.39f, -2.35f, -1.39f, -3.8f,
+R_H_LINE_TO, 1.66f,
+R_CUBIC_TO, 0, 1.14f, 0.4f, 2.11f, 1.2f, 2.91f,
+R_CUBIC_TO, 0.8f, 0.8f, 1.77f, 1.2f, 2.9f, 1.2f,
+R_CUBIC_TO, 0.5f, 0, 0.98f, -0.1f, 1.43f, -0.3f,
+R_CUBIC_TO, 0.45f, -0.2f, 0.86f, -0.46f, 1.24f, -0.79f,
+R_LINE_TO, 1.2f, 1.2f,
+R_ARC_TO, 6.5f, 6.5f, 0, 0, 1, -1.41f, 0.96f,
+R_ARC_TO, 5.09f, 5.09f, 0, 0, 1, -1.62f, 0.51f,
+R_V_LINE_TO, 2.08f,
+CLOSE,
+R_MOVE_TO, 6.78f, 0.78f,
+LINE_TO, 1.85f, 3.94f,
+LINE_TO, 2.96f, 2.83f,
+R_LINE_TO, 14.13f, 14.15f,
+CLOSE
+
 CANVAS_DIMENSIONS, 16,
 R_MOVE_TO, 11.93f, 10.04f,
 R_LINE_TO, -0.98f, -0.98f,
diff --git a/components/vector_icons/midi_chrome_refresh.icon b/components/vector_icons/midi_chrome_refresh.icon
new file mode 100644
index 0000000..9b51ff25
--- /dev/null
+++ b/components/vector_icons/midi_chrome_refresh.icon
@@ -0,0 +1,92 @@
+// 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, 24,
+MOVE_TO, 5.07f, 21.2f,
+R_ARC_TO, 2.2f, 2.2f, 0, 0, 1, -1.61f, -0.66f,
+R_ARC_TO, 2.2f, 2.2f, 0, 0, 1, -0.66f, -1.61f,
+V_LINE_TO, 5.07f,
+R_CUBIC_TO, 0, -0.63f, 0.22f, -1.16f, 0.66f, -1.61f,
+R_CUBIC_TO, 0.45f, -0.44f, 0.98f, -0.66f, 1.61f, -0.66f,
+H_LINE_TO, 18.93f,
+R_CUBIC_TO, 0.63f, 0, 1.16f, 0.22f, 1.61f, 0.66f,
+R_CUBIC_TO, 0.44f, 0.45f, 0.66f, 0.98f, 0.66f, 1.61f,
+V_LINE_TO, 18.93f,
+R_CUBIC_TO, 0, 0.63f, -0.22f, 1.16f, -0.66f, 1.61f,
+R_CUBIC_TO, -0.44f, 0.44f, -0.98f, 0.66f, -1.61f, 0.66f,
+CLOSE,
+R_MOVE_TO, 0, -2.27f,
+R_H_LINE_TO, 3.09f,
+R_V_LINE_TO, -4.38f,
+R_H_LINE_TO, -0.2f,
+R_CUBIC_TO, -0.3f, 0, -0.55f, -0.1f, -0.75f, -0.3f,
+R_CUBIC_TO, -0.2f, -0.2f, -0.3f, -0.45f, -0.3f, -0.75f,
+V_LINE_TO, 5.07f,
+H_LINE_TO, 5.07f,
+CLOSE,
+R_MOVE_TO, 10.77f, 0,
+R_H_LINE_TO, 3.09f,
+V_LINE_TO, 5.07f,
+R_H_LINE_TO, -1.84f,
+R_V_LINE_TO, 8.43f,
+R_CUBIC_TO, 0, 0.3f, -0.1f, 0.55f, -0.3f, 0.75f,
+R_CUBIC_TO, -0.2f, 0.2f, -0.45f, 0.3f, -0.75f, 0.3f,
+R_H_LINE_TO, -0.2f,
+CLOSE,
+R_MOVE_TO, -6, 0,
+R_H_LINE_TO, 4.32f,
+R_V_LINE_TO, -4.38f,
+R_H_LINE_TO, -0.2f,
+R_CUBIC_TO, -0.3f, 0, -0.54f, -0.1f, -0.75f, -0.3f,
+R_CUBIC_TO, -0.2f, -0.2f, -0.3f, -0.45f, -0.3f, -0.75f,
+V_LINE_TO, 5.07f,
+H_LINE_TO, 11.09f,
+R_V_LINE_TO, 8.44f,
+R_ARC_TO, 1.02f, 1.02f, 0, 0, 1, -1.05f, 1.04f,
+H_LINE_TO, 9.84f,
+CLOSE
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 4.56f, 17.17f,
+R_CUBIC_TO, -0.47f, 0, -0.87f, -0.17f, -1.22f, -0.51f,
+R_ARC_TO, 1.65f, 1.65f, 0, 0, 1, -0.51f, -1.22f,
+V_LINE_TO, 4.56f,
+R_CUBIC_TO, 0, -0.48f, 0.17f, -0.89f, 0.51f, -1.22f,
+R_ARC_TO, 1.67f, 1.67f, 0, 0, 1, 1.22f, -0.5f,
+H_LINE_TO, 15.44f,
+R_CUBIC_TO, 0.48f, 0, 0.89f, 0.17f, 1.22f, 0.5f,
+R_CUBIC_TO, 0.34f, 0.34f, 0.5f, 0.75f, 0.5f, 1.22f,
+V_LINE_TO, 15.44f,
+R_CUBIC_TO, 0, 0.47f, -0.17f, 0.88f, -0.5f, 1.22f,
+R_ARC_TO, 1.65f, 1.65f, 0, 0, 1, -1.22f, 0.51f,
+CLOSE,
+R_MOVE_TO, 0, -1.73f,
+R_H_LINE_TO, 2.36f,
+V_LINE_TO, 12.04f,
+H_LINE_TO, 6.46f,
+R_ARC_TO, 0.52f, 0.52f, 0, 0, 1, -0.54f, -0.54f,
+V_LINE_TO, 4.56f,
+H_LINE_TO, 4.56f,
+CLOSE,
+R_MOVE_TO, 8.52f, 0,
+R_H_LINE_TO, 2.36f,
+V_LINE_TO, 4.56f,
+R_H_LINE_TO, -1.36f,
+V_LINE_TO, 11.5f,
+R_ARC_TO, 0.52f, 0.52f, 0, 0, 1, -0.54f, 0.54f,
+R_H_LINE_TO, -0.46f,
+CLOSE,
+R_MOVE_TO, -5, 0,
+R_H_LINE_TO, 3.85f,
+V_LINE_TO, 12.04f,
+R_H_LINE_TO, -0.46f,
+R_ARC_TO, 0.51f, 0.51f, 0, 0, 1, -0.38f, -0.16f,
+R_ARC_TO, 0.51f, 0.51f, 0, 0, 1, -0.16f, -0.38f,
+V_LINE_TO, 4.56f,
+H_LINE_TO, 9.07f,
+R_V_LINE_TO, 6.95f,
+R_ARC_TO, 0.51f, 0.51f, 0, 0, 1, -0.16f, 0.38f,
+R_ARC_TO, 0.52f, 0.52f, 0, 0, 1, -0.38f, 0.15f,
+R_H_LINE_TO, -0.46f,
+CLOSE
diff --git a/components/vector_icons/midi_off_chrome_refresh.icon b/components/vector_icons/midi_off_chrome_refresh.icon
new file mode 100644
index 0000000..d84adec
--- /dev/null
+++ b/components/vector_icons/midi_off_chrome_refresh.icon
@@ -0,0 +1,105 @@
+// 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, 24,
+R_MOVE_TO, 20, 22.88f,
+R_LINE_TO, -1.69f, -1.68f,
+R_CUBIC_TO, -0.01f, 0, -0.03f, 0, -0.04f, 0,
+H_LINE_TO, 5.07f,
+R_ARC_TO, 2.2f, 2.2f, 0, 0, 1, -1.61f, -0.66f,
+R_ARC_TO, 2.2f, 2.2f, 0, 0, 1, -0.66f, -1.61f,
+V_LINE_TO, 5.72f,
+R_CUBIC_TO, 0, -0.01f, 0, -0.02f, 0, -0.04f,
+LINE_TO, 1.13f, 4,
+R_LINE_TO, 1.48f, -1.48f,
+LINE_TO, 21.49f, 21.39f,
+CLOSE,
+R_MOVE_TO, 1.2f, -4.74f,
+R_LINE_TO, -2.27f, -2.27f,
+V_LINE_TO, 5.07f,
+R_H_LINE_TO, -1.84f,
+R_V_LINE_TO, 8.44f,
+R_ARC_TO, 0.71f, 0.71f, 0, 0, 1, -0.12f, 0.4f,
+LINE_TO, 12.91f, 9.85f,
+V_LINE_TO, 5.07f,
+R_H_LINE_TO, -1.82f,
+R_V_LINE_TO, 2.95f,
+LINE_TO, 5.86f, 2.8f,
+H_LINE_TO, 18.93f,
+R_CUBIC_TO, 0.63f, 0, 1.16f, 0.22f, 1.61f, 0.66f,
+R_CUBIC_TO, 0.44f, 0.45f, 0.66f, 0.98f, 0.66f, 1.61f,
+CLOSE,
+MOVE_TO, 5.07f, 18.93f,
+R_H_LINE_TO, 3.09f,
+R_V_LINE_TO, -4.38f,
+R_H_LINE_TO, -0.2f,
+R_CUBIC_TO, -0.3f, 0, -0.54f, -0.1f, -0.75f, -0.3f,
+R_CUBIC_TO, -0.2f, -0.2f, -0.3f, -0.45f, -0.3f, -0.75f,
+V_LINE_TO, 9.79f,
+LINE_TO, 5.07f, 7.95f,
+CLOSE,
+R_MOVE_TO, 4.77f, 0,
+R_H_LINE_TO, 4.32f,
+R_V_LINE_TO, -1.89f,
+R_LINE_TO, -3.16f, -3.16f,
+R_ARC_TO, 1.05f, 1.05f, 0, 0, 1, -0.36f, 0.48f,
+R_ARC_TO, 0.97f, 0.97f, 0, 0, 1, -0.59f, 0.19f,
+H_LINE_TO, 9.84f,
+CLOSE,
+R_MOVE_TO, 5.88f, 0,
+R_H_LINE_TO, 0.32f,
+R_LINE_TO, -0.32f, -0.33f,
+CLOSE
+
+CANVAS_DIMENSIONS, 20,
+R_MOVE_TO, 16.19f, 18.34f,
+R_LINE_TO, -1.17f, -1.17f,
+R_CUBIC_TO, -0.02f, 0, -0.03f, 0, -0.04f, 0,
+H_LINE_TO, 4.56f,
+R_CUBIC_TO, -0.48f, 0, -0.89f, -0.17f, -1.22f, -0.5f,
+R_ARC_TO, 1.67f, 1.67f, 0, 0, 1, -0.5f, -1.22f,
+V_LINE_TO, 5.02f,
+R_CUBIC_TO, 0, -0.01f, 0, -0.02f, 0, -0.04f,
+LINE_TO, 1.66f, 3.81f,
+R_LINE_TO, 1.11f, -1.11f,
+R_LINE_TO, 14.52f, 14.52f,
+CLOSE,
+R_MOVE_TO, 0.98f, -3.47f,
+R_LINE_TO, -1.73f, -1.73f,
+V_LINE_TO, 4.56f,
+R_H_LINE_TO, -1.36f,
+R_V_LINE_TO, 6.95f,
+R_CUBIC_TO, 0, 0.03f, -0.01f, 0.07f, -0.02f, 0.11f,
+R_CUBIC_TO, -0.02f, 0.04f, -0.03f, 0.07f, -0.05f, 0.08f,
+R_LINE_TO, -3.07f, -3.07f,
+V_LINE_TO, 4.56f,
+H_LINE_TO, 9.07f,
+R_V_LINE_TO, 2.21f,
+LINE_TO, 5.14f, 2.83f,
+H_LINE_TO, 15.44f,
+R_CUBIC_TO, 0.48f, 0, 0.89f, 0.17f, 1.22f, 0.5f,
+R_CUBIC_TO, 0.34f, 0.34f, 0.5f, 0.75f, 0.5f, 1.22f,
+CLOSE,
+R_MOVE_TO, -12.61f, 0.58f,
+R_H_LINE_TO, 2.36f,
+V_LINE_TO, 12.04f,
+H_LINE_TO, 6.46f,
+R_ARC_TO, 0.51f, 0.51f, 0, 0, 1, -0.38f, -0.16f,
+R_ARC_TO, 0.51f, 0.51f, 0, 0, 1, -0.16f, -0.38f,
+V_LINE_TO, 8.07f,
+LINE_TO, 4.56f, 6.71f,
+CLOSE,
+R_MOVE_TO, 3.52f, 0,
+R_H_LINE_TO, 3.85f,
+R_V_LINE_TO, -1.37f,
+R_LINE_TO, -2.89f, -2.88f,
+R_V_LINE_TO, 0.38f,
+R_ARC_TO, 0.45f, 0.45f, 0, 0, 1, -0.16f, 0.34f,
+R_ARC_TO, 0.48f, 0.48f, 0, 0, 1, -0.34f, 0.14f,
+R_H_LINE_TO, -0.46f,
+CLOSE,
+R_MOVE_TO, 4.9f, -0.04f,
+R_H_LINE_TO, 0.12f,
+R_LINE_TO, -0.12f, -0.13f,
+CLOSE
diff --git a/components/vector_icons/notifications_chrome_refresh.icon b/components/vector_icons/notifications_chrome_refresh.icon
index 6f6f4351..02f0a93 100644
--- a/components/vector_icons/notifications_chrome_refresh.icon
+++ b/components/vector_icons/notifications_chrome_refresh.icon
@@ -2,6 +2,43 @@
 // 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, 3.72f, 15.65f,
+R_V_LINE_TO, -1.73f,
+H_LINE_TO, 4.77f,
+V_LINE_TO, 9.1f,
+R_CUBIC_TO, 0, -1.24f, 0.38f, -2.34f, 1.14f, -3.3f,
+ARC_TO, 4.8f, 4.8f, 0, 0, 1, 8.89f, 4,
+V_LINE_TO, 2.93f,
+R_CUBIC_TO, 0, -0.31f, 0.11f, -0.57f, 0.32f, -0.79f,
+R_CUBIC_TO, 0.22f, -0.22f, 0.48f, -0.32f, 0.79f, -0.32f,
+R_CUBIC_TO, 0.31f, 0, 0.57f, 0.11f, 0.79f, 0.33f,
+R_CUBIC_TO, 0.22f, 0.22f, 0.32f, 0.48f, 0.32f, 0.79f,
+V_LINE_TO, 4,
+R_CUBIC_TO, 1.23f, 0.23f, 2.22f, 0.82f, 2.98f, 1.78f,
+R_CUBIC_TO, 0.76f, 0.96f, 1.14f, 2.06f, 1.14f, 3.32f,
+R_V_LINE_TO, 4.81f,
+R_H_LINE_TO, 1.06f,
+R_V_LINE_TO, 1.73f,
+CLOSE,
+MOVE_TO, 10, 9.64f,
+CLOSE,
+R_MOVE_TO, 0, 8.53f,
+R_CUBIC_TO, -0.43f, 0, -0.8f, -0.15f, -1.1f, -0.46f,
+R_ARC_TO, 1.5f, 1.5f, 0, 0, 1, -0.45f, -1.1f,
+R_H_LINE_TO, 3.11f,
+R_CUBIC_TO, 0, 0.43f, -0.15f, 0.8f, -0.46f, 1.11f,
+R_CUBIC_TO, -0.3f, 0.3f, -0.67f, 0.45f, -1.1f, 0.45f,
+CLOSE,
+R_MOVE_TO, -3.5f, -4.25f,
+R_H_LINE_TO, 7,
+V_LINE_TO, 9.1f,
+R_CUBIC_TO, 0, -0.97f, -0.34f, -1.8f, -1.02f, -2.48f,
+R_CUBIC_TO, -0.68f, -0.68f, -1.51f, -1.02f, -2.48f, -1.02f,
+R_CUBIC_TO, -0.97f, 0, -1.8f, 0.34f, -2.48f, 1.02f,
+R_CUBIC_TO, -0.68f, 0.68f, -1.02f, 1.51f, -1.02f, 2.48f,
+CLOSE
+
 CANVAS_DIMENSIONS, 16,
 MOVE_TO, 12, 11,
 V_LINE_TO, 7,
diff --git a/components/vector_icons/notifications_off_chrome_refresh.icon b/components/vector_icons/notifications_off_chrome_refresh.icon
index f73cac8..9e9eaff 100644
--- a/components/vector_icons/notifications_off_chrome_refresh.icon
+++ b/components/vector_icons/notifications_off_chrome_refresh.icon
@@ -2,6 +2,55 @@
 // 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, 3.72f, 15.65f,
+R_V_LINE_TO, -1.73f,
+H_LINE_TO, 4.77f,
+V_LINE_TO, 9.1f,
+R_CUBIC_TO, 0, -0.6f, 0.09f, -1.18f, 0.25f, -1.74f,
+ARC_TO, 5.07f, 5.07f, 0, 0, 1, 5.81f, 5.81f,
+R_LINE_TO, 1.27f, 1.27f,
+R_ARC_TO, 2.79f, 2.79f, 0, 0, 0, -0.44f, 0.95f,
+R_ARC_TO, 4.3f, 4.3f, 0, 0, 0, -0.14f, 1.07f,
+R_V_LINE_TO, 4.81f,
+R_H_LINE_TO, 5.19f,
+R_LINE_TO, -9.94f, -9.96f,
+R_LINE_TO, 1.12f, -1.11f,
+R_LINE_TO, 14.36f, 14.38f,
+R_LINE_TO, -1.12f, 1.12f,
+R_LINE_TO, -2.69f, -2.69f,
+CLOSE,
+MOVE_TO, 15.23f, 13,
+R_LINE_TO, -1.73f, -1.73f,
+V_LINE_TO, 9.1f,
+R_CUBIC_TO, 0, -0.97f, -0.34f, -1.8f, -1.02f, -2.48f,
+R_CUBIC_TO, -0.68f, -0.68f, -1.51f, -1.02f, -2.48f, -1.02f,
+R_CUBIC_TO, -0.29f, 0, -0.59f, 0.03f, -0.88f, 0.1f,
+R_CUBIC_TO, -0.29f, 0.07f, -0.57f, 0.19f, -0.82f, 0.36f,
+R_LINE_TO, -1.27f, -1.26f,
+R_CUBIC_TO, 0.27f, -0.21f, 0.57f, -0.38f, 0.88f, -0.51f,
+R_CUBIC_TO, 0.32f, -0.12f, 0.64f, -0.22f, 0.98f, -0.29f,
+V_LINE_TO, 2.93f,
+R_CUBIC_TO, 0, -0.31f, 0.11f, -0.57f, 0.32f, -0.79f,
+R_CUBIC_TO, 0.22f, -0.22f, 0.48f, -0.32f, 0.79f, -0.32f,
+R_CUBIC_TO, 0.31f, 0, 0.57f, 0.11f, 0.79f, 0.33f,
+R_CUBIC_TO, 0.22f, 0.22f, 0.32f, 0.48f, 0.32f, 0.79f,
+V_LINE_TO, 4,
+R_CUBIC_TO, 1.21f, 0.22f, 2.19f, 0.82f, 2.96f, 1.79f,
+R_ARC_TO, 5.19f, 5.19f, 0, 0, 1, 1.16f, 3.31f,
+CLOSE,
+R_MOVE_TO, -6.09f, -1.66f,
+CLOSE,
+R_MOVE_TO, 0.86f, 6.82f,
+R_CUBIC_TO, -0.43f, 0, -0.8f, -0.15f, -1.1f, -0.46f,
+R_ARC_TO, 1.5f, 1.5f, 0, 0, 1, -0.45f, -1.1f,
+R_H_LINE_TO, 3.11f,
+R_CUBIC_TO, 0, 0.43f, -0.15f, 0.8f, -0.46f, 1.11f,
+R_CUBIC_TO, -0.3f, 0.3f, -0.67f, 0.45f, -1.1f, 0.45f,
+CLOSE,
+R_MOVE_TO, 0.67f, -9.73f,
+CLOSE
+
 CANVAS_DIMENSIONS, 16,
 MOVE_TO, 3.01f, 12.58f,
 R_V_LINE_TO, -1.37f,
diff --git a/components/vector_icons/select_window_chrome_refresh.icon b/components/vector_icons/select_window_chrome_refresh.icon
index b8840d3..9eecaabd 100644
--- a/components/vector_icons/select_window_chrome_refresh.icon
+++ b/components/vector_icons/select_window_chrome_refresh.icon
@@ -37,4 +37,41 @@
 H_LINE_TO, 16,
 R_CUBIC_TO, 0.6f, 0, 1.12f, 0.21f, 1.54f, 0.64f,
 R_CUBIC_TO, 0.43f, 0.43f, 0.64f, 0.94f, 0.64f, 1.54f,
-CLOSE
\ No newline at end of file
+CLOSE
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 3.5f, 18.16f,
+R_CUBIC_TO, -0.48f, 0, -0.89f, -0.17f, -1.22f, -0.51f,
+R_ARC_TO, 1.66f, 1.66f, 0, 0, 1, -0.51f, -1.22f,
+V_LINE_TO, 9.57f,
+R_CUBIC_TO, 0, -0.48f, 0.17f, -0.89f, 0.51f, -1.22f,
+ARC_TO, 1.67f, 1.67f, 0, 0, 1, 3.5f, 7.84f,
+R_H_LINE_TO, 1.34f,
+R_V_LINE_TO, -4.27f,
+R_CUBIC_TO, 0, -0.48f, 0.17f, -0.89f, 0.51f, -1.22f,
+R_ARC_TO, 1.67f, 1.67f, 0, 0, 1, 1.22f, -0.51f,
+H_LINE_TO, 16.5f,
+R_CUBIC_TO, 0.48f, 0, 0.89f, 0.17f, 1.22f, 0.51f,
+R_CUBIC_TO, 0.34f, 0.34f, 0.51f, 0.75f, 0.51f, 1.22f,
+R_V_LINE_TO, 6.85f,
+R_CUBIC_TO, 0, 0.48f, -0.17f, 0.89f, -0.51f, 1.22f,
+R_ARC_TO, 1.67f, 1.67f, 0, 0, 1, -1.22f, 0.51f,
+R_H_LINE_TO, -1.34f,
+R_V_LINE_TO, 4.27f,
+R_CUBIC_TO, 0, 0.48f, -0.17f, 0.89f, -0.51f, 1.22f,
+R_ARC_TO, 1.67f, 1.67f, 0, 0, 1, -1.22f, 0.51f,
+CLOSE,
+R_MOVE_TO, 0, -1.73f,
+R_H_LINE_TO, 9.93f,
+V_LINE_TO, 11,
+H_LINE_TO, 3.5f,
+CLOSE,
+R_MOVE_TO, 11.66f, -6,
+H_LINE_TO, 16.5f,
+V_LINE_TO, 5,
+H_LINE_TO, 6.57f,
+R_V_LINE_TO, 2.84f,
+H_LINE_TO, 13.5f,
+R_CUBIC_TO, 0.45f, 0, 0.84f, 0.16f, 1.17f, 0.49f,
+R_CUBIC_TO, 0.32f, 0.32f, 0.49f, 0.72f, 0.49f, 1.17f,
+CLOSE
diff --git a/components/vector_icons/videocam_off_chrome_refresh.icon b/components/vector_icons/videocam_off_chrome_refresh.icon
index f935933..77e6d39 100644
--- a/components/vector_icons/videocam_off_chrome_refresh.icon
+++ b/components/vector_icons/videocam_off_chrome_refresh.icon
@@ -2,6 +2,46 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+CANVAS_DIMENSIONS, 20,
+R_MOVE_TO, 18.17f, 13.98f,
+R_LINE_TO, -3, -3,
+R_V_LINE_TO, 1.95f,
+R_LINE_TO, -1.73f, -1.73f,
+V_LINE_TO, 5.56f,
+R_H_LINE_TO, -5.66f,
+R_LINE_TO, -1.73f, -1.73f,
+R_H_LINE_TO, 7.39f,
+R_CUBIC_TO, 0.48f, 0, 0.89f, 0.17f, 1.22f, 0.5f,
+R_CUBIC_TO, 0.34f, 0.34f, 0.5f, 0.75f, 0.5f, 1.22f,
+V_LINE_TO, 8.98f,
+R_LINE_TO, 3, -3,
+CLOSE,
+R_MOVE_TO, -1.36f, 4.93f,
+LINE_TO, 1.07f, 3.19f,
+LINE_TO, 2.18f, 2.07f,
+LINE_TO, 17.93f, 17.79f,
+CLOSE,
+R_MOVE_TO, -6.2f, -10.54f,
+CLOSE,
+R_MOVE_TO, -2.16f, 2.16f,
+CLOSE,
+R_MOVE_TO, -4.48f, -6.66f,
+LINE_TO, 5.66f, 5.54f,
+H_LINE_TO, 4.56f,
+R_V_LINE_TO, 8.9f,
+R_H_LINE_TO, 8.88f,
+R_V_LINE_TO, -1.14f,
+R_LINE_TO, 1.72f, 1.72f,
+R_ARC_TO, 2.17f, 2.17f, 0, 0, 1, -0.62f, 0.81f,
+R_CUBIC_TO, -0.27f, 0.23f, -0.64f, 0.34f, -1.1f, 0.34f,
+H_LINE_TO, 4.56f,
+R_ARC_TO, 1.67f, 1.67f, 0, 0, 1, -1.22f, -0.5f,
+R_ARC_TO, 1.66f, 1.66f, 0, 0, 1, -0.51f, -1.23f,
+V_LINE_TO, 5.54f,
+R_CUBIC_TO, 0, -0.4f, 0.11f, -0.74f, 0.32f, -1.03f,
+R_ARC_TO, 1.83f, 1.83f, 0, 0, 1, 0.82f, -0.62f,
+CLOSE
+
 CANVAS_DIMENSIONS, 16,
 R_MOVE_TO, 14.54f, 11.18f,
 R_LINE_TO, -2.4f, -2.4f,
diff --git a/components/vector_icons/vr_headset_off_chrome_refresh.icon b/components/vector_icons/vr_headset_off_chrome_refresh.icon
index af47fb2a..a5277a79 100644
--- a/components/vector_icons/vr_headset_off_chrome_refresh.icon
+++ b/components/vector_icons/vr_headset_off_chrome_refresh.icon
@@ -64,4 +64,68 @@
 R_MOVE_TO, -1.91f, -3,
 CLOSE,
 R_MOVE_TO, -6.66f, 0.41f,
-CLOSE
\ No newline at end of file
+CLOSE
+
+CANVAS_DIMENSIONS, 20,
+R_MOVE_TO, 4.31f, 13.11f,
+R_LINE_TO, 3.32f, 0,
+R_H_LINE_TO, 0,
+R_CUBIC_TO, 0, 0, 0, 0, 0, -0.01f,
+R_LINE_TO, 0.63f, -1.26f,
+R_CUBIC_TO, 0.09f, -0.16f, 0.19f, -0.29f, 0.3f, -0.41f,
+R_CUBIC_TO, 0.12f, -0.11f, 0.25f, -0.22f, 0.39f, -0.32f,
+R_LINE_TO, -1, -0.99f,
+R_CUBIC_TO, -0.04f, 0.42f, -0.2f, 0.76f, -0.49f, 1.03f,
+R_ARC_TO, 1.5f, 1.5f, 0, 0, 1, -1.06f, 0.41f,
+R_CUBIC_TO, -0.43f, 0, -0.8f, -0.15f, -1.1f, -0.46f,
+ARC_TO, 1.49f, 1.49f, 0, 0, 1, 4.84f, 9.98f,
+R_CUBIC_TO, 0, -0.42f, 0.14f, -0.77f, 0.41f, -1.07f,
+R_CUBIC_TO, 0.27f, -0.29f, 0.61f, -0.46f, 1.03f, -0.49f,
+R_LINE_TO, -1.57f, -1.56f,
+R_H_LINE_TO, -0.4f,
+CLOSE,
+R_MOVE_TO, 11.95f, 5.33f,
+R_LINE_TO, -3.77f, -3.77f,
+R_ARC_TO, 1.79f, 1.79f, 0, 0, 1, -0.86f, -0.23f,
+R_ARC_TO, 1.39f, 1.39f, 0, 0, 1, -0.58f, -0.62f,
+R_LINE_TO, -0.66f, -1.24f,
+R_ARC_TO, 0.47f, 0.47f, 0, 0, 0, -0.37f, -0.26f,
+R_ARC_TO, 0.4f, 0.4f, 0, 0, 0, -0.21f, 0.07f,
+R_ARC_TO, 0.35f, 0.35f, 0, 0, 0, -0.15f, 0.17f,
+LINE_TO, 9, 13.81f,
+R_ARC_TO, 1.47f, 1.47f, 0, 0, 1, -0.58f, 0.62f,
+R_CUBIC_TO, -0.25f, 0.15f, -0.53f, 0.23f, -0.82f, 0.23f,
+H_LINE_TO, 4.31f,
+R_CUBIC_TO, -0.43f, 0, -0.8f, -0.15f, -1.1f, -0.46f,
+R_ARC_TO, 1.49f, 1.49f, 0, 0, 1, -0.46f, -1.1f,
+V_LINE_TO, 6.86f,
+R_CUBIC_TO, 0, -0.26f, 0.06f, -0.5f, 0.19f, -0.72f,
+R_ARC_TO, 1.69f, 1.69f, 0, 0, 1, 0.48f, -0.55f,
+LINE_TO, 1.57f, 3.75f,
+R_LINE_TO, 1.11f, -1.11f,
+LINE_TO, 17.36f, 17.32f,
+CLOSE,
+R_MOVE_TO, 0.57f, -4.24f,
+R_LINE_TO, -1.09f, -1.09f,
+V_LINE_TO, 6.86f,
+H_LINE_TO, 9.18f,
+R_LINE_TO, -1.63f, -1.56f,
+R_LINE_TO, 8.19f, 0,
+R_CUBIC_TO, 0.43f, 0, 0.8f, 0.15f, 1.1f, 0.46f,
+R_CUBIC_TO, 0.31f, 0.31f, 0.46f, 0.67f, 0.46f, 1.1f,
+R_V_LINE_TO, 6.24f,
+R_CUBIC_TO, 0, 0.21f, -0.04f, 0.41f, -0.12f, 0.6f,
+R_CUBIC_TO, -0.09f, 0.19f, -0.2f, 0.36f, -0.35f, 0.5f,
+CLOSE,
+R_MOVE_TO, -2.81f, -2.7f,
+R_CUBIC_TO, 0.34f, -0.09f, 0.63f, -0.27f, 0.86f, -0.55f,
+R_CUBIC_TO, 0.22f, -0.28f, 0.34f, -0.6f, 0.34f, -0.96f,
+R_CUBIC_TO, 0, -0.43f, -0.15f, -0.8f, -0.46f, -1.1f,
+R_ARC_TO, 1.5f, 1.5f, 0, 0, 0, -1.1f, -0.46f,
+R_CUBIC_TO, -0.38f, 0, -0.71f, 0.12f, -1, 0.35f,
+R_CUBIC_TO, -0.29f, 0.24f, -0.47f, 0.54f, -0.54f, 0.91f,
+CLOSE,
+R_MOVE_TO, -1.59f, -5.43f,
+CLOSE,
+MOVE_TO, 7.41f, 9.56f,
+CLOSE
diff --git a/components/webapps/browser/android/BUILD.gn b/components/webapps/browser/android/BUILD.gn
index 5d6cc8e..968fea8 100644
--- a/components/webapps/browser/android/BUILD.gn
+++ b/components/webapps/browser/android/BUILD.gn
@@ -133,6 +133,7 @@
     "shortcut_info_unittest.cc",
     "webapk/webapk_icon_hasher_unittest.cc",
     "webapk/webapk_proto_builder_unittest.cc",
+    "webapp_icon_unittest.cc",
     "webapps_utils_unittest.cc",
   ]
   deps = [
diff --git a/components/webapps/browser/android/webapp_icon_unittest.cc b/components/webapps/browser/android/webapp_icon_unittest.cc
new file mode 100644
index 0000000..b38a717
--- /dev/null
+++ b/components/webapps/browser/android/webapp_icon_unittest.cc
@@ -0,0 +1,86 @@
+// 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/webapps/browser/android/webapp_icon.h"
+
+#include "components/webapps/browser/android/webapps_icon_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace webapps {
+
+namespace {
+
+const int kIdealHomescreenIconSize = 96;
+const int kMinimumHomescreenIconSize = 48;
+const int kIdealSplashImageSize = 256;
+const int kMinimumSplashImageSize = 32;
+const int kIdealMonochromeIconSize = 48;
+const int kIdealAdaptiveLauncherIconSize = 166;
+const int kIdealShortcutIconSize = 72;
+
+}  // namespace
+
+class WebappIconTest : public testing::Test {
+ public:
+  WebappIconTest() = default;
+
+  WebappIconTest(const WebappIconTest&) = delete;
+  WebappIconTest& operator=(const WebappIconTest&) = delete;
+
+ protected:
+  void SetUp() override {
+    WebappsIconUtils::SetIconSizesForTesting({
+        kIdealHomescreenIconSize,
+        kMinimumHomescreenIconSize,
+        kIdealSplashImageSize,
+        kMinimumSplashImageSize,
+        kIdealMonochromeIconSize,
+        kIdealAdaptiveLauncherIconSize,
+        kIdealShortcutIconSize,
+    });
+  }
+
+  const GURL kIconUrl = GURL("http://example.com");
+};
+
+TEST_F(WebappIconTest, GetIdealIconSizes) {
+  WebappIcon primary_icon(kIconUrl, false /* is_maskable*/,
+                          webapk::Image::PRIMARY_ICON);
+  EXPECT_EQ(primary_icon.GetIdealSizeInPx(), kIdealHomescreenIconSize);
+
+  WebappIcon maskable_primary_icon(kIconUrl, true /* is_maskable*/,
+                                   webapk::Image::PRIMARY_ICON);
+  EXPECT_EQ(maskable_primary_icon.GetIdealSizeInPx(),
+            kIdealAdaptiveLauncherIconSize);
+
+  WebappIcon splash_icon(kIconUrl, false /* is_maskable*/,
+                         webapk::Image::SPLASH_ICON);
+  EXPECT_EQ(splash_icon.GetIdealSizeInPx(), kIdealSplashImageSize);
+
+  WebappIcon shortcut_icon(kIconUrl, false /* is_maskable*/,
+                           webapk::Image::SHORTCUT_ICON);
+  EXPECT_EQ(shortcut_icon.GetIdealSizeInPx(), kIdealShortcutIconSize);
+}
+
+// Test that icon with multiple usages have ideal size of the largest usage.
+TEST_F(WebappIconTest, GetIdealSizeForMultiplePurpose) {
+  WebappIcon icon(kIconUrl);
+  icon.AddUsage(webapk::Image::PRIMARY_ICON);
+  icon.AddUsage(webapk::Image::SPLASH_ICON);
+  EXPECT_EQ(icon.GetIdealSizeInPx(), kIdealSplashImageSize);
+
+  WebappIcon icon2(kIconUrl);
+  icon2.AddUsage(webapk::Image::PRIMARY_ICON);
+  icon2.AddUsage(webapk::Image::SHORTCUT_ICON);
+  EXPECT_EQ(icon2.GetIdealSizeInPx(), kIdealHomescreenIconSize);
+
+  WebappIcon icon3(kIconUrl);
+  icon3.AddUsage(webapk::Image::PRIMARY_ICON);
+  icon3.AddUsage(webapk::Image::SPLASH_ICON);
+  icon3.AddUsage(webapk::Image::SHORTCUT_ICON);
+  EXPECT_EQ(icon3.GetIdealSizeInPx(), kIdealSplashImageSize);
+}
+
+}  // namespace webapps
diff --git a/components/webapps/browser/android/webapps_icon_utils.cc b/components/webapps/browser/android/webapps_icon_utils.cc
index 3abe9b3..4a755f56 100644
--- a/components/webapps/browser/android/webapps_icon_utils.cc
+++ b/components/webapps/browser/android/webapps_icon_utils.cc
@@ -181,4 +181,15 @@
   g_ideal_shortcut_icon_size = size;
 }
 
+void WebappsIconUtils::SetIconSizesForTesting(std::vector<int> sizes) {
+  // This ordering must be kept up to date with the |GetIconSizes()| above.
+  g_ideal_homescreen_icon_size = sizes[0];
+  g_minimum_homescreen_icon_size = sizes[1];
+  g_ideal_splash_image_size = sizes[2];
+  g_minimum_splash_image_size = sizes[3];
+  g_ideal_monochrome_icon_size = sizes[4];
+  g_ideal_adaptive_launcher_icon_size = sizes[5];
+  g_ideal_shortcut_icon_size = sizes[6];
+}
+
 }  // namespace webapps
diff --git a/components/webapps/browser/android/webapps_icon_utils.h b/components/webapps/browser/android/webapps_icon_utils.h
index 7693069..64bdf7e 100644
--- a/components/webapps/browser/android/webapps_icon_utils.h
+++ b/components/webapps/browser/android/webapps_icon_utils.h
@@ -64,6 +64,7 @@
   static int GetIdealIconCornerRadiusPxForPromptUI();
 
   static void SetIdealShortcutSizeForTesting(int size);
+  static void SetIconSizesForTesting(std::vector<int> sizes);
 };
 
 }  // namespace webapps
diff --git a/content/browser/preloading/prerender/prerender_browsertest.cc b/content/browser/preloading/prerender/prerender_browsertest.cc
index 0abc40d0..7394d1f0 100644
--- a/content/browser/preloading/prerender/prerender_browsertest.cc
+++ b/content/browser/preloading/prerender/prerender_browsertest.cc
@@ -4365,7 +4365,7 @@
   // "Navigation.Prerender.ActivationCommitDeferTime" histogram should be
   // recorded as PrerenderCommitDeferringCondition defers the navigation.
   histogram_tester().ExpectTotalCount(
-      "Navigation.Prerender.ActivationCommitDeferTime", 1u);
+      "Navigation.Prerender.ActivationCommitDeferTime.SpeculationRule", 1u);
 }
 
 // TODO(https://crbug.com/1182032): Now the File System Access API is not
diff --git a/content/browser/preloading/prerender/prerender_commit_deferring_condition.cc b/content/browser/preloading/prerender/prerender_commit_deferring_condition.cc
index 2982f063..c2f076c 100644
--- a/content/browser/preloading/prerender/prerender_commit_deferring_condition.cc
+++ b/content/browser/preloading/prerender/prerender_commit_deferring_condition.cc
@@ -6,6 +6,8 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/task/sequenced_task_runner.h"
+#include "content/browser/preloading/prerender/prerender_host.h"
+#include "content/browser/preloading/prerender/prerender_metrics.h"
 #include "content/browser/renderer_host/frame_tree.h"
 #include "content/browser/renderer_host/frame_tree_node.h"
 #include "content/browser/renderer_host/navigation_request.h"
@@ -68,8 +70,16 @@
 
   // If there is no ongoing main frame navigation in prerender frame tree, the
   // prerender activation is allowed to continue.
-  if (!prerender_frame_tree_node->HasNavigation())
+  if (!prerender_frame_tree_node->HasNavigation()) {
+    // Record the defer waiting time for PrerenderCommitDeferringCondition as no
+    // delay.
+    PrerenderHost& prerender_host =
+        PrerenderHost::GetFromFrameTreeNode(*prerender_frame_tree_node);
+    RecordPrerenderActivationCommitDeferTime(
+        base::TimeDelta(), prerender_host.trigger_type(),
+        prerender_host.embedder_histogram_suffix());
     return Result::kProceed;
+  }
 
   // Defer the prerender activation until the ongoing prerender main frame
   // navigation commits.
@@ -108,8 +118,11 @@
 
     // Record the defer waiting time for PrerenderCommitDeferringCondition.
     base::TimeDelta delta = base::TimeTicks::Now() - defer_start_time_;
-    base::UmaHistogramTimes("Navigation.Prerender.ActivationCommitDeferTime",
-                            delta);
+    PrerenderHost& prerender_host =
+        PrerenderHost::GetFromFrameTreeNode(*prerender_frame_tree_node);
+    RecordPrerenderActivationCommitDeferTime(
+        delta, prerender_host.trigger_type(),
+        prerender_host.embedder_histogram_suffix());
   }
 }
 
diff --git a/content/browser/preloading/prerender/prerender_host.cc b/content/browser/preloading/prerender/prerender_host.cc
index c243145..3dcb821 100644
--- a/content/browser/preloading/prerender/prerender_host.cc
+++ b/content/browser/preloading/prerender/prerender_host.cc
@@ -120,6 +120,13 @@
   }
 }
 
+// static
+PrerenderHost& PrerenderHost::GetFromFrameTreeNode(
+    FrameTreeNode& frame_tree_node) {
+  CHECK(frame_tree_node.frame_tree().is_prerendering());
+  return *static_cast<PrerenderHost*>(frame_tree_node.frame_tree().delegate());
+}
+
 PrerenderHost::PrerenderHost(
     const PrerenderAttributes& attributes,
     WebContentsImpl& web_contents,
diff --git a/content/browser/preloading/prerender/prerender_host.h b/content/browser/preloading/prerender/prerender_host.h
index e8c4827..4e9e1ac 100644
--- a/content/browser/preloading/prerender/prerender_host.h
+++ b/content/browser/preloading/prerender/prerender_host.h
@@ -102,6 +102,9 @@
   // frame_tree_node is in a prerendering tree.
   static PrerenderHost* GetPrerenderHostFromFrameTreeNode(
       FrameTreeNode& frame_tree_node);
+  // Similar to GetPrerenderHostFromFrameTreeNode() but `frame_tree_node` must
+  // be in prerendering.
+  static PrerenderHost& GetFromFrameTreeNode(FrameTreeNode& frame_tree_node);
 
   // Checks whether two headers are the same in a case-insensitive and
   // order-insensitive way.
diff --git a/content/browser/preloading/prerender/prerender_metrics.cc b/content/browser/preloading/prerender/prerender_metrics.cc
index d27fe05..c58195c9 100644
--- a/content/browser/preloading/prerender/prerender_metrics.cc
+++ b/content/browser/preloading/prerender/prerender_metrics.cc
@@ -441,4 +441,14 @@
   }
 }
 
+void RecordPrerenderActivationCommitDeferTime(
+    base::TimeDelta time_delta,
+    PrerenderTriggerType trigger_type,
+    const std::string& embedder_histogram_suffix) {
+  base::UmaHistogramTimes(
+      GenerateHistogramName("Navigation.Prerender.ActivationCommitDeferTime",
+                            trigger_type, embedder_histogram_suffix),
+      time_delta);
+}
+
 }  // namespace content
diff --git a/content/browser/preloading/prerender/prerender_metrics.h b/content/browser/preloading/prerender/prerender_metrics.h
index 20e69a0..608c830c 100644
--- a/content/browser/preloading/prerender/prerender_metrics.h
+++ b/content/browser/preloading/prerender/prerender_metrics.h
@@ -196,6 +196,11 @@
     PrerenderBackNavigationEligibility eligibility,
     PreloadingAttempt* preloading_attempt);
 
+void RecordPrerenderActivationCommitDeferTime(
+    base::TimeDelta time_delta,
+    PrerenderTriggerType trigger_type,
+    const std::string& embedder_histogram_suffix);
+
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_PRELOADING_PRERENDER_PRERENDER_METRICS_H_
diff --git a/docs/ios/build_instructions.md b/docs/ios/build_instructions.md
index 75b37246..ca3dc8c 100644
--- a/docs/ios/build_instructions.md
+++ b/docs/ios/build_instructions.md
@@ -481,6 +481,15 @@
 $ git update-index --untracked-cache
 ```
 
+#### Configure git to use fsmonitor
+
+If `git --version` reports 2.37 or higher, use fsmonitor, which will
+significantly speed git:
+
+```shell
+$ git config core.fsmonitor true
+```
+
 ### Xcode license agreement
 
 If you're getting the error
diff --git a/infra/config/PRESUBMIT.py b/infra/config/PRESUBMIT.py
index 9671aa3..df4b233 100644
--- a/infra/config/PRESUBMIT.py
+++ b/infra/config/PRESUBMIT.py
@@ -9,7 +9,6 @@
 """
 
 PRESUBMIT_VERSION = '2.0.0'
-USE_PYTHON3 = True
 
 _IGNORE_FREEZE_FOOTER = 'Ignore-Freeze'
 
diff --git a/infra/config/scripts/PRESUBMIT.py b/infra/config/scripts/PRESUBMIT.py
index 6963afd..a031c74 100644
--- a/infra/config/scripts/PRESUBMIT.py
+++ b/infra/config/scripts/PRESUBMIT.py
@@ -8,7 +8,6 @@
 """
 
 PRESUBMIT_VERSION = '2.0.0'
-USE_PYTHON3 = True
 
 
 def CheckTests(input_api, output_api):
diff --git a/media/gpu/test/local_gpu_memory_buffer_manager.cc b/media/gpu/test/local_gpu_memory_buffer_manager.cc
index be17bce..cfa64eb 100644
--- a/media/gpu/test/local_gpu_memory_buffer_manager.cc
+++ b/media/gpu/test/local_gpu_memory_buffer_manager.cc
@@ -8,6 +8,7 @@
 #include <gbm.h>
 #include <stddef.h>
 #include <stdint.h>
+#include <sys/mman.h>
 #include <xf86drm.h>
 
 #include <vector>
@@ -139,7 +140,7 @@
           gbm_bo_map2(buffer_object_, 0, 0, gbm_bo_get_width(buffer_object_),
                       gbm_bo_get_height(buffer_object_),
                       GBM_BO_TRANSFER_READ_WRITE, &stride, &mapped_data, i);
-      if (!addr) {
+      if (addr == MAP_FAILED) {
         LOG(ERROR) << "Failed to map GpuMemoryBufferImplGbm plane " << i;
         Unmap();
         return false;
diff --git a/net/quic/quic_chromium_packet_reader.h b/net/quic/quic_chromium_packet_reader.h
index 2caf8c8..1ab3e0b5 100644
--- a/net/quic/quic_chromium_packet_reader.h
+++ b/net/quic/quic_chromium_packet_reader.h
@@ -62,7 +62,7 @@
   // Return true if reading should continue.
   bool ProcessReadResult(int result);
 
-  raw_ptr<DatagramClientSocket, DanglingUntriaged> socket_;
+  raw_ptr<DatagramClientSocket> socket_;
 
   raw_ptr<Visitor> visitor_;
   bool read_pending_ = false;
diff --git a/net/quic/quic_chromium_packet_writer.h b/net/quic/quic_chromium_packet_writer.h
index a60c168..71256d648 100644
--- a/net/quic/quic_chromium_packet_writer.h
+++ b/net/quic/quic_chromium_packet_writer.h
@@ -118,8 +118,8 @@
   bool MaybeRetryAfterWriteError(int rv);
   void RetryPacketAfterNoBuffers();
   quic::WriteResult WritePacketToSocketImpl();
-  raw_ptr<DatagramClientSocket, DanglingUntriaged> socket_;  // Unowned.
-  raw_ptr<Delegate, DanglingUntriaged> delegate_ = nullptr;  // Unowned.
+  raw_ptr<DatagramClientSocket> socket_;  // Unowned.
+  raw_ptr<Delegate> delegate_ = nullptr;  // Unowned.
   // Reused for every packet write for the lifetime of the writer.  Is
   // moved to the delegate in the case of a write error.
   scoped_refptr<ReusableIOBuffer> packet_;
diff --git a/services/network/network_service_memory_cache.cc b/services/network/network_service_memory_cache.cc
index 954d1de..5c4cfa87 100644
--- a/services/network/network_service_memory_cache.cc
+++ b/services/network/network_service_memory_cache.cc
@@ -11,7 +11,6 @@
 #include "base/memory/ref_counted_memory.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/metrics/field_trial_params.h"
-#include "base/metrics/histogram_functions.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_piece.h"
@@ -96,23 +95,6 @@
     &features::kNetworkServiceMemoryCache, "max_per_entry_size",
     4 * 1024 * 1024};
 
-// These values are persisted to logs. Entries should not be renumbered and
-// numeric values should never be reused.
-enum class EntryStatus {
-  kNotInCache = 0,
-  kStale = 1,
-  kUsed = 2,
-  kVaryMismatch = 3,
-  kBlockedByRequestHeaders = 4,
-  kBlockedServiceWorkerOriginatedRequest_Deprecated = 5,
-  kMaxValue = kBlockedServiceWorkerOriginatedRequest_Deprecated,
-};
-
-void RecordEntryStatus(EntryStatus result) {
-  base::UmaHistogramEnumeration("NetworkService.MemoryCache.EntryStatus",
-                                result);
-}
-
 absl::optional<std::string> GenerateCacheKeyForResourceRequest(
     const ResourceRequest& resource_request,
     const net::NetworkIsolationKey& network_isolation_key) {
@@ -398,24 +380,6 @@
     return;
   }
 
-  base::UmaHistogramCustomCounts(
-      base::StrCat(
-          {"NetworkService.MemoryCache.ContentLength.",
-           RequestDestinationToStringForHistogram(request_destination)}),
-      base::saturated_cast<base::Histogram::Sample>(data.size()),
-      /*min=*/1, /*exclusive_max=*/50000000,
-      /*buckets=*/50);
-
-  // Record fresness of the response in seconds.
-  const int64_t freshness_in_seconds = lifetimes.freshness.InSeconds();
-  constexpr int kMinSeconds = 1;
-  constexpr int kMaxSeconds = 60 * 60 * 24 * 10;  // 10 days.
-  base::UmaHistogramCustomCounts(
-      "NetworkService.MemoryCache.FreshnessAtStore",
-      base::saturated_cast<base::Histogram::Sample>(freshness_in_seconds),
-      kMinSeconds, kMaxSeconds,
-      /*buckets=*/50);
-
   auto prev = entries_.Peek(cache_key);
   if (prev != entries_.end()) {
     DCHECK_GE(total_bytes_, prev->second->content->size());
@@ -474,17 +438,12 @@
 
   auto it = entries_.Peek(*cache_key);
   if (it == entries_.end()) {
-    RecordEntryStatus(EntryStatus::kNotInCache);
     return absl::nullopt;
   }
 
   absl::optional<BlockedByRequestHeaderReason> blocked_by_headers =
       CheckSpecialRequestHeaders(resource_request.headers);
   if (blocked_by_headers.has_value()) {
-    RecordEntryStatus(EntryStatus::kBlockedByRequestHeaders);
-    base::UmaHistogramEnumeration(
-        "NetworkService.MemoryCache.BlockedByRequestHeaderReason",
-        *blocked_by_headers);
     return absl::nullopt;
   }
 
@@ -513,20 +472,17 @@
   if (!MatchVaryHeader(
           resource_request, it->second->vary_data, *response->headers,
           network_context_->url_request_context()->enable_brotli())) {
-    RecordEntryStatus(EntryStatus::kVaryMismatch);
     return absl::nullopt;
   }
 
   net::ValidationType validation_type = response->headers->RequiresValidation(
       response->request_time, response->response_time, GetCurrentTime());
   if (validation_type != net::VALIDATION_NONE) {
-    RecordEntryStatus(EntryStatus::kStale);
     // The cached response is stale, erase it from the in-memory cache.
     EraseEntry(it);
     return absl::nullopt;
   }
 
-  RecordEntryStatus(EntryStatus::kUsed);
   return std::move(*cache_key);
 }
 
diff --git a/services/proxy_resolver_win/windows_system_proxy_resolver_impl_unittest.cc b/services/proxy_resolver_win/windows_system_proxy_resolver_impl_unittest.cc
index fbadd47..57e7062d 100644
--- a/services/proxy_resolver_win/windows_system_proxy_resolver_impl_unittest.cc
+++ b/services/proxy_resolver_win/windows_system_proxy_resolver_impl_unittest.cc
@@ -407,6 +407,7 @@
   // WindowsSystemProxyResolverImpl.
   void DoFailedGetProxyForUrlTest(net::WinHttpStatus winhttp_status,
                                   int windows_error) {
+    ::SetLastError(windows_error);
     PerformGetProxyForUrlAndValidateResult(net::ProxyList(), winhttp_status,
                                            windows_error);
   }
diff --git a/services/webnn/BUILD.gn b/services/webnn/BUILD.gn
index 108b9f44..ae8d864 100644
--- a/services/webnn/BUILD.gn
+++ b/services/webnn/BUILD.gn
@@ -29,6 +29,7 @@
 
   deps = [
     "//base",
+    "//components/ml/webnn",
     "//mojo/public/cpp/bindings",
     "//services/webnn/public/mojom",
   ]
@@ -37,7 +38,10 @@
 source_set("tests") {
   testonly = true
 
-  sources = [ "webnn_context_impl_unittest.cc" ]
+  sources = [
+    "webnn_context_impl_unittest.cc",
+    "webnn_graph_impl_unittest.cc",
+  ]
 
   if (is_win) {
     sources += [
diff --git a/services/webnn/DEPS b/services/webnn/DEPS
index 4ba7b60..1ba0c22 100644
--- a/services/webnn/DEPS
+++ b/services/webnn/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+components/ml/webnn",
   "+ui/gl/gl_angle_util_win.h",
   "+ui/gl/init/gl_factory.h",
 ]
diff --git a/services/webnn/README.md b/services/webnn/README.md
index 9f4e8ef..a58cd60 100644
--- a/services/webnn/README.md
+++ b/services/webnn/README.md
@@ -2,5 +2,7 @@
 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/webnn_graph.mojom b/services/webnn/public/mojom/webnn_graph.mojom
index 4c3479e0..893be0f 100644
--- a/services/webnn/public/mojom/webnn_graph.mojom
+++ b/services/webnn/public/mojom/webnn_graph.mojom
@@ -4,10 +4,71 @@
 
 module webnn.mojom;
 
+// Represents the `MLOperand` which describes not only input and constant
+// operand, but also the output operand of operator.
+struct Operand {
+  // Represents the `MLOperandType` in the WebIDL definition.
+  enum DataType {
+    kFloat32,
+    kFloat16,
+    kInt32,
+    kUint32,
+    kInt8,
+    kUint8,
+  };
+
+  enum Kind { kInput, kConstant, kOutput };
+
+  Kind kind;
+  // The data type of the operand.
+  DataType data_type;
+  // The dimensions of the operand.
+  array<uint32> dimensions;
+  // The name field is only required for input/output operands of graph.
+  string? name;
+};
+
+// Represents the operations defined in `MLGraphBuilder` that describes the
+// functional semantics.
+struct Operator {
+  enum Kind {
+    // Keep the order as the same as build methods of `MLGraphBuilder`.
+    kAdd,
+    kSub,
+    kMul,
+    kDiv,
+    kMax,
+    kMin,
+  };
+
+  // The kind of this `Operator`.
+  Kind kind;
+  // The id array from the `GraphInfo.operands` will be used to map the input
+  // operands of `Operator`.
+  array<uint64> input_operands;
+  // The id array from the `GraphInfo.operands` will be used to map the output
+  // operands of `Operator`.
+  array<uint64> output_operands;
+};
+
+// Describes an entire WebNN graph information.
+struct GraphInfo {
+  // A map of all operands used in this `GraphInfo`, the key is the operand id.
+  map<uint64, Operand> id_to_operand_map;
+  // The id array from the `GraphInfo.operands` is used to identify the input
+  // operands of this graph.
+  array<uint64> input_operands;
+  // The id array from the `GraphInfo.operands` is used to identify the output
+  // operands of this graph.
+  array<uint64> output_operands;
+  // The operators are sorted in the topological order.
+  array<Operator> operators;
+};
+
 // 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.
+// execute the computational graph. Graph 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.
+  // TODO(crbug.com/1273291): Add `Compute` method to execute computational
+  // graph with system framework.
 };
diff --git a/services/webnn/public/mojom/webnn_service.mojom b/services/webnn/public/mojom/webnn_service.mojom
index 753dbb1..c5e2fab 100644
--- a/services/webnn/public/mojom/webnn_service.mojom
+++ b/services/webnn/public/mojom/webnn_service.mojom
@@ -35,8 +35,10 @@
 // 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);
+  // executing computational graph, the WebNN graph will be validated and
+  // compiled. Initializes the compiled graph for optimal performance of the
+  // subsequent graph executions if the initialization is a necessary step.
+  CreateGraph(GraphInfo graph_info) => (pending_remote<WebNNGraph>? remote);
 };
 
 // This interface runs in the GPU process and is called from the renderer
diff --git a/services/webnn/webnn_context_impl.cc b/services/webnn/webnn_context_impl.cc
index 16309ff..6f7f223 100644
--- a/services/webnn/webnn_context_impl.cc
+++ b/services/webnn/webnn_context_impl.cc
@@ -8,29 +8,37 @@
 #include <utility>
 
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#include "services/webnn/webnn_context_provider_impl.h"
 #include "services/webnn/webnn_graph_impl.h"
 
 namespace webnn {
 
-WebNNContextImpl::WebNNContextImpl() = default;
+WebNNContextImpl::WebNNContextImpl(
+    mojo::PendingReceiver<mojom::WebNNContext> receiver,
+    WebNNContextProviderImpl* context_provider)
+    : receiver_(this, std::move(receiver)),
+      context_provider_(context_provider) {
+  CHECK(context_provider_);
+  // Safe to use base::Unretained because the context_provider_ owns this class
+  // that won't be destroyed until this callback executes.
+  receiver_.set_disconnect_handler(base::BindOnce(
+      &WebNNContextImpl::OnConnectionError, base::Unretained(this)));
+}
 
 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::OnConnectionError() {
+  context_provider_->OnConnectionError(this);
 }
 
 void WebNNContextImpl::CreateGraph(
+    mojom::GraphInfoPtr graph_info,
     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));
+  if (!WebNNGraphImpl::ValidateAndBuildGraph(std::move(callback),
+                                             std::move(graph_info))) {
+    receiver_.ReportBadMessage("Invalid graph from renderer.");
+    return;
+  }
 }
 
 }  // namespace webnn
diff --git a/services/webnn/webnn_context_impl.h b/services/webnn/webnn_context_impl.h
index 9d2060c..c0506c0 100644
--- a/services/webnn/webnn_context_impl.h
+++ b/services/webnn/webnn_context_impl.h
@@ -6,24 +6,34 @@
 #define SERVICES_WEBNN_WEBNN_CONTEXT_IMPL_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 WebNNContextProviderImpl;
+
 class WebNNContextImpl : public mojom::WebNNContext {
  public:
-  WebNNContextImpl();
+  WebNNContextImpl(mojo::PendingReceiver<mojom::WebNNContext> receiver,
+                   WebNNContextProviderImpl* context_provider);
 
   WebNNContextImpl(const WebNNContextImpl&) = delete;
   WebNNContextImpl& operator=(const WebNNContextImpl&) = delete;
 
   ~WebNNContextImpl() override;
 
-  static void Create(mojo::PendingReceiver<mojom::WebNNContext> receiver);
-
  private:
+  void OnConnectionError();
+
   // mojom::WebNNContext
-  void CreateGraph(CreateGraphCallback callback) override;
+  void CreateGraph(mojom::GraphInfoPtr graph_info,
+                   CreateGraphCallback callback) override;
+
+  mojo::Receiver<mojom::WebNNContext> receiver_;
+
+  // Owns this object.
+  raw_ptr<WebNNContextProviderImpl> context_provider_;
 };
 
 }  // namespace webnn
diff --git a/services/webnn/webnn_context_impl_unittest.cc b/services/webnn/webnn_context_impl_unittest.cc
index 585f5587..cf208932 100644
--- a/services/webnn/webnn_context_impl_unittest.cc
+++ b/services/webnn/webnn_context_impl_unittest.cc
@@ -15,6 +15,52 @@
 
 namespace webnn {
 
+namespace {
+
+mojom::GraphInfoPtr BuildSimpleGraph() {
+  auto graph_info = mojom::GraphInfo::New();
+  size_t operand_id = 0;
+  // Create left mojo operand.
+  auto lhs_operand = mojom::Operand::New();
+  lhs_operand->data_type = mojom::Operand::DataType::kFloat32;
+  lhs_operand->dimensions = std::vector<uint32_t>(3, 2);
+  lhs_operand->name = std::move("lhs");
+  lhs_operand->kind = mojom::Operand::Kind::kInput;
+  size_t lhs_operand_id = ++operand_id;
+  graph_info->id_to_operand_map[lhs_operand_id] = std::move(lhs_operand);
+  graph_info->input_operands.push_back(lhs_operand_id);
+
+  // Create right mojo operand.
+  auto rhs_operand = mojom::Operand::New();
+  rhs_operand->data_type = mojom::Operand::DataType::kFloat32;
+  rhs_operand->dimensions = std::vector<uint32_t>(3, 2);
+  rhs_operand->name = std::move("rhs");
+  rhs_operand->kind = mojom::Operand::Kind::kInput;
+  size_t rhs_operand_id = ++operand_id;
+  graph_info->id_to_operand_map[rhs_operand_id] = std::move(rhs_operand);
+  graph_info->input_operands.push_back(rhs_operand_id);
+
+  // Create output mojo operand.
+  auto output_operand = mojom::Operand::New();
+  output_operand->data_type = mojom::Operand::DataType::kFloat32;
+  output_operand->dimensions = std::vector<uint32_t>(3, 2);
+  output_operand->name = std::move("output");
+  output_operand->kind = mojom::Operand::Kind::kOutput;
+  size_t output_operand_id = ++operand_id;
+  graph_info->id_to_operand_map[output_operand_id] = std::move(output_operand);
+  graph_info->output_operands.push_back(output_operand_id);
+
+  // Create the add operation.
+  auto operation = mojom::Operator::New();
+  operation->kind = mojom::Operator::Kind::kAdd;
+  operation->input_operands = {lhs_operand_id, rhs_operand_id};
+  operation->output_operands = {output_operand_id};
+  graph_info->operators.emplace_back(std::move(operation));
+  return graph_info;
+}
+
+}  // namespace
+
 class WebNNContextImplTest : public testing::Test {
  public:
   WebNNContextImplTest(const WebNNContextImplTest&) = delete;
@@ -62,12 +108,14 @@
 
   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();
-      }));
+  webnn_context_remote->CreateGraph(
+      BuildSimpleGraph(),
+      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);
 }
diff --git a/services/webnn/webnn_context_provider_impl.cc b/services/webnn/webnn_context_provider_impl.cc
index 928dbfe..efc25a0 100644
--- a/services/webnn/webnn_context_provider_impl.cc
+++ b/services/webnn/webnn_context_provider_impl.cc
@@ -30,6 +30,13 @@
       std::make_unique<WebNNContextProviderImpl>(), std::move(receiver));
 }
 
+void WebNNContextProviderImpl::OnConnectionError(WebNNContextImpl* impl) {
+  auto it =
+      base::ranges::find(impls_, impl, &std::unique_ptr<WebNNContextImpl>::get);
+  CHECK(it != impls_.end());
+  impls_.erase(it);
+}
+
 void WebNNContextProviderImpl::CreateWebNNContext(
     CreateContextOptionsPtr options,
     WebNNContextProvider::CreateWebNNContextCallback callback) {
@@ -37,7 +44,8 @@
   // The remote sent to the renderer.
   mojo::PendingRemote<mojom::WebNNContext> blink_remote;
   // The receiver bound to WebNNContextImpl.
-  WebNNContextImpl::Create(blink_remote.InitWithNewPipeAndPassReceiver());
+  impls_.push_back(base::WrapUnique<WebNNContextImpl>(new WebNNContextImpl(
+      blink_remote.InitWithNewPipeAndPassReceiver(), this)));
   std::move(callback).Run(mojom::CreateContextResult::kOk,
                           std::move(blink_remote));
 #else
diff --git a/services/webnn/webnn_context_provider_impl.h b/services/webnn/webnn_context_provider_impl.h
index bfb5ca4..7a1acc0a 100644
--- a/services/webnn/webnn_context_provider_impl.h
+++ b/services/webnn/webnn_context_provider_impl.h
@@ -5,11 +5,18 @@
 #ifndef SERVICES_WEBNN_WEBNN_CONTEXT_PROVIDER_IMPL_H_
 #define SERVICES_WEBNN_WEBNN_CONTEXT_PROVIDER_IMPL_H_
 
+#include <memory>
+#include <vector>
+
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "services/webnn/public/mojom/webnn_service.mojom.h"
 
 namespace webnn {
 
+class WebNNContextImpl;
+
+// Maintain a set of WebNNContextImpl instances that are created by the context
+// provider.
 class WebNNContextProviderImpl : public mojom::WebNNContextProvider {
  public:
   WebNNContextProviderImpl();
@@ -22,10 +29,16 @@
   static void Create(
       mojo::PendingReceiver<mojom::WebNNContextProvider> receiver);
 
+  // Called when a WebNNContextImpl has a connection error. After this call, it
+  // is no longer safe to access |impl|.
+  void OnConnectionError(WebNNContextImpl* impl);
+
  private:
   // mojom::WebNNContextProvider
   void CreateWebNNContext(mojom::CreateContextOptionsPtr options,
                           CreateWebNNContextCallback callback) override;
+
+  std::vector<std::unique_ptr<WebNNContextImpl>> impls_;
 };
 
 }  // namespace webnn
diff --git a/services/webnn/webnn_graph_impl.cc b/services/webnn/webnn_graph_impl.cc
index fbf4ceb4..9b951fd 100644
--- a/services/webnn/webnn_graph_impl.cc
+++ b/services/webnn/webnn_graph_impl.cc
@@ -4,21 +4,195 @@
 
 #include "services/webnn/webnn_graph_impl.h"
 
-#include <memory>
 #include <utility>
+#include <vector>
 
+#include "components/ml/webnn/graph_validation_utils.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 
 namespace webnn {
 
+namespace {
+
+// Maps the id to its `mojo::Operand`.
+using IdToOperandMap = base::flat_map<uint64_t, mojom::OperandPtr>;
+
+size_t GetBytesPerElement(mojom::Operand::DataType operand_type) {
+  switch (operand_type) {
+    case mojom::Operand::DataType::kFloat32:
+      return sizeof(float);
+    case mojom::Operand::DataType::kFloat16:
+      return sizeof(uint16_t);
+    case mojom::Operand::DataType::kInt32:
+      return sizeof(int32_t);
+    case mojom::Operand::DataType::kUint32:
+      return sizeof(uint32_t);
+    case mojom::Operand::DataType::kInt8:
+      return sizeof(int8_t);
+    case mojom::Operand::DataType::kUint8:
+      return sizeof(uint8_t);
+  }
+  NOTREACHED();
+}
+
+bool ValidateInputOperand(const IdToOperandMap& id_to_operand_map,
+                          uint64_t input_id) {
+  if (!id_to_operand_map.contains(input_id)) {
+    // Invalid input operand.
+    return false;
+  }
+
+  const mojom::OperandPtr& operand = id_to_operand_map.at(input_id);
+  if (operand->kind != mojom::Operand::Kind::kInput) {
+    // Invalid input kind.
+    return false;
+  }
+  const absl::optional<std::string>& name = operand->name;
+  if (name && name.value().empty()) {
+    // The name of input operand is empty.
+    return false;
+  }
+
+  if (!ValidateAndCalculateByteLength(GetBytesPerElement(operand->data_type),
+                                      operand->dimensions)
+           .has_value()) {
+    // The byte length is invalid.
+    return false;
+  }
+  return true;
+}
+
+bool ValidateOutputOperand(const IdToOperandMap& id_to_operand_map,
+                           uint64_t output_id) {
+  if (!id_to_operand_map.contains(output_id)) {
+    // Invalid output operand.
+    return false;
+  }
+
+  const mojom::OperandPtr& operand = id_to_operand_map.at(output_id);
+  if (operand->kind != mojom::Operand::Kind::kOutput) {
+    // Invalid output kind.
+    return false;
+  }
+  absl::optional<std::string>& name = operand->name;
+  if (name && name.value().empty()) {
+    // The name of output operand is empty.
+    return false;
+  }
+  return true;
+}
+
+const mojom::Operand* GetMojoOperand(
+    const IdToOperandMap& id_to_operand_map,
+    const std::vector<uint64_t>& operand_id_array,
+    size_t index = 0) {
+  if (index >= operand_id_array.size()) {
+    // Index out of range.
+    return nullptr;
+  }
+  uint64_t operand_id = operand_id_array[index];
+  if (!id_to_operand_map.contains(operand_id)) {
+    // There is no operand for the id.
+    return nullptr;
+  }
+  return id_to_operand_map.at(operand_id).get();
+}
+
+bool ValidateElementWiseBinary(const IdToOperandMap& id_to_operand_map,
+                               const mojom::OperatorPtr& operation) {
+  auto* a = GetMojoOperand(id_to_operand_map, operation->input_operands, 0);
+  auto* b = GetMojoOperand(id_to_operand_map, operation->input_operands, 1);
+  auto* output = GetMojoOperand(id_to_operand_map, operation->output_operands);
+  if (!a || !b || !output) {
+    // The elementWise binary operator is invalid.
+    return false;
+  }
+  if (a->data_type != b->data_type || output->data_type != a->data_type) {
+    // The input types don't match.
+    return false;
+  }
+
+  auto dims_output = BroadcastShapes(a->dimensions, b->dimensions);
+  if (!dims_output) {
+    // The input shapes are not broadcastable.
+    return false;
+  }
+  if (output->dimensions != dims_output.value()) {
+    // The output shapes are not expected.
+    return false;
+  }
+  return true;
+}
+
+bool ValidateOperator(const IdToOperandMap& id_to_operand_map,
+                      const mojom::OperatorPtr& operation) {
+  switch (operation->kind) {
+    case mojom::Operator::Kind::kAdd:
+    case mojom::Operator::Kind::kSub:
+    case mojom::Operator::Kind::kMul:
+    case mojom::Operator::Kind::kDiv:
+    case mojom::Operator::Kind::kMax:
+    case mojom::Operator::Kind::kMin:
+      return ValidateElementWiseBinary(id_to_operand_map, operation);
+  }
+  NOTREACHED_NORETURN();
+}
+
+bool ValidateGraphInfo(const mojom::GraphInfoPtr& graph_info) {
+  // The input operands of graph can be empty.
+  if (graph_info->id_to_operand_map.empty() || graph_info->operators.empty() ||
+      graph_info->output_operands.empty()) {
+    return false;
+  }
+
+  // Validate the input operands of graph.
+  for (auto& input_id : graph_info->input_operands) {
+    if (!ValidateInputOperand(graph_info->id_to_operand_map, input_id)) {
+      return false;
+    }
+  }
+
+  // Validate the operators which are sorted in the topological order.
+  for (auto& operation : graph_info->operators) {
+    if (!ValidateOperator(graph_info->id_to_operand_map, operation)) {
+      return false;
+    }
+  }
+
+  // Validate the output operands in the entire graph.
+  for (auto& output_id : graph_info->output_operands) {
+    if (!ValidateOutputOperand(graph_info->id_to_operand_map, output_id)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+}  // namespace
+
 WebNNGraphImpl::WebNNGraphImpl() = default;
 
 WebNNGraphImpl::~WebNNGraphImpl() = default;
 
 // static
-void WebNNGraphImpl::Create(mojo::PendingReceiver<mojom::WebNNGraph> receiver) {
+bool WebNNGraphImpl::ValidateAndBuildGraph(
+    mojom::WebNNContext::CreateGraphCallback callback,
+    const mojom::GraphInfoPtr& graph_info) {
+  if (!ValidateGraphInfo(graph_info)) {
+    return false;
+  }
+
+  // The remote sent to the renderer.
+  mojo::PendingRemote<mojom::WebNNGraph> blink_remote;
+  // The receiver bound to WebNNGraphImpl.
   mojo::MakeSelfOwnedReceiver<mojom::WebNNGraph>(
-      std::make_unique<WebNNGraphImpl>(), std::move(receiver));
+      std::make_unique<WebNNGraphImpl>(),
+      blink_remote.InitWithNewPipeAndPassReceiver());
+  // TODO(crbug.com/1273291): Build graph with OS machine learning APIs.
+  // webnn_graph_impl->BuildGraph(std::move(callback), std::move(blink_remote));
+  std::move(callback).Run(std::move(blink_remote));
+  return true;
 }
 
 }  // namespace webnn
diff --git a/services/webnn/webnn_graph_impl.h b/services/webnn/webnn_graph_impl.h
index 5e1d88a..6c1d510 100644
--- a/services/webnn/webnn_graph_impl.h
+++ b/services/webnn/webnn_graph_impl.h
@@ -5,8 +5,8 @@
 #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"
+#include "services/webnn/public/mojom/webnn_service.mojom.h"
 
 namespace webnn {
 
@@ -17,7 +17,10 @@
   WebNNGraphImpl& operator=(const WebNNGraphImpl&) = delete;
   ~WebNNGraphImpl() override;
 
-  static void Create(mojo::PendingReceiver<mojom::WebNNGraph> receiver);
+  // Return false if the graph is invalid.
+  static bool ValidateAndBuildGraph(
+      mojom::WebNNContext::CreateGraphCallback callback,
+      const mojom::GraphInfoPtr& graph_info);
 };
 
 }  // namespace webnn
diff --git a/services/webnn/webnn_graph_impl_unittest.cc b/services/webnn/webnn_graph_impl_unittest.cc
new file mode 100644
index 0000000..3a9d404
--- /dev/null
+++ b/services/webnn/webnn_graph_impl_unittest.cc
@@ -0,0 +1,202 @@
+// 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 "base/test/bind.h"
+#include "base/test/task_environment.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 {
+
+namespace {
+
+mojom::OperandPtr CreateOperand(const std::string& name,
+                                const std::vector<uint32_t>& dimensions,
+                                mojom::Operand::DataType type) {
+  auto operand = mojom::Operand::New();
+  operand->data_type = type;
+  operand->dimensions = dimensions;
+  operand->name = name;
+  return operand;
+}
+
+mojom::OperatorPtr CreateOperator(mojom::Operator::Kind kind,
+                                  const std::vector<uint64_t>& inputs,
+                                  const std::vector<uint64_t>& outputs) {
+  auto operation = mojom::Operator::New();
+  operation->kind = kind;
+  operation->input_operands = inputs;
+  operation->output_operands = outputs;
+
+  return operation;
+}
+
+}  // namespace
+
+class WebNNGraphImplTest : public testing::Test {
+ public:
+  WebNNGraphImplTest(const WebNNGraphImplTest&) = delete;
+  WebNNGraphImplTest& operator=(const WebNNGraphImplTest&) = delete;
+
+  void TearDown() override { operand_id_ = 0; }
+
+  uint64_t BuildInput(mojom::GraphInfoPtr& graph_info,
+                      const std::string& name,
+                      const std::vector<uint32_t>& dimensions,
+                      mojom::Operand::DataType type) {
+    auto operand = CreateOperand(name, dimensions, type);
+    operand->kind = mojom::Operand::Kind::kInput;
+    operand_id_++;
+    CHECK(graph_info->id_to_operand_map.find(operand_id_) ==
+          graph_info->id_to_operand_map.end());
+    graph_info->id_to_operand_map[operand_id_] = std::move(operand);
+    graph_info->input_operands.push_back(operand_id_);
+    return operand_id_;
+  }
+
+  uint64_t BuildOutput(mojom::GraphInfoPtr& graph_info,
+                       const std::string& name,
+                       const std::vector<uint32_t>& dimensions,
+                       mojom::Operand::DataType type) {
+    auto operand = CreateOperand(name, dimensions, type);
+    operand->kind = mojom::Operand::Kind::kOutput;
+    operand_id_++;
+    CHECK(graph_info->id_to_operand_map.find(operand_id_) ==
+          graph_info->id_to_operand_map.end());
+    graph_info->id_to_operand_map[operand_id_] = std::move(operand);
+    graph_info->output_operands.push_back(operand_id_);
+    return operand_id_;
+  }
+
+  bool ValidateGraph(mojom::GraphInfoPtr graph_info) {
+    return WebNNGraphImpl::ValidateAndBuildGraph(
+        base::BindLambdaForTesting(
+            [&](mojo::PendingRemote<mojom::WebNNGraph> remote) {}),
+        std::move(graph_info));
+  }
+
+ protected:
+  WebNNGraphImplTest() = default;
+  ~WebNNGraphImplTest() override = default;
+
+ private:
+  uint64_t operand_id_ = 0;
+  base::test::TaskEnvironment task_environment_;
+};
+
+struct OperandInfo {
+  mojom::Operand::DataType type;
+  std::vector<uint32_t> dimensions;
+};
+
+struct ElementWiseBinaryTester {
+  mojom::Operator::Kind kind;
+  OperandInfo lhs;
+  OperandInfo rhs;
+  OperandInfo output;
+  bool expected;
+
+  void Test(WebNNGraphImplTest& helper) {
+    // Build the graph with mojo type.
+    auto graph_info = mojom::GraphInfo::New();
+    uint64_t lhs_operand_id =
+        helper.BuildInput(graph_info, "lhs", lhs.dimensions, lhs.type);
+    uint64_t rhs_operand_id =
+        helper.BuildInput(graph_info, "rhs", rhs.dimensions, rhs.type);
+    uint64_t output_operand_id = helper.BuildOutput(
+        graph_info, "output", output.dimensions, output.type);
+    auto operation = CreateOperator(kind, {lhs_operand_id, rhs_operand_id},
+                                    {output_operand_id});
+    graph_info->operators.emplace_back(std::move(operation));
+    auto result = helper.ValidateGraph(std::move(graph_info));
+    EXPECT_EQ(result, expected);
+  }
+};
+
+TEST_F(WebNNGraphImplTest, ElementWiseBinaryTest) {
+  {
+    // Testing building add with two input dimensions - {8, 1, 6, 1} and {7, 1,
+    // 5}. Both the a and b dimensions have axes with length one that are
+    // expanded to a larger size during the broadcast operation.
+    // a_dimensions     (4d) 8 * 1 * 6 * 1
+    // b_dimensions     (3d)     7 * 1 * 5
+    // output_dimenions (4d) 8 * 7 * 6 * 5
+    ElementWiseBinaryTester{
+        .kind = mojom::Operator::Kind::kAdd,
+        .lhs = {.type = mojom::Operand::DataType::kFloat32,
+                .dimensions = {8, 1, 6, 1}},
+        .rhs = {.type = mojom::Operand::DataType::kFloat32,
+                .dimensions = {7, 1, 5}},
+        .output = {.type = mojom::Operand::DataType::kFloat32,
+                   .dimensions = {8, 7, 6, 5}},
+        .expected = true}
+        .Test(*this);
+  }
+  {
+    // Testing building add with two input dimensions - {4, 2, 1} and {4}.
+    // a_dimensions     (3d) 4 * 2 * 1
+    // b_dimensions     (1d)         4
+    // output_dimenions (3d) 4 * 2 * 4
+    ElementWiseBinaryTester{
+        .kind = mojom::Operator::Kind::kSub,
+        .lhs = {.type = mojom::Operand::DataType::kFloat32,
+                .dimensions = {4, 2, 1}},
+        .rhs = {.type = mojom::Operand::DataType::kFloat32, .dimensions = {4}},
+        .output = {.type = mojom::Operand::DataType::kFloat32,
+                   .dimensions = {4, 2, 4}},
+        .expected = true}
+        .Test(*this);
+  }
+  {
+    // Test the invalid graph for the input shapes are not broadcastable.
+    ElementWiseBinaryTester{
+        .kind = mojom::Operator::Kind::kMul,
+        .lhs = {.type = mojom::Operand::DataType::kFloat32,
+                .dimensions = {4, 2}},
+        .rhs = {.type = mojom::Operand::DataType::kFloat32, .dimensions = {4}},
+        .output = {.type = mojom::Operand::DataType::kFloat32,
+                   .dimensions = {4, 2}},
+        .expected = false}
+        .Test(*this);
+  }
+  {
+    // Test the invalid graph for the output shapes are not expected.
+    ElementWiseBinaryTester{
+        .kind = mojom::Operator::Kind::kDiv,
+        .lhs = {.type = mojom::Operand::DataType::kFloat32,
+                .dimensions = {4, 2}},
+        .rhs = {.type = mojom::Operand::DataType::kFloat32,
+                .dimensions = {4, 2}},
+        .output = {.type = mojom::Operand::DataType::kFloat32,
+                   .dimensions = {2}},
+        .expected = false}
+        .Test(*this);
+  }
+  {
+    // Test the invalid graph for input types don't match.
+    ElementWiseBinaryTester{
+        .kind = mojom::Operator::Kind::kMax,
+        .lhs = {.type = mojom::Operand::DataType::kFloat32, .dimensions = {2}},
+        .rhs = {.type = mojom::Operand::DataType::kInt32, .dimensions = {2}},
+        .output = {.type = mojom::Operand::DataType::kFloat32,
+                   .dimensions = {2}},
+        .expected = false}
+        .Test(*this);
+  }
+  {
+    // Test the invalid graph for output types don't match.
+    ElementWiseBinaryTester{
+        .kind = mojom::Operator::Kind::kMin,
+        .lhs = {.type = mojom::Operand::DataType::kFloat32, .dimensions = {2}},
+        .rhs = {.type = mojom::Operand::DataType::kFloat32, .dimensions = {2}},
+        .output = {.type = mojom::Operand::DataType::kInt32, .dimensions = {2}},
+        .expected = false}
+        .Test(*this);
+  }
+}
+
+}  // namespace webnn
diff --git a/testing/buildbot/PRESUBMIT.py b/testing/buildbot/PRESUBMIT.py
index f2c1f27..499a24b 100644
--- a/testing/buildbot/PRESUBMIT.py
+++ b/testing/buildbot/PRESUBMIT.py
@@ -9,7 +9,6 @@
 """
 
 PRESUBMIT_VERSION = '2.0.0'
-USE_PYTHON3 = True
 
 _IGNORE_FREEZE_FOOTER = 'Ignore-Freeze'
 
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index a4b503e..6b551fb 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -5736,9 +5736,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5799.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5801.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 116.0.5799.0",
+        "description": "Run with ash-chrome version 116.0.5801.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5749,8 +5749,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v116.0.5799.0",
-              "revision": "version:116.0.5799.0"
+              "location": "lacros_version_skew_tests_v116.0.5801.0",
+              "revision": "version:116.0.5801.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_v116.0.5799.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5801.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 116.0.5799.0",
+        "description": "Run with ash-chrome version 116.0.5801.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_v116.0.5799.0",
-              "revision": "version:116.0.5799.0"
+              "location": "lacros_version_skew_tests_v116.0.5801.0",
+              "revision": "version:116.0.5801.0"
             }
           ],
           "dimension_sets": [
@@ -6048,9 +6048,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5799.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5801.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 116.0.5799.0",
+        "description": "Run with ash-chrome version 116.0.5801.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -6061,8 +6061,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v116.0.5799.0",
-              "revision": "version:116.0.5799.0"
+              "location": "lacros_version_skew_tests_v116.0.5801.0",
+              "revision": "version:116.0.5801.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json
index c636428f..dcf2aad3 100644
--- a/testing/buildbot/chromium.coverage.json
+++ b/testing/buildbot/chromium.coverage.json
@@ -25494,9 +25494,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5799.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5801.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 116.0.5799.0",
+        "description": "Run with ash-chrome version 116.0.5801.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25507,8 +25507,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v116.0.5799.0",
-              "revision": "version:116.0.5799.0"
+              "location": "lacros_version_skew_tests_v116.0.5801.0",
+              "revision": "version:116.0.5801.0"
             }
           ],
           "dimension_sets": [
@@ -25659,9 +25659,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5799.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5801.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 116.0.5799.0",
+        "description": "Run with ash-chrome version 116.0.5801.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25672,8 +25672,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v116.0.5799.0",
-              "revision": "version:116.0.5799.0"
+              "location": "lacros_version_skew_tests_v116.0.5801.0",
+              "revision": "version:116.0.5801.0"
             }
           ],
           "dimension_sets": [
@@ -25806,9 +25806,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5799.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5801.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 116.0.5799.0",
+        "description": "Run with ash-chrome version 116.0.5801.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -25819,8 +25819,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v116.0.5799.0",
-              "revision": "version:116.0.5799.0"
+              "location": "lacros_version_skew_tests_v116.0.5801.0",
+              "revision": "version:116.0.5801.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 552ab764..b238d48 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -45686,9 +45686,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5799.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5801.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 116.0.5799.0",
+        "description": "Run with ash-chrome version 116.0.5801.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -45698,8 +45698,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v116.0.5799.0",
-              "revision": "version:116.0.5799.0"
+              "location": "lacros_version_skew_tests_v116.0.5801.0",
+              "revision": "version:116.0.5801.0"
             }
           ],
           "dimension_sets": [
@@ -45851,9 +45851,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5799.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5801.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 116.0.5799.0",
+        "description": "Run with ash-chrome version 116.0.5801.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -45863,8 +45863,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v116.0.5799.0",
-              "revision": "version:116.0.5799.0"
+              "location": "lacros_version_skew_tests_v116.0.5801.0",
+              "revision": "version:116.0.5801.0"
             }
           ],
           "dimension_sets": [
@@ -45998,9 +45998,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5799.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5801.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 116.0.5799.0",
+        "description": "Run with ash-chrome version 116.0.5801.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -46010,8 +46010,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v116.0.5799.0",
-              "revision": "version:116.0.5799.0"
+              "location": "lacros_version_skew_tests_v116.0.5801.0",
+              "revision": "version:116.0.5801.0"
             }
           ],
           "dimension_sets": [
@@ -47475,9 +47475,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5799.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5801.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 116.0.5799.0",
+        "description": "Run with ash-chrome version 116.0.5801.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -47487,8 +47487,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v116.0.5799.0",
-              "revision": "version:116.0.5799.0"
+              "location": "lacros_version_skew_tests_v116.0.5801.0",
+              "revision": "version:116.0.5801.0"
             }
           ],
           "dimension_sets": [
@@ -47640,9 +47640,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5799.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5801.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 116.0.5799.0",
+        "description": "Run with ash-chrome version 116.0.5801.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -47652,8 +47652,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v116.0.5799.0",
-              "revision": "version:116.0.5799.0"
+              "location": "lacros_version_skew_tests_v116.0.5801.0",
+              "revision": "version:116.0.5801.0"
             }
           ],
           "dimension_sets": [
@@ -47787,9 +47787,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5799.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5801.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 116.0.5799.0",
+        "description": "Run with ash-chrome version 116.0.5801.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -47799,8 +47799,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v116.0.5799.0",
-              "revision": "version:116.0.5799.0"
+              "location": "lacros_version_skew_tests_v116.0.5801.0",
+              "revision": "version:116.0.5801.0"
             }
           ],
           "dimension_sets": [
@@ -48535,9 +48535,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5799.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5801.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 116.0.5799.0",
+        "description": "Run with ash-chrome version 116.0.5801.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -48547,8 +48547,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v116.0.5799.0",
-              "revision": "version:116.0.5799.0"
+              "location": "lacros_version_skew_tests_v116.0.5801.0",
+              "revision": "version:116.0.5801.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 9fcf5d3..eb9f095 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -18080,12 +18080,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5799.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5801.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 116.0.5799.0",
+        "description": "Run with ash-chrome version 116.0.5801.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -18096,8 +18096,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v116.0.5799.0",
-              "revision": "version:116.0.5799.0"
+              "location": "lacros_version_skew_tests_v116.0.5801.0",
+              "revision": "version:116.0.5801.0"
             }
           ],
           "dimension_sets": [
@@ -18265,12 +18265,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5799.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5801.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 116.0.5799.0",
+        "description": "Run with ash-chrome version 116.0.5801.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -18281,8 +18281,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v116.0.5799.0",
-              "revision": "version:116.0.5799.0"
+              "location": "lacros_version_skew_tests_v116.0.5801.0",
+              "revision": "version:116.0.5801.0"
             }
           ],
           "dimension_sets": [
@@ -18427,12 +18427,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5799.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5801.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 116.0.5799.0",
+        "description": "Run with ash-chrome version 116.0.5801.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -18443,8 +18443,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v116.0.5799.0",
-              "revision": "version:116.0.5799.0"
+              "location": "lacros_version_skew_tests_v116.0.5801.0",
+              "revision": "version:116.0.5801.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/filters/PRESUBMIT.py b/testing/buildbot/filters/PRESUBMIT.py
index b9aa5eeb..f367fb1 100644
--- a/testing/buildbot/filters/PRESUBMIT.py
+++ b/testing/buildbot/filters/PRESUBMIT.py
@@ -11,7 +11,6 @@
 import re
 
 
-USE_PYTHON3 = True
 
 
 def _CheckFilterFileFormat(input_api, output_api):
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 9b3fa37..b60f114b 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_v116.0.5799.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v116.0.5801.0/test_ash_chrome',
     ],
-    'description': 'Run with ash-chrome version 116.0.5799.0',
+    'description': 'Run with ash-chrome version 116.0.5801.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_v116.0.5799.0',
-          'revision': 'version:116.0.5799.0',
+          'location': 'lacros_version_skew_tests_v116.0.5801.0',
+          'revision': 'version:116.0.5801.0',
         },
       ],
     },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index b900f8f..350a39a 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1005,30 +1005,6 @@
             ]
         }
     ],
-    "AutofillAcrossIframes": [
-        {
-            "platforms": [
-                "android",
-                "android_weblayer",
-                "android_webview",
-                "chromeos",
-                "chromeos_lacros",
-                "fuchsia",
-                "ios",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled_20221212",
-                    "enable_features": [
-                        "AutofillAcrossIframes"
-                    ]
-                }
-            ]
-        }
-    ],
     "AutofillAlwaysParsePlaceholders": [
         {
             "platforms": [
@@ -8083,6 +8059,21 @@
             ]
         }
     ],
+    "LoadNotificationsForSameDocumentNavigations": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled_20230519",
+                    "enable_features": [
+                        "LoadNotificationsForSameDocumentNavigations"
+                    ]
+                }
+            ]
+        }
+    ],
     "LockProfileCookieDatabase": [
         {
             "platforms": [
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 1973c811..f682d4e4 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -1763,6 +1763,10 @@
              "ForceHighPerformanceGPUForWebGL",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kCorrectFloatExtensionTestForWebGL,
+             "CorrectFloatExtensionTestForWebGL",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 BASE_FEATURE(kSplitUserMediaQueues,
              "SplitUserMediaQueues",
              base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index 73e8468..3b97fea 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -992,6 +992,10 @@
 // WebGL contexts.
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kForceHighPerformanceGPUForWebGL);
 
+// Enable the correction testing for float extension for webgl version 1.
+// This is simply a killswitch in case we need to restore original behavior.
+BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kCorrectFloatExtensionTestForWebGL);
+
 // Process device and display capture requests on different queues.
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kSplitUserMediaQueues);
 
diff --git a/third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps b/third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps
index b40b15e..5d0d406 100644
--- a/third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps
+++ b/third_party/blink/renderer/bindings/scripts/validate_web_idl.pydeps
@@ -16,11 +16,13 @@
 validator/framework/target_type.py
 validator/framework/validator.py
 validator/rules/__init__.py
+validator/rules/extended_attribute_descriptor.py
 validator/rules/rules_attributes.py
 validator/rules/rules_constants.py
 validator/rules/rules_dictionaries.py
 validator/rules/rules_extended_attributes.py
 validator/rules/rules_function_like.py
+validator/rules/supported_extended_attributes.py
 web_idl/__init__.py
 web_idl/argument.py
 web_idl/ast_group.py
diff --git a/third_party/blink/renderer/bindings/scripts/validator/rules/extended_attribute_descriptor.py b/third_party/blink/renderer/bindings/scripts/validator/rules/extended_attribute_descriptor.py
new file mode 100644
index 0000000..53f646b
--- /dev/null
+++ b/third_party/blink/renderer/bindings/scripts/validator/rules/extended_attribute_descriptor.py
@@ -0,0 +1,126 @@
+# 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.
+
+import enum
+
+import web_idl
+
+
+class ExtendedAttributeDescriptor(object):
+    class Target(enum.Enum):
+        ATTRIBUTE = web_idl.Attribute
+        CALLBACK_FUNCTION = web_idl.CallbackFunction
+        CALLBACK_INTERFACE = web_idl.CallbackInterface
+        CONSTANT = web_idl.Constant
+        CONSTRUCTOR = web_idl.Constructor
+        DICTIONARY = web_idl.Dictionary
+        DICTIONARY_MEMBER = web_idl.DictionaryMember
+        INTERFACE = web_idl.Interface
+        LEGACY_WINDOW_ALIAS = web_idl.LegacyWindowAlias
+        NAMESPACE = web_idl.Namespace
+        OPERATION = web_idl.Operation
+        TYPE = web_idl.IdlType
+
+    class Form(enum.Enum):
+        # https://webidl.spec.whatwg.org/#idl-extended-attributes
+        NO_ARGS = enum.auto()  # [ExtAttr]
+        IDENT = enum.auto()  # [ExtAttr=Value]
+        IDENT_LIST = enum.auto()  # [ExtAttr=(Value1, ...)]
+        ARG_LIST = enum.auto()  # [ExtAttr(V1L V1R, ...)]
+        NAMED_ARG_LIST = enum.auto()  # [ExtAttr=Name(V1L V1R, ...)]
+
+    def __init__(self,
+                 name,
+                 applicable_to=None,
+                 forms=None,
+                 values=None,
+                 post_validate=None):
+        assert isinstance(name, str)
+        assert isinstance(applicable_to, list) and all(
+            isinstance(target, ExtendedAttributeDescriptor.Target)
+            for target in applicable_to)
+        assert forms is None or isinstance(
+            forms, ExtendedAttributeDescriptor.Form) or (isinstance(
+                forms, list) and all(
+                    isinstance(form, ExtendedAttributeDescriptor.Form)
+                    for form in forms))
+        assert values is None or (isinstance(values, list) and all(
+            isinstance(value, str) for value in values))
+        assert post_validate is None or callable(post_validate)
+
+        self._name = name
+        # self._applicable_to is a list of valid target object's types, e.g.
+        # web_idl.Attribute, web_idl.Constant, etc.
+        self._applicable_to = tuple(map(lambda e: e.value, applicable_to))
+        # self._forms is a list of valid forms.
+        if forms is None:
+            self._forms = [ExtendedAttributeDescriptor.Form.NO_ARGS]
+        elif not isinstance(forms, list):
+            self._forms = [forms]
+        else:
+            self._forms = forms
+        # self._values is a list of valid "ident" values
+        if values is None:
+            self._values = None
+        else:
+            assert (ExtendedAttributeDescriptor.Form.IDENT in self._forms or
+                    ExtendedAttributeDescriptor.Form.IDENT_LIST in self._forms)
+            self._values = values
+        # self._post_validate is a callable or None.
+        self._post_validate = post_validate
+
+    @property
+    def name(self):
+        return self._name
+
+    def validate(self, assert_, target_object, ext_attr):
+        T = ExtendedAttributeDescriptor.Target
+        F = ExtendedAttributeDescriptor.Form
+
+        failure_count = [0]
+
+        def _assert(condition, text, *args, **kwargs):
+            if not condition:
+                failure_count[0] = failure_count[0] + 1
+                assert_(condition, text, *args, **kwargs)
+
+        # applicable_to
+        _assert(isinstance(target_object, self._applicable_to),
+                "[{}] is not applicable to {}.", self._name,
+                target_object.__class__.__name__)
+
+        # forms
+        if ext_attr.has_values:
+            if not ext_attr.values:
+                _assert(F.NO_ARGS in self._forms,
+                        "[{}] needs an identifier or an argument list.",
+                        self._name)
+            elif F.IDENT_LIST in self._forms:
+                pass
+            elif F.IDENT in self._forms:
+                _assert(
+                    len(ext_attr.values) == 1,
+                    "[{}] doesn't take an identifier list.", self._name)
+            elif F.ARG_LIST in self._forms or F.NAMED_ARG_LIST in self._forms:
+                _assert(False, "[{}] needs an argument list.", self._name)
+            else:  # F.NO_ARGS only
+                _assert(False, "[{}] doesn't take an identifier.", self._name)
+        if ext_attr.has_arguments:
+            _assert(
+                F.ARG_LIST in self._forms or F.NAMED_ARG_LIST in self._forms,
+                "[{}] doesn't take an argument list.", self._name)
+        if ext_attr.has_name:
+            _assert(F.NAMED_ARG_LIST in self._forms,
+                    "[{}] doesn't take an named argument list.", self._name)
+
+        # values
+        if self._values:
+            for value in ext_attr.values:
+                _assert(value in self._values, "[{}={}] is not supported.",
+                        self._name, value)
+
+        # post_validate
+        if self._post_validate:
+            if failure_count[0] == 0:
+                self._post_validate(assert_, target_object, ext_attr)
diff --git a/third_party/blink/renderer/bindings/scripts/validator/rules/rules_extended_attributes.py b/third_party/blink/renderer/bindings/scripts/validator/rules/rules_extended_attributes.py
index 84ad22e..db01bf6 100644
--- a/third_party/blink/renderer/bindings/scripts/validator/rules/rules_extended_attributes.py
+++ b/third_party/blink/renderer/bindings/scripts/validator/rules/rules_extended_attributes.py
@@ -8,51 +8,26 @@
 Each rule class must inherit RuleBase.
 """
 
-from validator.framework import target
+from . import supported_extended_attributes
 from validator.framework import RuleBase
-
-_web_idl_extended_attributes_applicable_to_types = [
-    "AllowShared",
-    "Clamp",
-    "EnforceRange",
-    "LegacyNullToEmptyString",
-]
-_blink_specific_extended_attributes_applicable_to_types = [
-    "BufferSourceTypeNoSizeLimit",
-    "FlexibleArrayBufferView",
-    "StringContext",
-    # "TreatNullAs" is the old version of "LegacyNullToEmptyString".
-    "TreatNullAs",
-]
-_extended_attributes_applicable_to_types = (
-    _web_idl_extended_attributes_applicable_to_types +
-    _blink_specific_extended_attributes_applicable_to_types)
+from validator.framework import target
 
 
-class ExtendedAttributesApplicableToTypes(RuleBase):
+class ExtendedAttributesOnNonType(RuleBase):
     def validate(self, assert_, target_object):
-        web_idl_link = "https://webidl.spec.whatwg.org/#extended-attributes-applicable-to-types"
-        for extended_attribute in target_object.extended_attributes.keys():
-            assert_(
-                extended_attribute not in
-                _extended_attributes_applicable_to_types,
-                ("Extended attribute '{}' is applicable to types, "
-                 "but applied in the wrong context. See {}"),
-                extended_attribute, web_idl_link)
+        for ext_attr in target_object.extended_attributes:
+            supported_extended_attributes.validate(assert_, target_object,
+                                                   ext_attr)
 
 
-class ExtendedAttributesApplicableToTypesForIdlType(RuleBase):
+class ExtendedAttributesOnType(RuleBase):
     def validate(self, assert_, target_object):
-        web_idl_link = "https://webidl.spec.whatwg.org/#extended-attributes-applicable-to-types"
-        for annotation in target_object.effective_annotations:
-            assert_(annotation.key in _extended_attributes_applicable_to_types,
-                    ("Extended attribute '{}' is not applicable to types, "
-                     "but applied to a type. See {}"), annotation.key,
-                    web_idl_link)
+        for ext_attr in target_object.effective_annotations:
+            supported_extended_attributes.validate(assert_, target_object,
+                                                   ext_attr)
 
 
 def register_rules(rule_store):
     rule_store.register(target.OBJECTS_WITH_EXTENDED_ATTRIBUTES,
-                        ExtendedAttributesApplicableToTypes())
-    rule_store.register(target.IDL_TYPES,
-                        ExtendedAttributesApplicableToTypesForIdlType())
+                        ExtendedAttributesOnNonType())
+    rule_store.register(target.IDL_TYPES, ExtendedAttributesOnType())
diff --git a/third_party/blink/renderer/bindings/scripts/validator/rules/supported_extended_attributes.py b/third_party/blink/renderer/bindings/scripts/validator/rules/supported_extended_attributes.py
new file mode 100644
index 0000000..0f795f8
--- /dev/null
+++ b/third_party/blink/renderer/bindings/scripts/validator/rules/supported_extended_attributes.py
@@ -0,0 +1,214 @@
+# 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.
+
+from .extended_attribute_descriptor import ExtendedAttributeDescriptor
+
+
+def _build_supported_extended_attributes():
+    E = ExtendedAttributeDescriptor
+    T = ExtendedAttributeDescriptor.Target
+    F = ExtendedAttributeDescriptor.Form
+
+    # T_EXPOSURE is used at 'applicable_to' if an extended attribute changes
+    # the exposure of the IDL construct.
+    T_EXPOSURE = [
+        T.ATTRIBUTE, T.CALLBACK_INTERFACE, T.CONSTANT, T.CONSTRUCTOR,
+        T.DICTIONARY_MEMBER, T.INTERFACE, T.LEGACY_WINDOW_ALIAS, T.NAMESPACE,
+        T.OPERATION
+    ]
+    # V_CALL_WITH is used at 'values' of [CallWith], [GetterCallWith], and
+    # [SetterCallWith].
+    V_CALL_WITH = [
+        "Document", "ExecutionContext", "Isolate", "ScriptState", "ThisValue"
+    ]
+
+    # pv_readonly_attribute is used at 'post_validate' when an extended
+    # attribute is applicable only to readonly attributes.
+    def pv_readonly_attribute(assert_, target_object, ext_attr):
+        assert_(target_object.is_readonly,
+                "[{}] is applicable only to readonly attributes.",
+                ext_attr.key)
+
+    # Each entry must be in the form of:
+    #
+    #     E("name of an extended attribute",
+    #       applicable_to=[T.TARGET1, T.TARGET2, ...],
+    #       forms=[F.FORM1, F.FORM2, ...],
+    #       values=["allowed value 1", "allowed value 2", ...],
+    #       post_validate=func)
+    #
+    # where 'forms', 'values', and 'post_validate' are optional. If not
+    # specified, it defaults to
+    # 'forms=F.NO_ARGS' (doesn't take any argument/option),
+    # 'values=None' (any argument/option is allowed), and
+    # 'post_validate=None' (no additional validation).
+    descriptors = [
+        E("ActiveScriptWrappable", applicable_to=[T.INTERFACE]),
+        E("Affects",
+          applicable_to=[T.ATTRIBUTE, T.OPERATION],
+          forms=F.IDENT,
+          values=["Everything", "Nothing"]),
+        E("AllowShared", applicable_to=[T.TYPE]),
+        E("BufferSourceTypeNoSizeLimit", applicable_to=[T.TYPE]),
+        E("CEReactions", applicable_to=[T.ATTRIBUTE, T.OPERATION]),
+        E("CachedAccessor",
+          applicable_to=[T.ATTRIBUTE],
+          forms=F.IDENT,
+          post_validate=pv_readonly_attribute),
+        E("CachedAttribute",
+          applicable_to=[T.ATTRIBUTE],
+          forms=F.IDENT,
+          post_validate=pv_readonly_attribute),
+        E("CallWith",
+          applicable_to=[T.ATTRIBUTE, T.CONSTRUCTOR, T.OPERATION],
+          forms=[F.IDENT, F.IDENT_LIST],
+          values=V_CALL_WITH),
+        E("CheckSecurity",
+          applicable_to=[T.ATTRIBUTE, T.OPERATION],
+          forms=[F.IDENT, F.IDENT_LIST],
+          values=["ReturnValue"]),
+        E("Clamp", applicable_to=[T.TYPE]),
+        E("ContextEnabled", applicable_to=T_EXPOSURE, forms=F.IDENT),
+        E("CrossOrigin",
+          applicable_to=[T.ATTRIBUTE, T.OPERATION],
+          forms=[F.NO_ARGS, F.IDENT, F.IDENT_LIST],
+          values=["Getter", "Setter"]),
+        E("CrossOriginIsolated", applicable_to=T_EXPOSURE),
+        E("Custom",
+          applicable_to=[T.ATTRIBUTE, T.OPERATION],
+          forms=[F.NO_ARGS, F.IDENT],
+          values=["Getter", "Setter"]),
+        E("DeprecateAs",
+          applicable_to=[
+              T.ATTRIBUTE, T.CONSTANT, T.CONSTRUCTOR, T.DICTIONARY_MEMBER,
+              T.OPERATION
+          ],
+          forms=F.IDENT),
+        E("EnforceRange", applicable_to=[T.TYPE]),
+        E("Exposed",
+          applicable_to=T_EXPOSURE,
+          forms=[F.IDENT, F.IDENT_LIST, F.ARG_LIST]),
+        E("FlexibleArrayBufferView", applicable_to=[T.TYPE]),
+        E("GetterCallWith",
+          applicable_to=[T.ATTRIBUTE],
+          forms=[F.IDENT, F.IDENT_LIST],
+          values=V_CALL_WITH),
+        E("Global", applicable_to=[T.INTERFACE], forms=[F.IDENT,
+                                                        F.IDENT_LIST]),
+        E("HighEntropy",
+          applicable_to=[T.ATTRIBUTE, T.CONSTRUCTOR, T.OPERATION],
+          forms=[F.NO_ARGS, F.IDENT],
+          values=["Direct"]),
+        E("HTMLConstructor", applicable_to=[T.CONSTRUCTOR, T.INTERFACE]),
+        E("ImplementedAs",
+          applicable_to=[
+              T.ATTRIBUTE, T.CONSTRUCTOR, T.DICTIONARY, T.DICTIONARY_MEMBER,
+              T.INTERFACE, T.NAMESPACE, T.OPERATION
+          ],
+          forms=F.IDENT),
+        E("IsCodeLike", applicable_to=[T.INTERFACE]),
+        E("IsolatedContext", applicable_to=T_EXPOSURE),
+        E("LegacyLenientSetter", applicable_to=[T.ATTRIBUTE]),
+        E("LegacyLenientThis", applicable_to=[T.ATTRIBUTE]),
+        E("LegacyNoInterfaceObject", applicable_to=[T.INTERFACE]),
+        E("LegacyOverrideBuiltIns", applicable_to=[T.INTERFACE]),
+        E("LegacyTreatNonObjectAsNull", applicable_to=[T.CALLBACK_FUNCTION]),
+        E("LegacyUnenumerableNamedProperties", applicable_to=[T.INTERFACE]),
+        E("LegacyUnforgeable", applicable_to=[T.ATTRIBUTE, T.OPERATION]),
+        E("LegacyWindowAlias", applicable_to=[T.INTERFACE], forms=F.IDENT),
+        E("LegacyWindowAlias_Measure", applicable_to=[T.INTERFACE]),
+        E("LegacyWindowAlias_MeasureAs",
+          applicable_to=[T.INTERFACE],
+          forms=F.IDENT),
+        E("LegacyWindowAlias_RuntimeEnabled",
+          applicable_to=[T.INTERFACE],
+          forms=F.IDENT),
+        E("LogActivity",
+          applicable_to=[T.ATTRIBUTE, T.OPERATION],
+          forms=[F.NO_ARGS, F.IDENT],
+          values=["GetterOnly", "SetterOnly"]),
+        E("LogAllWorlds", applicable_to=[T.OPERATION]),
+        E("Measure",
+          applicable_to=[
+              T.ATTRIBUTE, T.CONSTANT, T.CONSTRUCTOR, T.DICTIONARY_MEMBER,
+              T.LEGACY_WINDOW_ALIAS, T.OPERATION
+          ]),
+        E("MeasureAs",
+          applicable_to=[
+              T.ATTRIBUTE, T.CONSTANT, T.CONSTRUCTOR, T.DICTIONARY_MEMBER,
+              T.LEGACY_WINDOW_ALIAS, T.OPERATION
+          ],
+          forms=F.IDENT),
+        E("NamedConstructor",
+          applicable_to=[T.INTERFACE],
+          forms=F.NAMED_ARG_LIST),
+        E("NamedConstructor_CallWith",
+          applicable_to=[T.INTERFACE],
+          forms=[F.IDENT, F.IDENT_LIST],
+          values=V_CALL_WITH),
+        E("NamedConstructor_RaisesException", applicable_to=[T.INTERFACE]),
+        E("NewObject", applicable_to=[T.OPERATION]),
+        E("NoAllocDirectCall", applicable_to=[T.OPERATION]),
+        E("NotEnumerable", applicable_to=[T.ATTRIBUTE, T.OPERATION]),
+        E("PermissiveDictionaryConversion", applicable_to=[T.DICTIONARY]),
+        E("PerWorldBindings", applicable_to=[T.ATTRIBUTE, T.OPERATION]),
+        E("PutForwards",
+          applicable_to=[T.ATTRIBUTE],
+          forms=F.IDENT,
+          post_validate=pv_readonly_attribute),
+        E("RaisesException",
+          applicable_to=[T.ATTRIBUTE, T.CONSTRUCTOR, T.OPERATION],
+          forms=[F.NO_ARGS, F.IDENT],
+          values=["Getter", "Setter"]),
+        E("Reflect", applicable_to=[T.ATTRIBUTE], forms=[F.NO_ARGS, F.IDENT]),
+        E("ReflectEmpty", applicable_to=[T.ATTRIBUTE], forms=F.IDENT),
+        E("ReflectInvalid", applicable_to=[T.ATTRIBUTE], forms=F.IDENT),
+        E("ReflectMissing", applicable_to=[T.ATTRIBUTE], forms=F.IDENT),
+        E("ReflectOnly", applicable_to=[T.ATTRIBUTE], forms=F.IDENT_LIST),
+        E("Replaceable",
+          applicable_to=[T.ATTRIBUTE],
+          post_validate=pv_readonly_attribute),
+        E("RuntimeEnabled", applicable_to=T_EXPOSURE, forms=F.IDENT),
+        E("RuntimeCallStatsCounter",
+          applicable_to=[T.ATTRIBUTE, T.OPERATION],
+          forms=F.IDENT),
+        E("SameObject", applicable_to=[T.ATTRIBUTE]),
+        E("SaveSameObject", applicable_to=[T.ATTRIBUTE]),
+        E("SecureContext", applicable_to=T_EXPOSURE),
+        E("Serializable", applicable_to=[T.INTERFACE]),
+        E("SetterCallWith",
+          applicable_to=[T.ATTRIBUTE],
+          forms=[F.IDENT, F.IDENT_LIST],
+          values=V_CALL_WITH),
+        E("StringContext",
+          applicable_to=[T.TYPE],
+          forms=F.IDENT,
+          values=["TrustedHTML", "TrustedScript", "TrustedScriptURL"]),
+        E("SupportsTaskAttribution", applicable_to=[T.CALLBACK_FUNCTION]),
+        E("TargetOfExposed", applicable_to=[T.INTERFACE], forms=F.IDENT),
+        E("Transferable", applicable_to=[T.INTERFACE]),
+        E("TreatNullAs",
+          applicable_to=[T.TYPE],
+          forms=F.IDENT,
+          values=["EmptyString"]),
+        E("URL", applicable_to=[T.ATTRIBUTE]),
+        E("Unscopable", applicable_to=[T.ATTRIBUTE, T.OPERATION]),
+    ]
+
+    desc_map = dict()
+    for desc in descriptors:
+        desc_map[desc.name] = desc
+    return desc_map
+
+
+_SUPPORTED_EXTENDED_ATTRIBUTES = _build_supported_extended_attributes()
+
+
+def validate(assert_, target_object, ext_attr):
+    desc = _SUPPORTED_EXTENDED_ATTRIBUTES.get(ext_attr.key)
+    if desc:
+        desc.validate(assert_, target_object, ext_attr)
+    else:
+        assert_(False, "[{}] is an unknown IDL extended attribute.",
+                ext_attr.key)
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute.py b/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute.py
index cac2255..071b795 100644
--- a/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute.py
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/extended_attribute.py
@@ -141,6 +141,10 @@
             self.syntactic_form))
 
     @property
+    def has_name(self):
+        return self._format == self._FORM_NAMED_ARG_LIST
+
+    @property
     def name(self):
         """
         Returns |Name| for format NamedArgList.  Otherwise, raises a ValueError.
diff --git a/third_party/blink/renderer/modules/ml/BUILD.gn b/third_party/blink/renderer/modules/ml/BUILD.gn
index 6d33320..e45129f5 100644
--- a/third_party/blink/renderer/modules/ml/BUILD.gn
+++ b/third_party/blink/renderer/modules/ml/BUILD.gn
@@ -76,6 +76,8 @@
       # renderer process.
       "webnn/ml_graph_mojo.cc",
       "webnn/ml_graph_mojo.h",
+      "webnn/ml_graph_type_converter.cc",
+      "webnn/ml_graph_type_converter.h",
     ]
   }
 }
diff --git a/third_party/blink/renderer/modules/ml/ml_context.cc b/third_party/blink/renderer/modules/ml/ml_context.cc
index 1be0f92..6172779 100644
--- a/third_party/blink/renderer/modules/ml/ml_context.cc
+++ b/third_party/blink/renderer/modules/ml/ml_context.cc
@@ -113,6 +113,7 @@
 }
 
 void MLContext::CreateWebNNGraph(ScriptState* script_state,
+                                 webnn::mojom::blink::GraphInfoPtr graph_info,
                                  CreateWebNNGraphCallback callback) {
   if (!webnn_context_.is_bound()) {
     // Needs to create `WebNNContext` interface first.
@@ -121,16 +122,19 @@
     ml_->CreateWebNNContext(
         std::move(options),
         WTF::BindOnce(&MLContext::OnCreateWebNNContext, WrapPersistent(this),
-                      WrapPersistent(script_state), std::move(callback)));
+                      WrapPersistent(script_state), std::move(graph_info),
+                      std::move(callback)));
   } else {
     // Directly use `WebNNContext` to create `WebNNGraph` message pipe.
     webnn_context_->CreateGraph(
+        std::move(graph_info),
         WTF::BindOnce(std::move(callback), CreateWebNNGraphResult::kOk));
   }
 }
 
 void MLContext::OnCreateWebNNContext(
     ScriptState* script_state,
+    webnn::mojom::blink::GraphInfoPtr graph_info,
     CreateWebNNGraphCallback callback,
     webnn::mojom::blink::CreateContextResult result,
     mojo::PendingRemote<webnn::mojom::blink::WebNNContext>
@@ -158,6 +162,7 @@
           execution_context->GetTaskRunner(TaskType::kInternalDefault));
 
       webnn_context_->CreateGraph(
+          std::move(graph_info),
           WTF::BindOnce(std::move(callback), CreateWebNNGraphResult::kOk));
       return;
     }
diff --git a/third_party/blink/renderer/modules/ml/ml_context.h b/third_party/blink/renderer/modules/ml/ml_context.h
index fffc8b13..5e2c2a6 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_graph.mojom-blink.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"
@@ -69,6 +70,7 @@
       CreateWebNNGraphResult result,
       mojo::PendingRemote<webnn::mojom::blink::WebNNGraph>)>;
   void CreateWebNNGraph(ScriptState* script_state,
+                        webnn::mojom::blink::GraphInfoPtr graph_info,
                         CreateWebNNGraphCallback callback);
 
  private:
@@ -84,6 +86,7 @@
   // The callback of creating context called from WebNN server side.
   void OnCreateWebNNContext(
       ScriptState* script_state,
+      webnn::mojom::blink::GraphInfoPtr graph_info,
       CreateWebNNGraphCallback callback,
       webnn::mojom::blink::CreateContextResult result,
       mojo::PendingRemote<webnn::mojom::blink::WebNNContext>
diff --git a/third_party/blink/renderer/modules/ml/webnn/OWNERS b/third_party/blink/renderer/modules/ml/webnn/OWNERS
index 608fe8f..91a2f0f 100644
--- a/third_party/blink/renderer/modules/ml/webnn/OWNERS
+++ b/third_party/blink/renderer/modules/ml/webnn/OWNERS
@@ -1,2 +1,4 @@
 per-file ml_graph_mojo.*=ningxin.hu@intel.com
 per-file ml_graph_mojo.*=rafael.cintron@microsoft.com
+per-file *_type_converter*.*=set noparent
+per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
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
index 04d3051..6fa7c683 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo.cc
@@ -9,9 +9,101 @@
 #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"
+#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.h"
+#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.h"
+#include "third_party/blink/renderer/modules/ml/webnn/ml_operand.h"
 
 namespace blink {
 
+namespace {
+
+webnn::mojom::blink::GraphInfoPtr BuildWebNNGraphInfo(
+    const MLNamedOperands& named_outputs) {
+  // The `GraphInfo` represents an entire information of WebNN graph.
+  auto graph_info = webnn::mojom::blink::GraphInfo::New();
+  // The id used to identify operand on the server side. Each operation
+  // generates an output operand that will be inserted in a hash map with the
+  // MLOperand and id, incrementing the id by one.
+  uint64_t operand_id = 0;
+  HeapHashMap<Member<const MLOperand>, uint64_t> operand_to_id_map;
+  for (const auto& [name, operand] : named_outputs) {
+    // Create `mojo::Operand` for output operands of graph with the name.
+    auto output_operand =
+        mojo::ConvertTo<webnn::mojom::blink::OperandPtr>(operand.Get());
+    output_operand->name = name;
+    operand_id++;
+    graph_info->id_to_operand_map.insert(operand_id, std::move(output_operand));
+    graph_info->output_operands.push_back(operand_id);
+    operand_to_id_map.insert(operand, operand_id);
+  }
+
+  HeapVector<Member<const MLOperator>>* topologically_sorted_operators =
+      GetOperatorsInTopologicalOrder(named_outputs);
+  // Visit the operators in topological order. For each operator,
+  // 1, Create `mojo::Operand` for its input and output operands if needed.
+  // 2, Create `mojo::Operator` with the id of input and output operands.
+  for (const auto& current_operator : *topologically_sorted_operators) {
+    for (const auto& operand : current_operator->Inputs()) {
+      if (operand_to_id_map.Contains(operand.Get())) {
+        // The `mojo::Operand` is already converted with the MLOperand, skip it.
+        continue;
+      }
+      switch (operand->Kind()) {
+        case MLOperand::OperandKind::kInput: {
+          // Create `mojo::Operand` for the input MLOperand.
+          operand_id++;
+          graph_info->id_to_operand_map.insert(
+              operand_id,
+              mojo::ConvertTo<webnn::mojom::blink::OperandPtr>(operand.Get()));
+          //  Build the array of input operands for this graph with the id.
+          graph_info->input_operands.push_back(operand_id);
+          operand_to_id_map.insert(operand, operand_id);
+          break;
+        }
+        case MLOperand::OperandKind::kConstant: {
+          // TODO(crbug.com/1273291): Convert `mojo::Operand` for constant
+          // operand.
+          NOTIMPLEMENTED();
+          return nullptr;
+        }
+        case MLOperand::OperandKind::kOutput:
+          // Because the operators are visited in topological order, if this
+          // operand is an intermediate operand, it should already be defined as
+          // an output operand of the dependent operator.
+          NOTREACHED_NORETURN();
+      }
+    }
+
+    for (const auto& operand : current_operator->Outputs()) {
+      if (operand_to_id_map.Contains(operand.Get())) {
+        // The `mojo::Operand` is already converted with the MLOperand, skip it.
+        continue;
+      }
+      // Because the graph's output operands are already converted before, this
+      // operand should be an intermediate operand that connects with two
+      // operators. Create `mojo::Operand` for this operand.
+      operand_id++;
+      graph_info->id_to_operand_map.insert(
+          operand_id,
+          mojo::ConvertTo<webnn::mojom::blink::OperandPtr>(operand.Get()));
+      operand_to_id_map.insert(operand, operand_id);
+    }
+
+    // Create `mojo::Operator` with the id of the input and output operands.
+    auto operation =
+        ConvertToMojoOperator(operand_to_id_map, current_operator.Get());
+    if (!operation) {
+      // Return here if the operator is not implemented.
+      return nullptr;
+    }
+    graph_info->operators.emplace_back(std::move(operation));
+  }
+
+  return graph_info;
+}
+
+}  // namespace
+
 // static
 void MLGraphMojo::ValidateAndBuildAsync(MLContext* context,
                                         const MLNamedOperands& named_outputs,
@@ -33,13 +125,18 @@
 
 void MLGraphMojo::BuildAsyncImpl(const MLNamedOperands& outputs,
                                  ScriptPromiseResolver* resolver) {
-  auto* named_outputs = MakeGarbageCollected<MLNamedOperands>(outputs);
+  auto graph_info = BuildWebNNGraphInfo(outputs);
+  if (!graph_info) {
+    resolver->Reject(MakeGarbageCollected<DOMException>(
+        DOMExceptionCode::kDataError, "Failed to build graph."));
+    return;
+  }
   // Create `WebNNGraph` message pipe with `WebNNContext` mojo interface.
   auto* script_state = resolver->GetScriptState();
   ml_context_->CreateWebNNGraph(
-      script_state,
+      script_state, std::move(graph_info),
       WTF::BindOnce(&MLGraphMojo::OnCreateWebNNGraph, WrapPersistent(this),
-                    WrapPersistent(resolver), WrapPersistent(named_outputs)));
+                    WrapPersistent(resolver)));
 }
 
 MLGraph* MLGraphMojo::BuildSyncImpl(const MLNamedOperands& named_outputs,
@@ -74,7 +171,6 @@
 
 void MLGraphMojo::OnCreateWebNNGraph(
     ScriptPromiseResolver* resolver,
-    const MLNamedOperands* named_output,
     MLContext::CreateWebNNGraphResult result,
     mojo::PendingRemote<webnn::mojom::blink::WebNNGraph> pending_remote) {
   switch (result) {
@@ -97,7 +193,6 @@
           std::move(pending_remote),
           execution_context->GetTaskRunner(TaskType::kInternalDefault));
 
-      // TODO(crbug.com/1273291): Build the graph in the WebNN Service.
       resolver->Resolve(this);
       return;
     }
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
index 548a70f..f2526ea 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo.h
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo.h
@@ -9,7 +9,6 @@
 #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"
 
@@ -57,12 +56,11 @@
   // 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.
+  // The `WebNNGraph` is compiled graph that can be executed by the hardware
+  // accelerated OS machine learning API.
   HeapMojoRemote<webnn::mojom::blink::WebNNGraph> remote_graph_;
 };
 
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.cc
index 3053970..8946a8d 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.cc
@@ -36,6 +36,9 @@
     case BackendType::kModelLoader:
       name += "ModelLoader_";
       break;
+    case BackendType::kWebNNService:
+      name += "WebNNService_";
+      break;
   }
 
   switch (execution_mode) {
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.h b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.h
index 1176798..a560a20 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.h
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.h
@@ -24,7 +24,7 @@
 // The utility methods for graph test.
 enum ExecutionMode { kAsync, kSync };
 // The backends share the unit tests in the MLGraphTest.
-enum BackendType { kFake, kXnnpack, kModelLoader };
+enum BackendType { kFake, kXnnpack, kModelLoader, kWebNNService };
 
 using TestVariety = std::tuple<BackendType, ExecutionMode>;
 
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
index a29837f..c95c369 100644
--- 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
@@ -21,11 +21,24 @@
 #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"
+#include "third_party/blink/renderer/modules/ml/webnn/ml_graph_test_base.h"
 
 namespace blink {
 
 namespace blink_mojom = webnn::mojom::blink;
 
+class MLGraphTestMojo : public MLGraphTestBase {
+ public:
+  void SetGraphInfo(blink_mojom::GraphInfoPtr graph_info) {
+    graph_info_ = std::move(graph_info);
+  }
+
+  blink_mojom::GraphInfoPtr GetGraphInfo() { return std::move(graph_info_); }
+
+ private:
+  blink_mojom::GraphInfoPtr graph_info_;
+};
+
 class FakeWebNNGraph : public blink_mojom::WebNNGraph {
  public:
   FakeWebNNGraph() = default;
@@ -40,14 +53,17 @@
 
 class FakeWebNNContext : public blink_mojom::WebNNContext {
  public:
-  FakeWebNNContext() = default;
+  explicit FakeWebNNContext(MLGraphTestMojo& helper) : helper_(helper) {}
   FakeWebNNContext(const FakeWebNNContext&) = delete;
   FakeWebNNContext(FakeWebNNContext&&) = delete;
   ~FakeWebNNContext() override = default;
 
  private:
   // Override methods from webnn::mojom::WebNNContext.
-  void CreateGraph(CreateGraphCallback callback) override {
+  void CreateGraph(blink_mojom::GraphInfoPtr graph_info,
+                   CreateGraphCallback callback) override {
+    helper_.SetGraphInfo(std::move(graph_info));
+
     mojo::PendingRemote<blink_mojom::WebNNGraph> blink_remote;
     // The receiver bind to FakeWebNNGraph.
     mojo::MakeSelfOwnedReceiver<blink_mojom::WebNNGraph>(
@@ -56,11 +72,13 @@
 
     std::move(callback).Run(std::move(blink_remote));
   }
+  MLGraphTestMojo& helper_;
 };
 
 class FakeWebNNContextProvider : public blink_mojom::WebNNContextProvider {
  public:
-  FakeWebNNContextProvider() : receiver_(this) {}
+  explicit FakeWebNNContextProvider(MLGraphTestMojo& helper)
+      : helper_(helper), receiver_(this) {}
   FakeWebNNContextProvider(const FakeWebNNContextProvider&) = delete;
   FakeWebNNContextProvider(FakeWebNNContextProvider&&) = delete;
   ~FakeWebNNContextProvider() override = default;
@@ -84,21 +102,23 @@
     mojo::PendingRemote<blink_mojom::WebNNContext> blink_remote;
     // The receiver bind to FakeWebNNContext.
     mojo::MakeSelfOwnedReceiver<blink_mojom::WebNNContext>(
-        std::make_unique<FakeWebNNContext>(),
+        std::make_unique<FakeWebNNContext>(helper_),
         blink_remote.InitWithNewPipeAndPassReceiver());
 
     std::move(callback).Run(blink_mojom::CreateContextResult::kOk,
                             std::move(blink_remote));
   }
 
+  MLGraphTestMojo& helper_;
   mojo::Receiver<blink_mojom::WebNNContextProvider> receiver_;
 };
 
 class ScopedWebNNServiceBinder {
  public:
-  explicit ScopedWebNNServiceBinder(V8TestingScope& scope)
+  explicit ScopedWebNNServiceBinder(MLGraphTestMojo& helper,
+                                    V8TestingScope& scope)
       : fake_webnn_context_provider_(
-            std::make_unique<FakeWebNNContextProvider>()),
+            std::make_unique<FakeWebNNContextProvider>(helper)),
         interface_broker_(
             scope.GetExecutionContext()->GetBrowserInterfaceBroker()) {
     interface_broker_.SetBinderForTesting(
@@ -122,8 +142,6 @@
   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());
@@ -134,19 +152,30 @@
                                MLContextOptions* context_options) {
   auto* builder =
       CreateMLGraphBuilder(scope.GetExecutionContext(), context_options);
-  auto* input =
-      BuildInput(builder, "input", {3, 4, 5}, V8MLOperandType::Enum::kFloat32,
+  auto* lhs_operand =
+      BuildInput(builder, "lhs", {3, 4, 5}, V8MLOperandType::Enum::kFloat32,
                  scope.GetExceptionState());
-  auto* output = builder->relu(input, scope.GetExceptionState());
+  auto* rhs_operand =
+      BuildInput(builder, "rhs", {3, 4, 5}, V8MLOperandType::Enum::kFloat32,
+                 scope.GetExceptionState());
+  auto* output =
+      builder->add(lhs_operand, rhs_operand, scope.GetExceptionState());
   EXPECT_NE(output, nullptr);
   return builder->build(scope.GetScriptState(), {{"output", output}},
                         scope.GetExceptionState());
 }
 
-TEST_F(MLGraphTestMojo, CreateWebNNGraphTest) {
+struct OperandInfoMojo {
+  blink_mojom::Operand::DataType type;
+  Vector<uint32_t> dimensions;
+};
+
+using OperandInfoBlink = OperandInfo<float>;
+
+TEST_P(MLGraphTestMojo, CreateWebNNGraphTest) {
   V8TestingScope scope;
   // Bind fake WebNN Context in the service for testing.
-  ScopedWebNNServiceBinder scoped_setup_binder(scope);
+  ScopedWebNNServiceBinder scoped_setup_binder(*this, scope);
 
   auto* script_state = scope.GetScriptState();
   auto* options = MLContextOptions::Create();
@@ -183,4 +212,138 @@
   }
 }
 
+struct ElementWiseBinaryTester {
+  ElementWiseBinaryKind kind;
+  OperandInfoBlink lhs;
+  OperandInfoBlink rhs;
+  OperandInfoMojo expected;
+
+  void Test(MLGraphTestMojo& helper,
+            V8TestingScope& scope,
+            MLGraphBuilder* builder) {
+    // Build the graph.
+    auto* lhs_operand = BuildInput(builder, "lhs", lhs.dimensions, lhs.type,
+                                   scope.GetExceptionState());
+    auto* rhs_operand = BuildInput(builder, "rhs", rhs.dimensions, rhs.type,
+                                   scope.GetExceptionState());
+    auto* output_operand =
+        BuildElementWiseBinary(scope, builder, kind, lhs_operand, rhs_operand);
+    auto [graph, build_exception] =
+        helper.BuildGraph(scope, builder, {{"output", output_operand}});
+    ASSERT_NE(graph, nullptr);
+
+    auto graph_info = helper.GetGraphInfo();
+    // Verify the graph information of mojo are as expected.
+    EXPECT_EQ(graph_info->id_to_operand_map.size(), 3u);
+    EXPECT_EQ(graph_info->input_operands.size(), 2u);
+    // Verify the left `mojo::Operand`.
+    auto lhs_operand_id = graph_info->input_operands[0];
+    auto lhs_operand_iter = graph_info->id_to_operand_map.find(lhs_operand_id);
+    ASSERT_TRUE(lhs_operand_iter != graph_info->id_to_operand_map.end());
+    EXPECT_EQ(lhs_operand_iter->value->kind,
+              blink_mojom::Operand::Kind::kInput);
+    EXPECT_EQ(lhs_operand_iter->value->data_type, expected.type);
+    EXPECT_EQ(lhs_operand_iter->value->dimensions, lhs.dimensions);
+    EXPECT_EQ(lhs_operand_iter->value->name, "lhs");
+    // Verify the right `mojo::Operand`.
+    auto rhs_operand_id = graph_info->input_operands[1];
+    auto rhs_operand_iter = graph_info->id_to_operand_map.find(rhs_operand_id);
+    ASSERT_TRUE(rhs_operand_iter != graph_info->id_to_operand_map.end());
+    EXPECT_EQ(rhs_operand_iter->value->kind,
+              blink_mojom::Operand::Kind::kInput);
+    EXPECT_EQ(rhs_operand_iter->value->data_type, expected.type);
+    EXPECT_EQ(rhs_operand_iter->value->dimensions, rhs.dimensions);
+    EXPECT_EQ(rhs_operand_iter->value->name, "rhs");
+    // Verify the output `mojo::Operand`.
+    auto output_operand_id = graph_info->output_operands[0];
+    auto output_operand_iter =
+        graph_info->id_to_operand_map.find(output_operand_id);
+    ASSERT_TRUE(output_operand_iter != graph_info->id_to_operand_map.end());
+    EXPECT_EQ(output_operand_iter->value->kind,
+              blink_mojom::Operand::Kind::kOutput);
+    EXPECT_EQ(output_operand_iter->value->data_type, expected.type);
+    EXPECT_EQ(output_operand_iter->value->dimensions, expected.dimensions);
+    EXPECT_EQ(output_operand_iter->value->name, "output");
+    // Verify the `mojo::Operator`.
+    ASSERT_EQ(graph_info->operators.size(), 1u);
+    auto& operation = graph_info->operators[0];
+    ASSERT_EQ(operation->input_operands.size(), 2u);
+    EXPECT_EQ(operation->input_operands[0], lhs_operand_id);
+    EXPECT_EQ(operation->input_operands[1], rhs_operand_id);
+    ASSERT_EQ(operation->output_operands.size(), 1u);
+    EXPECT_EQ(operation->output_operands[0], output_operand_id);
+  }
+};
+
+TEST_P(MLGraphTestMojo, ElementWiseBinaryTest) {
+  V8TestingScope scope;
+  // Bind fake WebNN Context in the service for testing.
+  ScopedWebNNServiceBinder scoped_setup_binder(*this, scope);
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      blink::features::kEnableMachineLearningNeuralNetworkService);
+  auto* options = MLContextOptions::Create();
+  // Create WebNN Context with GPU device preference.
+  options->setDevicePreference(V8MLDevicePreference::Enum::kGpu);
+  auto* builder = CreateMLGraphBuilder(scope.GetExecutionContext(), options);
+  {
+    // Test element-wise add operator for two 1-D tensors.
+    ElementWiseBinaryTester{
+        .kind = ElementWiseBinaryKind::kAdd,
+        .lhs = {.type = V8MLOperandType::Enum::kFloat32, .dimensions = {2}},
+        .rhs = {.type = V8MLOperandType::Enum::kFloat32, .dimensions = {2}},
+        .expected = {.type = blink_mojom::Operand::DataType::kFloat32,
+                     .dimensions = {2}}}
+        .Test(*this, scope, builder);
+  }
+  {
+    // Test element-wise add operator for two 2-D tensors.
+    ElementWiseBinaryTester{
+        .kind = ElementWiseBinaryKind::kAdd,
+        .lhs = {.type = V8MLOperandType::Enum::kFloat16, .dimensions = {3, 7}},
+        .rhs = {.type = V8MLOperandType::Enum::kFloat16, .dimensions = {3, 7}},
+        .expected = {.type = blink_mojom::Operand::DataType::kFloat16,
+                     .dimensions = {3, 7}}}
+        .Test(*this, scope, builder);
+  }
+  {
+    // Test element-wise add operator for broadcasting to 2-D tensor.
+    ElementWiseBinaryTester{
+        .kind = ElementWiseBinaryKind::kAdd,
+        .lhs = {.type = V8MLOperandType::Enum::kInt32, .dimensions = {5, 3}},
+        .rhs = {.type = V8MLOperandType::Enum::kInt32, .dimensions = {5, 1}},
+        .expected = {.type = blink_mojom::Operand::DataType::kInt32,
+                     .dimensions = {5, 3}}}
+        .Test(*this, scope, builder);
+  }
+  {
+    // Test element-wise add operator for broadcasting to 3-D tensor.
+    ElementWiseBinaryTester{
+        .kind = ElementWiseBinaryKind::kAdd,
+        .lhs = {.type = V8MLOperandType::Enum::kInt8, .dimensions = {4, 2, 1}},
+        .rhs = {.type = V8MLOperandType::Enum::kInt8, .dimensions = {4}},
+        .expected = {.type = blink_mojom::Operand::DataType::kInt8,
+                     .dimensions = {4, 2, 4}}}
+        .Test(*this, scope, builder);
+  }
+  {
+    // Test element-wise add operator for broadcasting to 4-D tensors.
+    ElementWiseBinaryTester{
+        .kind = ElementWiseBinaryKind::kAdd,
+        .lhs = {.type = V8MLOperandType::Enum::kUint8,
+                .dimensions = {8, 1, 6, 1}},
+        .rhs = {.type = V8MLOperandType::Enum::kUint8, .dimensions = {7, 1, 5}},
+        .expected = {.type = blink_mojom::Operand::DataType::kUint8,
+                     .dimensions = {8, 7, 6, 5}}}
+        .Test(*this, scope, builder);
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    MLGraphTestMojo,
+    testing::Combine(::testing::Values(BackendType::kWebNNService),
+                     ::testing::Values(ExecutionMode::kAsync)),
+    TestVarietyToString);
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.cc
new file mode 100644
index 0000000..750870a
--- /dev/null
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.cc
@@ -0,0 +1,166 @@
+// 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_type_converter.h"
+
+#include "third_party/blink/renderer/modules/ml/webnn/ml_operand.h"
+#include "third_party/blink/renderer/modules/ml/webnn/ml_operator.h"
+
+namespace mojo {
+
+webnn::mojom::blink::Operand::DataType BlinkOperandTypeToMojo(
+    blink::V8MLOperandType::Enum type) {
+  switch (type) {
+    case blink::V8MLOperandType::Enum::kFloat32:
+      return webnn::mojom::blink::Operand::DataType::kFloat32;
+    case blink::V8MLOperandType::Enum::kFloat16:
+      return webnn::mojom::blink::Operand::DataType::kFloat16;
+    case blink::V8MLOperandType::Enum::kInt32:
+      return webnn::mojom::blink::Operand::DataType::kInt32;
+    case blink::V8MLOperandType::Enum::kUint32:
+      return webnn::mojom::blink::Operand::DataType::kUint32;
+    case blink::V8MLOperandType::Enum::kInt8:
+      return webnn::mojom::blink::Operand::DataType::kInt8;
+    case blink::V8MLOperandType::Enum::kUint8:
+      return webnn::mojom::blink::Operand::DataType::kUint8;
+  }
+  NOTREACHED_NORETURN();
+}
+
+// Converters from IDL to Mojo.
+webnn::mojom::blink::OperandPtr
+TypeConverter<webnn::mojom::blink::OperandPtr, blink::MLOperand*>::Convert(
+    const blink::MLOperand* ml_operand) {
+  if (!ml_operand) {
+    return nullptr;
+  }
+  auto mojo_operand = webnn::mojom::blink::Operand::New();
+  switch (ml_operand->Kind()) {
+    case blink::MLOperand::OperandKind::kInput:
+      mojo_operand->kind = webnn::mojom::blink::Operand::Kind::kInput;
+      mojo_operand->name = ml_operand->Name();
+      break;
+    case blink::MLOperand::OperandKind::kConstant:
+      mojo_operand->kind = webnn::mojom::blink::Operand::Kind::kConstant;
+      break;
+    case blink::MLOperand::OperandKind::kOutput:
+      mojo_operand->kind = webnn::mojom::blink::Operand::Kind::kOutput;
+      break;
+  }
+  mojo_operand->data_type = BlinkOperandTypeToMojo(ml_operand->Type());
+  mojo_operand->dimensions = ml_operand->Dimensions();
+  return mojo_operand;
+}
+
+}  // namespace mojo
+
+namespace blink {
+
+namespace {
+
+using webnn::mojom::blink::Operator;
+using webnn::mojom::blink::OperatorPtr;
+
+// Maps MLOperand to its id which is used to identify the `mojo::Operand` across
+// processes.
+using OperandToIdMap = HeapHashMap<Member<const MLOperand>, uint64_t>;
+
+uint64_t GetOperatorInputId(const MLOperator* op,
+                            const OperandToIdMap& operand_to_id_map,
+                            wtf_size_t index = 0) {
+  CHECK_NE(op, nullptr);
+  CHECK_LE(index, op->Inputs().size());
+  const auto* input = op->Inputs()[index].Get();
+  return operand_to_id_map.at(input);
+}
+
+uint64_t GetOperatorOutputId(const MLOperator* op,
+                             const OperandToIdMap& operand_to_id_map,
+                             wtf_size_t index = 0) {
+  CHECK_NE(op, nullptr);
+  CHECK_LE(index, op->Outputs().size());
+  const auto* output = op->Outputs()[index].Get();
+  return operand_to_id_map.at(output);
+}
+
+OperatorPtr CreateElementWiseBinaryOperator(
+    const OperandToIdMap& operand_to_id_map,
+    const MLOperator* binary) {
+  const uint64_t lhs_operand_id =
+      GetOperatorInputId(binary, operand_to_id_map, 0);
+  const uint64_t rhs_operand_id =
+      GetOperatorInputId(binary, operand_to_id_map, 1);
+  const uint64_t output_operand_id =
+      GetOperatorOutputId(binary, operand_to_id_map);
+
+  auto operator_mojo = webnn::mojom::blink::Operator::New();
+  switch (binary->Kind()) {
+    case MLOperator::OperatorKind::kAdd:
+      operator_mojo->kind = Operator::Kind::kAdd;
+      break;
+    case MLOperator::OperatorKind::kSub:
+      operator_mojo->kind = Operator::Kind::kSub;
+      break;
+    case MLOperator::OperatorKind::kMul:
+      operator_mojo->kind = Operator::Kind::kMul;
+      break;
+    case MLOperator::OperatorKind::kDiv:
+      operator_mojo->kind = Operator::Kind::kDiv;
+      break;
+    case MLOperator::OperatorKind::kMax:
+      operator_mojo->kind = Operator::Kind::kMax;
+      break;
+    case MLOperator::OperatorKind::kMin:
+      operator_mojo->kind = Operator::Kind::kMin;
+      break;
+    default:
+      NOTREACHED();
+  }
+  operator_mojo->input_operands = {lhs_operand_id, rhs_operand_id};
+  operator_mojo->output_operands = {output_operand_id};
+  return operator_mojo;
+}
+
+}  // namespace
+
+OperatorPtr ConvertToMojoOperator(const OperandToIdMap& operand_to_id_map,
+                                  const MLOperator* op) {
+  switch (op->Kind()) {
+    case MLOperator::OperatorKind::kAdd:
+    case MLOperator::OperatorKind::kSub:
+    case MLOperator::OperatorKind::kMul:
+    case MLOperator::OperatorKind::kDiv:
+    case MLOperator::OperatorKind::kMin:
+    case MLOperator::OperatorKind::kMax:
+      return CreateElementWiseBinaryOperator(operand_to_id_map, op);
+    case MLOperator::OperatorKind::kClamp:
+    case MLOperator::OperatorKind::kConv2d:
+    case MLOperator::OperatorKind::kGemm:
+    case MLOperator::OperatorKind::kAveragePool2d:
+    case MLOperator::OperatorKind::kMaxPool2d:
+    case MLOperator::OperatorKind::kRelu:
+    case MLOperator::OperatorKind::kSoftmax:
+    case MLOperator::OperatorKind::kReshape:
+    case MLOperator::OperatorKind::kHardSwish:
+    case MLOperator::OperatorKind::kResample2d:
+    case MLOperator::OperatorKind::kSigmoid:
+    case MLOperator::OperatorKind::kConcat:
+    case MLOperator::OperatorKind::kTranspose:
+    case MLOperator::OperatorKind::kLeakyRelu:
+    case MLOperator::OperatorKind::kConvTranspose2d:
+    case MLOperator::OperatorKind::kPRelu:
+    case MLOperator::OperatorKind::kPad:
+    case MLOperator::OperatorKind::kElu:
+    case MLOperator::OperatorKind::kAbs:
+    case MLOperator::OperatorKind::kCeil:
+    case MLOperator::OperatorKind::kFloor:
+    case MLOperator::OperatorKind::kNeg:
+    case MLOperator::OperatorKind::kSlice:
+      NOTIMPLEMENTED();
+      return nullptr;
+  }
+  NOTREACHED_NORETURN();
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.h b/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.h
new file mode 100644
index 0000000..95b704d
--- /dev/null
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.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 THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_GRAPH_TYPE_CONVERTER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_GRAPH_TYPE_CONVERTER_H_
+
+#include "mojo/public/cpp/bindings/type_converter.h"
+#include "services/webnn/public/mojom/webnn_graph.mojom-blink.h"
+#include "third_party/blink/renderer/platform/heap/collection_support/heap_hash_map.h"
+
+namespace blink {
+
+class MLOperand;
+class MLOperator;
+webnn::mojom::blink::OperatorPtr ConvertToMojoOperator(
+    const HeapHashMap<Member<const MLOperand>, uint64_t>& operand_to_id_map,
+    const MLOperator* op);
+
+}  // namespace blink
+
+namespace mojo {
+
+template <>
+struct TypeConverter<webnn::mojom::blink::OperandPtr, blink::MLOperand*> {
+  static webnn::mojom::blink::OperandPtr Convert(
+      const blink::MLOperand* ml_operand);
+};
+
+}  // namespace mojo
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_GRAPH_TYPE_CONVERTER_H_
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index aee6a553..b027fcc5 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -667,13 +667,18 @@
       }
       break;
     case GL_RGBA16F:
-      if (IsWebGL2()) {
-        if (!ExtensionEnabled(kEXTColorBufferFloatName) &&
-            !ExtensionEnabled(kEXTColorBufferHalfFloatName)) {
-          SynthesizeGLError(
-              GL_INVALID_ENUM, function_name,
-              "EXT_color_buffer_float/EXT_color_buffer_half_float not enabled");
-          return;
+      if (base::FeatureList::IsEnabled(
+              blink::features::kCorrectFloatExtensionTestForWebGL)) {
+        // Correct float extension testing for WebGL1/2.
+        // See: https://github.com/KhronosGroup/WebGL/pull/3222
+        if (IsWebGL2()) {
+          if (!ExtensionEnabled(kEXTColorBufferFloatName) &&
+              !ExtensionEnabled(kEXTColorBufferHalfFloatName)) {
+            SynthesizeGLError(GL_INVALID_ENUM, function_name,
+                              "EXT_color_buffer_float/"
+                              "EXT_color_buffer_half_float not enabled");
+            return;
+          }
         } else {
           if (!ExtensionEnabled(kEXTColorBufferHalfFloatName)) {
             SynthesizeGLError(GL_INVALID_ENUM, function_name,
@@ -681,6 +686,24 @@
             return;
           }
         }
+      } else {
+        // This is the original incorrect extension testing. Remove this code
+        // once this correction safely launches.
+        if (IsWebGL2()) {
+          if (!ExtensionEnabled(kEXTColorBufferFloatName) &&
+              !ExtensionEnabled(kEXTColorBufferHalfFloatName)) {
+            SynthesizeGLError(GL_INVALID_ENUM, function_name,
+                              "EXT_color_buffer_float/"
+                              "EXT_color_buffer_half_float not enabled");
+            return;
+          } else {
+            if (!ExtensionEnabled(kEXTColorBufferHalfFloatName)) {
+              SynthesizeGLError(GL_INVALID_ENUM, function_name,
+                                "EXT_color_buffer_half_float not enabled");
+              return;
+            }
+          }
+        }
       }
       break;
     default:
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource.cc b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
index 07a236e..122a072 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource.cc
@@ -572,8 +572,8 @@
   DCHECK(!is_cross_thread());
 
   // The context deletes all shared images on destruction which means no
-  // cleanup is needed if the context was lost.
-  if (ContextProviderWrapper()) {
+  // cleanup is needed if the context or the mailbox was lost.
+  if (ContextProviderWrapper() && !IsLost() && IsValid()) {
     auto* raster_interface = RasterInterface();
     auto* shared_image_interface =
         ContextProviderWrapper()->ContextProvider()->SharedImageInterface();
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
index 756ce3fc..80e4ea39 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
@@ -55,6 +55,7 @@
 #include "gpu/command_buffer/common/shared_image_usage.h"
 #include "gpu/config/gpu_driver_bug_workaround_type.h"
 #include "gpu/config/gpu_feature_info.h"
+#include "gpu/config/gpu_finch_features.h"
 #include "media/base/video_frame.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/platform/platform.h"
@@ -883,14 +884,24 @@
   }
 
   auto webgl_preferences = ContextProvider()->GetWebglPreferences();
+
   // We can't use anything other than explicit resolve for swap chain.
-  bool supports_implicit_resolve =
+  bool use_implicit_resolve =
       !using_swap_chain_ && extensions_util_->SupportsExtension(
                                 "GL_EXT_multisampled_render_to_texture");
+
+  const auto& gpu_feature_info = ContextProvider()->GetGpuFeatureInfo();
+  // With graphite, Skia is not using ANGLE, so ANGLE will never be able to know
+  // when the back buffer is sampled by Skia, so we can't use implicit resolve.
+  use_implicit_resolve =
+      use_implicit_resolve &&
+      gpu_feature_info.status_values[gpu::GPU_FEATURE_TYPE_SKIA_GRAPHITE] ==
+          gpu::kGpuFeatureStatusEnabled;
+
   if (webgl_preferences.anti_aliasing_mode == kAntialiasingModeUnspecified) {
     if (use_multisampling) {
       anti_aliasing_mode_ = kAntialiasingModeMSAAExplicitResolve;
-      if (supports_implicit_resolve) {
+      if (use_implicit_resolve) {
         anti_aliasing_mode_ = kAntialiasingModeMSAAImplicitResolve;
       }
     } else {
@@ -899,7 +910,7 @@
   } else {
     bool prefer_implicit_resolve = (webgl_preferences.anti_aliasing_mode ==
                                     kAntialiasingModeMSAAImplicitResolve);
-    if (prefer_implicit_resolve && !supports_implicit_resolve) {
+    if (prefer_implicit_resolve && !use_multisampling) {
       DLOG(ERROR) << "Invalid anti-aliasing mode specified.";
       return false;
     }
diff --git a/third_party/blink/web_tests/SlowTests b/third_party/blink/web_tests/SlowTests
index 85382d2..70730409 100644
--- a/third_party/blink/web_tests/SlowTests
+++ b/third_party/blink/web_tests/SlowTests
@@ -1524,3 +1524,6 @@
 crbug.com/1310326 http/tests/misc/transforms-usecounter-3d-scene.html [ Slow ]
 
 crbug.com/1307741 external/wpt/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-routing.html [ Slow ]
+
+crbug.com/626703 [ Mac ] virtual/threaded-prefer-compositing/external/wpt/scroll-animations/css/view-timeline-inset-animation.html [ Slow ]
+crbug.com/1376679 [ Mac ] virtual/threaded-prefer-compositing/external/wpt/scroll-animations/css/scroll-timeline-dynamic.tentative.html [ Slow ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 313b4d7f..1c0feb0 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2876,7 +2876,7 @@
 crbug.com/626703 external/wpt/css/css-color/oklch-011.html [ Failure ]
 crbug.com/626703 [ Mac13 ] virtual/threaded/external/wpt/scroll-animations/css/scroll-timeline-range-animation.html [ Timeout ]
 crbug.com/626703 [ Mac13 ] virtual/threaded-prefer-compositing/external/wpt/scroll-animations/css/animation-timeline-view-functional-notation.tentative.html [ Timeout ]
-crbug.com/626703 [ Mac13 ] virtual/threaded-prefer-compositing/external/wpt/scroll-animations/view-timelines/view-timeline-inset.html [ Timeout ]
+crbug.com/626703 [ Mac13 ] virtual/threaded-prefer-compositing/external/wpt/scroll-animations/view-timelines/view-timeline-inset.html [ Pass Timeout ]
 crbug.com/626703 [ Mac11 ] external/wpt/mediacapture-record/MediaRecorder-mimetype.html [ Timeout ]
 crbug.com/626703 external/wpt/css/css-backgrounds/box-shadow-border-radius-001.html [ Failure ]
 crbug.com/626703 virtual/threaded/external/wpt/css/css-backgrounds/box-shadow-border-radius-001.html [ Failure ]
@@ -2889,7 +2889,7 @@
 crbug.com/626703 [ Mac13 ] virtual/threaded-prefer-compositing/external/wpt/scroll-animations/scroll-timelines/effect-updateTiming.html [ Timeout ]
 crbug.com/626703 [ Mac13 ] virtual/threaded-prefer-compositing/external/wpt/scroll-animations/view-timelines/view-timeline-range.html [ Timeout ]
 crbug.com/626703 [ Mac13 ] virtual/threaded/external/wpt/scroll-animations/scroll-timelines/effect-updateTiming.html [ Timeout ]
-crbug.com/626703 [ Mac13 ] virtual/threaded/external/wpt/scroll-animations/view-timelines/view-timeline-inset.html [ Timeout ]
+crbug.com/626703 [ Mac13 ] virtual/threaded/external/wpt/scroll-animations/view-timelines/view-timeline-inset.html [ Pass Timeout ]
 crbug.com/626703 external/wpt/css/css-images/image-set/image-set-negative-resolution-rendering-3.html [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/video-rvfc/request-video-frame-callback-webrtc.https.html [ Failure Timeout ]
 crbug.com/626703 [ Mac13-arm64 ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-simulcast.https.html [ Timeout ]
@@ -2906,8 +2906,8 @@
 crbug.com/626703 [ Mac13 Release ] external/wpt/html/semantics/embedded-content/media-elements/ready-states/autoplay-hidden.optional.html [ Timeout ]
 crbug.com/626703 [ Mac13-arm64 Release ] external/wpt/html/semantics/embedded-content/media-elements/ready-states/autoplay-hidden.optional.html [ Timeout ]
 crbug.com/626703 [ Mac13 ] virtual/pending-beacon/external/wpt/pending-beacon/pending_post_beacon-cors.tentative.https.window.html [ Timeout ]
-crbug.com/626703 [ Mac12 Release ] virtual/threaded-prefer-compositing/external/wpt/scroll-animations/css/view-timeline-inset-animation.html [ Timeout ]
-crbug.com/626703 [ Mac13 ] virtual/threaded-prefer-compositing/external/wpt/scroll-animations/css/view-timeline-inset-animation.html [ Timeout ]
+crbug.com/626703 [ Mac12 Release ] virtual/threaded-prefer-compositing/external/wpt/scroll-animations/css/view-timeline-inset-animation.html [ Pass Timeout ]
+crbug.com/626703 [ Mac13 ] virtual/threaded-prefer-compositing/external/wpt/scroll-animations/css/view-timeline-inset-animation.html [ Pass Timeout ]
 crbug.com/626703 external/wpt/css/css-backgrounds/color-mix-currentcolor-outline-repaint-parent.html [ Failure Pass ]
 crbug.com/626703 virtual/threaded/external/wpt/css/css-backgrounds/color-mix-currentcolor-outline-repaint-parent.html [ Failure Pass ]
 crbug.com/626703 external/wpt/css/css-backgrounds/color-mix-currentcolor-background-repaint-parent.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/tools/gentestutilsunion.py b/third_party/blink/web_tests/external/wpt/html/canvas/tools/gentestutilsunion.py
index 6cf8df22..0542e325 100644
--- a/third_party/blink/web_tests/external/wpt/html/canvas/tools/gentestutilsunion.py
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/tools/gentestutilsunion.py
@@ -291,46 +291,59 @@
     return rendered
 
 
+def _render(jinja_env: jinja2.Environment, template_name: str,
+            params: Mapping[str, Any]):
+    params = dict(params)
+    params.update({
+        # Render the code on its own, as it could contain templates expanding
+        # to multuple lines. This is needed to get proper indentation of the
+        # code in the main template.
+        'code': _render_template(jinja_env,
+                                 jinja_env.from_string(params['code']),
+                                 params)
+    })
+
+    return _render_template(jinja_env, jinja_env.get_template(template_name),
+                            params)
+
+
 def _write_reference_test(jinja_env: jinja2.Environment,
                           params: Mapping[str, Any],
                           enabled_tests: Set[CanvasType],
                           canvas_path: str, offscreen_path: str):
     if CanvasType.HTML_CANVAS in enabled_tests:
+        html_params = dict(params)
+        html_params.update({'canvas_type': CanvasType.HTML_CANVAS.value})
         pathlib.Path(f'{canvas_path}.html').write_text(
-            _render_template(jinja_env,
-                             jinja_env.get_template("reftest_element.html"),
-                             params), 'utf-8')
+            _render(jinja_env, "reftest_element.html", html_params), 'utf-8')
     if CanvasType.OFFSCREEN_CANVAS in enabled_tests:
+        offscreen_params = dict(params)
+        offscreen_params.update({
+            'canvas_type': CanvasType.OFFSCREEN_CANVAS.value
+        })
         pathlib.Path(f'{offscreen_path}.html').write_text(
-            _render_template(jinja_env,
-                             jinja_env.get_template("reftest_offscreen.html"),
-                             params), 'utf-8')
+            _render(jinja_env, "reftest_offscreen.html", offscreen_params),
+            'utf-8')
     if CanvasType.WORKER in enabled_tests:
+        worker_params = dict(params)
+        worker_params.update({'canvas_type': CanvasType.WORKER.value})
         pathlib.Path(f'{offscreen_path}.w.html').write_text(
-            _render_template(jinja_env,
-                             jinja_env.get_template("reftest_worker.html"),
-                             params), 'utf-8')
+            _render(jinja_env, "reftest_worker.html", worker_params), 'utf-8')
 
     js_ref = params.get('reference', '')
     html_ref = params.get('html_reference', '')
     ref_params = dict(params)
     ref_params.update({
         'is_test_reference': True,
-        'code': _render_template(jinja_env,
-                                 jinja_env.from_string(js_ref or html_ref),
-                                 params)
+        'code': js_ref or html_ref
     })
     ref_template_name = 'reftest_element.html' if js_ref else 'reftest.html'
     if CanvasType.HTML_CANVAS in enabled_tests:
         pathlib.Path(f'{canvas_path}-expected.html').write_text(
-            _render_template(jinja_env,
-                             jinja_env.get_template(ref_template_name),
-                             ref_params), 'utf-8')
+            _render(jinja_env, ref_template_name, ref_params), 'utf-8')
     if {CanvasType.OFFSCREEN_CANVAS, CanvasType.WORKER} & enabled_tests:
         pathlib.Path(f'{offscreen_path}-expected.html').write_text(
-            _render_template(jinja_env,
-                             jinja_env.get_template(ref_template_name),
-                             ref_params), 'utf-8')
+            _render(jinja_env, ref_template_name, ref_params), 'utf-8')
 
 
 def _write_testharness_test(jinja_env: jinja2.Environment,
@@ -340,23 +353,27 @@
                             offscreen_path: str):
     # Create test cases for canvas and offscreencanvas.
     if CanvasType.HTML_CANVAS in enabled_tests:
+        html_params = dict(params)
+        html_params.update({'canvas_type': CanvasType.HTML_CANVAS.value})
         pathlib.Path(f'{canvas_path}.html').write_text(
-            _render_template(jinja_env,
-                             jinja_env.get_template("testharness_element.html"),
-                             params), 'utf-8')
+            _render(jinja_env, "testharness_element.html", html_params),
+            'utf-8')
 
     if CanvasType.OFFSCREEN_CANVAS in enabled_tests:
+        offscreen_params = dict(params)
+        offscreen_params.update({
+            'canvas_type': CanvasType.OFFSCREEN_CANVAS.value
+        })
         pathlib.Path(f'{offscreen_path}.html').write_text(
-            _render_template(
-                jinja_env,
-                jinja_env.get_template("testharness_offscreen.html"), params),
+            _render(jinja_env, "testharness_offscreen.html", offscreen_params),
             'utf-8')
 
     if CanvasType.WORKER in enabled_tests:
+        worker_params = dict(params)
+        worker_params.update({'canvas_type': CanvasType.WORKER.value})
         pathlib.Path(f'{offscreen_path}.worker.js').write_text(
-            _render_template(jinja_env,
-                             jinja_env.get_template("testharness_worker.js"),
-                             params), 'utf-8')
+            _render(jinja_env, "testharness_worker.js", worker_params),
+            'utf-8')
 
 
 def _generate_test(test: Mapping[str, Any], jinja_env: jinja2.Environment,
@@ -411,13 +428,6 @@
         'expected_img': expected_img
     })
 
-    # Render the code on its own, as it could contain templating. The code
-    # must be rendered separately so that it could be indented as a whole into
-    # the final template.
-    params['code'] = _render_template(jinja_env,
-                                      jinja_env.from_string(params['code']),
-                                      params)
-
     canvas_path = os.path.join(html_canvas_cfg.out_dir, sub_dir, name)
     offscreen_path = os.path.join(offscreen_canvas_cfg.out_dir, sub_dir, name)
     if 'manual' in test:
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/anonymous-script-with-source-map-breakpoint.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/anonymous-script-with-source-map-breakpoint.js
index f01eb82..ba574508 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/anonymous-script-with-source-map-breakpoint.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/anonymous-script-with-source-map-breakpoint.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests breakpoint in anonymous script with source map on reload.`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await SourcesTestRunner.startDebuggerTestPromise();
   TestRunner.navigatePromise(
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-fetch-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-fetch-expected.txt
index 97d6af4..3ad24367 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-fetch-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-fetch-expected.txt
@@ -3,21 +3,21 @@
 Set timer for test function.
 Captured call stacks in no particular order:
 Call stack:
-    0) chained1 (async-callstack-fetch.js:18)
+    0) chained1 (async-callstack-fetch.js:21)
     [Promise.then]
-    0) doFetch (async-callstack-fetch.js:17)
+    0) doFetch (async-callstack-fetch.js:20)
     [setTimeout]
-    0) testFunction (async-callstack-fetch.js:12)
+    0) testFunction (async-callstack-fetch.js:15)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
 
 Call stack:
-    0) chained4 (async-callstack-fetch.js:22)
+    0) chained4 (async-callstack-fetch.js:25)
     [Promise.then]
-    0) doFetch (async-callstack-fetch.js:21)
+    0) doFetch (async-callstack-fetch.js:24)
     [setTimeout]
-    0) testFunction (async-callstack-fetch.js:12)
+    0) testFunction (async-callstack-fetch.js:15)
     [setTimeout]
     0) scheduleTestFunction <omitted>
     <... skipped remaining frames ...>
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-fetch.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-fetch.js
index 2a2ecc7a..5fd168b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-fetch.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-fetch.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests asynchronous call stacks for fetch.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       function testFunction()
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-network-initiator-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-network-initiator-expected.txt
index cf6f7a6..4289b67 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-network-initiator-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-network-initiator-expected.txt
@@ -1,18 +1,18 @@
 Tests asynchronous call stacks printed in console for a Network.Initiator.
 
 Set timer for test function.
-async-callstack-network-initiator.js:14 Console was cleared
-async-callstack-network-initiator.js:32 POST http://127.0.0.1:8000/failure/foo 404 (Not Found)
+async-callstack-network-initiator.js:18 Console was cleared
+async-callstack-network-initiator.js:36 POST http://127.0.0.1:8000/failure/foo 404 (Not Found)
 
-sendXHR @ async-callstack-network-initiator.js:32
+sendXHR @ async-callstack-network-initiator.js:36
 
-timeout2 @ async-callstack-network-initiator.js:25
+timeout2 @ async-callstack-network-initiator.js:29
 
 setTimeout (async)
 
-timeout1 @ async-callstack-network-initiator.js:20
+timeout1 @ async-callstack-network-initiator.js:24
 
 setTimeout (async)
 
-testFunction @ async-callstack-network-initiator.js:15
+testFunction @ async-callstack-network-initiator.js:19
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-network-initiator-image-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-network-initiator-image-expected.txt
index fbe1531..df51081 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-network-initiator-image-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-network-initiator-image-expected.txt
@@ -1,4 +1,4 @@
 Tests asynchronous network initiator for image loaded from JS.
 
-async-callstack-network-initiator-image.js:18
+async-callstack-network-initiator-image.js:20
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-network-initiator-image.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-network-initiator-image.js
index c4fb423..62a926e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-network-initiator-image.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-network-initiator-image.js
@@ -2,13 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+import {NetworkTestRunner} from 'network_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests asynchronous network initiator for image loaded from JS.\n`);
   await TestRunner.loadLegacyModule('sources');
-  await TestRunner.loadTestModule('sources_test_runner');
   await TestRunner.loadLegacyModule('console');
-  await TestRunner.loadTestModule('console_test_runner');
-  await TestRunner.loadTestModule('network_test_runner');
   await TestRunner.loadLegacyModule('components');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-network-initiator.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-network-initiator.js
index 66d875f..88cb6326 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-network-initiator.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/async-callstack-network-initiator.js
@@ -2,10 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests asynchronous call stacks printed in console for a Network.Initiator.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('sources');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       function testFunction()
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debug-inlined-modules-fragment-id.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debug-inlined-modules-fragment-id.js
index e3b3732..d1e1ffb6 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debug-inlined-modules-fragment-id.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debug-inlined-modules-fragment-id.js
@@ -2,11 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that all inlined modules from the same document are shown in the same source frame with html script tags. Bug 1338257.\n`);
   await TestRunner.loadLegacyModule('sources');
-  await TestRunner.loadTestModule('sources_test_runner');
   await TestRunner.showPanel('sources');
 
   await TestRunner.navigatePromise('resources/inline-modules.html');
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debug-inlined-scripts-fragment-id.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debug-inlined-scripts-fragment-id.js
index 75d880f..74eedfb 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debug-inlined-scripts-fragment-id.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debug-inlined-scripts-fragment-id.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that all inlined scripts from the same document are shown in the same source frame with html script tags. Bug 54544.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
 
   await TestRunner.navigatePromise('resources/inline-scripts.html');
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debug-inlined-scripts.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debug-inlined-scripts.js
index 23721e6..894bad8 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debug-inlined-scripts.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debug-inlined-scripts.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that all inlined scripts from the same document are shown in the same source frame with html script tags.`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.navigatePromise('resources/debug-inline-scripts.html');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-autocontinue-on-syntax-error.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-autocontinue-on-syntax-error.js
index d2b37eb..931aa60 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-autocontinue-on-syntax-error.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-autocontinue-on-syntax-error.js
@@ -2,11 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that debugger won't stop on syntax errors even if "pause on uncaught exceptions" is on.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('sources');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('sources');
 
   SourcesTestRunner.startDebuggerTest(step1);
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-compile-and-run.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-compile-and-run.js
index f234faad5..9c23944 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-compile-and-run.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-compile-and-run.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests separate compilation and run.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
 
   function printExceptionDetails(exceptionDetails) {
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-cyclic-reference.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-cyclic-reference.js
index 8584739..232200f2 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-cyclic-reference.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-cyclic-reference.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that debugging a page where Object prototype has a cyclic reference won't crash the browser.Bug 43558\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       Object.prototype.cyclicRef = Object.prototype;
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-disable-enable.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-disable-enable.js
index 24916309..768be9a 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-disable-enable.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-disable-enable.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that breakpoints are successfully restored after debugger disabling.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       function testFunction()
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-es6-harmony-scopes.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-es6-harmony-scopes.js
index acb1084..47375b56 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-es6-harmony-scopes.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-es6-harmony-scopes.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests ES6 harmony scope sections.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.loadHTML(`
       <input type="button" onclick="testFunction()" value="Test">
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-minified-variables-evalution.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-minified-variables-evalution.js
index 677468c..2373827 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-minified-variables-evalution.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-minified-variables-evalution.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests evaluation in minified scripts.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.addScriptTag('resources/resolve-expressions-compressed.js');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-prototype-property.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-prototype-property.js
index bf78a55e..cc0dbd3ae 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-prototype-property.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-prototype-property.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that object's [[Prototype]] property is present in object properties section when script is paused on a breakpoint.Bug 41214\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       function C()
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-reload-on-pause.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-reload-on-pause.js
index 3a8cdcd2..6bb79665 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-reload-on-pause.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-reload-on-pause.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests "reload" from within inspector window while on pause.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       function testFunction()
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-resolve-expression-line-by-line.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-resolve-expression-line-by-line.js
index 2f91405d..84bb001 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-resolve-expression-line-by-line.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-resolve-expression-line-by-line.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests evaluation in webpack bundled scripts with 'line-by'line' source maps.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
 
   // Bundle created using `npx webpack` with 'cheap-module-source-map'.
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-return-value-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-return-value-expected.txt
index 98cd2c8..69747c39 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-return-value-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-return-value-expected.txt
@@ -2,6 +2,6 @@
 
 Set timer for test function.
 Call stack:
-    0) testFunction (debugger-return-value.js:19)
+    0) testFunction (debugger-return-value.js:22)
        <return>: 10
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-return-value.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-return-value.js
index de433769..ea16a2e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-return-value.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-return-value.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests function's return value reported from backend.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       function d()
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-scope-minified-variables.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-scope-minified-variables.js
index d1690ed..3ed8178 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-scope-minified-variables.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-scope-minified-variables.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests resolving variable names via source maps.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.addScriptTag('resources/resolve-variable-names-compressed.js');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-scope-resolve-identifiers.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-scope-resolve-identifiers.js
index 1e3dc465..4e31279f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-scope-resolve-identifiers.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-scope-resolve-identifiers.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests resolving variable names via source maps.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.addScriptTag('resources/resolve-identifiers.js');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-scope-resolve-this.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-scope-resolve-this.js
index 2ea7a232..68fd014 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-scope-resolve-this.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-scope-resolve-this.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests resolving this object name via source maps.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.addScriptTag('resources/resolve-this.js');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-scripts-reload.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-scripts-reload.js
index 05bfdb3..104e2f9 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-scripts-reload.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-scripts-reload.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that scripts list is cleared upon page reload.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
 
   TestRunner.evaluateInPage('function foo() {} //# sourceURL=dummyScript.js', step1);
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-scripts.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-scripts.js
index 4acb1d30..6adac72 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-scripts.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-scripts.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that valid parsed script notifications are received by front-end.`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.navigatePromise('resources/debugger-scripts.html');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-suspend-active-dom-objects.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-suspend-active-dom-objects.js
index bf4072a..9e7ecf6 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-suspend-active-dom-objects.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/debugger-suspend-active-dom-objects.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that browser won't crash if user evaluates something in the console that would suspend active dom objects (e.g. if user attempts to show an alert) when script execution is paused on a breakpoint and all active dom objects are already suspended.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       function testFunction() {
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/dont-report-injected-script.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/dont-report-injected-script.js
index 837f38f..2305b16 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/dont-report-injected-script.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/dont-report-injected-script.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that injected script isn't reported to frontend.\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       function newWorld()
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/dynamic-script-tag.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/dynamic-script-tag.js
index 35203e1..4b5c6fb3 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/dynamic-script-tag.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/dynamic-script-tag.js
@@ -2,11 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that inline scripts and document.write scripts get different uiSourceCodes with different URLs.`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('sources');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('sources');
   await TestRunner.navigatePromise('resources/dynamic-script-tag.html');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/dynamic-scripts.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/dynamic-scripts.js
index 992e5ade..d057036 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/dynamic-scripts.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/dynamic-scripts.js
@@ -2,11 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that scripts for dynamically added script elements are shown in sources panel if loaded with inspector open.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('sources');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       function appendDynamicScriptElement(src, content)
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/live-edit-no-reveal.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/live-edit-no-reveal.js
index d09c566..ff1ff1b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/live-edit-no-reveal.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/live-edit-no-reveal.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests live edit feature.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.addScriptTag('resources/edit-me-when-paused-no-reveal.js');
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/mutation-observer-suspend-while-paused.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/mutation-observer-suspend-while-paused.js
index 3e874e1..4e99245a 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/mutation-observer-suspend-while-paused.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/mutation-observer-suspend-while-paused.js
@@ -2,11 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that DOM Mutation Observers do not attempt to deliver mutation records while the debugger is paused.Bug 105810\n`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('console');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
 
   var setup = 'window.testDiv = document.createElement(\'div\');\n' +
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/navigator-view.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/navigator-view.js
index 41d4214..94cdb28 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/navigator-view.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/navigator-view.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+import {SDKTestRunner} from 'sdk_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests scripts panel file selectors.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
-  await TestRunner.loadTestModule('sdk_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.addIframe(
       'resources/post-message-listener.html', {name: 'childframe'});
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/network-uisourcecode-provider.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/network-uisourcecode-provider.js
index abfe5f8..5e9b7dc 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/network-uisourcecode-provider.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/network-uisourcecode-provider.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests NetworkUISourceCodeProvider class.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       function removeStyleSheet()
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/pause-in-removed-frame-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/pause-in-removed-frame-expected.txt
index 2f54b78..56b2910 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/pause-in-removed-frame-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/pause-in-removed-frame-expected.txt
@@ -2,9 +2,9 @@
 Set timer for test function.
 Script execution paused.
 Call stack:
-    0) window.removeIframe (pause-in-removed-frame.js:16)
+    0) window.removeIframe (pause-in-removed-frame.js:19)
     1) onXhrLoad (:8000/devtools/sources/debugger/resources/child.html:12)
     2) sendRequest (:8000/devtools/sources/debugger/resources/child.html:16)
-    3) testFunction (pause-in-removed-frame.js:22)
+    3) testFunction (pause-in-removed-frame.js:25)
 Script execution resumed.
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/pause-in-removed-frame.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/pause-in-removed-frame.js
index 4bbfef8..a279eee 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/pause-in-removed-frame.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/pause-in-removed-frame.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests pause functionality in detached frame.`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.loadHTML(
       `<iframe id="child" src="resources/child.html"></iframe>`);
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/properties-special-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/properties-special-expected.txt
index 8f4f16eca..03816c2 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/properties-special-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/properties-special-expected.txt
@@ -1,17 +1,17 @@
 Tests how debugger presents special properties of closures, bound functions and object wrappers.
-properties-special.js:11 Boolean
+properties-special.js:14 Boolean
     [[Prototype]]: Boolean
     [[PrimitiveValue]]: true
-properties-special.js:12 ƒ anonymous(a,b)
+properties-special.js:15 ƒ anonymous(a,b)
     arguments: null
     caller: null
     length: 2
     name: ""
     prototype: {constructor: ƒ}
-    [[FunctionLocation]]: properties-special.js:12
+    [[FunctionLocation]]: properties-special.js:15
     [[Prototype]]: ƒ ()
     [[Scopes]]: Scopes[1]
-properties-special.js:13 ƒ bound ()
+properties-special.js:16 ƒ bound ()
     length: 1
     name: "bound "
     arguments: (...)
@@ -20,13 +20,13 @@
     [[TargetFunction]]: ƒ (a,b)
     [[BoundThis]]: Object
     [[BoundArgs]]: Array(1)
-properties-special.js:14 ƒ* anonymous()
+properties-special.js:17 ƒ* anonymous()
     length: 0
     name: ""
     prototype: Generator {}
     arguments: (...)
     caller: (...)
-    [[FunctionLocation]]: properties-special.js:14
+    [[FunctionLocation]]: properties-special.js:17
     [[IsGenerator]]: true
     [[Prototype]]: GeneratorFunction
     [[Scopes]]: Scopes[1]
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/properties-special.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/properties-special.js
index 9fd53c4..dbcb584f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/properties-special.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/properties-special.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests how debugger presents special properties of closures, bound functions and object wrappers.`);
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       console.dir(Object(true));
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/resource-script-mapping.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/resource-script-mapping.js
index 3d3d07b..0b3a972 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/resource-script-mapping.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/resource-script-mapping.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests ResourceScriptMapping class.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       function loadIframe()
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/rethrow-error-from-bindings-crash-expected.txt b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/rethrow-error-from-bindings-crash-expected.txt
index af9e799..ebaceb0a 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/rethrow-error-from-bindings-crash-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/rethrow-error-from-bindings-crash-expected.txt
@@ -1,117 +1,117 @@
 Tests that pausing on uncaught exceptions thrown from C++ bindings will not crash.
 
 Set timer for test function.
-rethrow-error-from-bindings-crash.js:15 Console was cleared
-rethrow-error-from-bindings-crash.js:29 Uncaught TypeError: Failed to execute 'compareBoundaryPoints' on 'Range': parameter 2 is not of type 'Range'.
-    at f2 (rethrow-error-from-b…ings-crash.js:29:23)
-    at testFunction (rethrow-error-from-b…ings-crash.js:19:28)
-f2 @ rethrow-error-from-bindings-crash.js:29
-testFunction @ rethrow-error-from-bindings-crash.js:19
+rethrow-error-from-bindings-crash.js:19 Console was cleared
+rethrow-error-from-bindings-crash.js:33 Uncaught TypeError: Failed to execute 'compareBoundaryPoints' on 'Range': parameter 2 is not of type 'Range'.
+    at f2 (rethrow-error-from-b…ings-crash.js:33:23)
+    at testFunction (rethrow-error-from-b…ings-crash.js:23:28)
+f2 @ rethrow-error-from-bindings-crash.js:33
+testFunction @ rethrow-error-from-bindings-crash.js:23
 setTimeout (async)
 scheduleTestFunction @ VM:3
 (anonymous) @ VM:1
-rethrow-error-from-bindings-crash.js:24 Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
-    at f1 (rethrow-error-from-b…ings-crash.js:24:25)
-f1 @ rethrow-error-from-bindings-crash.js:24
+rethrow-error-from-bindings-crash.js:28 Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
+    at f1 (rethrow-error-from-b…ings-crash.js:28:25)
+f1 @ rethrow-error-from-bindings-crash.js:28
 setTimeout (async)
-f2 @ rethrow-error-from-bindings-crash.js:28
-testFunction @ rethrow-error-from-bindings-crash.js:19
+f2 @ rethrow-error-from-bindings-crash.js:32
+testFunction @ rethrow-error-from-bindings-crash.js:23
 setTimeout (async)
 scheduleTestFunction @ VM:3
 (anonymous) @ VM:1
-rethrow-error-from-bindings-crash.js:29 Uncaught TypeError: Failed to execute 'compareBoundaryPoints' on 'Range': parameter 2 is not of type 'Range'.
-    at f2 (rethrow-error-from-b…ings-crash.js:29:23)
-f2 @ rethrow-error-from-bindings-crash.js:29
+rethrow-error-from-bindings-crash.js:33 Uncaught TypeError: Failed to execute 'compareBoundaryPoints' on 'Range': parameter 2 is not of type 'Range'.
+    at f2 (rethrow-error-from-b…ings-crash.js:33:23)
+f2 @ rethrow-error-from-bindings-crash.js:33
 setTimeout (async)
-f1 @ rethrow-error-from-bindings-crash.js:23
+f1 @ rethrow-error-from-bindings-crash.js:27
 setTimeout (async)
-f2 @ rethrow-error-from-bindings-crash.js:28
-testFunction @ rethrow-error-from-bindings-crash.js:19
+f2 @ rethrow-error-from-bindings-crash.js:32
+testFunction @ rethrow-error-from-bindings-crash.js:23
 setTimeout (async)
 scheduleTestFunction @ VM:3
 (anonymous) @ VM:1
-rethrow-error-from-bindings-crash.js:24 Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
-    at f1 (rethrow-error-from-b…ings-crash.js:24:25)
-f1 @ rethrow-error-from-bindings-crash.js:24
+rethrow-error-from-bindings-crash.js:28 Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
+    at f1 (rethrow-error-from-b…ings-crash.js:28:25)
+f1 @ rethrow-error-from-bindings-crash.js:28
 setTimeout (async)
-f2 @ rethrow-error-from-bindings-crash.js:28
+f2 @ rethrow-error-from-bindings-crash.js:32
 setTimeout (async)
-f1 @ rethrow-error-from-bindings-crash.js:23
+f1 @ rethrow-error-from-bindings-crash.js:27
 setTimeout (async)
-f2 @ rethrow-error-from-bindings-crash.js:28
-testFunction @ rethrow-error-from-bindings-crash.js:19
+f2 @ rethrow-error-from-bindings-crash.js:32
+testFunction @ rethrow-error-from-bindings-crash.js:23
 setTimeout (async)
 scheduleTestFunction @ VM:3
 (anonymous) @ VM:1
-rethrow-error-from-bindings-crash.js:29 Uncaught TypeError: Failed to execute 'compareBoundaryPoints' on 'Range': parameter 2 is not of type 'Range'.
-    at f2 (rethrow-error-from-b…ings-crash.js:29:23)
-f2 @ rethrow-error-from-bindings-crash.js:29
+rethrow-error-from-bindings-crash.js:33 Uncaught TypeError: Failed to execute 'compareBoundaryPoints' on 'Range': parameter 2 is not of type 'Range'.
+    at f2 (rethrow-error-from-b…ings-crash.js:33:23)
+f2 @ rethrow-error-from-bindings-crash.js:33
 setTimeout (async)
-f1 @ rethrow-error-from-bindings-crash.js:23
+f1 @ rethrow-error-from-bindings-crash.js:27
 setTimeout (async)
-f2 @ rethrow-error-from-bindings-crash.js:28
+f2 @ rethrow-error-from-bindings-crash.js:32
 setTimeout (async)
-f1 @ rethrow-error-from-bindings-crash.js:23
+f1 @ rethrow-error-from-bindings-crash.js:27
 setTimeout (async)
-f2 @ rethrow-error-from-bindings-crash.js:28
-testFunction @ rethrow-error-from-bindings-crash.js:19
+f2 @ rethrow-error-from-bindings-crash.js:32
+testFunction @ rethrow-error-from-bindings-crash.js:23
 setTimeout (async)
 scheduleTestFunction @ VM:3
 (anonymous) @ VM:1
-rethrow-error-from-bindings-crash.js:24 Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
-    at f1 (rethrow-error-from-b…ings-crash.js:24:25)
-f1 @ rethrow-error-from-bindings-crash.js:24
+rethrow-error-from-bindings-crash.js:28 Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
+    at f1 (rethrow-error-from-b…ings-crash.js:28:25)
+f1 @ rethrow-error-from-bindings-crash.js:28
 setTimeout (async)
-f2 @ rethrow-error-from-bindings-crash.js:28
+f2 @ rethrow-error-from-bindings-crash.js:32
 setTimeout (async)
-f1 @ rethrow-error-from-bindings-crash.js:23
+f1 @ rethrow-error-from-bindings-crash.js:27
 setTimeout (async)
-f2 @ rethrow-error-from-bindings-crash.js:28
+f2 @ rethrow-error-from-bindings-crash.js:32
 setTimeout (async)
-f1 @ rethrow-error-from-bindings-crash.js:23
+f1 @ rethrow-error-from-bindings-crash.js:27
 setTimeout (async)
-f2 @ rethrow-error-from-bindings-crash.js:28
-testFunction @ rethrow-error-from-bindings-crash.js:19
+f2 @ rethrow-error-from-bindings-crash.js:32
+testFunction @ rethrow-error-from-bindings-crash.js:23
 setTimeout (async)
 scheduleTestFunction @ VM:3
 (anonymous) @ VM:1
-rethrow-error-from-bindings-crash.js:29 Uncaught TypeError: Failed to execute 'compareBoundaryPoints' on 'Range': parameter 2 is not of type 'Range'.
-    at f2 (rethrow-error-from-b…ings-crash.js:29:23)
-f2 @ rethrow-error-from-bindings-crash.js:29
+rethrow-error-from-bindings-crash.js:33 Uncaught TypeError: Failed to execute 'compareBoundaryPoints' on 'Range': parameter 2 is not of type 'Range'.
+    at f2 (rethrow-error-from-b…ings-crash.js:33:23)
+f2 @ rethrow-error-from-bindings-crash.js:33
 setTimeout (async)
-f1 @ rethrow-error-from-bindings-crash.js:23
+f1 @ rethrow-error-from-bindings-crash.js:27
 setTimeout (async)
-f2 @ rethrow-error-from-bindings-crash.js:28
+f2 @ rethrow-error-from-bindings-crash.js:32
 setTimeout (async)
-f1 @ rethrow-error-from-bindings-crash.js:23
+f1 @ rethrow-error-from-bindings-crash.js:27
 setTimeout (async)
-f2 @ rethrow-error-from-bindings-crash.js:28
+f2 @ rethrow-error-from-bindings-crash.js:32
 setTimeout (async)
-f1 @ rethrow-error-from-bindings-crash.js:23
+f1 @ rethrow-error-from-bindings-crash.js:27
 setTimeout (async)
-f2 @ rethrow-error-from-bindings-crash.js:28
-testFunction @ rethrow-error-from-bindings-crash.js:19
+f2 @ rethrow-error-from-bindings-crash.js:32
+testFunction @ rethrow-error-from-bindings-crash.js:23
 setTimeout (async)
 scheduleTestFunction @ VM:3
 (anonymous) @ VM:1
-rethrow-error-from-bindings-crash.js:24 Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
-    at f1 (rethrow-error-from-b…ings-crash.js:24:25)
-f1 @ rethrow-error-from-bindings-crash.js:24
+rethrow-error-from-bindings-crash.js:28 Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
+    at f1 (rethrow-error-from-b…ings-crash.js:28:25)
+f1 @ rethrow-error-from-bindings-crash.js:28
 setTimeout (async)
-f2 @ rethrow-error-from-bindings-crash.js:28
+f2 @ rethrow-error-from-bindings-crash.js:32
 setTimeout (async)
-f1 @ rethrow-error-from-bindings-crash.js:23
+f1 @ rethrow-error-from-bindings-crash.js:27
 setTimeout (async)
-f2 @ rethrow-error-from-bindings-crash.js:28
+f2 @ rethrow-error-from-bindings-crash.js:32
 setTimeout (async)
-f1 @ rethrow-error-from-bindings-crash.js:23
+f1 @ rethrow-error-from-bindings-crash.js:27
 setTimeout (async)
-f2 @ rethrow-error-from-bindings-crash.js:28
+f2 @ rethrow-error-from-bindings-crash.js:32
 setTimeout (async)
-f1 @ rethrow-error-from-bindings-crash.js:23
+f1 @ rethrow-error-from-bindings-crash.js:27
 setTimeout (async)
-f2 @ rethrow-error-from-bindings-crash.js:28
-testFunction @ rethrow-error-from-bindings-crash.js:19
+f2 @ rethrow-error-from-bindings-crash.js:32
+testFunction @ rethrow-error-from-bindings-crash.js:23
 setTimeout (async)
 scheduleTestFunction @ VM:3
 (anonymous) @ VM:1
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/rethrow-error-from-bindings-crash.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/rethrow-error-from-bindings-crash.js
index 6a193541..ab04f1d 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/rethrow-error-from-bindings-crash.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/rethrow-error-from-bindings-crash.js
@@ -2,10 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that pausing on uncaught exceptions thrown from C++ bindings will not crash.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('sources');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       var functions;
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/script-collected.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/script-collected.js
index afe23ac..768506c66 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/script-collected.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/script-collected.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that DiscardedAnonymousScriptSource event is fired and workspace is cleared.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       function generateErrorScripts()
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/script-failed-to-parse.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/script-failed-to-parse.js
index b4e1e9a..a3b1067 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/script-failed-to-parse.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/script-failed-to-parse.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that ParsedScriptSource event is raised after compile script with syntax error.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       function addScript(url)
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/script-lazily-failed-to-parse.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/script-lazily-failed-to-parse.js
index 39943eac..ddcc5c6 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/script-lazily-failed-to-parse.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/script-lazily-failed-to-parse.js
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that FailedToParseScriptSource event is NOT raised after running a damaged part of a script that was already parsed.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       function thisIsBroken() {
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/skip-pause-during-navigation.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/skip-pause-during-navigation.js
index abda868c..0949271c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/skip-pause-during-navigation.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/skip-pause-during-navigation.js
@@ -2,11 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that we skip all pauses during navigation`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('sources');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('sources');
   await SourcesTestRunner.startDebuggerTestPromise();
   await TestRunner.navigatePromise('resources/page-with-unload.html');
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/source-frame-inline-breakpoint-decorations.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/source-frame-inline-breakpoint-decorations.js
index 7f663f2..3ccb1f9 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/source-frame-inline-breakpoint-decorations.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/source-frame-inline-breakpoint-decorations.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Checks that JavaScriptSourceFrame show inline breakpoints correctly\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       function foo()
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/source-map-http-header.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/source-map-http-header.js
index a96168c..b0b9d337 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/source-map-http-header.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/source-map-http-header.js
@@ -2,11 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(
       `Tests that SourceMap and X-SourceMap http headers are propagated to scripts in the front-end.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('sources');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('sources');
   await SourcesTestRunner.startDebuggerTestPromise();
   var debuggerModel = TestRunner.debuggerModel;
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/sources-panel-content-scripts.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/sources-panel-content-scripts.js
index fa3609b..1dd2bbf 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/sources-panel-content-scripts.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/sources-panel-content-scripts.js
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests that content scripts are reported.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.loadLegacyModule('sources');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       function createContentScript()
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/worker-debugging-script-mapping.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/worker-debugging-script-mapping.js
index 15fde57..c69cc8b0 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/worker-debugging-script-mapping.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/worker-debugging-script-mapping.js
@@ -2,10 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests stopping in debugger in the worker with source mapping.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('sources');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       function installWorker()
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/worker-debugging.js b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/worker-debugging.js
index a3b03fb..646bbfed 100644
--- a/third_party/blink/web_tests/http/tests/devtools/sources/debugger/worker-debugging.js
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/debugger/worker-debugging.js
@@ -2,10 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {TestRunner} from 'test_runner';
+import {SourcesTestRunner} from 'sources_test_runner';
+import {ConsoleTestRunner} from 'console_test_runner';
+
 (async function() {
   TestRunner.addResult(`Tests stopping in debugger in the worker.\n`);
-  await TestRunner.loadLegacyModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
-  await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner');
+  await TestRunner.loadLegacyModule('sources');
+  await TestRunner.loadLegacyModule('console');
   await TestRunner.showPanel('sources');
   await TestRunner.evaluateInPagePromise(`
       function installWorker()
diff --git a/tools/android/modularization/gn/dep_operations.py b/tools/android/modularization/gn/dep_operations.py
index 797a4d0..1c58baa 100755
--- a/tools/android/modularization/gn/dep_operations.py
+++ b/tools/android/modularization/gn/dep_operations.py
@@ -29,8 +29,6 @@
 
 _GIT_IGNORE_STR = '(git ignored file) '
 
-NO_VALID_GN_STR = 'No valid GN files found after filtering.'
-
 
 @dataclasses.dataclass
 class OperationResult:
@@ -404,9 +402,7 @@
         p for p in build_filepaths if not utils.is_bad_gn_file(p, root)
     ]
     num_total = len(filtered_build_filepaths)
-    if num_total == 0:
-        logging.error(NO_VALID_GN_STR)
-        sys.exit(1)
+    assert num_total > 0, 'No valid GN files found.'
     logging.info('Running on %d valid build files.', num_total)
 
     operation_results: List[OperationResult] = args.command(
diff --git a/tools/android/modularization/gn/json_gn_editor.py b/tools/android/modularization/gn/json_gn_editor.py
index dc5a92f..522d0414 100644
--- a/tools/android/modularization/gn/json_gn_editor.py
+++ b/tools/android/modularization/gn/json_gn_editor.py
@@ -113,7 +113,6 @@
     target_name: Optional[str]  # The name of the target containing the list.
     variable_name: str  # Left-hand side variable name the list is assigned to.
     child_nodes: List[dict]  # Right-hand side list of nodes.
-    operation: str  # The assignment operation, whether += or =.
 
 
 class BuildFile:
@@ -230,16 +229,15 @@
         def match_list_assignments(node):
             r"""Matches and returns the list being assigned.
 
-            Binary node (with an operation such as = or +=)
+            Binary node
              /       \
             /         \
             name      list of nodes
 
-            Returns (name, list of nodes, op)
+            Returns the pair (name, list of nodes)
             """
             if node.get(NODE_TYPE) != 'BINARY':
                 return None
-            operation = node.get(NODE_VALUE)
             children = node.get(NODE_CHILD)
             assert len(children) == 2, (
                 'Binary nodes should have two child nodes, but the node is: '
@@ -251,19 +249,18 @@
             if right_child.get(NODE_TYPE) != 'LIST':
                 return None
             list_of_nodes = right_child.get(NODE_CHILD)
-            return name, list_of_nodes, operation
+            return name, list_of_nodes
 
         return self._find_all(match_list_assignments)
 
     def _find_all_deps_lists(self) -> Iterator[DepList]:
         list_tuples = self._find_all_list_assignments()
-        for target_name, (var_name, node_list, operation) in list_tuples:
+        for target_name, (var_name, node_list) in list_tuples:
             if (var_name == 'deps' or var_name.startswith('deps_')
                     or var_name.endswith('_deps') or '_deps_' in var_name):
                 yield DepList(target_name=target_name,
                               variable_name=var_name,
-                              child_nodes=node_list,
-                              operation=operation)
+                              child_nodes=node_list)
 
     def _clone_replacing_value(self, node_to_copy: Dict, new_dep_name: str):
         """Clone the existing node to preserve line numbers and update name.
@@ -298,11 +295,6 @@
         for dep_list in self._find_all_deps_lists():
             if dep_list.target_name is None:
                 continue
-            # Only modify the first assignment operation to the deps variable,
-            # otherwise if there are += operations, then the list of deps will
-            # be added multiple times to the same target's deps.
-            if dep_list.operation != '=':
-                continue
             full_target_name = f'{self._gn_rel_path}:{dep_list.target_name}'
             # Support both the exact name and the absolute GN target names
             # starting with //.
diff --git a/tools/infra/PRESUBMIT.py b/tools/infra/PRESUBMIT.py
index c550309..512cb706 100644
--- a/tools/infra/PRESUBMIT.py
+++ b/tools/infra/PRESUBMIT.py
@@ -8,7 +8,6 @@
 for more details on the presubmit API built into depot_tools.
 """
 
-USE_PYTHON3 = True
 
 
 def _CommonChecks(input_api, output_api):
diff --git a/tools/mb/PRESUBMIT.py b/tools/mb/PRESUBMIT.py
index f4bf951..26d29d5 100644
--- a/tools/mb/PRESUBMIT.py
+++ b/tools/mb/PRESUBMIT.py
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-USE_PYTHON3 = True
 
 
 _IGNORE_FREEZE_FOOTER = 'Ignore-Freeze'
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 0c284ad..22a2e3c0 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -52178,6 +52178,15 @@
   <int value="4" label="Url or App not allowed"/>
 </enum>
 
+<enum name="IMEAssistiveMultiWordSuggestionState">
+  <int value="0" label="Other"/>
+  <int value="1" label="Valid"/>
+  <int value="2" label="StaleAndUserEditedText"/>
+  <int value="3" label="StaleAndUserDeletedText"/>
+  <int value="4" label="StaleAndUserAddedMatchingText"/>
+  <int value="5" label="StaleAndUserAddedDifferentText"/>
+</enum>
+
 <enum name="IMEAssistiveMultiWordSuggestionType">
   <int value="0" label="Unknown"/>
   <int value="1" label="Prediction"/>
@@ -62019,6 +62028,7 @@
   <int value="-438379844" label="SwapSideVolumeButtonsForOrientation:enabled"/>
   <int value="-438348502" label="LogUrlScoringSignals:disabled"/>
   <int value="-437292646" label="DeferBeginMainFrameDuringLoading:enabled"/>
+  <int value="-436799973" label="FederatedService:enabled"/>
   <int value="-436470115" label="TouchpadAndWheelScrollLatching:enabled"/>
   <int value="-435914745" label="ClipboardContentSetting:disabled"/>
   <int value="-435636565" label="EnableLensPing:disabled"/>
@@ -63060,6 +63070,7 @@
   <int value="114480372" label="DeprecateAltClick:enabled"/>
   <int value="114541256" label="HomepagePromoCard:disabled"/>
   <int value="114657517" label="SecurePaymentConfirmationDebug:disabled"/>
+  <int value="114948617" label="SurfacePolish:enabled"/>
   <int value="115852043"
       label="PageInfoAboutThisSiteKeepSidePanelOnSameTabNavs:enabled"/>
   <int value="115915570"
@@ -65306,6 +65317,7 @@
   <int value="1313608203"
       label="TabbedAppOverflowMenuThreeButtonActionbar:enabled"/>
   <int value="1313850691" label="Metal:disabled"/>
+  <int value="1314067176" label="FederatedService:disabled"/>
   <int value="1314681756" label="NoStatePrefetch:disabled"/>
   <int value="1314797690"
       label="CCTRealTimeEngagementSignalsAlternativeImpl:disabled"/>
@@ -66508,6 +66520,7 @@
   <int value="1943083555" label="NotificationScheduleService:enabled"/>
   <int value="1944156526" label="sync-url"/>
   <int value="1945031120" label="LanguageSettingsUpdate2:disabled"/>
+  <int value="1945637293" label="SurfacePolish:disabled"/>
   <int value="1946014982"
       label="MagnifierContinuousMouseFollowingModeSetting:disabled"/>
   <int value="1946358032" label="SwapClankShareHubRows:disabled"/>
@@ -74656,27 +74669,6 @@
   <int value="28" label="INVALID_APN"/>
 </enum>
 
-<enum name="NetworkServiceMemoryCacheBlockedByRequestHeaderReason">
-  <int value="0" label="IfUnmodifiedSince"/>
-  <int value="1" label="IfMatch"/>
-  <int value="2" label="IfRange"/>
-  <int value="3" label="IfModifiedSince"/>
-  <int value="4" label="IfNoneMatch"/>
-  <int value="5" label="CacheControlNoCache"/>
-  <int value="6" label="PragmaNoCache"/>
-  <int value="7" label="CacheControlMaxAgeZero"/>
-  <int value="8" label="Range"/>
-</enum>
-
-<enum name="NetworkServiceMemoryCacheEntryStatus">
-  <int value="0" label="NotInCache"/>
-  <int value="1" label="Stale"/>
-  <int value="2" label="Used"/>
-  <int value="3" label="VaryMismatch"/>
-  <int value="4" label="BlockedByRequestHeaders"/>
-  <int value="5" label="BlockedServiceWorkerOriginatedRequest"/>
-</enum>
-
 <enum name="NetworkServiceSandboxGrantResult">
   <int value="0" label="kSuccess">A data migration was successful.</int>
   <int value="1" label="kFailedToCreateCacheDirectory">
@@ -88518,7 +88510,7 @@
   <int value="12" label="IME"/>
   <int value="13" label="Locale"/>
   <int value="14" label="DarkMode"/>
-  <int value="15" label="ShelfParty"/>
+  <int value="15" label="ShelfParty (deprecated)"/>
   <int value="16" label="AutoZoom"/>
 </enum>
 
diff --git a/tools/metrics/histograms/metadata/arc/histograms.xml b/tools/metrics/histograms/metadata/arc/histograms.xml
index df35a118..443ca958 100644
--- a/tools/metrics/histograms/metadata/arc/histograms.xml
+++ b/tools/metrics/histograms/metadata/arc/histograms.xml
@@ -1503,7 +1503,7 @@
 </histogram>
 
 <histogram name="Arc.LaunchedWithGhostWindow" units="apps"
-    expires_after="2023-07-09">
+    expires_after="2023-12-09">
   <owner>sstan@chromium.org</owner>
   <owner>nancylingwang@chromium.org</owner>
   <summary>The number of ARC apps launched with ghost window.</summary>
diff --git a/tools/metrics/histograms/metadata/enterprise/histograms.xml b/tools/metrics/histograms/metadata/enterprise/histograms.xml
index d72abe3..39c5209e 100644
--- a/tools/metrics/histograms/metadata/enterprise/histograms.xml
+++ b/tools/metrics/histograms/metadata/enterprise/histograms.xml
@@ -469,7 +469,7 @@
 
 <histogram name="Enterprise.CloudManagementEnrollmentTokenLocation.Mac"
     enum="EnterpriseCloudManagementEnrollmentTokenLocationMac"
-    expires_after="2023-06-04">
+    expires_after="2024-06-04">
   <owner>zmin@chromium.org</owner>
   <owner>igorruvinov@chromium.org</owner>
   <summary>
@@ -2126,7 +2126,7 @@
 
 <histogram
     name="Enterprise.MachineLevelUserCloudPolicyEnrollment.RequestSuccessTime"
-    units="ms" expires_after="2023-06-01">
+    units="ms" expires_after="2024-06-01">
   <owner>zmin@chromium.org</owner>
   <owner>rogerta@chromium.org</owner>
   <summary>
@@ -2137,7 +2137,7 @@
 
 <histogram name="Enterprise.MachineLevelUserCloudPolicyEnrollment.Result"
     enum="MachineLevelUserCloudPolicyEnrollmentResult"
-    expires_after="2023-07-31">
+    expires_after="2024-06-01">
   <owner>zmin@chromium.org</owner>
   <owner>rogerta@chromium.org</owner>
   <summary>The result of machine level user cloud policy enrollment.</summary>
@@ -2146,7 +2146,7 @@
 <histogram
     name="Enterprise.MachineLevelUserCloudPolicyEnrollment.StartupDialog"
     enum="MachineLevelUserCloudPolicyEnrollmentStartupDialog"
-    expires_after="2023-10-08">
+    expires_after="2024-06-01">
   <owner>zmin@chromium.org</owner>
   <owner>rogerta@chromium.org</owner>
   <summary>
@@ -2157,7 +2157,7 @@
 
 <histogram
     name="Enterprise.MachineLevelUserCloudPolicyEnrollment.StartupDialogTime"
-    units="ms" expires_after="2023-06-01">
+    units="ms" expires_after="2024-06-01">
   <owner>zmin@chromium.org</owner>
   <owner>rogerta@chromium.org</owner>
   <summary>
@@ -2168,7 +2168,7 @@
 
 <histogram
     name="Enterprise.MachineLevelUserCloudPolicyEnrollment.UnenrollSuccess"
-    enum="BooleanSuccess" expires_after="2023-06-01">
+    enum="BooleanSuccess" expires_after="2024-06-01">
   <owner>zmin@chromium.org</owner>
   <owner>domfc@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/input/histograms.xml b/tools/metrics/histograms/metadata/input/histograms.xml
index f3a3dd9c..47c647d4 100644
--- a/tools/metrics/histograms/metadata/input/histograms.xml
+++ b/tools/metrics/histograms/metadata/input/histograms.xml
@@ -751,6 +751,23 @@
   </summary>
 </histogram>
 
+<histogram name="InputMethod.Assistive.MultiWord.SuggestionState.{Type}"
+    enum="IMEAssistiveMultiWordSuggestionType" expires_after="2023-10-08">
+  <owner>curtismcmullan@google.com</owner>
+  <owner>essential-inputs-team@google.com</owner>
+  <summary>
+    This histogram records when a new suggestion is found and the system
+    attempts to reconcile it with the text found in the currently focused text
+    input. The histogram records the state of the reconciliation process. This
+    metric is recorded exactly once for every suggestion that goes through this
+    process.
+  </summary>
+  <token key="Type">
+    <variant name="Completion" summary="CompletionSuggestion"/>
+    <variant name="Prediction" summary="PredictionSuggestion"/>
+  </token>
+</histogram>
+
 <histogram name="InputMethod.Assistive.NotAllowed" enum="IMEAssistiveAction"
     expires_after="2023-05-01">
   <owner>jiwan@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml
index 66335a8..3fa3450 100644
--- a/tools/metrics/histograms/metadata/navigation/histograms.xml
+++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -1231,15 +1231,22 @@
   </summary>
 </histogram>
 
-<histogram name="Navigation.Prerender.ActivationCommitDeferTime" units="ms"
-    expires_after="2023-11-23">
+<histogram
+    name="Navigation.Prerender.ActivationCommitDeferTime{PrerenderTriggerType}"
+    units="ms" expires_after="2023-11-23">
   <owner>nhiroki@chromium.org</owner>
   <owner>chrome-prerendering@chromium.org</owner>
   <summary>
     Measures time a PrerenderCommitDeferringCondition defers activation waiting
     to commit an ongoing mainframe prerender navigation. Logged every time a
     PrerenderCommitDeferringCondition defers navigation.
+
+    After 2023/05, this metric is used with PrerenderTriggerType key and records
+    even when PrerenderCommitDeferringCondition doesn't delay navigation as zero
+    delay. Previously the metric was only used without the key and recorded only
+    when PrerenderCommitDeferringCondition deferred navigation.
   </summary>
+  <token key="PrerenderTriggerType" variants="PrerenderTriggerType"/>
 </histogram>
 
 <histogram name="Navigation.QueueTime.{Method}.{FrameType}" units="ms"
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml
index 6388a22..757dab8 100644
--- a/tools/metrics/histograms/metadata/network/histograms.xml
+++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -4110,57 +4110,8 @@
   </summary>
 </histogram>
 
-<histogram name="NetworkService.MemoryCache.BlockedByRequestHeaderReason"
-    enum="NetworkServiceMemoryCacheBlockedByRequestHeaderReason"
-    expires_after="2023-08-28">
-  <owner>bashi@chromium.org</owner>
-  <owner>blink-network-stack@google.com</owner>
-  <summary>
-    Records a reason why a request cannot be served from the in-memory cache due
-    to request header checks. Recorded when the in-memory cache tries to serve a
-    stored response.
-  </summary>
-</histogram>
-
-<histogram name="NetworkService.MemoryCache.ContentLength.{RequestDestination}"
-    units="bytes" expires_after="2023-07-10">
-  <owner>bashi@chromium.org</owner>
-  <owner>blink-network-stack@google.com</owner>
-  <summary>
-    Size of a response body that is going to be stored to the network service
-    in-memory cache. Recorded before a response is going to be stored to the
-    in-memory cache. If the size is larger than a configurable limit, the
-    response won't be stored in the in-memory cache. This histogram is recorded
-    for {RequestDestination}.
-  </summary>
-  <token key="RequestDestination" variants="NetworkRequestDestination"/>
-</histogram>
-
-<histogram name="NetworkService.MemoryCache.EntryStatus"
-    enum="NetworkServiceMemoryCacheEntryStatus" expires_after="2023-07-18">
-  <owner>bashi@chromium.org</owner>
-  <owner>blink-network-stack@google.com</owner>
-  <summary>
-    Records whether an HTTP response is served from the in-memory cache in the
-    network service. Recorded when the network service starts a network request
-    and the request satisfies preconditions. Preconditions include: CORS checks
-    passed, the request was a valid GET request, and the request didn't force
-    network access etc. See NetworkServiceMemoryCache::CanServe() for details.
-  </summary>
-</histogram>
-
-<histogram name="NetworkService.MemoryCache.FreshnessAtStore" units="seconds"
-    expires_after="2023-07-10">
-  <owner>bashi@chromium.org</owner>
-  <owner>blink-network-stack@google.com</owner>
-  <summary>
-    Records freshness of a response when it is going to be stored into the
-    in-memory cache. The range is from 1 seconds to 864000 seconds (10 days).
-  </summary>
-</histogram>
-
 <histogram name="NetworkService.NetworkLoaderCompletionTime.{Source}"
-    units="ms" expires_after="2023-07-10">
+    units="ms" expires_after="2024-05-30">
   <owner>bashi@chromium.org</owner>
   <owner>blink-network-stack@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/scheduler/histograms.xml b/tools/metrics/histograms/metadata/scheduler/histograms.xml
index 135f1c2..76b9ca9d 100644
--- a/tools/metrics/histograms/metadata/scheduler/histograms.xml
+++ b/tools/metrics/histograms/metadata/scheduler/histograms.xml
@@ -88,25 +88,6 @@
   </summary>
 </histogram>
 
-<histogram name="Scheduling.Renderer.DrawIntervalWithCustomPropertyAnimations2"
-    units="microseconds" expires_after="2022-07-03">
-  <owner>xidachen@chromium.org</owner>
-  <owner>animations-dev@chromium.org</owner>
-  <summary>
-    The time delta between the draw times of back-to-back BeginImplFrames,
-    regardless of whether or not they result in a swap, when there is at least
-    one custom property animation.
-
-    The interval is only recorded when every BeginImplFrame wants to draw.
-
-    Warning: This metric may include reports from clients with low-resolution
-    clocks (i.e. on Windows, ref. |TimeTicks::IsHighResolution()|). Such reports
-    will cause this metric to have an abnormal distribution. When considering
-    revising this histogram, see UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES for the
-    solution.
-  </summary>
-</histogram>
-
 <histogram base="true" name="ThreadPool.NumTasksBeforeDetach" units="tasks"
     expires_after="M85">
   <owner>fdoray@chromium.org</owner>
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css
index a71d29e..ba05dbf3 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -369,6 +369,10 @@
 
 /* Can be removed after new directory replacement. -- END */
 
+#directory-tree xf-tree-item > input::selection {
+  background-color: var(--cros-text-highlight-color);
+}
+
 /* These changes are for the new directory to work with FilesLegacy style. */
 #directory-tree .align-right-icon {
   --iron-icon-height: 20px;
@@ -1276,7 +1280,7 @@
   text-align: center;
   /* Ensure links in label are on top when not hidden so a click is not
   absorbed by an empty file-list. */
-  z-index: 999;
+  z-index: 500;  /* Must be below the contextmenu (600). */
 }
 
 #empty-folder > .label > span#empty-folder-title {
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager_gm3.css b/ui/file_manager/file_manager/foreground/css/file_manager_gm3.css
index fd45ada..a64de87 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager_gm3.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager_gm3.css
@@ -279,10 +279,11 @@
 
 html[dir='rtl'] #directory-tree .tree-row > .file-row > .align-right-icon {
   left: -12px; /* Same as padding inline end of side nav. */
+  right: unset;
 }
 
 #directory-tree .tree-row > .file-row > .external-link-icon iron-icon {
-  padding: 6px;
+  padding: 10px;
 }
 
 #directory-tree .tree-row > .file-row > .root-eject {
@@ -315,6 +316,14 @@
 }
 /* Can be removed after new directory replacement. -- END */
 
+#directory-tree xf-tree-item > input::selection {
+  background-color: var(--cros-sys-highlight_text);
+}
+
+#directory-tree xf-tree-item > .external-link-icon iron-icon {
+  padding: 10px;
+}
+
 /* Splitter. */
 /* Prevent the sudden flickering when opening the Files app. "div.splitter" is
   the legacy splitter DOM element. We need to maintain the existing DOM
@@ -1043,7 +1052,7 @@
   width: 320px;
   /* Ensure links in label are on top when not hidden so a click is not
   absorbed by an empty file-list. */
-  z-index: 999;
+  z-index: 500;  /* Must be below the contextmenu (600). */
 }
 
 #empty-folder #empty-folder-title {
diff --git a/ui/file_manager/file_manager/widgets/xf_tree_item.ts b/ui/file_manager/file_manager/widgets/xf_tree_item.ts
index c3cad86e..741cc9e 100644
--- a/ui/file_manager/file_manager/widgets/xf_tree_item.ts
+++ b/ui/file_manager/file_manager/widgets/xf_tree_item.ts
@@ -39,8 +39,8 @@
   @property({type: Boolean, reflect: true}) selected = false;
   /** Indicate if a tree item has been expanded or not. */
   @property({type: Boolean, reflect: true}) expanded = false;
-  /** Indicate if a tree item is in editing mode (rename) or not. */
-  @property({type: Boolean, reflect: true}) editing = false;
+  /** Indicate if a tree item is in renaming mode or not. */
+  @property({type: Boolean, reflect: true}) renaming = false;
 
   /**
    * A tree item will have children if the child tree items have been inserted
@@ -206,7 +206,8 @@
             type=${ifDefined(this.iconSet ? undefined : this.icon)}
             .iconSet=${this.iconSet}
           ></xf-icon>
-          ${this.renderTreeLabel()}
+          <span class="tree-label" id="tree-label">${this.label || ''}</span>
+          <slot name="rename"></slot>
           <slot name="trailingIcon"></slot>
         </div>
         <ul
@@ -219,19 +220,6 @@
     `;
   }
 
-  private renderTreeLabel() {
-    if (this.editing) {
-      // The render of <input> for renaming is handled by
-      // `DirectoryTreeNamingController`.
-      return html``;
-    }
-    return html`
-    <span
-      class="tree-label"
-      id="tree-label"
-    >${this.label || ''}</span>`;
-  }
-
   override connectedCallback() {
     super.connectedCallback();
     if (!this.tree) {
@@ -383,7 +371,7 @@
       border-radius: 20px 0 0 20px;
     }
 
-    :host(:not([selected]):not([disabled]):not([editing]))
+    :host(:not([selected]):not([disabled]):not([renaming]))
         li:not(:focus-visible) .tree-row:hover {
       background-color: var(--cros-ripple-color);
     }
@@ -398,7 +386,7 @@
       pointer-events: none;
     }
 
-    :host-context(.pointer-active):host(:not([selected]):not([disabled]):not([editing]))
+    :host-context(.pointer-active):host(:not([selected]):not([disabled]):not([renaming]))
         li:not(:focus-visible) .tree-row:not(:hover):active {
       background-color: var(--cros-ripple-color);
     }
@@ -412,7 +400,7 @@
       cursor: default;
     }
 
-    :host-context(.pointer-active):host(:not([selected]):not([disabled]):not([editing]))
+    :host-context(.pointer-active):host(:not([selected]):not([disabled]):not([renaming]))
         li:not(:focus-visible) .tree-row:not(:active):hover {
       background-color: unset;
     }
@@ -468,6 +456,26 @@
       white-space: pre;
     }
 
+    /** input is attached by DirectoryTreeNamingController. */
+    slot[name="rename"]::slotted(input) {
+      background-color: var(--cros-bg-color);
+      border: none;
+      border-radius: 2px;
+      caret-color: var(--cros-textfield-cursor-color-focus);
+      color: var(--cros-text-color-primary);
+      margin: 0 10px;
+      outline: 2px solid var(--cros-focus-ring-color);
+      overflow: hidden;
+    }
+
+    :host([renaming]) slot[name="rename"]::slotted(input) {
+      display: block;
+    }
+
+    :host([renaming]) .tree-label {
+      display: none;
+    }
+
     paper-ripple {
       display: none;
     }
@@ -486,16 +494,48 @@
       display: block;
     }
 
-    slot[name="trailingIcon"]::slotted(*) {
-      height: 20px;
-      margin: 0;
-      width: 20px;
+    /* Trailing icon styles. */
+    slot[name="trailingIcon"]::slotted(.align-right-icon) {
+      --iron-icon-height: 20px;
+      --iron-icon-width: 20px;
+      border-radius: 16px;
+      border-style: none;
+      box-sizing: border-box;
+      flex: none;
+      height: 32px;
+      left: 1px;
+      position: relative;
+      right: 1px;
+      width: 32px;
+      z-index: 1;
+    }
+
+    slot[name="trailingIcon"]::slotted(.root-eject) {
+      --text-color: currentColor;
+      --hover-bg-color: var(--cros-ripple-color);
+      min-width: 32px;
+      padding: 0;
+    }
+
+    :host-context(html.col-resize) slot[name="trailingIcon"]::slotted(.root-eject:hover) {
+      --hover-bg-color: none;
+    }
+
+    slot[name="trailingIcon"]::slotted(.root-eject:focus) {
+      border: 1px solid var(--cros-focus-ring-color);
+    }
+
+    slot[name="trailingIcon"]::slotted(.root-eject:active) {
+      --ink-color: var(--cros-ripple-color);
+      border-width: 0;
     }
   `;
 
   const refresh23Style = css`
     :host {
       --xf-tree-item-indent: ${TREE_ITEM_INDENT};
+      display: block;
+      margin-top: 8px;
     }
 
     ul {
@@ -530,13 +570,13 @@
       cursor: pointer;
       display: flex;
       height: 40px;
-      margin: 8px 0;
+      padding-inline-end: 12px;
       position: relative;
       user-select: none;
       white-space: nowrap;
     }
 
-    :host(:not([selected]):not([disabled]):not([editing]))
+    :host(:not([selected]):not([disabled]):not([renaming]))
         li:not(:focus-visible) .tree-row:hover {
       background-color: var(--cros-sys-hover_on_subtle);
     }
@@ -557,7 +597,7 @@
       z-index: 2;
     }
 
-    :host-context(.pointer-active):host(:not([selected]):not([disabled]):not([editing]))
+    :host-context(.pointer-active):host(:not([selected]):not([disabled]):not([renaming]))
         li:not(:focus-visible) .tree-row:not(:hover):active {
       background-color: var(--cros-sys-hover_on_subtle);
     }
@@ -566,7 +606,7 @@
       cursor: default;
     }
 
-    :host-context(.pointer-active):host(:not([selected]):not([disabled]):not([editing]))
+    :host-context(.pointer-active):host(:not([selected]):not([disabled]):not([renaming]))
         li:not(:focus-visible) .tree-row:not(:active):hover {
       background-color: unset;
     }
@@ -614,7 +654,7 @@
     .tree-label {
       display: block;
       flex: auto;
-      font-weight: 500;
+      font: var(--cros-button-2-font);
       margin-inline-end: 2px;
       margin-inline-start: 8px;
       min-width: 0;
@@ -623,12 +663,38 @@
       white-space: pre;
     }
 
+    /** input is attached by DirectoryTreeNamingController. */
+    slot[name="rename"]::slotted(input) {
+      background-color: var(--cros-sys-app_base);
+      border-radius: 4px;
+      border: none;
+      color: var(--cros-sys-on_surface);
+      display: none;
+      height: 20px;
+      margin: 0 10px;
+      outline: 2px solid var(--cros-sys-focus_ring);
+      overflow: hidden;
+      padding: 1px 8px;
+    }
+
+    :host([renaming]) slot[name="rename"]::slotted(input) {
+      display: block;
+    }
+
+    :host([renaming]) .tree-label {
+      display: none;
+    }
+
+    :host([selected]) slot[name="rename"]::slotted(input) {
+      outline: 2px solid var(--cros-sys-inverse_primary);
+    }
+
     paper-ripple {
       border-radius: 20px;
       color: var(--cros-sys-ripple_primary);
     }
 
-    /* We need to ensure that even empty labels take up space */
+    /* We need to ensure that even empty labels take up space. */
     .tree-label:empty::after {
       content: ' ';
       white-space: pre;
@@ -642,12 +708,63 @@
       display: block;
     }
 
-    slot[name="trailingIcon"]::slotted(*) {
-      height: 20px;
-      margin: 0;
-      width: 20px;
+    /* Trailing icon styles. */
+    slot[name="trailingIcon"]::slotted(.align-right-icon) {
+      --ink-color: var(--cros-sys-ripple_neutral_on_subtle);
+      --iron-icon-height: 20px;
+      --iron-icon-width: 20px;
+      -ripple-opacity: 100%;
+      border: none;
+      border-radius: 20px;
+      box-sizing: border-box;
+      height: 40px;
+      position: relative;
+      right: -12px; /* Same as padding inline end of tree row. */
+      width: 40px;
+      z-index: 1;
     }
-    `;
+
+    :host-context([dir="rtl"]) slot[name="trailingIcon"]::slotted(.align-right-icon) {
+      left: -12px; /* Same as padding inline end of tree row. */
+      right: unset;
+    }
+
+    slot[name="trailingIcon"]::slotted(.external-link-icon iron-icon) {
+      padding: 6px;
+    }
+
+    slot[name="trailingIcon"]::slotted(.root-eject) {
+      --text-color: currentColor;
+      --hover-bg-color: var(--cros-sys-hover_on_subtle);
+      min-width: 32px;
+      padding: 0;
+    }
+
+    :host([selected]) slot[name="trailingIcon"]::slotted(.root-eject) {
+      --hover-bg-color: var(--cros-sys-hover_on_prominent);
+    }
+
+    :host-context(html.col-resize) slot[name="trailingIcon"]::slotted(.root-eject:hover) {
+      --hover-bg-color: none;
+    }
+
+    slot[name="trailingIcon"]::slotted(.root-eject:focus) {
+      outline: 2px solid var(--cros-sys-focus_ring);
+      outline-offset: 2px;
+    }
+
+    :host([selected]) slot[name="trailingIcon"]::slotted(.root-eject:focus) {
+      outline: 2px solid var(--cros-sys-inverse_primary);
+    }
+
+    slot[name="trailingIcon"]::slotted(.root-eject:active) {
+      --ink-color: var(--cros-sys-ripple_neutral_on_subtle);
+    }
+
+    :host([selected]) slot[name="trailingIcon"]::slotted(.root-eject:active) {
+      --ink-color: var(--cros-sys-ripple_neutral_on_prominent);
+    }
+  `;
 
   return [
     addCSSPrefixSelector(legacyStyle, '[theme="legacy"]'),
diff --git a/ui/ozone/platform/wayland/host/wayland_screen.cc b/ui/ozone/platform/wayland/host/wayland_screen.cc
index 973d81b..81cb927 100644
--- a/ui/ozone/platform/wayland/host/wayland_screen.cc
+++ b/ui/ozone/platform/wayland/host/wayland_screen.cc
@@ -139,10 +139,12 @@
 
 void WaylandScreen::OnOutputRemoved(WaylandOutput::Id output_id) {
   DCHECK(display_id_map_.contains(output_id));
-  if (display_id_map_.find(output_id) == display_id_map_.end())
+  auto iter = display_id_map_.find(output_id);
+  if (iter == display_id_map_.end()) {
     return;
-
-  int64_t display_id = display_id_map_[output_id];
+  }
+  int64_t display_id = iter->second;
+  display_id_map_.erase(iter);
 
   if (display_id == GetPrimaryDisplay().id()) {
     // First, set a new primary display as required by the |display_list_|. It's
diff --git a/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc b/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
index f778101..6f8cbf0 100644
--- a/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_screen_unittest.cc
@@ -319,6 +319,10 @@
   int64_t removed_display_id = observer.GetRemovedDisplay().id();
   EXPECT_EQ(added_display_id, removed_display_id);
 
+  // Ensure that |WaylandScreen| has forgotten about the removed display.
+  EXPECT_EQ(platform_screen_->GetOutputIdForDisplayId(removed_display_id),
+            WaylandOutput::Id(0));
+
   // Create another display again. Updates rect again.
   PostToServerAndWait(
       [&output2, &output1](wl::TestWaylandServerThread* server) {