diff --git a/DEPS b/DEPS
index f21a7b0..041e350 100644
--- a/DEPS
+++ b/DEPS
@@ -286,7 +286,7 @@
   'sysroots_json_path': 'build/linux/sysroot_scripts/sysroots.json',
 
   # siso CIPD package version.
-  'siso_version': 'git_revision:669c48208b82db909d20a0e61f33f6f0f6916e08',
+  'siso_version': 'git_revision:3cd0e6e55246b8eca6646e33b124e54e67fc5660',
 
   # download libaom test data
   'download_libaom_testdata': False,
@@ -306,15 +306,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'src_internal_revision': '267ce4f58248ec59895483e5ef12b065db32717c',
+  'src_internal_revision': '4852454fa25ae02654a48b1592efb73803fe8067',
   # 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': 'de3f3987a8365b51e4f0546442f8d990a376e192',
+  'skia_revision': 'c29a20702356a118d09d173755d66315b16127cf',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '28312d3b2ac96a3a325a4a761851c15808a75c12',
+  'v8_revision': 'f243ba1bf4f7673ff645e31af0370f22e968d19d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
@@ -381,7 +381,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'c2c3cef34d1a1cee17fffcf34c98a6a9a352d064',
+  'catapult_revision': 'f092a8625f3f04979970ace175bd99c2f4196c08',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling chromium_variations
   # and whatever else without interference from each other.
@@ -825,7 +825,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '27098a272f4239731ab13adb3dd53bc91652c28f',
+    '923f628b8e7644a1c009747dafe7bf61e12896b6',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1058,7 +1058,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_build_tools/manifest_merger',
-               'version': '_BpuezAM4mQeQj5WNI7H6zkNx4nV2d8uGzcoJOlLQJcC',
+               'version': 'xxtHLi-sldjnrAZqfTewA7Ai7T_i46GDTkbeOQm4Da4C',
           },
       ],
       'condition': 'checkout_android',
@@ -1197,13 +1197,13 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '0696c428b04513254d3b3e0b1fba5e5afdb11cf4',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '120efcb475aa5f8c6f38c4598c602f4713015112',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '30cbeb81ec54e2be41b6de16ad50353ea798740d',
+      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'd27a6b83a969ae8c9a02df0e03e5756a1f4c521a',
     'condition': 'checkout_src_internal',
   },
 
@@ -1848,7 +1848,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'e082b08475761a2ba6a3349dfea72f704c8b68d4',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '1df269099fcb3c8e7474786a21bcdd32335c43ed',
+    Var('webrtc_git') + '/src.git' + '@' + '1188d0849f18baf91ab0061781ea1a521363b8bd',
 
   # Wuffs' canonical repository is at github.com/google/wuffs, but we use
   # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file.
@@ -1960,7 +1960,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/eche_app/app',
-        'version': '4mBGvQVJBJ7CTd6Q7nigOzaus6OTnP3k8XXL7qZqdA4C',
+        'version': 'cj6U89uuybmhL60Yo05WMPs4iRpeWzw1AKnPZYs1jrwC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -3843,7 +3843,7 @@
 
   'src/chrome/browser/resources/chromeos/quickoffice': {
       'url': Var('chrome_git') + '/quickoffice/crx.git' + '@' +
-        '79e797d69d4675a2f0ef916dbb65457fe9485fc9',
+        '82b2a09bf9550c7435a774a6261e6736b787468f',
       'condition': '(checkout_chromeos or checkout_linux) and checkout_src_internal',
   },
 
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 9b6c3be..a926c9f 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -961,6 +961,8 @@
     "picker/picker_controller.h",
     "picker/picker_insert_media_request.cc",
     "picker/picker_insert_media_request.h",
+    "picker/views/picker_caps_nudge_view.cc",
+    "picker/views/picker_caps_nudge_view.h",
     "picker/views/picker_category_view.cc",
     "picker/views/picker_category_view.h",
     "picker/views/picker_contents_view.cc",
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 8d19db9..240a3abf 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -278,19 +278,16 @@
         See all apps
       </message>
       <message name="IDS_SHELF_PREVIOUS_DESK_BUTTON_TITLE" desc="The title used for the previous desk button within the desk button on the shelf.">
-        Previous Desk: <ph name="PREVIOUS_DESK_NAME">$1<ex>Desk 1</ex></ph>, use Search+Space or keyboard shortcut: Shift+Search+<ph name="PREVIOUS_DESK_INDEX">$2<ex>1</ex></ph> to activate.
+        Previous desk: <ph name="DESK_NAME">$1<ex>Desk 1</ex></ph>. Desk <ph name="DESK_INDEX">$2<ex>1</ex></ph> of <ph name="DESK_COUNT">$3<ex>3</ex></ph>.
       </message>
-      <message name="IDS_SHELF_PREVIOUS_DESK_BUTTON_TITLE_16_DESKS" desc="The title used for the previous desk button within the desk button on the shelf when that desk is beyond the 8th desk.">
-        Previous Desk: <ph name="PREVIOUS_DESK_NAME">$1<ex>Desk 12</ex></ph>, use Search+Space to activate.
+      <message name="IDS_SHELF_DESK_BUTTON_TITLE_NO_PROFILE_AVATAR" desc="The title used for the desk button on the shelf with no profile avatar.">
+        Current desk: <ph name="DESK_NAME">$1<ex>Desk 2</ex></ph>. Desk <ph name="DESK_INDEX">$2<ex>2</ex></ph> of <ph name="DESK_COUNT">$3<ex>3</ex></ph>.
       </message>
-      <message name="IDS_SHELF_DESK_BUTTON_TITLE" desc="The title used for the desk button on the shelf.">
-        Current Desk: <ph name="CURRENT_DESK_NAME">$1<ex>Desk 2</ex></ph>, use Search+Space to open all desks menu.
+      <message name="IDS_SHELF_DESK_BUTTON_TITLE_WITH_PROFILE_AVATAR" desc="The title used for the desk button on the shelf with profile avatar.">
+        Current desk: <ph name="DESK_NAME">$1<ex>Desk 2</ex></ph>. <ph name="PROFILE_NAME">$2<ex>Profile name</ex></ph> <ph name="EMAIL">$3<ex>test@gmail.com</ex></ph>. Desk <ph name="DESK_INDEX">$4<ex>2</ex></ph> of <ph name="DESK_COUNT">$5<ex>3</ex></ph>.
       </message>
       <message name="IDS_SHELF_NEXT_DESK_BUTTON_TITLE" desc="The title used for the next desk button within the desk button on the shelf.">
-        Next Desk: <ph name="NEXT_DESK_NAME">$1<ex>Desk 3</ex></ph>, use Search+Space or keyboard shortcut: Shift+Search+<ph name="NEXT_DESK_INDEX">$2<ex>3</ex></ph> to activate.
-      </message>
-      <message name="IDS_SHELF_NEXT_DESK_BUTTON_TITLE_16_DESKS" desc="The title used for the next desk button within the desk button on the shelf when that desk is beyond the 8th desk.">
-        Next Desk: <ph name="NEXT_DESK_NAME">$1<ex>Desk 14</ex></ph>, use Search+Space to activate.
+        Next desk: <ph name="DESK_NAME">$1<ex>Desk 3</ex></ph>. Desk <ph name="DESK_INDEX">$2<ex>3</ex></ph> of <ph name="DESK_COUNT">$3<ex>3</ex></ph>.
       </message>
 
 
@@ -843,7 +840,7 @@
         Show Focus session settings. Duration set to <ph name="FOCUS_DURATION">$1<ex>25 minutes</ex></ph>
       </message>
       <message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_TILE_ACTIVE" translateable="false" desc="The accessible name for the focus mode feature tile in the quick settings menu when focus mode is active.">
-        Show Focus session settings. <ph name="FOCUS_DURATION">$1<ex>7 minutes</ex></ph> left for the current Focus session
+        Show Focus session settings. <ph name="REMAINING_TIME">$1<ex>7 minutes</ex></ph> left for the current Focus session
       </message>
       <message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_TILE_INITIAL" translateable="false" desc="The accessible name for the focus mode feature tile in the quick settings menu when focus mode has never been used before.">
         Show Focus session settings
@@ -852,13 +849,13 @@
         Toggle Focus session. Duration set to <ph name="FOCUS_DURATION">$1<ex>25 minutes</ex></ph>
       </message>
       <message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_TILE_BUTTON_ACTIVE" translateable="false" desc="The accessible name for the toggle button in the focus mode feature tile in the quick settings menu when focus mode is active.">
-        Toggle Focus session. <ph name="FOCUS_DURATION">$1<ex>7 minutes</ex></ph> left for the current Focus session
+        Toggle Focus session. <ph name="REMAINING_TIME">$1<ex>7 minutes</ex></ph> left for the current Focus session
       </message>
       <message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_TOGGLE_START_BUTTON_ACCESSIBLE_NAME" translateable="false" desc="The accessible name for the toggle button in the focus mode toggle row in the focus mode detailed view when focus mode is not active.">
         Start Focus session
       </message>
       <message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_TOGGLE_END_BUTTON_ACCESSIBLE_NAME" translateable="false" desc="The accessible name for the toggle button in the focus mode toggle row in the focus mode detailed view for when focus mode is active.">
-        Finish Focus session. <ph name="FOCUS_DURATION">$1<ex>24 minutes</ex></ph> left
+        Finish Focus session. <ph name="REMAINING_TIME">$1<ex>24 minutes</ex></ph> left
       </message>
       <message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_TASK_TEXTFIELD_SELECTED_ACCESSIBLE_NAME" translateable="false" desc="The accessible name for the task textfield in the focus mode detailed view.">
         Focusing on <ph name="TASK_NAME">$1<ex>Plan for trip to Paris</ex></ph> Press enter to edit task
@@ -875,11 +872,14 @@
       <message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_DO_NOT_DISTURB_ACCESSIBLE_NAME_DISABLED" translateable="false" desc="The accessible name for the do not disturb switch when disabled in the focus mode detailed view.">
         Enable Do not disturb while in Focus. Do not disturb is disabled
       </message>
+      <message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_TRAY_ACCESSIBLE_NAME" translateable="false" desc="The accessible name for the focus mode tray icon.">
+        Focusing, <ph name="REMAINING_TIME">$1<ex>24 minutes 35 seconds</ex></ph> left
+      </message>
       <message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_TRAY_BUBBLE_TASK_ACCESSIBLE_NAME" translateable="false" desc="The accessible name for the tray bubble contextual panel when there is a selected task.">
-        Focus session, <ph name="FOCUS_DURATION">$1<ex>24 minutes 35 seconds</ex></ph>, focusing on <ph name="TASK_NAME">$2<ex>Plan for trip to Paris</ex></ph>
+        Focus session, <ph name="REMAINING_TIME">$1<ex>24 minutes 35 seconds</ex></ph>, focusing on <ph name="TASK_NAME">$2<ex>Plan for trip to Paris</ex></ph>
       </message>
       <message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_TRAY_BUBBLE_ACCESSIBLE_NAME" translateable="false" desc="The accessible name for the tray bubble contextual panel when there is no selected task.">
-        Focus session, <ph name="FOCUS_DURATION">$1<ex>24 minutes 35 seconds</ex></ph>
+        Focus session, <ph name="REMAINING_TIME">$1<ex>24 minutes 35 seconds</ex></ph>
       </message>
       <message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_TRAY_BUBBLE_ENDING_MOMENT_ACCESSIBLE_NAME" translateable="false" desc="The accessible name for the tray bubble contextual panel when in the ending moment.">
         Time's up! Great job!
@@ -6945,9 +6945,21 @@
       <message name="IDS_PICKER_GIFS_CATEGORY_LABEL" translateable="false" desc="Label of the Picker list item which can be clicked to show gif results.">
         Gifs
       </message>
-      <message name="IDS_PICKER_SEARCH_FIELD_PLACEHOLDER_TEXT" translateable="false" desc="Placeholder text for the search field shown in the Picker UI.">
+      <message name="IDS_PICKER_ZERO_STATE_SEARCH_FIELD_PLACEHOLDER_TEXT" translateable="false" desc="Placeholder text for the search field shown in the Picker UI.">
         Search to insert
       </message>
+      <message name="IDS_PICKER_EMOJIS_CATEGORY_SEARCH_FIELD_PLACEHOLDER_TEXT" translateable="false" desc="Placeholder text for the search field shown in the Picker UI when the emojis category is selected.">
+        Search Emojis
+      </message>
+      <message name="IDS_PICKER_SYMBOLS_CATEGORY_SEARCH_FIELD_PLACEHOLDER_TEXT" translateable="false" desc="Placeholder text for the search field shown in the Picker UI when the symbols category is selected.">
+        Search Symbols
+      </message>
+      <message name="IDS_PICKER_EMOTICONS_CATEGORY_SEARCH_FIELD_PLACEHOLDER_TEXT" translateable="false" desc="Placeholder text for the search field shown in the Picker UI when the emoticons category is selected.">
+        Search Emoticons
+      </message>
+      <message name="IDS_PICKER_GIFS_CATEGORY_SEARCH_FIELD_PLACEHOLDER_TEXT" translateable="false" desc="Placeholder text for the search field shown in the Picker UI when the gifs category is selected.">
+        Search Gifs
+      </message>
 
       <!-- WM -->
       <message name="IDS_ENTER_PIP_A11Y_NOTIFICATION" is_accessibility_with_no_ui="true" desc="Accessibility text read by chromevox when a window starts picture-in-picture mode.">
diff --git a/ash/ash_strings_grd/IDS_SHELF_DESK_BUTTON_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_SHELF_DESK_BUTTON_TITLE.png.sha1
deleted file mode 100644
index 2a980b6b..0000000
--- a/ash/ash_strings_grd/IDS_SHELF_DESK_BUTTON_TITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-7cd27ea32853e41b4398004fe2dfa2d9939b438b
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_SHELF_DESK_BUTTON_TITLE_NO_PROFILE_AVATAR.png.sha1 b/ash/ash_strings_grd/IDS_SHELF_DESK_BUTTON_TITLE_NO_PROFILE_AVATAR.png.sha1
new file mode 100644
index 0000000..e38c3618
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_SHELF_DESK_BUTTON_TITLE_NO_PROFILE_AVATAR.png.sha1
@@ -0,0 +1 @@
+e11263d96d7a2201c608351f82f98f789eb19cb9
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_SHELF_DESK_BUTTON_TITLE_WITH_PROFILE_AVATAR.png.sha1 b/ash/ash_strings_grd/IDS_SHELF_DESK_BUTTON_TITLE_WITH_PROFILE_AVATAR.png.sha1
new file mode 100644
index 0000000..efe8891
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_SHELF_DESK_BUTTON_TITLE_WITH_PROFILE_AVATAR.png.sha1
@@ -0,0 +1 @@
+b95106681e23a17ad249ae6d4fb1973d24cc8056
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_SHELF_NEXT_DESK_BUTTON_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_SHELF_NEXT_DESK_BUTTON_TITLE.png.sha1
index 10167ed..e5849273 100644
--- a/ash/ash_strings_grd/IDS_SHELF_NEXT_DESK_BUTTON_TITLE.png.sha1
+++ b/ash/ash_strings_grd/IDS_SHELF_NEXT_DESK_BUTTON_TITLE.png.sha1
@@ -1 +1 @@
-9779b0564eaba7361dd7f0f33e7300437224bc3f
\ No newline at end of file
+a96e8db5db570e9c0920f90852c908e0c3ab2481
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_SHELF_NEXT_DESK_BUTTON_TITLE_16_DESKS.png.sha1 b/ash/ash_strings_grd/IDS_SHELF_NEXT_DESK_BUTTON_TITLE_16_DESKS.png.sha1
deleted file mode 100644
index 3d1d462..0000000
--- a/ash/ash_strings_grd/IDS_SHELF_NEXT_DESK_BUTTON_TITLE_16_DESKS.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-fccfc6a0870cc6a6621843b07bd187d30836816f
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_SHELF_PREVIOUS_DESK_BUTTON_TITLE.png.sha1 b/ash/ash_strings_grd/IDS_SHELF_PREVIOUS_DESK_BUTTON_TITLE.png.sha1
index 84d81f0..46993ba 100644
--- a/ash/ash_strings_grd/IDS_SHELF_PREVIOUS_DESK_BUTTON_TITLE.png.sha1
+++ b/ash/ash_strings_grd/IDS_SHELF_PREVIOUS_DESK_BUTTON_TITLE.png.sha1
@@ -1 +1 @@
-e98b80cc9d6aa1c9da35e3d6535f88625b81b071
\ No newline at end of file
+ac20b85cac695c02f3e8b9b5f71c9afabdae2245
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_SHELF_PREVIOUS_DESK_BUTTON_TITLE_16_DESKS.png.sha1 b/ash/ash_strings_grd/IDS_SHELF_PREVIOUS_DESK_BUTTON_TITLE_16_DESKS.png.sha1
deleted file mode 100644
index 68fe01d..0000000
--- a/ash/ash_strings_grd/IDS_SHELF_PREVIOUS_DESK_BUTTON_TITLE_16_DESKS.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-400267ebd23a9cd1c926baa225b8ce6406f968e2
\ No newline at end of file
diff --git a/ash/picker/picker_controller.cc b/ash/picker/picker_controller.cc
index a5e57741..ef49bef 100644
--- a/ash/picker/picker_controller.cc
+++ b/ash/picker/picker_controller.cc
@@ -260,7 +260,9 @@
     std::move(callback).Run(std::string());
     return;
   }
-  client_->DownloadGifToString(url, std::move(callback));
+  std::optional<ValidGifUrl> validated_url = ValidGifUrl::Create(url);
+  CHECK(validated_url.has_value());
+  client_->DownloadGifToString(*validated_url, std::move(callback));
 }
 
 }  // namespace ash
diff --git a/ash/picker/picker_controller_unittest.cc b/ash/picker/picker_controller_unittest.cc
index 6e0a514..de1433da 100644
--- a/ash/picker/picker_controller_unittest.cc
+++ b/ash/picker/picker_controller_unittest.cc
@@ -42,7 +42,7 @@
     return web_view_factory_.Create(params);
   }
 
-  void DownloadGifToString(const GURL& url,
+  void DownloadGifToString(const ValidGifUrl& url,
                            DownloadGifToStringCallback callback) override {}
 
  private:
diff --git a/ash/picker/views/picker_caps_nudge_view.cc b/ash/picker/views/picker_caps_nudge_view.cc
new file mode 100644
index 0000000..e25aed83
--- /dev/null
+++ b/ash/picker/views/picker_caps_nudge_view.cc
@@ -0,0 +1,120 @@
+// Copyright 2024 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/picker/views/picker_caps_nudge_view.h"
+
+#include <memory>
+
+#include "ash/bubble/bubble_utils.h"
+#include "ash/strings/grit/ash_strings.h"
+#include "ash/style/pill_button.h"
+#include "ash/style/typography.h"
+#include "components/vector_icons/vector_icons.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/metadata/metadata_impl_macros.h"
+#include "ui/base/themed_vector_icon.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/views/background.h"
+#include "ui/views/border.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/image_view.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/layout/flex_layout.h"
+#include "ui/views/layout/flex_layout_view.h"
+#include "ui/views/layout/layout_types.h"
+#include "ui/views/view.h"
+
+namespace ash {
+namespace {
+
+constexpr ui::ColorId kBackgroundColor = cros_tokens::kCrosSysSystemOnBase;
+constexpr int kBorderRadius = 16;
+constexpr int kPadding = 16;
+constexpr int kLeftIconSize = 48;
+constexpr int kKeyIconSize = 14;
+constexpr int kPadingAroundSmallIcon = 4;
+constexpr int kPaddingBetweenItems = 8;
+
+}  // namespace
+
+PickerCapsNudgeView::PickerCapsNudgeView() {
+  SetLayoutManager(std::make_unique<views::FlexLayout>())
+      ->SetOrientation(views::LayoutOrientation::kHorizontal)
+      .SetCrossAxisAlignment(views::LayoutAlignment::kCenter);
+
+  // LHS - Random placeholder icon.
+  const ui::ImageModel icon = ui::ImageModel::FromVectorIcon(
+      vector_icons::kForwardArrowIcon, ui::kColorAvatarIconIncognito,
+      kLeftIconSize);
+  AddChildView(views::Builder<views::ImageView>()
+                   .SetImage(icon)
+                   .SetBorder(views::CreateEmptyBorder(
+                       gfx::Insets::TLBR(0, 0, 0, kPaddingBetweenItems)))
+                   .Build());
+
+  // Central nudge text.
+  // TODO(b/323413906): translate all strings below.
+  auto* nudge_text_container =
+      AddChildView(views::Builder<views::FlexLayoutView>()
+                       .SetOrientation(views::LayoutOrientation::kVertical)
+                       .SetCrossAxisAlignment(views::LayoutAlignment::kStart)
+                       .Build());
+
+  // Allow the nudge text to grow to ensure good padding between text and the
+  // buttons.
+  nudge_text_container->SetProperty(
+      views::kFlexBehaviorKey,
+      views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToMinimum,
+                               views::MaximumFlexSizeRule::kUnbounded)
+          .WithWeight(1));
+  nudge_text_container->AddChildView(ash::bubble_utils::CreateLabel(
+      TypographyToken::kCrosButton2, u"Looking for Caps Lock",
+      cros_tokens::kCrosSysOnSurface));
+
+  auto* secondary_text = nudge_text_container->AddChildView(
+      views::Builder<views::FlexLayoutView>()
+          .SetOrientation(views::LayoutOrientation::kHorizontal)
+          .SetCollapseMargins(true)
+          .SetIgnoreDefaultMainAxisMargins(true)
+          .Build());
+  secondary_text->SetDefault(
+      views::kMarginsKey,
+      gfx::Insets::TLBR(0, kPadingAroundSmallIcon, 0, kPadingAroundSmallIcon));
+  secondary_text->AddChildView(ash::bubble_utils::CreateLabel(
+      TypographyToken::kCrosAnnotation1, u"Hold the",
+      cros_tokens::kCrosSysSecondary));
+
+  const ui::ImageModel key_icon = ui::ImageModel::FromVectorIcon(
+      vector_icons::kForwardArrowIcon, cros_tokens::kCrosSysSystemOnBase,
+      kKeyIconSize);
+  secondary_text->AddChildView(
+      views::Builder<views::ImageView>().SetImage(key_icon).Build());
+  secondary_text->AddChildView(
+      ash::bubble_utils::CreateLabel(TypographyToken::kCrosAnnotation1, u"key",
+                                     cros_tokens::kCrosSysSecondary));
+
+  // RHS - OK pill button.
+  AddChildView(
+      views::Builder<ash::PillButton>()
+          .SetText(u"OK")
+          .SetBorder(views::CreateEmptyBorder(
+              gfx::Insets::TLBR(0, kPaddingBetweenItems, 0, 0)))
+          .SetPillButtonType(ash::PillButton::Type::kDefaultElevatedWithoutIcon)
+          .Build());
+
+  SetBorder(views::CreateEmptyBorder(kPadding));
+  SetBackground(views::CreateThemedRoundedRectBackground(kBackgroundColor,
+                                                         kBorderRadius));
+  SetProperty(views::kMarginsKey,
+              gfx::Insets::TLBR(kPaddingBetweenItems, kPaddingBetweenItems, 0,
+                                kPaddingBetweenItems));
+}
+
+PickerCapsNudgeView::~PickerCapsNudgeView() = default;
+
+BEGIN_METADATA(PickerCapsNudgeView)
+END_METADATA
+}  // namespace ash
diff --git a/ash/picker/views/picker_caps_nudge_view.h b/ash/picker/views/picker_caps_nudge_view.h
new file mode 100644
index 0000000..8ac982c
--- /dev/null
+++ b/ash/picker/views/picker_caps_nudge_view.h
@@ -0,0 +1,27 @@
+// Copyright 2024 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_PICKER_VIEWS_PICKER_CAPS_NUDGE_VIEW_H_
+#define ASH_PICKER_VIEWS_PICKER_CAPS_NUDGE_VIEW_H_
+
+#include "ash/ash_export.h"
+#include "ui/base/metadata/metadata_header_macros.h"
+#include "ui/views/view.h"
+
+namespace ash {
+
+// View for the caps notifier in the picker zero state
+class ASH_EXPORT PickerCapsNudgeView : public views::View {
+  METADATA_HEADER(PickerCapsNudgeView, views::View)
+
+ public:
+  PickerCapsNudgeView();
+  PickerCapsNudgeView(const PickerCapsNudgeView&) = delete;
+  PickerCapsNudgeView& operator=(const PickerCapsNudgeView&) = delete;
+  ~PickerCapsNudgeView() override;
+};
+
+}  // namespace ash
+
+#endif  // ASH_PICKER_VIEWS_PICKER_CAPS_NUDGE_VIEW_H_
diff --git a/ash/picker/views/picker_search_field_view.cc b/ash/picker/views/picker_search_field_view.cc
index b530496..03a5ec6 100644
--- a/ash/picker/views/picker_search_field_view.cc
+++ b/ash/picker/views/picker_search_field_view.cc
@@ -44,7 +44,7 @@
           .SetFontList(TypographyProvider::Get()->ResolveTypographyToken(
               TypographyToken::kCrosBody2))
           .SetPlaceholderText(l10n_util::GetStringUTF16(
-              IDS_PICKER_SEARCH_FIELD_PLACEHOLDER_TEXT))
+              IDS_PICKER_ZERO_STATE_SEARCH_FIELD_PLACEHOLDER_TEXT))
           // TODO(b/309706053): Replace this once the strings are finalized.
           .SetAccessibleName(u"placeholder")
           .Build());
diff --git a/ash/picker/views/picker_strings.cc b/ash/picker/views/picker_strings.cc
index 40fb3597..13ca6e5 100644
--- a/ash/picker/views/picker_strings.cc
+++ b/ash/picker/views/picker_strings.cc
@@ -23,4 +23,22 @@
   }
 }
 
+std::u16string GetSearchFieldPlaceholderTextForPickerCategory(
+    PickerCategory category) {
+  switch (category) {
+    case PickerCategory::kEmojis:
+      return l10n_util::GetStringUTF16(
+          IDS_PICKER_EMOJIS_CATEGORY_SEARCH_FIELD_PLACEHOLDER_TEXT);
+    case PickerCategory::kSymbols:
+      return l10n_util::GetStringUTF16(
+          IDS_PICKER_SYMBOLS_CATEGORY_SEARCH_FIELD_PLACEHOLDER_TEXT);
+    case PickerCategory::kEmoticons:
+      return l10n_util::GetStringUTF16(
+          IDS_PICKER_EMOTICONS_CATEGORY_SEARCH_FIELD_PLACEHOLDER_TEXT);
+    case PickerCategory::kGifs:
+      return l10n_util::GetStringUTF16(
+          IDS_PICKER_GIFS_CATEGORY_SEARCH_FIELD_PLACEHOLDER_TEXT);
+  }
+}
+
 }  // namespace ash
diff --git a/ash/picker/views/picker_strings.h b/ash/picker/views/picker_strings.h
index 73a04fe..167989a 100644
--- a/ash/picker/views/picker_strings.h
+++ b/ash/picker/views/picker_strings.h
@@ -13,6 +13,9 @@
 
 std::u16string GetLabelForPickerCategory(PickerCategory category);
 
+std::u16string GetSearchFieldPlaceholderTextForPickerCategory(
+    PickerCategory category);
+
 }  // namespace ash
 
 #endif  // ASH_PICKER_VIEWS_PICKER_STRINGS_H_
diff --git a/ash/picker/views/picker_view.cc b/ash/picker/views/picker_view.cc
index a603399..e12de80 100644
--- a/ash/picker/views/picker_view.cc
+++ b/ash/picker/views/picker_view.cc
@@ -13,6 +13,7 @@
 #include "ash/picker/views/picker_contents_view.h"
 #include "ash/picker/views/picker_search_field_view.h"
 #include "ash/picker/views/picker_search_results_view.h"
+#include "ash/picker/views/picker_strings.h"
 #include "ash/picker/views/picker_view_delegate.h"
 #include "ash/picker/views/picker_zero_state_view.h"
 #include "ash/style/system_shadow.h"
@@ -278,6 +279,8 @@
 
 void PickerView::SelectCategory(PickerCategory category) {
   selected_category_ = category;
+  search_field_view_->SetPlaceholderText(
+      GetSearchFieldPlaceholderTextForPickerCategory(category));
   contents_view_->SetActivePage(category_view_);
   delegate_->GetResultsForCategory(
       category, base::BindRepeating(&PickerView::PublishCategoryResults,
diff --git a/ash/picker/views/picker_view_unittest.cc b/ash/picker/views/picker_view_unittest.cc
index e67cc5f..834fe54 100644
--- a/ash/picker/views/picker_view_unittest.cc
+++ b/ash/picker/views/picker_view_unittest.cc
@@ -15,6 +15,7 @@
 #include "ash/picker/views/picker_section_view.h"
 #include "ash/picker/views/picker_view_delegate.h"
 #include "ash/picker/views/picker_zero_state_view.h"
+#include "ash/strings/grit/ash_strings.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/test_ash_web_view.h"
 #include "ash/test/test_ash_web_view_factory.h"
@@ -25,6 +26,7 @@
 #include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/display/screen.h"
 #include "ui/events/event_constants.h"
@@ -32,6 +34,7 @@
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/views/background.h"
+#include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/view_utils.h"
 
 namespace ash {
@@ -271,6 +274,25 @@
   EXPECT_FALSE(picker_view->search_results_view_for_testing().GetVisible());
 }
 
+TEST_F(PickerViewTest, SelectingCategoryUpdatesSearchFieldPlaceholderText) {
+  FakePickerViewDelegate delegate;
+  auto widget =
+      PickerView::CreateWidget(kDefaultCaretBounds, kDefaultCursorPoint,
+                               kDefaultFocusedWindowBounds, &delegate);
+  widget->Show();
+
+  PickerView* picker_view = GetPickerViewFromWidget(*widget);
+  views::View* category_item_view = GetCategoryItemView(picker_view);
+  ViewDrawnWaiter().Wait(category_item_view);
+  LeftClickOn(category_item_view);
+
+  EXPECT_THAT(picker_view->search_field_view_for_testing()
+                  .textfield_for_testing()
+                  .GetPlaceholderText(),
+              Eq(l10n_util::GetStringUTF16(
+                  IDS_PICKER_EMOJIS_CATEGORY_SEARCH_FIELD_PLACEHOLDER_TEXT)));
+}
+
 TEST_F(PickerViewTest, SearchingWithCategorySwitchesToSearchResultsView) {
   FakePickerViewDelegate delegate;
   auto widget =
diff --git a/ash/picker/views/picker_zero_state_view.cc b/ash/picker/views/picker_zero_state_view.cc
index 59ef1be8..0e0e2abd 100644
--- a/ash/picker/views/picker_zero_state_view.cc
+++ b/ash/picker/views/picker_zero_state_view.cc
@@ -11,6 +11,7 @@
 
 #include "ash/picker/model/picker_category.h"
 #include "ash/picker/model/picker_model.h"
+#include "ash/picker/views/picker_caps_nudge_view.h"
 #include "ash/picker/views/picker_icons.h"
 #include "ash/picker/views/picker_item_view.h"
 #include "ash/picker/views/picker_section_view.h"
@@ -37,6 +38,8 @@
   SetLayoutManager(std::make_unique<views::FlexLayout>())
       ->SetOrientation(views::LayoutOrientation::kVertical);
 
+  AddChildView(std::make_unique<PickerCapsNudgeView>());
+
   // TODO: b/316935911 - Get actual sections for the categories.
   auto* section_view = AddChildView(
       std::make_unique<PickerSectionView>(kPlaceholderCategorySectionTitle));
diff --git a/ash/public/cpp/picker/picker_client.cc b/ash/public/cpp/picker/picker_client.cc
index d8438f8..6b0f18f9a 100644
--- a/ash/public/cpp/picker/picker_client.cc
+++ b/ash/public/cpp/picker/picker_client.cc
@@ -6,6 +6,24 @@
 
 namespace ash {
 
+std::optional<ValidGifUrl> ValidGifUrl::Create(const GURL& url) {
+  // For now, only allow gifs from tenor.
+  // TODO: b/323784358 - Once we know what gifs the picker might show, consider
+  // making the method parameters more specific to allowed gif sources.
+  if (url.DomainIs("media.tenor.com") && url.SchemeIs(url::kHttpsScheme)) {
+    return ValidGifUrl(url);
+  }
+  return std::nullopt;
+}
+
+ValidGifUrl::~ValidGifUrl() = default;
+
+GURL ValidGifUrl::ToGURL() const {
+  return url_;
+}
+
+ValidGifUrl::ValidGifUrl(GURL url) : url_(url) {}
+
 PickerClient::PickerClient() = default;
 
 PickerClient::~PickerClient() = default;
diff --git a/ash/public/cpp/picker/picker_client.h b/ash/public/cpp/picker/picker_client.h
index 72469778..5ff23d0 100644
--- a/ash/public/cpp/picker/picker_client.h
+++ b/ash/public/cpp/picker/picker_client.h
@@ -6,16 +6,30 @@
 #define ASH_PUBLIC_CPP_PICKER_PICKER_CLIENT_H_
 
 #include <memory>
+#include <optional>
 #include <string>
 
 #include "ash/public/cpp/ash_public_export.h"
 #include "ash/public/cpp/ash_web_view.h"
 #include "base/functional/callback_forward.h"
-
-class GURL;
+#include "url/gurl.h"
 
 namespace ash {
 
+class ASH_PUBLIC_EXPORT ValidGifUrl {
+ public:
+  static std::optional<ValidGifUrl> Create(const GURL& url);
+
+  ~ValidGifUrl();
+
+  GURL ToGURL() const;
+
+ private:
+  explicit ValidGifUrl(GURL url);
+
+  GURL url_;
+};
+
 // Lets PickerController in Ash to communicate with the browser.
 class ASH_PUBLIC_EXPORT PickerClient {
  public:
@@ -28,7 +42,7 @@
   // Downloads a gif from `url`. If the download is successful, the gif is
   // passed to `callback` as a string of encoded bytes in gif format. Otherwise,
   // `callback` is run with an empty string.
-  virtual void DownloadGifToString(const GURL& url,
+  virtual void DownloadGifToString(const ValidGifUrl& url,
                                    DownloadGifToStringCallback callback) = 0;
 
  protected:
diff --git a/ash/system/focus_mode/focus_mode_tray.cc b/ash/system/focus_mode/focus_mode_tray.cc
index ba9104a..4b7c5c8 100644
--- a/ash/system/focus_mode/focus_mode_tray.cc
+++ b/ash/system/focus_mode/focus_mode_tray.cc
@@ -48,6 +48,20 @@
 constexpr base::TimeDelta kTaskItemViewFadeOutDuration =
     base::Milliseconds(200);
 
+std::u16string GetAccessibleTrayName(
+    const FocusModeSession::Snapshot& session_snapshot) {
+  if (session_snapshot.state == FocusModeSession::State::kEnding) {
+    return l10n_util::GetStringUTF16(
+        IDS_ASH_STATUS_TRAY_FOCUS_MODE_TRAY_BUBBLE_ENDING_MOMENT_ACCESSIBLE_NAME);
+  }
+
+  const std::u16string time_remaining =
+      focus_mode_util::GetDurationString(session_snapshot.remaining_time,
+                                         /*digital_format=*/false);
+  return l10n_util::GetStringFUTF16(
+      IDS_ASH_STATUS_TRAY_FOCUS_MODE_TRAY_ACCESSIBLE_NAME, time_remaining);
+}
+
 }  // namespace
 
 class FocusModeTray::TaskItemView : public views::BoxLayoutView {
@@ -128,7 +142,6 @@
   SetCallback(base::BindRepeating(&FocusModeTray::FocusModeIconActivated,
                                   weak_ptr_factory_.GetWeakPtr()));
 
-  image_view_->SetTooltipText(GetAccessibleNameForTray());
   image_view_->SetHorizontalAlignment(views::ImageView::Alignment::kCenter);
   image_view_->SetVerticalAlignment(views::ImageView::Alignment::kCenter);
   image_view_->SetPreferredSize(gfx::Size(kTrayItemSize, kTrayItemSize));
@@ -188,9 +201,11 @@
 }
 
 std::u16string FocusModeTray::GetAccessibleNameForTray() {
-  // TODO(b/288975135): Update once we get UX writing.
-  return l10n_util::GetStringUTF16(
-      IDS_ASH_STATUS_TRAY_FOCUS_MODE_TOGGLE_ACTIVE_LABEL);
+  if (!session_snapshot_) {
+    return std::u16string();
+  }
+
+  return GetAccessibleTrayName(session_snapshot_.value());
 }
 
 std::u16string FocusModeTray::GetAccessibleNameForBubble() {
@@ -284,8 +299,9 @@
   ending_moment_view_ = bubble_view_container_->AddChildView(
       std::make_unique<FocusModeEndingMomentView>());
 
-  UpdateBubbleViews(
-      controller->current_session()->GetSnapshot(base::Time::Now()));
+  session_snapshot_ =
+      controller->current_session()->GetSnapshot(base::Time::Now());
+  UpdateBubbleViews(session_snapshot_.value());
 
   if (controller->HasSelectedTask()) {
     task_item_view_ =
@@ -318,23 +334,32 @@
 void FocusModeTray::OnFocusModeChanged(bool in_focus_session) {
   UpdateProgressRing();
 
-  if (!bubble_) {
+  auto current_session = FocusModeController::Get()->current_session();
+  if (!current_session) {
+    session_snapshot_.reset();
     return;
   }
 
-  auto current_session = FocusModeController::Get()->current_session();
-  CHECK(current_session);
-  UpdateBubbleViews(current_session->GetSnapshot(base::Time::Now()));
+  session_snapshot_ = current_session->GetSnapshot(base::Time::Now());
+  image_view_->SetTooltipText(GetAccessibleTrayName(session_snapshot_.value()));
+
+  if (bubble_) {
+    UpdateBubbleViews(session_snapshot_.value());
+  }
 }
 
 void FocusModeTray::OnTimerTick(
     const FocusModeSession::Snapshot& session_snapshot) {
+  session_snapshot_ = session_snapshot;
+  image_view_->SetTooltipText(GetAccessibleTrayName(session_snapshot_.value()));
   UpdateProgressRing();
   MaybeUpdateCountdownViewUI(session_snapshot);
 }
 
 void FocusModeTray::OnActiveSessionDurationChanged(
     const FocusModeSession::Snapshot& session_snapshot) {
+  session_snapshot_ = session_snapshot;
+  image_view_->SetTooltipText(GetAccessibleTrayName(session_snapshot_.value()));
   UpdateProgressRing();
   MaybeUpdateCountdownViewUI(session_snapshot);
 }
diff --git a/ash/system/focus_mode/focus_mode_tray.h b/ash/system/focus_mode/focus_mode_tray.h
index 92743ebf..475f747 100644
--- a/ash/system/focus_mode/focus_mode_tray.h
+++ b/ash/system/focus_mode/focus_mode_tray.h
@@ -102,6 +102,9 @@
   // Updates the progression of the progress indicator.
   void UpdateProgressRing();
 
+  // This is used to track the current session snapshot, if any.
+  std::optional<FocusModeSession::Snapshot> session_snapshot_;
+
   // Image view of the focus mode lamp.
   const raw_ptr<views::ImageView> image_view_;
 
diff --git a/ash/webui/BUILD.gn b/ash/webui/BUILD.gn
index 4fb5d52d..3c1c4fe 100644
--- a/ash/webui/BUILD.gn
+++ b/ash/webui/BUILD.gn
@@ -67,7 +67,6 @@
     "//ash/webui/eche_app_ui:closure_compile",
     "//ash/webui/file_manager/untrusted_resources:closure_compile",
     "//ash/webui/files_internals:closure_compile",
-    "//ash/webui/help_app_ui:closure_compile",
     "//ash/webui/media_app_ui:closure_compile",
     "//ash/webui/multidevice_debug/resources:closure_compile",
     "//ash/webui/projector_app/resources:closure_compile",
diff --git a/ash/webui/help_app_ui/BUILD.gn b/ash/webui/help_app_ui/BUILD.gn
index 4d25136..6c07116 100644
--- a/ash/webui/help_app_ui/BUILD.gn
+++ b/ash/webui/help_app_ui/BUILD.gn
@@ -7,7 +7,6 @@
 import("//build/buildflag_header.gni")
 import("//build/config/chromeos/ui_mode.gni")
 import("//mojo/public/tools/bindings/mojom.gni")
-import("//third_party/closure_compiler/compile_js.gni")
 
 assert(is_chromeos_ash, "Help App is ash-chrome only")
 
@@ -96,16 +95,6 @@
   ]
 }
 
-group("closure_compile") {
-  testonly = true
-  deps = [
-    ":closure_compile_browsertests",
-    ":closure_compile_test_lib",
-    "resources:closure_compile",
-    "resources/mock:closure_compile",
-  ]
-}
-
 source_set("browser_test_support") {
   testonly = true
   sources = [
@@ -131,93 +120,6 @@
   ]
 }
 
-mojo_test_flags = mojom_js_args + [
-                    "language_in=ECMASCRIPT_2020",
-                    "js_module_root=" +
-                        rebase_path("resources", root_build_dir),
-                    "js_module_root=" + rebase_path(
-                            "$root_gen_dir/mojom-webui/ash/webui/help_app_ui",
-                            root_build_dir),
-                    "js_module_root=" + rebase_path(
-                            "$root_gen_dir/mojom-webui/ash/webui/help_app_ui/search",
-                            root_build_dir),
-                    "js_module_root=" + rebase_path(
-                            "$root_gen_dir/mojom-webui/chromeos/ash/components/local_search_service/public/mojom",
-                            root_build_dir),
-                  ]
-
-js_type_check("closure_compile_test_lib") {
-  testonly = true
-  closure_flags = system_app_closure_flags_strict + mojo_test_flags
-  deps = [
-    ":test_driver_api_js",
-    ":test_driver_js",
-    ":test_guest_query_receiver_js",
-  ]
-}
-
-# Use relaxed flags for the browsertest files themselves. This removes null
-# checks and "could not determine type" errors which don't add a lot of value.
-js_type_check("closure_compile_browsertests") {
-  testonly = true
-  closure_flags = system_app_closure_flags + mojo_test_flags
-  deps = [
-    ":test_help_app_guest_ui_browsertest_js",
-    ":test_help_app_ui_browsertest_js",
-  ]
-}
-
-js_library("test_driver_api_js") {
-  testonly = true
-  sources = [ "test/driver_api.js" ]
-}
-
-js_library("test_guest_query_receiver_js") {
-  testonly = true
-  sources = [ "test/guest_query_receiver.js" ]
-  externs_list = [ "//ash/webui/system_apps/public/js/message_pipe.externs.js" ]
-  deps = [
-    ":test_driver_api_js",
-    "//ash/webui/help_app_ui/resources:receiver",
-  ]
-}
-
-js_library("test_driver_js") {
-  testonly = true
-  sources = [ "test/driver.js" ]
-  externs_list = [
-    "//third_party/closure_compiler/externs/chai-3.5.js",
-    "//ash/webui/system_apps/public/js/message_pipe.externs.js",
-  ]
-  deps = [
-    ":test_driver_api_js",
-    "//ash/webui/help_app_ui/resources:browser_proxy",
-  ]
-}
-
-js_library("test_help_app_ui_browsertest_js") {
-  testonly = true
-  sources = [ "test/help_app_ui_browsertest.js" ]
-  externs_list = [ "//ash/webui/system_apps/public/js/message_pipe.externs.js" ]
-  deps = [
-    ":test_driver_js",
-    "//ash/webui/help_app_ui/resources:browser_proxy",
-  ]
-}
-
-js_library("test_help_app_guest_ui_browsertest_js") {
-  testonly = true
-  sources = [ "test/help_app_guest_ui_browsertest.js" ]
-  externs_list = [
-    "//ash/webui/web_applications/js2gtest_support.externs.js",
-    "//ash/webui/system_apps/public/js/message_pipe.externs.js",
-  ]
-  deps = [
-    ":test_driver_js",
-    "//ash/webui/help_app_ui/resources:receiver",
-  ]
-}
-
 # Used to turn off tests that only work with our CIPD package.
 buildflag_header("buildflags") {
   header = "buildflags.h"
diff --git a/ash/webui/help_app_ui/resources/BUILD.gn b/ash/webui/help_app_ui/resources/BUILD.gn
index 40808bb35..dbcda6c 100644
--- a/ash/webui/help_app_ui/resources/BUILD.gn
+++ b/ash/webui/help_app_ui/resources/BUILD.gn
@@ -4,50 +4,68 @@
 
 import("//ash/webui/web_applications/system_apps.gni")
 import("//build/config/chromeos/ui_mode.gni")
-import("//third_party/closure_compiler/compile_js.gni")
+import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/optimize_webui.gni")
 
 assert(is_chromeos_ash, "Help App is ash-chrome only")
 
-stage_folder = "$target_gen_dir/stage"
+stage_folder = "$target_gen_dir/stage_rollup"
+ts_root_dir = "$target_gen_dir/stage_ts"
 
-group("closure_compile") {
-  deps = [
-    ":closure_compile_app",
-    ":closure_compile_index",
+copy("copy_for_tsc") {
+  visibility = [ ":build_ts" ]
+  public_deps = [
+    "//ash/webui/help_app_ui:mojo_bindings_js__generator",
+    "//ash/webui/help_app_ui/search:mojo_bindings_js__generator",
+    "//ash/webui/system_apps/public/js:build_ts",
+    "//chromeos/ash/components/local_search_service/public/mojom:mojom_js__generator",
   ]
-}
-
-# Move all files into a single folder so optimize_webui can generate a single
-# file bundle. stage_static moves all static files from src/ into stage/ and
-# stage_generated moves generated files from gen/ into stage/.
-copy("stage_static") {
-  sources = [
-    "//ash/webui/system_apps/public/js/sandboxed_load_time_data.js",
-    "browser_proxy.js",
-    "message_types.js",
-    "receiver.js",
-  ]
-  outputs = [ stage_folder + "/{{source_file_part}}" ]
-}
-
-copy("stage_generated") {
   sources = [
     "$root_gen_dir/ash/webui/system_apps/public/js/message_pipe.js",
     "$root_gen_dir/mojom-webui/ash/webui/help_app_ui/help_app_ui.mojom-webui.js",
     "$root_gen_dir/mojom-webui/ash/webui/help_app_ui/search/search.mojom-webui.js",
     "$root_gen_dir/mojom-webui/chromeos/ash/components/local_search_service/public/mojom/index.mojom-webui.js",
     "$root_gen_dir/mojom-webui/chromeos/ash/components/local_search_service/public/mojom/types.mojom-webui.js",
+    "//ui/webui/resources/js/mojo_type_util.ts",
+    "browser_proxy.ts",
+    "message_types.ts",
+    "receiver.ts",
   ]
-  outputs = [ stage_folder + "/{{source_file_part}}" ]
-  deps = [
-    "//ash/webui/help_app_ui:mojo_bindings_js__generator",
-    "//ash/webui/help_app_ui/search:mojo_bindings_js__generator",
-    "//ash/webui/system_apps/public/js:build_ts",
-    "//chromeos/ash/components/local_search_service/public/mojom:mojom_js__generator",
-  ]
+  outputs = [ "${ts_root_dir}/{{source_file_part}}" ]
 }
 
+ts_library("build_ts") {
+  root_dir = ts_root_dir
+  in_files = []
+  foreach(o, get_target_outputs(":copy_for_tsc")) {
+    in_files += [ rebase_path(o, ts_root_dir) ]
+  }
+  definitions = [ "//ash/webui/help_app_ui/resources/js/help_app.d.ts" ]
+
+  # The out_dir needs to be a different folder from the folder containing files
+  # generated by targets in this BUILD.gn, otherwise it may be treated as an
+  # artifact from a previous build which will cause ts_library to delete them.
+  out_dir = stage_folder
+  deps = [
+    "//ash/webui/common/resources:build_ts",
+    "//ash/webui/system_apps/public/js:build_ts",
+    "//ui/webui/resources/cr_components/color_change_listener:build_ts",
+    "//ui/webui/resources/mojo:build_ts",
+  ]
+  extra_deps = [ ":copy_for_tsc" ]
+  path_mappings = [ "//system_apps/*|" + rebase_path(
+                        "$root_gen_dir/ash/webui/system_apps/public/js/*",
+                        target_gen_dir) ]
+}
+
+copy("stage_static") {
+  sources = [ "//ash/webui/system_apps/public/js/sandboxed_load_time_data.js" ]
+  outputs = [ stage_folder + "/{{source_file_part}}" ]
+}
+
+system_apps_dir =
+    rebase_path("$root_gen_dir/ash/webui/system_apps/public/js", root_build_dir)
+
 # Generate a bundle of all the JS needed for chrome://help-app.
 optimize_webui("browser_proxy_rollup") {
   host = "help-app"
@@ -62,9 +80,10 @@
   ]
   input = rebase_path(stage_folder, root_build_dir)
   deps = [
-    ":stage_generated",
+    ":build_ts",
     ":stage_static",
   ]
+  external_paths = [ "//system_apps/|$system_apps_dir" ]
 }
 
 # Generate a bundle of all the JS needed for chrome-untrusted://help-app.
@@ -73,59 +92,8 @@
   js_module_in_files = [ "receiver.js" ]
   input = rebase_path(stage_folder, root_build_dir)
   deps = [
-    ":stage_generated",
+    ":build_ts",
     ":stage_static",
-    "//ui/webui/resources/cr_components/color_change_listener:build_ts",
   ]
-}
-
-js_type_check("closure_compile_index") {
-  closure_flags = system_app_closure_flags_strict + mojom_js_args + [
-                    "js_module_root=" + rebase_path(".", root_build_dir),
-                    "js_module_root=" + rebase_path(
-                            "$root_gen_dir/mojom-webui/ash/webui/help_app_ui",
-                            root_build_dir),
-                    "js_module_root=" + rebase_path(
-                            "$root_gen_dir/mojom-webui/ash/webui/help_app_ui/search",
-                            root_build_dir),
-                    "js_module_root=" + rebase_path(
-                            "$root_gen_dir/mojom-webui/chromeos/ash/components/local_search_service/public/mojom",
-                            root_build_dir),
-                  ]
-
-  deps = [ ":browser_proxy" ]
-}
-
-js_type_check("closure_compile_app") {
-  closure_flags = system_app_closure_flags_strict
-  deps = [ ":receiver" ]
-}
-
-# We don't use these libraries in our build process but have them so we can
-# retain type checking via the above js_type_check rules.
-js_library("browser_proxy") {
-  externs_list = [
-    # The privileged context can't access the app, but shares struct definitions
-    # passed over postMessage.
-    "help_app.externs.js",
-    "//third_party/closure_compiler/externs/metrics_private.js",
-    "//ash/webui/system_apps/public/js/message_pipe.externs.js",
-  ]
-  deps = [
-    ":message_types",
-    "//ash/webui/help_app_ui:mojo_bindings_webui_js",
-    "//ash/webui/help_app_ui/search:mojo_bindings_webui_js",
-    "//chromeos/ash/components/local_search_service/public/mojom:mojom_webui_js",
-  ]
-}
-
-js_library("message_types") {
-}
-
-js_library("receiver") {
-  externs_list = [
-    "help_app.externs.js",
-    "//ash/webui/system_apps/public/js/message_pipe.externs.js",
-  ]
-  deps = [ ":message_types" ]
+  external_paths = [ "//system_apps/|$system_apps_dir" ]
 }
diff --git a/ash/webui/help_app_ui/resources/browser_proxy.js b/ash/webui/help_app_ui/resources/browser_proxy.ts
similarity index 63%
rename from ash/webui/help_app_ui/resources/browser_proxy.js
rename to ash/webui/help_app_ui/resources/browser_proxy.ts
index a913c7fb..8cf75dab 100644
--- a/ash/webui/help_app_ui/resources/browser_proxy.js
+++ b/ash/webui/help_app_ui/resources/browser_proxy.ts
@@ -1,27 +1,26 @@
 // Copyright 2020 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-import {stringToMojoString16} from 'chrome://resources/js/mojo_type_util.js';
+import {stringToMojoString16} from './mojo_type_util.js';
 import {String16} from 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-webui.js';
 import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js';
 
 import {PageHandlerFactory, PageHandlerRemote} from './help_app_ui.mojom-webui.js';
-import {Index, IndexRemote} from './index.mojom-webui.js';
-import {MessagePipe} from './message_pipe.js';
+import {Index} from './index.mojom-webui.js';
+import {MessagePipe} from '//system_apps/message_pipe.js';
 import {Message} from './message_types.js';
-import {SearchConcept, SearchHandler, SearchHandlerRemote} from './search.mojom-webui.js';
+import {SearchConcept, SearchHandler} from './search.mojom-webui.js';
 import {Content, ResponseStatus, Result} from './types.mojom-webui.js';
 
-const help_app = {
+const helpApp = {
   handler: new PageHandlerRemote(),
 };
 
 // Set up a page handler to talk to the browser process.
 PageHandlerFactory.getRemote().createPageHandler(
-    help_app.handler.$.bindNewPipeAndPassReceiver());
+    helpApp.handler.$.bindNewPipeAndPassReceiver());
 
 // Set up an index remote to talk to Local Search Service.
-/** @type {!IndexRemote} */
 const indexRemote = Index.getRemote();
 
 // Expose `indexRemote` on `window`, because it is accessed by a CrOS Tast test.
@@ -30,47 +29,36 @@
 /**
  * Talks to the search handler. Use for updating the content for launcher
  * search.
- *
- * @type {!SearchHandlerRemote}
  */
 const searchHandlerRemote = SearchHandler.getRemote();
 
 const GUEST_ORIGIN = 'chrome-untrusted://help-app';
 const MAX_STRING_LEN = 9999;
-const guestFrame =
-    /** @type {!HTMLIFrameElement} */ (document.createElement('iframe'));
+const guestFrame = document.createElement('iframe');
 guestFrame.src = `${GUEST_ORIGIN}${location.pathname}`;
 document.body.appendChild(guestFrame);
 
 // Cached result whether Local Search Service is enabled.
-/** @type {Promise<boolean>} */
 const isLssEnabled =
-    help_app.handler.isLssEnabled().then(result => result.enabled);
+    helpApp.handler.isLssEnabled().then(result => result.enabled);
 
 // Cached result of whether Launcher Search is enabled.
-/** @type {Promise<boolean>} */
 const isLauncherSearchEnabled =
-    help_app.handler.isLauncherSearchEnabled().then(result => result.enabled);
+    helpApp.handler.isLauncherSearchEnabled().then(result => result.enabled);
 
-/**
- * @param {string|Object} url
- * @return {!Url}
- */
-function toUrl(url) {
+/** Converts a string or object to url. */
+function toUrl(url: string|object): Url {
   // TODO(b/279132899): Figure out why `url` is an empty object when it should
   // have been an empty string.
   if (url === '' || typeof (url) !== 'string') {
-    return /** @type {!Url} */ ({url: ''});
+    return {url: ''};
   }
-  return /** @type {!Url} */ ({url});
+  return {url};
 }
 
-/**
- * @param {string} s
- * @return {!String16}
- */
-function toTruncatedString16(s) {
-  return /** @type {!String16} */ (stringToMojoString16(truncate(s)));
+/** Converts string to String16. */
+function toTruncatedString16(s: string): String16 {
+  return stringToMojoString16(truncate(s));
 }
 const TITLE_ID = 'title';
 const BODY_ID = 'body';
@@ -90,71 +78,70 @@
     /*rethrowErrors=*/ false);
 
 guestMessagePipe.registerHandler(Message.OPEN_FEEDBACK_DIALOG, () => {
-  return help_app.handler.openFeedbackDialog();
+  return helpApp.handler.openFeedbackDialog();
 });
 
-guestMessagePipe.registerHandler(Message.SHOW_PARENTAL_CONTROLS, () => {
-  help_app.handler.showParentalControls();
-});
+guestMessagePipe.registerHandler(Message.SHOW_PARENTAL_CONTROLS, () => void
+  helpApp.handler.showParentalControls());
 
 guestMessagePipe.registerHandler(
-    Message.TRIGGER_WELCOME_TIP_CALL_TO_ACTION, (actionTypeId) => {
-      help_app.handler.triggerWelcomeTipCallToAction(actionTypeId);
-    });
+    Message.TRIGGER_WELCOME_TIP_CALL_TO_ACTION, (actionTypeId: number) => void
+      helpApp.handler.triggerWelcomeTipCallToAction(actionTypeId));
 
 guestMessagePipe.registerHandler(
-    Message.ADD_OR_UPDATE_SEARCH_INDEX, async (message) => {
+    Message.ADD_OR_UPDATE_SEARCH_INDEX, async (data: SearchableItem[]) => {
       if (!(await isLssEnabled)) {
         return;
       }
-      const data_from_app =
-          /** @type {!Array<!helpApp.SearchableItem>} */ (message);
-      const data_to_send = data_from_app.map(searchable_item => {
-        /** @type {!Array<!Content>} */
-        const contents = [
+      const dataToSend = data.map(searchableItem => {
+        const contents: Content[] = [
           {
             id: TITLE_ID,
-            content: toTruncatedString16(searchable_item.title),
+            content: toTruncatedString16(searchableItem.title),
             weight: 1.0,
           },
           {
             id: CATEGORY_ID,
-            content: toTruncatedString16(searchable_item.mainCategoryName),
+            content: toTruncatedString16(searchableItem.mainCategoryName),
             weight: 0.1,
           },
         ];
-        if (searchable_item.subcategoryNames) {
-          for (let i = 0; i < searchable_item.subcategoryNames.length; ++i) {
+        if (searchableItem.subcategoryNames) {
+          for (let i = 0; i < searchableItem.subcategoryNames.length; ++i) {
+            const subcategoryName = searchableItem.subcategoryNames[i]!;
             contents.push({
               id: SUBCATEGORY_ID + i,
-              content: toTruncatedString16(searchable_item.subcategoryNames[i]),
+              content: toTruncatedString16(subcategoryName),
               weight: 0.1,
             });
           }
         }
         // If there are subheadings, use those instead of the body.
-        if (searchable_item.subheadings) {
-          for (let i = 0; i < searchable_item.subheadings.length; ++i) {
+        const subheadings = searchableItem.subheadings;
+        if (subheadings) {
+          for (let i = 0; i < subheadings.length; ++i) {
+            const subheading = subheadings[i];
+            if (!subheading) continue;
             contents.push({
               id: SUBHEADING_ID + i,
-              content: toTruncatedString16(searchable_item.subheadings[i]),
+              content: toTruncatedString16(subheading),
               weight: 0.4,
             });
           }
-        } else if (searchable_item.body) {
+        } else if (searchableItem.body) {
           contents.push({
             id: BODY_ID,
-            content: toTruncatedString16(searchable_item.body),
+            content: toTruncatedString16(searchableItem.body),
             weight: 0.2,
           });
         }
         return {
-          id: searchable_item.id,
+          id: searchableItem.id,
           contents,
-          locale: searchable_item.locale,
+          locale: searchableItem.locale,
         };
       });
-      return indexRemote.addOrUpdate(data_to_send);
+      return indexRemote.addOrUpdate(dataToSend);
     });
 
 guestMessagePipe.registerHandler(Message.CLEAR_SEARCH_INDEX, async () => {
@@ -165,38 +152,29 @@
 });
 
 guestMessagePipe.registerHandler(
-    Message.FIND_IN_SEARCH_INDEX, async (message) => {
+  Message.FIND_IN_SEARCH_INDEX,
+  async (dataFromApp: {query: string, maxResults: number}) => {
       if (!(await isLssEnabled)) {
         return {results: null};
       }
-      const dataFromApp =
-          /** @type {{query: string, maxResults:(number|undefined)}} */
-          (message);
       const response = await indexRemote.find(
           toTruncatedString16(dataFromApp.query), dataFromApp.maxResults || 50);
 
       if (response.status !== ResponseStatus.kSuccess || !response.results) {
         return {results: null};
       }
-      const search_results =
-          /** @type {!Array<!Result>} */ (response.results);
+      const searchResults: Result[] = (response.results);
       // Sort results by decreasing score.
-      search_results.sort((a, b) => b.score - a.score);
-      /** @type {!Array<!helpApp.SearchResult>} */
-      const results = search_results.map(result => {
-        /** @type {!Array<!helpApp.Position>} */
-        const titlePositions = [];
-        /** @type {!Array<!helpApp.Position>} */
-        const bodyPositions = [];
+      searchResults.sort((a, b) => b.score - a.score);
+      const results: SearchResult[] = searchResults.map(result => {
+        const titlePositions: Position[] = [];
+        const bodyPositions: Position[] = [];
         // Id of the best subheading that appears in positions. We consider
         // the subheading containing the most match positions to be the best.
         // "" means no subheading positions found.
         let bestSubheadingId = '';
-        /**
-         * Counts how many positions there are for each subheading id.
-         * @type {!Object<string, number>}
-         */
-        const subheadingPosCounts = {};
+        /** Counts how many positions there are for each subheading id. */
+        const subheadingPosCounts: Record<string, number> = {};
         // Note: result.positions is not sorted.
         for (const position of result.positions) {
           if (position.contentId === TITLE_ID) {
@@ -211,14 +189,13 @@
             const newCount = (subheadingPosCounts[position.contentId] || 0) + 1;
             subheadingPosCounts[position.contentId] = newCount;
             if (!bestSubheadingId ||
-                newCount > subheadingPosCounts[bestSubheadingId]) {
+                newCount > (subheadingPosCounts[bestSubheadingId] ?? 0)) {
               bestSubheadingId = position.contentId;
             }
           }
         }
         // Use only the positions of the best subheading.
-        /** @type {!Array<!helpApp.Position>} */
-        const subheadingPositions = [];
+        const subheadingPositions: Position[] = [];
         if (bestSubheadingId) {
           for (const position of result.positions) {
             if (position.contentId === bestSubheadingId) {
@@ -239,13 +216,13 @@
           titlePositions,
           bodyPositions,
           subheadingIndex: bestSubheadingId ?
-              Number(bestSubheadingId.substring(SUBHEADING_ID.length)) :
-              null,
+              Number(bestSubheadingId.substring(SUBHEADING_ID.length)) : null,
           subheadingPositions: bestSubheadingId ? subheadingPositions : null,
         };
       });
       return {results};
-    });
+  },
+);
 
 guestMessagePipe.registerHandler(Message.CLOSE_BACKGROUND_PAGE, async () => {
   // TODO(b/186180962): Add background page and test that it closes when done.
@@ -257,15 +234,13 @@
 });
 
 guestMessagePipe.registerHandler(
-    Message.UPDATE_LAUNCHER_SEARCH_INDEX, async (message) => {
+  Message.UPDATE_LAUNCHER_SEARCH_INDEX,
+  async (message: LauncherSearchableItem[]) => {
       if (!(await isLauncherSearchEnabled)) {
         return;
       }
 
-      const dataFromApp =
-          /** @type {!Array<!helpApp.LauncherSearchableItem>} */ (message);
-      /** @type {!Array<!SearchConcept>} */
-      const dataToSend = dataFromApp.map(
+      const dataToSend: SearchConcept[] = message.map(
           searchableItem => ({
             id: truncate(searchableItem.id),
             title: toTruncatedString16(searchableItem.title),
@@ -284,44 +259,40 @@
         // This is a google-internal histogram. If changing this, also change
         // the corresponding histograms file.
         if (!valid) {
-          chrome.metricsPrivate.recordSparseValueWithPersistentHash(
+          (window as any).chrome.metricsPrivate
+            .recordSparseValueWithPersistentHash(
               'Discover.LauncherSearch.InvalidConceptInUpdate', item.id);
         }
         return valid;
       });
       return searchHandlerRemote.update(dataFiltered);
-    });
+  },
+);
 
-guestMessagePipe.registerHandler(Message.LAUNCH_MICROSOFT_365_SETUP, () => {
-  help_app.handler.launchMicrosoft365Setup();
-});
+guestMessagePipe.registerHandler(Message.LAUNCH_MICROSOFT_365_SETUP, () => void
+  helpApp.handler.launchMicrosoft365Setup());
 
 guestMessagePipe.registerHandler(
-    Message.MAYBE_SHOW_DISCOVER_NOTIFICATION, () => {
-      help_app.handler.maybeShowDiscoverNotification();
-    });
+    Message.MAYBE_SHOW_DISCOVER_NOTIFICATION, () => void
+      helpApp.handler.maybeShowDiscoverNotification());
 
 guestMessagePipe.registerHandler(
-    Message.MAYBE_SHOW_RELEASE_NOTES_NOTIFICATION, () => {
-      help_app.handler.maybeShowReleaseNotesNotification();
-    });
+    Message.MAYBE_SHOW_RELEASE_NOTES_NOTIFICATION, () => void
+      helpApp.handler.maybeShowReleaseNotesNotification());
 
 guestMessagePipe.registerHandler(Message.GET_DEVICE_INFO, async () => {
-  return (await help_app.handler.getDeviceInfo()).deviceInfo;
+  return (await helpApp.handler.getDeviceInfo()).deviceInfo;
 });
 
 guestMessagePipe.registerHandler(
-    Message.OPEN_URL_IN_BROWSER_AND_TRIGGER_INSTALL_DIALOG, (url) => {
-      help_app.handler.openUrlInBrowserAndTriggerInstallDialog(toUrl(url));
-    });
+  Message.OPEN_URL_IN_BROWSER_AND_TRIGGER_INSTALL_DIALOG,
+  (url: string | object) => {
+    helpApp.handler.openUrlInBrowserAndTriggerInstallDialog(toUrl(url));
+  },
+);
 
-/**
- * Compare two positions by their start index. Use for sorting.
- *
- * @param {!helpApp.Position} a
- * @param {!helpApp.Position} b
- */
-function compareByStart(a, b) {
+/** Compare two positions by their start index. Use for sorting. */
+function compareByStart(a: Position, b: Position): number {
   return a.start - b.start;
 }
 
@@ -329,10 +300,9 @@
  * Limits the maximum length of the input string. Converts non-strings into
  * empty string.
  *
- * @param {*} s Probably a string, but might not be.
- * @return {string}
+ * @param s Probably a string, but might not be.
  */
-function truncate(s) {
+function truncate(s: any): string {
   if (typeof s !== 'string') {
     return '';
   }
diff --git a/ash/webui/help_app_ui/resources/help_app.externs.js b/ash/webui/help_app_ui/resources/help_app.externs.js
deleted file mode 100644
index d87bc0f..0000000
--- a/ash/webui/help_app_ui/resources/help_app.externs.js
+++ /dev/null
@@ -1,312 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview @externs
- * Externs file shipped into the chromium build to typecheck uncompiled, "pure"
- * JavaScript used to interoperate with the open-source privileged WebUI.
- * TODO(b/168274868): Convert this file to ES6.
- */
-
-/** @const */
-const helpApp = {};
-
-/**
- * Each SearchableItem maps to one Data field in the LSS Mojo API and represents
- * a single potential search result for in-app search inside the help app.
- * These originate from the untrusted frame and get parsed by the LSS.
- * @record
- * @struct
- */
-helpApp.SearchableItem = function() {};
-/**
- * The id of this item.
- * @type {string}
- */
-helpApp.SearchableItem.prototype.id;
-/**
- * Title text. Plain localized text.
- * @type {string}
- */
-helpApp.SearchableItem.prototype.title;
-/**
- * Body text. Plain localized text.
- * @type {string}
- */
-helpApp.SearchableItem.prototype.body;
-/**
- * The main category name, e.g. Perks or Help. Plain localized text.
- * @type {string}
- */
-helpApp.SearchableItem.prototype.mainCategoryName;
-/**
- * Any sub category name, e.g. a help topic name. Plain localized text.
- * @type {?Array<string>}
- */
-helpApp.SearchableItem.prototype.subcategoryNames;
-/**
- * Sub headings from the content. Removed from the body text.
- * Plain localized text.
- * @type {?Array<string>}
- */
-helpApp.SearchableItem.prototype.subheadings;
-/**
- * The locale that this content is localized in. Empty string means system
- *     locale. The format is language[-country] (e.g., en-US) where the language
- *     is the 2 or 3 letter code from ISO-639.
- * @type {string}
- */
-helpApp.SearchableItem.prototype.locale;
-
-/**
- * Each LauncherSearchableItem maps to one Data field in the LSS Mojo API and
- * represents a single potential help app search result in the CrOS launcher.
- * These originate from the untrusted frame and get parsed by the LSS.
- * @record
- * @struct
- */
-helpApp.LauncherSearchableItem = function() {};
-/**
- * The unique identifier of this item.
- * @type {string}
- */
-helpApp.LauncherSearchableItem.prototype.id;
-/**
- * Title text. Plain localized text.
- * @type {string}
- */
-helpApp.LauncherSearchableItem.prototype.title;
-/**
- * The main category name, e.g. Perks or Help. Plain localized text.
- * @type {string}
- */
-helpApp.LauncherSearchableItem.prototype.mainCategoryName;
-/**
- * List of tags. Each tag is plain localized text. The item will be searchable
- *     by these tags.
- * @type {!Array<!string>}
- */
-helpApp.LauncherSearchableItem.prototype.tags;
-/**
- * The locale of the tags. This could be different from the locale of the other
- * fields. Empty string means system locale. Same format as the locale field.
- * @type {string}
- */
-helpApp.LauncherSearchableItem.prototype.tagLocale;
-/**
- * The URL path containing the relevant content, which may or may not contain
- *     URL parameters. For example, if the help content is at
- *     chrome://help-app/help/sub/3399763/id/1282338#install-user, then the
- *     field would be "help/sub/3399763/id/1282338#install-user" for this page.
- * @type {string}
- */
-helpApp.LauncherSearchableItem.prototype.urlPathWithParameters;
-/**
- * The locale that this content is localized in. Empty string means system
- *     locale. The format is language[-country] (e.g., en-US) where the language
- *     is the 2 or 3 letter code from ISO-639.
- * @type {string}
- */
-helpApp.LauncherSearchableItem.prototype.locale;
-
-/**
- * A position in a string. For highlighting matches in snippets.
- * @record
- * @struct
- */
-helpApp.Position = function() {};
-/** @type {number} */
-helpApp.Position.prototype.length;
-/** @type {number} */
-helpApp.Position.prototype.start;
-
-/**
- * Response from calling findInSearchIndex.
- * @record
- * @struct
- */
-helpApp.SearchResult = function() {};
-/** @type {string} */
-helpApp.SearchResult.prototype.id;
-/**
- * List of positions corresponding to the title, sorted by start index. Used in
- * snippet.
- * @type {?Array<!helpApp.Position>}
- */
-helpApp.SearchResult.prototype.titlePositions;
-/**
- * List of positions corresponding to the body, sorted by start index. Used in
- * snippet.
- * @type {?Array<!helpApp.Position>}
- */
-helpApp.SearchResult.prototype.bodyPositions;
-/**
- * Index of the most relevant subheading match.
- * @type {?number}
- */
-helpApp.SearchResult.prototype.subheadingIndex;
-/**
- * List of positions corresponding to the most relevant subheading. Used in
- * snippet.
- * @type {?Array<!helpApp.Position>}
- */
-helpApp.SearchResult.prototype.subheadingPositions;
-
-/**
- * Response from calling findInSearchIndex.
- * @record
- * @struct
- */
-helpApp.FindResponse = function() {};
-/** @type {?Array<!helpApp.SearchResult>} */
-helpApp.FindResponse.prototype.results;
-
-/**
- * Device info supplied by the DeviceInfoManager.
- * @record
- * @struct
- */
-helpApp.DeviceInfo = function() {};
-/**
- * The board family of the device. e.g. "brya".
- * @type {string}
- */
-helpApp.DeviceInfo.prototype.board;
-/**
- * The model of the device. e.g. "taniks".
- * @type {string}
- */
-helpApp.DeviceInfo.prototype.model;
-/**
- * The user type of the profile currently running. e.g. "unmanaged".
- * The possible values for this can be found at
- * https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/apps/user_type_filter.cc;l=27;drc=0d0b76e40dfff0f4ad58d0640cdf2c4df72030d3.
- * @type {string}
- */
-helpApp.DeviceInfo.prototype.userType;
-/**
- * If Steam is allowed for the device, regardless of install status.
- * @type {boolean}
- */
-helpApp.DeviceInfo.prototype.isSteamAllowed;
-
-/**
- * The delegate which exposes open source privileged WebUi functions to
- * HelpApp.
- * @record
- * @struct
- */
-helpApp.ClientApiDelegate = function() {};
-
-/**
- * Opens up the built-in chrome feedback dialog.
- * @return {!Promise<?string>} Promise which resolves when the request has been
- *     acknowledged, if the dialog could not be opened the promise resolves with
- *     an error message, resolves with null otherwise.
- */
-helpApp.ClientApiDelegate.prototype.openFeedbackDialog = function() {};
-
-/**
- * Opens up the parental controls section of OS settings.
- * @return {!Promise<undefined>}
- */
-helpApp.ClientApiDelegate.prototype.showParentalControls = function() {};
-
-/**
- * Triggers the call-to-action associated with the given action type id.
- * @param {number} actionTypeId
- * @return {!Promise<undefined>}
- */
-helpApp.ClientApiDelegate.prototype.triggerWelcomeTipCallToAction = function(
-    actionTypeId) {};
-
-/**
- * Add or update the content that is stored in the Search Index.
- * @param {!Array<!helpApp.SearchableItem>} data
- * @return {!Promise<undefined>}
- */
-helpApp.ClientApiDelegate.prototype.addOrUpdateSearchIndex = function(data) {};
-
-/**
- * Clear the content that is stored in the Search Index.
- * @return {!Promise<undefined>}
- */
-helpApp.ClientApiDelegate.prototype.clearSearchIndex = function() {};
-
-/**
- * Search the search index for content that matches the given query.
- * @param {string} query
- * @param {number=} maxResults Maximum number of search results. Default 50.
- * @return {!Promise<!helpApp.FindResponse>}
- */
-helpApp.ClientApiDelegate.prototype.findInSearchIndex = function(
-    query, maxResults) {};
-
-/**
- * Close the app. Works if the app is open in the background page.
- * @return {undefined}
- */
-helpApp.ClientApiDelegate.prototype.closeBackgroundPage = function() {};
-
-/**
- * Replace the content that is stored in the launcher search index.
- * @param {!Array<!helpApp.LauncherSearchableItem>} data
- * @return {!Promise<undefined>} Promise which resolves after the update is
- *     complete.
- */
-helpApp.ClientApiDelegate.prototype.updateLauncherSearchIndex
-    = function(data) {};
-
-/**
- * Launches the MS365 setup flow (or shows the final screen of the flow if it
- * was already completed).
- * @return {!Promise<undefined>}
- */
-helpApp.ClientApiDelegate.prototype.launchMicrosoft365Setup = function() {};
-
-/**
- * Request for the discover page notification to be shown to the user. The
- * notification will only be shown if the relevant heuristics are true, i.e.
- * user is a child, is using a supported language etc.
- * @return {!Promise<undefined>}
- */
-helpApp.ClientApiDelegate.prototype.maybeShowDiscoverNotification =
-    function() {};
-
-/**
- * Request for the release notes notification to be shown to the user. The
- * notification will only be shown if a notification for the help app has not
- * yet been shown in the current milestone.
- * @return {!Promise<undefined>}
- */
-helpApp.ClientApiDelegate.prototype.maybeShowReleaseNotesNotification =
-    function() {};
-
-/**
- * Gets device info supplied by the DeviceInfoManager. This has to be a MOJO
- * method rather than additional fields in loadTimeData because the info is
- * obtained asynchronously.
- * @return {!Promise<!helpApp.DeviceInfo>}
- */
-helpApp.ClientApiDelegate.prototype.getDeviceInfo = function() {};
-
-/**
- * Opens a valid https:// URL in a new browser tab without getting intercepted
- * by URL capturing logic. If the "HelpAppAutoTriggerInstallDialog" feature flag
- * is enabled, this will automatically trigger the install dialog.
- * Failure to provide a valid https:// URL will cause the Help app renderer
- * process to crash.
- * @param {string} url
- * @return {!Promise<undefined>}
- */
-helpApp.ClientApiDelegate.prototype.openUrlInBrowserAndTriggerInstallDialog =
-    function(url) {};
-
-/**
- * Launch data that can be read by the app when it first loads.
- * @type {{
- *     delegate: !helpApp.ClientApiDelegate,
- * }}
- */
-window.customLaunchData;
diff --git a/ash/webui/help_app_ui/resources/js/help_app.d.ts b/ash/webui/help_app_ui/resources/js/help_app.d.ts
new file mode 100644
index 0000000..213563d
--- /dev/null
+++ b/ash/webui/help_app_ui/resources/js/help_app.d.ts
@@ -0,0 +1,201 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview
+ * Types for go/help-app-externs. Currently this only exists in the chromium
+ * repository and is handcrafted. When no help_app JS exists, this file will
+ * replace go/help-app-externs, and it can be a regular `.ts` file that both
+ * toolchains consume directly. Until then, the internal toolchain builds only
+ * off the JS externs and has no knowledge of this file.
+ */
+
+/**
+ * Each SearchableItem maps to one Data field in the Local Search Service (LSS)
+ * Mojo API and represents a single potential search result for in-app search
+ * inside the help app. These originate from the untrusted frame and get parsed
+ * by the LSS.
+ */
+declare interface SearchableItem {
+  /** The id of this item. */
+  id: string;
+  /** Title text. Plain localized text. */
+  title: string;
+  /** Body text. Plain localized text. */
+  body: string;
+  /** The main category name, e.g. Perks or Help. Plain localized text. */
+  mainCategoryName: string;
+  /** Any sub category name, e.g. a help topic name. Plain localized text. */
+  subcategoryNames?: string[];
+  /**
+   * Sub headings from the content. Removed from the body text. Plain localized
+   * text.
+   */
+  subheadings?: string[];
+  /**
+   * The locale that this content is localized in. Empty string means system
+   * locale. The format is language[-country] (e.g., en-US) where the language
+   * is the 2 or 3 letter code from ISO-639.
+   */
+  locale: string;
+}
+
+/**
+ * Each LauncherSearchableItem maps to one Data field in the LSS Mojo API and
+ * represents a single potential help app search result in the CrOS launcher.
+ * These originate from the untrusted frame and get parsed by the LSS.
+ */
+declare interface LauncherSearchableItem {
+  /** The unique identifier of this item. */
+  id: string;
+  /** Title text. Plain localized text. */
+  title: string;
+  /** The main category name, e.g. Perks or Help. Plain localized text. */
+  mainCategoryName: string;
+  /**
+   * List of tags. Each tag is plain localized text. The item will be searchable
+   * by these tags.
+   */
+  tags: string[];
+  /**
+   * The locale of the tags. This could be different from the locale of the
+   * other fields. Empty string means system locale. Same format as the locale
+   * field.
+   */
+  tagLocale: string;
+  /**
+   * The URL path containing the relevant content, which may or may not contain
+   * URL parameters. For example, if the help content is at
+   * chrome://help-app/help/sub/3399763/id/1282338#install-user, then the field
+   * would be "help/sub/3399763/id/1282338#install-user" for this page.
+   */
+  urlPathWithParameters: string;
+  /**
+   * The locale that this content is localized in. Empty string means system
+   * locale. The format is language[-country] (e.g., en-US) where the language
+   * is the 2 or 3 letter code from ISO-639.
+   */
+  locale: string;
+}
+
+/** A position in a string. For highlighting matches in snippets. */
+declare interface Position {
+  length: number;
+  start: number;
+}
+
+/** Response from calling findInSearchIndex. */
+declare interface SearchResult {
+  id: string;
+  /**
+   * List of positions corresponding to the title, sorted by start index. Used
+   * in snippet.
+   */
+  titlePositions: Position[]|null;
+  /**
+   * List of positions corresponding to the body, sorted by start index. Used in
+   * snippet.
+   */
+  bodyPositions: Position[]|null;
+  /** Index of the most relevant subheading match. */
+  subheadingIndex: number|null;
+  /**
+   * List of positions corresponding to the most relevant subheading. Used in
+   * snippet.
+   */
+  subheadingPositions: Position[]|null;
+}
+
+/** Response from calling findInSearchIndex. */
+declare interface FindResponse {
+  results?: SearchResult[];
+}
+
+/** Device info supplied by the DeviceInfoManager. */
+declare interface DeviceInfo {
+  /** The board family of the device. e.g. "brya". */
+  board: string;
+  /** The model of the device. e.g. "taniks". */
+  model: string;
+  /**
+   * The user type of the profile currently running. e.g. "unmanaged".
+   * The possible values for this can be found at
+   * https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/apps/user_type_filter.cc;l=30;drc=fe09990eb42846949283fa0bbd315f9bc06c54e5.
+   */
+  userType: string;
+  /** If Steam is allowed for the device, regardless of install status. */
+  isSteamAllowed: boolean;
+}
+
+/**
+ * The delegate which exposes open source privileged WebUI functions to HelpApp.
+ */
+declare interface ClientApiDelegate {
+  /**
+   * Opens up the built-in chrome feedback dialog.
+   * @return Promise which resolves when the request has been acknowledged. If
+   *     the dialog could not be opened the promise resolves with an error
+   *     message. Resolves with undefined otherwise.
+   */
+  openFeedbackDialog: () => Promise<string|undefined>;
+  /** Opens up the parental controls section of OS settings. */
+  showParentalControls: () => Promise<void>;
+  /** Triggers the call-to-action associated with the given action type id. */
+  triggerWelcomeTipCallToAction: (actionTypeId: number) => Promise<void>;
+  /** Add or update the content that is stored in the Search Index. */
+  addOrUpdateSearchIndex: (data: SearchableItem[]) => Promise<void>;
+  /** Clear the content that is stored in the Search Index. */
+  clearSearchIndex: () => Promise<void>;
+  /** Search the search index for content that matches the given query. */
+  findInSearchIndex:
+      (query: string, maxResults?: number) => Promise<FindResponse>;
+  /** Close the app. Works if the app is open in the background page. */
+  closeBackgroundPage: () => undefined;
+  /**
+   * Replace the content that is stored in the launcher search index.
+   *
+   * @return Promise that resolves after the update is complete.
+   */
+  updateLauncherSearchIndex: (data: LauncherSearchableItem[]) => Promise<void>;
+  /**
+   * Launches the MS365 setup flow (or shows the final screen of the flow if it
+   * was already completed).
+   */
+  launchMicrosoft365Setup: () => Promise<void>;
+  /**
+   * Request for the discover page notification to be shown to the user. The
+   * notification will only be shown if the relevant heuristics are true, i.e.
+   * user is a child, is using a supported language etc.
+   */
+  maybeShowDiscoverNotification: () => Promise<void>;
+  /**
+   * Request for the release notes notification to be shown to the user. The
+   * notification will only be shown if a notification for the help app has not
+   * yet been shown in the current milestone.
+   */
+  maybeShowReleaseNotesNotification: () => Promise<void>;
+  /**
+   * Gets device info supplied by the DeviceInfoManager. This has to be a Mojo
+   * method rather than additional fields in loadTimeData because the info is
+   * obtained asynchronously.
+   */
+  getDeviceInfo: () => Promise<DeviceInfo>;
+  /**
+   * Opens a valid https:// URL in a new browser tab without getting intercepted
+   * by URL capturing logic. If the "HelpAppAutoTriggerInstallDialog" feature
+   * flag is enabled, this will automatically trigger the install dialog.
+   * Failure to provide a valid https:// URL will cause the Help app renderer
+   * process to crash.
+   */
+  openUrlInBrowserAndTriggerInstallDialog: (url: string) => Promise<void>;
+}
+
+/** Launch data that can be read by the app when it first loads. */
+declare interface CustomLaunchData {
+  delegate: ClientApiDelegate;
+}
+
+interface Window {
+  customLaunchData: CustomLaunchData;
+}
diff --git a/ash/webui/help_app_ui/resources/message_types.js b/ash/webui/help_app_ui/resources/message_types.js
deleted file mode 100644
index 6206eac1..0000000
--- a/ash/webui/help_app_ui/resources/message_types.js
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview
- * Message definitions passed over the HelpApp privileged/unprivileged pipe.
- */
-
-/**
- * Enum for message types.
- * @enum {string}
- */
-export const Message = {
-  OPEN_FEEDBACK_DIALOG: 'open-feedback-dialog',
-  SHOW_PARENTAL_CONTROLS: 'show-parental-controls',
-  TRIGGER_WELCOME_TIP_CALL_TO_ACTION: 'trigger-welcome-tip-call-to-action',
-  ADD_OR_UPDATE_SEARCH_INDEX: 'add-or-update-search-index',
-  CLEAR_SEARCH_INDEX: 'clear-search-index',
-  FIND_IN_SEARCH_INDEX: 'find-in-search-index',
-  CLOSE_BACKGROUND_PAGE: 'close-background-page',
-  UPDATE_LAUNCHER_SEARCH_INDEX: 'update-launcher-search-index',
-  LAUNCH_MICROSOFT_365_SETUP: 'launch-microsoft-365-setup',
-  MAYBE_SHOW_DISCOVER_NOTIFICATION: 'maybe-show-discover-notification',
-  MAYBE_SHOW_RELEASE_NOTES_NOTIFICATION:
-      'maybe-show-release-notes-notification',
-  GET_DEVICE_INFO: 'get-device-info',
-  OPEN_URL_IN_BROWSER_AND_TRIGGER_INSTALL_DIALOG:
-      'open-url-in-browser-and-trigger-install-dialog',
-};
diff --git a/ash/webui/help_app_ui/resources/message_types.ts b/ash/webui/help_app_ui/resources/message_types.ts
new file mode 100644
index 0000000..3766f7f
--- /dev/null
+++ b/ash/webui/help_app_ui/resources/message_types.ts
@@ -0,0 +1,27 @@
+// Copyright 2020 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview
+ * Message definitions passed over the HelpApp privileged/unprivileged pipe.
+ */
+
+/** Enum for message types. */
+export enum Message {
+  OPEN_FEEDBACK_DIALOG = 'open-feedback-dialog',
+  SHOW_PARENTAL_CONTROLS = 'show-parental-controls',
+  TRIGGER_WELCOME_TIP_CALL_TO_ACTION = 'trigger-welcome-tip-call-to-action',
+  ADD_OR_UPDATE_SEARCH_INDEX = 'add-or-update-search-index',
+  CLEAR_SEARCH_INDEX = 'clear-search-index',
+  FIND_IN_SEARCH_INDEX = 'find-in-search-index',
+  CLOSE_BACKGROUND_PAGE = 'close-background-page',
+  UPDATE_LAUNCHER_SEARCH_INDEX = 'update-launcher-search-index',
+  LAUNCH_MICROSOFT_365_SETUP = 'launch-microsoft-365-setup',
+  MAYBE_SHOW_DISCOVER_NOTIFICATION = 'maybe-show-discover-notification',
+  MAYBE_SHOW_RELEASE_NOTES_NOTIFICATION =
+      'maybe-show-release-notes-notification',
+  GET_DEVICE_INFO = 'get-device-info',
+  OPEN_URL_IN_BROWSER_AND_TRIGGER_INSTALL_DIALOG =
+      'open-url-in-browser-and-trigger-install-dialog',
+}
diff --git a/ash/webui/help_app_ui/resources/mock/BUILD.gn b/ash/webui/help_app_ui/resources/mock/BUILD.gn
index b32aba42..0976f36 100644
--- a/ash/webui/help_app_ui/resources/mock/BUILD.gn
+++ b/ash/webui/help_app_ui/resources/mock/BUILD.gn
@@ -2,17 +2,11 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//ash/webui/web_applications/system_apps.gni")
-import("//build/config/chromeos/ui_mode.gni")
-import("//third_party/closure_compiler/compile_js.gni")
+import("//tools/typescript/ts_library.gni")
 
 assert(is_chromeos_ash, "Help App is ash-chrome only")
 
-js_type_check("closure_compile") {
-  closure_flags = system_app_closure_flags_strict
-  deps = [ ":app_bin" ]
-}
-
-js_library("app_bin") {
-  externs_list = [ "//ash/webui/help_app_ui/resources/help_app.externs.js" ]
+ts_library("build_ts") {
+  in_files = [ "app_bin.ts" ]
+  definitions = [ "//ash/webui/help_app_ui/resources/js/help_app.d.ts" ]
 }
diff --git a/ash/webui/help_app_ui/resources/mock/app_bin.js b/ash/webui/help_app_ui/resources/mock/app_bin.ts
similarity index 92%
rename from ash/webui/help_app_ui/resources/mock/app_bin.js
rename to ash/webui/help_app_ui/resources/mock/app_bin.ts
index 4d20f14..4ea293c 100644
--- a/ash/webui/help_app_ui/resources/mock/app_bin.js
+++ b/ash/webui/help_app_ui/resources/mock/app_bin.ts
@@ -3,8 +3,9 @@
 // found in the LICENSE file.
 
 /**
- * @fileoverview Placeholder js file for mock app. Runs in an isolated guest.
+ * @fileoverview Placeholder file for mock app. Runs in an isolated guest.
  */
+
 document.addEventListener('DOMContentLoaded', () => {
   if (document.location.pathname === '/background') {
     // In the background page, don't render the app.
@@ -30,6 +31,7 @@
     title: 'Title',
     mainCategoryName: 'Help',
     tags: ['verycomplicatedsearchquery'],
+    tagLocale: '',
     urlPathWithParameters: 'help/sub/3399763/',
     locale: '',
   }]);
@@ -42,7 +44,7 @@
  * go/help-app-internal-initInAppSearchIndex and should be kept up to date with
  * the internal version.
  */
- async function initInAppSearchIndex() {
+async function initInAppSearchIndex() {
   await window.customLaunchData.delegate.clearSearchIndex();
   await window.customLaunchData.delegate.addOrUpdateSearchIndex([
     {
diff --git a/ash/webui/help_app_ui/resources/mock/help_app_bundle_mock_resources.grd b/ash/webui/help_app_ui/resources/mock/help_app_bundle_mock_resources.grd
index 439b5cb..2eade976 100644
--- a/ash/webui/help_app_ui/resources/mock/help_app_bundle_mock_resources.grd
+++ b/ash/webui/help_app_ui/resources/mock/help_app_bundle_mock_resources.grd
@@ -10,7 +10,9 @@
   </outputs>
   <release seq="1">
     <includes>
-      <include name="IDR_HELP_APP_APP_BIN_JS" file="app_bin.js" type="BINDATA" />
+      <include name="IDR_HELP_APP_APP_BIN_JS"
+          file="${root_gen_dir}/ash/webui/help_app_ui/resources/mock/app_bin.js"
+          resource_path="app_bin/js" use_base_dir="false" type="BINDATA" />
     </includes>
   </release>
 </grit>
diff --git a/ash/webui/help_app_ui/resources/receiver.js b/ash/webui/help_app_ui/resources/receiver.js
deleted file mode 100644
index 3a9db44..0000000
--- a/ash/webui/help_app_ui/resources/receiver.js
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright 2020 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @fileoverview
- * A script for the app inside the iframe. Implements a delegate.
- */
-import './sandboxed_load_time_data.js';
-
-import {COLOR_PROVIDER_CHANGED, ColorChangeUpdater} from '//resources/cr_components/color_change_listener/colors_css_updater.js';
-
-import {MessagePipe} from './message_pipe.js';
-import {Message} from './message_types.js';
-
-/** A pipe through which we can send messages to the parent frame. */
-const parentMessagePipe = new MessagePipe('chrome://help-app', window.parent);
-
-/**
- * A delegate which exposes privileged WebUI functionality to the help
- * app.
- * @type {!helpApp.ClientApiDelegate}
- */
-const DELEGATE = {
-  async openFeedbackDialog() {
-    const response =
-        await parentMessagePipe.sendMessage(Message.OPEN_FEEDBACK_DIALOG);
-    return /** @type {?string} */ (response['errorMessage']);
-  },
-  async showParentalControls() {
-    await parentMessagePipe.sendMessage(Message.SHOW_PARENTAL_CONTROLS);
-  },
-  async triggerWelcomeTipCallToAction(actionTypeId) {
-    await parentMessagePipe.sendMessage(
-        Message.TRIGGER_WELCOME_TIP_CALL_TO_ACTION, actionTypeId);
-  },
-  /**
-   * @override
-   * @param {!Array<!helpApp.SearchableItem>} data
-   */
-  async addOrUpdateSearchIndex(data) {
-    await parentMessagePipe.sendMessage(
-        Message.ADD_OR_UPDATE_SEARCH_INDEX, data);
-  },
-  async clearSearchIndex() {
-    await parentMessagePipe.sendMessage(Message.CLEAR_SEARCH_INDEX);
-  },
-  /**
-   * @override
-   * @param {string} query
-   * @param {number=} maxResults Maximum number of search results. Default 50.
-   * @return {!Promise<!helpApp.FindResponse>}
-   */
-  findInSearchIndex(query, maxResults) {
-    return /** @type {!Promise<!helpApp.FindResponse>} */ (
-        parentMessagePipe.sendMessage(
-            Message.FIND_IN_SEARCH_INDEX, {query, maxResults}));
-  },
-  closeBackgroundPage() {
-    parentMessagePipe.sendMessage(Message.CLOSE_BACKGROUND_PAGE);
-  },
-  /**
-   * @override
-   * @param {!Array<!helpApp.LauncherSearchableItem>} data
-   */
-  async updateLauncherSearchIndex(data) {
-    await parentMessagePipe.sendMessage(
-        Message.UPDATE_LAUNCHER_SEARCH_INDEX, data);
-  },
-  async launchMicrosoft365Setup() {
-    await parentMessagePipe.sendMessage(Message.LAUNCH_MICROSOFT_365_SETUP);
-  },
-  async maybeShowDiscoverNotification() {
-    await parentMessagePipe.sendMessage(
-        Message.MAYBE_SHOW_DISCOVER_NOTIFICATION);
-  },
-  async maybeShowReleaseNotesNotification() {
-    await parentMessagePipe.sendMessage(
-        Message.MAYBE_SHOW_RELEASE_NOTES_NOTIFICATION);
-  },
-  getDeviceInfo() {
-    return /** @type {!Promise<!helpApp.DeviceInfo>} */ (
-        parentMessagePipe.sendMessage(Message.GET_DEVICE_INFO));
-  },
-  /**
-   * @override
-   * @param {string} url
-   */
-  async openUrlInBrowserAndTriggerInstallDialog(url) {
-    await parentMessagePipe.sendMessage(
-        Message.OPEN_URL_IN_BROWSER_AND_TRIGGER_INSTALL_DIALOG, url);
-  },
-};
-
-window.customLaunchData = {
-  delegate: DELEGATE,
-};
-
-window.addEventListener(
-    'DOMContentLoaded', /** @suppress {checkTypes} */ function() {
-      // Start listening to color change events. These events get picked up by
-      // logic in ts_helpers.ts on the google3 side.
-      ColorChangeUpdater.forDocument().start();
-    });
-// Expose functions to bind to color change events to window so they can be
-// automatically picked up by installColors(). See ts_helpers.ts in google3.
-window['addColorChangeListener'] =
-    /** @suppress {checkTypes} */ function(listener) {
-      ColorChangeUpdater.forDocument().eventTarget.addEventListener(
-          COLOR_PROVIDER_CHANGED, listener);
-    };
-window['removeColorChangeListener'] =
-    /** @suppress {checkTypes} */ function(listener) {
-      ColorChangeUpdater.forDocument().eventTarget.removeEventListener(
-          COLOR_PROVIDER_CHANGED, listener);
-    };
-
-export const TEST_ONLY = {parentMessagePipe};
diff --git a/ash/webui/help_app_ui/resources/receiver.ts b/ash/webui/help_app_ui/resources/receiver.ts
new file mode 100644
index 0000000..eacac71
--- /dev/null
+++ b/ash/webui/help_app_ui/resources/receiver.ts
@@ -0,0 +1,105 @@
+// Copyright 2020 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview
+ * A script for the app inside the iframe. Implements a delegate.
+ */
+
+import './sandboxed_load_time_data.js';
+
+import {COLOR_PROVIDER_CHANGED, ColorChangeUpdater} from '//resources/cr_components/color_change_listener/colors_css_updater.js';
+import {MessagePipe} from '//system_apps/message_pipe.js';
+
+import {Message} from './message_types.js';
+
+/** A pipe through which we can send messages to the parent frame. */
+const parentMessagePipe = new MessagePipe('chrome://help-app', window.parent);
+
+/**
+ * A delegate which exposes privileged WebUI functionality to the help
+ * app.
+ */
+const DELEGATE: ClientApiDelegate = {
+  async openFeedbackDialog() {
+    const response =
+        await parentMessagePipe.sendMessage(Message.OPEN_FEEDBACK_DIALOG);
+    return response['errorMessage'] as string;
+  },
+  showParentalControls() {
+    return parentMessagePipe.sendMessage(Message.SHOW_PARENTAL_CONTROLS);
+  },
+  triggerWelcomeTipCallToAction(actionTypeId: number) {
+    return parentMessagePipe.sendMessage(
+        Message.TRIGGER_WELCOME_TIP_CALL_TO_ACTION, actionTypeId);
+  },
+  addOrUpdateSearchIndex(data: SearchableItem[]) {
+    return parentMessagePipe.sendMessage(
+        Message.ADD_OR_UPDATE_SEARCH_INDEX, data);
+  },
+  clearSearchIndex() {
+    return parentMessagePipe.sendMessage(Message.CLEAR_SEARCH_INDEX);
+  },
+  findInSearchIndex(query: string, maxResults = 50): Promise<FindResponse> {
+    return parentMessagePipe.sendMessage(
+        Message.FIND_IN_SEARCH_INDEX, {query, maxResults});
+  },
+  closeBackgroundPage() {
+    parentMessagePipe.sendMessage(Message.CLOSE_BACKGROUND_PAGE);
+  },
+  updateLauncherSearchIndex(data: LauncherSearchableItem[]) {
+    return parentMessagePipe.sendMessage(
+        Message.UPDATE_LAUNCHER_SEARCH_INDEX, data);
+  },
+  launchMicrosoft365Setup() {
+    return parentMessagePipe.sendMessage(Message.LAUNCH_MICROSOFT_365_SETUP);
+  },
+  maybeShowDiscoverNotification() {
+    return parentMessagePipe.sendMessage(
+        Message.MAYBE_SHOW_DISCOVER_NOTIFICATION);
+  },
+  maybeShowReleaseNotesNotification() {
+    return parentMessagePipe.sendMessage(
+        Message.MAYBE_SHOW_RELEASE_NOTES_NOTIFICATION);
+  },
+  getDeviceInfo(): Promise<DeviceInfo> {
+    return parentMessagePipe.sendMessage(Message.GET_DEVICE_INFO);
+  },
+  openUrlInBrowserAndTriggerInstallDialog(url: string) {
+    return parentMessagePipe.sendMessage(
+        Message.OPEN_URL_IN_BROWSER_AND_TRIGGER_INSTALL_DIALOG, url);
+  },
+};
+
+window.customLaunchData = {
+  delegate: DELEGATE,
+};
+
+window.addEventListener('DOMContentLoaded', function() {
+  // Start listening to color change events. These events get picked up by
+  // logic in ts_helpers.ts on the google3 side.
+  ColorChangeUpdater.forDocument().start();
+});
+
+declare global {
+  interface Window {
+    addColorChangeListener: (listener: EventListenerOrEventListenerObject|
+                             null) => unknown;
+    removeColorChangeListener: (listener: EventListenerOrEventListenerObject|
+                                null) => unknown;
+  }
+}
+
+// Expose functions to bind to color change events to window so they can be
+// automatically picked up by installColors(). See ts_helpers.ts in google3.
+window.addColorChangeListener = function(listener) {
+  ColorChangeUpdater.forDocument().eventTarget.addEventListener(
+      COLOR_PROVIDER_CHANGED, listener);
+};
+window.removeColorChangeListener = function(listener) {
+  ColorChangeUpdater.forDocument().eventTarget.removeEventListener(
+      COLOR_PROVIDER_CHANGED, listener);
+};
+
+export const TEST_ONLY = {parentMessagePipe};
diff --git a/ash/webui/resources/BUILD.gn b/ash/webui/resources/BUILD.gn
index bc77aa146..aabb1594 100644
--- a/ash/webui/resources/BUILD.gn
+++ b/ash/webui/resources/BUILD.gn
@@ -83,6 +83,7 @@
         "//ash/webui/help_app_ui/resources/prod/help_app_bundle_resources.grd"
   } else {
     source = "//ash/webui/help_app_ui/resources/mock/help_app_bundle_mock_resources.grd"
+    deps = [ "//ash/webui/help_app_ui/resources/mock:build_ts" ]
   }
 
   use_brotli = true
diff --git a/ash/wm/client_controlled_state.cc b/ash/wm/client_controlled_state.cc
index 18c54f21..c82ee9eca 100644
--- a/ash/wm/client_controlled_state.cc
+++ b/ash/wm/client_controlled_state.cc
@@ -111,9 +111,9 @@
                                                   const WMEvent* event) {
   if (!delegate_)
     return;
+  aura::Window* const window = window_state->window();
   // Client is responsible for adjusting bounds after workspace bounds change.
   if (window_state->IsSnapped()) {
-    const aura::Window* window = window_state->window();
     // If `SplitViewController` is aware of `window` (e.g. in tablet), let the
     // controller handle the workspace event.
     if (SplitViewController::Get(window)->IsWindowInSplitView(window)) {
@@ -127,12 +127,17 @@
     delegate_->HandleBoundsRequest(window_state, window_state->GetStateType(),
                                    bounds, window_state->GetDisplay().id());
   } else if (window_state->IsFloated()) {
+    if (!window->parent()) {
+      // If the window is now reparenting to another container (or being
+      // destroyed), no need to adjust floated bounds. The next workspace event
+      // (`WM_EVENT_ADDED_TO_WORKSPACE`) is coming soon anyway.
+      return;
+    }
     const gfx::Rect bounds =
         display::Screen::GetScreen()->InTabletMode()
-            ? FloatController::GetFloatWindowTabletBounds(
-                  window_state->window())
+            ? FloatController::GetFloatWindowTabletBounds(window)
             : FloatController::GetFloatWindowClamshellBounds(
-                  window_state->window(),
+                  window,
                   // TODO(b/292579250): Add a mechanism to float as close to the
                   // previous bounds in the event of a workspace event. For now,
                   // use the default float location.
@@ -143,12 +148,11 @@
     // Explicitly handle the primary change because it can change the display id
     // with no bounds change.
     if (event->AsDisplayMetricsChangedWMEvent()->primary_changed()) {
-      const gfx::Rect bounds = window_state->window()->bounds();
+      const gfx::Rect bounds = window->bounds();
       delegate_->HandleBoundsRequest(window_state, window_state->GetStateType(),
                                      bounds, window_state->GetDisplay().id());
     }
   } else if (event->type() == WM_EVENT_ADDED_TO_WORKSPACE) {
-    aura::Window* window = window_state->window();
     gfx::Rect bounds = window->bounds();
     AdjustBoundsForMinimumWindowVisibility(window->GetRootWindow()->bounds(),
                                            &bounds);
diff --git a/ash/wm/client_controlled_state_unittest.cc b/ash/wm/client_controlled_state_unittest.cc
index 0be2930..f144a10 100644
--- a/ash/wm/client_controlled_state_unittest.cc
+++ b/ash/wm/client_controlled_state_unittest.cc
@@ -15,6 +15,7 @@
 #include "ash/screen_util.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/test/test_widget_builder.h"
 #include "ash/wm/desks/desks_util.h"
 #include "ash/wm/float/float_controller.h"
 #include "ash/wm/overview/overview_controller.h"
@@ -1782,4 +1783,58 @@
   EXPECT_EQ(WindowStateType::kPrimarySnapped, window_state()->GetStateType());
 }
 
+// Tests that floating a fullscreen window to replace a floated window works
+// properly without any crash. Regression test for b/322374826.
+TEST_P(ClientControlledStateTestClamshellAndTablet,
+       ReplaceFloatedWindowWithFullscreenWindow) {
+  // The AppType must be set to any except `AppType::NON_APP` (default value) to
+  // make it floatable.
+  window()->SetProperty(aura::client::kAppType,
+                        static_cast<int>(AppType::ARC_APP));
+  widget_delegate()->EnableFloat();
+  ASSERT_TRUE(chromeos::wm::CanFloatWindow(window()));
+
+  // Make `window()` fullscreen to hide shelf.
+  const WMEvent enter_fullscreen(WM_EVENT_FULLSCREEN);
+  window_state()->OnWMEvent(&enter_fullscreen);
+  state()->EnterNextState(window_state(), delegate()->new_state());
+  EXPECT_TRUE(widget()->IsFullscreen());
+
+  // Create another client-controlled window.
+  auto widget2 = TestWidgetBuilder()
+                     .SetParent(Shell::GetPrimaryRootWindow()->GetChildById(
+                         desks_util::GetActiveDeskContainerId()))
+                     .SetBounds(kInitialBounds)
+                     .SetTestWidgetDelegate()
+                     .SetWindowProperty(aura::client::kAppType,
+                                        static_cast<int>(AppType::ARC_APP))
+                     .SetShow(false)
+                     .BuildOwnsNativeWidget();
+  auto* const window_state2 = WindowState::Get(widget2->GetNativeWindow());
+  window_state2->set_allow_set_bounds_direct(true);
+  auto delegate2 = std::make_unique<TestClientControlledStateDelegate>();
+  auto* const state_delegate2_ptr = delegate2.get();
+  auto state2 = std::make_unique<ClientControlledState>(std::move(delegate2));
+  auto* state2_ptr = state2.get();
+  window_state2->SetStateObject(std::move(state2));
+  widget2->Show();
+
+  // Float `widget2`.
+  const WindowFloatWMEvent float_event(
+      chromeos::FloatStartLocation::kBottomRight);
+  window_state2->OnWMEvent(&float_event);
+  state2_ptr->EnterNextState(window_state2, state_delegate2_ptr->new_state());
+  ASSERT_TRUE(window_state2->IsFloated());
+
+  // Float `window`.
+  window_state()->OnWMEvent(&float_event);
+  state()->EnterNextState(window_state(), delegate()->new_state());
+  ApplyPendingRequestedBounds();
+  ASSERT_TRUE(window_state()->IsFloated());
+
+  // Floating `window` should result in unfloating `widget2`.
+  state2_ptr->EnterNextState(window_state2, state_delegate2_ptr->new_state());
+  EXPECT_FALSE(window_state2->IsFloated());
+}
+
 }  // namespace ash
diff --git a/ash/wm/desks/desk_button/desk_button.cc b/ash/wm/desks/desk_button/desk_button.cc
index 280d439..792f429 100644
--- a/ash/wm/desks/desk_button/desk_button.cc
+++ b/ash/wm/desks/desk_button/desk_button.cc
@@ -237,8 +237,6 @@
   TypographyProvider::Get()->StyleLabel(TypographyToken::kCrosButton2,
                                         *desk_name_label_);
 
-  UpdateLocaleSpecificSettings();
-
   // Use shelf view as the context menu controller so that it shows the same
   // context menu.
   set_context_menu_controller(
@@ -273,8 +271,8 @@
 }
 
 void DeskButton::UpdateUi(const Desk* active_desk) {
-  desk_name_label_->SetText(GetDeskNameLabelText(active_desk));
   UpdateAvatar(active_desk);
+  UpdateLocaleSpecificSettings();
 }
 
 void DeskButton::UpdateAvatar(const Desk* active_desk) {
@@ -289,6 +287,7 @@
       if (auto* summary =
               desk_profiles_delegate->GetProfilesSnapshotByProfileId(
                   active_desk->lacros_profile_id())) {
+        profile_ = *summary;
         desk_avatar_image_ = gfx::ImageSkiaOperations::CreateResizedImage(
             summary->icon, skia::ImageOperations::RESIZE_BEST,
             kDeskButtonAvatarSize);
@@ -305,9 +304,23 @@
 }
 
 void DeskButton::UpdateLocaleSpecificSettings() {
-  const Desk* active_desk = DesksController::Get()->active_desk();
-  SetAccessibleName(l10n_util::GetStringFUTF16(IDS_SHELF_DESK_BUTTON_TITLE,
-                                               active_desk->name()));
+  // Update the accessible name.
+  DesksController* desk_controller = DesksController::Get();
+  const Desk* active_desk = desk_controller->active_desk();
+  if (desk_avatar_view_ && desk_avatar_view_->GetVisible()) {
+    SetAccessibleName(l10n_util::GetStringFUTF16(
+        IDS_SHELF_DESK_BUTTON_TITLE_WITH_PROFILE_AVATAR, active_desk->name(),
+        base::UTF8ToUTF16(profile_.name), base::UTF8ToUTF16(profile_.email),
+        base::NumberToString16(desk_controller->GetDeskIndex(active_desk) + 1),
+        base::NumberToString16(desk_controller->GetNumberOfDesks())));
+  } else {
+    SetAccessibleName(l10n_util::GetStringFUTF16(
+        IDS_SHELF_DESK_BUTTON_TITLE_NO_PROFILE_AVATAR, active_desk->name(),
+        base::NumberToString16(desk_controller->GetDeskIndex(active_desk) + 1),
+        base::NumberToString16(desk_controller->GetNumberOfDesks())));
+  }
+
+  // Update the button text since the default desk name can be locale specific.
   desk_name_label_->SetText(GetDeskNameLabelText(active_desk));
 }
 
diff --git a/ash/wm/desks/desk_button/desk_button.h b/ash/wm/desks/desk_button/desk_button.h
index 9ac1d7f..e86492c 100644
--- a/ash/wm/desks/desk_button/desk_button.h
+++ b/ash/wm/desks/desk_button/desk_button.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "ash/ash_export.h"
+#include "ash/public/cpp/desk_profiles_delegate.h"
 #include "ash/shelf/shelf.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/gfx/geometry/size.h"
@@ -98,6 +99,10 @@
   // Image for the profile avatar.
   gfx::ImageSkia desk_avatar_image_;
 
+  // Profile summary of the desk's associated profile. It's cached during
+  // `UpdateAvatar()`.
+  LacrosProfileSummary profile_;
+
   // A label that displays the active desk's name.
   raw_ptr<views::Label> desk_name_label_;
 
diff --git a/ash/wm/desks/desk_button/desk_switch_button.cc b/ash/wm/desks/desk_button/desk_switch_button.cc
index b391db2..0b62b84 100644
--- a/ash/wm/desks/desk_button/desk_switch_button.cc
+++ b/ash/wm/desks/desk_button/desk_switch_button.cc
@@ -104,8 +104,6 @@
       this, gfx::Insets(kDeskButtonSwitchButtonFocusRingHaloInset),
       kDeskButtonCornerRadius);
 
-  UpdateLocaleSpecificSettings();
-
   // Use shelf view as the context menu controller so that it shows the same
   // context menu.
   set_context_menu_controller(
@@ -145,18 +143,22 @@
   // normal, e.g. right clicks on the button.
   SetBackgroundVisible(GetEnabled() && IsMouseHovered() &&
                        GetState() == ButtonState::STATE_HOVERED);
+
+  UpdateLocaleSpecificSettings();
 }
 
 void DeskSwitchButton::UpdateLocaleSpecificSettings() {
   const auto* desk_controller = DesksController::Get();
-  const Desk* active_desk = desk_controller->active_desk();
-  const int index = desk_controller->GetDeskIndex(active_desk) +
-                    (type_ == Type::kPrev ? -1 : 1);
-  const int id = type_ == Type::kPrev ? IDS_SHELF_PREVIOUS_DESK_BUTTON_TITLE
-                                      : IDS_SHELF_NEXT_DESK_BUTTON_TITLE;
-  if (index >= 0 && index < desk_controller->GetNumberOfDesks()) {
+  const int target_index =
+      desk_controller->GetActiveDeskIndex() + (type_ == Type::kPrev ? -1 : 1);
+  const int desk_count = desk_controller->GetNumberOfDesks();
+  if (target_index >= 0 && target_index < desk_count) {
+    const Desk* target_desk = desk_controller->GetDeskAtIndex(target_index);
+    const int id = type_ == Type::kPrev ? IDS_SHELF_PREVIOUS_DESK_BUTTON_TITLE
+                                        : IDS_SHELF_NEXT_DESK_BUTTON_TITLE;
     SetAccessibleName(l10n_util::GetStringFUTF16(
-        id, active_desk->name(), base::NumberToString16(index + 1)));
+        id, target_desk->name(), base::NumberToString16(target_index + 1),
+        base::NumberToString16(desk_count)));
   }
 }
 
diff --git a/ash/wm/desks/desks_controller.cc b/ash/wm/desks/desks_controller.cc
index 9eaa392..67c1072b 100644
--- a/ash/wm/desks/desks_controller.cc
+++ b/ash/wm/desks/desks_controller.cc
@@ -1721,27 +1721,27 @@
   auto* shell = Shell::Get();
   auto* overview_controller = shell->overview_controller();
   const bool was_in_overview = overview_controller->InOverviewSession();
-  if (animation_) {
-    // The order here matters. Overview must end before ending tablet split view
-    // before switching desks. (If clamshell split view is active on one or more
-    // displays, then it simply will end when we end overview.) That's because
-    // we don't want `TabletModeWindowManager` maximizing all windows because we
-    // cleared the snapped ones in `SplitViewController` first. See
-    // `TabletModeWindowManager::OnOverviewModeEndingAnimationComplete`.
-    // See also test coverage for this case in
-    // `TabletModeDesksTest.SnappedStateRetainedOnSwitchingDesksFromOverview`.
-    if (was_in_overview) {
-      // Exit overview mode immediately without any animations before taking the
-      // ending desk screenshot. This makes sure that the ending desk screenshot
-      // will only show the windows in that desk, not overview stuff.
-      overview_controller->EndOverview(OverviewEndAction::kDeskActivation,
-                                       OverviewEnterExitType::kImmediateExit);
-    }
-    SplitViewController* split_view_controller =
-        SplitViewController::Get(Shell::GetPrimaryRootWindow());
-    split_view_controller->EndSplitView(
-        SplitViewController::EndReason::kDesksChange);
+  // The order here matters. Overview must end before ending tablet split view
+  // before switching desks. (If clamshell split view is active on one or more
+  // displays, then it simply will end when we end overview.) That's because
+  // we don't want `TabletModeWindowManager` maximizing all windows because we
+  // cleared the snapped ones in `SplitViewController` first. See
+  // `TabletModeWindowManager::OnOverviewModeEndingAnimationComplete`.
+  // See also test coverage for this case in
+  // `TabletModeDesksTest.SnappedStateRetainedOnSwitchingDesksFromOverview`.
+  if (animation_ && was_in_overview) {
+    // Exit overview mode immediately without any animations before taking the
+    // ending desk screenshot. This makes sure that the ending desk screenshot
+    // will only show the windows in that desk, not overview stuff.
+    overview_controller->EndOverview(OverviewEndAction::kDeskActivation,
+                                     OverviewEnterExitType::kImmediateExit);
   }
+  // We should always end split view during a desk change in order to update the
+  // divider widget.
+  SplitViewController* split_view_controller =
+      SplitViewController::Get(Shell::GetPrimaryRootWindow());
+  split_view_controller->EndSplitView(
+      SplitViewController::EndReason::kDesksChange);
 
   MoveVisibleOnAllDesksWindowsFromActiveDeskTo(const_cast<Desk*>(desk));
   active_desk_ = const_cast<Desk*>(desk);
diff --git a/ash/wm/mru_window_tracker.cc b/ash/wm/mru_window_tracker.cc
index 2b6212f6..3edf561 100644
--- a/ash/wm/mru_window_tracker.cc
+++ b/ash/wm/mru_window_tracker.cc
@@ -112,7 +112,7 @@
           window->GetProperty(ash::kPipOriginalWindowKey));
 }
 
-// Returns a list of windows ordered by their stacking order such that the most
+// Returns a list of windows ordered by their usage recency such that the most
 // recently used window is at the front of the list.
 // If |mru_windows| is passed, these windows are moved to the front of the list.
 // If |desks_mru_type| is `kAllDesks`, then all active and inactive desk
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc
index 0fd5b91..fbab0fb 100644
--- a/ash/wm/overview/overview_grid.cc
+++ b/ash/wm/overview/overview_grid.cc
@@ -1300,10 +1300,9 @@
         split_view_controller->GetDefaultSnappedWindow()->GetBoundsInScreen());
     occluded_region.op(snapped_window_bounds, SkRegion::kUnion_Op);
 
-    auto* divider = split_view_controller->split_view_divider();
-    if (divider) {
-      aura::Window* divider_window =
-          divider->divider_widget()->GetNativeWindow();
+    if (auto* divider_widget =
+            split_view_controller->split_view_divider()->divider_widget()) {
+      aura::Window* divider_window = divider_widget->GetNativeWindow();
       SkIRect divider_bounds =
           gfx::RectToSkIRect(divider_window->GetBoundsInScreen());
       occluded_region.op(divider_bounds, SkRegion::kUnion_Op);
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc
index 854aa91..5cf8f19 100644
--- a/ash/wm/overview/overview_session_unittest.cc
+++ b/ash/wm/overview/overview_session_unittest.cc
@@ -6830,7 +6830,8 @@
       return gfx::Rect();
     }
     return split_view_controller()
-        ->split_view_divider_->GetDividerBoundsInScreen(is_dragging);
+        ->split_view_divider()
+        ->GetDividerBoundsInScreen(is_dragging);
   }
 
   gfx::Rect GetWorkAreaInScreen(aura::Window* window) {
@@ -8283,7 +8284,7 @@
             split_view_controller()->state());
   EXPECT_TRUE(InOverviewSession());
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
-  ASSERT_TRUE(split_view_controller()->split_view_divider());
+  ASSERT_TRUE(split_view_controller()->split_view_divider()->divider_widget());
   const std::vector<aura::Window*> window_list =
       GetWindowsListInOverviewGrids();
   EXPECT_EQ(2u, window_list.size());
diff --git a/ash/wm/snap_group/snap_group_unittest.cc b/ash/wm/snap_group/snap_group_unittest.cc
index 37302be..9156c76 100644
--- a/ash/wm/snap_group/snap_group_unittest.cc
+++ b/ash/wm/snap_group/snap_group_unittest.cc
@@ -163,7 +163,7 @@
   gfx::Rect expected_grid_bounds = work_area_bounds();
   expected_grid_bounds.Subtract(window->GetBoundsInScreen());
 
-  if (split_view_divider()) {
+  if (split_view_divider()->divider_widget()) {
     expected_grid_bounds.Subtract(split_view_divider_bounds_in_screen());
   }
 
@@ -234,7 +234,7 @@
   gfx::Rect union_bounds;
   union_bounds.Union(w1->GetBoundsInScreen());
   union_bounds.Union(w2->GetBoundsInScreen());
-  const auto divider_bounds = split_view_divider()
+  const auto divider_bounds = split_view_divider()->divider_widget()
                                   ? split_view_divider_bounds_in_screen()
                                   : gfx::Rect();
   union_bounds.Union(divider_bounds);
@@ -699,6 +699,122 @@
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
 }
 
+// Tests that only when there is a non-occluded window snapped on the opposite
+// side should we skip showing partial overview on window snapped. This test
+// focuses on the window layout setup **with** intersections.
+TEST_F(FasterSplitScreenTest,
+       OppositeSnappedWindowOcclusionWithIntersectionsTest) {
+  UpdateDisplay("800x600");
+  // Window Layout before snapping `w1` to the primary snapped position:
+  // `w2` is snapped on the secondary snapped position;
+  // `w3` is stacked above `w2` with intersections.
+  //
+  //                  +-----------+
+  //          +-------|-+         |
+  //          |       | |         |
+  //          |   w3  | |   w2    |
+  //          |       | |         |
+  //          +-------|-+         |
+  //                  +-----------+
+  //
+  // For the window layout setup above, we should show partial overview
+  // when snapping `w1` by the desired snap action source.
+
+  // Snap `w2` to the secondary snapped location without triggering faster split
+  // screen to get window layout setup ready.
+  std::unique_ptr<aura::Window> w2 = CreateAppWindow();
+  SnapOneTestWindow(w2.get(), chromeos::WindowStateType::kSecondarySnapped,
+                    WindowSnapActionSource::kKeyboardShortcutToSnap);
+  ASSERT_TRUE(w2->IsVisible());
+
+  // Create `w3` with bounds that intersect with `w2`.
+  std::unique_ptr<aura::Window> w3 =
+      CreateAppWindow(gfx::Rect(350, 200, 150, 200));
+  ASSERT_TRUE(w3->IsVisible());
+  EXPECT_TRUE(w3->GetBoundsInScreen().Intersects(w2->GetBoundsInScreen()));
+
+  // Create and snap `w1` to the primary snapped position and expect to trigger
+  // the faster split screen setup.
+  std::unique_ptr<aura::Window> w1 = CreateAppWindow();
+  SnapOneTestWindow(w1.get(), chromeos::WindowStateType::kPrimarySnapped,
+                    WindowSnapActionSource::kSnapByWindowLayoutMenu);
+  ASSERT_TRUE(w1->IsVisible());
+  VerifySplitViewOverviewSession(w1.get());
+
+  // Activate `w2` to bring it to the front and snap it to the primary
+  // snapped location without triggering faster split screen in preparation for
+  // the next round of testing. `w2` is fully visible now.
+  wm::ActivateWindow(w2.get());
+  SnapOneTestWindow(w2.get(), chromeos::WindowStateType::kPrimarySnapped,
+                    WindowSnapActionSource::kKeyboardShortcutToSnap);
+  EXPECT_FALSE(IsInOverviewSession());
+
+  // Snap `w1` to secondary snapped position with desired snap action source to
+  // trigger faster split screen setup, with `w1` occupying the primary snapped
+  // position, partial overview shouldn't start.
+  SnapOneTestWindow(w1.get(), chromeos::WindowStateType::kSecondarySnapped,
+                    WindowSnapActionSource::kSnapByWindowLayoutMenu);
+  EXPECT_FALSE(IsInOverviewSession());
+}
+
+// Tests that only when there is a non-occluded window snapped on the opposite
+// side should we skip showing partial overview on window snapped. This test
+// focuses on the window layout setup **without** intersections.
+TEST_F(FasterSplitScreenTest,
+       OppositeSnappedWindowOcclusionWithoutIntersectionsTest) {
+  UpdateDisplay("800x600");
+  // Window Layout before snapping `w1` to the primary snapped position:
+  // `w2` is snapped on the secondary snapped position;
+  // `w3` is stacked above `w2` without intersections.
+  //
+  //              +-----------+
+  //              |    +---+  |
+  //              |    | w3|  |
+  //              |    +---+  |
+  //              |    w2     |
+  //              |           |
+  //              +-----------+
+  //
+  // For the window layout setup above, we should show partial overview
+  // when snapping `w1` by the desired snap action source.
+
+  // Snap `w2` to the secondary snapped location without triggering faster split
+  // screen to get window layout setup ready.
+  std::unique_ptr<aura::Window> w2 = CreateAppWindow();
+  SnapOneTestWindow(w2.get(), chromeos::WindowStateType::kSecondarySnapped,
+                    WindowSnapActionSource::kKeyboardShortcutToSnap);
+  ASSERT_TRUE(w2->IsVisible());
+
+  // Create `w3` with bounds confined by the bounds `w2`.
+  std::unique_ptr<aura::Window> w3 =
+      CreateAppWindow(gfx::Rect(550, 45, 50, 50));
+  ASSERT_TRUE(w3->IsVisible());
+  EXPECT_TRUE(w2->GetBoundsInScreen().Contains(w3->GetBoundsInScreen()));
+
+  // Create and snap `w1` to the primary snapped position and expect to trigger
+  // the faster split screen setup.
+  std::unique_ptr<aura::Window> w1 = CreateAppWindow();
+  SnapOneTestWindow(w1.get(), chromeos::WindowStateType::kPrimarySnapped,
+                    WindowSnapActionSource::kSnapByWindowLayoutMenu);
+  ASSERT_TRUE(w1->IsVisible());
+  VerifySplitViewOverviewSession(w1.get());
+
+  // Activate `w2` to bring it to the front and snap it to the primary
+  // snapped location without triggering faster split screen in preparation for
+  // the next round of testing. `w2` is fully visible now.
+  wm::ActivateWindow(w2.get());
+  SnapOneTestWindow(w2.get(), chromeos::WindowStateType::kPrimarySnapped,
+                    WindowSnapActionSource::kKeyboardShortcutToSnap);
+  EXPECT_FALSE(IsInOverviewSession());
+
+  // Snap `w1` to secondary snapped position with desired snap action source to
+  // trigger faster split screen setup, with `w1` occupying the primary snapped
+  // position, partial overview shouldn't start.
+  SnapOneTestWindow(w1.get(), chromeos::WindowStateType::kSecondarySnapped,
+                    WindowSnapActionSource::kSnapByWindowLayoutMenu);
+  EXPECT_FALSE(IsInOverviewSession());
+}
+
 TEST_F(FasterSplitScreenTest, MultiDisplay) {
   UpdateDisplay("800x600,1000x600");
   display::test::DisplayManagerTestApi display_manager_test(display_manager());
@@ -729,7 +845,7 @@
   VerifySplitViewOverviewSession(w1.get());
 
   SwitchToTabletMode();
-  EXPECT_TRUE(split_view_divider());
+  EXPECT_TRUE(split_view_divider()->divider_widget());
   auto observed_windows = split_view_divider()->observed_windows();
   EXPECT_EQ(1u, observed_windows.size());
   EXPECT_EQ(w1.get(), observed_windows.front());
@@ -748,10 +864,10 @@
                               ->GetTransformedBounds()
                               .CenterPoint()));
   event_generator->ClickLeftButton();
-  EXPECT_FALSE(split_view_divider());
+  EXPECT_FALSE(split_view_divider()->divider_widget());
 
   SwitchToTabletMode();
-  EXPECT_TRUE(split_view_divider());
+  EXPECT_TRUE(split_view_divider()->divider_widget());
   auto observed_windows = split_view_divider()->observed_windows();
   EXPECT_EQ(2u, observed_windows.size());
   // TODO(b/312229933): Determine whether the order of `observed_windows_`
@@ -771,9 +887,9 @@
   std::unique_ptr<aura::Window> w1(CreateAppWindow());
   SnapOneTestWindow(w1.get(), chromeos::WindowStateType::kPrimarySnapped);
   SwitchToTabletMode();
-  EXPECT_TRUE(split_view_divider());
+  EXPECT_TRUE(split_view_divider()->divider_widget());
 
-  // Double tap on the divider. This will start a drag and notify
+  // Double tap on the divider-> This will start a drag and notify
   // SplitViewOverviewSession.
   const gfx::Point divider_center =
       split_view_divider()
@@ -782,6 +898,7 @@
   GetEventGenerator()->GestureTapAt(divider_center);
   GetEventGenerator()->GestureTapAt(divider_center);
 }
+
 // Tests the histograms for the split view overview session exit points are
 // recorded correctly in clamshell.
 TEST_F(FasterSplitScreenTest,
@@ -904,73 +1021,6 @@
       /*expected_count=*/1);
 }
 
-// Tests the histograms for the split view overview session exit points are
-// recorded correctly in tablet mode.
-// SplitViewOverviewSession should not support tablet mode.
-// TODO(sophiewen): Re-enable or delete this.
-TEST_F(FasterSplitScreenTest,
-       DISABLED_SplitViewOverviewSessionExitPointTabletHistograms) {
-  UpdateDisplay("800x600");
-  SwitchToTabletMode();
-  EXPECT_TRUE(Shell::Get()->IsInTabletMode());
-
-  const auto kWindowLayoutCompleteOnSessionExit =
-      BuildWindowLayoutCompleteOnSessionExitHistogram();
-  const auto kSplitViewOverviewSessionExitPoint =
-      BuildSplitViewOverviewExitPointHistogramName(
-          WindowSnapActionSource::kNotSpecified);
-
-  std::unique_ptr<aura::Window> w1(CreateAppWindow());
-  std::unique_ptr<aura::Window> w2(CreateAppWindow());
-
-  // Verify the initial count for the histogram.
-  histogram_tester_.ExpectBucketCount(kWindowLayoutCompleteOnSessionExit,
-                                      /*sample=*/true,
-                                      /*expected_count=*/0);
-  histogram_tester_.ExpectBucketCount(kWindowLayoutCompleteOnSessionExit,
-                                      /*sample=*/false,
-                                      /*expected_count=*/0);
-
-  // Set up the splitview overview session and select a window in the partial
-  // overview to complete the window layout.
-  SnapOneTestWindow(w1.get(), chromeos::WindowStateType::kPrimarySnapped);
-  VerifySplitViewOverviewSession(w1.get());
-
-  auto* item2 = GetOverviewItemForWindow(w2.get());
-  auto* event_generator = GetEventGenerator();
-  event_generator->PressTouch(
-      gfx::ToRoundedPoint(item2->target_bounds().CenterPoint()));
-  event_generator->ReleaseTouch();
-  histogram_tester_.ExpectBucketCount(kWindowLayoutCompleteOnSessionExit,
-                                      /*sample=*/true,
-                                      /*expected_count=*/1);
-  histogram_tester_.ExpectBucketCount(kWindowLayoutCompleteOnSessionExit,
-                                      /*sample=*/false,
-                                      /*expected_count=*/0);
-  histogram_tester_.ExpectBucketCount(
-      kSplitViewOverviewSessionExitPoint,
-      SplitViewOverviewSessionExitPoint::kCompleteByActivating,
-      /*expected_count=*/1);
-  MaximizeToClearTheSession(w1.get());
-  MaximizeToClearTheSession(w2.get());
-
-  // Set up the splitview overview session, create a 3rd window to be
-  // auto-snapped and complete the window layout.
-  SnapOneTestWindow(w1.get(), chromeos::WindowStateType::kPrimarySnapped);
-  VerifySplitViewOverviewSession(w1.get());
-  std::unique_ptr<aura::Window> w3(CreateAppWindow());
-  histogram_tester_.ExpectBucketCount(kWindowLayoutCompleteOnSessionExit,
-                                      /*sample=*/true,
-                                      /*expected_count=*/2);
-  histogram_tester_.ExpectBucketCount(kWindowLayoutCompleteOnSessionExit,
-                                      /*sample=*/false,
-                                      /*expected_count=*/0);
-  histogram_tester_.ExpectBucketCount(
-      kSplitViewOverviewSessionExitPoint,
-      SplitViewOverviewSessionExitPoint::kCompleteByActivating,
-      /*expected_count=*/2);
-}
-
 // Integration test of the `SplitViewOverviewSession` exit point with drag to
 // snap action source. Verify that the end-to-end metric is recorded correctly.
 TEST_F(FasterSplitScreenTest, KeyMetricsIntegrationTest_DragToSnap) {
@@ -1194,7 +1244,7 @@
     EXPECT_TRUE(snap_group_controller->AreWindowsInSnapGroup(window1, window2));
 
     // The split view divider will show on two windows snapped.
-    EXPECT_TRUE(split_view_divider());
+    EXPECT_TRUE(split_view_divider()->divider_widget());
     EXPECT_EQ(0.5f, *WindowState::Get(window1)->snap_ratio());
     EXPECT_EQ(0.5f, *WindowState::Get(window2)->snap_ratio());
 
@@ -1448,7 +1498,7 @@
   EXPECT_FALSE(WindowState::Get(w3.get())->IsSnapped());
   EXPECT_TRUE(
       SnapGroupController::Get()->AreWindowsInSnapGroup(w1.get(), w2.get()));
-  EXPECT_TRUE(split_view_divider());
+  EXPECT_TRUE(split_view_divider()->divider_widget());
 }
 
 // Tests that removing a display during split view overview session doesn't
@@ -1480,7 +1530,7 @@
 }
 
 // Tests the snap ratio is updated correctly when resizing the windows in a snap
-// group with the split view divider.
+// group with the split view divider->
 TEST_F(SnapGroupTest, SnapRatioTest) {
   std::unique_ptr<aura::Window> w1(CreateTestWindow());
   std::unique_ptr<aura::Window> w2(CreateTestWindow());
@@ -1501,7 +1551,7 @@
 }
 
 // Tests that the windows in a snap group can be resized to an arbitrary
-// location with the split view divider.
+// location with the split view divider->
 TEST_F(SnapGroupTest, ResizeWithSplitViewDividerToArbitraryLocations) {
   std::unique_ptr<aura::Window> w1(CreateTestWindow());
   std::unique_ptr<aura::Window> w2(CreateTestWindow());
@@ -1603,7 +1653,7 @@
   EXPECT_TRUE(window_util::IsStackedBelow(w3.get(), w1.get()));
 
   w1.reset();
-  EXPECT_FALSE(split_view_divider());
+  EXPECT_FALSE(split_view_divider()->divider_widget());
   EXPECT_TRUE(snap_groups.empty());
   EXPECT_TRUE(window_to_snap_group_map.empty());
 }
@@ -1683,8 +1733,8 @@
   wm::ActivateWindow(w1.get());
 
   SplitViewDivider* divider = split_view_divider();
-  ASSERT_TRUE(divider);
   auto* divider_widget = divider->divider_widget();
+  ASSERT_TRUE(divider_widget);
   aura::Window* divider_window = divider_widget->GetNativeWindow();
   EXPECT_TRUE(window_util::IsStackedBelow(w2.get(), w1.get()));
   EXPECT_TRUE(window_util::IsStackedBelow(w1.get(), divider_window));
@@ -1706,8 +1756,8 @@
   SnapTwoTestWindows(w1.get(), w2.get());
 
   SplitViewDivider* divider = split_view_divider();
-  ASSERT_TRUE(divider);
   auto* divider_widget = divider->divider_widget();
+  ASSERT_TRUE(divider_widget);
   aura::Window* divider_window = divider_widget->GetNativeWindow();
   ASSERT_TRUE(window_util::IsStackedBelow(w1.get(), w2.get()));
   ASSERT_TRUE(window_util::IsStackedBelow(w1.get(), divider_window));
@@ -1771,7 +1821,7 @@
   WaitForOverviewEnterAnimation();
   EXPECT_TRUE(overview_controller->overview_session());
   EXPECT_EQ(GetOverviewGridBounds(), work_area_bounds());
-  EXPECT_FALSE(split_view_divider());
+  EXPECT_FALSE(split_view_divider()->divider_widget());
   EXPECT_EQ(chromeos::WindowStateType::kPrimarySnapped,
             WindowState::Get(w1.get())->GetStateType());
   EXPECT_EQ(chromeos::WindowStateType::kSecondarySnapped,
@@ -1787,7 +1837,7 @@
             WindowState::Get(w1.get())->GetStateType());
   EXPECT_EQ(chromeos::WindowStateType::kSecondarySnapped,
             WindowState::Get(w2.get())->GetStateType());
-  EXPECT_TRUE(split_view_divider());
+  EXPECT_TRUE(split_view_divider()->divider_widget());
 }
 
 // Tests that partial overview is shown on the other side of the screen on one
@@ -1907,7 +1957,7 @@
   std::unique_ptr<aura::Window> w2(CreateAppWindow());
   std::unique_ptr<aura::Window> w3(CreateAppWindow());
   SnapTwoTestWindows(w1.get(), w2.get());
-  ASSERT_TRUE(split_view_divider());
+  ASSERT_TRUE(split_view_divider()->divider_widget());
   const gfx::Size w1_size_before_overview = w1->GetBoundsInScreen().size();
 
   OverviewController* overview_controller = OverviewController::Get();
@@ -1967,7 +2017,7 @@
   std::unique_ptr<aura::Window> w1(CreateAppWindow());
   std::unique_ptr<aura::Window> w2(CreateAppWindow());
   SnapTwoTestWindows(w1.get(), w2.get());
-  ASSERT_TRUE(split_view_divider());
+  ASSERT_TRUE(split_view_divider()->divider_widget());
   const gfx::Point hover_location =
       split_view_divider_bounds_in_screen().CenterPoint();
   split_view_divider()->StartResizeWithDivider(hover_location);
@@ -2619,7 +2669,7 @@
   EXPECT_TRUE(SnapGroupController::Get()->AreWindowsInSnapGroup(window0.get(),
                                                                 window1.get()));
   ActivateDesk(desk1);
-  EXPECT_TRUE(split_view_divider());
+  EXPECT_TRUE(split_view_divider()->divider_widget());
   EXPECT_EQ(desks_util::GetDeskForContext(
                 split_view_divider()->divider_widget()->GetNativeWindow()),
             desk1);
@@ -2670,7 +2720,7 @@
   event_generator->PressAndReleaseKey(ui::VKEY_G,
                                       ui::EF_SHIFT_DOWN | ui::EF_COMMAND_DOWN);
   EXPECT_TRUE(snap_group_controller->AreWindowsInSnapGroup(w1.get(), w2.get()));
-  EXPECT_TRUE(split_view_divider());
+  EXPECT_TRUE(split_view_divider()->divider_widget());
 }
 
 // Tests that the windows in snap group can be toggled between been minimized
@@ -2696,7 +2746,7 @@
   EXPECT_FALSE(WindowState::Get(w1.get())->IsMinimized());
   EXPECT_FALSE(WindowState::Get(w2.get())->IsMinimized());
   EXPECT_TRUE(snap_group_controller->AreWindowsInSnapGroup(w1.get(), w2.get()));
-  EXPECT_TRUE(split_view_divider());
+  EXPECT_TRUE(split_view_divider()->divider_widget());
 }
 
 TEST_F(SnapGroupTest, SkipPairingInOverviewWhenClickingEmptyArea) {
@@ -3101,10 +3151,10 @@
   std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0));
   std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1));
   SnapTwoTestWindows(window1.get(), window2.get(), /*horizontal=*/true);
-  EXPECT_TRUE(split_view_divider());
+  EXPECT_TRUE(split_view_divider()->divider_widget());
 
   SwitchToTabletMode();
-  EXPECT_TRUE(split_view_divider());
+  EXPECT_TRUE(split_view_divider()->divider_widget());
   auto observed_windows = split_view_divider()->observed_windows();
   EXPECT_EQ(window1.get(), observed_windows.front());
   EXPECT_EQ(window2.get(), observed_windows.back());
@@ -3121,7 +3171,7 @@
               /*abs_error=*/0.01);
   EXPECT_NEAR(0.5f, *WindowState::Get(window2.get())->snap_ratio(),
               /*abs_error=*/0.01);
-  EXPECT_TRUE(split_view_divider());
+  EXPECT_TRUE(split_view_divider()->divider_widget());
 }
 
 // Tests that when converting to tablet mode with split view divider at an
@@ -3133,7 +3183,7 @@
   std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0));
   std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1));
   SnapTwoTestWindows(window1.get(), window2.get(), /*horizontal=*/true);
-  ASSERT_TRUE(split_view_divider());
+  ASSERT_TRUE(split_view_divider()->divider_widget());
   EXPECT_EQ(*WindowState::Get(window1.get())->snap_ratio(),
             chromeos::kDefaultSnapRatio);
 
@@ -3195,13 +3245,13 @@
 }
 
 // Tests that the cursor type gets updated to be resize cursor on mouse hovering
-// on the split view divider.
+// on the split view divider->
 TEST_F(SnapGroupTest, CursorUpdateTest) {
   std::unique_ptr<aura::Window> w1(CreateTestWindow());
   std::unique_ptr<aura::Window> w2(CreateTestWindow());
   SnapTwoTestWindows(w1.get(), w2.get(), /*horizontal=*/true);
   auto* divider = split_view_divider();
-  ASSERT_TRUE(divider);
+  ASSERT_TRUE(divider->divider_widget());
 
   auto divider_bounds = split_view_divider_bounds_in_screen();
   auto outside_point = split_view_divider_bounds_in_screen().CenterPoint();
@@ -3212,7 +3262,7 @@
   cursor_manager->SetCursor(CursorType::kPointer);
 
   // Test that the default cursor type when mouse is not hovered over the split
-  // view divider.
+  // view divider->
   auto* event_generator = GetEventGenerator();
   event_generator->MoveMouseTo(outside_point);
   EXPECT_TRUE(cursor_manager->IsCursorVisible());
@@ -3220,7 +3270,7 @@
   EXPECT_EQ(CursorType::kNull, cursor_manager->GetCursor().type());
 
   // Test that the cursor changed to resize cursor while hovering over the split
-  // view divider.
+  // view divider->
   const auto delta_vector = gfx::Vector2d(0, -10);
   const gfx::Point cached_hover_point =
       divider_bounds.CenterPoint() + delta_vector;
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc
index 90c3f06..bbb00836 100644
--- a/ash/wm/splitview/split_view_controller.cc
+++ b/ash/wm/splitview/split_view_controller.cc
@@ -25,6 +25,7 @@
 #include "ash/shell.h"
 #include "ash/style/ash_color_provider.h"
 #include "ash/wm/desks/desks_controller.h"
+#include "ash/wm/desks/desks_util.h"
 #include "ash/wm/float/float_controller.h"
 #include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/overview/delayed_animation_observer_impl.h"
@@ -486,6 +487,7 @@
     : root_window_(root_window),
       to_be_snapped_windows_observer_(
           std::make_unique<ToBeSnappedWindowsObserver>(this)),
+      split_view_divider_(this),
       split_view_metrics_controller_(
           std::make_unique<SplitViewMetricsController>(this)) {
   Shell::Get()->accessibility_controller()->AddObserver(this);
@@ -509,14 +511,12 @@
 }
 
 int SplitViewController::GetDividerPosition() const {
-  // TODO(b/308819668): Temporary check. Remove this entire function when
-  // `GetDividerPosition()` is moved to `SplitViewDivider`.
-  CHECK(split_view_divider_);
-  return split_view_divider_->divider_position_;
+  return split_view_divider_.divider_position_;
 }
 
 bool SplitViewController::IsResizingWithDivider() const {
-  return split_view_divider_ && split_view_divider_->is_resizing_with_divider();
+  return split_view_divider_.HasDividerWidget() &&
+         split_view_divider_.is_resizing_with_divider();
 }
 
 bool SplitViewController::InSplitViewMode() const {
@@ -802,7 +802,8 @@
   // TODO(michelefan): See if it is a valid case to not having `snap_ratio`
   // while `divider_position` is less than 0.
   bool do_snap_animation = false;
-  int divider_position = split_view_divider_ ? GetDividerPosition() : -1;
+  int divider_position =
+      split_view_divider_.divider_widget() ? GetDividerPosition() : -1;
   if (absl::optional<float> snap_ratio = WindowState::Get(window)->snap_ratio();
       snap_ratio) {
     divider_position = CalculateDividerPosition(snap_position, *snap_ratio);
@@ -815,21 +816,21 @@
         CalculateDividerPosition(snap_position, chromeos::kDefaultSnapRatio);
   }
 
-  if (InTabletMode() && !split_view_divider_) {
+  if (InTabletMode()) {
     // `split_view_divider_` must be created after we start observing windows.
-    split_view_divider_ =
-        std::make_unique<SplitViewDivider>(this, divider_position);
+    CHECK(primary_window_ || secondary_window_);
+    split_view_divider_.ShowFor(divider_position);
   }
 
   base::RecordAction(base::UserMetricsAction("SplitView_SnapWindow"));
 
-  if (!split_view_divider_) {
+  if (!split_view_divider_.divider_widget()) {
     return;
   }
 
   const int fixed_divider_position =
       GetClosestFixedDividerPosition(divider_position);
-  // This must be done before we update `split_view_divider_->divider_position_`
+  // This must be done before we update `split_view_divider_.divider_position_`
   // to `fixed_divider_position`, since the minimum size will be respected
   // there.
   if (do_snap_animation) {
@@ -848,7 +849,7 @@
   }
 
   SetDividerPosition(fixed_divider_position);
-  split_view_divider_->UpdateDividerBounds();
+  split_view_divider_.UpdateDividerBounds();
 }
 
 void SplitViewController::SwapWindows() {
@@ -944,11 +945,11 @@
   }
 
   const int divider_position =
-      split_view_divider_ ? GetDividerPosition()
-                          : CalculateDividerPosition(snap_position, snap_ratio);
-  const int divider_width = InTabletMode() || split_view_divider_
-                                ? kSplitviewDividerShortSideLength
-                                : 0;
+      split_view_divider_.divider_widget()
+          ? GetDividerPosition()
+          : CalculateDividerPosition(snap_position, snap_ratio);
+  const int divider_width =
+      ShouldConsiderDivider() ? kSplitviewDividerShortSideLength : 0;
   return CalculateSnappedWindowBoundsInScreen(
       snap_position, root_window_, window_for_minimum_size, divider_position,
       divider_width, IsResizingWithDivider());
@@ -970,7 +971,7 @@
   // TODO(b/309856199): Currently need to pipe `should_consider_divider` since
   // the divider is still created in `SplitViewController` for Snap Groups.
   // Refactor this when `split_view_divider_` is moved out.
-  return split_view_divider_ || InTabletMode();
+  return split_view_divider_.HasDividerWidget() || InTabletMode();
 }
 
 bool SplitViewController::IsDividerAnimating() const {
@@ -1034,7 +1035,7 @@
   // Close splitview divider widget after updating state so that
   // OnDisplayMetricsChanged triggered by the widget closing correctly
   // finds out !InSplitViewMode().
-  split_view_divider_.reset();
+  split_view_divider_.CloseDividerWidget();
   base::RecordAction(base::UserMetricsAction("SplitView_EndSplitView"));
   const base::Time now = base::Time::Now();
   UMA_HISTOGRAM_LONG_TIMES("Ash.SplitView.TimeInSplitView",
@@ -1117,8 +1118,8 @@
                             WindowDetachedReason::kWindowDragged);
   }
 
-  if (split_view_divider_) {
-    split_view_divider_->OnWindowDragStarted(dragged_window);
+  if (split_view_divider_.divider_widget()) {
+    split_view_divider_.OnWindowDragStarted(dragged_window);
   }
 }
 
@@ -1134,8 +1135,9 @@
 }
 
 void SplitViewController::OnWindowDragCanceled() {
-  if (split_view_divider_)
-    split_view_divider_->OnWindowDragEnded();
+  if (split_view_divider_.divider_widget()) {
+    split_view_divider_.OnWindowDragEnded();
+  }
 }
 
 SnapPosition SplitViewController::ComputeSnapPosition(
@@ -1211,7 +1213,7 @@
     const gfx::Rect& old_bounds,
     const gfx::Rect& new_bounds,
     ui::PropertyChangeReason reason) {
-  if (!InClamshellSplitViewMode() || split_view_divider_) {
+  if (!InClamshellSplitViewMode() || split_view_divider_.divider_widget()) {
     // Divider width is not taken into consideration in the calculation below.
     // Early exit if `split_view_divider_` exists in clamshell mode.
     return;
@@ -1492,7 +1494,7 @@
   // In clamshell split view mode, the divider position will be adjusted in
   // `OnWindowBoundsChanged`. Also when we first enter tablet mode, the divider
   // has not been created yet but there may be a work area change.
-  if (!InTabletMode() || !split_view_divider_) {
+  if (!InTabletMode() || !split_view_divider_.divider_widget()) {
     return;
   }
 
@@ -1618,13 +1620,15 @@
         display::Screen::GetScreen()->GetDisplayNearestWindow(root_window_));
   }
 
+  CHECK(split_view_divider_.divider_widget());
+
   // Set split view divider bounds.
-  split_view_divider_->divider_widget()->SetBounds(
+  split_view_divider_.divider_widget()->SetBounds(
       SplitViewDivider::GetDividerBoundsInScreen(work_area, /*landscape=*/false,
                                                  divider_position,
                                                  /*is_dragging=*/false));
   // Make split view divider unadjustable.
-  split_view_divider_->SetAdjustable(false);
+  split_view_divider_.SetAdjustable(false);
 }
 
 void SplitViewController::OnWindowActivated(ActivationReason reason,
@@ -1633,7 +1637,8 @@
   // If the bottom window is moved for the virtual keyboard (the split view
   // divider bar is unadjustable), when the bottom window lost active, restore
   // to the original layout.
-  if (!split_view_divider_ || split_view_divider_->IsAdjustable()) {
+  if (!split_view_divider_.divider_widget() ||
+      split_view_divider_.IsAdjustable()) {
     return;
   }
 
@@ -1658,7 +1663,7 @@
 
 void SplitViewController::OnSnapGroupRemoved(SnapGroup* snap_group) {
   CHECK(Shell::Get()->snap_group_controller());
-  split_view_divider_.reset();
+  split_view_divider_.CloseDividerWidget();
 
   if (snap_group->window1() == primary_window_ &&
       snap_group->window2() == secondary_window_) {
@@ -1731,9 +1736,8 @@
     Shell::Get()->shadow_controller()->UpdateShadowForWindow(window);
     window->AddObserver(this);
     WindowState::Get(window)->AddObserver(this);
-    if (split_view_divider_) {
-      split_view_divider_->AddObservedWindow(window);
-    }
+    // `SplitViewDivider` will start observing when the divider widget is
+    // created.
   }
 }
 
@@ -1748,8 +1752,9 @@
   if (window && window->HasObserver(this)) {
     window->RemoveObserver(this);
     WindowState::Get(window)->RemoveObserver(this);
-    if (split_view_divider_)
-      split_view_divider_->RemoveObservedWindow(window);
+    if (split_view_divider_.divider_widget()) {
+      split_view_divider_.RemoveObservedWindow(window);
+    }
     Shell::Get()->shadow_controller()->UpdateShadowForWindow(window);
 
     // It's possible that when we try to snap an ARC app window, while we are
@@ -1818,17 +1823,18 @@
 
   // TODO(b/309856199): Move this function to `SnapGroup`.
 void SplitViewController::RefreshSplitViewDividerInClamshell() {
+  if (split_view_divider_.divider_widget()) {
+    // Don't recreate the divider if it's already created, which may happen
+    // during tablet <-> clamshell transition. Needed since we still create
+    // the divider in `SplitViewController`, will be removed in b/309856199.
+    return;
+  }
   SnapGroupController* snap_group_controller = SnapGroupController::Get();
   CHECK(snap_group_controller);
-
   CHECK(primary_window_ && secondary_window_);
-  if (!split_view_divider_) {
-    split_view_divider_ = std::make_unique<SplitViewDivider>(
-        this, ash::GetEquivalentDividerPosition(primary_window_,
-                                                ShouldConsiderDivider()));
-  }
-
-  split_view_divider_->RefreshStackingOrder();
+  const int divider_position = ash::GetEquivalentDividerPosition(
+      primary_window_, /*should_consider_divider=*/false);
+  split_view_divider_.ShowFor(divider_position);
 }
 
 void SplitViewController::UpdateBlackScrim(
@@ -1841,7 +1847,7 @@
     black_scrim_layer_->SetColor(AshColorProvider::Get()->GetBackgroundColor());
     // Set the black scrim layer underneath split view divider.
     auto* divider_layer =
-        split_view_divider_->divider_widget()->GetNativeWindow()->layer();
+        split_view_divider_.divider_widget()->GetNativeWindow()->layer();
     auto* divider_parent_layer = divider_layer->parent();
     divider_parent_layer->Add(black_scrim_layer_.get());
     divider_parent_layer->StackBelow(black_scrim_layer_.get(), divider_layer);
@@ -1929,11 +1935,11 @@
   }
 
   // Update divider's bounds and make it adjustable.
-  if (split_view_divider_) {
-    split_view_divider_->UpdateDividerBounds();
+  if (split_view_divider_.divider_widget()) {
+    split_view_divider_.UpdateDividerBounds();
 
     // Make the split view divider adjustable.
-      split_view_divider_->SetAdjustable(true);
+    split_view_divider_.SetAdjustable(true);
   }
 }
 
@@ -2415,9 +2421,8 @@
   if (window != nullptr) {
     WindowState* window_state = WindowState::Get(window);
     if (window_state->is_dragged()) {
-      CHECK(split_view_divider_);
       window_state->OnCompleteDrag(gfx::PointF(GetEndDragLocationInScreen(
-          window, split_view_divider_->previous_event_location_)));
+          window, split_view_divider_.previous_event_location_)));
       window_state->DeleteDragDetails();
     }
   }
@@ -2427,7 +2432,7 @@
   base::RecordAction(base::UserMetricsAction("SplitView_ResizeWindows"));
   if (state_ == State::kBothSnapped) {
     presentation_time_recorder_ = CreatePresentationTimeHistogramRecorder(
-        split_view_divider_->divider_widget()->GetCompositor(),
+        split_view_divider_.divider_widget()->GetCompositor(),
         kTabletSplitViewResizeMultiHistogram,
         kTabletSplitViewResizeMultiMaxLatencyHistogram);
     return;
@@ -2436,12 +2441,12 @@
   CHECK(GetOverviewSession());
   if (GetOverviewSession()->GetGridWithRootWindow(root_window_)->empty()) {
     presentation_time_recorder_ = CreatePresentationTimeHistogramRecorder(
-        split_view_divider_->divider_widget()->GetCompositor(),
+        split_view_divider_.divider_widget()->GetCompositor(),
         kTabletSplitViewResizeSingleHistogram,
         kTabletSplitViewResizeSingleMaxLatencyHistogram);
   } else {
     presentation_time_recorder_ = CreatePresentationTimeHistogramRecorder(
-        split_view_divider_->divider_widget()->GetCompositor(),
+        split_view_divider_.divider_widget()->GetCompositor(),
         kTabletSplitViewResizeWithOverviewHistogram,
         kTabletSplitViewResizeWithOverviewMaxLatencyHistogram);
   }
@@ -2490,10 +2495,10 @@
 
 void SplitViewController::EndResizeWithDividerImpl() {
   DCHECK(InSplitViewMode());
-  if (split_view_divider_) {
+  if (split_view_divider_.divider_widget()) {
     // TODO(b/315854755): Move `DividerSnapAnimation` to `SplitViewDivider` and
     // see if we can remove this.
-    split_view_divider_->set_is_resizing_with_divider(false);
+    split_view_divider_.set_is_resizing_with_divider(false);
   }
 
   EndTabletResizeImpl();
@@ -2504,9 +2509,9 @@
 }
 
 void SplitViewController::OnResizeTimer() {
-  if (InSplitViewMode() && split_view_divider_) {
-    split_view_divider_->ResizeWithDivider(
-        split_view_divider_->previous_event_location_);
+  if (InSplitViewMode() && split_view_divider_.divider_widget()) {
+    split_view_divider_.ResizeWithDivider(
+        split_view_divider_.previous_event_location_);
   }
 }
 
@@ -2518,10 +2523,10 @@
 
   if (IsLayoutHorizontal(root_window_)) {
     accumulated_drag_distance_ += std::abs(
-        event_location.x() - split_view_divider_->previous_event_location_.x());
+        event_location.x() - split_view_divider_.previous_event_location_.x());
   } else {
     accumulated_drag_distance_ += std::abs(
-        event_location.y() - split_view_divider_->previous_event_location_.y());
+        event_location.y() - split_view_divider_.previous_event_location_.y());
   }
 
   const base::TimeDelta chunk_time_ticks =
@@ -2562,18 +2567,15 @@
     // `TabletModeWindowManager::ArrangeWindowsForTabletMode()`.
     CHECK(primary_window_ || secondary_window_);
     // Tablet mode only supports the fixed divider positions in
-    // `kFixedPositionRatios`, so push `target_divider_position` to the closest
+    // `kFixedPositionRatios`, so push `divider_position_` to the closest
     // fixed ratio.
-    // Note at this point we are calculating the equivalent divider position
-    // *before*
+    // TODO(b/308819668): Remove this when `divider_position` is saved in
+    // `SplitViewDivider`.
     const int divider_position =
         GetClosestFixedDividerPosition(ash::GetEquivalentDividerPosition(
             primary_window_ ? primary_window_ : secondary_window_,
-            /*account_for_divider_width=*/false));
-    if (!split_view_divider_) {
-      split_view_divider_ =
-          std::make_unique<SplitViewDivider>(this, divider_position);
-    }
+            /*should_consider_divider=*/false));
+    split_view_divider_.ShowFor(divider_position);
 
     UpdateSnappedWindowsAndDividerBounds();
     NotifyDividerPositionChanged();
@@ -2597,7 +2599,7 @@
   if (state_ != State::kBothSnapped || !snap_group_controller ||
       !snap_group_controller->AreWindowsInSnapGroup(primary_window_,
                                                     secondary_window_)) {
-    split_view_divider_.reset();
+    split_view_divider_.CloseDividerWidget();
   }
 }
 
@@ -2611,8 +2613,9 @@
     SnapPosition desired_snap_position,
     const gfx::Point& last_location_in_screen,
     WindowSnapActionSource snap_action_source) {
-  if (split_view_divider_)
-    split_view_divider_->OnWindowDragEnded();
+  if (split_view_divider_.divider_widget()) {
+    split_view_divider_.OnWindowDragEnded();
+  }
 
   // If the dragged window is to be destroyed, do not try to snap it.
   if (is_being_destroyed)
@@ -2698,8 +2701,8 @@
                                             gfx::Transform()))
           .MapPoint(p);
   // Use a coordinate of the transformed |window| corner for spawn_position.
-  split_view_divider_->DoSpawningAnimation(IsLayoutHorizontal(window) ? p.x()
-                                                                      : p.y());
+  split_view_divider_.DoSpawningAnimation(IsLayoutHorizontal(window) ? p.x()
+                                                                     : p.y());
 }
 
 void SplitViewController::SwapWindowsAndUpdateBounds() {
@@ -2724,8 +2727,10 @@
 }
 
 void SplitViewController::SetDividerPosition(int divider_position) {
-  CHECK(split_view_divider_);
-  split_view_divider_->divider_position_ = divider_position;
+  // TODO(sophiewen): Consolidate this with `SplitViewDivider::ShowFor()` and
+  // `SplitViewDivider::UpdateDividerBounds()`.
+  CHECK(split_view_divider_.divider_widget());
+  split_view_divider_.divider_position_ = divider_position;
 }
 
 }  // namespace ash
diff --git a/ash/wm/splitview/split_view_controller.h b/ash/wm/splitview/split_view_controller.h
index 4ba636d..1832333 100644
--- a/ash/wm/splitview/split_view_controller.h
+++ b/ash/wm/splitview/split_view_controller.h
@@ -19,6 +19,7 @@
 #include "ash/wm/overview/overview_types.h"
 #include "ash/wm/snap_group/snap_group_controller.h"
 #include "ash/wm/splitview/layout_divider_controller.h"
+#include "ash/wm/splitview/split_view_divider.h"
 #include "ash/wm/splitview/split_view_types.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/window_state_observer.h"
@@ -50,7 +51,6 @@
 class AutoSnapController;
 class OverviewSession;
 class SplitViewOverviewSession;
-class SplitViewDivider;
 class SplitViewMetricsController;
 class SplitViewObserver;
 class SplitViewOverviewSessionTest;
@@ -162,7 +162,7 @@
 
   State state() const { return state_; }
   SnapPosition default_snap_position() const { return default_snap_position_; }
-  SplitViewDivider* split_view_divider() { return split_view_divider_.get(); }
+  SplitViewDivider* split_view_divider() { return &split_view_divider_; }
   EndReason end_reason() const { return end_reason_; }
   SplitViewMetricsController* split_view_metrics_controller() {
     return split_view_metrics_controller_.get();
@@ -625,7 +625,7 @@
   // will be used in these two cases:
   // 1. Tablet splitview mode;
   // 2. Clamshell splitview mode when `kSnapGroup` is enabled.
-  std::unique_ptr<SplitViewDivider> split_view_divider_;
+  SplitViewDivider split_view_divider_;
 
   // A black scrim layer that fades in over a window when its width drops under
   // 1/3 of the width of the screen, increasing in opacity as the divider gets
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc
index 2b6c0f9..d522146 100644
--- a/ash/wm/splitview/split_view_controller_unittest.cc
+++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -616,7 +616,7 @@
   OverviewController* overview_controller = OverviewController::Get();
   EXPECT_TRUE(overview_controller->InOverviewSession());
   SplitViewDivider* divider = split_view_divider();
-  EXPECT_TRUE(divider);
+  EXPECT_TRUE(divider->divider_widget());
 
   const auto center_point =
       divider->GetDividerBoundsInScreen(/*is_dragging=*/false).CenterPoint();
@@ -885,13 +885,13 @@
   std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
   std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
 
-  EXPECT_TRUE(!split_view_divider());
+  EXPECT_TRUE(!split_view_divider()->divider_widget());
   split_view_controller()->SnapWindow(window1.get(), SnapPosition::kPrimary);
-  EXPECT_TRUE(split_view_divider());
+  EXPECT_TRUE(split_view_divider()->divider_widget());
   EXPECT_EQ(ui::ZOrderLevel::kNormal,
             split_view_divider()->divider_widget()->GetZOrderLevel());
   split_view_controller()->SnapWindow(window2.get(), SnapPosition::kSecondary);
-  EXPECT_TRUE(split_view_divider());
+  EXPECT_TRUE(split_view_divider()->divider_widget());
   EXPECT_EQ(ui::ZOrderLevel::kNormal,
             split_view_divider()->divider_widget()->GetZOrderLevel());
   EXPECT_TRUE(window_util::IsStackedBelow(
@@ -904,7 +904,7 @@
   // Test that activating an non-snappable window ends the split view mode.
   std::unique_ptr<aura::Window> window3(CreateNonSnappableWindow(bounds));
   wm::ActivateWindow(window3.get());
-  EXPECT_FALSE(split_view_divider());
+  EXPECT_FALSE(split_view_divider()->divider_widget());
 }
 
 // Tests that the split divider has the correct state when the dragged overview
@@ -995,7 +995,7 @@
 
   split_view_controller()->SnapWindow(window1.get(), SnapPosition::kPrimary);
   split_view_controller()->SnapWindow(window2.get(), SnapPosition::kSecondary);
-  ASSERT_TRUE(split_view_divider());
+  ASSERT_TRUE(split_view_divider()->divider_widget());
 
   // Verify with two freshly snapped windows are roughly the same width (off by
   // one pixel at most due to the display maybe being even and the divider being
@@ -1087,7 +1087,8 @@
       SplitViewController::Get(w2->GetRootWindow());
   split_view_controller_on_display2->SnapWindow(w2.get(),
                                                 SnapPosition::kPrimary);
-  ASSERT_TRUE(split_view_controller_on_display2->split_view_divider());
+  ASSERT_TRUE(split_view_controller_on_display2->split_view_divider()
+                  ->divider_widget());
 
   // Now disconnect the second display, verify there's no crash.
   UpdateDisplay("800x600");
@@ -1119,7 +1120,7 @@
   auto* split_view_controller = SplitViewController::Get(w->GetRootWindow());
   split_view_controller->SnapWindow(w.get(), SnapPosition::kPrimary);
   auto* split_view_divider = split_view_controller->split_view_divider();
-  ASSERT_TRUE(split_view_divider);
+  ASSERT_TRUE(split_view_divider->divider_widget());
 
   auto* event_generator = GetEventGenerator();
   const gfx::Point divider_center_pointer =
@@ -1450,7 +1451,7 @@
 
 // Verify the left and right windows get swapped when the divider is double
 // tapped. SwapWindows() contains a long code comment that shows it is worth
-// having separate tests for double clicking and double tapping the divider.
+// having separate tests for double clicking and double tapping the divider->
 TEST_F(SplitViewControllerTest, DoubleTapDivider) {
   const gfx::Rect bounds(0, 0, 400, 400);
   std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
@@ -2272,7 +2273,7 @@
   // Divider should be moved to the middle at the beginning.
   ToggleOverview();
   split_view_controller()->SnapWindow(window1.get(), SnapPosition::kPrimary);
-  ASSERT_TRUE(split_view_divider());
+  ASSERT_TRUE(split_view_divider()->divider_widget());
   EXPECT_GT(GetDividerPosition(), 0.33f * workarea_bounds.width());
   EXPECT_LE(GetDividerPosition(), 0.5f * workarea_bounds.width());
 
@@ -3266,9 +3267,9 @@
   tablet_mode_controller->SetEnabledForTest(true);
   EXPECT_TRUE(display::Screen::GetScreen()->InTabletMode());
   EXPECT_TRUE(split_view_controller()->InTabletSplitViewMode());
-  EXPECT_TRUE(split_view_divider());
+  EXPECT_TRUE(split_view_divider()->divider_widget());
 
-  // The left and right windows are observed by split view divider.
+  // The left and right windows are observed by split view divider->
   aura::Window::Windows observed_windows =
       split_view_divider()->observed_windows();
   EXPECT_TRUE(base::Contains(observed_windows, left_window.get()));
@@ -3593,7 +3594,7 @@
   EXPECT_NEAR(work_area_bounds.width() * 0.67f, window2->bounds().width(),
               kSplitviewDividerShortSideLength);
   EXPECT_TRUE(overview_controller->InOverviewSession());
-  EXPECT_TRUE(split_view_divider());
+  EXPECT_TRUE(split_view_divider()->divider_widget());
 }
 
 // Tests that auto-snap for partial windows works correctly.
@@ -3652,7 +3653,7 @@
 
   EXPECT_EQ(controller->state(), SplitViewController::State::kBothSnapped);
   SplitViewDivider* divider = split_view_divider();
-  ASSERT_TRUE(divider);
+  ASSERT_TRUE(divider->divider_widget());
   aura::Window* divider_widget_native_window =
       divider->divider_widget()->GetNativeWindow();
   EXPECT_TRUE(
@@ -3682,10 +3683,8 @@
   split_view_controller()->SnapWindow(w2.get(), SnapPosition::kSecondary);
   EXPECT_EQ(controller->state(), SplitViewController::State::kBothSnapped);
   SplitViewDivider* divider = split_view_divider();
-  ASSERT_TRUE(divider);
-  aura::Window* divider_widget_native_window =
-      divider->divider_widget()->GetNativeWindow();
-  EXPECT_TRUE(divider_widget_native_window->IsVisible());
+  ASSERT_TRUE(divider->divider_widget());
+  EXPECT_TRUE(divider->divider_widget()->GetNativeWindow()->IsVisible());
 
   // Tests that the divider stays visible on `w1` minimized and restore.
   // To simulate the actual CUJ when user minimizes a window i.e. the minimized
@@ -3695,10 +3694,12 @@
   WMEvent w1_minimize(WM_EVENT_MINIMIZE);
   WindowState::Get(w1.get())->OnWMEvent(&w1_minimize);
   EXPECT_FALSE(w1->IsVisible());
-  EXPECT_TRUE(divider_widget_native_window->IsVisible());
+  EXPECT_TRUE(divider->divider_widget()->GetNativeWindow()->IsVisible());
+
+  // Restoring the window will refresh the widget but keep it visible.
   WMEvent w1_restore(WM_EVENT_RESTORE);
   WindowState::Get(w1.get())->OnWMEvent(&w1_restore);
-  EXPECT_TRUE(divider_widget_native_window->IsVisible());
+  EXPECT_TRUE(divider->divider_widget()->GetNativeWindow()->IsVisible());
 }
 
 // Tests that windows with different containers can be snapped properly with no
@@ -3715,7 +3716,7 @@
   EXPECT_EQ(controller->state(), SplitViewController::State::kBothSnapped);
 
   SplitViewDivider* divider = split_view_divider();
-  ASSERT_TRUE(divider);
+  ASSERT_TRUE(divider->divider_widget());
   aura::Window* divider_widget_native_window =
       divider->divider_widget()->GetNativeWindow();
   EXPECT_EQ(divider_widget_native_window->parent(),
diff --git a/ash/wm/splitview/split_view_divider.cc b/ash/wm/splitview/split_view_divider.cc
index ddb4f75..6ce80c9 100644
--- a/ash/wm/splitview/split_view_divider.cc
+++ b/ash/wm/splitview/split_view_divider.cc
@@ -70,37 +70,10 @@
 
 }  // namespace
 
-SplitViewDivider::SplitViewDivider(LayoutDividerController* controller,
-                                   int divider_position)
-    : controller_(controller), divider_position_(divider_position) {
-  // Observe currently snapped windows.
-  for (aura::Window* window : controller_->GetLayoutWindows()) {
-    AddObservedWindow(window);
-  }
+SplitViewDivider::SplitViewDivider(LayoutDividerController* controller)
+    : controller_(controller) {}
 
-  CHECK_GE(observed_windows_.size(), 1u);
-
-  // Create the divider widget after adding observed windows which the parent
-  // container of the divider will depend on.
-  CreateDividerWidget(divider_position);
-}
-
-SplitViewDivider::~SplitViewDivider() {
-  auto* divider_window = divider_widget_->GetNativeWindow();
-  if (auto* transient_parent = wm::GetTransientParent(divider_window)) {
-    wm::RemoveTransientChild(transient_parent, divider_window);
-  }
-
-  divider_widget_->Close();
-
-  for (aura::Window* window : observed_windows_) {
-    window->RemoveObserver(this);
-    wm::TransientWindowManager::GetOrCreate(window)->RemoveObserver(this);
-  }
-
-  dragged_window_ = nullptr;
-  observed_windows_.clear();
-}
+SplitViewDivider::~SplitViewDivider() = default;
 
 // static
 gfx::Rect SplitViewDivider::GetDividerBoundsInScreen(
@@ -140,6 +113,41 @@
   return divider_widget_->GetNativeWindow()->GetRootWindow();
 }
 
+bool SplitViewDivider::HasDividerWidget() const {
+  return !!divider_widget_;
+}
+
+void SplitViewDivider::ShowFor(int divider_position) {
+  divider_position_ = divider_position;
+  CloseDividerWidget();
+
+  // Order here matters: we first refresh the observed windows, since the widget
+  // will be added to the topmost of `observed_windows_`. Then after the widget
+  // is created, we refresh the stacking order of all the windows.
+  for (aura::Window* window : controller_->GetLayoutWindows()) {
+    AddObservedWindow(window);
+  }
+  CreateDividerWidget(divider_position);
+  RefreshStackingOrder();
+}
+
+void SplitViewDivider::CloseDividerWidget() {
+  for (aura::Window* window : observed_windows_) {
+    window->RemoveObserver(this);
+    wm::TransientWindowManager::GetOrCreate(window)->RemoveObserver(this);
+  }
+  observed_windows_.clear();
+
+  divider_view_ = nullptr;
+  dragged_window_ = nullptr;
+
+  if (divider_widget_) {
+    auto* widget_ptr = divider_widget_.get();
+    divider_widget_ = nullptr;
+    widget_ptr->CloseNow();
+  }
+}
+
 void SplitViewDivider::UpdateDividerPosition(
     const gfx::Point& location_in_screen) {
   if (IsLayoutHorizontal(GetRootWindow())) {
@@ -242,12 +250,9 @@
 gfx::Rect SplitViewDivider::GetDividerBoundsInScreen(bool is_dragging) {
   const gfx::Rect work_area_bounds_in_screen =
       GetWorkAreaBoundsInScreen(divider_widget_->GetNativeWindow());
-  // TODO(b/308819668): Move `divider_position_` to here.
-  const int divider_position =
-      SplitViewController::Get(GetRootWindow())->GetDividerPosition();
   const bool landscape = IsCurrentScreenOrientationLandscape();
   return GetDividerBoundsInScreen(work_area_bounds_in_screen, landscape,
-                                  divider_position, is_dragging);
+                                  divider_position_, is_dragging);
 }
 
 void SplitViewDivider::SetAdjustable(bool adjustable) {
@@ -270,7 +275,10 @@
 }
 
 void SplitViewDivider::AddObservedWindow(aura::Window* window) {
-  CHECK(!base::Contains(observed_windows_, window));
+  // TODO(b/322890782): Change this back to a CHECK and add `window` directly.
+  if (base::Contains(observed_windows_, window)) {
+    return;
+  }
   window->AddObserver(this);
   observed_windows_.push_back(window);
   wm::TransientWindowManager* transient_manager =
@@ -280,7 +288,7 @@
        transient_manager->transient_children()) {
     StartObservingTransientChild(transient_window);
   }
-  RefreshStackingOrder();
+  // Don't refresh here, since we may not have created the divider widget yet.
 }
 
 void SplitViewDivider::RemoveObservedWindow(aura::Window* window) {
@@ -385,7 +393,7 @@
 }
 
 void SplitViewDivider::CreateDividerWidget(int divider_position) {
-  CHECK(!divider_widget_);
+  CHECK_GE(observed_windows_.size(), 1u);
   // Native widget owns this widget.
   divider_widget_ = new views::Widget;
   divider_widget_->set_focus_on_creation(false);
diff --git a/ash/wm/splitview/split_view_divider.h b/ash/wm/splitview/split_view_divider.h
index 1fa74a49..f0d4700d 100644
--- a/ash/wm/splitview/split_view_divider.h
+++ b/ash/wm/splitview/split_view_divider.h
@@ -10,6 +10,7 @@
 #include "base/scoped_multi_source_observation.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
+#include "ui/views/widget/widget_observer.h"
 #include "ui/wm/core/transient_window_observer.h"
 
 namespace gfx {
@@ -41,7 +42,7 @@
     kFast,
   };
 
-  SplitViewDivider(LayoutDividerController* controller, int divider_position);
+  explicit SplitViewDivider(LayoutDividerController* controller);
   SplitViewDivider(const SplitViewDivider&) = delete;
   SplitViewDivider& operator=(const SplitViewDivider&) = delete;
   ~SplitViewDivider() override;
@@ -68,6 +69,15 @@
     is_resizing_with_divider_ = is_resizing_with_divider;
   }
 
+  // Returns true if the divider widget is created.
+  bool HasDividerWidget() const;
+
+  // Shows the divider widget with the origin at `divider_position`.
+  void ShowFor(int divider_position);
+
+  // Closes the divider widget.
+  void CloseDividerWidget();
+
   // Updates `divider_position_` according to the current event location on the
   // divider widget during resizing.
   void UpdateDividerPosition(const gfx::Point& location_in_screen);
@@ -97,6 +107,7 @@
   // Returns true if the divider bar is adjustable.
   bool IsAdjustable() const;
 
+  // TODO(b/322890782): Hide these two APIs.
   void AddObservedWindow(aura::Window* window);
   void RemoveObservedWindow(aura::Window* window);
 
diff --git a/ash/wm/splitview/split_view_utils.cc b/ash/wm/splitview/split_view_utils.cc
index 7c6b913..4ced33dd 100644
--- a/ash/wm/splitview/split_view_utils.cc
+++ b/ash/wm/splitview/split_view_utils.cc
@@ -4,6 +4,8 @@
 
 #include "ash/wm/splitview/split_view_utils.h"
 
+#include <vector>
+
 #include "ash/accessibility/accessibility_controller.h"
 #include "ash/constants/ash_pref_names.h"
 #include "ash/constants/notifier_catalogs.h"
@@ -20,6 +22,7 @@
 #include "ash/wm/overview/overview_utils.h"
 #include "ash/wm/screen_pinning_controller.h"
 #include "ash/wm/snap_group/snap_group_controller.h"
+#include "ash/wm/splitview/layout_divider_controller.h"
 #include "ash/wm/splitview/split_view_constants.h"
 #include "ash/wm/splitview/split_view_types.h"
 #include "ash/wm/window_positioning_utils.h"
@@ -38,9 +41,12 @@
 #include "ui/compositor/layer_animator.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/display/screen.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
 #include "ui/views/widget/widget_delegate.h"
 #include "ui/wm/core/transient_window_manager.h"
+#include "ui/wm/core/window_util.h"
 
 namespace ash {
 
@@ -209,35 +215,54 @@
                             : ".ClamshellMode");
 }
 
-// Returns true if there is another window snapped to the opposite side of
-// `window` and we can't start partial overview.
+// Returns true if there is another fully visible (not occluded) window snapped
+// on the opposite side of `window` and we can't start partial overview in this
+// case.
 bool IsAnotherWindowSnappedOppositeOf(aura::Window* window) {
   const auto windows =
       Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk);
-  const auto snap_type = WindowState::Get(window)->GetStateType();
   const auto opposite_snap_type = GetOppositeSnapType(window);
-  for (aura::Window* top_window : base::Reversed(windows)) {
-    if (top_window == window) {
-      // Skip `window` itself.
+
+  // Track the union bounds of the windows that are more recently used than the
+  // currently iterated window, i.e. `top_window` below to check the occlusion
+  // state of the opposite snapped window.
+  gfx::Rect union_bounds;
+  for (aura::Window* top_window : windows) {
+    const auto* top_window_state = WindowState::Get(top_window);
+    // The `top_window` should be excluded for occlusion check under the
+    // following conditions:
+    // 1. When it is the `window` itself;
+    // 2. When it is not visible or minimized;
+    // 3. When it is the transient child of the `window`, for example the window
+    // layout menu or other bubble widget;
+    // 4. When it is a float or pip window.
+    const bool should_be_excluded_for_occlusion_check =
+        top_window == window || wm::GetTransientRoot(top_window) == window ||
+        !top_window->IsVisible() || top_window_state->IsMinimized() ||
+        top_window_state->IsFloated() || top_window_state->IsPip();
+
+    if (should_be_excluded_for_occlusion_check) {
       continue;
     }
-    auto* top_window_state = WindowState::Get(top_window);
-    if (top_window_state->IsFloated()) {
-      // Skip any floated windows that are on top of the snapped windows.
-      continue;
+
+    const gfx::Rect top_window_bounds = top_window->GetBoundsInScreen();
+    if (top_window_state->GetStateType() == opposite_snap_type) {
+      // Ensure that `top_window` is fully visible by checking:
+      // 1. There is no window stacked above `top_window` with bounds
+      // confined or confining `top_window`. Note that if `union_bounds` is
+      // empty, `top_window` will be the topmost window snapped on the
+      // opposite position;
+      // 2. There is no window with bounds that intersect with `top_window`.
+      // See http://b/320759574#comment3 for more details with graphs.
+      if (!top_window_bounds.Intersects(union_bounds) &&
+          !union_bounds.Intersects(top_window_bounds)) {
+        return true;
+      }
     }
-    if (!top_window_state->IsSnapped()) {
-      // Otherwise if `top_window` is not snapped, return false.
-      return false;
-    }
-    if (top_window_state->GetStateType() == snap_type) {
-      // Skip any windows that are snapped to the *same* side as `window`.
-      continue;
-    }
-    // Else `top_window` is snapped to the opposite side of `window`.
-    CHECK_EQ(top_window_state->GetStateType(), opposite_snap_type);
-    return true;
+
+    union_bounds.Union(top_window_bounds);
   }
+
   return false;
 }
 
diff --git a/ash/wm/window_restore/window_restore_controller.cc b/ash/wm/window_restore/window_restore_controller.cc
index d4825ed..cafa2ba 100644
--- a/ash/wm/window_restore/window_restore_controller.cc
+++ b/ash/wm/window_restore/window_restore_controller.cc
@@ -336,6 +336,10 @@
     return;
   }
 
+  if (!window->GetProperty(app_restore::kLaunchedFromAppRestoreKey)) {
+    return;
+  }
+
   // Windows with restore window key less than -1 are launched from desk
   // templates or saved desks; we want to stay in overview for these. Windows
   // with restore window key more than -1 are launched from full restore and we
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc
index e840859..a2a6bcfa 100644
--- a/ash/wm/window_state.cc
+++ b/ash/wm/window_state.cc
@@ -28,6 +28,7 @@
 #include "ash/wm/snap_group/snap_group_controller.h"
 #include "ash/wm/splitview/split_view_constants.h"
 #include "ash/wm/splitview/split_view_controller.h"
+#include "ash/wm/splitview/split_view_divider.h"
 #include "ash/wm/splitview/split_view_utils.h"
 #include "ash/wm/window_animations.h"
 #include "ash/wm/window_positioning_utils.h"
@@ -216,7 +217,7 @@
   SplitViewController* split_view_controller =
       SplitViewController::Get(window->GetRootWindow());
   return split_view_controller->InSplitViewMode() &&
-         split_view_controller->split_view_divider();
+         split_view_controller->split_view_divider()->divider_widget();
 }
 
 float GetCurrentSnapRatio(aura::Window* window,
diff --git a/base/metrics/persistent_memory_allocator.cc b/base/metrics/persistent_memory_allocator.cc
index 2a48a96..b50da308 100644
--- a/base/metrics/persistent_memory_allocator.cc
+++ b/base/metrics/persistent_memory_allocator.cc
@@ -400,8 +400,14 @@
     shared_meta()->page_size = mem_page_;
     shared_meta()->version = kGlobalVersion;
     shared_meta()->id = id;
-    shared_meta()->freeptr.store(sizeof(SharedMetadata),
-                                 std::memory_order_release);
+    // Don't overwrite `freeptr` if it is set since we could have raced with
+    // another allocator. In such a case, `freeptr` would get "rewinded", and
+    // new objects would be allocated on top of already allocated objects.
+    uint32_t empty_freeptr = 0;
+    shared_meta()->freeptr.compare_exchange_strong(
+        /*expected=*/empty_freeptr, /*desired=*/sizeof(SharedMetadata),
+        /*success=*/std::memory_order_release,
+        /*failure=*/std::memory_order_relaxed);
 
     // Set up the queue of iterable allocations.
     shared_meta()->queue.size = sizeof(BlockHeader);
diff --git a/base/win/shortcut.cc b/base/win/shortcut.cc
index c8dd648b..5500017 100644
--- a/base/win/shortcut.cc
+++ b/base/win/shortcut.cc
@@ -204,7 +204,7 @@
     return false;
 
   SHChangeNotify(shortcut_existed ? SHCNE_UPDATEITEM : SHCNE_CREATE,
-                 SHCNF_PATH | SHCNF_FLUSHNOWAIT, shortcut_path.value().c_str(),
+                 SHCNF_PATH | SHCNF_FLUSH, shortcut_path.value().c_str(),
                  nullptr);
 
   return true;
diff --git a/build/config/siso/PRESUBMIT.py b/build/config/siso/PRESUBMIT.py
index 2483b80e..d574d28 100644
--- a/build/config/siso/PRESUBMIT.py
+++ b/build/config/siso/PRESUBMIT.py
@@ -21,6 +21,5 @@
       "Cq-Include-Trybots: luci.chromium.try:linux_chromium_asan_siso_rel_ng\n"
       "Cq-Include-Trybots: luci.chromium.try:linux_chromium_compile_siso_dbg_ng\n"
       "Cq-Include-Trybots: luci.chromium.try:mac-siso-rel\n"
-      "Cq-Include-Trybots: luci.chromium.try:win_chromium_compile_siso_dbg_ng\n"
   )
   return [output_api.PresubmitPromptWarning(message)]
diff --git a/cc/layers/effect_tree_layer_list_iterator.h b/cc/layers/effect_tree_layer_list_iterator.h
index 3bd7d0c..d830f7e 100644
--- a/cc/layers/effect_tree_layer_list_iterator.h
+++ b/cc/layers/effect_tree_layer_list_iterator.h
@@ -5,7 +5,7 @@
 #ifndef CC_LAYERS_EFFECT_TREE_LAYER_LIST_ITERATOR_H_
 #define CC_LAYERS_EFFECT_TREE_LAYER_LIST_ITERATOR_H_
 
-#include "base/memory/raw_ptr.h"
+#include "base/memory/raw_ptr_exclusion.h"
 #include "base/notreached.h"
 #include "cc/cc_export.h"
 #include "cc/trees/effect_node.h"
@@ -75,9 +75,11 @@
 
   struct Position {
     State state = State::kEnd;
-    raw_ptr<LayerImpl> current_layer = nullptr;
-    raw_ptr<RenderSurfaceImpl> current_render_surface = nullptr;
-    raw_ptr<RenderSurfaceImpl> target_render_surface = nullptr;
+    // RAW_PTR_EXCLUSION: Renderer performance: visible in sampling profiler
+    // stacks.
+    RAW_PTR_EXCLUSION LayerImpl* current_layer = nullptr;
+    RAW_PTR_EXCLUSION RenderSurfaceImpl* current_render_surface = nullptr;
+    RAW_PTR_EXCLUSION RenderSurfaceImpl* target_render_surface = nullptr;
   };
 
   operator const Position() const {
@@ -119,8 +121,10 @@
   // render surface.
   int lowest_common_effect_tree_ancestor_index_;
 
-  raw_ptr<LayerTreeImpl> layer_tree_impl_;
-  raw_ptr<EffectTree> effect_tree_;
+  // RAW_PTR_EXCLUSION: Renderer performance: visible in sampling profiler
+  // stacks.
+  RAW_PTR_EXCLUSION LayerTreeImpl* layer_tree_impl_;
+  RAW_PTR_EXCLUSION EffectTree* effect_tree_;
 };
 
 }  // namespace cc
diff --git a/cc/layers/heads_up_display_layer_impl.h b/cc/layers/heads_up_display_layer_impl.h
index a53b593..115ae194 100644
--- a/cc/layers/heads_up_display_layer_impl.h
+++ b/cc/layers/heads_up_display_layer_impl.h
@@ -10,7 +10,7 @@
 #include <vector>
 
 #include "base/memory/ptr_util.h"
-#include "base/memory/raw_ptr.h"
+#include "base/memory/raw_ptr_exclusion.h"
 #include "base/time/time.h"
 #include "cc/cc_export.h"
 #include "cc/layers/layer_impl.h"
@@ -179,7 +179,10 @@
   // HUD's contents. The actual quad can't be created until UpdateHudTexture()
   // which happens during draw, so we hold this reference to it when
   // constructing the placeholder between these two steps in the draw process.
-  raw_ptr<viz::DrawQuad> placeholder_quad_ = nullptr;
+  //
+  // RAW_PTR_EXCLUSION: Renderer performance: visible in sampling profiler
+  // stacks.
+  RAW_PTR_EXCLUSION viz::DrawQuad* placeholder_quad_ = nullptr;
   // Used for software raster when it will be uploaded to a texture.
   sk_sp<SkSurface> staging_surface_;
 
diff --git a/cc/layers/layer_collections.h b/cc/layers/layer_collections.h
index 03e1fd0..4bd396a 100644
--- a/cc/layers/layer_collections.h
+++ b/cc/layers/layer_collections.h
@@ -9,7 +9,7 @@
 #include <unordered_map>
 #include <vector>
 
-#include "base/memory/raw_ptr.h"
+#include "base/memory/raw_ptr_exclusion.h"
 #include "base/memory/ref_counted.h"
 #include "cc/cc_export.h"
 
@@ -20,9 +20,9 @@
 
 using LayerList = std::vector<scoped_refptr<Layer>>;
 using OwnedLayerImplList = std::vector<std::unique_ptr<LayerImpl>>;
-using LayerImplList = std::vector<raw_ptr<LayerImpl, VectorExperimental>>;
-using RenderSurfaceList =
-    std::vector<raw_ptr<RenderSurfaceImpl, VectorExperimental>>;
+// RAW_PTR_EXCLUSION: Renderer performance: visible in sampling profiler stacks.
+using LayerImplList = RAW_PTR_EXCLUSION std::vector<LayerImpl*>;
+using RenderSurfaceList = RAW_PTR_EXCLUSION std::vector<RenderSurfaceImpl*>;
 using OwnedLayerImplMap = std::unordered_map<int, std::unique_ptr<LayerImpl>>;
 using LayerImplMap = std::unordered_map<int, LayerImpl*>;
 
diff --git a/cc/metrics/compositor_frame_reporter.h b/cc/metrics/compositor_frame_reporter.h
index a1783b6..334b059 100644
--- a/cc/metrics/compositor_frame_reporter.h
+++ b/cc/metrics/compositor_frame_reporter.h
@@ -15,6 +15,7 @@
 
 #include <optional>
 #include "base/memory/raw_ptr.h"
+#include "base/memory/raw_ptr_exclusion.h"
 #include "base/rand_util.h"
 #include "base/time/default_tick_clock.h"
 #include "base/time/time.h"
@@ -41,15 +42,19 @@
 class LatencyUkmReporter;
 
 struct GlobalMetricsTrackers {
-  raw_ptr<DroppedFrameCounter> dropped_frame_counter = nullptr;
-  raw_ptr<LatencyUkmReporter> latency_ukm_reporter = nullptr;
-  raw_ptr<FrameSequenceTrackerCollection> frame_sequence_trackers = nullptr;
-  raw_ptr<EventLatencyTracker, DanglingUntriaged> event_latency_tracker =
+  // RAW_PTR_EXCLUSION: Renderer performance: visible in sampling profiler
+  // stacks.
+  RAW_PTR_EXCLUSION DroppedFrameCounter* dropped_frame_counter = nullptr;
+  RAW_PTR_EXCLUSION LatencyUkmReporter* latency_ukm_reporter = nullptr;
+  RAW_PTR_EXCLUSION FrameSequenceTrackerCollection* frame_sequence_trackers =
       nullptr;
-  raw_ptr<PredictorJankTracker> predictor_jank_tracker = nullptr;
-  raw_ptr<ScrollJankDroppedFrameTracker> scroll_jank_dropped_frame_tracker =
-      nullptr;
-  raw_ptr<ScrollJankUkmReporter> scroll_jank_ukm_reporter = nullptr;
+  // TODO(crbug.com/1489080): This member was marked `DanglingUntriaged`
+  // before being unrewritten.
+  RAW_PTR_EXCLUSION EventLatencyTracker* event_latency_tracker = nullptr;
+  RAW_PTR_EXCLUSION PredictorJankTracker* predictor_jank_tracker = nullptr;
+  RAW_PTR_EXCLUSION ScrollJankDroppedFrameTracker*
+      scroll_jank_dropped_frame_tracker = nullptr;
+  RAW_PTR_EXCLUSION ScrollJankUkmReporter* scroll_jank_ukm_reporter = nullptr;
 };
 
 // This is used for tracing and reporting the duration of pipeline stages within
@@ -192,7 +197,9 @@
       base::TimeDelta GetLatency() const;
 
      private:
-      raw_ptr<const ProcessedBlinkBreakdown> owner_;
+      // RAW_PTR_EXCLUSION: Renderer performance: visible in sampling profiler
+      // stacks.
+      RAW_PTR_EXCLUSION const ProcessedBlinkBreakdown* owner_;
 
       size_t index_ = 0;
     };
@@ -233,7 +240,9 @@
       bool HasValue() const;
       void SkipBreakdownsIfNecessary();
 
-      raw_ptr<const ProcessedVizBreakdown> owner_;
+      // RAW_PTR_EXCLUSION: Renderer performance: visible in sampling profiler
+      // stacks.
+      RAW_PTR_EXCLUSION const ProcessedVizBreakdown* owner_;
       const bool skip_swap_start_to_swap_end_;
 
       size_t index_ = 0;
diff --git a/cc/tiles/picture_layer_tiling_set.h b/cc/tiles/picture_layer_tiling_set.h
index c4bf11b..35bbc914 100644
--- a/cc/tiles/picture_layer_tiling_set.h
+++ b/cc/tiles/picture_layer_tiling_set.h
@@ -180,7 +180,9 @@
    private:
     size_t NextTiling() const;
 
-    raw_ptr<const PictureLayerTilingSet> set_;
+    // RAW_PTR_EXCLUSION: Renderer performance: visible in sampling profiler
+    // stacks.
+    RAW_PTR_EXCLUSION const PictureLayerTilingSet* set_;
     float coverage_scale_;
     PictureLayerTiling::CoverageIterator tiling_iter_;
     size_t current_tiling_;
diff --git a/cc/tiles/prioritized_tile.h b/cc/tiles/prioritized_tile.h
index acbe452..fc1dcc3 100644
--- a/cc/tiles/prioritized_tile.h
+++ b/cc/tiles/prioritized_tile.h
@@ -5,7 +5,7 @@
 #ifndef CC_TILES_PRIORITIZED_TILE_H_
 #define CC_TILES_PRIORITIZED_TILE_H_
 
-#include "base/memory/raw_ptr.h"
+#include "base/memory/raw_ptr_exclusion.h"
 #include "cc/cc_export.h"
 #include "cc/paint/paint_worklet_input.h"
 #include "cc/raster/raster_source.h"
@@ -51,8 +51,13 @@
   const PictureLayerTiling* source_tiling() const { return source_tiling_; }
 
  private:
-  raw_ptr<Tile, DanglingUntriaged> tile_ = nullptr;
-  raw_ptr<const PictureLayerTiling, DanglingUntriaged> source_tiling_ = nullptr;
+  // RAW_PTR_EXCLUSION: Renderer performance: visible in sampling profiler
+  // stacks.
+  //
+  // TODO(crbug.com/1489080): These members were marked `DanglingUntriaged`
+  // before being unrewritten.
+  RAW_PTR_EXCLUSION Tile* tile_ = nullptr;
+  RAW_PTR_EXCLUSION const PictureLayerTiling* source_tiling_ = nullptr;
   TilePriority priority_;
   bool is_occluded_ = false;
   bool is_process_for_images_only_ = false;
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc
index 7b5faea..e5b66e2 100644
--- a/cc/trees/draw_property_utils.cc
+++ b/cc/trees/draw_property_utils.cc
@@ -1444,9 +1444,8 @@
   }
 }
 
-void FindLayersThatNeedUpdates(
-    LayerTreeImpl* layer_tree_impl,
-    std::vector<raw_ptr<LayerImpl, VectorExperimental>>* visible_layer_list) {
+void FindLayersThatNeedUpdates(LayerTreeImpl* layer_tree_impl,
+                               std::vector<LayerImpl*>* visible_layer_list) {
   const PropertyTrees* property_trees = layer_tree_impl->property_trees();
   const EffectTree& effect_tree = property_trees->effect_tree();
 
diff --git a/cc/trees/draw_property_utils.h b/cc/trees/draw_property_utils.h
index a3b6dbb1..f710c51 100644
--- a/cc/trees/draw_property_utils.h
+++ b/cc/trees/draw_property_utils.h
@@ -50,9 +50,9 @@
 void CC_EXPORT FindLayersThatNeedUpdates(LayerTreeHost* layer_tree_host,
                                          LayerList* update_layer_list);
 
-void CC_EXPORT FindLayersThatNeedUpdates(
-    LayerTreeImpl* layer_tree_impl,
-    std::vector<raw_ptr<LayerImpl, VectorExperimental>>* visible_layer_list);
+void CC_EXPORT
+FindLayersThatNeedUpdates(LayerTreeImpl* layer_tree_impl,
+                          std::vector<LayerImpl*>* visible_layer_list);
 
 gfx::Transform CC_EXPORT DrawTransform(const LayerImpl* layer,
                                        const TransformTree& transform_tree,
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 2723386..64ac5a8 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -2594,7 +2594,7 @@
   // TODO(boliu): If we did a temporary software renderer frame, propogate the
   // damage forward to the next frame.
   for (size_t i = 0; i < frame->render_surface_list->size(); i++) {
-    auto* surface = (*frame->render_surface_list)[i].get();
+    auto* surface = (*frame->render_surface_list)[i];
     surface->damage_tracker()->DidDrawDamagedArea();
   }
   active_tree_->ResetAllChangeTracking();
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 9da3214..950c04ff 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -20,6 +20,8 @@
 #include "base/containers/lru_cache.h"
 #include "base/functional/callback.h"
 #include "base/memory/memory_pressure_listener.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/raw_ptr_exclusion.h"
 #include "base/memory/shared_memory_mapping.h"
 #include "base/rand_util.h"
 #include "base/task/sequenced_task_runner.h"
@@ -218,7 +220,9 @@
     std::optional<uint32_t> deadline_in_frames;
     bool use_default_lower_bound_deadline = false;
     viz::CompositorRenderPassList render_passes;
-    raw_ptr<const RenderSurfaceList> render_surface_list = nullptr;
+    // RAW_PTR_EXCLUSION: Renderer performance: visible in sampling profiler
+    // stacks.
+    RAW_PTR_EXCLUSION const RenderSurfaceList* render_surface_list = nullptr;
     LayerImplList will_draw_layers;
     bool has_no_damage = false;
     bool may_contain_video = false;
diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h
index b9f1fa4..4eeed0f46 100644
--- a/cc/trees/property_tree.h
+++ b/cc/trees/property_tree.h
@@ -18,7 +18,7 @@
 #include "base/containers/flat_map.h"
 #include "base/containers/flat_set.h"
 #include "base/functional/callback.h"
-#include "base/memory/raw_ptr.h"
+#include "base/memory/raw_ptr_exclusion.h"
 #include "base/memory/raw_ref.h"
 #include "base/memory/weak_ptr.h"
 #include "cc/base/synced_property.h"
@@ -139,7 +139,9 @@
   }
 
   bool needs_update_;
-  raw_ptr<PropertyTrees> property_trees_;
+  // RAW_PTR_EXCLUSION: Renderer performance: visible in sampling profiler
+  // stacks.
+  RAW_PTR_EXCLUSION PropertyTrees* property_trees_;
   // This map allow mapping directly from a compositor element id to the
   // respective property node. This will eventually allow simplifying logic in
   // various places that today has to map from element id to layer id, and then
diff --git a/chrome/VERSION b/chrome/VERSION
index d8a721a..d201303e 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=123
 MINOR=0
-BUILD=6284
+BUILD=6285
 PATCH=0
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index 2ed7591..cff5daf5 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -502,6 +502,7 @@
       "//third_party/androidx:androidx_window_sidecar_sidecar_java",
       "//third_party/androidx:androidx_window_window_java_java",
       "//third_party/android_deps:org_jetbrains_kotlinx_atomicfu_jvm_java",
+      "//third_party/android_deps:org_jetbrains_kotlin_kotlin_parcelize_runtime",
     ]
     if (defined(invoker.assert_no_deps)) {
       assert_no_deps += invoker.assert_no_deps
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java
index 89605dd..b009d7b32 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java
@@ -60,6 +60,7 @@
 import org.chromium.base.test.util.ApplicationTestUtils;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.DoNotBatch;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Features.DisableFeatures;
@@ -193,6 +194,7 @@
     @Test
     @LargeTest
     @Feature({"RenderTest"})
+    @DisabledTest(message = "http://b/issues/41491395")
     public void testRenderDifferentSignedInStates() throws IOException {
         launchSettingsActivity();
         waitForOptionsMenu();
@@ -488,6 +490,7 @@
 
     @Test
     @SmallTest
+    @DisabledTest(message = "http://b/issues/41491395")
     public void testAccountSignIn() throws InterruptedException {
         launchSettingsActivity();
 
diff --git a/chrome/app/os_settings_search_tag_strings.grdp b/chrome/app/os_settings_search_tag_strings.grdp
index 4f9dfdc9..67525da 100644
--- a/chrome/app/os_settings_search_tag_strings.grdp
+++ b/chrome/app/os_settings_search_tag_strings.grdp
@@ -1577,4 +1577,21 @@
   <message name="IDS_OS_SETTINGS_TAG_RESTORE_APPS_AND_PAGES" desc="Text for search result item which, when clicked, navigates the user to On Startup settings, with a radio group to configure the restore apps and pages options">
     Restore apps and pages
   </message>
+
+  <!-- Multitasking section. -->
+  <message name="IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW" desc="Text for search result item which, when clicked, navigates the user to Multitasking settings, with a toggle to enable/disable snap window suggestions. Alternate phrase for 'Split screen set up', 'Dock window', 'Snap window', 'Split screen overview'">
+    Split screen window suggestion
+  </message>
+  <message name="IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW_ALT1" desc="Text for search result item which, when clicked, navigates the user to Multitasking settings, with a toggle to enable/disable snap window suggestions. Alternate phrase for 'Split screen window suggestion', 'Dock window', 'Snap window', 'Split screen overview'">
+    Split screen set up
+  </message>
+  <message name="IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW_ALT2" desc="Text for search result item which, when clicked, navigates the user to Multitasking settings, with a toggle to enable/disable snap window suggestions. Alternate phrase for 'Split screen window suggestion', 'Split screen set up', 'Snap window', 'Split screen overview'">
+    Dock window
+  </message>
+  <message name="IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW_ALT3" desc="Text for search result item which, when clicked, navigates the user to Multitasking settings, with a toggle to enable/disable snap window suggestions. Alternate phrase for 'Split screen window suggestion', 'Split screen set up', 'Dock window', 'Split screen overview'">
+    Snap window
+  </message>
+  <message name="IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW_ALT4" desc="Text for search result item which, when clicked, navigates the user to Multitasking settings, with a toggle to enable/disable snap window suggestions. Alternate phrase for 'Split screen window suggestion', 'Split screen set up', 'Dock window', 'Snap window'">
+    Split screen overview
+  </message>
 </grit-part>
diff --git a/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW.png.sha1 b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW.png.sha1
new file mode 100644
index 0000000..e9aad33
--- /dev/null
+++ b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW.png.sha1
@@ -0,0 +1 @@
+7338fb241a3d42620b3678056ecbd4251922d639
\ No newline at end of file
diff --git a/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW_ALT1.png.sha1 b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW_ALT1.png.sha1
new file mode 100644
index 0000000..207c68f
--- /dev/null
+++ b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW_ALT1.png.sha1
@@ -0,0 +1 @@
+fadcecb595670e1f24f4e9cb8d36e3d489048591
\ No newline at end of file
diff --git a/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW_ALT2.png.sha1 b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW_ALT2.png.sha1
new file mode 100644
index 0000000..f15786b
--- /dev/null
+++ b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW_ALT2.png.sha1
@@ -0,0 +1 @@
+95954ec84a2fda96ebe0139862470fb4b3723bd0
\ No newline at end of file
diff --git a/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW_ALT3.png.sha1 b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW_ALT3.png.sha1
new file mode 100644
index 0000000..380a141d
--- /dev/null
+++ b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW_ALT3.png.sha1
@@ -0,0 +1 @@
+43015018448813faa16cdbac52fbb9d74245acfd
\ No newline at end of file
diff --git a/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW_ALT4.png.sha1 b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW_ALT4.png.sha1
new file mode 100644
index 0000000..6701eac
--- /dev/null
+++ b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW_ALT4.png.sha1
@@ -0,0 +1 @@
+8c763ed287ee9efdbb0c7ba8872f34e8d3006ef2
\ No newline at end of file
diff --git a/chrome/browser/ash/file_system_provider/cloud_file_system.cc b/chrome/browser/ash/file_system_provider/cloud_file_system.cc
index a7c104b..622fcf6 100644
--- a/chrome/browser/ash/file_system_provider/cloud_file_system.cc
+++ b/chrome/browser/ash/file_system_provider/cloud_file_system.cc
@@ -13,6 +13,8 @@
 #include "base/notreached.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
+#include "base/timer/timer.h"
+#include "chrome/browser/ash/file_manager/fileapi_util.h"
 #include "chrome/browser/ash/file_system_provider/provided_file_system_interface.h"
 #include "chrome/browser/ash/file_system_provider/queue.h"
 
@@ -20,6 +22,10 @@
 
 namespace {
 
+// The frequency that the FSP syncs with the cloud when the File Manager is a
+// watcher.
+constexpr base::TimeDelta kFileManagerWatcherInterval = base::Seconds(15);
+
 std::ostream& operator<<(std::ostream& out,
                          const std::vector<base::FilePath>& entry_paths) {
   for (size_t i = 0; i < entry_paths.size(); ++i) {
@@ -232,6 +238,16 @@
           << origin.spec() << "', entry_path = '" << entry_path
           << "', recursive = '" << recursive << "', persistent = '"
           << persistent << "'}";
+
+  // Set timer if the File Manager is a watcher.
+  file_manager_watchers_ +=
+      file_manager::util::IsFileManagerURL(origin) ? 1 : 0;
+  if (file_manager_watchers_ > 0 && !timer_.IsRunning()) {
+    timer_.Start(FROM_HERE, kFileManagerWatcherInterval,
+                 base::BindRepeating(&CloudFileSystem::OnTimer,
+                                     weak_ptr_factory_.GetWeakPtr()));
+  }
+
   return file_system_->AddWatcher(origin, entry_path, recursive, persistent,
                                   std::move(callback),
                                   std::move(notification_callback));
@@ -245,6 +261,14 @@
   VLOG(2) << "RemoveWatcher {fsid = '" << GetFileSystemId() << "', origin = '"
           << origin.spec() << "', entry_path = '" << entry_path
           << "', recursive = '" << recursive << "'}";
+
+  // Stop timer if the File Manager is not a watcher.
+  file_manager_watchers_ -=
+      file_manager::util::IsFileManagerURL(origin) ? 1 : 0;
+  if (file_manager_watchers_ == 0 && timer_.IsRunning()) {
+    timer_.Stop();
+  }
+
   file_system_->RemoveWatcher(origin, entry_path, recursive,
                               std::move(callback));
 }
@@ -307,4 +331,9 @@
   return file_system_->GetFileSystemInfo().file_system_id();
 }
 
+void CloudFileSystem::OnTimer() {
+  VLOG(2) << "OnTimer";
+  // TODO(b/317137739): Sync with the cloud.
+}
+
 }  // namespace ash::file_system_provider
diff --git a/chrome/browser/ash/file_system_provider/cloud_file_system.h b/chrome/browser/ash/file_system_provider/cloud_file_system.h
index 388409c..d280ce9 100644
--- a/chrome/browser/ash/file_system_provider/cloud_file_system.h
+++ b/chrome/browser/ash/file_system_provider/cloud_file_system.h
@@ -24,6 +24,7 @@
 
 namespace base {
 class FilePath;
+class MetronomeTimer;
 }  // namespace base
 
 class GURL;
@@ -131,8 +132,11 @@
 
  private:
   const std::string GetFileSystemId() const;
+  void OnTimer();
   std::unique_ptr<ProvidedFileSystemInterface> file_system_;
   raw_ptr<ContentCache> content_cache_;  // Not owned.
+  base::MetronomeTimer timer_;
+  int file_manager_watchers_ = 0;
 
   base::WeakPtrFactory<CloudFileSystem> weak_ptr_factory_{this};
 };
diff --git a/chrome/browser/ash/file_system_provider/extension_provider.cc b/chrome/browser/ash/file_system_provider/extension_provider.cc
index 9852138..b228b53e 100644
--- a/chrome/browser/ash/file_system_provider/extension_provider.cc
+++ b/chrome/browser/ash/file_system_provider/extension_provider.cc
@@ -70,8 +70,8 @@
 std::unique_ptr<ProviderInterface> ExtensionProvider::Create(
     extensions::ExtensionRegistry* registry,
     const extensions::ExtensionId& extension_id) {
-  const extensions::Extension* const extension = registry->GetExtensionById(
-      extension_id, extensions::ExtensionRegistry::ENABLED);
+  const extensions::Extension* const extension =
+      registry->enabled_extensions().GetByID(extension_id);
   if (!extension ||
       !extension->permissions_data()->HasAPIPermission(
           extensions::mojom::APIPermissionID::kFileSystemProvider)) {
diff --git a/chrome/browser/ash/input_method/component_extension_ime_manager_delegate_impl.cc b/chrome/browser/ash/input_method/component_extension_ime_manager_delegate_impl.cc
index d14e92e..1c839a9 100644
--- a/chrome/browser/ash/input_method/component_extension_ime_manager_delegate_impl.cc
+++ b/chrome/browser/ash/input_method/component_extension_ime_manager_delegate_impl.cc
@@ -119,8 +119,7 @@
   extensions::ExtensionRegistry* extension_registry =
       extensions::ExtensionRegistry::Get(profile);
   DCHECK(extension_registry);
-  if (extension_registry->GetExtensionById(
-          extension_id, extensions::ExtensionRegistry::ENABLED)) {
+  if (extension_registry->enabled_extensions().GetByID(extension_id)) {
     VLOG(1) << "the IME extension(id=\"" << extension_id
             << "\") is already enabled";
     return;
diff --git a/chrome/browser/ash/lock_screen_apps/app_manager_impl.cc b/chrome/browser/ash/lock_screen_apps/app_manager_impl.cc
index c7dca75..5c54936 100644
--- a/chrome/browser/ash/lock_screen_apps/app_manager_impl.cc
+++ b/chrome/browser/ash/lock_screen_apps/app_manager_impl.cc
@@ -521,8 +521,8 @@
       extensions::ExtensionRegistry::Get(lock_screen_profile_);
 
   // Return the app, in case it's currently loaded.
-  const extensions::Extension* app = extension_registry->GetExtensionById(
-      lock_screen_app_id_, extensions::ExtensionRegistry::ENABLED);
+  const extensions::Extension* app =
+      extension_registry->enabled_extensions().GetByID(lock_screen_app_id_);
   if (app) {
     return app;
   }
@@ -554,8 +554,7 @@
   extension_service->AddExtension(lock_profile_app.get());
   extension_service->EnableExtension(lock_profile_app->id());
 
-  app = extension_registry->GetExtensionById(
-      lock_screen_app_id_, extensions::ExtensionRegistry::ENABLED);
+  app = extension_registry->enabled_extensions().GetByID(lock_screen_app_id_);
 
   return app;
 }
diff --git a/chrome/browser/ash/lock_screen_apps/app_manager_impl_unittest.cc b/chrome/browser/ash/lock_screen_apps/app_manager_impl_unittest.cc
index eed4ee2..230f548 100644
--- a/chrome/browser/ash/lock_screen_apps/app_manager_impl_unittest.cc
+++ b/chrome/browser/ash/lock_screen_apps/app_manager_impl_unittest.cc
@@ -514,30 +514,30 @@
 
 bool IsInstalledAndEnabled(const std::string& app_id, Profile* profile) {
   const extensions::Extension* app =
-      extensions::ExtensionRegistry::Get(profile)->GetExtensionById(
-          app_id, extensions::ExtensionRegistry::ENABLED);
+      extensions::ExtensionRegistry::Get(profile)->enabled_extensions().GetByID(
+          app_id);
   return app;
 }
 
 bool PathExists(const std::string& app_id, Profile* profile) {
   const extensions::Extension* app =
-      extensions::ExtensionRegistry::Get(profile)->GetExtensionById(
-          app_id, extensions::ExtensionRegistry::ENABLED);
+      extensions::ExtensionRegistry::Get(profile)->enabled_extensions().GetByID(
+          app_id);
   return app && base::PathExists(app->path());
 }
 
 base::FilePath GetPath(const std::string& app_id, Profile* profile) {
   const extensions::Extension* app =
-      extensions::ExtensionRegistry::Get(profile)->GetExtensionById(
-          app_id, extensions::ExtensionRegistry::ENABLED);
+      extensions::ExtensionRegistry::Get(profile)->enabled_extensions().GetByID(
+          app_id);
   return app ? app->path() : base::FilePath();
 }
 
 std::optional<std::string> GetVersion(const std::string& app_id,
                                       Profile* profile) {
   const extensions::Extension* app =
-      extensions::ExtensionRegistry::Get(profile)->GetExtensionById(
-          app_id, extensions::ExtensionRegistry::ENABLED);
+      extensions::ExtensionRegistry::Get(profile)->enabled_extensions().GetByID(
+          app_id);
   if (!app)
     return std::nullopt;
   return app->VersionString();
diff --git a/chrome/browser/ash/lock_screen_apps/lock_screen_apps.cc b/chrome/browser/ash/lock_screen_apps/lock_screen_apps.cc
index 9b684cf8..e8f11db 100644
--- a/chrome/browser/ash/lock_screen_apps/lock_screen_apps.cc
+++ b/chrome/browser/ash/lock_screen_apps/lock_screen_apps.cc
@@ -94,8 +94,8 @@
   }
 
   const extensions::Extension* chrome_app =
-      extensions::ExtensionRegistry::Get(profile)->GetExtensionById(
-          app_id, extensions::ExtensionRegistry::ENABLED);
+      extensions::ExtensionRegistry::Get(profile)->enabled_extensions().GetByID(
+          app_id);
   if (!chrome_app)
     return false;
   if (!chrome_app->permissions_data()->HasAPIPermission(
diff --git a/chrome/browser/ash/note_taking_helper.cc b/chrome/browser/ash/note_taking_helper.cc
index 8bdee2b..6f0dea6 100644
--- a/chrome/browser/ash/note_taking_helper.cc
+++ b/chrome/browser/ash/note_taking_helper.cc
@@ -165,8 +165,8 @@
   // TODO(crbug.com/1194370): Remove once Chrome Apps are gone or Lacros
   // launches, as note-taking Chrome Apps will not be supported in Lacros.
   const extensions::Extension* chrome_app =
-      extensions::ExtensionRegistry::Get(profile)->GetExtensionById(
-          app_id, extensions::ExtensionRegistry::ENABLED);
+      extensions::ExtensionRegistry::Get(profile)->enabled_extensions().GetByID(
+          app_id);
   DCHECK(chrome_app) << "app_id must be a valid app";
   name = chrome_app->name();
 
@@ -663,8 +663,8 @@
   // Chrome app.
   const extensions::ExtensionRegistry* extension_registry =
       extensions::ExtensionRegistry::Get(profile);
-  const extensions::Extension* app = extension_registry->GetExtensionById(
-      app_id, extensions::ExtensionRegistry::ENABLED);
+  const extensions::Extension* app =
+      extension_registry->enabled_extensions().GetByID(app_id);
   if (!app) {
     LOG(WARNING) << "Failed to find note-taking app " << app_id;
     return LaunchResult::CHROME_APP_MISSING;
diff --git a/chrome/browser/ash/power/renderer_freezer.cc b/chrome/browser/ash/power/renderer_freezer.cc
index f9c578eb6..4be36e8 100644
--- a/chrome/browser/ash/power/renderer_freezer.cc
+++ b/chrome/browser/ash/power/renderer_freezer.cc
@@ -82,8 +82,8 @@
       extensions::ExtensionRegistry::Get(context);
   for (const std::string& extension_id :
        extensions::ProcessMap::Get(context)->GetExtensionsInProcess(rph_id)) {
-    const extensions::Extension* extension = registry->GetExtensionById(
-        extension_id, extensions::ExtensionRegistry::ENABLED);
+    const extensions::Extension* extension =
+        registry->enabled_extensions().GetByID(extension_id);
     if (!extension || !extension->permissions_data()->HasAPIPermission(
                           extensions::mojom::APIPermissionID::kGcm)) {
       continue;
diff --git a/chrome/browser/ash/smb_client/discovery/fake_netbios_client.cc b/chrome/browser/ash/smb_client/discovery/fake_netbios_client.cc
index 014e1a9..03a06c4 100644
--- a/chrome/browser/ash/smb_client/discovery/fake_netbios_client.cc
+++ b/chrome/browser/ash/smb_client/discovery/fake_netbios_client.cc
@@ -6,8 +6,7 @@
 
 #include "net/base/ip_endpoint.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 FakeNetBiosClient::FakeNetBiosClient() = default;
 
@@ -30,5 +29,4 @@
   }
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/discovery/fake_netbios_client.h b/chrome/browser/ash/smb_client/discovery/fake_netbios_client.h
index a40fa56..23a5847 100644
--- a/chrome/browser/ash/smb_client/discovery/fake_netbios_client.h
+++ b/chrome/browser/ash/smb_client/discovery/fake_netbios_client.h
@@ -15,8 +15,7 @@
 class IPEndPoint;
 }  // namespace net
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 // FakeNetBiosClient is used for testing the NetBiosHostLocator.
 // FakeNetBiosClient is constructed with a map of IPs -> Packets to simulate
@@ -44,7 +43,6 @@
   std::map<net::IPEndPoint, std::vector<uint8_t>> fake_data_;
 };
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_DISCOVERY_FAKE_NETBIOS_CLIENT_H_
diff --git a/chrome/browser/ash/smb_client/discovery/host_locator.h b/chrome/browser/ash/smb_client/discovery/host_locator.h
index 2de79d5..8331e15 100644
--- a/chrome/browser/ash/smb_client/discovery/host_locator.h
+++ b/chrome/browser/ash/smb_client/discovery/host_locator.h
@@ -11,8 +11,7 @@
 #include "base/functional/callback.h"
 #include "net/base/ip_address.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 using Hostname = std::string;
 using Address = net::IPAddress;
@@ -40,7 +39,6 @@
   virtual void FindHosts(FindHostsCallback callback) = 0;
 };
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_DISCOVERY_HOST_LOCATOR_H_
diff --git a/chrome/browser/ash/smb_client/discovery/in_memory_host_locator.cc b/chrome/browser/ash/smb_client/discovery/in_memory_host_locator.cc
index c478eef..332b8571 100644
--- a/chrome/browser/ash/smb_client/discovery/in_memory_host_locator.cc
+++ b/chrome/browser/ash/smb_client/discovery/in_memory_host_locator.cc
@@ -7,8 +7,7 @@
 #include <map>
 #include <utility>
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 InMemoryHostLocator::InMemoryHostLocator() = default;
 InMemoryHostLocator::InMemoryHostLocator(bool should_run_synchronously)
@@ -44,5 +43,4 @@
   std::move(stored_callback_).Run(true /* success */, host_map_);
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/discovery/in_memory_host_locator.h b/chrome/browser/ash/smb_client/discovery/in_memory_host_locator.h
index 483173d..208c1763 100644
--- a/chrome/browser/ash/smb_client/discovery/in_memory_host_locator.h
+++ b/chrome/browser/ash/smb_client/discovery/in_memory_host_locator.h
@@ -7,8 +7,7 @@
 
 #include "chrome/browser/ash/smb_client/discovery/host_locator.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 // HostLocator implementation that uses a map as the source for hosts. New hosts
 // can be registered through AddHost().
@@ -43,7 +42,6 @@
   bool should_run_synchronously_ = true;
 };
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_DISCOVERY_IN_MEMORY_HOST_LOCATOR_H_
diff --git a/chrome/browser/ash/smb_client/discovery/in_memory_host_locator_unittest.cc b/chrome/browser/ash/smb_client/discovery/in_memory_host_locator_unittest.cc
index 0816f40..d912d21f 100644
--- a/chrome/browser/ash/smb_client/discovery/in_memory_host_locator_unittest.cc
+++ b/chrome/browser/ash/smb_client/discovery/in_memory_host_locator_unittest.cc
@@ -10,8 +10,7 @@
 #include "base/functional/bind.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 namespace {
 
@@ -156,5 +155,4 @@
   ExpectHostMapEqual(expected);
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/discovery/mdns_host_locator.cc b/chrome/browser/ash/smb_client/discovery/mdns_host_locator.cc
index 038d594..ea3124d 100644
--- a/chrome/browser/ash/smb_client/discovery/mdns_host_locator.cc
+++ b/chrome/browser/ash/smb_client/discovery/mdns_host_locator.cc
@@ -17,8 +17,7 @@
 #include "net/dns/public/dns_protocol.h"
 #include "net/dns/record_rdata.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 namespace {
 
@@ -350,5 +349,4 @@
   std::move(callback_).Run(success, std::move(results_));
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/discovery/mdns_host_locator.h b/chrome/browser/ash/smb_client/discovery/mdns_host_locator.h
index 2fb198c..02da606 100644
--- a/chrome/browser/ash/smb_client/discovery/mdns_host_locator.h
+++ b/chrome/browser/ash/smb_client/discovery/mdns_host_locator.h
@@ -14,8 +14,7 @@
 #include "base/task/single_thread_task_runner.h"
 #include "chrome/browser/ash/smb_client/discovery/host_locator.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 // Removes .local from |raw_hostname| if located at the end of the string and
 // returns the new hostname.
@@ -60,7 +59,6 @@
   base::WeakPtrFactory<MDnsHostLocator> weak_factory_{this};
 };
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_DISCOVERY_MDNS_HOST_LOCATOR_H_
diff --git a/chrome/browser/ash/smb_client/discovery/mdns_host_locator_unittest.cc b/chrome/browser/ash/smb_client/discovery/mdns_host_locator_unittest.cc
index 549d5c86..f3f50ae 100644
--- a/chrome/browser/ash/smb_client/discovery/mdns_host_locator_unittest.cc
+++ b/chrome/browser/ash/smb_client/discovery/mdns_host_locator_unittest.cc
@@ -5,8 +5,7 @@
 #include "chrome/browser/ash/smb_client/discovery/mdns_host_locator.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 class MDnsHostLocatorTest : public testing::Test {
  public:
@@ -28,5 +27,4 @@
   EXPECT_EQ(RemoveLocal("QNAP.LoCaL"), "QNAP");
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/discovery/netbios_client_interface.h b/chrome/browser/ash/smb_client/discovery/netbios_client_interface.h
index 859ead3..521fc26 100644
--- a/chrome/browser/ash/smb_client/discovery/netbios_client_interface.h
+++ b/chrome/browser/ash/smb_client/discovery/netbios_client_interface.h
@@ -14,8 +14,7 @@
 class IPEndPoint;
 }  // namespace net
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 using NetBiosResponseCallback = base::RepeatingCallback<
     void(const std::vector<uint8_t>&, uint16_t, const net::IPEndPoint&)>;
@@ -37,7 +36,6 @@
   NetBiosClientInterface() = default;
 };
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_DISCOVERY_NETBIOS_CLIENT_INTERFACE_H_
diff --git a/chrome/browser/ash/smb_client/discovery/netbios_host_locator.cc b/chrome/browser/ash/smb_client/discovery/netbios_host_locator.cc
index 5abb70c..0c73ad2 100644
--- a/chrome/browser/ash/smb_client/discovery/netbios_host_locator.cc
+++ b/chrome/browser/ash/smb_client/discovery/netbios_host_locator.cc
@@ -14,8 +14,7 @@
 #include "net/base/ip_endpoint.h"
 #include "net/base/network_change_notifier.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 namespace {
 
 bool IsMLan(const net::NetworkInterface& interface) {
@@ -195,5 +194,4 @@
          results_.at(hostname) != sender_ip.address();
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/discovery/netbios_host_locator.h b/chrome/browser/ash/smb_client/discovery/netbios_host_locator.h
index d688593a..c8da490 100644
--- a/chrome/browser/ash/smb_client/discovery/netbios_host_locator.h
+++ b/chrome/browser/ash/smb_client/discovery/netbios_host_locator.h
@@ -17,8 +17,7 @@
 #include "chromeos/ash/components/dbus/smbprovider/smb_provider_client.h"
 #include "net/base/network_interfaces.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 // Calculates the broadcast address of a network interface.
 net::IPAddress CalculateBroadcastAddress(
@@ -114,7 +113,6 @@
   base::WeakPtrFactory<NetBiosHostLocator> weak_ptr_factory_{this};
 };
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_DISCOVERY_NETBIOS_HOST_LOCATOR_H_
diff --git a/chrome/browser/ash/smb_client/discovery/netbios_host_locator_unittest.cc b/chrome/browser/ash/smb_client/discovery/netbios_host_locator_unittest.cc
index cc257aa..d284fbe 100644
--- a/chrome/browser/ash/smb_client/discovery/netbios_host_locator_unittest.cc
+++ b/chrome/browser/ash/smb_client/discovery/netbios_host_locator_unittest.cc
@@ -14,8 +14,7 @@
 #include "net/base/ip_endpoint.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 namespace {
 
 // Helper method to create a NetworkInterface for testing.
@@ -432,5 +431,4 @@
   task_runner_->FastForwardBy(base::Seconds(kNetBiosDiscoveryTimeoutSeconds));
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/discovery/network_scanner.cc b/chrome/browser/ash/smb_client/discovery/network_scanner.cc
index 8e7d161..24360d12 100644
--- a/chrome/browser/ash/smb_client/discovery/network_scanner.cc
+++ b/chrome/browser/ash/smb_client/discovery/network_scanner.cc
@@ -13,8 +13,7 @@
 #include "base/strings/string_util.h"
 #include "chrome/browser/ash/smb_client/discovery/host_locator.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 namespace {
 
@@ -131,5 +130,4 @@
   }
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/discovery/network_scanner.h b/chrome/browser/ash/smb_client/discovery/network_scanner.h
index 7313d82..b7f98af 100644
--- a/chrome/browser/ash/smb_client/discovery/network_scanner.h
+++ b/chrome/browser/ash/smb_client/discovery/network_scanner.h
@@ -13,8 +13,7 @@
 #include "chrome/browser/ash/smb_client/discovery/host_locator.h"
 #include "net/base/ip_address.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 // Holds the number of in-flight requests and the callback to call once all the
 // HostLocators are finished. Also holds the hosts found from the HostLocators
@@ -106,7 +105,6 @@
   base::WeakPtrFactory<NetworkScanner> weak_ptr_factory_{this};
 };
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_DISCOVERY_NETWORK_SCANNER_H_
diff --git a/chrome/browser/ash/smb_client/discovery/network_scanner_unittest.cc b/chrome/browser/ash/smb_client/discovery/network_scanner_unittest.cc
index 56c9ae3..d131b59 100644
--- a/chrome/browser/ash/smb_client/discovery/network_scanner_unittest.cc
+++ b/chrome/browser/ash/smb_client/discovery/network_scanner_unittest.cc
@@ -12,8 +12,7 @@
 #include "chrome/browser/ash/smb_client/discovery/in_memory_host_locator.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 namespace {
 
@@ -197,5 +196,4 @@
   ExpectResolvedHostEquals("21.22.23.24", "share3");
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/fileapi/smbfs_async_file_util.cc b/chrome/browser/ash/smb_client/fileapi/smbfs_async_file_util.cc
index a851d2f..6ec214d 100644
--- a/chrome/browser/ash/smb_client/fileapi/smbfs_async_file_util.cc
+++ b/chrome/browser/ash/smb_client/fileapi/smbfs_async_file_util.cc
@@ -19,8 +19,7 @@
 #include "storage/browser/file_system/file_system_url.h"
 #include "storage/browser/file_system/local_file_util.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 namespace {
 
 void AllowCredentialsRequestOnUIThread(Profile* profile,
@@ -142,5 +141,4 @@
                          base::SequencedTaskRunner::GetCurrentDefault()))));
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/fileapi/smbfs_async_file_util.h b/chrome/browser/ash/smb_client/fileapi/smbfs_async_file_util.h
index 53b3c0f..6eda013 100644
--- a/chrome/browser/ash/smb_client/fileapi/smbfs_async_file_util.h
+++ b/chrome/browser/ash/smb_client/fileapi/smbfs_async_file_util.h
@@ -11,8 +11,7 @@
 
 class Profile;
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 // The implementation of storage::AsyncFileUtil for SmbFs. This forwards to a
 // AsyncFileUtil for native files by default.
@@ -50,7 +49,6 @@
   base::WeakPtrFactory<SmbFsAsyncFileUtil> weak_factory_{this};
 };
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_FILEAPI_SMBFS_ASYNC_FILE_UTIL_H_
diff --git a/chrome/browser/ash/smb_client/fileapi/smbfs_file_system_backend_delegate.cc b/chrome/browser/ash/smb_client/fileapi/smbfs_file_system_backend_delegate.cc
index a67e112..c19cc74 100644
--- a/chrome/browser/ash/smb_client/fileapi/smbfs_file_system_backend_delegate.cc
+++ b/chrome/browser/ash/smb_client/fileapi/smbfs_file_system_backend_delegate.cc
@@ -11,8 +11,7 @@
 #include "storage/browser/file_system/file_stream_reader.h"
 #include "storage/browser/file_system/file_stream_writer.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 SmbFsFileSystemBackendDelegate::SmbFsFileSystemBackendDelegate(Profile* profile)
     : async_file_util_(std::make_unique<SmbFsAsyncFileUtil>(profile)) {}
@@ -58,5 +57,4 @@
   NOTREACHED();
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/fileapi/smbfs_file_system_backend_delegate.h b/chrome/browser/ash/smb_client/fileapi/smbfs_file_system_backend_delegate.h
index df7dfd0..062e1491 100644
--- a/chrome/browser/ash/smb_client/fileapi/smbfs_file_system_backend_delegate.h
+++ b/chrome/browser/ash/smb_client/fileapi/smbfs_file_system_backend_delegate.h
@@ -11,8 +11,7 @@
 
 class Profile;
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 class SmbFsAsyncFileUtil;
 
@@ -43,7 +42,6 @@
   std::unique_ptr<SmbFsAsyncFileUtil> async_file_util_;
 };
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_FILEAPI_SMBFS_FILE_SYSTEM_BACKEND_DELEGATE_H_
diff --git a/chrome/browser/ash/smb_client/smb_constants.cc b/chrome/browser/ash/smb_client/smb_constants.cc
index fce3444..83ae27c3 100644
--- a/chrome/browser/ash/smb_client/smb_constants.cc
+++ b/chrome/browser/ash/smb_client/smb_constants.cc
@@ -4,11 +4,9 @@
 
 #include "chrome/browser/ash/smb_client/smb_constants.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 const char kSmbScheme[] = "smb";
 const char kSmbSchemePrefix[] = "smb://";
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/smb_constants.h b/chrome/browser/ash/smb_client/smb_constants.h
index 6e8d62c3..d611d3a 100644
--- a/chrome/browser/ash/smb_client/smb_constants.h
+++ b/chrome/browser/ash/smb_client/smb_constants.h
@@ -5,15 +5,13 @@
 #ifndef CHROME_BROWSER_ASH_SMB_CLIENT_SMB_CONSTANTS_H_
 #define CHROME_BROWSER_ASH_SMB_CLIENT_SMB_CONSTANTS_H_
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 extern const char kSmbScheme[];
 extern const char kSmbSchemePrefix[];
 
 constexpr int kNetBiosDiscoveryTimeoutSeconds = 1;
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_SMB_CONSTANTS_H_
diff --git a/chrome/browser/ash/smb_client/smb_errors.cc b/chrome/browser/ash/smb_client/smb_errors.cc
index 37896bf..03cc644 100644
--- a/chrome/browser/ash/smb_client/smb_errors.cc
+++ b/chrome/browser/ash/smb_client/smb_errors.cc
@@ -6,8 +6,7 @@
 
 #include "base/logging.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 SmbMountResult TranslateErrorToMountResult(smbprovider::ErrorType error) {
   switch (error) {
@@ -54,5 +53,4 @@
   }
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/smb_errors.h b/chrome/browser/ash/smb_client/smb_errors.h
index 93db54e..72343269 100644
--- a/chrome/browser/ash/smb_client/smb_errors.h
+++ b/chrome/browser/ash/smb_client/smb_errors.h
@@ -8,8 +8,7 @@
 #include "base/files/file.h"
 #include "chromeos/ash/components/dbus/smbprovider/smb_provider_client.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 // These values are written to logs. New enum values may be added, but existing
 // enums must never be renumbered or values reused. Must be kept in sync
@@ -38,7 +37,6 @@
 // Translates an smbprovider::ErrorType to an SmbMountResult.
 SmbMountResult TranslateErrorToMountResult(smbprovider::ErrorType error);
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_SMB_ERRORS_H_
diff --git a/chrome/browser/ash/smb_client/smb_errors_unittest.cc b/chrome/browser/ash/smb_client/smb_errors_unittest.cc
index 41df477..514a554 100644
--- a/chrome/browser/ash/smb_client/smb_errors_unittest.cc
+++ b/chrome/browser/ash/smb_client/smb_errors_unittest.cc
@@ -8,8 +8,7 @@
 #include "chromeos/ash/components/dbus/smbprovider/directory_entry.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 class SmbErrorsTest : public ::testing::Test {
  public:
@@ -60,5 +59,4 @@
             TranslateErrorToMountResult(smbprovider::ERROR_OPERATION_FAILED));
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/smb_file_system.cc b/chrome/browser/ash/smb_client/smb_file_system.cc
index 9380fdd..2cd6d79c 100644
--- a/chrome/browser/ash/smb_client/smb_file_system.cc
+++ b/chrome/browser/ash/smb_client/smb_file_system.cc
@@ -11,8 +11,7 @@
 #include "chrome/browser/ash/smb_client/smb_file_system_id.h"
 #include "components/services/filesystem/public/mojom/types.mojom.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 using file_system_provider::AbortCallback;
 
@@ -20,7 +19,7 @@
     const file_system_provider::ProvidedFileSystemInfo& file_system_info)
     : file_system_info_(file_system_info) {}
 
-SmbFileSystem::~SmbFileSystem() {}
+SmbFileSystem::~SmbFileSystem() = default;
 
 AbortCallback SmbFileSystem::RequestUnmount(
     storage::AsyncFileUtil::StatusCallback callback) {
@@ -228,5 +227,4 @@
   return nullptr;
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/smb_file_system.h b/chrome/browser/ash/smb_client/smb_file_system.h
index 1209d684..488d8b4 100644
--- a/chrome/browser/ash/smb_client/smb_file_system.h
+++ b/chrome/browser/ash/smb_client/smb_file_system.h
@@ -42,7 +42,7 @@
 // Allows Files App to mount SMB filesystems.
 class SmbFileSystem : public file_system_provider::ProvidedFileSystemInterface {
  public:
-  SmbFileSystem(
+  explicit SmbFileSystem(
       const file_system_provider::ProvidedFileSystemInfo& file_system_info);
   SmbFileSystem(const SmbFileSystem&) = delete;
   SmbFileSystem& operator=(const SmbFileSystem&) = delete;
diff --git a/chrome/browser/ash/smb_client/smb_file_system_id.cc b/chrome/browser/ash/smb_client/smb_file_system_id.cc
index 904dab9..d9c03b0 100644
--- a/chrome/browser/ash/smb_client/smb_file_system_id.cc
+++ b/chrome/browser/ash/smb_client/smb_file_system_id.cc
@@ -16,8 +16,7 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 namespace {
 
 constexpr char kDelimiter[] = "@@";
@@ -91,5 +90,4 @@
   return components[2].substr(strlen(kUserPrefix));
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/smb_file_system_id.h b/chrome/browser/ash/smb_client/smb_file_system_id.h
index 6a29dbb..0f0f9fb 100644
--- a/chrome/browser/ash/smb_client/smb_file_system_id.h
+++ b/chrome/browser/ash/smb_client/smb_file_system_id.h
@@ -10,8 +10,7 @@
 
 #include "base/files/file_path.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 // Creates a FileSystemId by concatenating a random filesystem identifier and
 // |share_path| with a delimiter. The random ID is used so that the same share
@@ -42,7 +41,6 @@
 std::optional<std::string> GetUserFromFileSystemId(
     const std::string& file_system_id);
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_SMB_FILE_SYSTEM_ID_H_
diff --git a/chrome/browser/ash/smb_client/smb_file_system_id_test.cc b/chrome/browser/ash/smb_client/smb_file_system_id_test.cc
index 6ea19973..6e9d9f4 100644
--- a/chrome/browser/ash/smb_client/smb_file_system_id_test.cc
+++ b/chrome/browser/ash/smb_client/smb_file_system_id_test.cc
@@ -13,8 +13,7 @@
 
 using ::testing::MatchesRegex;
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 namespace {
 // gmock "regex" support is very basic and doesn't support [] or + operations.
@@ -120,5 +119,4 @@
   EXPECT_FALSE(GetUserFromFileSystemId(file_system_id_3));
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/smb_kerberos_credentials_updater.cc b/chrome/browser/ash/smb_client/smb_kerberos_credentials_updater.cc
index ed29730..0d840e1 100644
--- a/chrome/browser/ash/smb_client/smb_kerberos_credentials_updater.cc
+++ b/chrome/browser/ash/smb_client/smb_kerberos_credentials_updater.cc
@@ -6,8 +6,7 @@
 
 #include "base/check.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 SmbKerberosCredentialsUpdater::SmbKerberosCredentialsUpdater(
     KerberosCredentialsManager* credentials_manager,
@@ -53,5 +52,4 @@
   }
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/smb_kerberos_credentials_updater.h b/chrome/browser/ash/smb_client/smb_kerberos_credentials_updater.h
index 88b4a11..ff7dedc2 100644
--- a/chrome/browser/ash/smb_client/smb_kerberos_credentials_updater.h
+++ b/chrome/browser/ash/smb_client/smb_kerberos_credentials_updater.h
@@ -12,8 +12,7 @@
 #include "base/memory/raw_ptr.h"
 #include "chrome/browser/ash/kerberos/kerberos_credentials_manager.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 // Updates Kerberos credentials in SmbService after receiving a
 // `OnKerberosEnabledStateChanged` or `OnAccountsChanged` notification from
@@ -57,7 +56,6 @@
   const ActiveAccountChangedCallback active_account_changed_callback_;
 };
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_SMB_KERBEROS_CREDENTIALS_UPDATER_H_
diff --git a/chrome/browser/ash/smb_client/smb_kerberos_credentials_updater_unittest.cc b/chrome/browser/ash/smb_client/smb_kerberos_credentials_updater_unittest.cc
index dee4229..21d5a8e 100644
--- a/chrome/browser/ash/smb_client/smb_kerberos_credentials_updater_unittest.cc
+++ b/chrome/browser/ash/smb_client/smb_kerberos_credentials_updater_unittest.cc
@@ -26,8 +26,7 @@
 
 using ::base::test::RunClosure;
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 namespace {
 
@@ -200,5 +199,4 @@
   EXPECT_EQ(credentials_updater_->active_account_name(), kPrincipal);
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/smb_persisted_share_registry.h b/chrome/browser/ash/smb_client/smb_persisted_share_registry.h
index 377fc99..5fcd7bd 100644
--- a/chrome/browser/ash/smb_client/smb_persisted_share_registry.h
+++ b/chrome/browser/ash/smb_client/smb_persisted_share_registry.h
@@ -17,8 +17,7 @@
 class PrefRegistrySyncable;
 }  // namespace user_prefs
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 class SmbUrl;
 
@@ -53,7 +52,6 @@
   const raw_ptr<Profile> profile_;
 };
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_SMB_PERSISTED_SHARE_REGISTRY_H_
diff --git a/chrome/browser/ash/smb_client/smb_persisted_share_registry_unittest.cc b/chrome/browser/ash/smb_client/smb_persisted_share_registry_unittest.cc
index a684208..19046bf 100644
--- a/chrome/browser/ash/smb_client/smb_persisted_share_registry_unittest.cc
+++ b/chrome/browser/ash/smb_client/smb_persisted_share_registry_unittest.cc
@@ -9,8 +9,7 @@
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 namespace {
 
 const char kShareUrl[] = "smb://server/share1";
@@ -156,5 +155,4 @@
 }
 
 }  // namespace
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/smb_provider.cc b/chrome/browser/ash/smb_client/smb_provider.cc
index 88da429..ffc687a5 100644
--- a/chrome/browser/ash/smb_client/smb_provider.cc
+++ b/chrome/browser/ash/smb_client/smb_provider.cc
@@ -17,8 +17,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 SmbProvider::SmbProvider()
     : provider_id_(file_system_provider::ProviderId::CreateFromNativeId("smb")),
@@ -71,5 +70,4 @@
   return true;
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/smb_provider.h b/chrome/browser/ash/smb_client/smb_provider.h
index 0dff2df..77c00720a 100644
--- a/chrome/browser/ash/smb_client/smb_provider.h
+++ b/chrome/browser/ash/smb_client/smb_provider.h
@@ -17,8 +17,7 @@
 
 class Profile;
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 class SmbProvider : public file_system_provider::ProviderInterface {
  public:
@@ -49,7 +48,6 @@
   file_system_provider::IconSet icon_set_;
 };
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_SMB_PROVIDER_H_
diff --git a/chrome/browser/ash/smb_client/smb_service.cc b/chrome/browser/ash/smb_client/smb_service.cc
index 4ffdccc..2f6d056 100644
--- a/chrome/browser/ash/smb_client/smb_service.cc
+++ b/chrome/browser/ash/smb_client/smb_service.cc
@@ -50,8 +50,7 @@
 #include "net/base/network_interfaces.h"
 #include "url/url_util.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 namespace {
 
@@ -711,5 +710,4 @@
   return !saved_smbfs_shares.empty() || !preconfigured_shares.empty();
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/smb_service.h b/chrome/browser/ash/smb_client/smb_service.h
index bcbea8d..a36b564 100644
--- a/chrome/browser/ash/smb_client/smb_service.h
+++ b/chrome/browser/ash/smb_client/smb_service.h
@@ -37,8 +37,7 @@
 class PrefRegistrySyncable;
 }  // namespace user_prefs
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 class SmbKerberosCredentialsUpdater;
 class SmbShareInfo;
@@ -259,7 +258,6 @@
   base::WeakPtrFactory<SmbService> weak_ptr_factory_{this};
 };
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_SMB_SERVICE_H_
diff --git a/chrome/browser/ash/smb_client/smb_service_factory.cc b/chrome/browser/ash/smb_client/smb_service_factory.cc
index 352f9599..03ddadc 100644
--- a/chrome/browser/ash/smb_client/smb_service_factory.cc
+++ b/chrome/browser/ash/smb_client/smb_service_factory.cc
@@ -15,8 +15,7 @@
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 namespace {
 
@@ -85,5 +84,4 @@
   SmbService::RegisterProfilePrefs(registry);
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/smb_service_factory.h b/chrome/browser/ash/smb_client/smb_service_factory.h
index c1077d98..40c7079 100644
--- a/chrome/browser/ash/smb_client/smb_service_factory.h
+++ b/chrome/browser/ash/smb_client/smb_service_factory.h
@@ -9,8 +9,7 @@
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
 #include "content/public/browser/browser_context.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 class SmbService;
 
@@ -44,7 +43,6 @@
       user_prefs::PrefRegistrySyncable* registry) override;
 };
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_SMB_SERVICE_FACTORY_H_
diff --git a/chrome/browser/ash/smb_client/smb_service_helper.cc b/chrome/browser/ash/smb_client/smb_service_helper.cc
index 36aff077..cbfdfe5 100644
--- a/chrome/browser/ash/smb_client/smb_service_helper.cc
+++ b/chrome/browser/ash/smb_client/smb_service_helper.cc
@@ -7,8 +7,7 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 bool ParseUserPrincipalName(const std::string& user_principal_name,
                             std::string* user_name,
@@ -60,5 +59,4 @@
   return true;
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/smb_service_helper.h b/chrome/browser/ash/smb_client/smb_service_helper.h
index f8d594f..e0c2a63 100644
--- a/chrome/browser/ash/smb_client/smb_service_helper.h
+++ b/chrome/browser/ash/smb_client/smb_service_helper.h
@@ -10,8 +10,7 @@
 
 #include "base/logging.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 // Parse a user principal name into the user name and domain.
 // The format is "user@domain.com", following RFC-822.
@@ -38,7 +37,6 @@
                    std::string* user_name,
                    std::string* workgroup);
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_SMB_SERVICE_HELPER_H_
diff --git a/chrome/browser/ash/smb_client/smb_service_helper_unittest.cc b/chrome/browser/ash/smb_client/smb_service_helper_unittest.cc
index 2459ca6..b67c08d4 100644
--- a/chrome/browser/ash/smb_client/smb_service_helper_unittest.cc
+++ b/chrome/browser/ash/smb_client/smb_service_helper_unittest.cc
@@ -8,8 +8,7 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 class SmbServiceHelperTest : public ::testing::Test {
  public:
@@ -146,5 +145,4 @@
   EXPECT_EQ(realm_, "");
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/smb_share_finder.cc b/chrome/browser/ash/smb_client/smb_share_finder.cc
index 560570d5..d144c2d1d 100644
--- a/chrome/browser/ash/smb_client/smb_share_finder.cc
+++ b/chrome/browser/ash/smb_client/smb_share_finder.cc
@@ -13,8 +13,7 @@
 #include "chrome/browser/ash/smb_client/smb_constants.h"
 #include "chrome/browser/ash/smb_client/smb_errors.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 SmbShareFinder::SmbShareFinder(SmbProviderClient* client) : client_(client) {}
 SmbShareFinder::~SmbShareFinder() = default;
@@ -203,5 +202,4 @@
   discovery_callbacks_.push_back(std::move(discovery_callback));
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/smb_share_finder.h b/chrome/browser/ash/smb_client/smb_share_finder.h
index 9cb28eb6..021001ab 100644
--- a/chrome/browser/ash/smb_client/smb_share_finder.h
+++ b/chrome/browser/ash/smb_client/smb_share_finder.h
@@ -16,8 +16,7 @@
 #include "chrome/browser/ash/smb_client/smb_url.h"
 #include "chromeos/ash/components/dbus/smbprovider/smb_provider_client.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 // The callback run to indicate the scan for hosts on the network is complete.
 using HostDiscoveryResponse = base::OnceClosure;
@@ -108,7 +107,6 @@
   base::WeakPtrFactory<SmbShareFinder> weak_ptr_factory_{this};
 };
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_SMB_SHARE_FINDER_H_
diff --git a/chrome/browser/ash/smb_client/smb_share_finder_unittest.cc b/chrome/browser/ash/smb_client/smb_share_finder_unittest.cc
index 66f455d..0adb127 100644
--- a/chrome/browser/ash/smb_client/smb_share_finder_unittest.cc
+++ b/chrome/browser/ash/smb_client/smb_share_finder_unittest.cc
@@ -18,8 +18,7 @@
 #include "chromeos/ash/components/dbus/smbprovider/fake_smb_provider_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 namespace {
 
@@ -333,5 +332,4 @@
   ExpectAllSharesHaveBeenFound();
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/smb_share_info.cc b/chrome/browser/ash/smb_client/smb_share_info.cc
index 9a287b2..3db0f1c 100644
--- a/chrome/browser/ash/smb_client/smb_share_info.cc
+++ b/chrome/browser/ash/smb_client/smb_share_info.cc
@@ -6,8 +6,7 @@
 
 #include "base/check.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 SmbShareInfo::SmbShareInfo(const SmbUrl& share_url,
                            const std::string& display_name,
@@ -31,5 +30,4 @@
 
 SmbShareInfo& SmbShareInfo::operator=(const SmbShareInfo&) = default;
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/smb_share_info.h b/chrome/browser/ash/smb_client/smb_share_info.h
index 81c49cf1..447343c7 100644
--- a/chrome/browser/ash/smb_client/smb_share_info.h
+++ b/chrome/browser/ash/smb_client/smb_share_info.h
@@ -10,8 +10,7 @@
 
 #include "chrome/browser/ash/smb_client/smb_url.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 // Common parameters for SMB shares.
 // Note: Password is explicitly excluded here. Due to being sensitive
@@ -49,7 +48,6 @@
   std::vector<uint8_t> password_salt_;
 };
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_SMB_SHARE_INFO_H_
diff --git a/chrome/browser/ash/smb_client/smb_url.cc b/chrome/browser/ash/smb_client/smb_url.cc
index 754c1fc8..7834606 100644
--- a/chrome/browser/ash/smb_client/smb_url.cc
+++ b/chrome/browser/ash/smb_client/smb_url.cc
@@ -13,8 +13,7 @@
 #include "chrome/browser/ash/smb_client/smb_constants.h"
 #include "url/url_canon_stdstring.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 namespace {
 
@@ -205,5 +204,4 @@
   url_.clear();
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/smb_url.h b/chrome/browser/ash/smb_client/smb_url.h
index dc53d31..5b98f06b 100644
--- a/chrome/browser/ash/smb_client/smb_url.h
+++ b/chrome/browser/ash/smb_client/smb_url.h
@@ -9,8 +9,7 @@
 
 #include "url/third_party/mozilla/url_parse.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 // Represents an SMB URL.
 // This class stores a URL using url::Component and can contain either a
@@ -75,7 +74,6 @@
   std::string share_;
 };
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_SMB_URL_H_
diff --git a/chrome/browser/ash/smb_client/smb_url_unittest.cc b/chrome/browser/ash/smb_client/smb_url_unittest.cc
index 1b4b54d4..eb024a1 100644
--- a/chrome/browser/ash/smb_client/smb_url_unittest.cc
+++ b/chrome/browser/ash/smb_client/smb_url_unittest.cc
@@ -9,8 +9,7 @@
 #include "chrome/browser/ash/smb_client/smb_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 class SmbUrlTest : public testing::Test {
  public:
@@ -208,5 +207,4 @@
   ExpectValidWindowsUNC("\\\\server/share", "\\\\server\\share");
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/smbfs_share.cc b/chrome/browser/ash/smb_client/smbfs_share.cc
index 190e5c1..62b86cd 100644
--- a/chrome/browser/ash/smb_client/smbfs_share.cc
+++ b/chrome/browser/ash/smb_client/smbfs_share.cc
@@ -19,8 +19,7 @@
 #include "crypto/sha2.h"
 #include "storage/browser/file_system/external_mount_points.h"
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 namespace {
 
@@ -346,5 +345,4 @@
   return base::JoinString(mount_id_hash_components, kMountIdHashSeparator);
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/ash/smb_client/smbfs_share.h b/chrome/browser/ash/smb_client/smbfs_share.h
index b71722af..bcef57a9 100644
--- a/chrome/browser/ash/smb_client/smbfs_share.h
+++ b/chrome/browser/ash/smb_client/smbfs_share.h
@@ -22,8 +22,7 @@
 
 class Profile;
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 
 // Represents an SMB share mounted using smbfs. Handles mounting, unmounting,
 // registration, and IPC communication with filesystem.
@@ -150,7 +149,6 @@
   base::WeakPtrFactory<SmbFsShare> weak_factory_{this};
 };
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
 
 #endif  // CHROME_BROWSER_ASH_SMB_CLIENT_SMBFS_SHARE_H_
diff --git a/chrome/browser/ash/smb_client/smbfs_share_unittest.cc b/chrome/browser/ash/smb_client/smbfs_share_unittest.cc
index 5fc593ff..d0ddf9d 100644
--- a/chrome/browser/ash/smb_client/smbfs_share_unittest.cc
+++ b/chrome/browser/ash/smb_client/smbfs_share_unittest.cc
@@ -33,8 +33,7 @@
 using testing::Property;
 using testing::Unused;
 
-namespace ash {
-namespace smb_client {
+namespace ash::smb_client {
 namespace {
 
 constexpr char kSharePath[] = "smb://share/path";
@@ -490,5 +489,4 @@
   EXPECT_EQ(mount_id2.size(), 64u);
 }
 
-}  // namespace smb_client
-}  // namespace ash
+}  // namespace ash::smb_client
diff --git a/chrome/browser/browsing_data/browsing_data_model_browsertest.cc b/chrome/browser/browsing_data/browsing_data_model_browsertest.cc
index 031b66d..b2bd5168 100644
--- a/chrome/browser/browsing_data/browsing_data_model_browsertest.cc
+++ b/chrome/browser/browsing_data/browsing_data_model_browsertest.cc
@@ -1452,16 +1452,8 @@
   ASSERT_EQ(browsing_data_model->size(), 0u);
 }
 
-// TODO(crbug.com/1524052): Flaky on at least Mac11 and Mac13.
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_SharedDictionaryAccessReportedCorrectly \
-  DISABLED_SharedDictionaryAccessReportedCorrectly
-#else
-#define MAYBE_SharedDictionaryAccessReportedCorrectly \
-  SharedDictionaryAccessReportedCorrectly
-#endif  // BUILDFLAG(IS_MAC)
 IN_PROC_BROWSER_TEST_P(BrowsingDataModelBrowserTest,
-                       MAYBE_SharedDictionaryAccessReportedCorrectly) {
+                       SharedDictionaryAccessReportedCorrectly) {
   ASSERT_TRUE(ui_test_utils::NavigateToURL(
       browser(),
       https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html")));
@@ -1510,8 +1502,9 @@
 
   // Need this polling because the shared dictionary is used only if the
   // metadata database has been read when sending the HTTP request.
-  EXPECT_TRUE(base::test::RunUntil(
-      [&]() { return HasDataForType("SharedDictionary", web_contents()); }));
+  while (!HasDataForType("SharedDictionary", web_contents())) {
+    base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
+  }
 
   // Checking HasDataForType("SharedDictionary") accesses the registered
   // shared dictionary. This must be reported to the data model.
diff --git a/chrome/browser/lacros/lacros_file_system_provider.cc b/chrome/browser/lacros/lacros_file_system_provider.cc
index 519e9a2..18309f9 100644
--- a/chrome/browser/lacros/lacros_file_system_provider.cc
+++ b/chrome/browser/lacros/lacros_file_system_provider.cc
@@ -39,8 +39,7 @@
     const extensions::ExtensionId& extension_id) {
   extensions::ExtensionRegistry* registry =
       extensions::ExtensionRegistry::Get(browser_context);
-  return registry->GetExtensionById(extension_id,
-                                    extensions::ExtensionRegistry::ENABLED);
+  return registry->enabled_extensions().GetByID(extension_id);
 }
 
 // Loads an icon of a single size.
diff --git a/chrome/browser/password_check/android/password_check_manager.cc b/chrome/browser/password_check/android/password_check_manager.cc
index 6721dc77..586ce38b 100644
--- a/chrome/browser/password_check/android/password_check_manager.cc
+++ b/chrome/browser/password_check/android/password_check_manager.cc
@@ -318,14 +318,10 @@
   switch (sync_state) {
     case SyncState::kNotActive:
       ABSL_FALLTHROUGH_INTENDED;
-    case SyncState::kSyncingWithCustomPassphrase:
-      ABSL_FALLTHROUGH_INTENDED;
-    case SyncState::kAccountPasswordsActiveWithCustomPassphrase:
+    case SyncState::kActiveWithCustomPassphrase:
       return false;
 
-    case SyncState::kSyncingNormalEncryption:
-      ABSL_FALLTHROUGH_INTENDED;
-    case SyncState::kAccountPasswordsActiveNormalEncryption:
+    case SyncState::kActiveWithNormalEncryption:
       return true;
   }
 }
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 0354196..ce18ea6 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -1002,6 +1002,10 @@
 constexpr char kSavePasswordsSuspendedByError[] =
     "profile.save_passwords_suspended_by_error";
 #endif
+constexpr char kSafeBrowsingDeepScanPromptSeen[] =
+    "safebrowsing.deep_scan_prompt_seen";
+constexpr char kSafeBrowsingEsbEnabledTimestamp[] =
+    "safebrowsing.esb_enabled_timestamp";
 
 // Register local state used only for migration (clearing or moving to a new
 // key).
@@ -1426,6 +1430,8 @@
 #if BUILDFLAG(IS_ANDROID)
   registry->RegisterBooleanPref(kSavePasswordsSuspendedByError, false);
 #endif
+  registry->RegisterBooleanPref(kSafeBrowsingDeepScanPromptSeen, false);
+  registry->RegisterTimePref(kSafeBrowsingEsbEnabledTimestamp, base::Time());
 }
 
 void ClearSyncRequestedPrefAndMaybeMigrate(PrefService* profile_prefs) {
@@ -2697,6 +2703,10 @@
   profile_prefs->ClearPref(kSavePasswordsSuspendedByError);
 #endif
 
+  // Deprecated 02/2024
+  profile_prefs->ClearPref(kSafeBrowsingDeepScanPromptSeen);
+  profile_prefs->ClearPref(kSafeBrowsingEsbEnabledTimestamp);
+
   // Please don't delete the following line. It is used by PRESUBMIT.py.
   // END_MIGRATE_OBSOLETE_PROFILE_PREFS
 
diff --git a/chrome/browser/privacy_sandbox/android/BUILD.gn b/chrome/browser/privacy_sandbox/android/BUILD.gn
index c71b551..39b05ffe 100644
--- a/chrome/browser/privacy_sandbox/android/BUILD.gn
+++ b/chrome/browser/privacy_sandbox/android/BUILD.gn
@@ -40,6 +40,7 @@
     "java/src/org/chromium/chrome/browser/privacy_sandbox/TopicsFragment.java",
     "java/src/org/chromium/chrome/browser/privacy_sandbox/TopicsLearnMoreFragment.java",
     "java/src/org/chromium/chrome/browser/privacy_sandbox/TopicsManageFragment.java",
+    "java/src/org/chromium/chrome/browser/privacy_sandbox/TopicsUtils.java",
     "java/src/org/chromium/chrome/browser/privacy_sandbox/TrackingProtectionBridge.java",
   ]
   deps = [
@@ -145,28 +146,28 @@
     "java/res/drawable/ic_interests_24dp.xml",
     "java/res/drawable/privacy_sandbox_interests_illustration.xml",
     "java/res/drawable/privacy_sandbox_notice_eea_illustration.xml",
-    "java/res/drawable/topic_taxonomy_2_id_1.xml",
-    "java/res/drawable/topic_taxonomy_2_id_100.xml",
-    "java/res/drawable/topic_taxonomy_2_id_103.xml",
-    "java/res/drawable/topic_taxonomy_2_id_126.xml",
-    "java/res/drawable/topic_taxonomy_2_id_149.xml",
-    "java/res/drawable/topic_taxonomy_2_id_172.xml",
-    "java/res/drawable/topic_taxonomy_2_id_180.xml",
-    "java/res/drawable/topic_taxonomy_2_id_196.xml",
-    "java/res/drawable/topic_taxonomy_2_id_207.xml",
-    "java/res/drawable/topic_taxonomy_2_id_215.xml",
-    "java/res/drawable/topic_taxonomy_2_id_226.xml",
-    "java/res/drawable/topic_taxonomy_2_id_239.xml",
-    "java/res/drawable/topic_taxonomy_2_id_243.xml",
-    "java/res/drawable/topic_taxonomy_2_id_250.xml",
-    "java/res/drawable/topic_taxonomy_2_id_254.xml",
-    "java/res/drawable/topic_taxonomy_2_id_263.xml",
-    "java/res/drawable/topic_taxonomy_2_id_272.xml",
-    "java/res/drawable/topic_taxonomy_2_id_289.xml",
-    "java/res/drawable/topic_taxonomy_2_id_299.xml",
-    "java/res/drawable/topic_taxonomy_2_id_332.xml",
-    "java/res/drawable/topic_taxonomy_2_id_57.xml",
-    "java/res/drawable/topic_taxonomy_2_id_86.xml",
+    "java/res/drawable/topic_taxonomy_1_id_1.xml",
+    "java/res/drawable/topic_taxonomy_1_id_100.xml",
+    "java/res/drawable/topic_taxonomy_1_id_103.xml",
+    "java/res/drawable/topic_taxonomy_1_id_126.xml",
+    "java/res/drawable/topic_taxonomy_1_id_149.xml",
+    "java/res/drawable/topic_taxonomy_1_id_172.xml",
+    "java/res/drawable/topic_taxonomy_1_id_180.xml",
+    "java/res/drawable/topic_taxonomy_1_id_196.xml",
+    "java/res/drawable/topic_taxonomy_1_id_207.xml",
+    "java/res/drawable/topic_taxonomy_1_id_215.xml",
+    "java/res/drawable/topic_taxonomy_1_id_226.xml",
+    "java/res/drawable/topic_taxonomy_1_id_239.xml",
+    "java/res/drawable/topic_taxonomy_1_id_243.xml",
+    "java/res/drawable/topic_taxonomy_1_id_250.xml",
+    "java/res/drawable/topic_taxonomy_1_id_254.xml",
+    "java/res/drawable/topic_taxonomy_1_id_263.xml",
+    "java/res/drawable/topic_taxonomy_1_id_272.xml",
+    "java/res/drawable/topic_taxonomy_1_id_289.xml",
+    "java/res/drawable/topic_taxonomy_1_id_299.xml",
+    "java/res/drawable/topic_taxonomy_1_id_332.xml",
+    "java/res/drawable/topic_taxonomy_1_id_57.xml",
+    "java/res/drawable/topic_taxonomy_1_id_86.xml",
     "java/res/drawable/topic_taxonomy_placeholder.xml",
     "java/res/layout/category_with_clickable_summary_preference.xml",
     "java/res/layout/privacy_sandbox_consent_eea.xml",
@@ -176,6 +177,7 @@
     "java/res/layout/privacy_sandbox_notice_restricted.xml",
     "java/res/layout/privacy_sandbox_notice_row.xml",
     "java/res/layout/privacy_sandbox_notice_row_dropdown.xml",
+    "java/res/layout/topics_explanation_summary.xml",
     "java/res/values/dimens.xml",
     "java/res/xml/ad_measurement_preference.xml",
     "java/res/xml/block_list_preference.xml",
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_1.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_1.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_1.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_1.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_100.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_100.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_100.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_100.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_103.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_103.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_103.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_103.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_126.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_126.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_126.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_126.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_149.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_149.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_149.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_149.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_172.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_172.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_172.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_172.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_180.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_180.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_180.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_180.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_196.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_196.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_196.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_196.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_207.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_207.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_207.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_207.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_215.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_215.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_215.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_215.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_226.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_226.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_226.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_226.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_239.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_239.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_239.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_239.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_243.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_243.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_243.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_243.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_250.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_250.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_250.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_250.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_254.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_254.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_254.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_254.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_263.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_263.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_263.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_263.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_272.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_272.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_272.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_272.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_289.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_289.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_289.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_289.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_299.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_299.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_299.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_299.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_332.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_332.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_332.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_332.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_57.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_57.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_57.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_57.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_86.xml b/chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_86.xml
similarity index 100%
rename from chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_2_id_86.xml
rename to chrome/browser/privacy_sandbox/android/java/res/drawable/topic_taxonomy_1_id_86.xml
diff --git a/chrome/browser/privacy_sandbox/android/java/res/layout/topics_explanation_summary.xml b/chrome/browser/privacy_sandbox/android/java/res/layout/topics_explanation_summary.xml
new file mode 100644
index 0000000..a4d7ab7
--- /dev/null
+++ b/chrome/browser/privacy_sandbox/android/java/res/layout/topics_explanation_summary.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2024 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal"
+    android:layout_marginTop="-24dp"
+    android:paddingHorizontal="16dp"
+    android:paddingVertical="16dp">
+    <TextView
+        android:id="@android:id/summary"
+        style="@style/PreferenceSummary"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/chrome/browser/privacy_sandbox/android/java/res/xml/topics_preference_v2.xml b/chrome/browser/privacy_sandbox/android/java/res/xml/topics_preference_v2.xml
index 079711f8..9d34937 100644
--- a/chrome/browser/privacy_sandbox/android/java/res/xml/topics_preference_v2.xml
+++ b/chrome/browser/privacy_sandbox/android/java/res/xml/topics_preference_v2.xml
@@ -10,12 +10,13 @@
     <org.chromium.components.browser_ui.settings.ChromeSwitchPreference
         android:key="topics_toggle"
         android:title="@string/settings_topics_page_toggle_label"
-        android:summary="@string/settings_topics_page_toggle_sub_label"
+        android:summary="@string/settings_topics_page_toggle_sub_label_v2"
         app:allowDividerBelow="false" />
 
     <org.chromium.components.browser_ui.settings.TextMessagePreference
         android:key="topics_explanation"
-        android:summary="@string/settings_topics_page_explanation_description" />
+        android:summary="@string/settings_topics_page_explanation_description"
+        android:layout="@layout/topics_explanation_summary" />
 
     <org.chromium.components.browser_ui.settings.ChromeBasePreference
         android:key="active_topics"
diff --git a/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/TopicSwitchPreference.java b/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/TopicSwitchPreference.java
index 32a1cc3..b56550c 100644
--- a/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/TopicSwitchPreference.java
+++ b/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/TopicSwitchPreference.java
@@ -38,16 +38,8 @@
         FaviconViewUtils.formatIconForFavicon(getContext().getResources(), icon);
     }
 
-    @SuppressWarnings("DiscouragedApi")
     private void updateIcon() {
-        String iconName =
-                String.format(
-                        "topic_taxonomy_%s_id_%s",
-                        mTopic.getTaxonomyVersion(), mTopic.getTopicId());
-        int iconId =
-                getContext()
-                        .getResources()
-                        .getIdentifier(iconName, "drawable", getContext().getPackageName());
+        int iconId = TopicsUtils.getIconResourceIdForTopic(getContext(), mTopic);
         setIcon((iconId != 0) ? iconId : R.drawable.topic_taxonomy_placeholder);
     }
 }
diff --git a/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/TopicsUtils.java b/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/TopicsUtils.java
new file mode 100644
index 0000000..8709000
--- /dev/null
+++ b/chrome/browser/privacy_sandbox/android/java/src/org/chromium/chrome/browser/privacy_sandbox/TopicsUtils.java
@@ -0,0 +1,29 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.privacy_sandbox;
+
+import android.content.Context;
+
+public class TopicsUtils {
+    /**
+     * Fetches the icon resource id for a given topic.
+     *
+     * @param context The current context.
+     * @param topic The topic to fetch the icon for.
+     * @return icon id if it exists; 0 if it doesn't.
+     */
+    @SuppressWarnings("DiscouragedApi")
+    public static int getIconResourceIdForTopic(Context context, Topic topic) {
+        // Check all the previous taxonomy versions as well, in case the version is increased.
+        for (int version = topic.getTaxonomyVersion(); version > 0; version--) {
+            String iconName = String.format("topic_taxonomy_%s_id_%s", version, topic.getTopicId());
+            int iconId =
+                    context.getResources()
+                            .getIdentifier(iconName, "drawable", context.getPackageName());
+            if (iconId != 0) return iconId;
+        }
+        return 0;
+    }
+}
diff --git a/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/TopicsFragmentTest.java b/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/TopicsFragmentTest.java
index 107cfc6..aea0960 100644
--- a/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/TopicsFragmentTest.java
+++ b/chrome/browser/privacy_sandbox/android/javatests/src/org/chromium/chrome/browser/privacy_sandbox/TopicsFragmentTest.java
@@ -482,15 +482,10 @@
         TestThreadUtils.runOnUiThreadBlocking(
                 () -> {
                     for (var topic : PrivacySandboxBridge.getFirstLevelTopics()) {
-                        String iconName =
-                                String.format(
-                                        "topic_taxonomy_%s_id_%s",
-                                        topic.getTaxonomyVersion(), topic.getTopicId());
-                        int iconId =
-                                activity.getResources()
-                                        .getIdentifier(
-                                                iconName, "drawable", activity.getPackageName());
-                        assertTrue("Topic drawable icon not found: " + iconName, iconId != 0);
+                        int iconId = TopicsUtils.getIconResourceIdForTopic(activity, topic);
+                        assertTrue(
+                                "Topic drawable icon not found for: " + topic.getName(),
+                                iconId != 0);
                     }
                 });
     }
diff --git a/chrome/browser/resources/ash/settings/os_settings_icons.html b/chrome/browser/resources/ash/settings/os_settings_icons.html
index 7c9bd26a2..b04f70a1 100644
--- a/chrome/browser/resources/ash/settings/os_settings_icons.html
+++ b/chrome/browser/resources/ash/settings/os_settings_icons.html
@@ -307,7 +307,7 @@
       <g id="set-date-time" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M4.563 7.5h10.875V5.562H4.562V7.5Zm0 0V5.562 7.5Zm0 10.667c-.487 0-.896-.167-1.23-.5a1.671 1.671 0 0 1-.5-1.23V5.563c0-.472.167-.875.5-1.208.348-.347.757-.52 1.23-.52H6v-2h1.625v2h4.75v-2H14v2h1.438c.472 0 .874.173 1.208.52.347.333.52.736.52 1.208v4.355a3.444 3.444 0 0 0-.833-.271 6.34 6.34 0 0 0-.895-.146V9H4.562v7.438h5.209c.083.319.194.625.333.916.153.278.327.549.521.813H4.562Zm10.52.833c-1.11 0-2.055-.389-2.833-1.167-.778-.777-1.167-1.722-1.167-2.833 0-1.111.39-2.056 1.167-2.833A3.927 3.927 0 0 1 15.104 11c1.097 0 2.035.389 2.813 1.167.777.777 1.166 1.722 1.166 2.833 0 1.111-.389 2.056-1.166 2.833-.778.778-1.723 1.167-2.834 1.167Zm1.146-2.104.771-.75-1.375-1.375v-1.813h-1.063v2.271l1.667 1.667Z"></path></g>
       <g id="restore" viewBox="0 0 20 20"><path fill-rule="evenodd" clip-rule="evenodd" d="M12 9V7H15.1979C14.1609 5.20627 12.2219 4 10 4C6.685 4 4 6.685 4 10C4 13.315 6.685 16 10 16C12.9739 16 15.4407 13.8392 15.9169 11.0011L17.9379 11.0005C17.4451 14.9449 14.0766 18 9.992 18C5.576 18 2 14.416 2 10C2 5.584 5.576 2 9.992 2C12.3857 2 14.5335 3.04926 16.0007 4.71184L16 3H18V9H12ZM10.5 6V10L13 12.5L11.5 14L8.5 11V6H10.5Z"></path></g>
       <g id="restore-revamp" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M10 11.583a1.53 1.53 0 0 1-1.125-.458A1.575 1.575 0 0 1 8.417 10c0-.43.152-.799.458-1.104.32-.32.694-.48 1.125-.48.43 0 .799.16 1.104.48.32.305.48.673.48 1.104 0 .444-.16.82-.48 1.125a1.505 1.505 0 0 1-1.104.458Zm0 5.584c-1.986 0-3.68-.695-5.083-2.084C3.514 13.694 2.819 12 2.833 10h1.73c.027 1.514.562 2.799 1.604 3.854C7.222 14.91 8.5 15.438 10 15.438c1.514 0 2.799-.528 3.854-1.584 1.056-1.055 1.584-2.34 1.584-3.854 0-1.514-.528-2.799-1.584-3.854C12.8 5.09 11.514 4.563 10 4.563c-.778 0-1.52.166-2.23.5-.707.319-1.326.77-1.853 1.354H8V8H2.875V2.875h1.583V5.5c.68-.847 1.5-1.5 2.459-1.958A6.882 6.882 0 0 1 10 2.833c.986 0 1.917.188 2.792.563a6.996 6.996 0 0 1 2.27 1.542 7.165 7.165 0 0 1 1.521 2.27c.39.861.584 1.792.584 2.792 0 1-.195 1.938-.584 2.813a7.49 7.49 0 0 1-1.52 2.27 7.165 7.165 0 0 1-2.271 1.521 7.012 7.012 0 0 1-2.792.563Z"></path></g>
-      <g id="multitasking" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M12.5 17q-.625 0-1.062-.437A1.45 1.45 0 0 1 11 15.5v-11q0-.604.438-1.042A1.41 1.41 0 0 1 12.5 3h3q.604 0 1.042.458Q17 3.896 17 4.5v11q0 .624-.458 1.063A1.42 1.42 0 0 1 15.5 17zm-8 0q-.625 0-1.062-.437A1.45 1.45 0 0 1 3 15.5v-11q0-.604.438-1.042A1.41 1.41 0 0 1 4.5 3h3q.604 0 1.042.458Q9 3.896 9 4.5v11q0 .624-.458 1.063A1.42 1.42 0 0 1 7.5 17zm0-12.5v11h3v-11zm3 11h-3z"></path></g>
+      <g id="snap-window-suggestions" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M12.5 17q-.625 0-1.062-.437A1.45 1.45 0 0 1 11 15.5v-11q0-.604.438-1.042A1.41 1.41 0 0 1 12.5 3h3q.604 0 1.042.458Q17 3.896 17 4.5v11q0 .624-.458 1.063A1.42 1.42 0 0 1 15.5 17zm-8 0q-.625 0-1.062-.437A1.45 1.45 0 0 1 3 15.5v-11q0-.604.438-1.042A1.41 1.41 0 0 1 4.5 3h3q.604 0 1.042.458Q9 3.896 9 4.5v11q0 .624-.458 1.063A1.42 1.42 0 0 1 7.5 17zm0-12.5v11h3v-11zm3 11h-3z"></path></g>
 
       <!-- General OS Settings icons -->
       <g id="account" viewBox="0 0 20 20"><path fill-rule="evenodd" clip-rule="evenodd" d="M7.6 9.8a1 1 0 1 0 0 2 1 1 0 0 0 0-2Zm4.8 0a1 1 0 1 0 0 2 1 1 0 0 0 0-2ZM10 2c-4.416 0-8 3.584-8 8s3.584 8 8 8 8-3.584 8-8-3.584-8-8-8Zm0 14.4A6.409 6.409 0 0 1 3.6 10c0-.232.016-.464.04-.688a8.05 8.05 0 0 0 4.168-4.296 7.98 7.98 0 0 0 8.328 3.176c.168.568.264 1.176.264 1.808 0 3.528-2.872 6.4-6.4 6.4Z"/></g>
diff --git a/chrome/browser/resources/ash/settings/os_settings_search_box/os_search_result_row.ts b/chrome/browser/resources/ash/settings/os_settings_search_box/os_search_result_row.ts
index 12ace6d..b053900 100644
--- a/chrome/browser/resources/ash/settings/os_settings_search_box/os_search_result_row.ts
+++ b/chrome/browser/resources/ash/settings/os_settings_search_box/os_search_result_row.ts
@@ -814,6 +814,8 @@
         return 'os-settings:select-to-speak';
       case SearchResultIcon.kShield:
         return 'cr:security';
+      case SearchResultIcon.kSnapWindowSuggestions:
+        return 'os-settings:snap-window-suggestions';
       case SearchResultIcon.kStorage:
         return isRevampEnabled ? 'os-settings:storage' :
                                  'os-settings:hard-drive';
diff --git a/chrome/browser/resources/ash/settings/system_preferences_page/multitasking_settings_card.html b/chrome/browser/resources/ash/settings/system_preferences_page/multitasking_settings_card.html
index 7bc7521..afe7d599 100644
--- a/chrome/browser/resources/ash/settings/system_preferences_page/multitasking_settings_card.html
+++ b/chrome/browser/resources/ash/settings/system_preferences_page/multitasking_settings_card.html
@@ -7,7 +7,7 @@
 
 <settings-card header-text="[[getHeaderText_()]]">
   <settings-toggle-button id="snapWindowSuggestionsToggle"
-      icon="os-settings:multitasking"
+      icon="os-settings:snap-window-suggestions"
       pref="{{prefs.ash.snap_window_suggestions.enabled}}"
       label="[[getLabelText_()]]"
       sub-label="[[getDescriptionText_()]]"
diff --git a/chrome/browser/resources/chromeos/emoji_picker/app.html b/chrome/browser/resources/chromeos/emoji_picker/app.html
index 4e414c9..dc71d6e 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/app.html
+++ b/chrome/browser/resources/chromeos/emoji_picker/app.html
@@ -336,6 +336,7 @@
     gif-support$="[[gifSupport]]"
     seal-support$="[[sealSupport]]"
     close-gif-nudge-overlay="[[closeGifNudgeOverlay]]"
+    useMojoSearch="[[useMojoSearch]]"
     use-grouped-preference="[[variantGroupingSupport]]"
     global-tone="[[globalTone]]"
     global-gender="[[globalGender]]">
diff --git a/chrome/browser/resources/chromeos/login/components/hd_iron_icon.html b/chrome/browser/resources/chromeos/login/components/hd_iron_icon.html
index 782fdda..0972857 100644
--- a/chrome/browser/resources/chromeos/login/components/hd_iron_icon.html
+++ b/chrome/browser/resources/chromeos/login/components/hd_iron_icon.html
@@ -6,15 +6,21 @@
 
 <style include="oobe-common-styles">
   @media all and (-webkit-max-device-pixel-ratio: 1.5) {
+    #icon1x {
+      display: flex;
+    }
     #icon2x {
       display: none;
     }
   }
 
-  @media all and (-webkit-min-device-pixel-ratio: 1.51) {
+  @media all and not (-webkit-max-device-pixel-ratio: 1.5) {
     #icon1x {
       display: none;
     }
+    #icon2x {
+      display: flex;
+    }
   }
 </style>
 <div class="flex layout vertical" aria-hidden="true">
diff --git a/chrome/browser/resources/chromeos/quickoffice b/chrome/browser/resources/chromeos/quickoffice
index 79e797d..82b2a09 160000
--- a/chrome/browser/resources/chromeos/quickoffice
+++ b/chrome/browser/resources/chromeos/quickoffice
@@ -1 +1 @@
-Subproject commit 79e797d69d4675a2f0ef916dbb65457fe9485fc9
+Subproject commit 82b2a09bf9550c7435a774a6261e6736b787468f
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc b/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc
index 701f053c4..adbe9386 100644
--- a/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc
+++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc
@@ -251,11 +251,6 @@
 void CheckClientDownloadRequest::LogDeepScanningPrompt(bool did_prompt) const {
   if (did_prompt) {
     LogDeepScanEvent(item_, DeepScanEvent::kPromptShown);
-    Profile* profile = Profile::FromBrowserContext(GetBrowserContext());
-    if (profile && profile->GetPrefs()) {
-      profile->GetPrefs()->SetBoolean(prefs::kSafeBrowsingDeepScanPromptSeen,
-                                      true);
-    }
   }
 
   base::UmaHistogramBoolean("SBClientDownload.ServerRequestsDeepScanningPrompt",
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc
index bd8a502..b30a17c 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -505,17 +505,6 @@
         estimated_extended_reporting_by_prefs_ = erl;
       }
     }
-
-    if (IsEnhancedProtectionEnabled(*pref.first)) {
-      if (pref.first->GetTime(prefs::kSafeBrowsingEsbEnabledTimestamp)
-              .is_null()) {
-        pref.first->SetTime(prefs::kSafeBrowsingEsbEnabledTimestamp,
-                            base::Time::Now());
-      }
-    } else {
-      pref.first->SetTime(prefs::kSafeBrowsingEsbEnabledTimestamp,
-                          base::Time());
-    }
   }
 
   if (enabled_by_prefs_) {
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.h b/chrome/browser/safe_browsing/safe_browsing_service.h
index aebf8c92..ebc340e 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.h
+++ b/chrome/browser/safe_browsing/safe_browsing_service.h
@@ -79,7 +79,6 @@
 class SafeBrowsingUIManager;
 class TriggerManager;
 class HashRealTimeService;
-class SafeBrowsingServiceTest;
 
 // Construction needs to happen on the main thread.
 // The SafeBrowsingService owns both the UI and Database managers which do
@@ -237,7 +236,7 @@
   friend class SafeBrowsingBlockingPageTestBase;
   friend class SafeBrowsingBlockingQuietPageTest;
   friend class extensions::SafeBrowsingPrivateApiUnitTest;
-  friend class SafeBrowsingServiceTest;
+  friend class SafeBrowsingServerTest;
   friend class SafeBrowsingUIManagerTest;
   friend class TestSafeBrowsingService;
   friend class TestSafeBrowsingServiceFactory;
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_service_unittest.cc
index 41ff86f..59a2a0d 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service_unittest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service_unittest.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
-
 #include <memory>
 
 #include "base/test/bind.h"
@@ -15,7 +14,6 @@
 #include "chrome/test/base/testing_profile.h"
 #include "components/download/public/common/download_danger_type.h"
 #include "components/download/public/common/mock_download_item.h"
-#include "components/prefs/pref_service.h"
 #include "components/safe_browsing/content/browser/safe_browsing_service_interface.h"
 #include "components/safe_browsing/core/browser/ping_manager.h"
 #include "components/safe_browsing/core/common/proto/csd.pb.h"
@@ -65,7 +63,6 @@
     // dependency of PingManager on ChromeOS.
     TestingBrowserProcess::GetGlobal()->SetLocalState(profile_->GetPrefs());
 #endif
-    sb_service_->OnProfileAdded(profile_.get());
   }
 
   void TearDown() override {
@@ -249,33 +246,6 @@
       /*show_download_in_folder=*/true));
 }
 
-TEST_F(SafeBrowsingServiceTest, EsbEnabledTimestampOnlyWhenEsbEnabled) {
-  SetSafeBrowsingState(profile_->GetPrefs(),
-                       safe_browsing::SafeBrowsingState::ENHANCED_PROTECTION,
-                       /*is_esb_enabled_in_sync=*/false);
-  EXPECT_FALSE(profile_->GetPrefs()
-                   ->GetTime(prefs::kSafeBrowsingEsbEnabledTimestamp)
-                   .is_null());
-  SetSafeBrowsingState(profile_->GetPrefs(),
-                       safe_browsing::SafeBrowsingState::STANDARD_PROTECTION,
-                       /*is_esb_enabled_in_sync=*/false);
-  EXPECT_TRUE(profile_->GetPrefs()
-                  ->GetTime(prefs::kSafeBrowsingEsbEnabledTimestamp)
-                  .is_null());
-}
-
-TEST_F(SafeBrowsingServiceTest, DoesNotChangeEsbTimestampIfPresent) {
-  profile_->GetPrefs()->SetTime(prefs::kSafeBrowsingEsbEnabledTimestamp,
-                                base::Time::FromTimeT(12345));
-  SetSafeBrowsingState(profile_->GetPrefs(),
-                       safe_browsing::SafeBrowsingState::ENHANCED_PROTECTION,
-                       /*is_esb_enabled_in_sync=*/false);
-  EXPECT_EQ(profile_->GetPrefs()
-                ->GetTime(prefs::kSafeBrowsingEsbEnabledTimestamp)
-                .ToTimeT(),
-            12345);
-}
-
 class SafeBrowsingServiceAntiPhishingTelemetryTest
     : public SafeBrowsingServiceTest {
  protected:
diff --git a/chrome/browser/sync/test/integration/password_manager_sync_test.cc b/chrome/browser/sync/test/integration/password_manager_sync_test.cc
index 739104b..7de017109 100644
--- a/chrome/browser/sync/test/integration/password_manager_sync_test.cc
+++ b/chrome/browser/sync/test/integration/password_manager_sync_test.cc
@@ -1147,7 +1147,7 @@
             SyncTest::kDefaultUserEmail);
   EXPECT_EQ(
       password_manager::sync_util::GetPasswordSyncState(GetSyncService(0)),
-      password_manager::sync_util::SyncState::kSyncingNormalEncryption);
+      password_manager::sync_util::SyncState::kActiveWithNormalEncryption);
 
   // Enter a persistent auth error state.
   GetClient(0)->EnterSyncPausedStateForPrimaryAccount();
diff --git a/chrome/browser/ui/ash/faster_split_screen_browsertest.cc b/chrome/browser/ui/ash/faster_split_screen_browsertest.cc
index 32f40ec7..1349ec4d 100644
--- a/chrome/browser/ui/ash/faster_split_screen_browsertest.cc
+++ b/chrome/browser/ui/ash/faster_split_screen_browsertest.cc
@@ -104,3 +104,23 @@
   ASSERT_TRUE(settings_browser);
   ASSERT_EQ(os_settings, GetActiveUrl(settings_browser));
 }
+
+// Tests that if partial overview is active, and a window gets session
+// restore'd, partial overview auto-snaps the window. See b/314816288.
+IN_PROC_BROWSER_TEST_F(FasterSplitScreenBrowserTest,
+                       AutoSnapWhileInSessionRestore) {
+  // Snap the window to start partial overview.
+  aura::Window* window = browser()->window()->GetNativeWindow();
+  ash::WindowState* window_state = ash::WindowState::Get(window);
+  const ash::WindowSnapWMEvent primary_snap_event(
+      ash::WM_EVENT_SNAP_PRIMARY, ash::WindowSnapActionSource::kTest);
+  window_state->OnWMEvent(&primary_snap_event);
+  ash::WaitForOverviewEnterAnimation();
+  ASSERT_TRUE(ash::OverviewController::Get()->InOverviewSession());
+
+  // Open a new browser window. Test it gets auto-snapped.
+  Browser* browser2 = CreateBrowser(browser()->profile());
+  aura::Window* window2 = browser2->window()->GetNativeWindow();
+  EXPECT_TRUE(ash::WindowState::Get(window2)->IsSnapped());
+  EXPECT_FALSE(ash::OverviewController::Get()->InOverviewSession());
+}
diff --git a/chrome/browser/ui/ash/picker/picker_client_impl.cc b/chrome/browser/ui/ash/picker/picker_client_impl.cc
index 6179d0b..4af5602 100644
--- a/chrome/browser/ui/ash/picker/picker_client_impl.cc
+++ b/chrome/browser/ui/ash/picker/picker_client_impl.cc
@@ -20,7 +20,6 @@
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/simple_url_loader.h"
-#include "url/gurl.h"
 #include "url/url_constants.h"
 
 namespace {
@@ -62,16 +61,12 @@
 }
 
 void PickerClientImpl::DownloadGifToString(
-    const GURL& url,
+    const ash::ValidGifUrl& url,
     DownloadGifToStringCallback callback) {
   DCHECK(profile_);
-  // For now, only allow gifs from tenor.
-  // TODO: b/316936723 - Once we know what gifs the picker might show, consider
-  // making the method parameters more specific to allowed gif sources.
-  CHECK(url.DomainIs("media.tenor.com") && url.SchemeIs(url::kHttpsScheme));
 
   auto resource_request = std::make_unique<network::ResourceRequest>();
-  resource_request->url = url;
+  resource_request->url = url.ToGURL();
   resource_request->method = "GET";
   resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
 
diff --git a/chrome/browser/ui/ash/picker/picker_client_impl.h b/chrome/browser/ui/ash/picker/picker_client_impl.h
index 6380b69a..8c65c5f 100644
--- a/chrome/browser/ui/ash/picker/picker_client_impl.h
+++ b/chrome/browser/ui/ash/picker/picker_client_impl.h
@@ -34,7 +34,7 @@
   // ash::PickerClient:
   std::unique_ptr<ash::AshWebView> CreateWebView(
       const ash::AshWebView::InitParams& params) override;
-  void DownloadGifToString(const GURL& url,
+  void DownloadGifToString(const ash::ValidGifUrl& url,
                            DownloadGifToStringCallback callback) override;
 
   // user_manager::UserManager::UserSessionStateObserver:
diff --git a/chrome/browser/ui/passwords/bubble_controllers/manage_passwords_bubble_controller.cc b/chrome/browser/ui/passwords/bubble_controllers/manage_passwords_bubble_controller.cc
index f5c08dc..34f9b2b 100644
--- a/chrome/browser/ui/passwords/bubble_controllers/manage_passwords_bubble_controller.cc
+++ b/chrome/browser/ui/passwords/bubble_controllers/manage_passwords_bubble_controller.cc
@@ -6,6 +6,7 @@
 
 #include "base/containers/span.h"
 #include "base/functional/bind.h"
+#include "base/notreached.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/password_manager/account_password_store_factory.h"
@@ -111,11 +112,20 @@
       &favicon_tracker_);
 }
 
-password_manager::sync_util::SyncState
-ManagePasswordsBubbleController::GetPasswordSyncState() {
+ManagePasswordsBubbleController::SyncState
+ManagePasswordsBubbleController::GetPasswordSyncState() const {
   const syncer::SyncService* sync_service =
       SyncServiceFactory::GetForProfile(GetProfile());
-  return password_manager::sync_util::GetPasswordSyncState(sync_service);
+  switch (password_manager::sync_util::GetPasswordSyncState(sync_service)) {
+    case password_manager::sync_util::SyncState::kNotActive:
+      return SyncState::kNotActive;
+    case password_manager::sync_util::SyncState::kActiveWithNormalEncryption:
+    case password_manager::sync_util::SyncState::kActiveWithCustomPassphrase:
+      return sync_service->IsSyncFeatureEnabled()
+                 ? SyncState::kActiveWithSyncFeatureEnabled
+                 : SyncState::kActiveWithAccountPasswords;
+  }
+  NOTREACHED_NORETURN();
 }
 
 std::u16string ManagePasswordsBubbleController::GetPrimaryAccountEmail() {
diff --git a/chrome/browser/ui/passwords/bubble_controllers/manage_passwords_bubble_controller.h b/chrome/browser/ui/passwords/bubble_controllers/manage_passwords_bubble_controller.h
index 11401a9b..20492cd5 100644
--- a/chrome/browser/ui/passwords/bubble_controllers/manage_passwords_bubble_controller.h
+++ b/chrome/browser/ui/passwords/bubble_controllers/manage_passwords_bubble_controller.h
@@ -25,15 +25,17 @@
 
 namespace password_manager {
 class PasswordStoreInterface;
-
-namespace sync_util {
-enum class SyncState;
-}  // namespace sync_util
 }  // namespace password_manager
 
 // This controller provides data and actions for the ManagePasswordsView.
 class ManagePasswordsBubbleController : public PasswordBubbleControllerBase {
  public:
+  enum class SyncState {
+    kNotActive,
+    kActiveWithSyncFeatureEnabled,
+    kActiveWithAccountPasswords,
+  };
+
   explicit ManagePasswordsBubbleController(
       base::WeakPtr<PasswordsModelDelegate> delegate);
   ~ManagePasswordsBubbleController() override;
@@ -50,7 +52,7 @@
   void RequestFavicon(
       base::OnceCallback<void(const gfx::Image&)> favicon_ready_callback);
 
-  password_manager::sync_util::SyncState GetPasswordSyncState();
+  SyncState GetPasswordSyncState() const;
 
   // Returns the email of current primary account. Returns empty string if no
   // account is signed in.
diff --git a/chrome/browser/ui/passwords/bubble_controllers/manage_passwords_bubble_controller_unittest.cc b/chrome/browser/ui/passwords/bubble_controllers/manage_passwords_bubble_controller_unittest.cc
index 7f8b3b5..075bd585 100644
--- a/chrome/browser/ui/passwords/bubble_controllers/manage_passwords_bubble_controller_unittest.cc
+++ b/chrome/browser/ui/passwords/bubble_controllers/manage_passwords_bubble_controller_unittest.cc
@@ -21,7 +21,6 @@
 #include "components/password_manager/core/browser/password_manager_client.h"
 #include "components/password_manager/core/browser/password_manager_test_utils.h"
 #include "components/password_manager/core/browser/password_store/mock_password_store_interface.h"
-#include "components/password_manager/core/browser/password_sync_util.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/signin/public/identity_manager/identity_test_utils.h"
 #include "components/sync/test/test_sync_service.h"
@@ -200,23 +199,28 @@
       /*types=*/syncer::UserSelectableTypeSet());
 
   EXPECT_EQ(controller()->GetPasswordSyncState(),
-            password_manager::sync_util::SyncState::kNotActive);
+            ManagePasswordsBubbleController::SyncState::kNotActive);
 
   sync_service()->GetUserSettings()->SetSelectedTypes(
       /*sync_everything=*/false,
       /*types=*/{syncer::UserSelectableType::kPasswords});
-  EXPECT_EQ(controller()->GetPasswordSyncState(),
-            password_manager::sync_util::SyncState::
-                kAccountPasswordsActiveNormalEncryption);
+  ASSERT_FALSE(sync_service()->IsSyncFeatureEnabled());
 
-  sync_service()->SetHasSyncConsent(true);
-  EXPECT_EQ(controller()->GetPasswordSyncState(),
-            password_manager::sync_util::SyncState::kSyncingNormalEncryption);
-
-  sync_service()->SetIsUsingExplicitPassphrase(true);
   EXPECT_EQ(
       controller()->GetPasswordSyncState(),
-      password_manager::sync_util::SyncState::kSyncingWithCustomPassphrase);
+      ManagePasswordsBubbleController::SyncState::kActiveWithAccountPasswords);
+
+  sync_service()->SetHasSyncConsent(true);
+  ASSERT_TRUE(sync_service()->IsSyncFeatureEnabled());
+
+  EXPECT_EQ(controller()->GetPasswordSyncState(),
+            ManagePasswordsBubbleController::SyncState::
+                kActiveWithSyncFeatureEnabled);
+
+  sync_service()->SetIsUsingExplicitPassphrase(true);
+  EXPECT_EQ(controller()->GetPasswordSyncState(),
+            ManagePasswordsBubbleController::SyncState::
+                kActiveWithSyncFeatureEnabled);
 }
 
 TEST_F(ManagePasswordsBubbleControllerTest, ShouldGetPrimaryAccountEmail) {
diff --git a/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller.cc b/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller.cc
index 453c09b..294e872 100644
--- a/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller.cc
+++ b/chrome/browser/ui/passwords/bubble_controllers/save_update_bubble_controller.cc
@@ -86,12 +86,8 @@
   CHECK(profile);
   const syncer::SyncService* sync_service =
       SyncServiceFactory::GetForProfile(profile);
-  password_manager::sync_util::SyncState sync_state =
-      password_manager::sync_util::GetPasswordSyncState(sync_service);
-  return sync_state ==
-             password_manager::sync_util::SyncState::kSyncingNormalEncryption ||
-         sync_state == password_manager::sync_util::SyncState::
-                           kSyncingWithCustomPassphrase;
+  return password_manager::sync_util::IsSyncFeatureActiveIncludingPasswords(
+      sync_service);
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc
index 16ee723..f4c71cb 100644
--- a/chrome/browser/ui/ui_features.cc
+++ b/chrome/browser/ui/ui_features.cc
@@ -333,6 +333,12 @@
              "TearOffWebAppTabOpensWebAppWindow",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+#if !defined(ANDROID)
+BASE_FEATURE(kToolbarPinning,
+             "ToolbarPinning",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+#endif
+
 BASE_FEATURE(kToolbarUseHardwareBitmapDraw,
              "ToolbarUseHardwareBitmapDraw",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h
index 2f08fb5..90de44b6 100644
--- a/chrome/browser/ui/ui_features.h
+++ b/chrome/browser/ui/ui_features.h
@@ -213,6 +213,8 @@
 
 BASE_DECLARE_FEATURE(kTearOffWebAppTabOpensWebAppWindow);
 
+BASE_DECLARE_FEATURE(kToolbarPinning);
+
 // Determines how screenshots of the toolbar uses Software or Hardware drawing.
 // Works on Android 10+.
 BASE_DECLARE_FEATURE(kToolbarUseHardwareBitmapDraw);
diff --git a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc
index c1b6348..1b685e1 100644
--- a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc
+++ b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc
@@ -1461,13 +1461,13 @@
   OnSodaProgress(12);
   ASSERT_FALSE(GetLabel()->GetVisible());
   ASSERT_TRUE(GetDownloadProgressLabel()->GetVisible());
-  ASSERT_EQ(u"Downloading French language pack...12%",
+  ASSERT_EQ(u"Downloading French language pack\x2026 12%",
             GetDownloadProgressLabel()->GetText());
 
   OnPartialTranscription(
       "Tasmanian devils hold the chomping champ title for mammals, crushing "
       "bone with a bite four times their own weight.");
-  ASSERT_EQ(u"Downloading French language pack...12%",
+  ASSERT_EQ(u"Downloading French language pack\x2026 12%",
             GetDownloadProgressLabel()->GetText());
 
   OnSodaInstalled();
diff --git a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.cc b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.cc
index 70ea430..41488dc 100644
--- a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.cc
+++ b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_linux.cc
@@ -358,6 +358,14 @@
                new_tiled_edges.bottom || new_tiled_edges.right;
   browser_frame_->set_tiled(tiled && !maximized);
   UpdateFrameHints();
+  if (SupportsClientFrameShadow()) {
+    // Trigger a re-layout as the insets will change even if the bounds don't.
+    ScheduleRelayout();
+    if (GetWidget()->non_client_view()) {
+      // This is needed for the decorated regions, borders etc. to be repainted.
+      GetWidget()->non_client_view()->SchedulePaint();
+    }
+  }
 }
 
 void BrowserDesktopWindowTreeHostLinux::OnNativeThemeUpdated(
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
index ed56e75..c603d26 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
@@ -127,6 +127,10 @@
   // through in the code but is short enough that it is essentially skipped.
   void ReduceAnimationTimeForTesting();
 
+  // Enables tests to reset slide animation to a state where the label is not
+  // showing.
+  void ResetSlideAnimationForTesting() { ResetSlideAnimation(false); }
+
  protected:
   static constexpr int kOpenTimeMS = 150;
 
diff --git a/chrome/browser/ui/views/location_bar/read_anything_icon_view.cc b/chrome/browser/ui/views/location_bar/read_anything_icon_view.cc
index 092d0ff1..dd8cbcc0 100644
--- a/chrome/browser/ui/views/location_bar/read_anything_icon_view.cc
+++ b/chrome/browser/ui/views/location_bar/read_anything_icon_view.cc
@@ -17,6 +17,15 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 
+namespace {
+
+// The time, in seconds, which the label is shown, before animating out again.
+// This number was chosen to be long enough for target users, who are slower
+// readers, to read the label.
+constexpr auto kLabelShownDuration = base::Seconds(3);
+
+}  // namespace
+
 ReadAnythingIconView::ReadAnythingIconView(
     CommandUpdater* command_updater,
     Browser* browser,
@@ -28,11 +37,13 @@
                          page_action_icon_delegate,
                          "ReadAnythingIcon",
                          true),
+      label_shown_count_(browser->profile()->GetPrefs()->GetInteger(
+          prefs::kAccessibilityReadAnythingOmniboxIconLabelShownCount)),
       browser_(browser) {
   DCHECK(browser_);
 
   SetActive(false);
-  SetLabel(l10n_util::GetStringUTF16(IDS_READING_MODE_TITLE));
+  SetUpForInOutAnimation(kLabelShownDuration);
 
   coordinator_ = ReadAnythingCoordinator::FromBrowser(browser_);
   if (coordinator_) {
@@ -56,21 +67,28 @@
   return kMenuBookChromeRefreshIcon;
 }
 
-bool ReadAnythingIconView::ShouldShowLabel() const {
-  // Only show the label a maximum of kReadAnythingOmniboxIconLabelShownCountMax
-  // times.
-  PrefService* prefs = browser_->profile()->GetPrefs();
-  int label_shown_count = prefs->GetInteger(
-      prefs::kAccessibilityReadAnythingOmniboxIconLabelShownCount);
-  if (label_shown_count < kReadAnythingOmniboxIconLabelShownCountMax) {
-    return true;
+void ReadAnythingIconView::UpdateImpl() {
+  if (GetVisible() != should_be_visible_) {
+    SetVisible(should_be_visible_);
+    base::UmaHistogramBoolean("Accessibility.ReadAnything.OmniboxIconShown",
+                              should_be_visible_);
   }
-  return false;
+  if (!should_be_visible_ || is_animating_label() ||
+      (label_shown_count_ >= kReadAnythingOmniboxIconLabelShownCountMax)) {
+    return;
+  }
+  ResetSlideAnimation(false);
+  AnimateIn(IDS_READING_MODE_TITLE);
+  ++label_shown_count_;
+  browser_->profile()->GetPrefs()->SetInteger(
+      prefs::kAccessibilityReadAnythingOmniboxIconLabelShownCount,
+      label_shown_count_);
 }
 
 void ReadAnythingIconView::Activate(bool active) {
   if (active) {
-    SetVisible(false);
+    should_be_visible_ = false;
+    Update();
     base::UmaHistogramBoolean("Accessibility.ReadAnything.OmniboxIconShown",
                               false);
   }
@@ -84,23 +102,8 @@
   if (IsReadAnythingEntryShowing(browser_)) {
     return;
   }
-  SetVisible(distillable);
-  base::UmaHistogramBoolean("Accessibility.ReadAnything.OmniboxIconShown",
-                            distillable);
-
-  // Increase `prefs::kAccessibilityReadAnythingOmniboxIconLabelShownCount` up
-  // to its max to denote that the icon was shown.
-  if (!distillable) {
-    return;
-  }
-  PrefService* prefs = browser_->profile()->GetPrefs();
-  int label_shown_count = prefs->GetInteger(
-      prefs::kAccessibilityReadAnythingOmniboxIconLabelShownCount);
-  if (label_shown_count < kReadAnythingOmniboxIconLabelShownCountMax) {
-    prefs->SetInteger(
-        prefs::kAccessibilityReadAnythingOmniboxIconLabelShownCount,
-        label_shown_count + 1);
-  }
+  should_be_visible_ = distillable;
+  Update();
 }
 
 BEGIN_METADATA(ReadAnythingIconView)
diff --git a/chrome/browser/ui/views/location_bar/read_anything_icon_view.h b/chrome/browser/ui/views/location_bar/read_anything_icon_view.h
index 77a377269..81d268f1 100644
--- a/chrome/browser/ui/views/location_bar/read_anything_icon_view.h
+++ b/chrome/browser/ui/views/location_bar/read_anything_icon_view.h
@@ -28,12 +28,11 @@
 
  protected:
   // PageActionIconView:
-  void UpdateImpl() override {}
+  void UpdateImpl() override;
   void OnExecuting(PageActionIconView::ExecuteSource execute_source) override {}
   void ExecuteCommand(ExecuteSource source) override;
   views::BubbleDialogDelegate* GetBubble() const override;
   const gfx::VectorIcon& GetVectorIcon() const override;
-  bool ShouldShowLabel() const override;
 
   // ReadAnythingCoordinator::Observer:
   void Activate(bool active) override;
@@ -41,6 +40,15 @@
   void OnCoordinatorDestroyed() override;
 
  private:
+  // Whether this view should be visible, so that the next time UpdateImpl() is
+  // called, the view visibility is set to this value.
+  bool should_be_visible_ = false;
+
+  // The number of times the label was shown. On construction, caches the value
+  // `prefs::kAccessibilityReadAnythingOmniboxIconLabelShownCount`. When the
+  // value changes, updates the pref.
+  int label_shown_count_;
+
   const raw_ptr<Browser> browser_;
   raw_ptr<ReadAnythingCoordinator> coordinator_;
   base::ScopedObservation<ReadAnythingCoordinator,
diff --git a/chrome/browser/ui/views/location_bar/read_anything_icon_view_interactive_uitest.cc b/chrome/browser/ui/views/location_bar/read_anything_icon_view_interactive_uitest.cc
index 353ef43..65e9824 100644
--- a/chrome/browser/ui/views/location_bar/read_anything_icon_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/location_bar/read_anything_icon_view_interactive_uitest.cc
@@ -52,6 +52,11 @@
     GetReadAnythingCoordinator()->ActivePageNotDistillableForTesting();
   }
 
+  int GetLabelShownCountFromPref() const {
+    return browser()->profile()->GetPrefs()->GetInteger(
+        prefs::kAccessibilityReadAnythingOmniboxIconLabelShownCount);
+  }
+
  private:
   ReadAnythingCoordinator* GetReadAnythingCoordinator() {
     return ReadAnythingCoordinator::GetOrCreateForBrowser(browser());
@@ -100,17 +105,22 @@
   EXPECT_FALSE(icon->GetVisible());
 }
 
-// The label only shows the first 3 times that the icon is shown.
+// The label only shows the first kReadAnythingOmniboxIconLabelShownCountMax
+// times that the icon is shown.
 IN_PROC_BROWSER_TEST_F(ReadAnythingIconViewTest, ShowLabel3Times) {
-  browser()->profile()->GetPrefs()->SetInteger(
-      prefs::kAccessibilityReadAnythingOmniboxIconLabelShownCount, 0);
-
   PageActionIconView* icon = GetReadAnythingOmniboxIcon();
-  for (int i = 0; i < 3; i++) {
-    EXPECT_TRUE(icon->ShouldShowLabel());
+  for (int i = 0; i < kReadAnythingOmniboxIconLabelShownCountMax; i++) {
+    EXPECT_EQ(i, GetLabelShownCountFromPref());
     SetActivePageDistillable();
+    EXPECT_TRUE(icon->ShouldShowLabel());
+    EXPECT_TRUE(icon->is_animating_label());
+    icon->ResetSlideAnimationForTesting();
   }
+  EXPECT_EQ(3, GetLabelShownCountFromPref());
+  SetActivePageDistillable();
   EXPECT_FALSE(icon->ShouldShowLabel());
+  EXPECT_FALSE(icon->is_animating_label());
+  EXPECT_EQ(3, GetLabelShownCountFromPref());
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_view.cc b/chrome/browser/ui/views/passwords/manage_passwords_view.cc
index 7ce24bf..d1c0c75a 100644
--- a/chrome/browser/ui/views/passwords/manage_passwords_view.cc
+++ b/chrome/browser/ui/views/passwords/manage_passwords_view.cc
@@ -20,7 +20,6 @@
 #include "chrome/browser/ui/views/passwords/views_utils.h"
 #include "chrome/grit/branded_strings.h"
 #include "chrome/grit/generated_resources.h"
-#include "components/password_manager/core/browser/password_manager_client.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/browser/password_sync_util.h"
 #include "components/password_manager/core/common/password_manager_constants.h"
@@ -198,15 +197,15 @@
       base::Unretained(this));
 
   switch (controller_.GetPasswordSyncState()) {
-    case password_manager::sync_util::SyncState::kNotActive:
+    case ManagePasswordsBubbleController::SyncState::kNotActive:
       return CreateGooglePasswordManagerLabel(
           /*text_message_id=*/
           IDS_PASSWORD_BUBBLES_FOOTER_SAVING_ON_DEVICE,
           /*link_message_id=*/
           IDS_PASSWORD_BUBBLES_PASSWORD_MANAGER_LINK_TEXT_SAVING_ON_DEVICE,
           open_password_manager_closure, views::style::CONTEXT_BUBBLE_FOOTER);
-    case password_manager::sync_util::SyncState::kSyncingNormalEncryption:
-    case password_manager::sync_util::SyncState::kSyncingWithCustomPassphrase:
+    case ManagePasswordsBubbleController::SyncState::
+        kActiveWithSyncFeatureEnabled:
       return CreateGooglePasswordManagerLabel(
           /*text_message_id=*/
           IDS_PASSWORD_BUBBLES_FOOTER_SYNCED_TO_ACCOUNT,
@@ -214,8 +213,8 @@
           IDS_PASSWORD_BUBBLES_PASSWORD_MANAGER_LINK_TEXT_SYNCED_TO_ACCOUNT,
           controller_.GetPrimaryAccountEmail(), open_password_manager_closure,
           views::style::CONTEXT_BUBBLE_FOOTER);
-    case password_manager::sync_util::SyncState::
-        kAccountPasswordsActiveNormalEncryption:
+    case ManagePasswordsBubbleController::SyncState::
+        kActiveWithAccountPasswords:
       // Account store users have a special footer in the management bubble
       // since they might have a mix of synced and non-synced passwords.
       return CreateGooglePasswordManagerLabel(
@@ -224,10 +223,6 @@
           /*link_message_id=*/
           IDS_PASSWORD_BUBBLES_PASSWORD_MANAGER_LINK_TEXT_SYNCED_TO_ACCOUNT,
           open_password_manager_closure, views::style::CONTEXT_BUBBLE_FOOTER);
-    case password_manager::sync_util::SyncState::
-        kAccountPasswordsActiveWithCustomPassphrase:
-      // Unreachable on desktop platforms.
-      NOTREACHED_NORETURN();
   }
 }
 
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
index c592f23b..e864e22 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -137,11 +137,7 @@
         tab_);
   }
 
-  bool IsCommandIdAlerted(int command_id) const override {
-    return command_id == TabStripModel::CommandAddToNewGroup &&
-           controller_->GetBrowser()->window()->IsFeaturePromoActive(
-               feature_engagement::kIPHDesktopTabGroupsNewGroupFeature);
-  }
+  bool IsCommandIdAlerted(int command_id) const override { return false; }
 
   bool GetAcceleratorForCommandId(int command_id,
                                   ui::Accelerator* accelerator) const override {
diff --git a/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.cc b/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.cc
index 79fb7bb..2dbb73e 100644
--- a/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.cc
+++ b/chrome/browser/ui/views/tabs/tab_group_editor_bubble_view.cc
@@ -566,14 +566,6 @@
 }
 
 void TabGroupEditorBubbleView::OnBubbleClose() {
-  // If we're doing the "create a tab group" tutorial, note whether the user
-  // actually entered a tab name.
-  if (browser_->window()->IsFeaturePromoActive(
-          feature_engagement::kIPHDesktopTabGroupsNewGroupFeature)) {
-    UMA_HISTOGRAM_BOOLEAN("Tutorial.TabGroup.EditedTitle",
-                          !title_field_->GetText().empty());
-  }
-
   if (title_at_opening_ != title_field_->GetText()) {
     base::RecordAction(
         base::UserMetricsAction("TabGroups_TabGroupBubble_NameChanged"));
diff --git a/chrome/browser/ui/views/toolbar/toolbar_controller_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/toolbar_controller_interactive_uitest.cc
index a6d7817..5ef1bd1 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_controller_interactive_uitest.cc
@@ -607,8 +607,7 @@
 class ToolbarControllerIphUiTest : public ToolbarControllerUiTest {
  public:
   ToolbarControllerIphUiTest() {
-    iph_feature_list_.InitForDemo(
-        feature_engagement::kIPHDesktopTabGroupsNewGroupFeature);
+    iph_feature_list_.InitForDemo(feature_engagement::kIPHTabSearchFeature);
   }
   ~ToolbarControllerIphUiTest() override = default;
 
@@ -619,7 +618,7 @@
     return CheckResult(
         [this]() {
           return browser()->window()->MaybeShowFeaturePromo(
-              feature_engagement::kIPHDesktopTabGroupsNewGroupFeature);
+              feature_engagement::kIPHTabSearchFeature);
         },
         expected_result, desc.str());
   }
diff --git a/chrome/browser/ui/views/user_education/browser_user_education_service.cc b/chrome/browser/ui/views/user_education/browser_user_education_service.cc
index dc1d663..b29f1d0 100644
--- a/chrome/browser/ui/views/user_education/browser_user_education_service.cc
+++ b/chrome/browser/ui/views/user_education/browser_user_education_service.cc
@@ -126,8 +126,6 @@
 
 }  // namespace
 
-const char kSideSearchTutorialId[] = "Side Search Tutorial";
-
 user_education::HelpBubbleDelegate* GetHelpBubbleDelegate() {
   static base::NoDestructor<BrowserHelpBubbleDelegate> delegate;
   return delegate.get();
@@ -217,15 +215,6 @@
                         89, "phillis@chromium.org",
                         "User navigates to a page with a promotable PWA."))));
 
-  // kIPHDesktopTabGroupsNewGroupFeature:
-  registry.RegisterFeature(
-      std::move(FeaturePromoSpecification::CreateForTutorialPromo(
-                    feature_engagement::kIPHDesktopTabGroupsNewGroupFeature,
-                    kTabStripRegionElementId, IDS_TAB_GROUPS_NEW_GROUP_PROMO,
-                    kTabGroupTutorialId)
-                    .SetBubbleArrow(HelpBubbleArrow::kNone)
-                    .SetBubbleIcon(kLightbulbOutlineIcon)));
-
   // kIPHDesktopCustomizeChromeFeature:
   registry.RegisterFeature(std::move(
       FeaturePromoSpecification::CreateForCustomAction(
@@ -692,8 +681,7 @@
               // These are not required features; they are just an example to
               // ensure that the tester page formats this data correctly.
               FeaturePromoSpecification::Metadata::FeatureSet{
-                  &feature_engagement::kIPHWebUiHelpBubbleTestFeature,
-                  &feature_engagement::kIPHDesktopTabGroupsNewGroupFeature})));
+                  &feature_engagement::kIPHWebUiHelpBubbleTestFeature})));
 
   // kIPHBatterySaverModeFeature:
   registry.RegisterFeature(std::move(
@@ -849,21 +837,6 @@
     return;
   }
 
-  {  // Menu item bubble test.
-    TutorialDescription test_description;
-    test_description.steps = {
-        BubbleStep(kToolbarAppMenuButtonElementId)
-            .SetBubbleBodyText(IDS_OK)
-            .SetBubbleArrow(HelpBubbleArrow::kTopRight),
-        BubbleStep(AppMenuModel::kDownloadsMenuItem)
-            .SetBubbleBodyText(IDS_OK)
-            .SetBubbleArrow(HelpBubbleArrow::kRightCenter),
-        HiddenStep::WaitForHidden(AppMenuModel::kDownloadsMenuItem),
-        BubbleStep(kTopContainerElementId).SetBubbleBodyText(IDS_OK)};
-    tutorial_registry.AddTutorial("Menu item bubble test tutorial",
-                                  std::move(test_description));
-  }
-
   // Tab Group tutorial.
   tutorial_registry.AddTutorial(
       kTabGroupTutorialId,
diff --git a/chrome/browser/ui/views/user_education/browser_user_education_service_browsertest.cc b/chrome/browser/ui/views/user_education/browser_user_education_service_browsertest.cc
index 5849d3d7..452d220 100644
--- a/chrome/browser/ui/views/user_education/browser_user_education_service_browsertest.cc
+++ b/chrome/browser/ui/views/user_education/browser_user_education_service_browsertest.cc
@@ -259,8 +259,6 @@
        IPHFailureReason::kWrongSessionRate, "crbug.com/1443063"},
       {&feature_engagement::kIPHDesktopCustomizeChromeRefreshFeature,
        IPHFailureReason::kWrongSessionImpact, "crbug.com/1443063"},
-      {&feature_engagement::kIPHDesktopTabGroupsNewGroupFeature,
-       IPHFailureReason::kWrongSessionRate, "crbug.com/1443063"},
       {&feature_engagement::kIPHSideSearchFeature,
        IPHFailureReason::kWrongSessionRate, "crbug.com/1443063"},
       {&feature_engagement::kIPHMemorySaverModeFeature,
diff --git a/chrome/browser/ui/views/user_education/feature_promo_dialog_interactive_uitest.cc b/chrome/browser/ui/views/user_education/feature_promo_dialog_interactive_uitest.cc
index fcc02c7..528541c 100644
--- a/chrome/browser/ui/views/user_education/feature_promo_dialog_interactive_uitest.cc
+++ b/chrome/browser/ui/views/user_education/feature_promo_dialog_interactive_uitest.cc
@@ -233,12 +233,6 @@
   ShowAndVerifyUi();
 }
 
-IN_PROC_BROWSER_TEST_F(FeaturePromoDialogTest,
-                       InvokeUi_IPH_DesktopTabGroupsNewGroup) {
-  set_baseline("4067389");
-  ShowAndVerifyUi();
-}
-
 IN_PROC_BROWSER_TEST_F(FeaturePromoDialogTest, InvokeUi_IPH_LiveCaption) {
   if (!captions::IsLiveCaptionFeatureSupported())
     return;
diff --git a/chrome/browser/ui/views/user_education/product_messaging_controller_interactive_uitest.cc b/chrome/browser/ui/views/user_education/product_messaging_controller_interactive_uitest.cc
index 4cd1565f..3b9fc088 100644
--- a/chrome/browser/ui/views/user_education/product_messaging_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/user_education/product_messaging_controller_interactive_uitest.cc
@@ -24,7 +24,7 @@
  public:
   ProductMessagingControllerUiTest() {
     feature_list_.InitAndEnableFeatures(
-        {feature_engagement::kIPHDesktopTabGroupsNewGroupFeature});
+        {feature_engagement::kIPHTabSearchFeature});
   }
 
   ~ProductMessagingControllerUiTest() override = default;
@@ -53,14 +53,13 @@
   auto CheckShowPromo(user_education::FeaturePromoResult expected_result) {
     std::ostringstream oss;
     oss << "CheckShowPromo(" << expected_result << ")";
-    return std::move(
-        CheckResult(
-            [this]() {
-              return browser()->window()->MaybeShowFeaturePromo(
-                  feature_engagement::kIPHDesktopTabGroupsNewGroupFeature);
-            },
-            expected_result)
-            .SetDescription(oss.str().c_str()));
+    return std::move(CheckResult(
+                         [this]() {
+                           return browser()->window()->MaybeShowFeaturePromo(
+                               feature_engagement::kIPHTabSearchFeature);
+                         },
+                         expected_result)
+                         .SetDescription(oss.str().c_str()));
   }
 
   auto EnsureHandle() {
diff --git a/chrome/browser/ui/webui/ash/settings/pages/multitasking/multitasking_section.cc b/chrome/browser/ui/webui/ash/settings/pages/multitasking/multitasking_section.cc
index 1e3e330f..7841f73 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/multitasking/multitasking_section.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/multitasking/multitasking_section.cc
@@ -21,6 +21,27 @@
 using ::chromeos::settings::mojom::Subpage;
 }  // namespace mojom
 
+namespace {
+
+const std::vector<SearchConcept>& GetSnapWindowSuggestionsSearchConcepts() {
+  static const base::NoDestructor<std::vector<SearchConcept>> tags({
+      {IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW,
+       mojom::kSystemPreferencesSectionPath,
+       mojom::SearchResultIcon::kSnapWindowSuggestions,
+       mojom::SearchResultDefaultRank::kMedium,
+       mojom::SearchResultType::kSetting,
+       {.setting = mojom::Setting::kSnapWindowSuggestions},
+       {IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW_ALT1,
+        IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW_ALT2,
+        IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW_ALT3,
+        IDS_OS_SETTINGS_TAG_MULTITASKING_SNAP_WINDOW_ALT4,
+        SearchConcept::kAltTagEnd}},
+  });
+  return *tags;
+}
+
+}  // namespace
+
 MultitaskingSection::MultitaskingSection(Profile* profile,
                                          SearchTagRegistry* search_tag_registry)
     : OsSettingsSection(profile, search_tag_registry) {
@@ -28,7 +49,10 @@
   CHECK(search_tag_registry);
   CHECK(ash::features::IsOsSettingsRevampWayfindingEnabled());
 
-  // TODO(sophiewen): Add multitasking search tags.
+  if (ShouldShowMultitasking()) {
+    SearchTagRegistry::ScopedTagUpdater updater = registry()->StartUpdate();
+    updater.AddSearchTags(GetSnapWindowSuggestionsSearchConcepts());
+  }
 }
 
 MultitaskingSection::~MultitaskingSection() = default;
diff --git a/chrome/browser/ui/webui/ash/settings/search/mojom/search_result_icon.mojom b/chrome/browser/ui/webui/ash/settings/search/mojom/search_result_icon.mojom
index d0f47a1..f2806b7 100644
--- a/chrome/browser/ui/webui/ash/settings/search/mojom/search_result_icon.mojom
+++ b/chrome/browser/ui/webui/ash/settings/search/mojom/search_result_icon.mojom
@@ -66,6 +66,7 @@
   kSearch,
   kSelectToSpeak,
   kShield,
+  kSnapWindowSuggestions,
   kStorage,
   kStylus,
   kSwitchAccess,
diff --git a/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc b/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
index 4adb0bb..8e9d2f6 100644
--- a/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
@@ -395,7 +395,9 @@
           url::Origin::Create(GURL(*dict.FindString("frame_origin"))),
           net::SchemefulSite(GURL(*dict.FindString("top_frame_site")))),
       network::mojom::SharedDictionaryInfo::New(
-          *dict.FindString("match"), GURL(*dict.FindString("dictionary_url")),
+          *dict.FindString("match"),
+          /*match_dest=*/std::vector<network::mojom::RequestDestination>(),
+          /*id=*/"", GURL(*dict.FindString("dictionary_url")),
           ToTime(dict.FindString("response_time")->c_str()),
           base::Seconds(*dict.FindInt("expiration")),
           ToTime(dict.FindString("last_used_time")->c_str()),
diff --git a/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc b/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc
index 935d3af..ef5e666 100644
--- a/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc
+++ b/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc
@@ -540,7 +540,7 @@
   const ui::ElementContext context = browser->window()->GetElementContext();
   CHECK(context);
 
-  user_education::TutorialIdentifier tutorial_id = kTabGroupTutorialId;
+  user_education::TutorialIdentifier tutorial_id = kSavedTabGroupTutorialId;
   tutorial_service->StartTutorial(tutorial_id, context);
 }
 
diff --git a/chrome/browser/user_education/user_education_service.cc b/chrome/browser/user_education/user_education_service.cc
index 5b64328..68b6c64 100644
--- a/chrome/browser/user_education/user_education_service.cc
+++ b/chrome/browser/user_education/user_education_service.cc
@@ -15,6 +15,7 @@
     "Side Panel Customize Chrome Tutorial";
 const char kTabGroupTutorialId[] = "Tab Group Tutorial";
 const char kSavedTabGroupTutorialId[] = "Saved Tab Group Tutorial";
+const char kSideSearchTutorialId[] = "Side Search Tutorial";
 const char kPasswordManagerTutorialId[] = "Password Manager Tutorial";
 
 UserEducationService::UserEducationService(
diff --git a/chrome/browser/user_education/user_education_service.h b/chrome/browser/user_education/user_education_service.h
index 976d2f98..53d2005 100644
--- a/chrome/browser/user_education/user_education_service.h
+++ b/chrome/browser/user_education/user_education_service.h
@@ -21,6 +21,7 @@
 extern const char kTabGroupTutorialId[];
 extern const char kSavedTabGroupTutorialId[];
 extern const char kSidePanelCustomizeChromeTutorialId[];
+extern const char kSideSearchTutorialId[];
 extern const char kPasswordManagerTutorialId[];
 
 class UserEducationService : public KeyedService {
diff --git a/chrome/build/lacros64.pgo.txt b/chrome/build/lacros64.pgo.txt
index 8d87585..781fe50f 100644
--- a/chrome/build/lacros64.pgo.txt
+++ b/chrome/build/lacros64.pgo.txt
@@ -1 +1 @@
-chrome-chromeos-amd64-generic-main-1707134433-5b13e95cc4ee223afe8d27988a425dc908c8b593.profdata
+chrome-chromeos-amd64-generic-main-1707177813-6d45c8b00f3860366b239f4c6b0e164f714e7766.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 23d2afe..cbb15bc 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1707154473-ecd2011c5d936b3235a193485760fcd7c24ca1ba.profdata
+chrome-linux-main-1707199177-3ffa5f2d59e628fc0e0050b3b530cf388455642e.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index febd3ea..4e5657c7 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1707177403-4a0d6c36070e061fe8cc29b0efbd3a1898fac03c.profdata
+chrome-mac-arm-main-1707206165-2cec8cfd5acfe2ba02e30042d0698539b7073f21.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index 510da5a..de0b5c2a 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1707111819-4b0282601a3e8dcd03b883519335ed1c7b862a2e.profdata
+chrome-win-arm64-main-1707199177-577e093e014d329e5d4a6f2a2e33f2a85f1699d0.profdata
diff --git a/chrome/installer/linux/common/rpm.include b/chrome/installer/linux/common/rpm.include
index 31ba8cb..58d649d 100644
--- a/chrome/installer/linux/common/rpm.include
+++ b/chrome/installer/linux/common/rpm.include
@@ -17,6 +17,8 @@
     "4EB27DB2A3B88B8B"
     # 2023 signing subkey
     "E88979FB9B30ACF2"
+    # 2024 signing subkey
+    "32EE5355A6BC6E42"
   )
 
   for SUB_KEY in "${SUB_KEY_LIST[@]}"; do
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index 2b84b53..8933b4e2 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -22,6 +22,7 @@
 #include <utility>
 
 #include "base/command_line.h"
+#include "base/containers/span.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -168,7 +169,7 @@
   static_assert(sizeof(base::MD5Digest) == 16, "size of MD5 not as expected");
   base::MD5Digest md5_digest;
   std::string user_sid_ascii(base::WideToASCII(user_sid));
-  base::MD5Sum(user_sid_ascii.c_str(), user_sid_ascii.length(), &md5_digest);
+  base::MD5Sum(base::as_byte_span(user_sid_ascii), &md5_digest);
   std::string base32_md5 = base32::Base32Encode(
       md5_digest.a, base32::Base32EncodePolicy::OMIT_PADDING);
   // The value returned by the base32 algorithm above must never change.
diff --git a/chrome/services/sharing/nearby/platform/crypto.cc b/chrome/services/sharing/nearby/platform/crypto.cc
index 1ac508d..a853b57 100644
--- a/chrome/services/sharing/nearby/platform/crypto.cc
+++ b/chrome/services/sharing/nearby/platform/crypto.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/nearby/src/internal/platform/implementation/crypto.h"
 
+#include "base/containers/span.h"
 #include "base/hash/md5.h"
 #include "base/memory/ptr_util.h"
 #include "crypto/sha2.h"
@@ -20,7 +21,7 @@
     return ByteArray();
 
   base::MD5Digest digest;
-  base::MD5Sum(input.data(), input.length(), &digest);
+  base::MD5Sum(base::as_byte_span(input), &digest);
   return ByteArray(std::string(std::begin(digest.a), std::end(digest.a)));
 }
 
diff --git a/chrome/services/speech/cros_speech_recognition_recognizer_impl.cc b/chrome/services/speech/cros_speech_recognition_recognizer_impl.cc
index de6e3e3..69d511f 100644
--- a/chrome/services/speech/cros_speech_recognition_recognizer_impl.cc
+++ b/chrome/services/speech/cros_speech_recognition_recognizer_impl.cc
@@ -8,7 +8,9 @@
 
 #include "base/containers/flat_map.h"
 #include "base/files/file_path.h"
+#include "base/logging.h"
 #include "chrome/services/speech/soda/cros_soda_client.h"
+#include "components/soda/constants.h"
 #include "google_apis/google_api_keys.h"
 #include "media/base/audio_buffer.h"
 #include "media/base/audio_sample_types.h"
@@ -104,6 +106,27 @@
     config->library_dlc_path = binary_path_.value();
     config->recognition_mode =
         GetSodaSpeechRecognitionMode(options_->recognition_mode);
+    if (options_->recognition_mode ==
+            media::mojom::SpeechRecognitionMode::kCaption &&
+        base::FeatureList::IsEnabled(media::kLiveCaptionMultiLanguage)) {
+      auto live_caption_languages = speech::GetLiveCaptionEnabledLanguages();
+      auto multi_lang_config =
+          chromeos::machine_learning::mojom::SodaMultilangConfig::New();
+
+      for (const auto& config_path : config_paths()) {
+        if (config_path.first == primary_language_name()) {
+          continue;
+        } else if (!base::Contains(live_caption_languages, config_path.first)) {
+          VLOG(1) << "Skipping multilang on captions of " << config_path.first
+                  << " as it is not listed as a live caption language.";
+          continue;
+        }
+        multi_lang_config->locale_to_language_pack_map[config_path.first] =
+            config_path.second.value();
+      }
+      config->multi_lang_config = std::move(multi_lang_config);
+    }
+
     config->enable_formatting =
         options_->enable_formatting
             ? chromeos::machine_learning::mojom::OptionalBool::kTrue
diff --git a/chrome/updater/util/util.h b/chrome/updater/util/util.h
index a727b4c6..a94c46c 100644
--- a/chrome/updater/util/util.h
+++ b/chrome/updater/util/util.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_UPDATER_UTIL_UTIL_H_
 #define CHROME_UPDATER_UTIL_UTIL_H_
 
+#include <cmath>
+#include <concepts>
 #include <optional>
 #include <ostream>
 #include <string>
@@ -225,6 +227,13 @@
 // Delete everything other than `except` under `except.DirName()`.
 [[nodiscard]] bool DeleteExcept(const std::optional<base::FilePath>& except);
 
+// Returns the quotient of dividing two integer numbers (m/n) rounded up.
+template <typename T>
+  requires std::integral<T>
+[[nodiscard]] constexpr T CeilingDivide(T m, T n) {
+  return std::ceil(static_cast<double>(m) / n);
+}
+
 }  // namespace updater
 
 #endif  // CHROME_UPDATER_UTIL_UTIL_H_
diff --git a/chrome/updater/util/util_unittest.cc b/chrome/updater/util/util_unittest.cc
index e660654..3cca4603 100644
--- a/chrome/updater/util/util_unittest.cc
+++ b/chrome/updater/util/util_unittest.cc
@@ -139,4 +139,34 @@
   test::ExpectOnlyMockUpdater(except_executable);
 }
 
+TEST(Util, CeilingDivide) {
+  EXPECT_EQ(CeilingDivide(0, 1), 0);
+  EXPECT_EQ(CeilingDivide(1, 2), 1);
+  EXPECT_EQ(CeilingDivide(1, 1), 1);
+  EXPECT_EQ(CeilingDivide(3, 2), 2);
+  EXPECT_EQ(CeilingDivide(5, 3), 2);
+  EXPECT_EQ(CeilingDivide(4, 2), 2);
+
+  EXPECT_EQ(CeilingDivide(-1, 2), 0);
+  EXPECT_EQ(CeilingDivide(-1, 1), -1);
+  EXPECT_EQ(CeilingDivide(-3, 2), -1);
+  EXPECT_EQ(CeilingDivide(-5, 3), -1);
+  EXPECT_EQ(CeilingDivide(-2, 1), -2);
+  EXPECT_EQ(CeilingDivide(-4, 2), -2);
+
+  EXPECT_EQ(CeilingDivide(1, -2), 0);
+  EXPECT_EQ(CeilingDivide(1, -1), -1);
+  EXPECT_EQ(CeilingDivide(3, -2), -1);
+  EXPECT_EQ(CeilingDivide(5, -3), -1);
+  EXPECT_EQ(CeilingDivide(2, -1), -2);
+  EXPECT_EQ(CeilingDivide(4, -2), -2);
+
+  EXPECT_EQ(CeilingDivide(-0, -1), 0);
+  EXPECT_EQ(CeilingDivide(-1, -2), 1);
+  EXPECT_EQ(CeilingDivide(-1, -1), 1);
+  EXPECT_EQ(CeilingDivide(-3, -2), 2);
+  EXPECT_EQ(CeilingDivide(-5, -3), 2);
+  EXPECT_EQ(CeilingDivide(-4, -2), 2);
+}
+
 }  // namespace updater
diff --git a/chrome/updater/win/ui/progress_wnd.cc b/chrome/updater/win/ui/progress_wnd.cc
index 02053108..3da8ec3 100644
--- a/chrome/updater/win/ui/progress_wnd.cc
+++ b/chrome/updater/win/ui/progress_wnd.cc
@@ -21,6 +21,7 @@
 #include "base/win/scoped_localalloc.h"
 #include "chrome/updater/app/app_install_progress.h"
 #include "chrome/updater/app/app_install_util_win.h"
+#include "chrome/updater/util/util.h"
 #include "chrome/updater/util/win_util.h"
 #include "chrome/updater/win/ui/l10n_util.h"
 #include "chrome/updater/win/ui/resources/updater_installer_strings.h"
diff --git a/chrome/updater/win/ui/ui_util.h b/chrome/updater/win/ui/ui_util.h
index 78b1a94..caa882e 100644
--- a/chrome/updater/win/ui/ui_util.h
+++ b/chrome/updater/win/ui/ui_util.h
@@ -11,8 +11,6 @@
 #include <string>
 #include <vector>
 
-#include "base/check_op.h"
-
 namespace updater::ui {
 
 // Finds all the primary windows owned by the given process. A primary window is
@@ -43,15 +41,6 @@
 // the friendly company name is used.
 std::wstring GetInstallerDisplayName(const std::u16string& bundle_name);
 
-// Returns the quotient of the two numbers (m/n) rounded upwards to the
-// nearest integer type. T should be unsigned integer type, such as unsigned
-// short, unsigned long, unsigned int etc.
-template <typename T>
-inline T CeilingDivide(T m, T n) {
-  CHECK_NE(0, n);
-  return (m + n - 1) / n;
-}
-
 // Gets the text corresponding to a control in a dialog box.
 bool GetDlgItemText(HWND dlg, int item_id, std::wstring* text);
 
diff --git a/chromecast/crash/cast_crash_storage.h b/chromecast/crash/cast_crash_storage.h
index 9c47a87..199313d 100644
--- a/chromecast/crash/cast_crash_storage.h
+++ b/chromecast/crash/cast_crash_storage.h
@@ -5,7 +5,7 @@
 #ifndef CHROMECAST_CRASH_CAST_CRASH_STORAGE_H_
 #define CHROMECAST_CRASH_CAST_CRASH_STORAGE_H_
 
-#include "base/strings/string_piece.h"
+#include <string_view>
 
 namespace chromecast {
 
@@ -19,16 +19,16 @@
   CastCrashStorage() = default;
   virtual ~CastCrashStorage() = default;
 
-  virtual void SetLastLaunchedApp(base::StringPiece app_id) = 0;
+  virtual void SetLastLaunchedApp(std::string_view app_id) = 0;
   virtual void ClearLastLaunchedApp() = 0;
 
-  virtual void SetCurrentApp(base::StringPiece app_id) = 0;
+  virtual void SetCurrentApp(std::string_view app_id) = 0;
   virtual void ClearCurrentApp() = 0;
 
-  virtual void SetPreviousApp(base::StringPiece app_id) = 0;
+  virtual void SetPreviousApp(std::string_view app_id) = 0;
   virtual void ClearPreviousApp() = 0;
 
-  virtual void SetStadiaSessionId(base::StringPiece session_id) = 0;
+  virtual void SetStadiaSessionId(std::string_view session_id) = 0;
   virtual void ClearStadiaSessionId() = 0;
 };
 
diff --git a/chromecast/crash/cast_crash_storage_impl.cc b/chromecast/crash/cast_crash_storage_impl.cc
index b342ac4..6ef66d0 100644
--- a/chromecast/crash/cast_crash_storage_impl.cc
+++ b/chromecast/crash/cast_crash_storage_impl.cc
@@ -4,6 +4,8 @@
 
 #include "chromecast/crash/cast_crash_storage_impl.h"
 
+#include <string_view>
+
 #include "chromecast/crash/cast_crash_keys.h"
 #include "components/crash/core/common/crash_key.h"
 
@@ -21,7 +23,7 @@
 CastCrashStorageImpl::CastCrashStorageImpl() = default;
 CastCrashStorageImpl::~CastCrashStorageImpl() = default;
 
-void CastCrashStorageImpl::SetLastLaunchedApp(base::StringPiece app_id) {
+void CastCrashStorageImpl::SetLastLaunchedApp(std::string_view app_id) {
   last_app.Set(app_id);
 }
 
@@ -29,7 +31,7 @@
   last_app.Clear();
 }
 
-void CastCrashStorageImpl::SetCurrentApp(base::StringPiece app_id) {
+void CastCrashStorageImpl::SetCurrentApp(std::string_view app_id) {
   current_app.Set(app_id);
 }
 
@@ -37,7 +39,7 @@
   current_app.Clear();
 }
 
-void CastCrashStorageImpl::SetPreviousApp(base::StringPiece app_id) {
+void CastCrashStorageImpl::SetPreviousApp(std::string_view app_id) {
   previous_app.Set(app_id);
 }
 
@@ -45,7 +47,7 @@
   previous_app.Clear();
 }
 
-void CastCrashStorageImpl::SetStadiaSessionId(base::StringPiece session_id) {
+void CastCrashStorageImpl::SetStadiaSessionId(std::string_view session_id) {
   stadia_session_id.Set(session_id);
 }
 
diff --git a/chromecast/crash/cast_crash_storage_impl.h b/chromecast/crash/cast_crash_storage_impl.h
index bc4e51e2f..450f3af 100644
--- a/chromecast/crash/cast_crash_storage_impl.h
+++ b/chromecast/crash/cast_crash_storage_impl.h
@@ -5,6 +5,8 @@
 #ifndef CHROMECAST_CRASH_CAST_CRASH_STORAGE_IMPL_H_
 #define CHROMECAST_CRASH_CAST_CRASH_STORAGE_IMPL_H_
 
+#include <string_view>
+
 #include "chromecast/crash/cast_crash_storage.h"
 
 namespace chromecast {
@@ -17,13 +19,13 @@
   CastCrashStorageImpl(const CastCrashStorageImpl&) = delete;
 
   // CastCrashStorage implementation:
-  void SetLastLaunchedApp(base::StringPiece app_id) override;
+  void SetLastLaunchedApp(std::string_view app_id) override;
   void ClearLastLaunchedApp() override;
-  void SetCurrentApp(base::StringPiece app_id) override;
+  void SetCurrentApp(std::string_view app_id) override;
   void ClearCurrentApp() override;
-  void SetPreviousApp(base::StringPiece app_id) override;
+  void SetPreviousApp(std::string_view app_id) override;
   void ClearPreviousApp() override;
-  void SetStadiaSessionId(base::StringPiece session_id) override;
+  void SetStadiaSessionId(std::string_view session_id) override;
   void ClearStadiaSessionId() override;
 };
 
diff --git a/chromecast/crash/fuchsia/cast_crash_storage_impl_fuchsia.cc b/chromecast/crash/fuchsia/cast_crash_storage_impl_fuchsia.cc
index 99f6b0d..678c2913 100644
--- a/chromecast/crash/fuchsia/cast_crash_storage_impl_fuchsia.cc
+++ b/chromecast/crash/fuchsia/cast_crash_storage_impl_fuchsia.cc
@@ -6,6 +6,8 @@
 
 #include <fuchsia/feedback/cpp/fidl.h>
 
+#include <string_view>
+
 #include "base/fuchsia/fuchsia_logging.h"
 #include "chromecast/crash/fuchsia/constants.h"
 
@@ -17,8 +19,8 @@
 const char kPreviousApp[] = "app.previous";
 const char kStadiaSessionId[] = "stadia-session-id";
 
-fuchsia::feedback::Annotation MakeAnnotation(base::StringPiece key,
-                                             base::StringPiece value) {
+fuchsia::feedback::Annotation MakeAnnotation(std::string_view key,
+                                             std::string_view value) {
   fuchsia::feedback::Annotation annotation;
   annotation.key = std::string(key);
   annotation.value = std::string(value);
@@ -35,37 +37,37 @@
 
 CastCrashStorageImplFuchsia::~CastCrashStorageImplFuchsia() = default;
 
-void CastCrashStorageImplFuchsia::SetLastLaunchedApp(base::StringPiece app_id) {
+void CastCrashStorageImplFuchsia::SetLastLaunchedApp(std::string_view app_id) {
   UpsertAnnotations({MakeAnnotation(kLastLaunchedApp, app_id)});
 }
 
 void CastCrashStorageImplFuchsia::ClearLastLaunchedApp() {
-  UpsertAnnotations({MakeAnnotation(kLastLaunchedApp, base::StringPiece())});
+  UpsertAnnotations({MakeAnnotation(kLastLaunchedApp, std::string_view())});
 }
 
-void CastCrashStorageImplFuchsia::SetCurrentApp(base::StringPiece app_id) {
+void CastCrashStorageImplFuchsia::SetCurrentApp(std::string_view app_id) {
   UpsertAnnotations({MakeAnnotation(kCurrentApp, app_id)});
 }
 
 void CastCrashStorageImplFuchsia::ClearCurrentApp() {
-  UpsertAnnotations({MakeAnnotation(kCurrentApp, base::StringPiece())});
+  UpsertAnnotations({MakeAnnotation(kCurrentApp, std::string_view())});
 }
 
-void CastCrashStorageImplFuchsia::SetPreviousApp(base::StringPiece app_id) {
+void CastCrashStorageImplFuchsia::SetPreviousApp(std::string_view app_id) {
   UpsertAnnotations({MakeAnnotation(kPreviousApp, app_id)});
 }
 
 void CastCrashStorageImplFuchsia::ClearPreviousApp() {
-  UpsertAnnotations({MakeAnnotation(kPreviousApp, base::StringPiece())});
+  UpsertAnnotations({MakeAnnotation(kPreviousApp, std::string_view())});
 }
 
 void CastCrashStorageImplFuchsia::SetStadiaSessionId(
-    base::StringPiece session_id) {
+    std::string_view session_id) {
   UpsertAnnotations({MakeAnnotation(kStadiaSessionId, session_id)});
 }
 
 void CastCrashStorageImplFuchsia::ClearStadiaSessionId() {
-  UpsertAnnotations({MakeAnnotation(kStadiaSessionId, base::StringPiece())});
+  UpsertAnnotations({MakeAnnotation(kStadiaSessionId, std::string_view())});
 }
 
 void CastCrashStorageImplFuchsia::UpsertAnnotations(
diff --git a/chromecast/crash/fuchsia/cast_crash_storage_impl_fuchsia.h b/chromecast/crash/fuchsia/cast_crash_storage_impl_fuchsia.h
index 2f1aa6d9..5a633ef60 100644
--- a/chromecast/crash/fuchsia/cast_crash_storage_impl_fuchsia.h
+++ b/chromecast/crash/fuchsia/cast_crash_storage_impl_fuchsia.h
@@ -8,6 +8,8 @@
 #include <fuchsia/feedback/cpp/fidl.h>
 #include <lib/sys/cpp/service_directory.h>
 
+#include <string_view>
+
 #include "chromecast/crash/cast_crash_storage.h"
 
 namespace chromecast {
@@ -22,13 +24,13 @@
   CastCrashStorageImplFuchsia(const CastCrashStorageImplFuchsia&) = delete;
 
   // CastCrashStorage implementation:
-  void SetLastLaunchedApp(base::StringPiece app_id) override;
+  void SetLastLaunchedApp(std::string_view app_id) override;
   void ClearLastLaunchedApp() override;
-  void SetCurrentApp(base::StringPiece app_id) override;
+  void SetCurrentApp(std::string_view app_id) override;
   void ClearCurrentApp() override;
-  void SetPreviousApp(base::StringPiece app_id) override;
+  void SetPreviousApp(std::string_view app_id) override;
   void ClearPreviousApp() override;
-  void SetStadiaSessionId(base::StringPiece session_id) override;
+  void SetStadiaSessionId(std::string_view session_id) override;
   void ClearStadiaSessionId() override;
 
  private:
diff --git a/chromecast/crash/linux/dump_info.cc b/chromecast/crash/linux/dump_info.cc
index d6095bce..c17d3e7 100644
--- a/chromecast/crash/linux/dump_info.cc
+++ b/chromecast/crash/linux/dump_info.cc
@@ -8,6 +8,8 @@
 #include <stddef.h>
 #include <stdlib.h>
 
+#include <string_view>
+
 #include "base/i18n/time_formatting.h"
 #include "base/logging.h"
 #include "base/time/time.h"
@@ -42,7 +44,7 @@
 // statements. If `key` is a string in `dict`, writes it to `out` and returns
 // true. Leaves `out` alone and returns false otherwise.
 bool FindString(const base::Value::Dict& dict,
-                base::StringPiece key,
+                std::string_view key,
                 std::string& out) {
   const std::string* value = dict.FindString(key);
   if (!value)
diff --git a/chromecast/external_mojo/public/cpp/common.cc b/chromecast/external_mojo/public/cpp/common.cc
index 8992770..302e987 100644
--- a/chromecast/external_mojo/public/cpp/common.cc
+++ b/chromecast/external_mojo/public/cpp/common.cc
@@ -4,11 +4,12 @@
 
 #include "chromecast/external_mojo/public/cpp/common.h"
 
+#include <string_view>
+
 #include "base/check.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/path_service.h"
-#include "base/strings/string_piece.h"
 #include "build/build_config.h"
 #include "chromecast/base/chromecast_switches.h"
 
@@ -20,7 +21,7 @@
 #if !BUILDFLAG(IS_ANDROID)
 // Default path for Unix domain socket used by external Mojo services to connect
 // to Mojo services within cast_shell.
-constexpr base::StringPiece kDefaultBrokerPath("/tmp/cast_mojo_broker");
+constexpr std::string_view kDefaultBrokerPath("/tmp/cast_mojo_broker");
 #endif  // !BUILDFLAG(IS_ANDROID)
 
 }  // namespace
diff --git a/chromecast/shared/platform_info_serializer.cc b/chromecast/shared/platform_info_serializer.cc
index 20468c3..73b7e83e 100644
--- a/chromecast/shared/platform_info_serializer.cc
+++ b/chromecast/shared/platform_info_serializer.cc
@@ -4,6 +4,8 @@
 
 #include "chromecast/shared/platform_info_serializer.h"
 
+#include <string_view>
+
 #include "base/check.h"
 #include "base/functional/callback.h"
 #include "base/logging.h"
@@ -28,7 +30,7 @@
 
 // static
 std::optional<PlatformInfoSerializer> PlatformInfoSerializer::Deserialize(
-    base::StringPiece base64) {
+    std::string_view base64) {
   std::optional<cast::bindings::MediaCapabilitiesMessage> proto =
       chromecast::bindings::ProtoSerializer<
           cast::bindings::MediaCapabilitiesMessage>::Deserialize(base64);
diff --git a/chromecast/shared/platform_info_serializer.h b/chromecast/shared/platform_info_serializer.h
index fcb4718..46e3e67 100644
--- a/chromecast/shared/platform_info_serializer.h
+++ b/chromecast/shared/platform_info_serializer.h
@@ -5,11 +5,11 @@
 #ifndef CHROMECAST_SHARED_PLATFORM_INFO_SERIALIZER_H_
 #define CHROMECAST_SHARED_PLATFORM_INFO_SERIALIZER_H_
 
+#include <optional>
 #include <string>
+#include <string_view>
 #include <vector>
 
-#include <optional>
-#include "base/strings/string_piece.h"
 #include "chromecast/public/media/decoder_config.h"
 #include "third_party/cast_core/public/src/proto/bindings/media_capabilities.pb.h"
 
@@ -43,7 +43,7 @@
 
   std::string Serialize() const;
   static std::optional<PlatformInfoSerializer> Deserialize(
-      base::StringPiece base64);
+      std::string_view base64);
 
   // Setters for known valid properties.
   void SetMaxWidth(int max_width);
diff --git a/chromecast/system/reboot/reboot_fuchsia_test.cc b/chromecast/system/reboot/reboot_fuchsia_test.cc
index 0407800f..b0ea1c21 100644
--- a/chromecast/system/reboot/reboot_fuchsia_test.cc
+++ b/chromecast/system/reboot/reboot_fuchsia_test.cc
@@ -13,7 +13,9 @@
 #include <lib/fpromise/result.h>
 #include <lib/sys/cpp/outgoing_directory.h>
 #include <lib/sys/cpp/service_directory.h>
+
 #include <memory>
+#include <string_view>
 #include <tuple>
 
 #include "base/files/file_util.h"
@@ -246,7 +248,7 @@
   base::FilePath full_path_;
 
  protected:
-  base::FilePath GenerateFlagFilePath(const base::StringPiece& name) {
+  base::FilePath GenerateFlagFilePath(std::string_view name) {
     return full_path_.Append(name);
   }
 
diff --git a/chromecast/tracing/ftrace.cc b/chromecast/tracing/ftrace.cc
index 6e33ef1..1ac1051 100644
--- a/chromecast/tracing/ftrace.cc
+++ b/chromecast/tracing/ftrace.cc
@@ -8,10 +8,11 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <string_view>
+
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/ranges/algorithm.h"
-#include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/trace_event/common/trace_event_common.h"
 #include "chromecast/tracing/system_tracing_common.h"
@@ -99,7 +100,7 @@
 
 bool WriteTracingFile(const char* tracing_dir,
                       const char* trace_file,
-                      base::StringPiece contents) {
+                      std::string_view contents) {
   base::FilePath path = base::FilePath(tracing_dir).Append(trace_file);
 
   if (!base::WriteFile(path, contents)) {
@@ -110,7 +111,7 @@
   return true;
 }
 
-bool EnableTraceEvent(const char* tracing_dir, base::StringPiece event) {
+bool EnableTraceEvent(const char* tracing_dir, std::string_view event) {
   base::FilePath path = base::FilePath(tracing_dir).Append(kTraceFileSetEvent);
 
   // Enabling events returns EINVAL if the event does not exist. It is normal
@@ -132,9 +133,9 @@
 
 }  // namespace
 
-bool IsValidCategory(base::StringPiece str) {
+bool IsValidCategory(std::string_view str) {
   for (size_t i = 0; i < kCategoryCount; ++i) {
-    base::StringPiece category(kCategories[i]);
+    std::string_view category(kCategories[i]);
     if (category == str)
       return true;
   }
diff --git a/chromecast/tracing/ftrace.h b/chromecast/tracing/ftrace.h
index 820cd32..6980881 100644
--- a/chromecast/tracing/ftrace.h
+++ b/chromecast/tracing/ftrace.h
@@ -6,16 +6,16 @@
 #define CHROMECAST_TRACING_FTRACE_H_
 
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include "base/files/scoped_file.h"
-#include "base/strings/string_piece.h"
 
 namespace chromecast {
 namespace tracing {
 
 // Returns true if |category| is valid for system tracing.
-bool IsValidCategory(base::StringPiece category);
+bool IsValidCategory(std::string_view category);
 
 // Starts ftrace for the specified categories.
 //
diff --git a/chromecast/tracing/system_tracer.cc b/chromecast/tracing/system_tracer.cc
index 3faa74d..f6e2ec3 100644
--- a/chromecast/tracing/system_tracer.cc
+++ b/chromecast/tracing/system_tracer.cc
@@ -7,6 +7,8 @@
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/un.h>
+
+#include <string_view>
 #include <utility>
 
 #include "base/functional/bind.h"
@@ -49,7 +51,7 @@
   SystemTracerImpl() : buffer_(new char[kBufferSize]) {}
   ~SystemTracerImpl() override { Cleanup(); }
 
-  void StartTracing(base::StringPiece categories,
+  void StartTracing(std::string_view categories,
                     StartTracingCallback callback) override;
 
   void StopTracing(const StopTracingCallback& callback) override;
@@ -93,7 +95,7 @@
   std::string trace_data_;
 };
 
-void SystemTracerImpl::StartTracing(base::StringPiece categories,
+void SystemTracerImpl::StartTracing(std::string_view categories,
                                     StartTracingCallback callback) {
   start_tracing_callback_ = std::move(callback);
   if (state_ != State::INITIAL) {
@@ -244,7 +246,7 @@
   FakeSystemTracer() = default;
   ~FakeSystemTracer() override = default;
 
-  void StartTracing(base::StringPiece categories,
+  void StartTracing(std::string_view categories,
                     StartTracingCallback callback) override {
     std::move(callback).Run(Status::OK);
   }
diff --git a/chromecast/tracing/system_tracer.h b/chromecast/tracing/system_tracer.h
index c31ed119..76a744d 100644
--- a/chromecast/tracing/system_tracer.h
+++ b/chromecast/tracing/system_tracer.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 #include <string>
+#include <string_view>
 
 #include "base/files/file_descriptor_watcher_posix.h"
 #include "base/files/scoped_file.h"
@@ -35,7 +36,7 @@
       base::RepeatingCallback<void(Status status, std::string trace_data)>;
 
   // Start system tracing for categories in |categories| (comma separated).
-  virtual void StartTracing(base::StringPiece categories,
+  virtual void StartTracing(std::string_view categories,
                             StartTracingCallback callback) = 0;
 
   // Stop system tracing.
diff --git a/chromecast/tracing/tracing_service_main.cc b/chromecast/tracing/tracing_service_main.cc
index 068c866..5f034aa4 100644
--- a/chromecast/tracing/tracing_service_main.cc
+++ b/chromecast/tracing/tracing_service_main.cc
@@ -8,7 +8,9 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/un.h>
+
 #include <memory>
+#include <string_view>
 
 #include "base/at_exit.h"
 #include "base/command_line.h"
@@ -66,7 +68,7 @@
   return socket_fd;
 }
 
-std::vector<std::string> ParseCategories(base::StringPiece message) {
+std::vector<std::string> ParseCategories(std::string_view message) {
   std::vector<std::string> requested_categories = base::SplitString(
       message, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
   std::vector<std::string> categories;
@@ -218,12 +220,12 @@
       LOG(INFO) << "connection closed";
       Finish();
     } else {
-      base::StringPiece message(recv_buffer_.get(), bytes);
+      std::string_view message(recv_buffer_.get(), bytes);
       HandleClientMessage(message);
     }
   }
 
-  void HandleClientMessage(base::StringPiece message) {
+  void HandleClientMessage(std::string_view message) {
     if (state_ == State::INITIAL) {
       std::vector<std::string> categories = ParseCategories(message);
 
diff --git a/chromeos/ash/components/dbus/device_management/install_attributes_client_unittest.cc b/chromeos/ash/components/dbus/device_management/install_attributes_client_unittest.cc
index f9f1e67..781e459 100644
--- a/chromeos/ash/components/dbus/device_management/install_attributes_client_unittest.cc
+++ b/chromeos/ash/components/dbus/device_management/install_attributes_client_unittest.cc
@@ -1,15 +1,18 @@
-// Copyright 2023 The Chromium Authors
+// Copyright 2024 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "chromeos/ash/components/dbus/device_management/install_attributes_client.h"
 
+#include <optional>
 #include <string>
 #include <utility>
 
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
+#include "base/memory/ref_counted.h"
 #include "base/task/single_thread_task_runner.h"
+#include "base/test/protobuf_matchers.h"
 #include "base/test/task_environment.h"
 #include "dbus/mock_bus.h"
 #include "dbus/mock_object_proxy.h"
@@ -18,6 +21,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/cros_system_api/dbus/device_management/dbus-constants.h"
 
+using ::base::test::EqualsProto;
 using ::testing::_;
 using ::testing::Invoke;
 using ::testing::Return;
@@ -27,21 +31,13 @@
 
 namespace {
 
-// Runs |callback| with |response|. Needed due to ResponseCallback expecting a
+// Runs `callback` with `response`. Needed due to ResponseCallback expecting a
 // bare pointer rather than an std::unique_ptr.
 void RunResponseCallback(dbus::ObjectProxy::ResponseCallback callback,
                          std::unique_ptr<dbus::Response> response) {
   std::move(callback).Run(response.get());
 }
 
-bool ProtobufEquals(const google::protobuf::MessageLite& a,
-                    const google::protobuf::MessageLite& b) {
-  std::string a_serialized, b_serialized;
-  a.SerializeToString(&a_serialized);
-  b.SerializeToString(&b_serialized);
-  return a_serialized == b_serialized;
-}
-
 // FakeTaskRunner will run all tasks posted to it immediately in the PostTask()
 // call. This class is a helper to ensure that BlockingMethodCaller would work
 // correctly in the unit test. Note that Mock is not used because
@@ -72,10 +68,10 @@
 
  private:
   // For reference counting.
-  ~FakeTaskRunner() override {}
+  ~FakeTaskRunner() override = default;
 };
 
-// Create a callback that would copy the input argument passed to it into |out|.
+// Create a callback that would copy the input argument passed to it into `out`.
 // This is used mostly to create a callback that would catch the reply from
 // dbus.
 template <typename T>
@@ -93,11 +89,11 @@
   void SetUp() override {
     dbus::Bus::Options options;
     options.bus_type = dbus::Bus::SYSTEM;
-    bus_ = new dbus::MockBus(options);
+    bus_ = base::MakeRefCounted<dbus::MockBus>(options);
 
     dbus::ObjectPath object_path =
         dbus::ObjectPath(::device_management::kDeviceManagementServicePath);
-    proxy_ = new dbus::MockObjectProxy(
+    proxy_ = base::MakeRefCounted<dbus::MockObjectProxy>(
         bus_.get(), ::device_management::kDeviceManagementServiceName,
         object_path);
 
@@ -166,7 +162,7 @@
   bool shall_message_parsing_fail_ = false;
 
  private:
-  // Handles calls to |proxy_|'s `CallMethod()`.
+  // Handles calls to `proxy_`'s `CallMethod()`.
   void OnCallMethod(dbus::MethodCall* method_call,
                     int timeout_ms,
                     dbus::ObjectProxy::ResponseCallback* callback) {
@@ -176,9 +172,9 @@
       // 0x02 => Field 0, Type String
       // (0xFF)*6 => Varint, the size of the string, it is not terminated and is
       // a very large value so the parsing will fail.
-      constexpr uint8_t invalid_protobuf[] = {0x02, 0xFF, 0xFF, 0xFF,
+      constexpr uint8_t kInvalidProtobuf[] = {0x02, 0xFF, 0xFF, 0xFF,
                                               0xFF, 0xFF, 0xFF};
-      writer.AppendArrayOfBytes(invalid_protobuf);
+      writer.AppendArrayOfBytes(kInvalidProtobuf);
     } else if (method_call->GetMember() ==
                ::device_management::kInstallAttributesGet) {
       writer.AppendProtoAsArrayOfBytes(expected_install_attributes_get_reply_);
@@ -203,14 +199,14 @@
       writer.AppendProtoAsArrayOfBytes(
           expected_get_firmware_management_parameters_reply_);
     } else {
-      ASSERT_FALSE(true) << "Unrecognized member: " << method_call->GetMember();
+      LOG(FATAL) << "Unrecognized member: " << method_call->GetMember();
     }
     task_environment_.GetMainThreadTaskRunner()->PostTask(
         FROM_HERE, base::BindOnce(RunResponseCallback, std::move(*callback),
                                   std::move(response)));
   }
 
-  // Handles blocking call to |proxy_|'s `CallMethodAndBlock`.
+  // Handles blocking call to `proxy_`'s `CallMethodAndBlock`.
   base::expected<std::unique_ptr<dbus::Response>, dbus::Error>
   OnBlockingCallMethod(dbus::MethodCall* method_call, int timeout_ms) {
     std::unique_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
@@ -219,9 +215,9 @@
       // 0x02 => Field 0, Type String
       // (0xFF)*6 => Varint, the size of the string, it is not terminated and is
       // a very large value so the parsing will fail.
-      constexpr uint8_t invalid_protobuf[] = {0x02, 0xFF, 0xFF, 0xFF,
+      constexpr uint8_t kInvalidProtobuf[] = {0x02, 0xFF, 0xFF, 0xFF,
                                               0xFF, 0xFF, 0xFF};
-      writer.AppendArrayOfBytes(invalid_protobuf);
+      writer.AppendArrayOfBytes(kInvalidProtobuf);
     } else if (method_call->GetMember() ==
                ::device_management::kInstallAttributesGet) {
       writer.AppendProtoAsArrayOfBytes(
@@ -249,202 +245,200 @@
   expected_install_attributes_get_reply_.set_error(
       device_management::DeviceManagementErrorCode::
           DEVICE_MANAGEMENT_ERROR_TPM_DEFEND_LOCK);
-  absl::optional<::device_management::InstallAttributesGetReply> result_reply;
+  std::optional<::device_management::InstallAttributesGetReply> result_reply;
 
   client_->InstallAttributesGet(
       ::device_management::InstallAttributesGetRequest(),
       CreateCopyCallback(&result_reply));
   base::RunLoop().RunUntilIdle();
-  ASSERT_NE(result_reply, absl::nullopt);
-  EXPECT_TRUE(ProtobufEquals(result_reply.value(),
-                             expected_install_attributes_get_reply_));
+  ASSERT_NE(result_reply, std::nullopt);
+  EXPECT_THAT(result_reply.value(),
+              EqualsProto(expected_install_attributes_get_reply_));
 }
 
 TEST_F(InstallAttributesClientTest, InstallAttributesGetInvalidProtobuf) {
   shall_message_parsing_fail_ = true;
-  absl::optional<::device_management::InstallAttributesGetReply> result_reply =
+  std::optional<::device_management::InstallAttributesGetReply> result_reply =
       ::device_management::InstallAttributesGetReply();
 
   client_->InstallAttributesGet(
       ::device_management::InstallAttributesGetRequest(),
       CreateCopyCallback(&result_reply));
   base::RunLoop().RunUntilIdle();
-  ASSERT_EQ(result_reply, absl::nullopt);
+  ASSERT_EQ(result_reply, std::nullopt);
 }
 
 TEST_F(InstallAttributesClientTest, InstallAttributesFinalize) {
   expected_install_attributes_finalize_reply_.set_error(
       device_management::DeviceManagementErrorCode::
           DEVICE_MANAGEMENT_ERROR_TPM_DEFEND_LOCK);
-  absl::optional<::device_management::InstallAttributesFinalizeReply>
+  std::optional<::device_management::InstallAttributesFinalizeReply>
       result_reply;
 
   client_->InstallAttributesFinalize(
       ::device_management::InstallAttributesFinalizeRequest(),
       CreateCopyCallback(&result_reply));
   base::RunLoop().RunUntilIdle();
-  ASSERT_NE(result_reply, absl::nullopt);
-  EXPECT_TRUE(ProtobufEquals(result_reply.value(),
-                             expected_install_attributes_finalize_reply_));
+  ASSERT_NE(result_reply, std::nullopt);
+  EXPECT_THAT(result_reply.value(),
+              EqualsProto(expected_install_attributes_finalize_reply_));
 }
 
 TEST_F(InstallAttributesClientTest, InstallAttributesGetStatus) {
   expected_install_attributes_get_status_reply_.set_error(
       device_management::DeviceManagementErrorCode::
           DEVICE_MANAGEMENT_ERROR_TPM_DEFEND_LOCK);
-  absl::optional<::device_management::InstallAttributesGetStatusReply>
+  std::optional<::device_management::InstallAttributesGetStatusReply>
       result_reply;
 
   client_->InstallAttributesGetStatus(
       ::device_management::InstallAttributesGetStatusRequest(),
       CreateCopyCallback(&result_reply));
   base::RunLoop().RunUntilIdle();
-  ASSERT_NE(result_reply, absl::nullopt);
-  EXPECT_TRUE(ProtobufEquals(result_reply.value(),
-                             expected_install_attributes_get_status_reply_));
+  ASSERT_NE(result_reply, std::nullopt);
+  EXPECT_THAT(result_reply.value(),
+              EqualsProto(expected_install_attributes_get_status_reply_));
 }
 
 TEST_F(InstallAttributesClientTest, RemoveFirmwareManagementParameters) {
   expected_remove_firmware_management_parameters_reply_.set_error(
       device_management::DeviceManagementErrorCode::
           DEVICE_MANAGEMENT_ERROR_TPM_DEFEND_LOCK);
-  absl::optional<::device_management::RemoveFirmwareManagementParametersReply>
+  std::optional<::device_management::RemoveFirmwareManagementParametersReply>
       result_reply;
 
   client_->RemoveFirmwareManagementParameters(
       ::device_management::RemoveFirmwareManagementParametersRequest(),
       CreateCopyCallback(&result_reply));
   base::RunLoop().RunUntilIdle();
-  ASSERT_NE(result_reply, absl::nullopt);
-  EXPECT_TRUE(
-      ProtobufEquals(result_reply.value(),
-                     expected_remove_firmware_management_parameters_reply_));
+  ASSERT_NE(result_reply, std::nullopt);
+  EXPECT_THAT(
+      result_reply.value(),
+      EqualsProto(expected_remove_firmware_management_parameters_reply_));
 }
 
 TEST_F(InstallAttributesClientTest, SetFirmwareManagementParameters) {
   expected_set_firmware_management_parameters_reply_.set_error(
       device_management::DeviceManagementErrorCode::
           DEVICE_MANAGEMENT_ERROR_TPM_DEFEND_LOCK);
-  absl::optional<::device_management::SetFirmwareManagementParametersReply>
+  std::optional<::device_management::SetFirmwareManagementParametersReply>
       result_reply;
 
   client_->SetFirmwareManagementParameters(
       ::device_management::SetFirmwareManagementParametersRequest(),
       CreateCopyCallback(&result_reply));
   base::RunLoop().RunUntilIdle();
-  ASSERT_NE(result_reply, absl::nullopt);
-  EXPECT_TRUE(
-      ProtobufEquals(result_reply.value(),
-                     expected_set_firmware_management_parameters_reply_));
+  ASSERT_NE(result_reply, std::nullopt);
+  EXPECT_THAT(result_reply.value(),
+              EqualsProto(expected_set_firmware_management_parameters_reply_));
 }
 
 TEST_F(InstallAttributesClientTest, GetFirmwareManagementParameters) {
   expected_set_firmware_management_parameters_reply_.set_error(
       device_management::DeviceManagementErrorCode::
           DEVICE_MANAGEMENT_ERROR_TPM_DEFEND_LOCK);
-  absl::optional<::device_management::GetFirmwareManagementParametersReply>
+  std::optional<::device_management::GetFirmwareManagementParametersReply>
       result_reply;
 
   client_->GetFirmwareManagementParameters(
       ::device_management::GetFirmwareManagementParametersRequest(),
       CreateCopyCallback(&result_reply));
   base::RunLoop().RunUntilIdle();
-  ASSERT_NE(result_reply, absl::nullopt);
-  EXPECT_TRUE(
-      ProtobufEquals(result_reply.value(),
-                     expected_get_firmware_management_parameters_reply_));
+  ASSERT_NE(result_reply, std::nullopt);
+  EXPECT_THAT(result_reply.value(),
+              EqualsProto(expected_get_firmware_management_parameters_reply_));
 }
 
 TEST_F(InstallAttributesClientTest, BlockingInstallAttributesGet) {
   expected_blocking_install_attributes_get_reply_.set_error(
       device_management::DeviceManagementErrorCode::
           DEVICE_MANAGEMENT_ERROR_TPM_DEFEND_LOCK);
-  absl::optional<::device_management::InstallAttributesGetReply> result_reply;
+  std::optional<::device_management::InstallAttributesGetReply> result_reply;
 
-  scoped_refptr<FakeTaskRunner> runner = new FakeTaskRunner;
+  auto runner = base::MakeRefCounted<FakeTaskRunner>();
   EXPECT_CALL(*bus_.get(), GetDBusTaskRunner())
       .WillRepeatedly(Return(runner.get()));
 
   result_reply = client_->BlockingInstallAttributesGet(
       ::device_management::InstallAttributesGetRequest());
 
-  ASSERT_NE(result_reply, absl::nullopt);
-  EXPECT_TRUE(ProtobufEquals(result_reply.value(),
-                             expected_blocking_install_attributes_get_reply_));
+  ASSERT_NE(result_reply, std::nullopt);
+  EXPECT_THAT(result_reply.value(),
+              EqualsProto(expected_blocking_install_attributes_get_reply_));
 }
 
 TEST_F(InstallAttributesClientTest,
        BlockingInstallAttributesGetInvalidProtobuf) {
   shall_message_parsing_fail_ = true;
-  absl::optional<::device_management::InstallAttributesGetReply> result_reply =
+  std::optional<::device_management::InstallAttributesGetReply> result_reply =
       ::device_management::InstallAttributesGetReply();
 
-  scoped_refptr<FakeTaskRunner> runner = new FakeTaskRunner;
+  auto runner = base::MakeRefCounted<FakeTaskRunner>();
   EXPECT_CALL(*bus_.get(), GetDBusTaskRunner())
       .WillRepeatedly(Return(runner.get()));
 
   result_reply = client_->BlockingInstallAttributesGet(
       ::device_management::InstallAttributesGetRequest());
 
-  EXPECT_EQ(result_reply, absl::nullopt);
+  EXPECT_EQ(result_reply, std::nullopt);
 }
 
 TEST_F(InstallAttributesClientTest, BlockingInstallAttributesSet) {
   expected_blocking_install_attributes_set_reply_.set_error(
       device_management::DeviceManagementErrorCode::
           DEVICE_MANAGEMENT_ERROR_TPM_DEFEND_LOCK);
-  absl::optional<::device_management::InstallAttributesSetReply> result_reply;
+  std::optional<::device_management::InstallAttributesSetReply> result_reply;
 
-  scoped_refptr<FakeTaskRunner> runner = new FakeTaskRunner;
+  auto runner = base::MakeRefCounted<FakeTaskRunner>();
   EXPECT_CALL(*bus_.get(), GetDBusTaskRunner())
       .WillRepeatedly(Return(runner.get()));
 
   result_reply = client_->BlockingInstallAttributesSet(
       ::device_management::InstallAttributesSetRequest());
 
-  ASSERT_NE(result_reply, absl::nullopt);
-  EXPECT_TRUE(ProtobufEquals(result_reply.value(),
-                             expected_blocking_install_attributes_set_reply_));
+  ASSERT_NE(result_reply, std::nullopt);
+  EXPECT_THAT(result_reply.value(),
+              EqualsProto(expected_blocking_install_attributes_set_reply_));
 }
 
 TEST_F(InstallAttributesClientTest, BlockingInstallAttributesFinalize) {
   expected_blocking_install_attributes_finalize_reply_.set_error(
       device_management::DeviceManagementErrorCode::
           DEVICE_MANAGEMENT_ERROR_TPM_DEFEND_LOCK);
-  absl::optional<::device_management::InstallAttributesFinalizeReply>
+  std::optional<::device_management::InstallAttributesFinalizeReply>
       result_reply;
 
-  scoped_refptr<FakeTaskRunner> runner = new FakeTaskRunner;
+  auto runner = base::MakeRefCounted<FakeTaskRunner>();
   EXPECT_CALL(*bus_.get(), GetDBusTaskRunner())
       .WillRepeatedly(Return(runner.get()));
 
   result_reply = client_->BlockingInstallAttributesFinalize(
       ::device_management::InstallAttributesFinalizeRequest());
 
-  ASSERT_NE(result_reply, absl::nullopt);
-  EXPECT_TRUE(
-      ProtobufEquals(result_reply.value(),
-                     expected_blocking_install_attributes_finalize_reply_));
+  ASSERT_NE(result_reply, std::nullopt);
+  EXPECT_THAT(
+      result_reply.value(),
+      EqualsProto(expected_blocking_install_attributes_finalize_reply_));
 }
 
 TEST_F(InstallAttributesClientTest, BlockingInstallAttributesGetStatus) {
   expected_blocking_install_attributes_get_status_reply_.set_error(
       device_management::DeviceManagementErrorCode::
           DEVICE_MANAGEMENT_ERROR_TPM_DEFEND_LOCK);
-  absl::optional<::device_management::InstallAttributesGetStatusReply>
+  std::optional<::device_management::InstallAttributesGetStatusReply>
       result_reply;
 
-  scoped_refptr<FakeTaskRunner> runner = new FakeTaskRunner;
+  auto runner = base::MakeRefCounted<FakeTaskRunner>();
   EXPECT_CALL(*bus_.get(), GetDBusTaskRunner())
       .WillRepeatedly(Return(runner.get()));
 
   result_reply = client_->BlockingInstallAttributesGetStatus(
       ::device_management::InstallAttributesGetStatusRequest());
 
-  ASSERT_NE(result_reply, absl::nullopt);
-  EXPECT_TRUE(
-      ProtobufEquals(result_reply.value(),
-                     expected_blocking_install_attributes_get_status_reply_));
+  ASSERT_NE(result_reply, std::nullopt);
+  EXPECT_THAT(
+      result_reply.value(),
+      EqualsProto(expected_blocking_install_attributes_get_status_reply_));
 }
 
 }  // namespace ash
diff --git a/chromeos/ash/components/dbus/userdataauth/fake_install_attributes_client.cc b/chromeos/ash/components/dbus/userdataauth/fake_install_attributes_client.cc
deleted file mode 100644
index 11648c0..0000000
--- a/chromeos/ash/components/dbus/userdataauth/fake_install_attributes_client.cc
+++ /dev/null
@@ -1,246 +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 "chromeos/ash/components/dbus/userdataauth/fake_install_attributes_client.h"
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/notreached.h"
-#include "base/path_service.h"
-#include "base/task/single_thread_task_runner.h"
-#include "base/threading/thread_restrictions.h"
-#include "chromeos/ash/components/dbus/cryptohome/rpc.pb.h"
-#include "chromeos/dbus/constants/dbus_paths.h"
-#include "components/policy/proto/install_attributes.pb.h"
-
-namespace ash {
-
-namespace {
-
-// Buffer size for reading install attributes file. 16k should be plenty. The
-// file contains six attributes only (see InstallAttributes::LockDevice).
-constexpr size_t kInstallAttributesFileMaxSize = 16384;
-
-// Used to track the fake instance, mirrors the instance in the base class.
-FakeInstallAttributesClient* g_instance = nullptr;
-
-}  // namespace
-
-FakeInstallAttributesClient::FakeInstallAttributesClient() {
-  DCHECK(!g_instance);
-  g_instance = this;
-
-  base::FilePath cache_path;
-  locked_ = base::PathService::Get(
-                chromeos::dbus_paths::FILE_INSTALL_ATTRIBUTES, &cache_path) &&
-            base::PathExists(cache_path);
-  if (locked_) {
-    LoadInstallAttributes();
-  }
-}
-
-FakeInstallAttributesClient::~FakeInstallAttributesClient() {
-  DCHECK_EQ(this, g_instance);
-  g_instance = nullptr;
-}
-
-// static
-FakeInstallAttributesClient* FakeInstallAttributesClient::Get() {
-  return g_instance;
-}
-
-void FakeInstallAttributesClient::InstallAttributesGet(
-    const ::user_data_auth::InstallAttributesGetRequest& request,
-    InstallAttributesGetCallback callback) {
-  NOTIMPLEMENTED();
-}
-void FakeInstallAttributesClient::InstallAttributesFinalize(
-    const ::user_data_auth::InstallAttributesFinalizeRequest& request,
-    InstallAttributesFinalizeCallback callback) {
-  NOTIMPLEMENTED();
-}
-void FakeInstallAttributesClient::InstallAttributesGetStatus(
-    const ::user_data_auth::InstallAttributesGetStatusRequest& request,
-    InstallAttributesGetStatusCallback callback) {
-  std::optional<::user_data_auth::InstallAttributesGetStatusReply> reply =
-      BlockingInstallAttributesGetStatus(request);
-  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), reply));
-}
-void FakeInstallAttributesClient::RemoveFirmwareManagementParameters(
-    const ::user_data_auth::RemoveFirmwareManagementParametersRequest& request,
-    RemoveFirmwareManagementParametersCallback callback) {
-  remove_firmware_management_parameters_from_tpm_call_count_++;
-  fwmp_flags_ = std::nullopt;
-  ReturnProtobufMethodCallback(
-      ::user_data_auth::RemoveFirmwareManagementParametersReply(),
-      std::move(callback));
-}
-void FakeInstallAttributesClient::SetFirmwareManagementParameters(
-    const ::user_data_auth::SetFirmwareManagementParametersRequest& request,
-    SetFirmwareManagementParametersCallback callback) {
-  if (request.has_fwmp()) {
-    fwmp_flags_ = request.fwmp().flags();
-  }
-  ReturnProtobufMethodCallback(
-      ::user_data_auth::SetFirmwareManagementParametersReply(),
-      std::move(callback));
-}
-void FakeInstallAttributesClient::GetFirmwareManagementParameters(
-    const ::user_data_auth::GetFirmwareManagementParametersRequest& request,
-    GetFirmwareManagementParametersCallback callback) {
-  auto reply = ::user_data_auth::GetFirmwareManagementParametersReply();
-  if (fwmp_flags_) {
-    reply.mutable_fwmp()->set_flags(*fwmp_flags_);
-  } else {
-    reply.set_error(
-        user_data_auth::
-            CRYPTOHOME_ERROR_FIRMWARE_MANAGEMENT_PARAMETERS_INVALID);
-  }
-  ReturnProtobufMethodCallback(reply, std::move(callback));
-}
-std::optional<::user_data_auth::InstallAttributesGetReply>
-FakeInstallAttributesClient::BlockingInstallAttributesGet(
-    const ::user_data_auth::InstallAttributesGetRequest& request) {
-  ::user_data_auth::InstallAttributesGetReply reply;
-  if (install_attrs_.find(request.name()) != install_attrs_.end()) {
-    reply.set_value(install_attrs_[request.name()]);
-  } else {
-    reply.set_error(::user_data_auth::CryptohomeErrorCode::
-                        CRYPTOHOME_ERROR_INSTALL_ATTRIBUTES_GET_FAILED);
-  }
-  return reply;
-}
-std::optional<::user_data_auth::InstallAttributesSetReply>
-FakeInstallAttributesClient::BlockingInstallAttributesSet(
-    const ::user_data_auth::InstallAttributesSetRequest& request) {
-  ::user_data_auth::InstallAttributesSetReply reply;
-  install_attrs_[request.name()] = request.value();
-  return reply;
-}
-std::optional<::user_data_auth::InstallAttributesFinalizeReply>
-FakeInstallAttributesClient::BlockingInstallAttributesFinalize(
-    const ::user_data_auth::InstallAttributesFinalizeRequest& request) {
-  locked_ = true;
-  ::user_data_auth::InstallAttributesFinalizeReply reply;
-
-  // Persist the install attributes so that they can be reloaded if the
-  // browser is restarted. This is used for ease of development when device
-  // enrollment is required.
-  base::FilePath cache_path;
-  if (!base::PathService::Get(chromeos::dbus_paths::FILE_INSTALL_ATTRIBUTES,
-                              &cache_path)) {
-    reply.set_error(::user_data_auth::CryptohomeErrorCode::
-                        CRYPTOHOME_ERROR_INSTALL_ATTRIBUTES_FINALIZE_FAILED);
-    return reply;
-  }
-
-  cryptohome::SerializedInstallAttributes install_attrs_proto;
-  for (const auto& it : install_attrs_) {
-    const std::string& name = it.first;
-    const std::string& value = it.second;
-    cryptohome::SerializedInstallAttributes::Attribute* attr_entry =
-        install_attrs_proto.add_attributes();
-    attr_entry->set_name(name);
-    attr_entry->set_value(value);
-  }
-
-  std::string result;
-  install_attrs_proto.SerializeToString(&result);
-
-  // The real implementation does a blocking wait on the dbus call; the fake
-  // implementation must have this file written before returning.
-  base::ScopedAllowBlockingForTesting allow_io;
-  base::WriteFile(cache_path, result);
-
-  return reply;
-}
-std::optional<::user_data_auth::InstallAttributesGetStatusReply>
-FakeInstallAttributesClient::BlockingInstallAttributesGetStatus(
-    const ::user_data_auth::InstallAttributesGetStatusRequest& request) {
-  ::user_data_auth::InstallAttributesGetStatusReply reply;
-  if (locked_) {
-    reply.set_state(user_data_auth::InstallAttributesState::VALID);
-  } else {
-    reply.set_state(user_data_auth::InstallAttributesState::FIRST_INSTALL);
-  }
-  return reply;
-}
-
-void FakeInstallAttributesClient::WaitForServiceToBeAvailable(
-    chromeos::WaitForServiceToBeAvailableCallback callback) {
-  if (service_is_available_ || service_reported_not_available_) {
-    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
-        FROM_HERE, base::BindOnce(std::move(callback), service_is_available_));
-  } else {
-    pending_wait_for_service_to_be_available_callbacks_.push_back(
-        std::move(callback));
-  }
-}
-
-void FakeInstallAttributesClient::SetServiceIsAvailable(bool is_available) {
-  service_is_available_ = is_available;
-  if (!is_available) {
-    return;
-  }
-
-  std::vector<chromeos::WaitForServiceToBeAvailableCallback> callbacks;
-  callbacks.swap(pending_wait_for_service_to_be_available_callbacks_);
-  for (auto& callback : callbacks) {
-    std::move(callback).Run(true);
-  }
-}
-
-void FakeInstallAttributesClient::ReportServiceIsNotAvailable() {
-  DCHECK(!service_is_available_);
-  service_reported_not_available_ = true;
-
-  std::vector<chromeos::WaitForServiceToBeAvailableCallback> callbacks;
-  callbacks.swap(pending_wait_for_service_to_be_available_callbacks_);
-  for (auto& callback : callbacks) {
-    std::move(callback).Run(false);
-  }
-}
-
-template <typename ReplyType>
-void FakeInstallAttributesClient::ReturnProtobufMethodCallback(
-    const ReplyType& reply,
-    chromeos::DBusMethodCallback<ReplyType> callback) {
-  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), reply));
-}
-
-bool FakeInstallAttributesClient::LoadInstallAttributes() {
-  base::FilePath cache_file;
-  const bool file_exists =
-      base::PathService::Get(chromeos::dbus_paths::FILE_INSTALL_ATTRIBUTES,
-                             &cache_file) &&
-      base::PathExists(cache_file);
-  DCHECK(file_exists);
-  // Mostly copied from
-  // chromeos/ash/components/install_attributes/install_attributes.cc.
-  std::string file_blob;
-  if (!base::ReadFileToStringWithMaxSize(cache_file, &file_blob,
-                                         kInstallAttributesFileMaxSize)) {
-    PLOG(ERROR) << "Failed to read " << cache_file.value();
-    return false;
-  }
-
-  cryptohome::SerializedInstallAttributes install_attrs_proto;
-  if (!install_attrs_proto.ParseFromString(file_blob)) {
-    LOG(ERROR) << "Failed to parse install attributes cache.";
-    return false;
-  }
-
-  for (const auto& entry : install_attrs_proto.attributes()) {
-    install_attrs_[entry.name()].assign(
-        entry.value().data(), entry.value().data() + entry.value().size());
-  }
-
-  return true;
-}
-
-}  // namespace ash
diff --git a/chromeos/ash/components/dbus/userdataauth/fake_install_attributes_client.h b/chromeos/ash/components/dbus/userdataauth/fake_install_attributes_client.h
deleted file mode 100644
index eafc1ab..0000000
--- a/chromeos/ash/components/dbus/userdataauth/fake_install_attributes_client.h
+++ /dev/null
@@ -1,130 +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 CHROMEOS_ASH_COMPONENTS_DBUS_USERDATAAUTH_FAKE_INSTALL_ATTRIBUTES_CLIENT_H_
-#define CHROMEOS_ASH_COMPONENTS_DBUS_USERDATAAUTH_FAKE_INSTALL_ATTRIBUTES_CLIENT_H_
-
-#include <cstdint>
-#include <optional>
-
-#include "base/component_export.h"
-#include "chromeos/ash/components/dbus/cryptohome/UserDataAuth.pb.h"
-#include "chromeos/ash/components/dbus/userdataauth/install_attributes_client.h"
-
-namespace ash {
-
-class COMPONENT_EXPORT(USERDATAAUTH_CLIENT) FakeInstallAttributesClient
-    : public InstallAttributesClient {
- public:
-  FakeInstallAttributesClient();
-  ~FakeInstallAttributesClient() override;
-
-  // Not copyable or movable.
-  FakeInstallAttributesClient(const FakeInstallAttributesClient&) = delete;
-  FakeInstallAttributesClient& operator=(const FakeInstallAttributesClient&) =
-      delete;
-
-  // Checks that a FakeInstallAttributesClient instance was initialized and
-  // returns it.
-  static FakeInstallAttributesClient* Get();
-
-  // InstallAttributesClient override:
-  void WaitForServiceToBeAvailable(
-      chromeos::WaitForServiceToBeAvailableCallback callback) override;
-  void InstallAttributesGet(
-      const ::user_data_auth::InstallAttributesGetRequest& request,
-      InstallAttributesGetCallback callback) override;
-  void InstallAttributesFinalize(
-      const ::user_data_auth::InstallAttributesFinalizeRequest& request,
-      InstallAttributesFinalizeCallback callback) override;
-  void InstallAttributesGetStatus(
-      const ::user_data_auth::InstallAttributesGetStatusRequest& request,
-      InstallAttributesGetStatusCallback callback) override;
-  void RemoveFirmwareManagementParameters(
-      const ::user_data_auth::RemoveFirmwareManagementParametersRequest&
-          request,
-      RemoveFirmwareManagementParametersCallback callback) override;
-  void SetFirmwareManagementParameters(
-      const ::user_data_auth::SetFirmwareManagementParametersRequest& request,
-      SetFirmwareManagementParametersCallback callback) override;
-  void GetFirmwareManagementParameters(
-      const ::user_data_auth::GetFirmwareManagementParametersRequest& request,
-      GetFirmwareManagementParametersCallback callback) override;
-  std::optional<::user_data_auth::InstallAttributesGetReply>
-  BlockingInstallAttributesGet(
-      const ::user_data_auth::InstallAttributesGetRequest& request) override;
-  std::optional<::user_data_auth::InstallAttributesSetReply>
-  BlockingInstallAttributesSet(
-      const ::user_data_auth::InstallAttributesSetRequest& request) override;
-  std::optional<::user_data_auth::InstallAttributesFinalizeReply>
-  BlockingInstallAttributesFinalize(
-      const ::user_data_auth::InstallAttributesFinalizeRequest& request)
-      override;
-  std::optional<::user_data_auth::InstallAttributesGetStatusReply>
-  BlockingInstallAttributesGetStatus(
-      const ::user_data_auth::InstallAttributesGetStatusRequest& request)
-      override;
-
-  // FWMP related:
-
-  // Return the number of times RemoveFirmwareManagementParameters is called.
-  int remove_firmware_management_parameters_from_tpm_call_count() const {
-    return remove_firmware_management_parameters_from_tpm_call_count_;
-  }
-
-  // WaitForServiceToBeAvailable() related:
-
-  // Changes the behavior of WaitForServiceToBeAvailable(). This method runs
-  // pending callbacks if is_available is true.
-  void SetServiceIsAvailable(bool is_available);
-
-  // Runs pending availability callbacks reporting that the service is
-  // unavailable. Expects service not to be available when called.
-  void ReportServiceIsNotAvailable();
-
- private:
-  // Helper that returns the protobuf reply.
-  template <typename ReplyType>
-  void ReturnProtobufMethodCallback(
-      const ReplyType& reply,
-      chromeos::DBusMethodCallback<ReplyType> callback);
-
-  // Loads install attributes from the stub file.
-  bool LoadInstallAttributes();
-
-  // FWMP related:
-
-  // Firmware management parameters.
-  std::optional<uint32_t> fwmp_flags_;
-
-  // Number of times RemoveFirmwareManagementParameters() is called.
-  int remove_firmware_management_parameters_from_tpm_call_count_ = 0;
-
-  // Install attributes related:
-
-  // A stub store for InstallAttributes, mapping an attribute name to the
-  // associated data blob. Used to implement InstallAttributesSet and -Get.
-  std::map<std::string, std::string> install_attrs_;
-
-  // Set to true if install attributes are finalized.
-  bool locked_;
-
-  // WaitForServiceToBeAvailable() related fields:
-
-  // If set, we tell callers that service is available.
-  bool service_is_available_ = true;
-
-  // If set, WaitForServiceToBeAvailable will run the callback, even if service
-  // is not available (instead of adding the callback to pending callback list).
-  bool service_reported_not_available_ = false;
-
-  // The list of callbacks passed to WaitForServiceToBeAvailable when the
-  // service wasn't available.
-  std::vector<chromeos::WaitForServiceToBeAvailableCallback>
-      pending_wait_for_service_to_be_available_callbacks_;
-};
-
-}  // namespace ash
-
-#endif  // CHROMEOS_ASH_COMPONENTS_DBUS_USERDATAAUTH_FAKE_INSTALL_ATTRIBUTES_CLIENT_H_
diff --git a/chromeos/ash/components/dbus/userdataauth/install_attributes_client.cc b/chromeos/ash/components/dbus/userdataauth/install_attributes_client.cc
deleted file mode 100644
index 476d4d8..0000000
--- a/chromeos/ash/components/dbus/userdataauth/install_attributes_client.cc
+++ /dev/null
@@ -1,305 +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 "chromeos/ash/components/dbus/userdataauth/install_attributes_client.h"
-
-#include <memory>
-#include <utility>
-
-#include <google/protobuf/message_lite.h>
-
-#include "base/functional/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/memory/raw_ptr.h"
-#include "base/task/single_thread_task_runner.h"
-#include "base/time/time.h"
-#include "chromeos/ash/components/dbus/userdataauth/fake_install_attributes_client.h"
-#include "chromeos/dbus/common/blocking_method_caller.h"
-#include "dbus/bus.h"
-#include "dbus/message.h"
-#include "dbus/object_path.h"
-#include "dbus/object_proxy.h"
-#include "third_party/cros_system_api/dbus/cryptohome/dbus-constants.h"
-
-namespace ash {
-namespace {
-
-// The default timeout for all method call within InstallAttributes interface.
-// Note that it is known that cryptohomed could be slow to respond to calls
-// certain conditions. D-Bus call blocking for as long as 2 minutes have been
-// observed in testing conditions/CQ.
-constexpr int kInstallAttributesDefaultTimeoutMS = 5 * 60 * 1000;
-
-InstallAttributesClient* g_instance = nullptr;
-
-// Tries to parse a proto message from |response| into |proto|.
-// Returns false if |response| is nullptr or the message cannot be parsed.
-bool ParseProto(dbus::Response* response,
-                google::protobuf::MessageLite* proto) {
-  if (!response) {
-    LOG(ERROR) << "Failed to call cryptohomed";
-    return false;
-  }
-
-  dbus::MessageReader reader(response);
-  if (!reader.PopArrayOfBytesAsProto(proto)) {
-    LOG(ERROR) << "Failed to parse response message from cryptohomed";
-    return false;
-  }
-
-  return true;
-}
-
-// "Real" implementation of InstallAttributesClient talking to the cryptohomed's
-// InstallAttributes interface on the Chrome OS side.
-class InstallAttributesClientImpl : public InstallAttributesClient {
- public:
-  InstallAttributesClientImpl() = default;
-  ~InstallAttributesClientImpl() override = default;
-
-  // Not copyable or movable.
-  InstallAttributesClientImpl(const InstallAttributesClientImpl&) = delete;
-  InstallAttributesClientImpl& operator=(const InstallAttributesClientImpl&) =
-      delete;
-
-  void Init(dbus::Bus* bus) {
-    proxy_ = bus->GetObjectProxy(
-        ::user_data_auth::kUserDataAuthServiceName,
-        dbus::ObjectPath(::user_data_auth::kUserDataAuthServicePath));
-    blocking_method_caller_ =
-        std::make_unique<chromeos::BlockingMethodCaller>(bus, proxy_);
-  }
-
-  // InstallAttributesClient override:
-
-  void WaitForServiceToBeAvailable(
-      chromeos::WaitForServiceToBeAvailableCallback callback) override {
-    proxy_->WaitForServiceToBeAvailable(std::move(callback));
-  }
-
-  void InstallAttributesGet(
-      const ::user_data_auth::InstallAttributesGetRequest& request,
-      InstallAttributesGetCallback callback) override {
-    CallProtoMethod(::user_data_auth::kInstallAttributesGet,
-                    ::user_data_auth::kInstallAttributesInterface, request,
-                    std::move(callback));
-  }
-
-  void InstallAttributesFinalize(
-      const ::user_data_auth::InstallAttributesFinalizeRequest& request,
-      InstallAttributesFinalizeCallback callback) override {
-    CallProtoMethod(::user_data_auth::kInstallAttributesFinalize,
-                    ::user_data_auth::kInstallAttributesInterface, request,
-                    std::move(callback));
-  }
-
-  void InstallAttributesGetStatus(
-      const ::user_data_auth::InstallAttributesGetStatusRequest& request,
-      InstallAttributesGetStatusCallback callback) override {
-    CallProtoMethod(::user_data_auth::kInstallAttributesGetStatus,
-                    ::user_data_auth::kInstallAttributesInterface, request,
-                    std::move(callback));
-  }
-
-  void RemoveFirmwareManagementParameters(
-      const ::user_data_auth::RemoveFirmwareManagementParametersRequest&
-          request,
-      RemoveFirmwareManagementParametersCallback callback) override {
-    CallProtoMethod(::user_data_auth::kRemoveFirmwareManagementParameters,
-                    ::user_data_auth::kInstallAttributesInterface, request,
-                    std::move(callback));
-  }
-
-  void SetFirmwareManagementParameters(
-      const ::user_data_auth::SetFirmwareManagementParametersRequest& request,
-      SetFirmwareManagementParametersCallback callback) override {
-    CallProtoMethod(::user_data_auth::kSetFirmwareManagementParameters,
-                    ::user_data_auth::kInstallAttributesInterface, request,
-                    std::move(callback));
-  }
-
-  void GetFirmwareManagementParameters(
-      const ::user_data_auth::GetFirmwareManagementParametersRequest& request,
-      GetFirmwareManagementParametersCallback callback) override {
-    CallProtoMethod(::user_data_auth::kGetFirmwareManagementParameters,
-                    ::user_data_auth::kInstallAttributesInterface, request,
-                    std::move(callback));
-  }
-
-  std::optional<::user_data_auth::InstallAttributesGetReply>
-  BlockingInstallAttributesGet(
-      const ::user_data_auth::InstallAttributesGetRequest& request) override {
-    return BlockingCallProtoMethod<::user_data_auth::InstallAttributesGetReply>(
-        ::user_data_auth::kInstallAttributesGet,
-        ::user_data_auth::kInstallAttributesInterface, request);
-  }
-
-  std::optional<::user_data_auth::InstallAttributesSetReply>
-  BlockingInstallAttributesSet(
-      const ::user_data_auth::InstallAttributesSetRequest& request) override {
-    return BlockingCallProtoMethod<::user_data_auth::InstallAttributesSetReply>(
-        ::user_data_auth::kInstallAttributesSet,
-        ::user_data_auth::kInstallAttributesInterface, request);
-  }
-
-  std::optional<::user_data_auth::InstallAttributesFinalizeReply>
-  BlockingInstallAttributesFinalize(
-      const ::user_data_auth::InstallAttributesFinalizeRequest& request)
-      override {
-    return BlockingCallProtoMethod<
-        ::user_data_auth::InstallAttributesFinalizeReply>(
-        ::user_data_auth::kInstallAttributesFinalize,
-        ::user_data_auth::kInstallAttributesInterface, request);
-  }
-
-  std::optional<::user_data_auth::InstallAttributesGetStatusReply>
-  BlockingInstallAttributesGetStatus(
-      const ::user_data_auth::InstallAttributesGetStatusRequest& request)
-      override {
-    return BlockingCallProtoMethod<
-        ::user_data_auth::InstallAttributesGetStatusReply>(
-        ::user_data_auth::kInstallAttributesGetStatus,
-        ::user_data_auth::kInstallAttributesInterface, request);
-  }
-
- private:
-  // Calls cryptohomed's |method_name| method in |interface_name| interface,
-  // passing in |request| as input with |timeout_ms|. Once the (asynchronous)
-  // call finishes, |callback| is called with the response proto.
-  template <typename RequestType, typename ReplyType>
-  void CallProtoMethodWithTimeout(
-      const char* method_name,
-      const char* interface_name,
-      int timeout_ms,
-      const RequestType& request,
-      chromeos::DBusMethodCallback<ReplyType> callback) {
-    dbus::MethodCall method_call(interface_name, method_name);
-    dbus::MessageWriter writer(&method_call);
-    if (!writer.AppendProtoAsArrayOfBytes(request)) {
-      LOG(ERROR)
-          << "Failed to append protobuf when calling InstallAttributes method "
-          << method_name;
-      base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
-          FROM_HERE, base::BindOnce(std::move(callback), std::nullopt));
-      return;
-    }
-    // Bind with the weak pointer of |this| so the response is not
-    // handled once |this| is already destroyed.
-    proxy_->CallMethod(
-        &method_call, timeout_ms,
-        base::BindOnce(&InstallAttributesClientImpl::HandleResponse<ReplyType>,
-                       weak_factory_.GetWeakPtr(), std::move(callback)));
-  }
-
-  // Calls cryptohomed's |method_name| method in |interface_name| interface,
-  // passing in |request| as input with the default InstallAttributes timeout.
-  // Once the (asynchronous) call finishes, |callback| is called with the
-  // response proto.
-  template <typename RequestType, typename ReplyType>
-  void CallProtoMethod(const char* method_name,
-                       const char* interface_name,
-                       const RequestType& request,
-                       chromeos::DBusMethodCallback<ReplyType> callback) {
-    CallProtoMethodWithTimeout(method_name, interface_name,
-                               kInstallAttributesDefaultTimeoutMS, request,
-                               std::move(callback));
-  }
-
-  // Parses the response proto message from |response| and calls |callback| with
-  // the decoded message. Calls |callback| with std::nullopt on error, including
-  // timeout.
-  template <typename ReplyType>
-  void HandleResponse(chromeos::DBusMethodCallback<ReplyType> callback,
-                      dbus::Response* response) {
-    ReplyType reply_proto;
-    if (!ParseProto(response, &reply_proto)) {
-      LOG(ERROR)
-          << "Failed to parse reply protobuf from InstallAttributes method";
-      std::move(callback).Run(std::nullopt);
-      return;
-    }
-    std::move(callback).Run(reply_proto);
-  }
-
-  template <typename ReplyType, typename RequestType>
-  std::optional<ReplyType> BlockingCallProtoMethod(const char* method_name,
-                                                   const char* interface_name,
-                                                   const RequestType& request) {
-    dbus::MethodCall method_call(interface_name, method_name);
-    dbus::MessageWriter writer(&method_call);
-    if (!writer.AppendProtoAsArrayOfBytes(request)) {
-      LOG(ERROR) << "Failed to append protobuf when calling InstallAttributes "
-                    "method (blocking) "
-                 << method_name;
-      return std::nullopt;
-    }
-
-    std::unique_ptr<dbus::Response> response(
-        blocking_method_caller_->CallMethodAndBlock(&method_call)
-            .value_or(nullptr));
-
-    if (!response) {
-      LOG(ERROR) << "DBus call failed for InstallAttributes method (blocking) "
-                 << method_name;
-      return std::nullopt;
-    }
-
-    ReplyType reply_proto;
-    if (!ParseProto(response.get(), &reply_proto)) {
-      LOG(ERROR)
-          << "Failed to parse proto from InstallAttributes method (blocking) "
-          << method_name;
-      return std::nullopt;
-    }
-
-    return reply_proto;
-  }
-
-  // D-Bus proxy for cryptohomed, not owned.
-  raw_ptr<dbus::ObjectProxy> proxy_ = nullptr;
-
-  // For making blocking dbus calls.
-  std::unique_ptr<chromeos::BlockingMethodCaller> blocking_method_caller_;
-
-  base::WeakPtrFactory<InstallAttributesClientImpl> weak_factory_{this};
-};
-
-}  // namespace
-
-InstallAttributesClient::InstallAttributesClient() {
-  CHECK(!g_instance);
-  g_instance = this;
-}
-
-InstallAttributesClient::~InstallAttributesClient() {
-  CHECK_EQ(this, g_instance);
-  g_instance = nullptr;
-}
-
-// static
-void InstallAttributesClient::Initialize(dbus::Bus* bus) {
-  CHECK(bus);
-  (new InstallAttributesClientImpl())->Init(bus);
-}
-
-// static
-void InstallAttributesClient::InitializeFake() {
-  new FakeInstallAttributesClient();
-}
-
-// static
-void InstallAttributesClient::Shutdown() {
-  CHECK(g_instance);
-  delete g_instance;
-  // The destructor resets |g_instance|.
-  DCHECK(!g_instance);
-}
-
-// static
-InstallAttributesClient* InstallAttributesClient::Get() {
-  return g_instance;
-}
-
-}  // namespace ash
diff --git a/chromeos/ash/components/dbus/userdataauth/install_attributes_client.h b/chromeos/ash/components/dbus/userdataauth/install_attributes_client.h
deleted file mode 100644
index 102d81a..0000000
--- a/chromeos/ash/components/dbus/userdataauth/install_attributes_client.h
+++ /dev/null
@@ -1,126 +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 CHROMEOS_ASH_COMPONENTS_DBUS_USERDATAAUTH_INSTALL_ATTRIBUTES_CLIENT_H_
-#define CHROMEOS_ASH_COMPONENTS_DBUS_USERDATAAUTH_INSTALL_ATTRIBUTES_CLIENT_H_
-
-#include <optional>
-
-#include "base/component_export.h"
-#include "base/functional/callback.h"
-#include "base/observer_list_types.h"
-#include "chromeos/ash/components/dbus/cryptohome/UserDataAuth.pb.h"
-#include "chromeos/ash/components/dbus/cryptohome/rpc.pb.h"
-#include "chromeos/dbus/common/dbus_method_call_status.h"
-
-namespace dbus {
-class Bus;
-}
-
-namespace ash {
-
-// InstallAttributesClient is used to communicate with the
-// org.chromium.InstallAttributes interface within org.chromium.UserDataAuth
-// service exposed by cryptohomed. All method should be called from the origin
-// thread (UI thread) which initializes the DBusThreadManager instance.
-class COMPONENT_EXPORT(USERDATAAUTH_CLIENT) InstallAttributesClient {
- public:
-  using InstallAttributesGetCallback =
-      chromeos::DBusMethodCallback<::user_data_auth::InstallAttributesGetReply>;
-  using InstallAttributesSetCallback =
-      chromeos::DBusMethodCallback<::user_data_auth::InstallAttributesSetReply>;
-  using InstallAttributesFinalizeCallback = chromeos::DBusMethodCallback<
-      ::user_data_auth::InstallAttributesFinalizeReply>;
-  using InstallAttributesGetStatusCallback = chromeos::DBusMethodCallback<
-      ::user_data_auth::InstallAttributesGetStatusReply>;
-  using RemoveFirmwareManagementParametersCallback =
-      chromeos::DBusMethodCallback<
-          ::user_data_auth::RemoveFirmwareManagementParametersReply>;
-  using SetFirmwareManagementParametersCallback = chromeos::DBusMethodCallback<
-      ::user_data_auth::SetFirmwareManagementParametersReply>;
-  using GetFirmwareManagementParametersCallback = chromeos::DBusMethodCallback<
-      ::user_data_auth::GetFirmwareManagementParametersReply>;
-
-  // Not copyable or movable.
-  InstallAttributesClient(const InstallAttributesClient&) = delete;
-  InstallAttributesClient& operator=(const InstallAttributesClient&) = delete;
-
-  // Creates and initializes the global instance. |bus| must not be null.
-  static void Initialize(dbus::Bus* bus);
-
-  // Creates and initializes a fake global instance if not already created.
-  static void InitializeFake();
-
-  // Destroys the global instance.
-  static void Shutdown();
-
-  // Returns the global instance which may be null if not initialized.
-  static InstallAttributesClient* Get();
-
-  // Actual DBus Methods:
-
-  // Runs the callback as soon as the service becomes available.
-  virtual void WaitForServiceToBeAvailable(
-      chromeos::WaitForServiceToBeAvailableCallback callback) = 0;
-
-  // Retrieves an install attribute.
-  virtual void InstallAttributesGet(
-      const ::user_data_auth::InstallAttributesGetRequest& request,
-      InstallAttributesGetCallback callback) = 0;
-
-  // Finalizes the install attribute.
-  virtual void InstallAttributesFinalize(
-      const ::user_data_auth::InstallAttributesFinalizeRequest& request,
-      InstallAttributesFinalizeCallback callback) = 0;
-
-  // Get the current status of the install attributes.
-  virtual void InstallAttributesGetStatus(
-      const ::user_data_auth::InstallAttributesGetStatusRequest& request,
-      InstallAttributesGetStatusCallback callback) = 0;
-
-  // Removes/unset the firmware management parameters.
-  virtual void RemoveFirmwareManagementParameters(
-      const ::user_data_auth::RemoveFirmwareManagementParametersRequest&
-          request,
-      RemoveFirmwareManagementParametersCallback callback) = 0;
-
-  // Set the firmware management parameters.
-  virtual void SetFirmwareManagementParameters(
-      const ::user_data_auth::SetFirmwareManagementParametersRequest& request,
-      SetFirmwareManagementParametersCallback callback) = 0;
-
-  // Get the firmware management parameters.
-  virtual void GetFirmwareManagementParameters(
-      const ::user_data_auth::GetFirmwareManagementParametersRequest& request,
-      GetFirmwareManagementParametersCallback callback) = 0;
-
-  // Blocking version of InstallAttributesGet().
-  virtual std::optional<::user_data_auth::InstallAttributesGetReply>
-  BlockingInstallAttributesGet(
-      const ::user_data_auth::InstallAttributesGetRequest& request) = 0;
-
-  // Blocking version of InstallAttributesSet().
-  virtual std::optional<::user_data_auth::InstallAttributesSetReply>
-  BlockingInstallAttributesSet(
-      const ::user_data_auth::InstallAttributesSetRequest& request) = 0;
-
-  // Blocking version of InstallAttributesFinalize().
-  virtual std::optional<::user_data_auth::InstallAttributesFinalizeReply>
-  BlockingInstallAttributesFinalize(
-      const ::user_data_auth::InstallAttributesFinalizeRequest& request) = 0;
-
-  // Blocking version of InstallAttributesGetStatus().
-  virtual std::optional<::user_data_auth::InstallAttributesGetStatusReply>
-  BlockingInstallAttributesGetStatus(
-      const ::user_data_auth::InstallAttributesGetStatusRequest& request) = 0;
-
- protected:
-  // Initialize/Shutdown should be used instead.
-  InstallAttributesClient();
-  virtual ~InstallAttributesClient();
-};
-
-}  // namespace ash
-
-#endif  // CHROMEOS_ASH_COMPONENTS_DBUS_USERDATAAUTH_INSTALL_ATTRIBUTES_CLIENT_H_
diff --git a/chromeos/ash/components/dbus/userdataauth/install_attributes_client_unittest.cc b/chromeos/ash/components/dbus/userdataauth/install_attributes_client_unittest.cc
deleted file mode 100644
index 4e896e5..0000000
--- a/chromeos/ash/components/dbus/userdataauth/install_attributes_client_unittest.cc
+++ /dev/null
@@ -1,435 +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 "chromeos/ash/components/dbus/userdataauth/install_attributes_client.h"
-
-#include <string>
-#include <utility>
-
-#include "base/logging.h"
-#include "base/memory/raw_ptr.h"
-#include "base/task/single_thread_task_runner.h"
-#include "base/test/task_environment.h"
-#include "chromeos/ash/components/dbus/cryptohome/UserDataAuth.pb.h"
-#include "dbus/mock_bus.h"
-#include "dbus/mock_object_proxy.h"
-#include "dbus/object_path.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/cros_system_api/dbus/cryptohome/dbus-constants.h"
-
-using ::testing::_;
-using ::testing::Invoke;
-using ::testing::Return;
-using ::testing::SaveArg;
-
-namespace ash {
-
-namespace {
-
-// Runs |callback| with |response|. Needed due to ResponseCallback expecting a
-// bare pointer rather than an std::unique_ptr.
-void RunResponseCallback(dbus::ObjectProxy::ResponseCallback callback,
-                         std::unique_ptr<dbus::Response> response) {
-  std::move(callback).Run(response.get());
-}
-
-bool ProtobufEquals(const google::protobuf::MessageLite& a,
-                    const google::protobuf::MessageLite& b) {
-  std::string a_serialized, b_serialized;
-  a.SerializeToString(&a_serialized);
-  b.SerializeToString(&b_serialized);
-  return a_serialized == b_serialized;
-}
-
-// FakeTaskRunner will run all tasks posted to it immediately in the PostTask()
-// call. This class is a helper to ensure that BlockingMethodCaller would work
-// correctly in the unit test. Note that Mock is not used because
-// SingleThreadTaskRunner is refcounted and it doesn't play well with Mock.
-class FakeTaskRunner : public base::SingleThreadTaskRunner {
- public:
-  // Yes, this task runner runs everything in sequence.
-  bool RunsTasksInCurrentSequence() const override { return true; }
-
-  // Run all tasks immediately, no delay is allowed.
-  bool PostDelayedTask(const base::Location& location,
-                       base::OnceClosure closure,
-                       base::TimeDelta delta) override {
-    // Since we are running it now, we can't accept any delay.
-    CHECK(delta.is_zero());
-    std::move(closure).Run();
-    return true;
-  }
-
-  // Non nestable task not supported.
-  bool PostNonNestableDelayedTask(const base::Location& location,
-                                  base::OnceClosure closure,
-                                  base::TimeDelta delta) override {
-    // Can't run non-nested stuff.
-    NOTIMPLEMENTED();
-    return false;
-  }
-
- private:
-  // For reference counting.
-  ~FakeTaskRunner() override {}
-};
-
-// Create a callback that would copy the input argument passed to it into |out|.
-// This is used mostly to create a callback that would catch the reply from
-// dbus.
-template <typename T>
-base::OnceCallback<void(T)> CreateCopyCallback(T* out) {
-  return base::BindOnce([](T* out, T result) { *out = result; }, out);
-}
-
-}  // namespace
-
-class InstallAttributesClientTest : public testing::Test {
- public:
-  InstallAttributesClientTest() = default;
-  ~InstallAttributesClientTest() override = default;
-
-  void SetUp() override {
-    dbus::Bus::Options options;
-    options.bus_type = dbus::Bus::SYSTEM;
-    bus_ = new dbus::MockBus(options);
-
-    dbus::ObjectPath userdataauth_object_path =
-        dbus::ObjectPath(::user_data_auth::kUserDataAuthServicePath);
-    proxy_ = new dbus::MockObjectProxy(
-        bus_.get(), ::user_data_auth::kUserDataAuthServiceName,
-        userdataauth_object_path);
-
-    // Makes sure `GetObjectProxy()` is called with the correct service name and
-    // path.
-    EXPECT_CALL(*bus_.get(),
-                GetObjectProxy(::user_data_auth::kUserDataAuthServiceName,
-                               userdataauth_object_path))
-        .WillRepeatedly(Return(proxy_.get()));
-
-    EXPECT_CALL(*proxy_.get(), DoCallMethod(_, _, _))
-        .WillRepeatedly(
-            Invoke(this, &InstallAttributesClientTest::OnCallMethod));
-    EXPECT_CALL(*proxy_.get(), CallMethodAndBlock(_, _))
-        .WillRepeatedly(
-            Invoke(this, &InstallAttributesClientTest::OnBlockingCallMethod));
-
-    InstallAttributesClient::Initialize(bus_.get());
-
-    // Execute callbacks posted by `client_->Init()`.
-    base::RunLoop().RunUntilIdle();
-
-    client_ = InstallAttributesClient::Get();
-  }
-
-  void TearDown() override { InstallAttributesClient::Shutdown(); }
-
- protected:
-  base::test::SingleThreadTaskEnvironment task_environment_;
-
-  // Mock bus and proxy for simulating calls.
-  scoped_refptr<dbus::MockBus> bus_;
-  scoped_refptr<dbus::MockObjectProxy> proxy_;
-
-  // Convenience pointer to the global instance.
-  raw_ptr<InstallAttributesClient, DanglingUntriaged> client_;
-
-  // The expected replies to the respective D-Bus calls.
-  ::user_data_auth::InstallAttributesGetReply
-      expected_install_attributes_get_reply_;
-  ::user_data_auth::InstallAttributesSetReply
-      expected_install_attributes_set_reply_;
-  ::user_data_auth::InstallAttributesFinalizeReply
-      expected_install_attributes_finalize_reply_;
-  ::user_data_auth::InstallAttributesGetStatusReply
-      expected_install_attributes_get_status_reply_;
-  ::user_data_auth::RemoveFirmwareManagementParametersReply
-      expected_remove_firmware_management_parameters_reply_;
-  ::user_data_auth::SetFirmwareManagementParametersReply
-      expected_set_firmware_management_parameters_reply_;
-  ::user_data_auth::GetFirmwareManagementParametersReply
-      expected_get_firmware_management_parameters_reply_;
-
-  // The expected replies to the respective blocking D-Bus calls.
-  ::user_data_auth::InstallAttributesGetReply
-      expected_blocking_install_attributes_get_reply_;
-  ::user_data_auth::InstallAttributesSetReply
-      expected_blocking_install_attributes_set_reply_;
-  ::user_data_auth::InstallAttributesFinalizeReply
-      expected_blocking_install_attributes_finalize_reply_;
-  ::user_data_auth::InstallAttributesGetStatusReply
-      expected_blocking_install_attributes_get_status_reply_;
-
-  // When it is set `true`, an invalid array of bytes that cannot be parsed will
-  // be the response.
-  bool shall_message_parsing_fail_ = false;
-
- private:
-  // Handles calls to |proxy_|'s `CallMethod()`.
-  void OnCallMethod(dbus::MethodCall* method_call,
-                    int timeout_ms,
-                    dbus::ObjectProxy::ResponseCallback* callback) {
-    std::unique_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
-    dbus::MessageWriter writer(response.get());
-    if (shall_message_parsing_fail_) {
-      // 0x02 => Field 0, Type String
-      // (0xFF)*6 => Varint, the size of the string, it is not terminated and is
-      // a very large value so the parsing will fail.
-      constexpr uint8_t invalid_protobuf[] = {0x02, 0xFF, 0xFF, 0xFF,
-                                              0xFF, 0xFF, 0xFF};
-      writer.AppendArrayOfBytes(invalid_protobuf);
-    } else if (method_call->GetMember() ==
-               ::user_data_auth::kInstallAttributesGet) {
-      writer.AppendProtoAsArrayOfBytes(expected_install_attributes_get_reply_);
-    } else if (method_call->GetMember() ==
-               ::user_data_auth::kInstallAttributesFinalize) {
-      writer.AppendProtoAsArrayOfBytes(
-          expected_install_attributes_finalize_reply_);
-    } else if (method_call->GetMember() ==
-               ::user_data_auth::kInstallAttributesGetStatus) {
-      writer.AppendProtoAsArrayOfBytes(
-          expected_install_attributes_get_status_reply_);
-    } else if (method_call->GetMember() ==
-               ::user_data_auth::kRemoveFirmwareManagementParameters) {
-      writer.AppendProtoAsArrayOfBytes(
-          expected_remove_firmware_management_parameters_reply_);
-    } else if (method_call->GetMember() ==
-               ::user_data_auth::kSetFirmwareManagementParameters) {
-      writer.AppendProtoAsArrayOfBytes(
-          expected_set_firmware_management_parameters_reply_);
-    } else if (method_call->GetMember() ==
-               ::user_data_auth::kGetFirmwareManagementParameters) {
-      writer.AppendProtoAsArrayOfBytes(
-          expected_get_firmware_management_parameters_reply_);
-    } else {
-      ASSERT_FALSE(true) << "Unrecognized member: " << method_call->GetMember();
-    }
-    task_environment_.GetMainThreadTaskRunner()->PostTask(
-        FROM_HERE, base::BindOnce(RunResponseCallback, std::move(*callback),
-                                  std::move(response)));
-  }
-
-  // Handles blocking call to |proxy_|'s `CallMethodAndBlock`.
-  base::expected<std::unique_ptr<dbus::Response>, dbus::Error>
-  OnBlockingCallMethod(dbus::MethodCall* method_call, int timeout_ms) {
-    std::unique_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
-    dbus::MessageWriter writer(response.get());
-    if (shall_message_parsing_fail_) {
-      // 0x02 => Field 0, Type String
-      // (0xFF)*6 => Varint, the size of the string, it is not terminated and is
-      // a very large value so the parsing will fail.
-      constexpr uint8_t invalid_protobuf[] = {0x02, 0xFF, 0xFF, 0xFF,
-                                              0xFF, 0xFF, 0xFF};
-      writer.AppendArrayOfBytes(invalid_protobuf);
-    } else if (method_call->GetMember() ==
-               ::user_data_auth::kInstallAttributesGet) {
-      writer.AppendProtoAsArrayOfBytes(
-          expected_blocking_install_attributes_get_reply_);
-    } else if (method_call->GetMember() ==
-               ::user_data_auth::kInstallAttributesSet) {
-      writer.AppendProtoAsArrayOfBytes(
-          expected_blocking_install_attributes_set_reply_);
-    } else if (method_call->GetMember() ==
-               ::user_data_auth::kInstallAttributesFinalize) {
-      writer.AppendProtoAsArrayOfBytes(
-          expected_blocking_install_attributes_finalize_reply_);
-    } else if (method_call->GetMember() ==
-               ::user_data_auth::kInstallAttributesGetStatus) {
-      writer.AppendProtoAsArrayOfBytes(
-          expected_blocking_install_attributes_get_status_reply_);
-    } else {
-      LOG(FATAL) << "Unrecognized member: " << method_call->GetMember();
-    }
-    return base::ok(std::move(response));
-  }
-};
-
-TEST_F(InstallAttributesClientTest, InstallAttributesGet) {
-  expected_install_attributes_get_reply_.set_error(
-      user_data_auth::CryptohomeErrorCode::CRYPTOHOME_ERROR_TPM_DEFEND_LOCK);
-  std::optional<::user_data_auth::InstallAttributesGetReply> result_reply;
-
-  client_->InstallAttributesGet(::user_data_auth::InstallAttributesGetRequest(),
-                                CreateCopyCallback(&result_reply));
-  base::RunLoop().RunUntilIdle();
-  ASSERT_NE(result_reply, std::nullopt);
-  EXPECT_TRUE(ProtobufEquals(result_reply.value(),
-                             expected_install_attributes_get_reply_));
-}
-
-TEST_F(InstallAttributesClientTest, InstallAttributesGetInvalidProtobuf) {
-  shall_message_parsing_fail_ = true;
-  std::optional<::user_data_auth::InstallAttributesGetReply> result_reply =
-      ::user_data_auth::InstallAttributesGetReply();
-
-  client_->InstallAttributesGet(::user_data_auth::InstallAttributesGetRequest(),
-                                CreateCopyCallback(&result_reply));
-  base::RunLoop().RunUntilIdle();
-  ASSERT_EQ(result_reply, std::nullopt);
-}
-
-TEST_F(InstallAttributesClientTest, InstallAttributesFinalize) {
-  expected_install_attributes_finalize_reply_.set_error(
-      user_data_auth::CryptohomeErrorCode::CRYPTOHOME_ERROR_TPM_DEFEND_LOCK);
-  std::optional<::user_data_auth::InstallAttributesFinalizeReply> result_reply;
-
-  client_->InstallAttributesFinalize(
-      ::user_data_auth::InstallAttributesFinalizeRequest(),
-      CreateCopyCallback(&result_reply));
-  base::RunLoop().RunUntilIdle();
-  ASSERT_NE(result_reply, std::nullopt);
-  EXPECT_TRUE(ProtobufEquals(result_reply.value(),
-                             expected_install_attributes_finalize_reply_));
-}
-
-TEST_F(InstallAttributesClientTest, InstallAttributesGetStatus) {
-  expected_install_attributes_get_status_reply_.set_error(
-      user_data_auth::CryptohomeErrorCode::CRYPTOHOME_ERROR_TPM_DEFEND_LOCK);
-  std::optional<::user_data_auth::InstallAttributesGetStatusReply> result_reply;
-
-  client_->InstallAttributesGetStatus(
-      ::user_data_auth::InstallAttributesGetStatusRequest(),
-      CreateCopyCallback(&result_reply));
-  base::RunLoop().RunUntilIdle();
-  ASSERT_NE(result_reply, std::nullopt);
-  EXPECT_TRUE(ProtobufEquals(result_reply.value(),
-                             expected_install_attributes_get_status_reply_));
-}
-
-TEST_F(InstallAttributesClientTest, RemoveFirmwareManagementParameters) {
-  expected_remove_firmware_management_parameters_reply_.set_error(
-      user_data_auth::CryptohomeErrorCode::CRYPTOHOME_ERROR_TPM_DEFEND_LOCK);
-  std::optional<::user_data_auth::RemoveFirmwareManagementParametersReply>
-      result_reply;
-
-  client_->RemoveFirmwareManagementParameters(
-      ::user_data_auth::RemoveFirmwareManagementParametersRequest(),
-      CreateCopyCallback(&result_reply));
-  base::RunLoop().RunUntilIdle();
-  ASSERT_NE(result_reply, std::nullopt);
-  EXPECT_TRUE(
-      ProtobufEquals(result_reply.value(),
-                     expected_remove_firmware_management_parameters_reply_));
-}
-
-TEST_F(InstallAttributesClientTest, SetFirmwareManagementParameters) {
-  expected_set_firmware_management_parameters_reply_.set_error(
-      user_data_auth::CryptohomeErrorCode::CRYPTOHOME_ERROR_TPM_DEFEND_LOCK);
-  std::optional<::user_data_auth::SetFirmwareManagementParametersReply>
-      result_reply;
-
-  client_->SetFirmwareManagementParameters(
-      ::user_data_auth::SetFirmwareManagementParametersRequest(),
-      CreateCopyCallback(&result_reply));
-  base::RunLoop().RunUntilIdle();
-  ASSERT_NE(result_reply, std::nullopt);
-  EXPECT_TRUE(
-      ProtobufEquals(result_reply.value(),
-                     expected_set_firmware_management_parameters_reply_));
-}
-
-TEST_F(InstallAttributesClientTest, GetFirmwareManagementParameters) {
-  expected_set_firmware_management_parameters_reply_.set_error(
-      user_data_auth::CryptohomeErrorCode::CRYPTOHOME_ERROR_TPM_DEFEND_LOCK);
-  std::optional<::user_data_auth::GetFirmwareManagementParametersReply>
-      result_reply;
-
-  client_->GetFirmwareManagementParameters(
-      ::user_data_auth::GetFirmwareManagementParametersRequest(),
-      CreateCopyCallback(&result_reply));
-  base::RunLoop().RunUntilIdle();
-  ASSERT_NE(result_reply, std::nullopt);
-  EXPECT_TRUE(
-      ProtobufEquals(result_reply.value(),
-                     expected_get_firmware_management_parameters_reply_));
-}
-
-TEST_F(InstallAttributesClientTest, BlockingInstallAttributesGet) {
-  expected_blocking_install_attributes_get_reply_.set_error(
-      user_data_auth::CryptohomeErrorCode::CRYPTOHOME_ERROR_TPM_DEFEND_LOCK);
-  std::optional<::user_data_auth::InstallAttributesGetReply> result_reply;
-
-  scoped_refptr<FakeTaskRunner> runner = new FakeTaskRunner;
-  EXPECT_CALL(*bus_.get(), GetDBusTaskRunner())
-      .WillRepeatedly(Return(runner.get()));
-
-  result_reply = client_->BlockingInstallAttributesGet(
-      ::user_data_auth::InstallAttributesGetRequest());
-
-  ASSERT_NE(result_reply, std::nullopt);
-  EXPECT_TRUE(ProtobufEquals(result_reply.value(),
-                             expected_blocking_install_attributes_get_reply_));
-}
-
-TEST_F(InstallAttributesClientTest,
-       BlockingInstallAttributesGetInvalidProtobuf) {
-  shall_message_parsing_fail_ = true;
-  std::optional<::user_data_auth::InstallAttributesGetReply> result_reply =
-      ::user_data_auth::InstallAttributesGetReply();
-
-  scoped_refptr<FakeTaskRunner> runner = new FakeTaskRunner;
-  EXPECT_CALL(*bus_.get(), GetDBusTaskRunner())
-      .WillRepeatedly(Return(runner.get()));
-
-  result_reply = client_->BlockingInstallAttributesGet(
-      ::user_data_auth::InstallAttributesGetRequest());
-
-  EXPECT_EQ(result_reply, std::nullopt);
-}
-
-TEST_F(InstallAttributesClientTest, BlockingInstallAttributesSet) {
-  expected_blocking_install_attributes_set_reply_.set_error(
-      user_data_auth::CryptohomeErrorCode::CRYPTOHOME_ERROR_TPM_DEFEND_LOCK);
-  std::optional<::user_data_auth::InstallAttributesSetReply> result_reply;
-
-  scoped_refptr<FakeTaskRunner> runner = new FakeTaskRunner;
-  EXPECT_CALL(*bus_.get(), GetDBusTaskRunner())
-      .WillRepeatedly(Return(runner.get()));
-
-  result_reply = client_->BlockingInstallAttributesSet(
-      ::user_data_auth::InstallAttributesSetRequest());
-
-  ASSERT_NE(result_reply, std::nullopt);
-  EXPECT_TRUE(ProtobufEquals(result_reply.value(),
-                             expected_blocking_install_attributes_set_reply_));
-}
-
-TEST_F(InstallAttributesClientTest, BlockingInstallAttributesFinalize) {
-  expected_blocking_install_attributes_finalize_reply_.set_error(
-      user_data_auth::CryptohomeErrorCode::CRYPTOHOME_ERROR_TPM_DEFEND_LOCK);
-  std::optional<::user_data_auth::InstallAttributesFinalizeReply> result_reply;
-
-  scoped_refptr<FakeTaskRunner> runner = new FakeTaskRunner;
-  EXPECT_CALL(*bus_.get(), GetDBusTaskRunner())
-      .WillRepeatedly(Return(runner.get()));
-
-  result_reply = client_->BlockingInstallAttributesFinalize(
-      ::user_data_auth::InstallAttributesFinalizeRequest());
-
-  ASSERT_NE(result_reply, std::nullopt);
-  EXPECT_TRUE(
-      ProtobufEquals(result_reply.value(),
-                     expected_blocking_install_attributes_finalize_reply_));
-}
-
-TEST_F(InstallAttributesClientTest, BlockingInstallAttributesGetStatus) {
-  expected_blocking_install_attributes_get_status_reply_.set_error(
-      user_data_auth::CryptohomeErrorCode::CRYPTOHOME_ERROR_TPM_DEFEND_LOCK);
-  std::optional<::user_data_auth::InstallAttributesGetStatusReply> result_reply;
-
-  scoped_refptr<FakeTaskRunner> runner = new FakeTaskRunner;
-  EXPECT_CALL(*bus_.get(), GetDBusTaskRunner())
-      .WillRepeatedly(Return(runner.get()));
-
-  result_reply = client_->BlockingInstallAttributesGetStatus(
-      ::user_data_auth::InstallAttributesGetStatusRequest());
-
-  ASSERT_NE(result_reply, std::nullopt);
-  EXPECT_TRUE(
-      ProtobufEquals(result_reply.value(),
-                     expected_blocking_install_attributes_get_status_reply_));
-}
-
-}  // namespace ash
diff --git a/chromeos/ash/components/dbus/userdataauth/install_attributes_util.cc b/chromeos/ash/components/dbus/userdataauth/install_attributes_util.cc
deleted file mode 100644
index dc4edfa..0000000
--- a/chromeos/ash/components/dbus/userdataauth/install_attributes_util.cc
+++ /dev/null
@@ -1,94 +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 "chromeos/ash/components/dbus/userdataauth/install_attributes_util.h"
-
-#include <stdint.h>
-
-#include <optional>
-
-#include "base/check_op.h"
-#include "base/functional/bind.h"
-#include "base/logging.h"
-#include "chromeos/ash/components/dbus/userdataauth/install_attributes_client.h"
-
-namespace ash::install_attributes_util {
-
-bool InstallAttributesGet(const std::string& name, std::string* value) {
-  ::user_data_auth::InstallAttributesGetRequest request;
-  request.set_name(name);
-  std::optional<::user_data_auth::InstallAttributesGetReply> result =
-      InstallAttributesClient::Get()->BlockingInstallAttributesGet(request);
-  if (!result.has_value() ||
-      result->error() !=
-          user_data_auth::CryptohomeErrorCode::CRYPTOHOME_ERROR_NOT_SET) {
-    LOG(WARNING) << "Unable to get install attributes, error: "
-                 << (result.has_value() ? result->error() : -1);
-    return false;
-  }
-
-  // result->value() returned by cryptohome comes with the terminating '\0'
-  // character.
-  DCHECK(!result->value().empty());
-  DCHECK_EQ(result->value().back(), 0);
-  value->assign(result->value().data(), result->value().size() - 1);
-  return true;
-}
-
-bool InstallAttributesSet(const std::string& name, const std::string& value) {
-  ::user_data_auth::InstallAttributesSetRequest request;
-  request.set_name(name);
-  request.set_value(value);
-  request.mutable_value()->push_back('\0');
-  std::optional<::user_data_auth::InstallAttributesSetReply> result =
-      InstallAttributesClient::Get()->BlockingInstallAttributesSet(request);
-  if (!result.has_value() ||
-      result->error() !=
-          user_data_auth::CryptohomeErrorCode::CRYPTOHOME_ERROR_NOT_SET) {
-    LOG(WARNING) << "Unable to set install attributes, error: "
-                 << (result.has_value() ? result->error() : -1);
-    return false;
-  }
-  return true;
-}
-
-bool InstallAttributesFinalize() {
-  std::optional<::user_data_auth::InstallAttributesFinalizeReply> result =
-      InstallAttributesClient::Get()->BlockingInstallAttributesFinalize(
-          ::user_data_auth::InstallAttributesFinalizeRequest());
-  if (!result.has_value() ||
-      result->error() !=
-          user_data_auth::CryptohomeErrorCode::CRYPTOHOME_ERROR_NOT_SET) {
-    LOG(WARNING) << "Unable to finalize install attributes, error: "
-                 << (result.has_value() ? result->error() : -1);
-    return false;
-  }
-  return true;
-}
-
-user_data_auth::InstallAttributesState InstallAttributesGetStatus() {
-  std::optional<::user_data_auth::InstallAttributesGetStatusReply> result =
-      InstallAttributesClient::Get()->BlockingInstallAttributesGetStatus(
-          ::user_data_auth::InstallAttributesGetStatusRequest());
-  if (!result.has_value() ||
-      result->error() !=
-          user_data_auth::CryptohomeErrorCode::CRYPTOHOME_ERROR_NOT_SET) {
-    LOG(WARNING) << "Unable to fetch install attributes status, error: "
-                 << (result.has_value() ? result->error() : -1);
-    return ::user_data_auth::InstallAttributesState::UNKNOWN;
-  }
-  return result->state();
-}
-
-bool InstallAttributesIsInvalid() {
-  user_data_auth::InstallAttributesState state = InstallAttributesGetStatus();
-  return state == user_data_auth::InstallAttributesState::INVALID;
-}
-
-bool InstallAttributesIsFirstInstall() {
-  user_data_auth::InstallAttributesState state = InstallAttributesGetStatus();
-  return state == user_data_auth::InstallAttributesState::FIRST_INSTALL;
-}
-
-}  // namespace ash::install_attributes_util
diff --git a/chromeos/ash/components/dbus/userdataauth/install_attributes_util.h b/chromeos/ash/components/dbus/userdataauth/install_attributes_util.h
deleted file mode 100644
index 48838f7..0000000
--- a/chromeos/ash/components/dbus/userdataauth/install_attributes_util.h
+++ /dev/null
@@ -1,32 +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 CHROMEOS_ASH_COMPONENTS_DBUS_USERDATAAUTH_INSTALL_ATTRIBUTES_UTIL_H_
-#define CHROMEOS_ASH_COMPONENTS_DBUS_USERDATAAUTH_INSTALL_ATTRIBUTES_UTIL_H_
-
-#include <string>
-
-#include "base/component_export.h"
-#include "chromeos/ash/components/dbus/userdataauth/install_attributes_client.h"
-
-namespace ash::install_attributes_util {
-
-// Wrappers for calls to InstallAttributesClient. Must be called from the UI
-// thread. NOTE: Some of these make blocking DBus calls which will spin until
-// the DBus call completes. They should be avoided if possible.
-
-// Blocking calls to InstallAttributesClient methods.
-COMPONENT_EXPORT(USERDATAAUTH_CLIENT)
-bool InstallAttributesGet(const std::string& name, std::string* value);
-COMPONENT_EXPORT(USERDATAAUTH_CLIENT)
-bool InstallAttributesSet(const std::string& name, const std::string& value);
-COMPONENT_EXPORT(USERDATAAUTH_CLIENT) bool InstallAttributesFinalize();
-COMPONENT_EXPORT(USERDATAAUTH_CLIENT)
-user_data_auth::InstallAttributesState InstallAttributesGetStatus();
-COMPONENT_EXPORT(USERDATAAUTH_CLIENT) bool InstallAttributesIsInvalid();
-COMPONENT_EXPORT(USERDATAAUTH_CLIENT) bool InstallAttributesIsFirstInstall();
-
-}  // namespace ash::install_attributes_util
-
-#endif  // CHROMEOS_ASH_COMPONENTS_DBUS_USERDATAAUTH_INSTALL_ATTRIBUTES_UTIL_H_
diff --git a/chromeos/tast_control.gni b/chromeos/tast_control.gni
index 29aa772..c5a361874 100644
--- a/chromeos/tast_control.gni
+++ b/chromeos/tast_control.gni
@@ -169,4 +169,17 @@
   # builds.
   tast_disabled_tests_from_chrome_all += [ "ui.ChromeCrashEarly.strict" ]
   tast_disabled_tests_from_lacros_all += [ "ui.ChromeCrashEarly.strict_lacros" ]
+
+  # b/317943159 public builders fail to install crostini.
+  tast_disabled_tests_from_chrome_all += [ "crostini.*" ]
+
+  # b/317733179 skylab builders lack of feature to pass runtime variables.
+  tast_disabled_tests_from_chrome_all += [
+    "login.AuthError",
+    "login.Offline",
+    "wmp.AdminTemplatesLaunch",
+    "wmp.DesksTemplatesBasic",
+    "wmp.DesksTemplatesLaunch",
+    "wmp.SavedDeskDelete",
+  ]
 }
diff --git a/clank b/clank
index 27098a2..923f628 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 27098a272f4239731ab13adb3dd53bc91652c28f
+Subproject commit 923f628b8e7644a1c009747dafe7bf61e12896b6
diff --git a/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc b/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc
index d23b7b9b..ef939b91 100644
--- a/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc
+++ b/components/autofill/core/browser/autofill_suggestion_generator_unittest.cc
@@ -1301,7 +1301,7 @@
               PopupItemId::kAddressFieldByFieldFilling,
               profile().GetInfo(ADDRESS_HOME_HOUSE_NUMBER, app_locale()),
               ADDRESS_HOME_HOUSE_NUMBER, Suggestion::Guid(profile().guid()),
-              {{Suggestion::Text(u"Building number")}}),
+              {{Suggestion::Text(u"House number")}}),
           EqualsFieldByFieldFillingSuggestion(
               PopupItemId::kAddressFieldByFieldFilling,
               profile().GetInfo(ADDRESS_HOME_STREET_NAME, app_locale()),
@@ -1578,7 +1578,7 @@
                   PopupItemId::kAddressFieldByFieldFilling,
                   profile.GetInfo(ADDRESS_HOME_HOUSE_NUMBER, app_locale()),
                   ADDRESS_HOME_HOUSE_NUMBER, Suggestion::Guid(profile.guid()),
-                  {{Suggestion::Text(u"Building number")}})));
+                  {{Suggestion::Text(u"House number")}})));
 }
 
 TEST_F(
diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp
index 1a40f19..31f3bfd 100644
--- a/components/autofill_strings.grdp
+++ b/components/autofill_strings.grdp
@@ -174,7 +174,7 @@
   </message>
 
   <message name="IDS_AUTOFILL_HOUSE_NUMBER_SUGGESTION_SECONDARY_TEXT_OPTION_SELECTED" desc="The secondary text displayed on a house number suggestion was selected." meaning="The label for the house number field type store by autofill has been selected in the subpopup.">
-    Building number option selected
+    House number option selected
   </message>
 
   <message name="IDS_AUTOFILL_STREET_NAME_SUGGESTION_SECONDARY_TEXT_OPTION_SELECTED" desc="The secondary text displayed on a street name suggestion was selected." meaning="The label for the street namefield type store by autofill has been selected in the subpopup.">
@@ -182,7 +182,7 @@
   </message>
 
   <message name="IDS_AUTOFILL_HOUSE_NUMBER_SUGGESTION_SECONDARY_TEXT" desc="The secondary text displayed on a house number suggestion." meaning="The label for the house number field type store by autofill.">
-    Building number
+    House number
   </message>
 
   <message name="IDS_AUTOFILL_STREET_NAME_SUGGESTION_SECONDARY_TEXT" desc="The secondary text displayed on a street name suggestion." meaning="The label for the street namefield type store by autofill.">
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_HOUSE_NUMBER_SUGGESTION_SECONDARY_TEXT.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_HOUSE_NUMBER_SUGGESTION_SECONDARY_TEXT.png.sha1
index 67c5254..52c45841 100644
--- a/components/autofill_strings_grdp/IDS_AUTOFILL_HOUSE_NUMBER_SUGGESTION_SECONDARY_TEXT.png.sha1
+++ b/components/autofill_strings_grdp/IDS_AUTOFILL_HOUSE_NUMBER_SUGGESTION_SECONDARY_TEXT.png.sha1
@@ -1 +1 @@
-c7680c9a2bc71b47bd03bb24842a0a4f563e1455
\ No newline at end of file
+ad14014aa6ad441f56f20191cac489affbf73c1c
\ No newline at end of file
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_HOUSE_NUMBER_SUGGESTION_SECONDARY_TEXT_OPTION_SELECTED.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_HOUSE_NUMBER_SUGGESTION_SECONDARY_TEXT_OPTION_SELECTED.png.sha1
index 67c5254..f1f3f36 100644
--- a/components/autofill_strings_grdp/IDS_AUTOFILL_HOUSE_NUMBER_SUGGESTION_SECONDARY_TEXT_OPTION_SELECTED.png.sha1
+++ b/components/autofill_strings_grdp/IDS_AUTOFILL_HOUSE_NUMBER_SUGGESTION_SECONDARY_TEXT_OPTION_SELECTED.png.sha1
@@ -1 +1 @@
-c7680c9a2bc71b47bd03bb24842a0a4f563e1455
\ No newline at end of file
+6aae152a602c99378e0d66f2aa46b80afb3c3f5b
\ No newline at end of file
diff --git a/components/exo/surface_tree_host.cc b/components/exo/surface_tree_host.cc
index 7040d0c..32ac567 100644
--- a/components/exo/surface_tree_host.cc
+++ b/components/exo/surface_tree_host.cc
@@ -365,7 +365,13 @@
   // the considerable overhead of flush verification in
   // 'VerifySyncTokensCHROMIUM'.
   for (auto& resource : frame.resource_list) {
-    if (prev_frame_verified_tokens_.find(resource.mailbox_holder.sync_token) !=
+    // Copy the token and set it as flush verified as the tokens, which
+    // |prev_frame_verified_tokens| has, have that flag set. If that is not done
+    // locally here, the comparison of the tokens fails as all fields of each
+    // tokens are compared during ::find().
+    auto tmp_sync_token = resource.mailbox_holder.sync_token;
+    tmp_sync_token.SetVerifyFlush();
+    if (prev_frame_verified_tokens_.find(tmp_sync_token) !=
         prev_frame_verified_tokens_.end()) {
       resource.mailbox_holder.sync_token.SetVerifyFlush();
     }
@@ -375,14 +381,11 @@
   rii->VerifySyncTokensCHROMIUM(sync_tokens.data(), sync_tokens.size());
 
   prev_frame_verified_tokens_.clear();
+  frame.metadata.content_color_usage = gfx::ContentColorUsage::kSRGB;
   for (auto& resource : frame.resource_list) {
     if (resource.mailbox_holder.sync_token.verified_flush()) {
       prev_frame_verified_tokens_.insert(resource.mailbox_holder.sync_token);
     }
-  }
-
-  frame.metadata.content_color_usage = gfx::ContentColorUsage::kSRGB;
-  for (auto& resource : frame.resource_list) {
     frame.metadata.content_color_usage =
         std::max(frame.metadata.content_color_usage,
                  resource.color_space.GetContentColorUsage());
@@ -754,6 +757,14 @@
                                                rounded_corners_bounds);
 }
 
+scoped_refptr<viz::RasterContextProvider>
+SurfaceTreeHost::SetRasterContextProviderForTesting(
+    scoped_refptr<viz::RasterContextProvider> context_provider_test) {
+  auto old_provider = context_provider_;
+  context_provider_ = context_provider_test;
+  return old_provider;
+}
+
 void SurfaceTreeHost::ApplyAndPropagateRoundedCornersToSurfaceTree(
     Surface* surface,
     const gfx::RRectF& rounded_corners_bounds) {
diff --git a/components/exo/surface_tree_host.h b/components/exo/surface_tree_host.h
index 5e59500..862f3c3 100644
--- a/components/exo/surface_tree_host.h
+++ b/components/exo/surface_tree_host.h
@@ -176,6 +176,9 @@
       const gfx::RectF& bounds,
       const gfx::RoundedCornersF& radii_in_dps);
 
+  scoped_refptr<viz::RasterContextProvider> SetRasterContextProviderForTesting(
+      scoped_refptr<viz::RasterContextProvider> context_provider_test);
+
  protected:
   void UpdateDisplayOnTree();
 
diff --git a/components/exo/surface_tree_host_unittest.cc b/components/exo/surface_tree_host_unittest.cc
index 7852956..6cb470a 100644
--- a/components/exo/surface_tree_host_unittest.cc
+++ b/components/exo/surface_tree_host_unittest.cc
@@ -15,6 +15,8 @@
 #include "components/exo/surface.h"
 #include "components/exo/test/exo_test_base.h"
 #include "components/exo/test/shell_surface_builder.h"
+#include "components/viz/test/test_raster_interface.h"
+#include "gpu/config/gpu_feature_info.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/layout_manager.h"
@@ -296,4 +298,174 @@
   }
 }
 
+namespace {
+
+//
+class InterceptingTestRasterInterface : public viz::TestRasterInterface {
+ public:
+  InterceptingTestRasterInterface() = default;
+  ~InterceptingTestRasterInterface() override = default;
+
+  // Returns verified and unverified sync tokens the raster interface received
+  // via VerifySyncTokensCHROMIUM.
+  std::pair<int, int> GetAndResetSyncTokensCount() {
+    auto verified_tokens = verified_sync_tokens_;
+    auto unverified_tokens = unverified_sync_tokens_;
+    ResetSyncTokensCount();
+    return {verified_tokens, unverified_tokens};
+  }
+
+  void ResetSyncTokensCount() {
+    verified_sync_tokens_ = 0;
+    unverified_sync_tokens_ = 0;
+  }
+
+  // gpu::raster::RasterInterface overrides:
+  void VerifySyncTokensCHROMIUM(GLbyte** sync_tokens, GLsizei count) override {
+    ResetSyncTokensCount();
+    for (GLsizei i = 0; i < count; ++i) {
+      gpu::SyncToken sync_token_data;
+      memcpy(sync_token_data.GetData(), sync_tokens[i],
+             sizeof(sync_token_data));
+      if (sync_token_data.verified_flush()) {
+        verified_sync_tokens_++;
+      } else {
+        unverified_sync_tokens_++;
+      }
+    }
+    viz::TestRasterInterface::VerifySyncTokensCHROMIUM(sync_tokens, count);
+  }
+
+ private:
+  int verified_sync_tokens_ = 0;
+  int unverified_sync_tokens_ = 0;
+};
+
+class FakeRasterContextProvider
+    : public base::RefCountedThreadSafe<FakeRasterContextProvider>,
+      public viz::RasterContextProvider {
+ public:
+  FakeRasterContextProvider() = default;
+
+  FakeRasterContextProvider(FakeRasterContextProvider&) = delete;
+  FakeRasterContextProvider& operator=(FakeRasterContextProvider&) = delete;
+
+  void SetOnDestroyedClosure(base::OnceClosure on_destroyed) {
+    on_destroyed_ = std::move(on_destroyed);
+  }
+
+  // viz::RasterContextProvider implementation;
+  void AddRef() const override {
+    base::RefCountedThreadSafe<FakeRasterContextProvider>::AddRef();
+  }
+  void Release() const override {
+    base::RefCountedThreadSafe<FakeRasterContextProvider>::Release();
+  }
+  gpu::ContextResult BindToCurrentSequence() override {
+    ADD_FAILURE();
+    return gpu::ContextResult::kFatalFailure;
+  }
+  void AddObserver(viz::ContextLostObserver* obs) override { ADD_FAILURE(); }
+  void RemoveObserver(viz::ContextLostObserver* obs) override { ADD_FAILURE(); }
+  base::Lock* GetLock() override {
+    ADD_FAILURE();
+    return nullptr;
+  }
+  viz::ContextCacheController* CacheController() override {
+    ADD_FAILURE();
+    return nullptr;
+  }
+  gpu::ContextSupport* ContextSupport() override { return nullptr; }
+  class GrDirectContext* GrContext() override {
+    ADD_FAILURE();
+    return nullptr;
+  }
+  gpu::SharedImageInterface* SharedImageInterface() override {
+    ADD_FAILURE();
+    return nullptr;
+  }
+  const gpu::Capabilities& ContextCapabilities() const override {
+    ADD_FAILURE();
+    static gpu::Capabilities dummy_caps;
+    return dummy_caps;
+  }
+  const gpu::GpuFeatureInfo& GetGpuFeatureInfo() const override {
+    ADD_FAILURE();
+    static gpu::GpuFeatureInfo dummy_feature_info;
+    return dummy_feature_info;
+  }
+  gpu::gles2::GLES2Interface* ContextGL() override {
+    ADD_FAILURE();
+    return nullptr;
+  }
+  gpu::raster::RasterInterface* RasterInterface() override {
+    return GetInterceptingTestRasterInterface();
+  }
+  unsigned int GetGrGLTextureFormat(
+      viz::SharedImageFormat format) const override {
+    ADD_FAILURE();
+    return 0;
+  }
+
+  InterceptingTestRasterInterface* GetInterceptingTestRasterInterface() {
+    return &intercepting_test_raster_interface_;
+  }
+
+ private:
+  friend class base::RefCountedThreadSafe<FakeRasterContextProvider>;
+
+  ~FakeRasterContextProvider() override {
+    if (on_destroyed_) {
+      std::move(on_destroyed_).Run();
+    }
+  }
+
+  base::OnceClosure on_destroyed_;
+
+  InterceptingTestRasterInterface intercepting_test_raster_interface_;
+};
+
+}  // namespace
+
+// The SurfaceTreeHost can set sync tokens as verified in advance to have less
+// load on the IPC if they were verified in the previous frame.
+TEST_F(SurfaceTreeHostTest, DoesntVerifyVerifiedSyncTokens) {
+  auto shell_surface = test::ShellSurfaceBuilder({50, 50})
+                           .SetClientSubmitsInPixelCoordinates(true)
+                           .BuildShellSurface();
+  auto* surface = shell_surface->root_surface();
+
+  scoped_refptr<FakeRasterContextProvider> ctx_prodiver =
+      base::MakeRefCounted<FakeRasterContextProvider>();
+  auto old_provider =
+      shell_surface->SetRasterContextProviderForTesting(ctx_prodiver);
+
+  auto* raster_interface = ctx_prodiver->GetInterceptingTestRasterInterface();
+  raster_interface->ResetSyncTokensCount();
+
+  // Create a buffer and attach it to the surface.
+  auto buffer = std::make_unique<Buffer>(
+      exo_test_helper()->CreateGpuMemoryBuffer({50, 50}));
+  surface->Attach(buffer.get());
+
+  surface->Commit();
+
+  // Its a new buffer and a newly generated sync token that shouldn't be known
+  // by the surface_tree_host. Thus, it must be unverified.
+  std::pair<int, int> sync_tokens_count =
+      raster_interface->GetAndResetSyncTokensCount();
+  EXPECT_EQ(0, sync_tokens_count.first);
+  EXPECT_EQ(1, sync_tokens_count.second);
+
+  // Commit the same buffer the second time.
+  surface->Commit();
+  // Same buffer, nothing has been changed. The sync token is known by the
+  // surface_tree_host. Thus, it must be a verified token.
+  sync_tokens_count = raster_interface->GetAndResetSyncTokensCount();
+  EXPECT_EQ(1, sync_tokens_count.first);
+  EXPECT_EQ(0, sync_tokens_count.second);
+
+  shell_surface->SetRasterContextProviderForTesting(old_provider);
+}
+
 }  // namespace exo
diff --git a/components/feature_engagement/public/feature_constants.cc b/components/feature_engagement/public/feature_constants.cc
index 1609688..770aea1 100644
--- a/components/feature_engagement/public/feature_constants.cc
+++ b/components/feature_engagement/public/feature_constants.cc
@@ -43,9 +43,6 @@
 BASE_FEATURE(kIPHDesktopSharedHighlightingFeature,
              "IPH_DesktopSharedHighlighting",
              base::FEATURE_DISABLED_BY_DEFAULT);
-BASE_FEATURE(kIPHDesktopTabGroupsNewGroupFeature,
-             "IPH_DesktopTabGroupsNewGroup",
-             base::FEATURE_DISABLED_BY_DEFAULT);
 BASE_FEATURE(kIPHDesktopCustomizeChromeFeature,
              "IPH_DesktopCustomizeChrome",
              base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/components/feature_engagement/public/feature_constants.h b/components/feature_engagement/public/feature_constants.h
index af14d56..8b18ee73e 100644
--- a/components/feature_engagement/public/feature_constants.h
+++ b/components/feature_engagement/public/feature_constants.h
@@ -33,7 +33,6 @@
 BASE_DECLARE_FEATURE(kIPHComposeMSBBSettingsFeature);
 BASE_DECLARE_FEATURE(kIPHComposeNewBadgeFeature);
 BASE_DECLARE_FEATURE(kIPHDesktopSharedHighlightingFeature);
-BASE_DECLARE_FEATURE(kIPHDesktopTabGroupsNewGroupFeature);
 BASE_DECLARE_FEATURE(kIPHDesktopCustomizeChromeFeature);
 BASE_DECLARE_FEATURE(kIPHDesktopCustomizeChromeRefreshFeature);
 BASE_DECLARE_FEATURE(kIPHDesktopNewTabPageModulesCustomizeFeature);
diff --git a/components/feature_engagement/public/feature_list.cc b/components/feature_engagement/public/feature_list.cc
index 2fcc482..03e74f5 100644
--- a/components/feature_engagement/public/feature_list.cc
+++ b/components/feature_engagement/public/feature_list.cc
@@ -163,7 +163,6 @@
     &kIPHComposeMenuNewBadgeFeature,
     &kIPHComposeMSBBSettingsFeature,
     &kIPHComposeNewBadgeFeature,
-    &kIPHDesktopTabGroupsNewGroupFeature,
     &kIPHDesktopCustomizeChromeFeature,
     &kIPHDesktopCustomizeChromeRefreshFeature,
     &kIPHDesktopNewTabPageModulesCustomizeFeature,
diff --git a/components/feature_engagement/public/feature_list.h b/components/feature_engagement/public/feature_list.h
index a78e9ab7..5647c1e 100644
--- a/components/feature_engagement/public/feature_list.h
+++ b/components/feature_engagement/public/feature_list.h
@@ -305,8 +305,6 @@
                        "IPH_DesktopCustomizeChromeRefresh");
 DEFINE_VARIATION_PARAM(kIPHDesktopNewTabPageModulesCustomizeFeature,
                        "IPH_DesktopNewTabPageModulesCustomize");
-DEFINE_VARIATION_PARAM(kIPHDesktopTabGroupsNewGroupFeature,
-                       "IPH_DesktopTabGroupsNewGroup");
 DEFINE_VARIATION_PARAM(kIPHDownloadEsbPromoFeature, "IPH_DownloadEsbPromo");
 DEFINE_VARIATION_PARAM(kIPHDownloadToolbarButtonFeature,
                        "IPH_DownloadToolbarButton");
@@ -625,7 +623,6 @@
         VARIATION_ENTRY(kIPHDesktopCustomizeChromeFeature),
         VARIATION_ENTRY(kIPHDesktopCustomizeChromeRefreshFeature),
         VARIATION_ENTRY(kIPHDesktopNewTabPageModulesCustomizeFeature),
-        VARIATION_ENTRY(kIPHDesktopTabGroupsNewGroupFeature),
         VARIATION_ENTRY(kIPHDownloadToolbarButtonFeature),
         VARIATION_ENTRY(kIPHExperimentalAIPromoFeature),
 #if BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/components/live_caption_strings.grdp b/components/live_caption_strings.grdp
index acb5e19..29168af9 100644
--- a/components/live_caption_strings.grdp
+++ b/components/live_caption_strings.grdp
@@ -50,7 +50,7 @@
     Caption settings
   </message>
   <message name="IDS_LIVE_CAPTION_DOWNLOAD_PROGRESS" desc="Download progress indicator after Live Caption is enabled. The user needs to download certain files for the feature to work.">
-   Downloading <ph name="LANGUAGE">$1<ex>Spanish</ex></ph> language pack...<ph name="PERCENT">$2<ex>17</ex></ph>%
+   Downloading <ph name="LANGUAGE">$1<ex>Spanish</ex></ph> language pack... <ph name="PERCENT">$2<ex>17</ex></ph>%
   </message>
   <message name="IDS_LIVE_CAPTION_LANGUAGE_DOWNLOAD_FAILED" desc="TODO.">
    Failed to download <ph name="LANGUAGE">$1<ex>Spanish</ex></ph>
diff --git a/components/live_caption_strings_grdp/IDS_LIVE_CAPTION_DOWNLOAD_PROGRESS.png.sha1 b/components/live_caption_strings_grdp/IDS_LIVE_CAPTION_DOWNLOAD_PROGRESS.png.sha1
index 7d2b894..82c024a 100644
--- a/components/live_caption_strings_grdp/IDS_LIVE_CAPTION_DOWNLOAD_PROGRESS.png.sha1
+++ b/components/live_caption_strings_grdp/IDS_LIVE_CAPTION_DOWNLOAD_PROGRESS.png.sha1
@@ -1 +1 @@
-ec4046ce4d46b8641d454b6ea73306a964166bec
\ No newline at end of file
+6468d15b8234af53811c2cc767da215ecd48940c
\ No newline at end of file
diff --git a/components/network_session_configurator/browser/network_session_configurator.cc b/components/network_session_configurator/browser/network_session_configurator.cc
index bedb99d3..0bd5e2f1 100644
--- a/components/network_session_configurator/browser/network_session_configurator.cc
+++ b/components/network_session_configurator/browser/network_session_configurator.cc
@@ -189,14 +189,6 @@
       GetVariationParam(quic_trial_params, "enable_quic"), "false");
 }
 
-bool ShouldEnableQuicProxiesForHttpsUrls(
-    const VariationParameters& quic_trial_params) {
-  return base::EqualsCaseInsensitiveASCII(
-      GetVariationParam(quic_trial_params,
-                        "enable_quic_proxies_for_https_urls"),
-      "true");
-}
-
 bool ShouldRetryWithoutAltSvcOnQuicErrors(
     const VariationParameters& quic_trial_params) {
   return !base::EqualsCaseInsensitiveASCII(
@@ -579,8 +571,6 @@
       ShouldRetryWithoutAltSvcOnQuicErrors(quic_trial_params);
 
   if (params->enable_quic) {
-    params->enable_quic_proxies_for_https_urls =
-        ShouldEnableQuicProxiesForHttpsUrls(quic_trial_params);
     quic_params->connection_options =
         GetQuicConnectionOptions(quic_trial_params);
     quic_params->client_connection_options =
diff --git a/components/network_session_configurator/browser/network_session_configurator_unittest.cc b/components/network_session_configurator/browser/network_session_configurator_unittest.cc
index 6854baf..8ca7a67 100644
--- a/components/network_session_configurator/browser/network_session_configurator_unittest.cc
+++ b/components/network_session_configurator/browser/network_session_configurator_unittest.cc
@@ -99,7 +99,6 @@
 
   EXPECT_EQ(net::DefaultSupportedQuicVersions(),
             quic_params_.supported_versions);
-  EXPECT_FALSE(params_.enable_quic_proxies_for_https_urls);
   EXPECT_EQ(0u, quic_params_.origins_to_force_quic_on.size());
   EXPECT_FALSE(
       quic_params_.initial_delay_for_broken_alternative_service.has_value());
@@ -198,17 +197,6 @@
   EXPECT_TRUE(params_.enable_quic);
 }
 
-TEST_F(NetworkSessionConfiguratorTest, EnableQuicProxiesForHttpsUrls) {
-  std::map<std::string, std::string> field_trial_params;
-  field_trial_params["enable_quic_proxies_for_https_urls"] = "true";
-  base::AssociateFieldTrialParams("QUIC", "Enabled", field_trial_params);
-  base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
-
-  ParseFieldTrials();
-
-  EXPECT_TRUE(params_.enable_quic_proxies_for_https_urls);
-}
-
 TEST_F(NetworkSessionConfiguratorTest, DisableRetryWithoutAltSvcOnQuicErrors) {
   std::map<std::string, std::string> field_trial_params;
   field_trial_params["retry_without_alt_svc_on_quic_errors"] = "false";
diff --git a/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc b/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc
index 7b94e73d..6524e58cf 100644
--- a/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc
+++ b/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc
@@ -4,6 +4,7 @@
 
 #include "components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.h"
 
+#include "base/containers/span.h"
 #include "base/functional/bind.h"
 #include "base/hash/md5.h"
 #include "base/logging.h"
@@ -64,7 +65,7 @@
           origin, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
 
   base::MD5Digest digest;
-  base::MD5Sum(domain_and_registry.data(), domain_and_registry.size(), &digest);
+  base::MD5Sum(base::as_byte_span(domain_and_registry), &digest);
 
   for (auto& byte : digest.a) {
     if (prefix_length >= 8) {
diff --git a/components/password_manager/core/browser/leak_detection_delegate.cc b/components/password_manager/core/browser/leak_detection_delegate.cc
index 2285209..17c57aa 100644
--- a/components/password_manager/core/browser/leak_detection_delegate.cc
+++ b/components/password_manager/core/browser/leak_detection_delegate.cc
@@ -113,6 +113,9 @@
 
   // A credential is marked as syncing if either the profile store is synced
   // or it is in the account store.
+  // TODO(b/317058107): Revisit if this codepath, and possibly others using
+  // `PasswordForm::Store::kAccountStore` are compatible with ongoing changes
+  // on Android.
   IsSyncing is_syncing{false};
   bool in_account_store = (in_stores & PasswordForm::Store::kAccountStore) ==
                           PasswordForm::Store::kAccountStore;
@@ -120,13 +123,11 @@
   switch (sync_util::GetPasswordSyncState(sync_service)) {
     case sync_util::SyncState::kNotActive:
       break;
-    case sync_util::SyncState::kAccountPasswordsActiveNormalEncryption:
-    case sync_util::SyncState::kAccountPasswordsActiveWithCustomPassphrase:
-      is_syncing = IsSyncing(in_account_store);
-      break;
-    case sync_util::SyncState::kSyncingWithCustomPassphrase:
-    case sync_util::SyncState::kSyncingNormalEncryption:
-      is_syncing = IsSyncing(true);
+    case sync_util::SyncState::kActiveWithNormalEncryption:
+    case sync_util::SyncState::kActiveWithCustomPassphrase:
+      is_syncing = IsSyncing(
+          in_account_store ||
+          sync_util::IsSyncFeatureEnabledIncludingPasswords(sync_service));
       break;
   }
 
diff --git a/components/password_manager/core/browser/leak_detection_delegate_unittest.cc b/components/password_manager/core/browser/leak_detection_delegate_unittest.cc
index 6a84e27..9ffb83d 100644
--- a/components/password_manager/core/browser/leak_detection_delegate_unittest.cc
+++ b/components/password_manager/core/browser/leak_detection_delegate_unittest.cc
@@ -363,7 +363,9 @@
       .WillByDefault(Return(profile_store()));
 
   ASSERT_EQ(sync_util::GetPasswordSyncState(sync_service()),
-            sync_util::SyncState::kSyncingNormalEncryption);
+            sync_util::SyncState::kActiveWithNormalEncryption);
+  ASSERT_TRUE(
+      sync_util::IsSyncFeatureEnabledIncludingPasswords(sync_service()));
 
   ExpectPasswords({form});
   EXPECT_CALL(factory(), TryCreateLeakCheck)
@@ -397,7 +399,9 @@
   sync_service()->GetUserSettings()->ClearInitialSyncFeatureSetupComplete();
 
   ASSERT_EQ(sync_util::GetPasswordSyncState(sync_service()),
-            sync_util::SyncState::kAccountPasswordsActiveNormalEncryption);
+            sync_util::SyncState::kActiveWithNormalEncryption);
+  ASSERT_FALSE(
+      sync_util::IsSyncFeatureEnabledIncludingPasswords(sync_service()));
 
   ExpectPasswords({form}, /*store=*/account_store());
   ExpectPasswords({}, /*store=*/profile_store());
@@ -433,7 +437,9 @@
   sync_service()->GetUserSettings()->ClearInitialSyncFeatureSetupComplete();
 
   ASSERT_EQ(sync_util::GetPasswordSyncState(sync_service()),
-            sync_util::SyncState::kAccountPasswordsActiveNormalEncryption);
+            sync_util::SyncState::kActiveWithNormalEncryption);
+  ASSERT_FALSE(
+      sync_util::IsSyncFeatureEnabledIncludingPasswords(sync_service()));
 
   ExpectPasswords({}, /*store=*/account_store());
   ExpectPasswords({form}, /*store=*/profile_store());
diff --git a/components/password_manager/core/browser/password_feature_manager_impl.cc b/components/password_manager/core/browser/password_feature_manager_impl.cc
index ee1d935..93a680b 100644
--- a/components/password_manager/core/browser/password_feature_manager_impl.cc
+++ b/components/password_manager/core/browser/password_feature_manager_impl.cc
@@ -28,10 +28,8 @@
   switch (password_manager::sync_util::GetPasswordSyncState(sync_service_)) {
     case sync_util::SyncState::kNotActive:
       return ShouldShowAccountStorageOptIn();
-    case sync_util::SyncState::kSyncingWithCustomPassphrase:
-    case sync_util::SyncState::kSyncingNormalEncryption:
-    case sync_util::SyncState::kAccountPasswordsActiveNormalEncryption:
-    case sync_util::SyncState::kAccountPasswordsActiveWithCustomPassphrase:
+    case sync_util::SyncState::kActiveWithNormalEncryption:
+    case sync_util::SyncState::kActiveWithCustomPassphrase:
       return true;
   }
 }
diff --git a/components/password_manager/core/browser/password_feature_manager_impl_unittest.cc b/components/password_manager/core/browser/password_feature_manager_impl_unittest.cc
index 7dd64ca..262750e 100644
--- a/components/password_manager/core/browser/password_feature_manager_impl_unittest.cc
+++ b/components/password_manager/core/browser/password_feature_manager_impl_unittest.cc
@@ -72,9 +72,12 @@
   sync_service_.GetUserSettings()->SetSelectedType(
       syncer::UserSelectableType::kPasswords, true);
 
-  ASSERT_EQ(password_manager::sync_util::GetPasswordSyncState(&sync_service_),
-            password_manager::sync_util::SyncState::
-                kAccountPasswordsActiveNormalEncryption);
+  ASSERT_EQ(
+      password_manager::sync_util::GetPasswordSyncState(&sync_service_),
+      password_manager::sync_util::SyncState::kActiveWithNormalEncryption);
+  ASSERT_FALSE(
+      password_manager::sync_util::IsSyncFeatureEnabledIncludingPasswords(
+          &sync_service_));
 
   EXPECT_TRUE(password_feature_manager_.IsGenerationEnabled());
 }
@@ -87,8 +90,12 @@
   sync_service_.GetUserSettings()->SetSelectedType(
       syncer::UserSelectableType::kPasswords, true);
 
-  ASSERT_EQ(password_manager::sync_util::GetPasswordSyncState(&sync_service_),
-            password_manager::sync_util::SyncState::kSyncingNormalEncryption);
+  ASSERT_EQ(
+      password_manager::sync_util::GetPasswordSyncState(&sync_service_),
+      password_manager::sync_util::SyncState::kActiveWithNormalEncryption);
+  ASSERT_TRUE(
+      password_manager::sync_util::IsSyncFeatureEnabledIncludingPasswords(
+          &sync_service_));
 
   EXPECT_TRUE(password_feature_manager_.IsGenerationEnabled());
 }
diff --git a/components/password_manager/core/browser/password_sync_util.cc b/components/password_manager/core/browser/password_sync_util.cc
index fd1c7537..20873ba 100644
--- a/components/password_manager/core/browser/password_sync_util.cc
+++ b/components/password_manager/core/browser/password_sync_util.cc
@@ -113,15 +113,9 @@
     return SyncState::kNotActive;
   }
 
-  if (sync_service->IsSyncFeatureActive()) {
-    return sync_service->GetUserSettings()->IsUsingExplicitPassphrase()
-               ? SyncState::kSyncingWithCustomPassphrase
-               : SyncState::kSyncingNormalEncryption;
-  }
-
   return sync_service->GetUserSettings()->IsUsingExplicitPassphrase()
-             ? SyncState::kAccountPasswordsActiveWithCustomPassphrase
-             : SyncState::kAccountPasswordsActiveNormalEncryption;
+             ? SyncState::kActiveWithCustomPassphrase
+             : SyncState::kActiveWithNormalEncryption;
 }
 
 }  // namespace sync_util
diff --git a/components/password_manager/core/browser/password_sync_util.h b/components/password_manager/core/browser/password_sync_util.h
index 241482c..fba294da 100644
--- a/components/password_manager/core/browser/password_sync_util.h
+++ b/components/password_manager/core/browser/password_sync_util.h
@@ -23,13 +23,8 @@
 
 enum class SyncState {
   kNotActive,
-  kSyncingNormalEncryption,
-  kSyncingWithCustomPassphrase,
-  // Sync is disabled but the user is signed in and opted in to passwords
-  // account storage.
-  kAccountPasswordsActiveNormalEncryption,
-  // Same as above but the account has a custom passphrase set.
-  kAccountPasswordsActiveWithCustomPassphrase,
+  kActiveWithNormalEncryption,
+  kActiveWithCustomPassphrase,
 };
 
 // Uses `sync_service` to determine whether the user is signed in with
@@ -88,8 +83,6 @@
 
 // Reports whether and how passwords are currently synced. In particular, for a
 // null `sync_service` returns kNotActive.
-// TODO(b/1488793): Revisit this function and avoid distinguishing account
-// passwords from full sync.
 SyncState GetPasswordSyncState(const syncer::SyncService* sync_service);
 
 }  // namespace sync_util
diff --git a/components/password_manager/core/browser/password_sync_util_unittest.cc b/components/password_manager/core/browser/password_sync_util_unittest.cc
index 446fc479..47f689b 100644
--- a/components/password_manager/core/browser/password_sync_util_unittest.cc
+++ b/components/password_manager/core/browser/password_sync_util_unittest.cc
@@ -120,7 +120,7 @@
   EXPECT_EQ(
       active_info.email,
       GetAccountEmailIfSyncFeatureEnabledIncludingPasswords(&sync_service));
-  EXPECT_EQ(SyncState::kSyncingNormalEncryption,
+  EXPECT_EQ(SyncState::kActiveWithNormalEncryption,
             GetPasswordSyncState(&sync_service));
 }
 
@@ -151,7 +151,7 @@
   EXPECT_EQ(
       active_info.email,
       GetAccountEmailIfSyncFeatureEnabledIncludingPasswords(&sync_service));
-  EXPECT_EQ(SyncState::kSyncingWithCustomPassphrase,
+  EXPECT_EQ(SyncState::kActiveWithCustomPassphrase,
             GetPasswordSyncState(&sync_service));
 }
 
@@ -167,7 +167,7 @@
   EXPECT_EQ(
       std::string(),
       GetAccountEmailIfSyncFeatureEnabledIncludingPasswords(&sync_service));
-  EXPECT_EQ(SyncState::kAccountPasswordsActiveNormalEncryption,
+  EXPECT_EQ(SyncState::kActiveWithNormalEncryption,
             GetPasswordSyncState(&sync_service));
 }
 
@@ -184,7 +184,7 @@
   EXPECT_EQ(
       std::string(),
       GetAccountEmailIfSyncFeatureEnabledIncludingPasswords(&sync_service));
-  EXPECT_EQ(SyncState::kAccountPasswordsActiveWithCustomPassphrase,
+  EXPECT_EQ(SyncState::kActiveWithCustomPassphrase,
             GetPasswordSyncState(&sync_service));
 }
 
diff --git a/components/password_manager/core/browser/store_metrics_reporter.cc b/components/password_manager/core/browser/store_metrics_reporter.cc
index cea96065..5046c4c 100644
--- a/components/password_manager/core/browser/store_metrics_reporter.cc
+++ b/components/password_manager/core/browser/store_metrics_reporter.cc
@@ -56,15 +56,11 @@
 bool IsCustomPassphraseEnabled(
     password_manager::sync_util::SyncState sync_state) {
   switch (sync_state) {
-    case password_manager::sync_util::SyncState::kSyncingWithCustomPassphrase:
-    case password_manager::sync_util::SyncState::
-        kAccountPasswordsActiveWithCustomPassphrase:
-      return true;
     case password_manager::sync_util::SyncState::kNotActive:
-    case password_manager::sync_util::SyncState::kSyncingNormalEncryption:
-    case password_manager::sync_util::SyncState::
-        kAccountPasswordsActiveNormalEncryption:
+    case password_manager::sync_util::SyncState::kActiveWithNormalEncryption:
       return false;
+    case password_manager::sync_util::SyncState::kActiveWithCustomPassphrase:
+      return true;
   }
   NOTREACHED_NORETURN();
 }
diff --git a/components/privacy_sandbox_strings.grdp b/components/privacy_sandbox_strings.grdp
index 39a95dc..d5b8dd4 100644
--- a/components/privacy_sandbox_strings.grdp
+++ b/components/privacy_sandbox_strings.grdp
@@ -179,7 +179,7 @@
   <message name="IDS_SETTINGS_TOPICS_PAGE_TOGGLE_SUB_LABEL" desc="A description of the new Ad topics setting. This text appears beneath the name of the new setting, 'Ad topics', and is associated with the control that a user can turn on or off. * 'browsing history': This help-center article explains 'browsing history' to users: https://support.google.com/chrome/answer/95589. * Ad topics are published at https://github.com/patcg-individual-drafts/topics/blob/main/taxonomy_v1.md * 'used by sites': Chrome estimates a user's topics of interest. As the user continues browsing, a site can ask Chrome for up to 3 of the user's topics to personalize ads for that user. **** CONTEXT PRIVACY SANDBOX **** Chrome’s Privacy Sandbox initiative 1) deprecates third-party cookies in Chrome, 2) supports free and open content on the web (by finding better ways to support ads online), 3) while providing stronger privacy protections for users. You can see a high-level description of this public project at www.privacysanbox.com. **** NEW SETTINGS SECTION IN CHROME **** 3 new ad-specific settings appear on an “Ad privacy” page in Chrome settings. For an equivalent structure, see “Security” on chrome://settings/privacy that opens chrome://settings/security. Likewise, “Ad privacy” on chrome://settings/privacy will open chrome://settings/AdPrivacy." formatter_data="android_java">
     Topics of interest are based on your recent browsing history and are used by sites to show you personalized ads
   </message>
-  <message name="IDS_SETTINGS_TOPICS_PAGE_TOGGLE_SUB_LABEL_V2" desc="A description of the new Ad topics setting page. This sits under the toggle to turn on the topics API." translateable="false">
+  <message name="IDS_SETTINGS_TOPICS_PAGE_TOGGLE_SUB_LABEL_V2" desc="A description of the new Ad topics setting page. This sits under the toggle to turn on the topics API." formatter_data="android_java" translateable="false">
     Topics are based on your recent browsing history and are used by sites to show you personalized ads while protecting your identity
   </message>
   <message name="IDS_SETTINGS_TOPICS_PAGE_DISCLAIMER" desc="Disclaimer of the new Ad topics setting. This text appears beneath the sublabel." translateable="false">
diff --git a/components/reading_list/core/dual_reading_list_model_unittest.cc b/components/reading_list/core/dual_reading_list_model_unittest.cc
index 366d4b5..dc898ef 100644
--- a/components/reading_list/core/dual_reading_list_model_unittest.cc
+++ b/components/reading_list/core/dual_reading_list_model_unittest.cc
@@ -1281,29 +1281,6 @@
             StorageStateForTesting::kExistsInAccountModelOnly);
 }
 
-TEST_F(DualReadingListModelTest, AddEntryFromLocalModel) {
-  ASSERT_TRUE(ResetStorageAndMimicSignedInSyncDisabled());
-  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kUrl),
-            StorageStateForTesting::kNotFound);
-  ASSERT_THAT(dual_model_->GetEntryByURL(kUrl), IsNull());
-
-  testing::InSequence seq;
-  EXPECT_CALL(observer_,
-              ReadingListWillAddEntry(dual_model_.get(), HasUrl(kUrl)));
-  EXPECT_CALL(observer_,
-              ReadingListDidAddEntry(dual_model_.get(), kUrl,
-                                     reading_list::ADDED_VIA_CURRENT_APP));
-  EXPECT_CALL(observer_, ReadingListDidApplyChanges(dual_model_.get()));
-
-  dual_model_->GetLocalOrSyncableModel()->AddOrReplaceEntry(
-      kUrl, "entry_title", reading_list::ADDED_VIA_CURRENT_APP,
-      /*estimated_read_time=*/base::TimeDelta());
-
-  EXPECT_THAT(dual_model_->GetEntryByURL(kUrl), NotNull());
-  EXPECT_EQ(dual_model_->GetStorageStateForURLForTesting(kUrl),
-            StorageStateForTesting::kExistsInLocalOrSyncableModelOnly);
-}
-
 TEST_F(DualReadingListModelTest, AddLocalExistingEntryFromSync) {
   ASSERT_TRUE(ResetStorageAndMimicSignedInSyncDisabled(
       /*initial_local_entries_builders=*/{
@@ -1327,7 +1304,30 @@
             StorageStateForTesting::kExistsInBothModels);
 }
 
-TEST_F(DualReadingListModelTest, AddExistingEntryFromLocalModel) {
+TEST_F(DualReadingListModelTest, AddEntryFromTheLocalModel) {
+  ASSERT_TRUE(ResetStorageAndMimicSignedInSyncDisabled());
+  ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kUrl),
+            StorageStateForTesting::kNotFound);
+  ASSERT_THAT(dual_model_->GetEntryByURL(kUrl), IsNull());
+
+  testing::InSequence seq;
+  EXPECT_CALL(observer_,
+              ReadingListWillAddEntry(dual_model_.get(), HasUrl(kUrl)));
+  EXPECT_CALL(observer_,
+              ReadingListDidAddEntry(dual_model_.get(), kUrl,
+                                     reading_list::ADDED_VIA_CURRENT_APP));
+  EXPECT_CALL(observer_, ReadingListDidApplyChanges(dual_model_.get()));
+
+  dual_model_->GetLocalOrSyncableModel()->AddOrReplaceEntry(
+      kUrl, "entry_title", reading_list::ADDED_VIA_CURRENT_APP,
+      /*estimated_read_time=*/base::TimeDelta());
+
+  EXPECT_THAT(dual_model_->GetEntryByURL(kUrl), NotNull());
+  EXPECT_EQ(dual_model_->GetStorageStateForURLForTesting(kUrl),
+            StorageStateForTesting::kExistsInLocalOrSyncableModelOnly);
+}
+
+TEST_F(DualReadingListModelTest, AddExistingEntryFromTheLocalModel) {
   ASSERT_TRUE(ResetStorageAndMimicSignedInSyncDisabled(
       /*initial_local_entries_builders=*/{},
       /*initial_account_entries_builders=*/{
diff --git a/components/safe_browsing/core/common/safe_browsing_prefs.cc b/components/safe_browsing/core/common/safe_browsing_prefs.cc
index e7a88bf..10e255a1 100644
--- a/components/safe_browsing/core/common/safe_browsing_prefs.cc
+++ b/components/safe_browsing/core/common/safe_browsing_prefs.cc
@@ -235,9 +235,6 @@
                                 true);
   registry->RegisterBooleanPref(prefs::kSafeBrowsingSurveysEnabled, true);
   registry->RegisterBooleanPref(prefs::kSafeBrowsingDeepScanningEnabled, true);
-  registry->RegisterBooleanPref(prefs::kSafeBrowsingDeepScanPromptSeen, false);
-  registry->RegisterTimePref(prefs::kSafeBrowsingEsbEnabledTimestamp,
-                             base::Time());
 }
 
 const base::Value::Dict& GetExtensionTelemetryConfig(const PrefService& prefs) {
diff --git a/components/safe_browsing/core/common/safe_browsing_prefs.h b/components/safe_browsing/core/common/safe_browsing_prefs.h
index 4d88a86..e2c97c8 100644
--- a/components/safe_browsing/core/common/safe_browsing_prefs.h
+++ b/components/safe_browsing/core/common/safe_browsing_prefs.h
@@ -230,21 +230,6 @@
 inline constexpr char kHashPrefixRealTimeChecksAllowedByPolicy[] =
     "safebrowsing.hash_prefix_real_time_checks_allowed_by_policy";
 
-// A boolean indicating if the user has previously seen a deep
-// scanning prompt.
-inline constexpr char kSafeBrowsingDeepScanPromptSeen[] =
-    "safebrowsing.deep_scan_prompt_seen";
-
-// A timestamp indicating when the user most recently enrolled in
-// Enhanced Safe Browsing. For users who enrolled in Enhanced Safe
-// Browsing before this pref was added, the timestamp is the first
-// Chrome startup with the pref, so the timestamp should be considered
-// a lower bound on the amount of time a user has been
-// enrolled. Contains a null time for users not enrolled in Enhanced
-// Safe Browsing.
-inline constexpr char kSafeBrowsingEsbEnabledTimestamp[] =
-    "safebrowsing.esb_enabled_timestamp";
-
 }  // namespace prefs
 
 namespace safe_browsing {
diff --git a/components/segmentation_platform/internal/database/ukm_url_table.cc b/components/segmentation_platform/internal/database/ukm_url_table.cc
index 1b10d89..c557cb61 100644
--- a/components/segmentation_platform/internal/database/ukm_url_table.cc
+++ b/components/segmentation_platform/internal/database/ukm_url_table.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/containers/span.h"
 #include "base/hash/md5.h"
 #include "base/logging.h"
 #include "base/sys_byteorder.h"
@@ -33,7 +34,7 @@
   // hashing scheme is architecture dependent.
   std::string db_url = GetDatabaseUrlString(url);
   base::MD5Digest digest;
-  base::MD5Sum(db_url.data(), db_url.size(), &digest);
+  base::MD5Sum(base::as_byte_span(db_url), &digest);
   int64_t hash;
   memcpy(&hash, digest.a, sizeof(int64_t));
   return UrlId::FromUnsafeValue(hash);
diff --git a/components/viz/common/BUILD.gn b/components/viz/common/BUILD.gn
index 4fb0378..e26ae1e 100644
--- a/components/viz/common/BUILD.gn
+++ b/components/viz/common/BUILD.gn
@@ -157,7 +157,6 @@
     "gpu/context_lost_reason.h",
     "gpu/context_provider.cc",
     "gpu/context_provider.h",
-    "gpu/gpu_vsync_callback.h",
     "gpu/raster_context_provider.cc",
     "gpu/raster_context_provider.h",
     "hit_test/aggregated_hit_test_region.h",
diff --git a/components/viz/common/frame_sinks/begin_frame_source.cc b/components/viz/common/frame_sinks/begin_frame_source.cc
index b19f56e1d..0503d7da 100644
--- a/components/viz/common/frame_sinks/begin_frame_source.cc
+++ b/components/viz/common/frame_sinks/begin_frame_source.cc
@@ -117,9 +117,9 @@
       EstimateTickCountsBetween(frame_time, next_expected_frame_time_,
                                 vsync_interval);
   // This is utilized by ExternalBeginFrameSourceAndroid,
-  // GpuVSyncBeginFrameSource, and DelayBasedBeginFrameSource. Which covers the
-  // main Viz use cases. BackToBackBeginFrameSource is not relevant. We also are
-  // not looking to adjust ExternalBeginFrameSourceMojo which is used in
+  // ExternalBeginFrameSourceWin, and DelayBasedBeginFrameSource. Which covers
+  // the main Viz use cases. BackToBackBeginFrameSource is not relevant. We also
+  // are not looking to adjust ExternalBeginFrameSourceMojo which is used in
   // headless.
   if (dynamic_begin_frame_deadline_offset_source_) {
     base::TimeDelta deadline_offset =
diff --git a/components/viz/common/gpu/gpu_vsync_callback.h b/components/viz/common/gpu/gpu_vsync_callback.h
deleted file mode 100644
index 0f7dc80..0000000
--- a/components/viz/common/gpu/gpu_vsync_callback.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_COMMON_GPU_GPU_VSYNC_CALLBACK_H_
-#define COMPONENTS_VIZ_COMMON_GPU_GPU_VSYNC_CALLBACK_H_
-
-#include "base/functional/callback.h"
-#include "base/time/time.h"
-
-namespace viz {
-
-using GpuVSyncCallback =
-    base::RepeatingCallback<void(base::TimeTicks vsync_time,
-                                 base::TimeDelta vsync_interval)>;
-
-}  // namespace viz
-
-#endif  // COMPONENTS_VIZ_COMMON_GPU_GPU_VSYNC_CALLBACK_H_
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn
index 5a57916..4edf413e 100644
--- a/components/viz/service/BUILD.gn
+++ b/components/viz/service/BUILD.gn
@@ -187,8 +187,6 @@
     "frame_sinks/gmb_video_frame_pool_context_provider.h",
     "frame_sinks/gmb_video_frame_pool_context_provider_impl.cc",
     "frame_sinks/gmb_video_frame_pool_context_provider_impl.h",
-    "frame_sinks/gpu_vsync_begin_frame_source.cc",
-    "frame_sinks/gpu_vsync_begin_frame_source.h",
     "frame_sinks/root_compositor_frame_sink_impl.cc",
     "frame_sinks/root_compositor_frame_sink_impl.h",
     "frame_sinks/surface_resource_holder.cc",
@@ -428,6 +426,8 @@
       "display_embedder/skia_output_device_dcomp.h",
       "display_embedder/software_output_device_win.cc",
       "display_embedder/software_output_device_win.h",
+      "frame_sinks/external_begin_frame_source_win.cc",
+      "frame_sinks/external_begin_frame_source_win.h",
       "gl/info_collection_gpu_service_impl.cc",
       "gl/info_collection_gpu_service_impl.h",
     ]
diff --git a/components/viz/service/display/output_surface.cc b/components/viz/service/display/output_surface.cc
index 23ca02f..2cdfafd 100644
--- a/components/viz/service/display/output_surface.cc
+++ b/components/viz/service/display/output_surface.cc
@@ -76,14 +76,6 @@
   return base::ScopedClosureRunner();
 }
 
-void OutputSurface::SetGpuVSyncCallback(GpuVSyncCallback callback) {
-  NOTREACHED();
-}
-
-void OutputSurface::SetGpuVSyncEnabled(bool enabled) {
-  NOTREACHED();
-}
-
 gpu::Mailbox OutputSurface::GetOverlayMailbox() const {
   return gpu::Mailbox();
 }
diff --git a/components/viz/service/display/output_surface.h b/components/viz/service/display/output_surface.h
index b6a673923..f303162 100644
--- a/components/viz/service/display/output_surface.h
+++ b/components/viz/service/display/output_surface.h
@@ -12,7 +12,6 @@
 #include "base/functional/callback_helpers.h"
 #include "base/threading/thread_checker.h"
 #include "components/viz/common/display/update_vsync_parameters_callback.h"
-#include "components/viz/common/gpu/gpu_vsync_callback.h"
 #include "components/viz/common/resources/returned_resource.h"
 #include "components/viz/service/display/pending_swap_params.h"
 #include "components/viz/service/display/render_pass_alpha_type.h"
@@ -80,8 +79,6 @@
     // (i.e. viewport) of its contents for display, allowing the DirectRenderer
     // to apply resize optimization by padding to its width/height.
     bool supports_viewporter = false;
-    // Whether this OutputSurface supports gpu vsync callbacks.
-    bool supports_gpu_vsync = false;
     // OutputSurface's orientation mode.
     OrientationMode orientation_mode = OrientationMode::kLogic;
     // Whether this OutputSurface supports direct composition layers.
@@ -243,13 +240,6 @@
   virtual void SetUpdateVSyncParametersCallback(
       UpdateVSyncParametersCallback callback) = 0;
 
-  // Set a callback for vsync signal from GPU service for begin frames.  The
-  // callbacks must be received on the calling thread.
-  virtual void SetGpuVSyncCallback(GpuVSyncCallback callback);
-
-  // Enable or disable vsync callback based on whether begin frames are needed.
-  virtual void SetGpuVSyncEnabled(bool enabled);
-
   virtual void SetVSyncDisplayID(int64_t display_id) {}
 
   // When the device is rotated, the scene prepared by the UI is in the logical
diff --git a/components/viz/service/display_embedder/skia_output_device.cc b/components/viz/service/display_embedder/skia_output_device.cc
index 76a4d8a..22d3222 100644
--- a/components/viz/service/display_embedder/skia_output_device.cc
+++ b/components/viz/service/display_embedder/skia_output_device.cc
@@ -187,10 +187,6 @@
   NOTREACHED();
 }
 
-void SkiaOutputDevice::SetGpuVSyncEnabled(bool enabled) {
-  NOTREACHED();
-}
-
 bool SkiaOutputDevice::IsPrimaryPlaneOverlay() const {
   return false;
 }
diff --git a/components/viz/service/display_embedder/skia_output_device.h b/components/viz/service/display_embedder/skia_output_device.h
index d5ef276..790ec19 100644
--- a/components/viz/service/display_embedder/skia_output_device.h
+++ b/components/viz/service/display_embedder/skia_output_device.h
@@ -157,8 +157,6 @@
   // Enable or disable DC layers. Must be called before DC layers are scheduled.
   virtual void SetEnableDCLayers(bool enabled);
 
-  virtual void SetGpuVSyncEnabled(bool enabled);
-
   virtual void SetVSyncDisplayID(int64_t display_id) {}
 
   // Whether the output device's primary plane is an overlay. This returns true
diff --git a/components/viz/service/display_embedder/skia_output_device_dcomp.cc b/components/viz/service/display_embedder/skia_output_device_dcomp.cc
index c4fc4517..80838a42 100644
--- a/components/viz/service/display_embedder/skia_output_device_dcomp.cc
+++ b/components/viz/service/display_embedder/skia_output_device_dcomp.cc
@@ -128,7 +128,6 @@
           features::kDirectCompositionUnlimitedOverlays)) {
     capabilities_.allowed_yuv_overlay_count = INT_MAX;
   }
-  capabilities_.supports_gpu_vsync = true;
   capabilities_.supports_dc_layers = true;
   capabilities_.supports_post_sub_buffer = true;
   capabilities_.supports_delegated_ink = presenter_->SupportsDelegatedInk();
@@ -140,7 +139,6 @@
   DCHECK(context_state_->gr_context() || context_state_->graphite_context());
   DCHECK(context_state_->context());
   DCHECK(presenter_);
-  DCHECK(presenter_->SupportsGpuVSync());
 
   // SRGB
   capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBA_8888)] =
@@ -280,10 +278,6 @@
   return presenter_->SetDrawRectangle(draw_rectangle);
 }
 
-void SkiaOutputDeviceDComp::SetGpuVSyncEnabled(bool enabled) {
-  presenter_->SetGpuVSyncEnabled(enabled);
-}
-
 SkSurface* SkiaOutputDeviceDComp::BeginPaint(
     std::vector<GrBackendSemaphore>* end_semaphores) {
   NOTIMPLEMENTED();
diff --git a/components/viz/service/display_embedder/skia_output_device_dcomp.h b/components/viz/service/display_embedder/skia_output_device_dcomp.h
index e2616490..81258b0 100644
--- a/components/viz/service/display_embedder/skia_output_device_dcomp.h
+++ b/components/viz/service/display_embedder/skia_output_device_dcomp.h
@@ -63,7 +63,6 @@
                float device_scale_factor,
                gfx::OverlayTransform transform) override;
   bool SetDrawRectangle(const gfx::Rect& draw_rectangle) override;
-  void SetGpuVSyncEnabled(bool enabled) override;
   SkSurface* BeginPaint(
       std::vector<GrBackendSemaphore>* end_semaphores) override;
   void EndPaint() override;
diff --git a/components/viz/service/display_embedder/skia_output_device_gl.cc b/components/viz/service/display_embedder/skia_output_device_gl.cc
index 9a52c49..a15f7036 100644
--- a/components/viz/service/display_embedder/skia_output_device_gl.cc
+++ b/components/viz/service/display_embedder/skia_output_device_gl.cc
@@ -115,7 +115,6 @@
   }
   capabilities_.pending_swap_params.max_pending_swaps =
       gl_surface_->GetBufferCount() - 1;
-  capabilities_.supports_gpu_vsync = gl_surface_->SupportsGpuVSync();
 #if BUILDFLAG(IS_ANDROID)
   // TODO(weiliangc): This capability is used to check whether we should do
   // overlay. Since currently none of the other overlay system is implemented,
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.cc b/components/viz/service/display_embedder/skia_output_surface_impl.cc
index 7d12e49..33a4f38c 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -446,16 +446,6 @@
   update_vsync_parameters_callback_ = std::move(callback);
 }
 
-void SkiaOutputSurfaceImpl::SetGpuVSyncEnabled(bool enabled) {
-  auto task = base::BindOnce(&SkiaOutputSurfaceImplOnGpu::SetGpuVSyncEnabled,
-                             base::Unretained(impl_on_gpu_.get()), enabled);
-  gpu_task_scheduler_->ScheduleOrRetainGpuTask(std::move(task), {});
-}
-
-void SkiaOutputSurfaceImpl::SetGpuVSyncCallback(GpuVSyncCallback callback) {
-  gpu_vsync_callback_ = std::move(callback);
-}
-
 void SkiaOutputSurfaceImpl::SetVSyncDisplayID(int64_t display_id) {
   auto task = base::BindOnce(&SkiaOutputSurfaceImplOnGpu::SetVSyncDisplayID,
                              base::Unretained(impl_on_gpu_.get()), display_id);
@@ -1122,29 +1112,9 @@
 
   weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
 
-  // This runner could be called from vsync or GPU thread after |this| is
-  // destroyed. We post directly to display compositor thread to check
-  // |weak_ptr_| as |dependency_| may have been destroyed.
-#if BUILDFLAG(IS_ANDROID)
-  // Callback is never used on Android. Doesn't work with WebView because
-  // calling it bypasses SkiaOutputSurfaceDependency.
-  GpuVSyncCallback vsync_callback_runner = base::DoNothing();
-#else
-  GpuVSyncCallback vsync_callback_runner = base::BindRepeating(
-      [](scoped_refptr<base::SingleThreadTaskRunner> runner,
-         base::WeakPtr<SkiaOutputSurfaceImpl> weak_ptr,
-         base::TimeTicks timebase, base::TimeDelta interval) {
-        runner->PostTask(FROM_HERE,
-                         base::BindOnce(&SkiaOutputSurfaceImpl::OnGpuVSync,
-                                        weak_ptr, timebase, interval));
-      },
-      base::SingleThreadTaskRunner::GetCurrentDefault(), weak_ptr_);
-#endif
-
   bool result = false;
-  auto callback =
-      base::BindOnce(&SkiaOutputSurfaceImpl::InitializeOnGpuThread,
-                     base::Unretained(this), vsync_callback_runner, &result);
+  auto callback = base::BindOnce(&SkiaOutputSurfaceImpl::InitializeOnGpuThread,
+                                 base::Unretained(this), &result);
   EnqueueGpuTask(std::move(callback), {}, /*make_current=*/false,
                  /*need_framebuffer=*/false);
   // |capabilities_| will be initialized in InitializeOnGpuThread(), so have to
@@ -1177,9 +1147,7 @@
   return result;
 }
 
-void SkiaOutputSurfaceImpl::InitializeOnGpuThread(
-    GpuVSyncCallback vsync_callback_runner,
-    bool* result) {
+void SkiaOutputSurfaceImpl::InitializeOnGpuThread(bool* result) {
   auto did_swap_buffer_complete_callback = base::BindRepeating(
       &SkiaOutputSurfaceImpl::DidSwapBuffersComplete, weak_ptr_);
   auto buffer_presented_callback =
@@ -1198,7 +1166,7 @@
       display_compositor_controller_->controller_on_gpu(),
       std::move(did_swap_buffer_complete_callback),
       std::move(buffer_presented_callback), std::move(context_lost_callback),
-      std::move(schedule_gpu_task), std::move(vsync_callback_runner),
+      std::move(schedule_gpu_task),
       std::move(add_child_window_to_browser_callback),
       std::move(release_overlays_callback));
   if (!impl_on_gpu_) {
@@ -1405,13 +1373,6 @@
   client_->AddChildWindowToBrowser(child_window);
 }
 
-void SkiaOutputSurfaceImpl::OnGpuVSync(base::TimeTicks timebase,
-                                       base::TimeDelta interval) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (gpu_vsync_callback_)
-    gpu_vsync_callback_.Run(timebase, interval);
-}
-
 void SkiaOutputSurfaceImpl::ScheduleGpuTaskForTesting(
     base::OnceClosure callback,
     std::vector<gpu::SyncToken> sync_tokens) {
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.h b/components/viz/service/display_embedder/skia_output_surface_impl.h
index 3d1e9c5..dc82496 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl.h
+++ b/components/viz/service/display_embedder/skia_output_surface_impl.h
@@ -97,8 +97,6 @@
   void Reshape(const ReshapeParams& params) override;
   void SetUpdateVSyncParametersCallback(
       UpdateVSyncParametersCallback callback) override;
-  void SetGpuVSyncEnabled(bool enabled) override;
-  void SetGpuVSyncCallback(GpuVSyncCallback callback) override;
   void SetVSyncDisplayID(int64_t display_id) override;
   void SetDisplayTransformHint(gfx::OverlayTransform transform) override;
   gfx::OverlayTransform GetDisplayTransform() override;
@@ -207,8 +205,7 @@
 
  private:
   bool Initialize();
-  void InitializeOnGpuThread(GpuVSyncCallback vsync_callback_runner,
-                             bool* result);
+  void InitializeOnGpuThread(bool* result);
   GrSurfaceCharacterization CreateGrSurfaceCharacterizationRenderPass(
       const gfx::Size& surface_size,
       SkColorType color_type,
@@ -230,9 +227,6 @@
   void BufferPresented(const gfx::PresentationFeedback& feedback);
   void AddChildWindowToBrowser(gpu::SurfaceHandle child_window);
 
-  // Provided as a callback for the GPU thread.
-  void OnGpuVSync(base::TimeTicks timebase, base::TimeDelta interval);
-
   using GpuTask = base::OnceClosure;
   void EnqueueGpuTask(GpuTask task,
                       std::vector<gpu::SyncToken> sync_tokens,
@@ -282,7 +276,6 @@
   uint64_t sync_fence_release_ = 0;
   raw_ptr<SkiaOutputSurfaceDependency> dependency_;
   UpdateVSyncParametersCallback update_vsync_parameters_callback_;
-  GpuVSyncCallback gpu_vsync_callback_;
   bool is_displayed_as_overlay_ = false;
   gpu::Mailbox last_swapped_mailbox_;
 
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index ed850d5..36b3d0e 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -262,7 +262,6 @@
     BufferPresentedCallback buffer_presented_callback,
     ContextLostCallback context_lost_callback,
     ScheduleGpuTaskCallback schedule_gpu_task,
-    GpuVSyncCallback gpu_vsync_callback,
     AddChildWindowToBrowserCallback add_child_window_to_browser_callback,
     SkiaOutputDevice::ReleaseOverlaysCallback release_overlays_callback) {
   TRACE_EVENT0("viz", "SkiaOutputSurfaceImplOnGpu::Create");
@@ -287,7 +286,7 @@
       context_state->feature_info(), renderer_settings, sequence_id,
       shared_gpu_deps, std::move(did_swap_buffer_complete_callback),
       std::move(buffer_presented_callback), std::move(context_lost_callback),
-      std::move(schedule_gpu_task), std::move(gpu_vsync_callback),
+      std::move(schedule_gpu_task),
       std::move(add_child_window_to_browser_callback),
       std::move(release_overlays_callback));
   if (!impl_on_gpu->Initialize()) {
@@ -308,7 +307,6 @@
     BufferPresentedCallback buffer_presented_callback,
     ContextLostCallback context_lost_callback,
     ScheduleGpuTaskCallback schedule_gpu_task,
-    GpuVSyncCallback gpu_vsync_callback,
     AddChildWindowToBrowserCallback add_child_window_to_browser_callback,
     SkiaOutputDevice::ReleaseOverlaysCallback release_overlays_callback)
     : dependency_(std::move(deps)),
@@ -332,7 +330,6 @@
           std::move(did_swap_buffer_complete_callback)),
       context_lost_callback_(std::move(context_lost_callback)),
       schedule_gpu_task_(std::move(schedule_gpu_task)),
-      gpu_vsync_callback_(std::move(gpu_vsync_callback)),
       add_child_window_to_browser_callback_(
           std::move(add_child_window_to_browser_callback)),
       release_overlays_callback_(release_overlays_callback),
@@ -1896,10 +1893,6 @@
   output_device_->SetEnableDCLayers(enable);
 }
 
-void SkiaOutputSurfaceImplOnGpu::SetGpuVSyncEnabled(bool enabled) {
-  output_device_->SetGpuVSyncEnabled(enabled);
-}
-
 void SkiaOutputSurfaceImplOnGpu::SetVSyncDisplayID(int64_t display_id) {
   output_device_->SetVSyncDisplayID(display_id);
 }
@@ -2482,10 +2475,6 @@
   return gpu_preferences_;
 }
 
-GpuVSyncCallback SkiaOutputSurfaceImplOnGpu::GetGpuVSyncCallback() {
-  return gpu_vsync_callback_;
-}
-
 void SkiaOutputSurfaceImplOnGpu::DidSwapBuffersCompleteInternal(
     gpu::SwapBuffersCompleteParams params,
     const gfx::Size& pixel_size,
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
index 2cfab9d..1380325 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
@@ -107,8 +107,7 @@
   using AddChildWindowToBrowserCallback =
       base::RepeatingCallback<void(gpu::SurfaceHandle child_window)>;
 
-  // |gpu_vsync_callback| must be safe to call on any thread. The other
-  // callbacks will only be called via |deps->PostTaskToClientThread|.
+  // Callbacks will only be called via |deps->PostTaskToClientThread|.
   static std::unique_ptr<SkiaOutputSurfaceImplOnGpu> Create(
       SkiaOutputSurfaceDependency* deps,
       const RendererSettings& renderer_settings,
@@ -118,7 +117,6 @@
       BufferPresentedCallback buffer_presented_callback,
       ContextLostCallback context_lost_callback,
       ScheduleGpuTaskCallback schedule_gpu_task,
-      GpuVSyncCallback gpu_vsync_callback,
       AddChildWindowToBrowserCallback parent_child_Window_to_browser_callback,
       SkiaOutputDevice::ReleaseOverlaysCallback release_overlays_callback);
 
@@ -133,7 +131,6 @@
       BufferPresentedCallback buffer_presented_callback,
       ContextLostCallback context_lost_callback,
       ScheduleGpuTaskCallback schedule_gpu_task,
-      GpuVSyncCallback gpu_vsync_callback,
       AddChildWindowToBrowserCallback parent_child_window_to_browser_callback,
       SkiaOutputDevice::ReleaseOverlaysCallback release_overlays_callback);
 
@@ -244,7 +241,6 @@
 #endif
   const gpu::gles2::FeatureInfo* GetFeatureInfo() const override;
   const gpu::GpuPreferences& GetGpuPreferences() const override;
-  GpuVSyncCallback GetGpuVSyncCallback() override;
 
   void PostTaskToClientThread(base::OnceClosure closure) {
     dependency_->PostTaskToClientThread(std::move(closure));
@@ -520,7 +516,6 @@
   BufferPresentedCallback buffer_presented_callback_;
   ContextLostCallback context_lost_callback_;
   ScheduleGpuTaskCallback schedule_gpu_task_;
-  GpuVSyncCallback gpu_vsync_callback_;
   AddChildWindowToBrowserCallback add_child_window_to_browser_callback_;
   SkiaOutputDevice::ReleaseOverlaysCallback release_overlays_callback_;
 
diff --git a/components/viz/service/frame_sinks/DEPS b/components/viz/service/frame_sinks/DEPS
index e32651a..4677f53 100644
--- a/components/viz/service/frame_sinks/DEPS
+++ b/components/viz/service/frame_sinks/DEPS
@@ -32,4 +32,7 @@
     "+ui/display/mac/display_link_mac.h",
     "+ui/display/types/display_constants.h",
   ],
+  "external_begin_frame_source_win.h": [
+    "+ui/gl/vsync_thread_win.h",
+  ],
 }
diff --git a/components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.cc b/components/viz/service/frame_sinks/external_begin_frame_source_win.cc
similarity index 60%
rename from components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.cc
rename to components/viz/service/frame_sinks/external_begin_frame_source_win.cc
index da01e1a..f093ef04 100644
--- a/components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.cc
+++ b/components/viz/service/frame_sinks/external_begin_frame_source_win.cc
@@ -2,32 +2,40 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.h"
+#include "components/viz/service/frame_sinks/external_begin_frame_source_win.h"
+
+#include <utility>
 
 #include "base/functional/bind.h"
 #include "base/trace_event/trace_event.h"
-#include "components/viz/service/display/output_surface.h"
 
 namespace viz {
 
-GpuVSyncBeginFrameSource::GpuVSyncBeginFrameSource(
+ExternalBeginFrameSourceWin::ExternalBeginFrameSourceWin(
     uint32_t restart_id,
-    OutputSurface* output_surface)
+    scoped_refptr<base::SequencedTaskRunner> task_runner)
     : ExternalBeginFrameSource(this, restart_id),
-      output_surface_(output_surface) {
-  DCHECK(output_surface->capabilities().supports_gpu_vsync);
-  output_surface->SetGpuVSyncCallback(base::BindRepeating(
-      &GpuVSyncBeginFrameSource::OnGpuVSync, base::Unretained(this)));
+      task_runner_(std::move(task_runner)) {}
+
+ExternalBeginFrameSourceWin::~ExternalBeginFrameSourceWin() {
+  if (observing_vsync_) {
+    gl::VSyncThreadWin::GetInstance()->RemoveObserver(this);
+  }
 }
 
-GpuVSyncBeginFrameSource::~GpuVSyncBeginFrameSource() = default;
-
-void GpuVSyncBeginFrameSource::OnGpuVSync(base::TimeTicks vsync_time,
+void ExternalBeginFrameSourceWin::OnVSync(base::TimeTicks vsync_time,
                                           base::TimeDelta vsync_interval) {
+  if (!task_runner_->RunsTasksInCurrentSequence()) {
+    task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(&ExternalBeginFrameSourceWin::OnVSync,
+                       weak_factory_.GetWeakPtr(), vsync_time, vsync_interval));
+    return;
+  }
   vsync_interval_ = vsync_interval;
   if (skip_next_vsync_) {
     TRACE_EVENT_INSTANT0("gpu",
-                         "GpuVSyncBeginFrameSource::OnGpuVSync - skip_vsync",
+                         "ExternalBeginFrameSourceWin::OnVSync - skip_vsync",
                          TRACE_EVENT_SCOPE_THREAD);
     skip_next_vsync_ = false;
     return;
@@ -42,7 +50,7 @@
   ExternalBeginFrameSource::OnBeginFrame(begin_frame_args);
 }
 
-BeginFrameArgs GpuVSyncBeginFrameSource::GetMissedBeginFrameArgs(
+BeginFrameArgs ExternalBeginFrameSourceWin::GetMissedBeginFrameArgs(
     BeginFrameObserver* obs) {
   auto frame_time = last_begin_frame_args_.frame_time;
   auto interval = last_begin_frame_args_.interval;
@@ -66,7 +74,8 @@
   return ExternalBeginFrameSource::GetMissedBeginFrameArgs(obs);
 }
 
-void GpuVSyncBeginFrameSource::SetPreferredInterval(base::TimeDelta interval) {
+void ExternalBeginFrameSourceWin::SetPreferredInterval(
+    base::TimeDelta interval) {
   auto interval_for_half_refresh_rate = vsync_interval_ * 2;
   constexpr auto kMaxDelta = base::Milliseconds(0.5);
   bool run_at_half_refresh_rate =
@@ -74,26 +83,34 @@
   if (run_at_half_refresh_rate_ == run_at_half_refresh_rate)
     return;
 
-  TRACE_EVENT1("gpu", "GpuVSyncBeginFrameSource::SetPreferredInterval",
+  TRACE_EVENT1("gpu", "ExternalBeginFrameSourceWin::SetPreferredInterval",
                "run_at_half_refresh_rate", run_at_half_refresh_rate);
   run_at_half_refresh_rate_ = run_at_half_refresh_rate;
   skip_next_vsync_ = false;
 }
 
-void GpuVSyncBeginFrameSource::SetDynamicBeginFrameDeadlineOffsetSource(
+void ExternalBeginFrameSourceWin::SetDynamicBeginFrameDeadlineOffsetSource(
     DynamicBeginFrameDeadlineOffsetSource*
         dynamic_begin_frame_deadline_offset_source) {
   begin_frame_args_generator_.set_dynamic_begin_frame_deadline_offset_source(
       dynamic_begin_frame_deadline_offset_source);
 }
 
-void GpuVSyncBeginFrameSource::OnNeedsBeginFrames(bool needs_begin_frames) {
+void ExternalBeginFrameSourceWin::OnNeedsBeginFrames(bool needs_begin_frames) {
+  if (observing_vsync_ == needs_begin_frames) {
+    return;
+  }
+  observing_vsync_ = needs_begin_frames;
   skip_next_vsync_ = false;
-  output_surface_->SetGpuVSyncEnabled(needs_begin_frames);
+  if (needs_begin_frames) {
+    gl::VSyncThreadWin::GetInstance()->AddObserver(this);
+  } else {
+    gl::VSyncThreadWin::GetInstance()->RemoveObserver(this);
+  }
 }
 
-void GpuVSyncBeginFrameSource::SetVSyncDisplayID(int64_t display_id) {
-  output_surface_->SetVSyncDisplayID(display_id);
+void ExternalBeginFrameSourceWin::SetVSyncDisplayID(int64_t display_id) {
+  // TODO(sunnyps): See if we should use non-primary displays for driving vsync.
 }
 
 }  // namespace viz
diff --git a/components/viz/service/frame_sinks/external_begin_frame_source_win.h b/components/viz/service/frame_sinks/external_begin_frame_source_win.h
new file mode 100644
index 0000000..21adbc9
--- /dev/null
+++ b/components/viz/service/frame_sinks/external_begin_frame_source_win.h
@@ -0,0 +1,63 @@
+// Copyright 2019 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VIZ_SERVICE_FRAME_SINKS_EXTERNAL_BEGIN_FRAME_SOURCE_WIN_H_
+#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_EXTERNAL_BEGIN_FRAME_SOURCE_WIN_H_
+
+#include "components/viz/common/display/update_vsync_parameters_callback.h"
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
+#include "components/viz/service/display/frame_rate_decider.h"
+#include "components/viz/service/viz_service_export.h"
+#include "ui/gl/vsync_thread_win.h"
+
+namespace viz {
+
+// Receives begin frames from VSyncThreadWin.
+class VIZ_SERVICE_EXPORT ExternalBeginFrameSourceWin
+    : public ExternalBeginFrameSource,
+      public ExternalBeginFrameSourceClient,
+      public gl::VSyncThreadWin::VSyncObserver {
+ public:
+  ExternalBeginFrameSourceWin(
+      uint32_t restart_id,
+      scoped_refptr<base::SequencedTaskRunner> task_runner);
+
+  ExternalBeginFrameSourceWin(const ExternalBeginFrameSourceWin&) = delete;
+  ExternalBeginFrameSourceWin& operator=(const ExternalBeginFrameSourceWin&) =
+      delete;
+
+  ~ExternalBeginFrameSourceWin() override;
+
+  // ExternalBeginFrameSource implementation.
+  BeginFrameArgs GetMissedBeginFrameArgs(BeginFrameObserver* obs) override;
+  void SetPreferredInterval(base::TimeDelta interval) override;
+  void SetVSyncDisplayID(int64_t display_id) override;
+
+  // BeginFrameSource implementation.
+  void SetDynamicBeginFrameDeadlineOffsetSource(
+      DynamicBeginFrameDeadlineOffsetSource*
+          dynamic_begin_frame_deadline_offset_source) override;
+
+  // ExternalBeginFrameSourceClient implementation.
+  void OnNeedsBeginFrames(bool needs_begin_frames) override;
+
+  // gl::VSyncThreadWin::VSyncObserver implementation.
+  void OnVSync(base::TimeTicks vsync_time, base::TimeDelta interval) override;
+
+ private:
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+  BeginFrameArgsGenerator begin_frame_args_generator_;
+
+  bool observing_vsync_ = false;
+  bool run_at_half_refresh_rate_ = false;
+  bool skip_next_vsync_ = false;
+  base::TimeDelta vsync_interval_ = BeginFrameArgs::DefaultInterval();
+
+  base::WeakPtrFactory<ExternalBeginFrameSourceWin> weak_factory_{this};
+};
+
+}  // namespace viz
+
+#endif  // COMPONENTS_VIZ_SERVICE_FRAME_SINKS_EXTERNAL_BEGIN_FRAME_SOURCE_WIN_H_
diff --git a/components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.h b/components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.h
deleted file mode 100644
index 38e73c5..0000000
--- a/components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GPU_VSYNC_BEGIN_FRAME_SOURCE_H_
-#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GPU_VSYNC_BEGIN_FRAME_SOURCE_H_
-
-#include "base/memory/raw_ptr.h"
-#include "components/viz/common/display/update_vsync_parameters_callback.h"
-#include "components/viz/common/frame_sinks/begin_frame_source.h"
-#include "components/viz/service/display/frame_rate_decider.h"
-#include "components/viz/service/viz_service_export.h"
-
-namespace viz {
-
-class OutputSurface;
-
-// Receives begin frames via OutputSurface::SetGpuVSyncCallback().  Output
-// surface must have |supports_gpu_vsync| capability.  This class is not thread
-// safe so the callbacks must be received on the original thread.  The BFS is
-// guaranteed to outlive the OutputSurface.
-class VIZ_SERVICE_EXPORT GpuVSyncBeginFrameSource
-    : public ExternalBeginFrameSource,
-      public ExternalBeginFrameSourceClient {
- public:
-  GpuVSyncBeginFrameSource(uint32_t restart_id, OutputSurface* output_surface);
-
-  GpuVSyncBeginFrameSource(const GpuVSyncBeginFrameSource&) = delete;
-  GpuVSyncBeginFrameSource& operator=(const GpuVSyncBeginFrameSource&) = delete;
-
-  ~GpuVSyncBeginFrameSource() override;
-
-  // ExternalBeginFrameSource overrides.
-  BeginFrameArgs GetMissedBeginFrameArgs(BeginFrameObserver* obs) override;
-  void SetPreferredInterval(base::TimeDelta interval) override;
-  void SetVSyncDisplayID(int64_t display_id) override;
-
-  // BeginFrameSource:
-  void SetDynamicBeginFrameDeadlineOffsetSource(
-      DynamicBeginFrameDeadlineOffsetSource*
-          dynamic_begin_frame_deadline_offset_source) override;
-
-  // ExternalBeginFrameSourceClient implementation.
-  void OnNeedsBeginFrames(bool needs_begin_frames) override;
-
- private:
-  void OnGpuVSync(base::TimeTicks vsync_time, base::TimeDelta vsync_interval);
-
-  const raw_ptr<OutputSurface, DanglingUntriaged> output_surface_;
-  BeginFrameArgsGenerator begin_frame_args_generator_;
-
-  bool run_at_half_refresh_rate_ = false;
-  bool skip_next_vsync_ = false;
-  base::TimeDelta vsync_interval_ = BeginFrameArgs::DefaultInterval();
-};
-
-}  // namespace viz
-
-#endif  // COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GPU_VSYNC_BEGIN_FRAME_SOURCE_H_
diff --git a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
index daec8c6..fc8cd6e3 100644
--- a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
+++ b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
@@ -25,7 +25,6 @@
 #include "components/viz/service/display_embedder/vsync_parameter_listener.h"
 #include "components/viz/service/frame_sinks/external_begin_frame_source_mojo.h"
 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
-#include "components/viz/service/frame_sinks/gpu_vsync_begin_frame_source.h"
 #include "components/viz/service/hit_test/hit_test_aggregator.h"
 #include "services/viz/public/mojom/compositing/layer_context.mojom.h"
 #include "ui/base/ozone_buildflags.h"
@@ -44,6 +43,10 @@
 #include "components/viz/service/frame_sinks/external_begin_frame_source_mac.h"
 #endif
 
+#if BUILDFLAG(IS_WIN)
+#include "components/viz/service/frame_sinks/external_begin_frame_source_win.h"
+#endif
+
 namespace viz {
 
 class RootCompositorFrameSinkImpl::StandaloneBeginFrameObserver
@@ -151,39 +154,35 @@
           std::make_unique<BackToBackBeginFrameSource>(
               std::make_unique<DelayBasedTimeSource>(
                   base::SingleThreadTaskRunner::GetCurrentDefault().get()));
-    } else if (output_surface->capabilities().supports_gpu_vsync) {
-#if BUILDFLAG(IS_WIN)
-      hw_support_for_multiple_refresh_rates =
-          output_surface->capabilities().supports_dc_layers &&
-          params->set_present_duration_allowed;
-#endif
-      // Vsync updates are required to update the FrameRateDecider with
-      // supported refresh rates.
-#if !BUILDFLAG(IS_APPLE)
-      wants_vsync_updates = true;
-#endif
-      external_begin_frame_source = std::make_unique<GpuVSyncBeginFrameSource>(
-          restart_id, output_surface.get());
     } else {
-      auto time_source = std::make_unique<DelayBasedTimeSource>(
-          base::SingleThreadTaskRunner::GetCurrentDefault().get());
-#if BUILDFLAG(IS_MAC)
+#if BUILDFLAG(IS_WIN)
+      // ExternalBeginFrameSourceWin also uses the D3D11 device used by dcomp.
+      if (output_surface->capabilities().supports_dc_layers) {
+        hw_support_for_multiple_refresh_rates =
+            params->set_present_duration_allowed;
+        // Vsync updates are required to update the FrameRateDecider with
+        // supported refresh rates.
+        wants_vsync_updates = true;
+        external_begin_frame_source =
+            std::make_unique<ExternalBeginFrameSourceWin>(
+                restart_id, base::SingleThreadTaskRunner::GetCurrentDefault());
+      }
+#elif BUILDFLAG(IS_MAC)
       if (base::FeatureList::IsEnabled(
               features::kCVDisplayLinkBeginFrameSource)) {
         external_begin_frame_source =
             std::make_unique<ExternalBeginFrameSourceMac>(
                 restart_id, params->renderer_settings.display_id,
                 output_surface.get());
-      } else {
-        synthetic_begin_frame_source =
-            std::make_unique<DelayBasedBeginFrameSourceMac>(
-                std::move(time_source), restart_id);
       }
-#else
-      synthetic_begin_frame_source =
-          std::make_unique<DelayBasedBeginFrameSource>(std::move(time_source),
-                                                       restart_id);
 #endif
+      if (!external_begin_frame_source) {
+        auto time_source = std::make_unique<DelayBasedTimeSource>(
+            base::SingleThreadTaskRunner::GetCurrentDefault().get());
+        synthetic_begin_frame_source =
+            std::make_unique<DelayBasedBeginFrameSource>(std::move(time_source),
+                                                         restart_id);
+      }
     }
 #endif  // BUILDFLAG(IS_ANDROID)
   }
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 53fc78d..86b88e2 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -571,6 +571,10 @@
     "background_sync/periodic_background_sync_service_impl.h",
     "bad_message.cc",
     "bad_message.h",
+    "binder_wrappers/ad_auction_service_impl_wrapper.cc",
+    "binder_wrappers/ad_auction_service_impl_wrapper.h",
+    "binder_wrappers/keyboard_lock_service_impl_wrapper.cc",
+    "binder_wrappers/keyboard_lock_service_impl_wrapper.h",
     "blob_storage/blob_internals_url_loader.cc",
     "blob_storage/blob_internals_url_loader.h",
     "blob_storage/blob_registry_wrapper.cc",
diff --git a/content/browser/binder_wrappers/OWNERS b/content/browser/binder_wrappers/OWNERS
new file mode 100644
index 0000000..3b71870
--- /dev/null
+++ b/content/browser/binder_wrappers/OWNERS
@@ -0,0 +1,3 @@
+# For security review.
+set noparent
+file://ipc/SECURITY_OWNERS
diff --git a/content/browser/binder_wrappers/ad_auction_service_impl_wrapper.cc b/content/browser/binder_wrappers/ad_auction_service_impl_wrapper.cc
new file mode 100644
index 0000000..157c2bc
--- /dev/null
+++ b/content/browser/binder_wrappers/ad_auction_service_impl_wrapper.cc
@@ -0,0 +1,22 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/binder_wrappers/ad_auction_service_impl_wrapper.h"
+
+#include "content/browser/interest_group/ad_auction_service_impl.h"
+#include "third_party/blink/public/mojom/interest_group/ad_auction_service.mojom.h"
+
+namespace content {
+
+namespace internal {
+
+void AdAuctionServiceImplCreateMojoService(
+    mojo::BinderMapWithContext<RenderFrameHost*>& map) {
+  map.Add<blink::mojom::AdAuctionService>(
+      base::BindRepeating(&AdAuctionServiceImpl::CreateMojoService));
+}
+
+}  // namespace internal
+
+}  // namespace content
diff --git a/content/browser/binder_wrappers/ad_auction_service_impl_wrapper.h b/content/browser/binder_wrappers/ad_auction_service_impl_wrapper.h
new file mode 100644
index 0000000..c56b957
--- /dev/null
+++ b/content/browser/binder_wrappers/ad_auction_service_impl_wrapper.h
@@ -0,0 +1,25 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_BINDER_WRAPPERS_AD_AUCTION_SERVICE_IMPL_WRAPPER_H_
+#define CONTENT_BROWSER_BINDER_WRAPPERS_AD_AUCTION_SERVICE_IMPL_WRAPPER_H_
+
+#include "mojo/public/cpp/bindings/binder_map.h"
+
+namespace content {
+
+class RenderFrameHost;
+
+// These are only used from functions in internal namespace of
+// browser_interface_binders.cc, so we use internal namespace here as well.
+namespace internal {
+
+void AdAuctionServiceImplCreateMojoService(
+    mojo::BinderMapWithContext<RenderFrameHost*>& map);
+
+}  // namespace internal
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_BINDER_WRAPPERS_AD_AUCTION_SERVICE_IMPL_WRAPPER_H_
diff --git a/content/browser/binder_wrappers/keyboard_lock_service_impl_wrapper.cc b/content/browser/binder_wrappers/keyboard_lock_service_impl_wrapper.cc
new file mode 100644
index 0000000..c22d6888
--- /dev/null
+++ b/content/browser/binder_wrappers/keyboard_lock_service_impl_wrapper.cc
@@ -0,0 +1,22 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/binder_wrappers/keyboard_lock_service_impl_wrapper.h"
+
+#include "content/browser/keyboard_lock/keyboard_lock_service_impl.h"
+#include "third_party/blink/public/mojom/keyboard_lock/keyboard_lock.mojom.h"
+
+namespace content {
+
+namespace internal {
+
+void KeyboardLockServiceImplCreateMojoService(
+    mojo::BinderMapWithContext<RenderFrameHost*>& map) {
+  map.Add<blink::mojom::KeyboardLockService>(
+      base::BindRepeating(&KeyboardLockServiceImpl::CreateMojoService));
+}
+
+}  // namespace internal
+
+}  // namespace content
diff --git a/content/browser/binder_wrappers/keyboard_lock_service_impl_wrapper.h b/content/browser/binder_wrappers/keyboard_lock_service_impl_wrapper.h
new file mode 100644
index 0000000..294e14a
--- /dev/null
+++ b/content/browser/binder_wrappers/keyboard_lock_service_impl_wrapper.h
@@ -0,0 +1,25 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_BINDER_WRAPPERS_KEYBOARD_LOCK_SERVICE_IMPL_WRAPPER_H_
+#define CONTENT_BROWSER_BINDER_WRAPPERS_KEYBOARD_LOCK_SERVICE_IMPL_WRAPPER_H_
+
+#include "mojo/public/cpp/bindings/binder_map.h"
+
+namespace content {
+
+class RenderFrameHost;
+
+// These are only used from functions in internal namespace of
+// browser_interface_binders.cc, so we use internal namespace here as well.
+namespace internal {
+
+void KeyboardLockServiceImplCreateMojoService(
+    mojo::BinderMapWithContext<RenderFrameHost*>& map);
+
+}  // namespace internal
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_BINDER_WRAPPERS_KEYBOARD_LOCK_SERVICE_IMPL_WRAPPER_H_
diff --git a/content/browser/browser_interface_binders.cc b/content/browser/browser_interface_binders.cc
index f9dc1e4..4a296c9 100644
--- a/content/browser/browser_interface_binders.cc
+++ b/content/browser/browser_interface_binders.cc
@@ -19,6 +19,8 @@
 #include "content/browser/attribution_reporting/attribution_internals_ui.h"
 #include "content/browser/background_fetch/background_fetch_service_impl.h"
 #include "content/browser/bad_message.h"
+#include "content/browser/binder_wrappers/ad_auction_service_impl_wrapper.h"
+#include "content/browser/binder_wrappers/keyboard_lock_service_impl_wrapper.h"
 #include "content/browser/bluetooth/web_bluetooth_service_impl.h"
 #include "content/browser/browser_context_impl.h"
 #include "content/browser/browser_main_loop.h"
@@ -33,8 +35,6 @@
 #include "content/browser/image_capture/image_capture_impl.h"
 #include "content/browser/indexed_db/indexed_db_internals.mojom.h"
 #include "content/browser/indexed_db/indexed_db_internals_ui.h"
-#include "content/browser/interest_group/ad_auction_service_impl.h"
-#include "content/browser/keyboard_lock/keyboard_lock_service_impl.h"
 #include "content/browser/loader/content_security_notifier.h"
 #include "content/browser/media/media_web_contents_observer.h"
 #include "content/browser/media/midi_host.h"
@@ -1165,11 +1165,11 @@
       base::BindRepeating(&CookieStoreManager::BindReceiverForFrame));
   map->Add<blink::mojom::ContentIndexService>(
       base::BindRepeating(&ContentIndexServiceImpl::CreateForFrame));
-  map->Add<blink::mojom::KeyboardLockService>(
-      base::BindRepeating(&KeyboardLockServiceImpl::CreateMojoService));
+
+  KeyboardLockServiceImplCreateMojoService(*map);
+
   if (base::FeatureList::IsEnabled(blink::features::kInterestGroupStorage)) {
-    map->Add<blink::mojom::AdAuctionService>(
-        base::BindRepeating(&AdAuctionServiceImpl::CreateMojoService));
+    AdAuctionServiceImplCreateMojoService(*map);
   }
   map->Add<blink::mojom::MediaSessionService>(
       base::BindRepeating(&MediaSessionServiceImpl::Create));
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
index 9da3a1c..3ecd107c 100644
--- a/content/browser/devtools/protocol/network_handler.cc
+++ b/content/browser/devtools/protocol/network_handler.cc
@@ -2591,6 +2591,21 @@
           .SetMixedContentType(Security::MixedContentTypeEnum::Blockable)
           .Build();
 
+  if (request.request_body) {
+    request_info->SetHasPostData(true);
+    std::string post_data;
+    auto data_entries =
+        std::make_unique<protocol::Array<protocol::Network::PostDataEntry>>();
+    if (GetPostData(*request.request_body, data_entries.get(), &post_data)) {
+      if (!post_data.empty()) {
+        request_info->SetPostData(post_data);
+      }
+      if (data_entries->size()) {
+        request_info->SetPostDataEntries(std::move(data_entries));
+      }
+    }
+  }
+
   frontend_->RequestWillBeSent(
       request_id, request_id, url, std::move(request_info), current_ticks,
       current_wall_time, std::move(initiator), redirect_emitted_extra_info,
diff --git a/content/browser/network/shared_dictionary_browsertest.cc b/content/browser/network/shared_dictionary_browsertest.cc
index 2785f35..5794031 100644
--- a/content/browser/network/shared_dictionary_browsertest.cc
+++ b/content/browser/network/shared_dictionary_browsertest.cc
@@ -2041,6 +2041,83 @@
   EXPECT_FALSE(observer->details()->is_blocked);
 }
 
+IN_PROC_BROWSER_TEST_P(SharedDictionaryBrowserTest, MatchDestEmptyString) {
+  Shell* shell = GetTargetShell();
+  EXPECT_TRUE(NavigateToURL(shell, GetURL("/shared_dictionary/blank.html")));
+
+  // The response header contains `match-dest=("")` in Use-As-Dictionary header.
+  const GURL dictionary_url = GetURL("/shared_dictionary/test.empty_dest.dict");
+  EXPECT_TRUE(ExecJs(shell->web_contents()->GetPrimaryMainFrame(),
+                     LinkRelDictionaryScript(dictionary_url)));
+
+  // Wait for the dictionary to be registered.
+  EXPECT_TRUE(WaitForHistogram(
+      GetBrowserType() == BrowserType::kNormal
+          ? "Net.SharedDictionaryManagerOnDisk.DictionarySizeKB"
+          : "Net.SharedDictionaryWriterInMemory.DictionarySize"));
+
+  // Check that Chrome uses the dictionary while fetching the resource using
+  // Fetch API.
+  EXPECT_EQ(kCompressedDataOriginalString,
+            EvalJs(shell->web_contents()->GetPrimaryMainFrame(),
+                   FetchTargetDataScript(dictionary_url))
+                .ExtractString());
+
+  switch (GetVersion()) {
+    case network::features::CompressionDictionaryTransportBackendVersion::kV1:
+      // Check that Chrome uses the dictionary while fetching a script.
+      EXPECT_EQ(kCompressedDataResultString,
+                LoadTestScript(GetURL(kTestPath + "?for_script")));
+      break;
+    case network::features::CompressionDictionaryTransportBackendVersion::kV2:
+      // Check that Chrome doesn't use the dictionary while fetching a script.
+      EXPECT_EQ(kUncompressedDataResultString,
+                LoadTestScript(GetURL(kTestPath + "?for_script")));
+      break;
+  }
+}
+
+IN_PROC_BROWSER_TEST_P(SharedDictionaryBrowserTest, MatchDestScript) {
+  Shell* shell = GetTargetShell();
+  EXPECT_TRUE(NavigateToURL(shell, GetURL("/shared_dictionary/blank.html")));
+
+  // The response header contains `match-dest=("script")` in Use-As-Dictionary
+  // header.
+  const GURL dictionary_url =
+      GetURL("/shared_dictionary/test.script_dest.dict");
+  EXPECT_TRUE(ExecJs(shell->web_contents()->GetPrimaryMainFrame(),
+                     LinkRelDictionaryScript(dictionary_url)));
+
+  // Wait for the dictionary to be registered.
+  EXPECT_TRUE(WaitForHistogram(
+      GetBrowserType() == BrowserType::kNormal
+          ? "Net.SharedDictionaryManagerOnDisk.DictionarySizeKB"
+          : "Net.SharedDictionaryWriterInMemory.DictionarySize"));
+
+  // Check that Chrome uses the dictionary while fetching a script.
+  EXPECT_EQ(kCompressedDataResultString,
+            LoadTestScript(GetURL(kTestPath + "?for_script")));
+
+  switch (GetVersion()) {
+    case network::features::CompressionDictionaryTransportBackendVersion::kV1:
+      // Check that Chrome uses the dictionary while fetching the resource using
+      // Fetch API.
+      EXPECT_EQ(kCompressedDataOriginalString,
+                EvalJs(shell->web_contents()->GetPrimaryMainFrame(),
+                       FetchTargetDataScript(dictionary_url))
+                    .ExtractString());
+      break;
+    case network::features::CompressionDictionaryTransportBackendVersion::kV2:
+      // Check that Chrome doesn't use the dictionary while fetching the
+      // resource using Fetch API.
+      EXPECT_EQ(kUncompressedDataString,
+                EvalJs(shell->web_contents()->GetPrimaryMainFrame(),
+                       FetchTargetDataScript(dictionary_url))
+                    .ExtractString());
+      break;
+  }
+}
+
 IN_PROC_BROWSER_TEST_P(
     SharedDictionaryBrowserTest,
     GetUsageInfoAndClearSharedDictionaryCacheForIsolationKey) {
diff --git a/content/test/content_test_bundle_data.filelist b/content/test/content_test_bundle_data.filelist
index 6c17658..141c1e6 100644
--- a/content/test/content_test_bundle_data.filelist
+++ b/content/test/content_test_bundle_data.filelist
@@ -7240,6 +7240,10 @@
 data/shared_dictionary/path/compressed.data.mock-http-headers
 data/shared_dictionary/test.dict
 data/shared_dictionary/test.dict.mock-http-headers
+data/shared_dictionary/test.empty_dest.dict
+data/shared_dictionary/test.empty_dest.dict.mock-http-headers
+data/shared_dictionary/test.script_dest.dict
+data/shared_dictionary/test.script_dest.dict.mock-http-headers
 data/shared_dictionary/test_dict.html
 data/shared_dictionary/test_dict.html.mock-http-headers
 data/shared_dictionary/test_no_acao.dict
diff --git a/content/test/data/shared_dictionary/test.empty_dest.dict b/content/test/data/shared_dictionary/test.empty_dest.dict
new file mode 100644
index 0000000..eccd446
--- /dev/null
+++ b/content/test/data/shared_dictionary/test.empty_dest.dict
@@ -0,0 +1 @@
+This is a test dictionary.
diff --git a/content/test/data/shared_dictionary/test.empty_dest.dict.mock-http-headers b/content/test/data/shared_dictionary/test.empty_dest.dict.mock-http-headers
new file mode 100644
index 0000000..5f742c7
--- /dev/null
+++ b/content/test/data/shared_dictionary/test.empty_dest.dict.mock-http-headers
@@ -0,0 +1,4 @@
+HTTP/1.1 200 OK
+Use-As-Dictionary: match="/shared_dictionary/path/*", match-dest=("")
+Access-Control-Allow-Origin: *
+Cache-Control: max-age=3600
diff --git a/content/test/data/shared_dictionary/test.script_dest.dict b/content/test/data/shared_dictionary/test.script_dest.dict
new file mode 100644
index 0000000..eccd446
--- /dev/null
+++ b/content/test/data/shared_dictionary/test.script_dest.dict
@@ -0,0 +1 @@
+This is a test dictionary.
diff --git a/content/test/data/shared_dictionary/test.script_dest.dict.mock-http-headers b/content/test/data/shared_dictionary/test.script_dest.dict.mock-http-headers
new file mode 100644
index 0000000..4b1f456
--- /dev/null
+++ b/content/test/data/shared_dictionary/test.script_dest.dict.mock-http-headers
@@ -0,0 +1,4 @@
+HTTP/1.1 200 OK
+Use-As-Dictionary: match="/shared_dictionary/path/*", match-dest=("script")
+Access-Control-Allow-Origin: *
+Cache-Control: max-age=3600
diff --git a/docs/linux/instrumented_libraries.md b/docs/linux/instrumented_libraries.md
index 08ac1db..6168fc7 100644
--- a/docs/linux/instrumented_libraries.md
+++ b/docs/linux/instrumented_libraries.md
@@ -20,20 +20,15 @@
 Create a configuration for a Focal chroot:
 
 ```shell
-sudo $EDITOR /etc/schroot/chroot.d/focal_amd64.conf
-```
-
-Add the following to the new file, replacing the instances of `thomasanderson`
-with your own username.
-
-```
+cat | sudo tee /etc/schroot/chroot.d/focal_amd64.conf > /dev/null <<EOF
 [focal_amd64]
 description=Ubuntu 20.04 Focal for amd64
 directory=/srv/chroot/focal_amd64
 personality=linux
-root-users=thomasanderson
+root-users=$USER
 type=directory
-users=thomasanderson
+users=$USER
+EOF
 ```
 
 Bootstrap the chroot:
@@ -51,21 +46,17 @@
 sudo mount --bind "$HOME" /home
 ```
 
-Add `sources.list`:
+Populate `sources.list`:
 
 ```shell
-sudo $EDITOR /srv/chroot/focal_amd64/etc/apt/sources.list
-```
-
-Add the following contents to the file:
-
-```
+cat | sudo tee -a /srv/chroot/focal_amd64/etc/apt/sources.list > /dev/null <<EOF
 deb     http://archive.ubuntu.com/ubuntu/ focal          main restricted universe
 deb-src	http://archive.ubuntu.com/ubuntu/ focal          main restricted universe
 deb     http://archive.ubuntu.com/ubuntu/ focal-security main restricted universe
 deb-src http://archive.ubuntu.com/ubuntu/ focal-security main restricted universe
 deb     http://archive.ubuntu.com/ubuntu/ focal-updates  main restricted universe
 deb-src http://archive.ubuntu.com/ubuntu/ focal-updates  main restricted universe
+EOF
 ```
 
 Enter the chroot and install the necessary packages:
@@ -79,7 +70,7 @@
 Install library packages:
 
 ```shell
-third_party/instrumented_libraries/scripts/install-build-deps.sh
+third_party/instrumented_libraries/focal/scripts/install-build-deps.sh
 ```
 
 Change to a non-root user:
diff --git a/extensions/browser/api/declarative_net_request/regex_rules_matcher.cc b/extensions/browser/api/declarative_net_request/regex_rules_matcher.cc
index b8c530c3..cda59a35 100644
--- a/extensions/browser/api/declarative_net_request/regex_rules_matcher.cc
+++ b/extensions/browser/api/declarative_net_request/regex_rules_matcher.cc
@@ -56,20 +56,24 @@
       params.first_party_origin, rule);
 }
 
-bool IsBeforeRequestAction(flat::ActionType action_type) {
+// For the given `action_type`, returns:
+// - true if multiple actions of this type can be matched for a request.
+// - false if an action of this type that is matched to a request will exclude
+//   all other actions from matching to that request.
+bool ActionTypeAllowsMultipleActions(flat::ActionType action_type) {
   switch (action_type) {
     case flat::ActionType_block:
     case flat::ActionType_allow:
     case flat::ActionType_redirect:
     case flat::ActionType_upgrade_scheme:
     case flat::ActionType_allow_all_requests:
-      return true;
-    case flat::ActionType_modify_headers:
       return false;
+    case flat::ActionType_modify_headers:
+      return true;
     case flat::ActionType_count:
       NOTREACHED();
   }
-  return false;
+  return true;
 }
 
 }  // namespace
@@ -83,16 +87,23 @@
 RegexRuleInfo::RegexRuleInfo(const RegexRuleInfo& info) = default;
 RegexRuleInfo& RegexRuleInfo::operator=(const RegexRuleInfo& info) = default;
 
-RegexRulesMatcher::RegexRulesMatcher(const ExtensionId& extension_id,
-                                     RulesetID ruleset_id,
-                                     const RegexRulesList* regex_list,
-                                     const ExtensionMetadataList* metadata_list)
+RegexRulesMatcher::RegexRulesMatcher(
+    const ExtensionId& extension_id,
+    RulesetID ruleset_id,
+    const RegexRulesList* before_request_regex_list,
+    const RegexRulesList* headers_received_regex_list,
+    const ExtensionMetadataList* metadata_list)
     : RulesetMatcherBase(extension_id, ruleset_id),
-      regex_list_(regex_list),
+      before_request_matcher_(before_request_regex_list,
+                              this,
+                              RulesetMatchingStage::kOnBeforeRequest),
+      headers_received_matcher_(headers_received_regex_list,
+                                this,
+                                RulesetMatchingStage::kOnHeadersReceived),
       metadata_list_(metadata_list),
-      is_extra_headers_matcher_(IsExtraHeadersMatcherInternal(regex_list)) {
-  InitializeMatcher();
-}
+      is_extra_headers_matcher_(
+          IsExtraHeadersMatcherInternal(before_request_regex_list) ||
+          IsExtraHeadersMatcherInternal(headers_received_regex_list)) {}
 
 RegexRulesMatcher::~RegexRulesMatcher() = default;
 
@@ -101,22 +112,22 @@
 }
 
 size_t RegexRulesMatcher::GetRulesCount() const {
-  return regex_list_->size();
+  return GetBeforeRequestRulesCount() + GetHeadersReceivedRulesCount();
 }
 
 size_t RegexRulesMatcher::GetBeforeRequestRulesCount() const {
-  return regex_list_->size();
+  return before_request_matcher_.GetRulesCount();
 }
 
 size_t RegexRulesMatcher::GetHeadersReceivedRulesCount() const {
-  return 0u;
+  return headers_received_matcher_.GetRulesCount();
 }
 
 std::vector<RequestAction> RegexRulesMatcher::GetModifyHeadersActions(
     const RequestParams& params,
     std::optional<uint64_t> min_priority) const {
   const std::vector<RegexRuleInfo>& potential_matches =
-      GetPotentialMatches(params);
+      before_request_matcher_.GetPotentialMatches(params);
 
   std::vector<const flat_rule::UrlRule*> rules;
   for (const RegexRuleInfo& info : potential_matches) {
@@ -138,7 +149,7 @@
 std::optional<RequestAction> RegexRulesMatcher::GetAllowAllRequestsAction(
     const RequestParams& params) const {
   const std::vector<RegexRuleInfo>& potential_matches =
-      GetPotentialMatches(params);
+      before_request_matcher_.GetPotentialMatches(params);
   auto info = base::ranges::find_if(
       potential_matches, [&params](const RegexRuleInfo& info) {
         return info.regex_rule->action_type() ==
@@ -155,51 +166,116 @@
 RegexRulesMatcher::GetBeforeRequestActionIgnoringAncestors(
     const RequestParams& params) const {
   const std::vector<RegexRuleInfo>& potential_matches =
-      GetPotentialMatches(params);
+      before_request_matcher_.GetPotentialMatches(params);
   auto info = base::ranges::find_if(
       potential_matches, [&params](const RegexRuleInfo& info) {
-        return IsBeforeRequestAction(info.regex_rule->action_type()) &&
+        return !ActionTypeAllowsMultipleActions(
+                   info.regex_rule->action_type()) &&
                re2::RE2::PartialMatch(params.url->spec(), *info.regex);
       });
-  if (info == potential_matches.end())
-    return std::nullopt;
 
-  const flat_rule::UrlRule& rule = *info->regex_rule->url_rule();
-  switch (info->regex_rule->action_type()) {
-    case flat::ActionType_block:
-      return CreateBlockOrCollapseRequestAction(params, rule);
-    case flat::ActionType_allow:
-      return CreateAllowAction(params, rule);
-    case flat::ActionType_redirect:
-      // If this is a regex substitution rule, handle the substitution. Else
-      // create the redirect action from the information in `metadata_list_`
-      // below.
-      return info->regex_rule->regex_substitution()
-                 ? CreateRegexSubstitutionRedirectAction(params, *info)
-                 : CreateRedirectActionFromMetadata(params, rule,
-                                                    *metadata_list_);
-    case flat::ActionType_upgrade_scheme:
-      return CreateUpgradeAction(params, rule);
-    case flat::ActionType_allow_all_requests:
-      return CreateAllowAllRequestsAction(params, rule);
-    case flat::ActionType_modify_headers:
-    case flat::ActionType_count:
-      NOTREACHED();
-      break;
-  }
-
-  return std::nullopt;
+  return info == potential_matches.end() ? std::nullopt
+                                         : CreateActionFromInfo(params, *info);
 }
 
 std::optional<RequestAction>
 RegexRulesMatcher::GetHeadersReceivedActionIgnoringAncestors(
     const RequestParams& params) const {
-  // TODO(kelvinjiang): Add support for regex rules matching on response
-  // headers.
-  return std::nullopt;
+  const std::vector<RegexRuleInfo>& potential_matches =
+      headers_received_matcher_.GetPotentialMatches(params);
+  auto info = base::ranges::find_if(
+      potential_matches, [&params](const RegexRuleInfo& info) {
+        return !ActionTypeAllowsMultipleActions(
+                   info.regex_rule->action_type()) &&
+               re2::RE2::PartialMatch(params.url->spec(), *info.regex);
+      });
+
+  return info == potential_matches.end() ? std::nullopt
+                                         : CreateActionFromInfo(params, *info);
 }
 
-void RegexRulesMatcher::InitializeMatcher() {
+RegexRulesMatcher::MatchHelper::MatchHelper(
+    const raw_ptr<const RegexRulesList> regex_list,
+    const RegexRulesMatcher* parent_matcher,
+    RulesetMatchingStage stage)
+    : regex_list_(regex_list), regex_match_key_(parent_matcher, stage) {
+  InitializeMatcher();
+}
+
+RegexRulesMatcher::MatchHelper::~MatchHelper() = default;
+
+size_t RegexRulesMatcher::MatchHelper::GetRulesCount() const {
+  return regex_list_->size();
+}
+
+const std::vector<RegexRuleInfo>&
+RegexRulesMatcher::MatchHelper::GetPotentialMatches(
+    const RequestParams& params) const {
+  auto iter = params.potential_regex_matches.find(regex_match_key_);
+  if (iter != params.potential_regex_matches.end()) {
+    return iter->second;
+  }
+
+  // Early out if this is an empty matcher.
+  if (IsEmpty()) {
+    auto result = params.potential_regex_matches.insert(
+        std::make_pair(regex_match_key_, std::vector<RegexRuleInfo>()));
+    return result.first->second;
+  }
+
+  // Compute the potential matches. FilteredRE2 requires the text to be lower
+  // cased first.
+  if (!params.lower_cased_url_spec) {
+    params.lower_cased_url_spec = base::ToLowerASCII(params.url->spec());
+  }
+
+  // To pre-filter the set of regexes to match against `params`, we first need
+  // to compute the set of candidate strings tracked by `substring_matcher_`
+  // within `params.lower_cased_url_spec`.
+  std::set<base::MatcherStringPattern::ID> candidate_ids_set;
+  DCHECK(substring_matcher_);
+  substring_matcher_->Match(*params.lower_cased_url_spec, &candidate_ids_set);
+  std::vector<int> candidate_ids_list(candidate_ids_set.begin(),
+                                      candidate_ids_set.end());
+
+  // FilteredRE2 then yields the set of potential regex matches.
+  std::vector<int> potential_re2_ids;
+  filtered_re2_.AllPotentials(candidate_ids_list, &potential_re2_ids);
+
+  // We prune the set of potential matches even further by matching request
+  // metadata.
+  std::vector<RegexRuleInfo> potential_matches;
+  for (int re2_id : potential_re2_ids) {
+    auto it = re2_id_to_rules_map_.find(re2_id);
+    DCHECK(it != re2_id_to_rules_map_.end());
+
+    const flat::RegexRule* rule = it->second;
+    if (!DoesRuleMetadataMatchRequest(*rule->url_rule(), params)) {
+      continue;
+    }
+
+    const RE2& regex = filtered_re2_.GetRE2(re2_id);
+    potential_matches.emplace_back(rule, &regex);
+  }
+
+  // Sort potential matches in descending order of priority.
+  std::sort(potential_matches.begin(), potential_matches.end(),
+            [](const RegexRuleInfo& lhs, const RegexRuleInfo& rhs) {
+              return lhs.regex_rule->url_rule()->priority() >
+                     rhs.regex_rule->url_rule()->priority();
+            });
+
+  // Cache `potential_matches`.
+  auto result = params.potential_regex_matches.insert(
+      std::make_pair(regex_match_key_, std::move(potential_matches)));
+  return result.first->second;
+}
+
+bool RegexRulesMatcher::MatchHelper::IsEmpty() const {
+  return regex_list_->size() == 0;
+}
+
+void RegexRulesMatcher::MatchHelper::InitializeMatcher() {
   if (IsEmpty())
     return;
 
@@ -261,67 +337,34 @@
   CHECK(success);
 }
 
-bool RegexRulesMatcher::IsEmpty() const {
-  return regex_list_->size() == 0;
-}
-
-const std::vector<RegexRuleInfo>& RegexRulesMatcher::GetPotentialMatches(
-    const RequestParams& params) const {
-  auto iter = params.potential_regex_matches.find(this);
-  if (iter != params.potential_regex_matches.end())
-    return iter->second;
-
-  // Early out if this is an empty matcher.
-  if (IsEmpty()) {
-    auto result = params.potential_regex_matches.insert(
-        std::make_pair(this, std::vector<RegexRuleInfo>()));
-    return result.first->second;
+std::optional<RequestAction> RegexRulesMatcher::CreateActionFromInfo(
+    const RequestParams& params,
+    const RegexRuleInfo& info) const {
+  const flat_rule::UrlRule& rule = *info.regex_rule->url_rule();
+  switch (info.regex_rule->action_type()) {
+    case flat::ActionType_block:
+      return CreateBlockOrCollapseRequestAction(params, rule);
+    case flat::ActionType_allow:
+      return CreateAllowAction(params, rule);
+    case flat::ActionType_redirect:
+      // If this is a regex substitution rule, handle the substitution. Else
+      // create the redirect action from the information in `metadata_list_`
+      // below.
+      return info.regex_rule->regex_substitution()
+                 ? CreateRegexSubstitutionRedirectAction(params, info)
+                 : CreateRedirectActionFromMetadata(params, rule,
+                                                    *metadata_list_);
+    case flat::ActionType_upgrade_scheme:
+      return CreateUpgradeAction(params, rule);
+    case flat::ActionType_allow_all_requests:
+      return CreateAllowAllRequestsAction(params, rule);
+    case flat::ActionType_modify_headers:
+    case flat::ActionType_count:
+      NOTREACHED();
+      break;
   }
 
-  // Compute the potential matches. FilteredRE2 requires the text to be lower
-  // cased first.
-  if (!params.lower_cased_url_spec)
-    params.lower_cased_url_spec = base::ToLowerASCII(params.url->spec());
-
-  // To pre-filter the set of regexes to match against `params`, we first need
-  // to compute the set of candidate strings tracked by `substring_matcher_`
-  // within `params.lower_cased_url_spec`.
-  std::set<base::MatcherStringPattern::ID> candidate_ids_set;
-  DCHECK(substring_matcher_);
-  substring_matcher_->Match(*params.lower_cased_url_spec, &candidate_ids_set);
-  std::vector<int> candidate_ids_list(candidate_ids_set.begin(),
-                                      candidate_ids_set.end());
-
-  // FilteredRE2 then yields the set of potential regex matches.
-  std::vector<int> potential_re2_ids;
-  filtered_re2_.AllPotentials(candidate_ids_list, &potential_re2_ids);
-
-  // We prune the set of potential matches even further by matching request
-  // metadata.
-  std::vector<RegexRuleInfo> potential_matches;
-  for (int re2_id : potential_re2_ids) {
-    auto it = re2_id_to_rules_map_.find(re2_id);
-    DCHECK(it != re2_id_to_rules_map_.end());
-
-    const flat::RegexRule* rule = it->second;
-    if (!DoesRuleMetadataMatchRequest(*rule->url_rule(), params))
-      continue;
-
-    const RE2& regex = filtered_re2_.GetRE2(re2_id);
-    potential_matches.emplace_back(rule, &regex);
-  }
-
-  // Sort potential matches in descending order of priority.
-  std::sort(potential_matches.begin(), potential_matches.end(),
-            [](const RegexRuleInfo& lhs, const RegexRuleInfo& rhs) {
-              return lhs.regex_rule->url_rule()->priority() >
-                     rhs.regex_rule->url_rule()->priority();
-            });
-
-  // Cache `potential_matches`.
-  auto result = params.potential_regex_matches.insert(
-      std::make_pair(this, std::move(potential_matches)));
-  return result.first->second;
+  return std::nullopt;
 }
 
 std::optional<RequestAction>
diff --git a/extensions/browser/api/declarative_net_request/regex_rules_matcher.h b/extensions/browser/api/declarative_net_request/regex_rules_matcher.h
index 1bb0a80..9751608 100644
--- a/extensions/browser/api/declarative_net_request/regex_rules_matcher.h
+++ b/extensions/browser/api/declarative_net_request/regex_rules_matcher.h
@@ -9,6 +9,7 @@
 
 #include "base/memory/raw_ptr.h"
 #include "base/substring_set_matcher/substring_set_matcher.h"
+#include "extensions/browser/api/declarative_net_request/constants.h"
 #include "extensions/browser/api/declarative_net_request/ruleset_matcher_base.h"
 #include "third_party/re2/src/re2/filtered_re2.h"
 
@@ -49,9 +50,12 @@
  public:
   using RegexRulesList =
       ::flatbuffers::Vector<flatbuffers::Offset<flat::RegexRule>>;
+  using RegexMatchKey =
+      std::pair<const RegexRulesMatcher*, RulesetMatchingStage>;
   RegexRulesMatcher(const ExtensionId& extension_id,
                     RulesetID ruleset_id,
-                    const RegexRulesList* regex_list,
+                    const RegexRulesList* before_request_regex_list,
+                    const RegexRulesList* headers_received_regex_list,
                     const ExtensionMetadataList* metadata_list);
 
   RegexRulesMatcher(const RegexRulesMatcher&) = delete;
@@ -68,6 +72,63 @@
   size_t GetHeadersReceivedRulesCount() const override;
 
  private:
+  // A helper class used to match regex rules from a single ruleset for a single
+  // request stage.
+  class MatchHelper {
+   public:
+    MatchHelper(const raw_ptr<const RegexRulesList> regex_list,
+                const RegexRulesMatcher* parent_matcher,
+                RulesetMatchingStage stage);
+    ~MatchHelper();
+    MatchHelper(const MatchHelper& other) = delete;
+    MatchHelper& operator=(const MatchHelper& other) = delete;
+
+    // Returns the rule count for regex rules to be matched in the request stage
+    // corresponding to this MatchHelper.
+    size_t GetRulesCount() const;
+
+    // Returns the potentially matching rules for the given request. A
+    // potentially matching rule is one whose metadata matches the given request
+    // `params` and which is not ruled out as a potential match by the
+    // `filtered_re2_` object. Note: The returned vector is sorted in descending
+    // order of rule priority.
+    const std::vector<RegexRuleInfo>& GetPotentialMatches(
+        const RequestParams& params) const;
+
+   private:
+    // Helper to build the necessary data structures for matching.
+    void InitializeMatcher();
+
+    // Returns true if this matcher doesn't correspond to any rules.
+    bool IsEmpty() const;
+
+    // The backing regex rules list for this MatchHelper. Contains all rules
+    // that are meant to be matched for a single request stage.
+    const raw_ptr<const RegexRulesList> regex_list_;
+
+    // The key used to cache potential regex matches from this helper in a
+    // RequestParams. Consists of a pointer to the RegexRulesMatcher which owns
+    // this helper and the request stage in which this helper will match rules.
+    RegexMatchKey regex_match_key_;
+
+    // Data structures used for matching. Initialized during construction in
+    // InitializeMatcher() and immutable for the rest of the object lifetime.
+
+    // This provides a pre-filtering mechanism, to reduce the number of regular
+    // expressions that are actually matched against a request.
+    re2::FilteredRE2 filtered_re2_;
+
+    // Map from re2 ID (as used by `filtered_re2_`) to the flat::RegexRule in
+    // `regex_list_`.
+    std::map<int, const flat::RegexRule*> re2_id_to_rules_map_;
+
+    // Structure for fast substring matching. Given a string S and a set of
+    // candidate strings, returns the sub-set of candidate strings that are a
+    // substring of S. Uses the Aho-Corasick algorithm internally. Will be null
+    // iff IsEmpty() returns false.
+    std::unique_ptr<base::SubstringSetMatcher> substring_matcher_;
+  };
+
   // RulesetMatcherBase override:
   std::optional<RequestAction> GetAllowAllRequestsAction(
       const RequestParams& params) const override;
@@ -76,47 +137,25 @@
   std::optional<RequestAction> GetHeadersReceivedActionIgnoringAncestors(
       const RequestParams& params) const override;
 
-  // Helper to build the necessary data structures for matching.
-  void InitializeMatcher();
-
-  // Returns true if this matcher doesn't correspond to any rules.
-  bool IsEmpty() const;
-
-  // Returns the potentially matching rules for the given request. A potentially
-  // matching rule is one whose metadata matches the given request `params` and
-  // which is not ruled out as a potential match by the `filtered_re2_` object.
-  // Note: The returned vector is sorted in descending order of rule priority.
-  const std::vector<RegexRuleInfo>& GetPotentialMatches(
-      const RequestParams& params) const;
+  // Returns a RequestAction for the given matched regex rule `info`.
+  std::optional<RequestAction> CreateActionFromInfo(
+      const RequestParams& params,
+      const RegexRuleInfo& info) const;
 
   // Returns a RequestAction for the the given regex substitution rule.
   std::optional<RequestAction> CreateRegexSubstitutionRedirectAction(
       const RequestParams& params,
       const RegexRuleInfo& info) const;
 
-  // Pointers to flatbuffer indexed data. Guaranteed to be valid through the
-  // lifetime of the object.
-  const raw_ptr<const RegexRulesList> regex_list_;
+  // A helper for matching regex rules in the onBeforeRequest stage.
+  MatchHelper before_request_matcher_;
+
+  // A helper for matching regex rules in the onHeadersReceived stage.
+  MatchHelper headers_received_matcher_;
+
   const raw_ptr<const ExtensionMetadataList> metadata_list_;
 
   const bool is_extra_headers_matcher_;
-
-  // Data structures used for matching. Initialized during construction in
-  // InitializeMatcher() and immutable for the rest of the object lifetime.
-
-  // This provides a pre-filtering mechanism, to reduce the number of regular
-  // expressions that are actually matched against a request.
-  re2::FilteredRE2 filtered_re2_;
-
-  // Map from re2 ID (as used by `filtered_re2_`) to the flat::RegexRule in
-  // `regex_list_`.
-  std::map<int, const flat::RegexRule*> re2_id_to_rules_map_;
-
-  // Structure for fast substring matching. Given a string S and a set of
-  // candidate strings, returns the sub-set of candidate strings that are a
-  // substring of S. Uses the Aho-Corasick algorithm internally. Will be null
-  // iff IsEmpty() returns false.
-  std::unique_ptr<base::SubstringSetMatcher> substring_matcher_;
 };
 
 }  // namespace extensions::declarative_net_request
diff --git a/extensions/browser/api/declarative_net_request/request_params.h b/extensions/browser/api/declarative_net_request/request_params.h
index 1dd735b..49f64584 100644
--- a/extensions/browser/api/declarative_net_request/request_params.h
+++ b/extensions/browser/api/declarative_net_request/request_params.h
@@ -77,9 +77,10 @@
   // Lower cased url, used for regex matching. Cached for performance.
   mutable std::optional<std::string> lower_cased_url_spec;
 
-  // Map from RegexRulesMatcher to a vector of potential matches for this
-  // request. Cached for performance.
-  mutable base::flat_map<const RegexRulesMatcher*, std::vector<RegexRuleInfo>>
+  // Map from a (RegexRulesMatcher, ruleset matching stage) pair to a vector of
+  // potential matches for this request. Cached for performance.
+  mutable base::flat_map<RegexRulesMatcher::RegexMatchKey,
+                         std::vector<RegexRuleInfo>>
       potential_regex_matches;
 };
 
diff --git a/extensions/browser/api/declarative_net_request/ruleset_matcher.cc b/extensions/browser/api/declarative_net_request/ruleset_matcher.cc
index 527324d..38f3cc0a 100644
--- a/extensions/browser/api/declarative_net_request/ruleset_matcher.cc
+++ b/extensions/browser/api/declarative_net_request/ruleset_matcher.cc
@@ -59,6 +59,7 @@
       regex_matcher_(extension_id,
                      id,
                      root_->before_request_regex_rules(),
+                     root_->headers_received_regex_rules(),
                      root_->extension_metadata()) {
   if (!IsRulesetStatic(id)) {
     unsafe_rule_count_ = ComputeUnsafeRuleCount(root_->extension_metadata());
diff --git a/extensions/browser/api/declarative_net_request/ruleset_matcher_unittest.cc b/extensions/browser/api/declarative_net_request/ruleset_matcher_unittest.cc
index 023cf01..63f4027 100644
--- a/extensions/browser/api/declarative_net_request/ruleset_matcher_unittest.cc
+++ b/extensions/browser/api/declarative_net_request/ruleset_matcher_unittest.cc
@@ -1551,6 +1551,109 @@
   EXPECT_EQ(std::nullopt, matcher->GetOnHeadersReceivedAction(params));
 }
 
+// Test matching response header conditions with regex rules.
+TEST_F(RulesetMatcherResponseHeadersTest, OnHeadersReceivedAction_Regex) {
+  auto create_regex_rule = [](size_t id, const std::string& regex_filter) {
+    TestRule rule = CreateGenericRule();
+    rule.id = id;
+    rule.condition->url_filter.reset();
+    rule.condition->regex_filter = regex_filter;
+    return rule;
+  };
+
+  // Create 3 rules:
+  // - A regex allow rule which is matched in the onBeforeRequest stage.
+  // - A url rule with a higher priority that redirects the request to
+  //   urlmatch.com when matched in the onHeadersReceived stage.
+  // - A regex rule that redirects the request to regexmatch.com when matched in
+  //   the onHeadersReceived stage.
+
+  TestRule before_request_rule =
+      create_regex_rule(kMinValidID, R"(^(?:http|https)://[a-z\.]+\.com)");
+  before_request_rule.action->type = std::string("allow");
+
+  TestRule url_response_headers_rule = CreateGenericRule(kMinValidID + 1);
+  url_response_headers_rule.priority = kMinValidPriority + 2;
+  url_response_headers_rule.condition->url_filter = std::string("google.com");
+  url_response_headers_rule.condition->response_headers = {
+      TestHeaderCondition("key1", {}, {})};
+  url_response_headers_rule.action->type = std::string("redirect");
+  url_response_headers_rule.action->redirect.emplace();
+  url_response_headers_rule.action->redirect->url =
+      std::string("http://urlmatch.com");
+
+  TestRule regex_response_headers_rule =
+      create_regex_rule(kMinValidID + 2, R"(^(?:http|https)://[a-z\.]+\.com)");
+  regex_response_headers_rule.priority = kMinValidPriority + 1;
+  regex_response_headers_rule.condition->response_headers = {
+      TestHeaderCondition("key1", {}, {})};
+  regex_response_headers_rule.action->type = std::string("redirect");
+  regex_response_headers_rule.action->redirect.emplace();
+  regex_response_headers_rule.action->redirect->url =
+      std::string("http://regexmatch.com");
+
+  char base_headers_string[] =
+      "HTTP/1.0 200 OK\r\n"
+      "Key1: Value1\r\n";
+  auto base_headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+      net::HttpUtil::AssembleRawHeaders(base_headers_string));
+
+  std::unique_ptr<RulesetMatcher> matcher;
+  ASSERT_TRUE(
+      CreateVerifiedMatcher({before_request_rule, url_response_headers_rule,
+                             regex_response_headers_rule},
+                            CreateTemporarySource(), &matcher));
+  ASSERT_TRUE(matcher);
+
+  struct {
+    std::string url;
+    std::optional<RequestAction> expected_before_request_action;
+    std::optional<RequestAction> expected_headers_received_action;
+    std::optional<std::string> expected_redirect_url;
+  } cases[] = {
+      // The request to google.com will match `before_request_rule` for
+      // GetBeforeRequestAction and `url_response_headers_rule` because of its
+      // higher priority for GetOnHeadersReceivedAction.
+      {"http://google.com",
+       CreateRequestActionForTesting(RequestAction::Type::ALLOW, kMinValidID),
+       CreateRequestActionForTesting(RequestAction::Type::REDIRECT,
+                                     kMinValidID + 1, kMinValidPriority + 2),
+       std::string("http://urlmatch.com")},
+
+      // The request to someotherurl.com will match `before_request_rule` for
+      // GetBeforeRequestAction and `regex_response_headers_rule` for
+      // GetOnHeadersReceivedAction.
+      {"http://someotherurl.com",
+       CreateRequestActionForTesting(RequestAction::Type::ALLOW, kMinValidID),
+       CreateRequestActionForTesting(RequestAction::Type::REDIRECT,
+                                     kMinValidID + 2, kMinValidPriority + 1),
+       std::string("http://regexmatch.com")},
+  };
+
+  for (size_t i = 0; i < std::size(cases); ++i) {
+    SCOPED_TRACE(base::StringPrintf("Testing case[%" PRIuS "]", i));
+    auto& test_case = cases[i];
+
+    GURL url(test_case.url);
+    ASSERT_TRUE(url.is_valid());
+    RequestParams params =
+        CreateRequestWithResponseHeaders(url, base_headers.get());
+
+    EXPECT_EQ(test_case.expected_before_request_action,
+              matcher->GetBeforeRequestAction(params));
+
+    // We assign the value of redirect_url from the test case so that we can use
+    // the operator== on the RequestAction below.
+    if (test_case.expected_headers_received_action) {
+      test_case.expected_headers_received_action->redirect_url =
+          GURL(*test_case.expected_redirect_url);
+    }
+
+    EXPECT_EQ(test_case.expected_headers_received_action,
+              matcher->GetOnHeadersReceivedAction(params));
+  }
+}
+
 // Test matching rules based on response header conditions.
 TEST_F(RulesetMatcherResponseHeadersTest, MatchOnResponseHeaders) {
   std::vector<TestHeaderCondition> header_condition(
diff --git a/gpu/command_buffer/client/gl_helper.cc b/gpu/command_buffer/client/gl_helper.cc
index 872b391..2e55a18 100644
--- a/gpu/command_buffer/client/gl_helper.cc
+++ b/gpu/command_buffer/client/gl_helper.cc
@@ -137,8 +137,7 @@
 
 // Implements texture consumption/readback and encapsulates
 // the data needed for it.
-class GLHelper::CopyTextureToImpl
-    : public base::SupportsWeakPtr<GLHelper::CopyTextureToImpl> {
+class GLHelper::CopyTextureToImpl final {
  public:
   CopyTextureToImpl(GLES2Interface* gl,
                     ContextSupport* context_support,
@@ -334,6 +333,8 @@
     BGRA_PREFERRED,
     BGRA_NOT_PREFERRED
   } bgra_preference_ = BGRA_PREFERENCE_UNKNOWN;
+
+  base::WeakPtrFactory<CopyTextureToImpl> weak_ptr_factory_{this};
 };
 
 std::unique_ptr<GLHelper::ScalerInterface> GLHelper::CreateScaler(
@@ -380,8 +381,8 @@
   gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM);
   gl_->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
   context_support_->SignalQuery(
-      request->query,
-      base::BindOnce(&CopyTextureToImpl::ReadbackDone, AsWeakPtr(), request));
+      request->query, base::BindOnce(&CopyTextureToImpl::ReadbackDone,
+                                     weak_ptr_factory_.GetWeakPtr(), request));
 }
 
 void GLHelper::CopyTextureToImpl::ReadbackTextureAsync(
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index 72eab27b..b6afb48 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -319,8 +319,6 @@
       "abstract_texture.h",
       "passthrough_abstract_texture_impl.cc",
       "passthrough_abstract_texture_impl.h",
-      "validating_abstract_texture_impl.cc",
-      "validating_abstract_texture_impl.h",
     ]
   } else {
     sources += [
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index bee74210..f75ae9f3 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -114,10 +114,6 @@
 #include "ui/gl/init/create_gr_gl_interface.h"
 #include "ui/gl/scoped_make_current.h"
 
-#if !BUILDFLAG(IS_ANDROID)
-#include "gpu/command_buffer/service/validating_abstract_texture_impl.h"
-#endif
-
 // Note: this undefs far and near so include this after other Windows headers.
 #include "third_party/angle/src/image_util/loadimage.h"
 
@@ -662,7 +658,7 @@
 
   ErrorState* GetErrorState() override;
   const ContextState* GetContextState() override { return &state_; }
-#if !BUILDFLAG(IS_ANDROID)
+  #if !BUILDFLAG(IS_ANDROID)
   std::unique_ptr<AbstractTexture> CreateAbstractTexture(GLenum target,
                                                          GLenum internal_format,
                                                          GLsizei width,
@@ -670,7 +666,10 @@
                                                          GLsizei depth,
                                                          GLint border,
                                                          GLenum format,
-                                                         GLenum type) override;
+                                                         GLenum type) override {
+    NOTREACHED();
+    return nullptr;
+  }
 #endif
 
   scoped_refptr<ShaderTranslatorInterface> GetTranslator(GLenum type) override;
@@ -2447,11 +2446,6 @@
   void UnbindTexture(TextureRef* texture_ref,
                      bool supports_separate_framebuffer_binds);
 
-#if !BUILDFLAG(IS_ANDROID)
-  void OnAbstractTextureDestroyed(ValidatingAbstractTextureImpl* texture,
-                                  scoped_refptr<TextureRef> texture_ref);
-#endif
-
   void ReadBackBuffersIntoShadowCopies(
       base::flat_set<scoped_refptr<Buffer>> buffers_to_shadow_copy);
 
@@ -2668,15 +2662,6 @@
 
   SamplerState default_sampler_state_;
 
-#if !BUILDFLAG(IS_ANDROID)
-  // All currently outstanding AbstractTextures that we've created.
-  std::set<ValidatingAbstractTextureImpl*> abstract_textures_;
-
-  // Set of texture refs that are pending destruction, at some point in the
-  // future when our context is current.
-  std::set<scoped_refptr<TextureRef>> texture_refs_pending_destruction_;
-#endif
-
   base::WeakPtrFactory<GLES2DecoderImpl> weak_ptr_factory_{this};
 };
 
@@ -4209,12 +4194,6 @@
   // Rebind textures if the service ids may have changed.
   RestoreAllExternalTextureBindingsIfNeeded();
 
-#if !BUILDFLAG(IS_ANDROID)
-  // Since we have a context now, take the opportunity to drop any TextureRefs
-  // that are pending destruction.
-  texture_refs_pending_destruction_.clear();
-#endif
-
   return true;
 }
 
@@ -4683,20 +4662,6 @@
 
   DCHECK(!have_context || context_->IsCurrent(nullptr));
 
-#if !BUILDFLAG(IS_ANDROID)
-  // Destroy any textures that are pending destruction.
-  if (!have_context) {
-    for (auto iter : texture_refs_pending_destruction_)
-      iter->ForceContextLost();
-  }
-  texture_refs_pending_destruction_.clear();
-
-  // Notify any AbstractTextures to drop their texture ref.
-  for (auto* iter : abstract_textures_)
-    iter->OnDecoderWillDestroy(have_context);
-  abstract_textures_.clear();
-#endif
-
   if (external_default_framebuffer_) {
     external_default_framebuffer_->Destroy(have_context);
     external_default_framebuffer_.reset();
@@ -16018,10 +15983,6 @@
 bool GLES2DecoderImpl::HasMoreIdleWork() const {
   bool has_more_idle_work =
       !pending_readpixel_fences_.empty() || gpu_tracer_->HasTracesToProcess();
-#if !BUILDFLAG(IS_ANDROID)
-  has_more_idle_work =
-      has_more_idle_work || !texture_refs_pending_destruction_.empty();
-#endif
   return has_more_idle_work;
 }
 
@@ -18166,56 +18127,6 @@
   state_.UpdateWindowRectangles();
 }
 
-#if !BUILDFLAG(IS_ANDROID)
-std::unique_ptr<AbstractTexture> GLES2DecoderImpl::CreateAbstractTexture(
-    GLenum target,
-    GLenum internal_format,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLint border,
-    GLenum format,
-    GLenum type) {
-  GLuint service_id = 0;
-  api()->glGenTexturesFn(1, &service_id);
-  scoped_refptr<gpu::gles2::TextureRef> texture_ref =
-      TextureRef::Create(texture_manager(), 0, service_id);
-  texture_manager()->SetTarget(texture_ref.get(), target);
-  const GLint level = 0;
-  // Mark the texture as "not cleared".
-  gfx::Rect cleared_rect = gfx::Rect();
-  texture_manager()->SetLevelInfo(texture_ref.get(), target, level,
-                                  internal_format, width, height, depth, border,
-                                  format, type, cleared_rect);
-
-  // Unretained is safe, because of the destruction cb.
-  std::unique_ptr<ValidatingAbstractTextureImpl> abstract_texture =
-      std::make_unique<ValidatingAbstractTextureImpl>(
-          std::move(texture_ref), this,
-          base::BindOnce(&GLES2DecoderImpl::OnAbstractTextureDestroyed,
-                         base::Unretained(this)));
-  abstract_textures_.insert(abstract_texture.get());
-
-  return abstract_texture;
-}
-
-void GLES2DecoderImpl::OnAbstractTextureDestroyed(
-    ValidatingAbstractTextureImpl* abstract_texture,
-    scoped_refptr<TextureRef> texture_ref) {
-  DCHECK(texture_ref);
-  abstract_textures_.erase(abstract_texture);
-  // Keep |texture_ref| until we have a current context to destroy it, unless
-  // the context is current.  In that case, clear everything that's pending
-  // destruction and let |texture_ref| go out of scope.
-  // TODO(liberato): Consider moving this to the context group, so that any
-  // context in our group can delete textures sooner.
-  if (context_->IsCurrent(nullptr))
-    texture_refs_pending_destruction_.clear();
-  else
-    texture_refs_pending_destruction_.insert(std::move(texture_ref));
-}
-#endif
-
 void GLES2DecoderImpl::DoSetReadbackBufferShadowAllocationINTERNAL(
     GLuint buffer_id,
     GLuint shm_id,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index 9495875..214856c 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -29,10 +29,6 @@
 #include "ui/gl/gpu_timing_fake.h"
 #include "ui/gl/scoped_make_current.h"
 
-#if !BUILDFLAG(IS_ANDROID)
-#include "gpu/command_buffer/service/validating_abstract_texture_impl.h"
-#endif
-
 #if !defined(GL_DEPTH24_STENCIL8)
 #define GL_DEPTH24_STENCIL8 0x88F0
 #endif
@@ -256,159 +252,6 @@
   EXPECT_FALSE(DoIsTexture(client_texture_id_));
 }
 
-#if BUILDFLAG(IS_OZONE)
-TEST_P(GLES2DecoderTest, CreateAbstractTexture) {
-  const GLuint service_id = 123;
-  EXPECT_CALL(*gl_, GenTextures(1, _))
-      .Times(1)
-      .WillOnce(SetArgPointee<1>(service_id))
-      .RetiresOnSaturation();
-  const GLenum target = GL_TEXTURE_EXTERNAL_OES;
-  std::unique_ptr<AbstractTexture> abstract_texture =
-      GetDecoder()->CreateAbstractTexture(target, GL_RGBA, 256, /* width */
-                                          256,                  /* height */
-                                          1,                    /* depth */
-                                          0,                    /* border */
-                                          GL_RGBA, GL_UNSIGNED_BYTE);
-  EXPECT_EQ(abstract_texture->GetTextureBase()->target(), target);
-  EXPECT_EQ(abstract_texture->service_id(), service_id);
-  Texture* texture = Texture::CheckedCast(abstract_texture->GetTextureBase());
-  EXPECT_EQ(texture->SafeToRenderFrom(), false);
-
-  // Set some parameters, and verify that we set them.
-  // These three are for ScopedTextureBinder.
-  // TODO(liberato): Is there a way to make this less brittle?
-  EXPECT_CALL(*gl_, GetIntegerv(_, _)).Times(1).RetiresOnSaturation();
-  EXPECT_CALL(*gl_, BindTexture(target, _)).Times(1).RetiresOnSaturation();
-  EXPECT_CALL(*gl_, BindTexture(target, abstract_texture->service_id()))
-      .Times(1)
-      .RetiresOnSaturation();
-
-  // This one we actually care about.
-  EXPECT_CALL(*gl_, TexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
-  abstract_texture->SetParameteri(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-  EXPECT_EQ(texture->min_filter(), static_cast<GLenum>(GL_LINEAR));
-
-  // Deleting |abstract_texture| should delete the platform texture as well,
-  // since we haven't make a copy of the TextureRef.  Also make sure that the
-  // cleanup CB is called.
-  EXPECT_CALL(*gl_, DeleteTextures(1, _)).Times(1).RetiresOnSaturation();
-  bool cleanup_flag = false;
-  abstract_texture->SetCleanupCallback(base::BindOnce(
-      [](bool* flag, AbstractTexture*) { *flag = true; }, &cleanup_flag));
-  abstract_texture.reset();
-  EXPECT_TRUE(cleanup_flag);
-}
-#endif
-
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_APPLE)
-TEST_P(GLES2DecoderTest, AbstractTextureIsDestroyedWithDecoder) {
-  // Deleting the decoder should delete the AbstractTexture's TextureRef.
-  const GLuint service_id = 123;
-  EXPECT_CALL(*gl_, GenTextures(1, _))
-      .Times(1)
-      .WillOnce(SetArgPointee<1>(service_id))
-      .RetiresOnSaturation();
-  const GLenum target = GL_TEXTURE_EXTERNAL_OES;
-  std::unique_ptr<AbstractTexture> abstract_texture =
-      GetDecoder()->CreateAbstractTexture(target, GL_RGBA, 256, /* width */
-                                          256,                  /* height */
-                                          1,                    /* depth */
-                                          0,                    /* border */
-                                          GL_RGBA, GL_UNSIGNED_BYTE);
-  bool cleanup_flag = false;
-  abstract_texture->SetCleanupCallback(base::BindOnce(
-      [](bool* flag, AbstractTexture*) { *flag = true; }, &cleanup_flag));
-
-  // There is only one TextureRef, so it should delete the platform texture.  It
-  // should also call the cleanup cb.
-  EXPECT_CALL(*gl_, DeleteTextures(1, _)).Times(1).RetiresOnSaturation();
-  ResetDecoder();
-  // The texture should no longer have a TextureRef.
-  EXPECT_EQ(abstract_texture->GetTextureBase(), nullptr);
-  EXPECT_TRUE(cleanup_flag);
-}
-
-TEST_P(GLES2DecoderTest, AbstractTextureIsDestroyedWhenMadeCurrent) {
-  // When an AbstractTexture is destroyed, the ref will be dropped by the next
-  // call to MakeCurrent if the context isn't already current.
-  const GLuint service_id = 123;
-  EXPECT_CALL(*gl_, GenTextures(1, _))
-      .Times(1)
-      .WillOnce(SetArgPointee<1>(service_id))
-      .RetiresOnSaturation();
-  const GLenum target = GL_TEXTURE_EXTERNAL_OES;
-  std::unique_ptr<AbstractTexture> abstract_texture =
-      GetDecoder()->CreateAbstractTexture(target, GL_RGBA, 256, /* width */
-                                          256,                  /* height */
-                                          1,                    /* depth */
-                                          0,                    /* border */
-                                          GL_RGBA, GL_UNSIGNED_BYTE);
-
-  // Make the context not current, so that it's not destroyed immediately.
-  context_->ReleaseCurrent(surface_.get());
-  abstract_texture.reset();
-  // Make the context current again, |context_| overrides it with a mock.
-  context_->GLContextStub::MakeCurrentImpl(surface_.get());
-
-  // Having textures to delete should signal idle work.
-  EXPECT_EQ(GetDecoder()->HasMoreIdleWork(), true);
-  EXPECT_CALL(*gl_, DeleteTextures(1, _)).Times(1).RetiresOnSaturation();
-
-  // Allow the context to be made current.
-  EXPECT_CALL(*context_, MakeCurrentImpl(surface_.get()))
-      .WillOnce(Return(true));
-  GetDecoder()->MakeCurrent();
-}
-
-TEST_P(GLES2DecoderTest, AbstractTextureIsDestroyedIfAlreadyCurrent) {
-  // When an AbstractTexture is destroyed, the ref will be dropped immediately
-  // if the context is current.
-  const GLuint service_id = 123;
-  EXPECT_CALL(*gl_, GenTextures(1, _))
-      .Times(1)
-      .WillOnce(SetArgPointee<1>(service_id))
-      .RetiresOnSaturation();
-  const GLenum target = GL_TEXTURE_EXTERNAL_OES;
-  std::unique_ptr<AbstractTexture> abstract_texture =
-      GetDecoder()->CreateAbstractTexture(target, GL_RGBA, 256, /* width */
-                                          256,                  /* height */
-                                          1,                    /* depth */
-                                          0,                    /* border */
-                                          GL_RGBA, GL_UNSIGNED_BYTE);
-
-  EXPECT_CALL(*gl_, DeleteTextures(1, _)).Times(1).RetiresOnSaturation();
-  abstract_texture.reset();
-  EXPECT_EQ(GetDecoder()->HasMoreIdleWork(), false);
-}
-
-TEST_P(GLES2DecoderTest, TestAbstractTextureSetClearedWorks) {
-  const GLuint service_id = 123;
-  EXPECT_CALL(*gl_, GenTextures(1, _))
-      .Times(1)
-      .WillOnce(SetArgPointee<1>(service_id))
-      .RetiresOnSaturation();
-  const GLenum target = GL_TEXTURE_2D;
-  std::unique_ptr<AbstractTexture> abstract_texture =
-      GetDecoder()->CreateAbstractTexture(target, GL_RGBA, 256, /* width */
-                                          256,                  /* height */
-                                          1,                    /* depth */
-                                          0,                    /* border */
-                                          GL_RGBA, GL_UNSIGNED_BYTE);
-  Texture* texture = Texture::CheckedCast(abstract_texture->GetTextureBase());
-
-  // Texture should start off unrenderable.
-  EXPECT_EQ(texture->SafeToRenderFrom(), false);
-
-  // Setting it to be cleared should make it renderable.
-  abstract_texture->SetCleared();
-  EXPECT_EQ(texture->SafeToRenderFrom(), true);
-
-  EXPECT_CALL(*gl_, DeleteTextures(1, _)).Times(1).RetiresOnSaturation();
-  abstract_texture.reset();
-}
-#endif
-
 TEST_P(GLES3DecoderTest, GetInternalformativValidArgsSamples) {
   const GLint kNumSampleCounts = 8;
   auto* result =
diff --git a/gpu/command_buffer/service/gles2_query_manager.cc b/gpu/command_buffer/service/gles2_query_manager.cc
index 0dfebfb..c60f128 100644
--- a/gpu/command_buffer/service/gles2_query_manager.cc
+++ b/gpu/command_buffer/service/gles2_query_manager.cc
@@ -174,9 +174,8 @@
   MarkAsCompleted(summed_result);
 }
 
-class AsyncReadPixelsCompletedQuery
-    : public GLES2QueryManager::GLES2Query,
-      public base::SupportsWeakPtr<AsyncReadPixelsCompletedQuery> {
+class AsyncReadPixelsCompletedQuery final
+    : public GLES2QueryManager::GLES2Query {
  public:
   AsyncReadPixelsCompletedQuery(GLES2QueryManager* manager,
                                 GLenum target,
@@ -194,6 +193,7 @@
  protected:
   void Complete();
   ~AsyncReadPixelsCompletedQuery() override;
+  base::WeakPtrFactory<AsyncReadPixelsCompletedQuery> weak_ptr_factory_{this};
 };
 
 AsyncReadPixelsCompletedQuery::AsyncReadPixelsCompletedQuery(
@@ -218,7 +218,8 @@
 void AsyncReadPixelsCompletedQuery::End(base::subtle::Atomic32 submit_count) {
   MarkAsPending(submit_count);
   gles2_query_manager()->decoder()->WaitForReadPixels(
-      base::BindOnce(&AsyncReadPixelsCompletedQuery::Complete, AsWeakPtr()));
+      base::BindOnce(&AsyncReadPixelsCompletedQuery::Complete,
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 void AsyncReadPixelsCompletedQuery::QueryCounter(
diff --git a/gpu/command_buffer/service/validating_abstract_texture_impl.cc b/gpu/command_buffer/service/validating_abstract_texture_impl.cc
deleted file mode 100644
index f0fe702..0000000
--- a/gpu/command_buffer/service/validating_abstract_texture_impl.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "gpu/command_buffer/service/validating_abstract_texture_impl.h"
-
-#include "build/build_config.h"
-#include "gpu/command_buffer/service/context_group.h"
-#include "gpu/command_buffer/service/error_state.h"
-#include "gpu/command_buffer/service/texture_manager.h"
-#include "ui/gl/gl_context.h"
-#include "ui/gl/scoped_binders.h"
-#include "ui/gl/scoped_make_current.h"
-
-namespace gpu {
-namespace gles2 {
-
-ValidatingAbstractTextureImpl::ValidatingAbstractTextureImpl(
-    scoped_refptr<TextureRef> texture_ref,
-    DecoderContext* decoder_context,
-    DestructionCB destruction_cb)
-    : texture_ref_(std::move(texture_ref)),
-      decoder_context_(decoder_context),
-      destruction_cb_(std::move(destruction_cb)) {}
-
-ValidatingAbstractTextureImpl::~ValidatingAbstractTextureImpl() {
-  if (cleanup_cb_) {
-    DCHECK(texture_ref_);
-    std::move(cleanup_cb_).Run(this);
-  }
-
-  if (destruction_cb_)
-    std::move(destruction_cb_).Run(this, std::move(texture_ref_));
-
-  DCHECK(!texture_ref_);
-}
-
-TextureBase* ValidatingAbstractTextureImpl::GetTextureBase() const {
-  if (!texture_ref_)
-    return nullptr;
-  return texture_ref_->texture();
-}
-
-void ValidatingAbstractTextureImpl::SetParameteri(GLenum pname, GLint param) {
-  if (!texture_ref_)
-    return;
-
-  gl::ScopedTextureBinder binder(texture_ref_->texture()->target(),
-                                 service_id());
-  GetTextureManager()->SetParameteri(__func__, GetErrorState(),
-                                     texture_ref_.get(), pname, param);
-}
-
-void ValidatingAbstractTextureImpl::SetCleared() {
-  if (!texture_ref_)
-    return;
-
-  const GLint level = 0;
-  GetTextureManager()->SetLevelCleared(
-      texture_ref_.get(), texture_ref_->texture()->target(), level, true);
-}
-
-void ValidatingAbstractTextureImpl::SetCleanupCallback(CleanupCallback cb) {
-  cleanup_cb_ = std::move(cb);
-}
-
-TextureManager* ValidatingAbstractTextureImpl::GetTextureManager() const {
-  DCHECK(decoder_context_);
-  return GetContextGroup()->texture_manager();
-}
-
-ContextGroup* ValidatingAbstractTextureImpl::GetContextGroup() const {
-  DCHECK(decoder_context_);
-  return decoder_context_->GetContextGroup();
-}
-
-ErrorState* ValidatingAbstractTextureImpl::GetErrorState() const {
-  DCHECK(decoder_context_);
-  return decoder_context_->GetErrorState();
-}
-
-void ValidatingAbstractTextureImpl::NotifyOnContextLost() {
-  NOTIMPLEMENTED();
-}
-
-void ValidatingAbstractTextureImpl::OnDecoderWillDestroy(bool have_context) {
-  // If we don't have a context, then notify the TextureRef not to delete itself
-  // if this is the last reference.
-  destruction_cb_ = DestructionCB();
-  decoder_context_ = nullptr;
-
-  // If we already got rid of the texture ref, then there's nothing to do.
-  if (!texture_ref_)
-    return;
-
-  if (cleanup_cb_)
-    std::move(cleanup_cb_).Run(this);
-
-  // If we have no context, then notify the TextureRef in case it's the last
-  // ref to the texture.
-  if (!have_context)
-    texture_ref_->ForceContextLost();
-  texture_ref_ = nullptr;
-}
-
-TextureRef* ValidatingAbstractTextureImpl::GetTextureRefForTesting() {
-  return texture_ref_.get();
-}
-
-}  // namespace gles2
-}  // namespace gpu
diff --git a/gpu/command_buffer/service/validating_abstract_texture_impl.h b/gpu/command_buffer/service/validating_abstract_texture_impl.h
deleted file mode 100644
index ad0f850..0000000
--- a/gpu/command_buffer/service/validating_abstract_texture_impl.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2018 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef GPU_COMMAND_BUFFER_SERVICE_VALIDATING_ABSTRACT_TEXTURE_IMPL_H_
-#define GPU_COMMAND_BUFFER_SERVICE_VALIDATING_ABSTRACT_TEXTURE_IMPL_H_
-
-#include "base/functional/callback.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/scoped_refptr.h"
-#include "build/build_config.h"
-#include "gpu/command_buffer/service/abstract_texture.h"
-#include "gpu/gpu_gles2_export.h"
-
-namespace gpu {
-class DecoderContext;
-
-namespace gles2 {
-
-class ContextGroup;
-class ErrorState;
-class TextureManager;
-class TextureRef;
-
-// Implementation of AbstractTexture used by the validating command decoder.
-class GPU_GLES2_EXPORT ValidatingAbstractTextureImpl : public AbstractTexture {
- public:
-  using DestructionCB = base::OnceCallback<void(ValidatingAbstractTextureImpl*,
-                                                scoped_refptr<TextureRef>)>;
-
-  ValidatingAbstractTextureImpl(scoped_refptr<TextureRef> texture_ref,
-                                DecoderContext* DecoderContext,
-                                DestructionCB destruction_cb);
-  ~ValidatingAbstractTextureImpl() override;
-
-  // AbstractTexture
-  TextureBase* GetTextureBase() const override;
-  void SetParameteri(GLenum pname, GLint param) override;
-
-  void SetCleared() override;
-  void SetCleanupCallback(CleanupCallback cb) override;
-  void NotifyOnContextLost() override;
-
-  // Called when our decoder is going away, so that we can try to clean up.
-  void OnDecoderWillDestroy(bool have_context);
-
-  // Testing methods
-  TextureRef* GetTextureRefForTesting();
-
- private:
-  TextureManager* GetTextureManager() const;
-  ContextGroup* GetContextGroup() const;
-  ErrorState* GetErrorState() const;
-
-  // Reset our level (0) info to be what we were given during construction.
-  void SetLevelInfo();
-
-  scoped_refptr<TextureRef> texture_ref_;
-
-  raw_ptr<DecoderContext> decoder_context_ = nullptr;
-  DestructionCB destruction_cb_;
-  CleanupCallback cleanup_cb_;
-};
-
-}  // namespace gles2
-}  // namespace gpu
-
-#endif  // GPU_COMMAND_BUFFER_SERVICE_VALIDATING_ABSTRACT_TEXTURE_IMPL_H_
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json
index 5b8bd78..84578534 100644
--- a/gpu/config/gpu_driver_bug_list.json
+++ b/gpu/config/gpu_driver_bug_list.json
@@ -3371,6 +3371,7 @@
         "type": "win"
       },
       "vendor_id": "0x1002",
+      "multi_gpu_category": "active",
       "device_id": [
         "0x67c7", "0x67df", "0x67ff", "0x6fdf", "0x67ef", "0x6981",
         "0x6987", "0x699f", "0x67c2", "0x67d0", "0x6900", "0x6984",
diff --git a/gpu/ipc/DEPS b/gpu/ipc/DEPS
index 3dbc42d..f28e212c 100644
--- a/gpu/ipc/DEPS
+++ b/gpu/ipc/DEPS
@@ -2,6 +2,5 @@
   "+cc/base/completion_event.h",
   "+components/viz/common/features.h",
   "+components/viz/common/display/update_vsync_parameters_callback.h",
-  "+components/viz/common/gpu/gpu_vsync_callback.h",
 ]
 
diff --git a/gpu/ipc/service/DEPS b/gpu/ipc/service/DEPS
index 219db9e..c1a5a773 100644
--- a/gpu/ipc/service/DEPS
+++ b/gpu/ipc/service/DEPS
@@ -2,7 +2,6 @@
   "+cc/paint",
   "+components/crash/core/common/crash_key.h",
   "+components/viz/common/features.h",
-  "+components/viz/common/gpu/gpu_vsync_callback.h",
   "+components/viz/common/gpu/vulkan_context_provider.h",
   "+components/viz/common/overlay_state/win/overlay_state_service.h",
   "+components/viz/common/resources/resource_sizes.h",
diff --git a/gpu/ipc/service/gles2_command_buffer_stub.cc b/gpu/ipc/service/gles2_command_buffer_stub.cc
index 7520038..f449aa84 100644
--- a/gpu/ipc/service/gles2_command_buffer_stub.cc
+++ b/gpu/ipc/service/gles2_command_buffer_stub.cc
@@ -404,10 +404,6 @@
   return context_group_->gpu_preferences();
 }
 
-viz::GpuVSyncCallback GLES2CommandBufferStub::GetGpuVSyncCallback() {
-  return viz::GpuVSyncCallback();
-}
-
 MemoryTracker* GLES2CommandBufferStub::GetContextGroupMemoryTracker() const {
   return context_group_->memory_tracker();
 }
diff --git a/gpu/ipc/service/gles2_command_buffer_stub.h b/gpu/ipc/service/gles2_command_buffer_stub.h
index c2a1231..73dabd82 100644
--- a/gpu/ipc/service/gles2_command_buffer_stub.h
+++ b/gpu/ipc/service/gles2_command_buffer_stub.h
@@ -52,7 +52,6 @@
 #endif
   const gles2::FeatureInfo* GetFeatureInfo() const override;
   const GpuPreferences& GetGpuPreferences() const override;
-  viz::GpuVSyncCallback GetGpuVSyncCallback() override;
 
  private:
   // CommandBufferStub overrides:
diff --git a/gpu/ipc/service/image_transport_surface_delegate.h b/gpu/ipc/service/image_transport_surface_delegate.h
index 5cc09ea0..2dc9b44b 100644
--- a/gpu/ipc/service/image_transport_surface_delegate.h
+++ b/gpu/ipc/service/image_transport_surface_delegate.h
@@ -7,7 +7,6 @@
 
 #include "base/functional/callback.h"
 #include "build/build_config.h"
-#include "components/viz/common/gpu/gpu_vsync_callback.h"
 #include "gpu/ipc/common/surface_handle.h"
 #include "gpu/ipc/service/gpu_ipc_service_export.h"
 #include "ui/gfx/gpu_fence_handle.h"
@@ -32,9 +31,6 @@
 
   virtual const GpuPreferences& GetGpuPreferences() const = 0;
 
-  // Callback for GPU vsync signal.  May be called on a different thread.
-  virtual viz::GpuVSyncCallback GetGpuVSyncCallback() = 0;
-
  protected:
   virtual ~ImageTransportSurfaceDelegate() = default;
 };
diff --git a/gpu/ipc/service/image_transport_surface_win.cc b/gpu/ipc/service/image_transport_surface_win.cc
index 88d07fd..9d8447cf 100644
--- a/gpu/ipc/service/image_transport_surface_win.cc
+++ b/gpu/ipc/service/image_transport_surface_win.cc
@@ -47,12 +47,10 @@
     base::WeakPtr<ImageTransportSurfaceDelegate> delegate,
     SurfaceHandle surface_handle) {
   if (gl::DirectCompositionSupported()) {
-    auto vsync_callback = delegate->GetGpuVSyncCallback();
     auto settings =
         CreatDCompPresenterSettings(delegate->GetFeatureInfo()->workarounds());
     auto presenter = base::MakeRefCounted<gl::DCompPresenter>(
-        display->GetAs<gl::GLDisplayEGL>(), std::move(vsync_callback),
-        settings);
+        display->GetAs<gl::GLDisplayEGL>(), settings);
     if (!presenter->Initialize()) {
       return nullptr;
     }
diff --git a/infra/config/generated/testing/variants.pyl b/infra/config/generated/testing/variants.pyl
index 8aa7644..00e161f5 100644
--- a/infra/config/generated/testing/variants.pyl
+++ b/infra/config/generated/testing/variants.pyl
@@ -121,6 +121,7 @@
       'cros_board': 'jacuzzi',
       'use_lkgm': True,
       'bucket': 'chromiumos-image-archive',
+      'dut_pool': 'chromium',
       'public_builder': 'cros_test_platform_public',
       'public_builder_bucket': 'testplatform-public',
     },
@@ -130,6 +131,7 @@
     'skylab': {
       'cros_board': 'jacuzzi',
       'use_lkgm': True,
+      'dut_pool': 'chrome',
     },
   },
   'CROS_JACUZZI_RELEASE_LKGM': {
@@ -137,6 +139,7 @@
     'skylab': {
       'cros_board': 'jacuzzi',
       'use_lkgm': True,
+      'dut_pool': 'chrome',
     },
   },
   'CROS_OCTOPUS_PUBLIC_LKGM': {
@@ -145,6 +148,7 @@
       'cros_board': 'octopus',
       'use_lkgm': True,
       'bucket': 'chromiumos-image-archive',
+      'dut_pool': 'chromium',
     },
   },
   'CROS_OCTOPUS_RELEASE_CHROME_FROM_TLS_ASH_LKGM': {
@@ -153,6 +157,7 @@
       'cros_board': 'octopus',
       'cros_model': 'casta',
       'use_lkgm': True,
+      'dut_pool': 'chrome',
     },
   },
   'CROS_PUFF_RELEASE_BETA': {
@@ -192,6 +197,7 @@
     'skylab': {
       'cros_board': 'strongbad',
       'use_lkgm': True,
+      'dut_pool': 'chrome',
     },
   },
   'CROS_TROGDOR_PUBLIC_LKGM': {
@@ -200,6 +206,7 @@
       'cros_board': 'trogdor',
       'cros_img': 'trogdor-public/R123-15763.0.0',
       'bucket': 'chromiumos-image-archive',
+      'dut_pool': 'chromium',
     },
   },
   'CROS_TROGDOR_RELEASE_ASH_LKGM': {
@@ -207,6 +214,7 @@
     'skylab': {
       'cros_board': 'trogdor',
       'use_lkgm': True,
+      'dut_pool': 'chrome',
     },
   },
   'CROS_VOLTEER_PUBLIC_LKGM': {
@@ -238,6 +246,7 @@
     'skylab': {
       'cros_board': 'volteer',
       'use_lkgm': True,
+      'dut_pool': 'chrome',
     },
   },
   'DISABLE_FIELD_TRIAL_CONFIG': {
@@ -307,16 +316,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'identifier': 'Lacros version skew testing ash canary',
-    'description': 'Run with ash-chrome version 123.0.6283.0',
+    'description': 'Run with ash-chrome version 123.0.6284.0',
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6283.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6284.0/test_ash_chrome',
     ],
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v123.0.6283.0',
-          'revision': 'version:123.0.6283.0',
+          'location': 'lacros_version_skew_tests_v123.0.6284.0',
+          'revision': 'version:123.0.6284.0',
         },
       ],
     },
diff --git a/infra/config/targets/cros-skylab-variants.json b/infra/config/targets/cros-skylab-variants.json
index a1f28e3..0b311e567 100644
--- a/infra/config/targets/cros-skylab-variants.json
+++ b/infra/config/targets/cros-skylab-variants.json
@@ -10,8 +10,8 @@
   "CROS_BRYA_RELEASE_LKGM": {
     "skylab": {
       "cros_board": "brya",
-      "use_lkgm": true,
-      "dut_pool": "chrome"
+      "dut_pool": "chrome",
+      "use_lkgm": true
     },
     "enabled": true,
     "identifier": "BRYA_RELEASE_LKGM"
@@ -49,8 +49,8 @@
   "CROS_FIZZ_RELEASE_LKGM": {
     "skylab": {
       "cros_board": "fizz",
-      "use_lkgm": true,
-      "dut_pool": "chrome"
+      "dut_pool": "chrome",
+      "use_lkgm": true
     },
     "enabled": true,
     "identifier": "FIZZ_RELEASE_LKGM"
@@ -88,8 +88,8 @@
   "CROS_GUYBRUSH_RELEASE_LKGM": {
     "skylab": {
       "cros_board": "guybrush",
-      "use_lkgm": true,
-      "dut_pool": "chrome"
+      "dut_pool": "chrome",
+      "use_lkgm": true
     },
     "enabled": true,
     "identifier": "GUYBRUSH_RELEASE_LKGM"
@@ -127,8 +127,8 @@
   "CROS_PUFF_RELEASE_LKGM": {
     "skylab": {
       "cros_board": "puff",
-      "use_lkgm": true,
-      "dut_pool": "chrome"
+      "dut_pool": "chrome",
+      "use_lkgm": true
     },
     "enabled": true,
     "identifier": "PUFF_RELEASE_LKGM"
@@ -166,6 +166,7 @@
   "CROS_JACUZZI_RELEASE_LKGM": {
     "skylab": {
       "cros_board": "jacuzzi",
+      "dut_pool": "chrome",
       "use_lkgm": true
     },
     "enabled": true,
@@ -174,6 +175,7 @@
   "CROS_JACUZZI_RELEASE_CHROME_FROM_TLS_ASH_LKGM": {
     "skylab": {
       "cros_board": "jacuzzi",
+      "dut_pool": "chrome",
       "use_lkgm": true
     },
     "identifier": "JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM"
@@ -181,6 +183,7 @@
   "CROS_JACUZZI_CQ_PUBLIC_LKGM": {
     "skylab": {
       "cros_board": "jacuzzi",
+      "dut_pool": "chromium",
       "use_lkgm": true,
       "bucket": "chromiumos-image-archive",
       "public_builder": "cros_test_platform_public",
@@ -194,6 +197,7 @@
       "cros_board": "trogdor",
       "cros_chrome_version": "123.0.6268.0",
       "cros_img": "trogdor-public/R123-15763.0.0",
+      "dut_pool": "chromium",
       "bucket": "chromiumos-image-archive"
     },
     "enabled": true,
@@ -202,6 +206,7 @@
   "CROS_OCTOPUS_PUBLIC_LKGM": {
     "skylab": {
       "cros_board": "octopus",
+      "dut_pool": "chromium",
       "use_lkgm": true,
       "bucket": "chromiumos-image-archive"
     },
@@ -212,6 +217,7 @@
     "skylab": {
       "cros_board": "octopus",
       "cros_model": "casta",
+      "dut_pool": "chrome",
       "use_lkgm": true
     },
     "identifier": "OCTOPUS_RELEASE_CHROME_FROM_TLS_LKGM"
@@ -219,6 +225,7 @@
   "CROS_STRONGBAD_RELEASE_LKGM": {
     "skylab": {
       "cros_board": "strongbad",
+      "dut_pool": "chrome",
       "use_lkgm": true
     },
     "enabled": true,
@@ -227,6 +234,7 @@
   "CROS_TROGDOR_RELEASE_ASH_LKGM": {
     "skylab": {
       "cros_board": "trogdor",
+      "dut_pool": "chrome",
       "use_lkgm": true
     },
     "identifier": "TROGDOR_RELEASE_LKGM"
@@ -260,8 +268,9 @@
   "CROS_VOLTEER_RELEASE_ASH_LKGM": {
     "skylab": {
       "cros_board": "volteer",
+      "dut_pool": "chrome",
       "use_lkgm": true
     },
     "identifier": "VOLTEER_RELEASE_LKGM"
   }
-}
\ No newline at end of file
+}
diff --git a/infra/config/targets/lacros-version-skew-variants.json b/infra/config/targets/lacros-version-skew-variants.json
index ad2be9e..b47c5c9 100644
--- a/infra/config/targets/lacros-version-skew-variants.json
+++ b/infra/config/targets/lacros-version-skew-variants.json
@@ -1,16 +1,16 @@
 {
   "LACROS_VERSION_SKEW_CANARY": {
     "args": [
-      "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6283.0/test_ash_chrome"
+      "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6284.0/test_ash_chrome"
     ],
-    "description": "Run with ash-chrome version 123.0.6283.0",
+    "description": "Run with ash-chrome version 123.0.6284.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_v123.0.6283.0",
-          "revision": "version:123.0.6283.0"
+          "location": "lacros_version_skew_tests_v123.0.6284.0",
+          "revision": "version:123.0.6284.0"
         }
       ]
     }
diff --git a/internal b/internal
index 267ce4f..4852454 160000
--- a/internal
+++ b/internal
@@ -1 +1 @@
-Subproject commit 267ce4f58248ec59895483e5ef12b065db32717c
+Subproject commit 4852454fa25ae02654a48b1592efb73803fe8067
diff --git a/ios/chrome/browser/passwords/model/password_manager_util_ios.cc b/ios/chrome/browser/passwords/model/password_manager_util_ios.cc
index c5c0e8d4..dab2c8cc 100644
--- a/ios/chrome/browser/passwords/model/password_manager_util_ios.cc
+++ b/ios/chrome/browser/passwords/model/password_manager_util_ios.cc
@@ -14,14 +14,10 @@
 bool IsSavingPasswordsToAccountWithNormalEncryption(
     const syncer::SyncService* sync_service) {
   switch (password_manager::sync_util::GetPasswordSyncState(sync_service)) {
-    case password_manager::sync_util::SyncState::kSyncingNormalEncryption:
-    case password_manager::sync_util::SyncState::
-        kAccountPasswordsActiveNormalEncryption:
+    case password_manager::sync_util::SyncState::kActiveWithNormalEncryption:
       return true;
     case password_manager::sync_util::SyncState::kNotActive:
-    case password_manager::sync_util::SyncState::kSyncingWithCustomPassphrase:
-    case password_manager::sync_util::SyncState::
-        kAccountPasswordsActiveWithCustomPassphrase:
+    case password_manager::sync_util::SyncState::kActiveWithCustomPassphrase:
       return false;
   }
   NOTREACHED_NORETURN();
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index ec19ecee..d3c7358 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -908,12 +908,17 @@
              base::FEATURE_DISABLED_BY_DEFAULT);
 #endif  // BUILDFLAG(IS_APPLE)
 
-// A video encoder is enabled to drop a frame in cast mirroring.
+// A video encoder is allowed to drop a frame in cast mirroring.
 BASE_FEATURE(kCastVideoEncoderFrameDrop,
              "CastVideoEncoderFrameDrop",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// A hardware video encoder is enabled to drop a frame in WebRTC.
+// A video encoder is allowed to drop a frame in WebCodecs.
+BASE_FEATURE(kWebCodecsVideoEncoderFrameDrop,
+             "WebCodecsVideoEncoderFrameDrop",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+// A hardware video encoder is allowed to drop a frame in WebRTC.
 BASE_FEATURE(kWebRTCHardwareVideoEncoderFrameDrop,
              "WebRTCHardwareVideoEncoderFrameDrop",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index 8a473b6..646f7df55 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -360,6 +360,7 @@
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kVideoToolboxVideoDecoder);
 #endif  // BUILDFLAG(IS_APPLE)
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kCastVideoEncoderFrameDrop);
+MEDIA_EXPORT BASE_DECLARE_FEATURE(kWebCodecsVideoEncoderFrameDrop);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kWebRTCHardwareVideoEncoderFrameDrop);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kWebRTCColorAccuracy);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kWebContentsCaptureHiDpi);
diff --git a/media/base/video_encoder.cc b/media/base/video_encoder.cc
index c238897..8ec6f1af 100644
--- a/media/base/video_encoder.cc
+++ b/media/base/video_encoder.cc
@@ -9,10 +9,18 @@
 #include "base/numerics/checked_math.h"
 #include "base/numerics/clamped_math.h"
 #include "base/system/sys_info.h"
+#include "media/base/media_switches.h"
 #include "media/base/video_frame.h"
 
 namespace media {
 
+uint8_t GetDefaultVideoEncoderDropFrameThreshold() {
+  // This function is to be invoked only in WebCodecs usage.
+  // The drop frame threshold is the same as WebRTC.
+  // https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc
+  return base::FeatureList::IsEnabled(kWebCodecsVideoEncoderFrameDrop) ? 30 : 0;
+}
+
 uint32_t GetDefaultVideoEncodeBitrate(gfx::Size frame_size,
                                       uint32_t framerate) {
   // Let's default to 2M bps for HD at 30 fps.
diff --git a/media/base/video_encoder.h b/media/base/video_encoder.h
index edf7a00..dc17c74 100644
--- a/media/base/video_encoder.h
+++ b/media/base/video_encoder.h
@@ -24,6 +24,9 @@
 struct VideoEncoderInfo;
 class VideoFrame;
 
+// Returns the drop frame threshold for media::VideoEncoder used in WebCodecs.
+MEDIA_EXPORT uint8_t GetDefaultVideoEncoderDropFrameThreshold();
+
 MEDIA_EXPORT uint32_t GetDefaultVideoEncodeBitrate(gfx::Size frame_size,
                                                    uint32_t framerate);
 
diff --git a/media/gpu/chromeos/BUILD.gn b/media/gpu/chromeos/BUILD.gn
index ebaa108..d32a68f 100644
--- a/media/gpu/chromeos/BUILD.gn
+++ b/media/gpu/chromeos/BUILD.gn
@@ -162,7 +162,6 @@
 # This needs to be separate from :common since it is depended on by
 # //media/gpu:video_frame_mapper_common.
 source_set("video_frame_resource") {
-  defines = [ "MEDIA_GPU_IMPLEMENTATION" ]
   sources = [
     "frame_resource.cc",
     "frame_resource.h",
diff --git a/media/gpu/test/image.cc b/media/gpu/test/image.cc
index 91d841b..24c8bea9 100644
--- a/media/gpu/test/image.cc
+++ b/media/gpu/test/image.cc
@@ -94,7 +94,7 @@
 
   // Verify that the image's checksum matches the checksum in the metadata.
   base::MD5Digest digest;
-  base::MD5Sum(mapped_file_.data(), mapped_file_.length(), &digest);
+  base::MD5Sum(mapped_file_.bytes(), &digest);
   if (base::MD5DigestToBase16(digest) != checksum_) {
     LOG(ERROR) << "Image checksum not matching metadata";
     return false;
diff --git a/media/gpu/v4l2/test/v4l2_stateless_decoder.cc b/media/gpu/v4l2/test/v4l2_stateless_decoder.cc
index e4af6e0..28db99ae 100644
--- a/media/gpu/v4l2/test/v4l2_stateless_decoder.cc
+++ b/media/gpu/v4l2/test/v4l2_stateless_decoder.cc
@@ -90,7 +90,7 @@
 void ComputeAndPrintMD5hash(const std::vector<uint8_t>& yuv_plane,
                             const base::FilePath md5_log_location) {
   base::MD5Digest md5_digest;
-  base::MD5Sum(yuv_plane.data(), yuv_plane.size(), &md5_digest);
+  base::MD5Sum(yuv_plane, &md5_digest);
   std::string md5_digest_b16 = MD5DigestToBase16(md5_digest);
 
   if (!md5_log_location.empty()) {
diff --git a/media/gpu/v4l2/v4l2_queue.cc b/media/gpu/v4l2/v4l2_queue.cc
index 39ca869..db7331c6 100644
--- a/media/gpu/v4l2/v4l2_queue.cc
+++ b/media/gpu/v4l2/v4l2_queue.cc
@@ -362,7 +362,7 @@
 
   // Create the video frame instance if requiring it for the first time.
   if (!frame_) {
-    // TODO(nhebert): switch to NativePixmap FrameResource when it is ready
+    // TODO(nhebert): switch to NativePixmap FrameResource when it is ready.
     frame_ = VideoFrameResource::Create(CreateVideoFrame());
   }
 
@@ -619,10 +619,9 @@
   if (!frame) {
     return nullptr;
   }
-  if (!frame->AsVideoFrameResource()) {
-    NOTREACHED() << "V4L2ReadableBuffer::GetVideoFrame() is only called when "
-                    "the |frame_| is a VideoFrameResource";
-  }
+  LOG_ASSERT(!!frame->AsVideoFrameResource())
+      << "V4L2WritableBufferRef::GetVideoFrame() is only called when the "
+         "|frame_| is a VideoFrameResource";
   return frame->AsVideoFrameResource()->GetMutableVideoFrame();
 }
 
@@ -962,10 +961,9 @@
   if (!frame) {
     return nullptr;
   }
-  if (!frame->AsVideoFrameResource()) {
-    NOTREACHED() << "V4L2ReadableBuffer::GetVideoFrame() is only called when "
-                    "the |frame_| is a VideoFrameResource";
-  }
+  LOG_ASSERT(!!frame->AsVideoFrameResource())
+      << "V4L2ReadableBuffer::GetVideoFrame() is only called when the |frame_| "
+         "is a VideoFrameResource";
   return frame->AsVideoFrameResource()->GetMutableVideoFrame();
 }
 
diff --git a/media/gpu/v4l2/v4l2_queue.h b/media/gpu/v4l2/v4l2_queue.h
index 5d450458..aa0b559 100644
--- a/media/gpu/v4l2/v4l2_queue.h
+++ b/media/gpu/v4l2/v4l2_queue.h
@@ -206,7 +206,7 @@
 // All methods of this class must be called from the same sequence, but
 // instances of V4L2ReadableBuffer objects can be destroyed from any sequence.
 // They can even outlive the V4L2 buffers they originate from. This flexibility
-// is required because V4L2ReadableBufferRefs can be embedded into VideoFrames,
+// is required because V4L2ReadableBufferRefs can be embedded into frames,
 // which are then passed to other threads and not necessarily destroyed before
 // the V4L2Queue buffers are freed.
 class MEDIA_GPU_EXPORT V4L2ReadableBuffer
@@ -508,21 +508,21 @@
   // return |std::nullopt|.
   [[nodiscard]] std::optional<V4L2WritableBufferRef> GetFreeBuffer(
       size_t requested_buffer_id);
-  // Return a V4L2 buffer suitable for the passed VideoFrame.
+  // Return a V4L2 buffer suitable for the passed frame.
   //
   // This method will try as much as possible to always return the same V4L2
   // buffer when the same frame is passed again, to avoid memory unmap
   // operations in the kernel driver.
   //
-  // The operating mode of the queue must be DMABUF, and the VideoFrame must
-  // be backed either by a GpuMemoryBuffer, or by DMABUFs. In the case of
-  // DMABUFs, this method will only work correctly if the same DMABUFs are
-  // passed with each call, i.e. no dup shall be performed.
+  // The operating mode of the queue must be DMABUF, and the frame must be
+  // backed either by a GpuMemoryBuffer, or by DMABUFs. In the case of DMABUFs,
+  // this method will only work correctly if the same DMABUFs are passed with
+  // each call, i.e. no dup shall be performed.
   //
   // This should be the preferred way to obtain buffers when using DMABUF mode,
   // since it will maximize performance in that case provided the number of
-  // different VideoFrames passed to this method does not exceed the number of
-  // V4L2 buffers allocated on the queue.
+  // different frames passed to this method does not exceed the number of V4L2
+  // buffers allocated on the queue.
   [[nodiscard]] std::optional<V4L2WritableBufferRef> GetFreeBufferForFrame(
       const gfx::GenericSharedMemoryId& id);
 
@@ -609,13 +609,13 @@
   scoped_refptr<V4L2BuffersList> free_buffers_;
 
   // Buffers that have been queued by the client, and not dequeued yet, indexed
-  // by the v4l2_buffer queue ID. The value will be set to the VideoFrame that
-  // has been passed when we queued the buffer, if any.
+  // by the v4l2_buffer queue ID. The value will be set to the FrameResource
+  // that has been passed when we queued the buffer, if any.
   base::small_map<std::map<size_t, scoped_refptr<FrameResource>>>
       queued_buffers_;
 
   // Dictionary of queue buffers (indexed 0... |buffers_| size), indexed by the
-  // unique VideoFrame id (be that a GpuMemoryBuffer ID or a DmaBuf ID).
+  // unique frame id (be that a GpuMemoryBuffer ID or a DmaBuf ID).
   std::map<gfx::GenericSharedMemoryId, size_t> free_buffers_indexes_
       GUARDED_BY_CONTEXT(sequence_checker_);
 
diff --git a/media/gpu/vaapi/test/shared_va_surface.cc b/media/gpu/vaapi/test/shared_va_surface.cc
index 962916e6..6fba1b2 100644
--- a/media/gpu/vaapi/test/shared_va_surface.cc
+++ b/media/gpu/vaapi/test/shared_va_surface.cc
@@ -278,7 +278,7 @@
   VA_LOG_ASSERT(res, "vaDestroyImage");
 
   base::MD5Digest md5_digest;
-  base::MD5Sum(i420_data.data(), i420_data.size(), &md5_digest);
+  base::MD5Sum(i420_data, &md5_digest);
   return MD5DigestToBase16(md5_digest);
 }
 
diff --git a/media/video/av1_video_encoder.cc b/media/video/av1_video_encoder.cc
index be461d9..42648e5 100644
--- a/media/video/av1_video_encoder.cc
+++ b/media/video/av1_video_encoder.cc
@@ -141,7 +141,11 @@
   config.g_lag_in_frames = 0;
   config.rc_max_quantizer = 56;
   config.rc_min_quantizer = 10;
-  config.rc_dropframe_thresh = 0;  // Don't drop frames
+  // Only if latency_mode is real time, a frame might be dropped.
+  config.rc_dropframe_thresh =
+      opts.latency_mode == VideoEncoder::LatencyMode::Realtime
+          ? GetDefaultVideoEncoderDropFrameThreshold()
+          : 0;
 
   config.rc_undershoot_pct = 50;
   config.rc_overshoot_pct = 50;
@@ -623,12 +627,14 @@
 void Av1VideoEncoder::DrainOutputs(int temporal_id,
                                    base::TimeDelta ts,
                                    gfx::ColorSpace color_space) {
+  bool dropped_frame = true;
   const aom_codec_cx_pkt_t* pkt = nullptr;
   aom_codec_iter_t iter = nullptr;
   while ((pkt = aom_codec_get_cx_data(codec_.get(), &iter)) != nullptr) {
     if (pkt->kind != AOM_CODEC_CX_FRAME_PKT)
       continue;
 
+    dropped_frame = false;
     VideoEncoderOutput result;
     result.key_frame = (pkt->data.frame.flags & AOM_FRAME_IS_KEY) != 0;
     result.timestamp = ts;
@@ -638,7 +644,7 @@
     if (result.key_frame) {
       // If we got an unexpected key frame, temporal_svc_frame_index needs to
       // be adjusted, because the next frame should have index 1.
-      temporal_svc_frame_index_ = 1;
+      temporal_svc_frame_index_ = 0;
       result.temporal_id = 0;
     } else {
       result.temporal_id = temporal_id;
@@ -648,11 +654,23 @@
     memcpy(result.data.get(), pkt->data.frame.buf, result.size);
     output_cb_.Run(std::move(result), {});
   }
+
+  if (dropped_frame) {
+    VideoEncoderOutput result;
+    result.timestamp = ts;
+    output_cb_.Run(std::move(result), {});
+    return;
+  }
+
+  if (svc_params_.number_temporal_layers > 1) {
+    temporal_svc_frame_index_++;
+  }
 }
 
 EncoderStatus::Or<int> Av1VideoEncoder::AssignNextTemporalId(bool key_frame) {
-  if (svc_params_.number_temporal_layers < 2)
+  if (svc_params_.number_temporal_layers <= 1) {
     return 0;
+  }
 
   int temporal_id = 0;
   if (key_frame)
@@ -673,8 +691,6 @@
     }
   }
 
-  temporal_svc_frame_index_++;
-
   aom_svc_layer_id_t layer_id = {};
   layer_id.temporal_layer_id = temporal_id;
 
diff --git a/media/video/openh264_video_encoder.cc b/media/video/openh264_video_encoder.cc
index cf3395b..ccbcdda7 100644
--- a/media/video/openh264_video_encoder.cc
+++ b/media/video/openh264_video_encoder.cc
@@ -12,6 +12,7 @@
 #include "base/system/sys_info.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
+#include "media/base/media_switches.h"
 #include "media/base/svc_scalability_mode.h"
 #include "media/base/video_frame.h"
 #include "media/base/video_util.h"
@@ -39,7 +40,9 @@
                          const VideoColorSpace& itu_cs,
                          SEncParamExt* params) {
   int threads = GetNumberOfThreadsForSoftwareEncoding(options.frame_size);
-  params->bEnableFrameSkip = false;
+  params->bEnableFrameSkip =
+      base::FeatureList::IsEnabled(kWebCodecsVideoEncoderFrameDrop) &&
+      options.latency_mode == VideoEncoder::LatencyMode::Realtime;
   params->iPaddingFlag = 0;
   params->iComplexityMode = MEDIUM_COMPLEXITY;
   params->iUsageType = options.content_hint == VideoEncoder::ContentHint::Screen
@@ -267,12 +270,17 @@
                                                  base::TimeDelta timestamp,
                                                  gfx::ColorSpace color_space) {
   VideoEncoderOutput result;
-  result.key_frame = (frame_info.eFrameType == videoFrameTypeIDR);
   result.timestamp = timestamp;
-  result.color_space = color_space;
 
-  DCHECK_GT(frame_info.iFrameSizeInBytes, 0);
-  size_t total_chunk_size = frame_info.iFrameSizeInBytes;
+  const size_t total_chunk_size = frame_info.iFrameSizeInBytes;
+  if (total_chunk_size == 0) {
+    // Drop frame.
+    output_cb_.Run(std::move(result), {});
+    return EncoderStatus::Codes::kOk;
+  }
+
+  result.key_frame = (frame_info.eFrameType == videoFrameTypeIDR);
+  result.color_space = color_space;
   result.data = std::make_unique<uint8_t[]>(total_chunk_size);
   auto* gather_buffer = result.data.get();
 
diff --git a/media/video/software_video_encoder_test.cc b/media/video/software_video_encoder_test.cc
index c3066b2..2fefe15 100644
--- a/media/video/software_video_encoder_test.cc
+++ b/media/video/software_video_encoder_test.cc
@@ -15,6 +15,7 @@
 #include "base/task/sequenced_task_runner.h"
 #include "base/test/bind.h"
 #include "base/test/gmock_callback_support.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
@@ -50,7 +51,6 @@
 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h"
 #include "third_party/libvpx/source/libvpx/vpx/vpx_codec.h"
 #endif
-
 #if BUILDFLAG(ENABLE_LIBAOM)
 #include "media/video/av1_video_encoder.h"
 #endif
@@ -574,6 +574,99 @@
   EXPECT_EQ(total_decoded_frames, total_frames_count);
 }
 
+TEST_P(SoftwareVideoEncoderTest, EncodeAndDecodeWithEnablingDrop) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(kWebCodecsVideoEncoderFrameDrop);
+  ASSERT_GT(GetDefaultVideoEncoderDropFrameThreshold(), 0u);
+
+  VideoEncoder::Options options = CreateDefaultOptions();
+  options.frame_size = gfx::Size(320, 200);
+  options.bitrate = Bitrate::ConstantBitrate(1000000u);  // 1Mbps
+  options.framerate = 25;
+  if (codec_ == VideoCodec::kH264) {
+    options.avc.produce_annexb = true;
+  }
+  options.keyframe_interval = options.framerate.value() * 3;  // every 3s
+  options.latency_mode = VideoEncoder::LatencyMode::Realtime;
+
+  base::circular_deque<scoped_refptr<VideoFrame>> frames_to_encode;
+  const int total_frames_count =
+      options.framerate.value() * 10;  // total duration 10s
+  int total_decoded_frames = 0;
+  int dropped_frames_count = 0;
+  base::circular_deque<base::TimeDelta> dropped_frame_timestamps;
+
+  auto frame_duration = base::Seconds(1.0 / options.framerate.value());
+
+  VideoEncoder::OutputCB encoder_output_cb = base::BindLambdaForTesting(
+      [&, this](VideoEncoderOutput output,
+                absl::optional<VideoEncoder::CodecDescription> desc) {
+        if (output.size == 0) {
+          dropped_frames_count++;
+          dropped_frame_timestamps.push_back(output.timestamp);
+          return;
+        }
+
+        auto buffer =
+            DecoderBuffer::FromArray(std::move(output.data), output.size);
+        buffer->set_timestamp(output.timestamp);
+        buffer->set_is_key_frame(output.key_frame);
+        decoder_->Decode(std::move(buffer), DecoderStatusCB());
+      });
+
+  VideoDecoder::OutputCB decoder_output_cb =
+      base::BindLambdaForTesting([&](scoped_refptr<VideoFrame> decoded_frame) {
+        ASSERT_FALSE(frames_to_encode.empty());
+        scoped_refptr<VideoFrame> original_frame;
+        while (!frames_to_encode.empty()) {
+          original_frame = std::move(frames_to_encode.front());
+          frames_to_encode.pop_front();
+          if (decoded_frame->timestamp() == original_frame->timestamp()) {
+            break;
+          }
+          ASSERT_FALSE(dropped_frame_timestamps.empty());
+          auto dropped_frame_timestamp = dropped_frame_timestamps.front();
+          dropped_frame_timestamps.pop_front();
+          EXPECT_EQ(original_frame->timestamp(), dropped_frame_timestamp);
+          original_frame.reset();
+        }
+
+        ASSERT_TRUE(original_frame);
+        EXPECT_EQ(decoded_frame->visible_rect().size(),
+                  original_frame->visible_rect().size());
+        EXPECT_EQ(decoded_frame->format(),
+                  GetExpectedOutputPixelFormat(profile_));
+        if (decoded_frame->format() == original_frame->format()) {
+          EXPECT_LE(CountDifferentPixels(*decoded_frame, *original_frame),
+                    original_frame->visible_rect().width());
+        }
+        ++total_decoded_frames;
+      });
+
+  PrepareDecoder(options.frame_size, std::move(decoder_output_cb));
+
+  encoder_->Initialize(profile_, options, /*info_cb=*/base::DoNothing(),
+                       std::move(encoder_output_cb),
+                       ValidateStatusThenQuitCB());
+  RunUntilQuit();
+
+  TestRandom random_color(0x964050);
+  for (int frame_index = 0; frame_index < total_frames_count; frame_index++) {
+    auto timestamp = frame_index * frame_duration;
+    auto frame = CreateFrame(options.frame_size, pixel_format_, timestamp,
+                             random_color.Rand() & 0x00FFFFFF);
+    frames_to_encode.push_back(frame);
+    encoder_->Encode(std::move(frame), VideoEncoder::EncodeOptions(false),
+                     ValidateStatusThenQuitCB());
+    ASSERT_NO_FATAL_FAILURE(RunUntilQuit());
+  }
+
+  encoder_->Flush(ValidateStatusThenQuitCB());
+  RunUntilQuit();
+  DecodeAndWaitForStatus(DecoderBuffer::CreateEOSBuffer());
+  EXPECT_EQ(total_decoded_frames + dropped_frames_count, total_frames_count);
+}
+
 TEST_P(SVCVideoEncoderTest, EncodeClipTemporalSvc) {
   VideoEncoder::Options options = CreateDefaultOptions();
   options.frame_size = gfx::Size(320, 200);
@@ -666,6 +759,139 @@
   }
 }
 
+TEST_P(SVCVideoEncoderTest, EncodeClipTemporalSvcWithEnablingDrop) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(kWebCodecsVideoEncoderFrameDrop);
+  ASSERT_GT(GetDefaultVideoEncoderDropFrameThreshold(), 0u);
+
+  VideoEncoder::Options options = CreateDefaultOptions();
+  options.frame_size = gfx::Size(320, 200);
+  options.bitrate = Bitrate::ConstantBitrate(100000u);  // 100kbps
+  options.framerate = 25;
+  options.scalability_mode = GetParam().scalability_mode;
+  if (codec_ == VideoCodec::kH264) {
+    options.avc.produce_annexb = true;
+  }
+  options.latency_mode = VideoEncoder::LatencyMode::Realtime;
+
+  std::vector<scoped_refptr<VideoFrame>> frames_to_encode;
+
+  std::vector<VideoEncoderOutput> chunks;
+  size_t total_frames_count = 80;
+  std::vector<size_t> dropped_frame_indices;
+
+  // Encoder all frames with 3 temporal layers and put all outputs in |chunks|
+  auto frame_duration = base::Seconds(1.0 / options.framerate.value());
+
+  VideoEncoder::OutputCB encoder_output_cb = base::BindLambdaForTesting(
+      [&](VideoEncoderOutput output,
+          std::optional<VideoEncoder::CodecDescription> desc) {
+        if (output.size == 0) {
+          dropped_frame_indices.push_back(chunks.size() +
+                                          dropped_frame_indices.size());
+          return;
+        }
+        chunks.push_back(std::move(output));
+      });
+
+  encoder_->Initialize(profile_, options, /*info_cb=*/base::DoNothing(),
+                       std::move(encoder_output_cb),
+                       ValidateStatusThenQuitCB());
+  RunUntilQuit();
+
+  for (auto frame_index = 0u; frame_index < total_frames_count; frame_index++) {
+    auto timestamp = frame_index * frame_duration;
+    auto frame = CreateFrame(options.frame_size, pixel_format_, timestamp);
+    frames_to_encode.push_back(frame);
+    encoder_->Encode(std::move(frame), VideoEncoder::EncodeOptions(false),
+                     ValidateStatusThenQuitCB());
+    RunUntilQuit();
+  }
+
+  encoder_->Flush(ValidateStatusThenQuitCB());
+  RunUntilQuit();
+  EXPECT_EQ(chunks.size() + dropped_frame_indices.size(), total_frames_count);
+
+  int num_temporal_layers = 1;
+  if (options.scalability_mode) {
+    switch (options.scalability_mode.value()) {
+      case SVCScalabilityMode::kL1T1:
+        // Nothing to do
+        break;
+      case SVCScalabilityMode::kL1T2:
+        num_temporal_layers = 2;
+        break;
+      case SVCScalabilityMode::kL1T3:
+        num_temporal_layers = 3;
+        break;
+      default:
+        NOTREACHED() << "Unsupported SVC: "
+                     << GetScalabilityModeName(
+                            options.scalability_mode.value());
+    }
+  }
+  // Try decoding saved outputs dropping varying number of layers
+  // and check that decoded frames indeed match the pattern:
+  // Layer Index 0: |0| | | |4| | | |8| |  |  |12|
+  // Layer Index 1: | | |2| | | |6| | | |10|  |  |
+  // Layer Index 2: | |1| |3| |5| |7| |9|  |11|  |
+  constexpr size_t kTemporalLayerCycle = 4;
+  constexpr int kTemporalLayerTable[][kTemporalLayerCycle] = {
+      {0, 0, 0, 0},
+      {0, 1, 0, 1},
+      {0, 2, 1, 2},
+  };
+  for (size_t i = 0; i < chunks.size(); ++i) {
+    ASSERT_TRUE(chunks[i].data);
+    EXPECT_EQ(
+        chunks[i].temporal_id,
+        kTemporalLayerTable[num_temporal_layers - 1][i % kTemporalLayerCycle]);
+  }
+
+  for (int max_layer = 0; max_layer < num_temporal_layers; max_layer++) {
+    std::vector<scoped_refptr<VideoFrame>> decoded_frames;
+    VideoDecoder::OutputCB decoder_output_cb =
+        base::BindLambdaForTesting([&](scoped_refptr<VideoFrame> frame) {
+          decoded_frames.push_back(frame);
+        });
+    PrepareDecoder(options.frame_size, std::move(decoder_output_cb));
+
+    size_t num_chunks = 0;
+    for (auto& chunk : chunks) {
+      if (chunk.temporal_id <= max_layer) {
+        num_chunks += 1;
+        auto buffer = DecoderBuffer::CopyFrom(chunk.data.get(), chunk.size);
+        buffer->set_timestamp(chunk.timestamp);
+        buffer->set_is_key_frame(chunk.key_frame);
+        DecodeAndWaitForStatus(std::move(buffer));
+      }
+    }
+    DecodeAndWaitForStatus(DecoderBuffer::CreateEOSBuffer());
+    ASSERT_EQ(decoded_frames.size(), num_chunks);
+    size_t encoded_frame_index = 0;
+    size_t decoded_frame_index = 0;
+    for (size_t i = 0; i < frames_to_encode.size(); ++i) {
+      if (base::Contains(dropped_frame_indices, i)) {
+        // Dropped
+        continue;
+      }
+      const int temporal_id =
+          kTemporalLayerTable[num_temporal_layers - 1]
+                             [encoded_frame_index % kTemporalLayerCycle];
+      encoded_frame_index++;
+      if (temporal_id > max_layer) {
+        // Not decoded frame.
+        continue;
+      }
+
+      auto decoded_frame = decoded_frames[decoded_frame_index];
+      decoded_frame_index++;
+      auto original_frame = frames_to_encode[i];
+      EXPECT_EQ(decoded_frame->timestamp(), original_frame->timestamp());
+    }
+  }
+}
+
 TEST_P(SVCVideoEncoderTest, ChangeLayers) {
   VideoEncoder::Options options = CreateDefaultOptions();
   options.frame_size = gfx::Size(640, 480);
diff --git a/media/video/video_encode_accelerator_adapter.cc b/media/video/video_encode_accelerator_adapter.cc
index 65503ea..7d826dc 100644
--- a/media/video/video_encode_accelerator_adapter.cc
+++ b/media/video/video_encode_accelerator_adapter.cc
@@ -21,6 +21,7 @@
 #include "gpu/ipc/common/gpu_memory_buffer_support.h"
 #include "media/base/bitstream_buffer.h"
 #include "media/base/media_log.h"
+#include "media/base/media_switches.h"
 #include "media/base/svc_scalability_mode.h"
 #include "media/base/video_frame.h"
 #include "media/base/video_util.h"
@@ -113,6 +114,11 @@
     }
   }
 
+  if (opts.latency_mode == VideoEncoder::LatencyMode::Realtime) {
+    config.drop_frame_thresh_percentage =
+        GetDefaultVideoEncoderDropFrameThreshold();
+  }
+
   size_t num_temporal_layers = 1;
   if (opts.scalability_mode) {
     switch (opts.scalability_mode.value()) {
@@ -915,11 +921,8 @@
     }
   }
   DCHECK(erased_active_encode);
-  if (result.size > 0) {
-    // Size = 0 means that frame was dropped by the platform encoder, we don't
-    // need to call the output callback in such cases.
-    output_cb_.Run(std::move(result), std::move(desc));
-  }
+  output_cb_.Run(std::move(result), std::move(desc));
+
   if (active_encodes_.empty() && !flush_support_.value()) {
     // Manually call FlushCompleted(), since |accelerator_| won't do it for us.
     FlushCompleted(true);
diff --git a/media/video/video_encode_accelerator_adapter_test.cc b/media/video/video_encode_accelerator_adapter_test.cc
index f07ae2d..cce6ea2 100644
--- a/media/video/video_encode_accelerator_adapter_test.cc
+++ b/media/video/video_encode_accelerator_adapter_test.cc
@@ -601,11 +601,16 @@
   options.frame_size = gfx::Size(640, 480);
   auto pixel_format = PIXEL_FORMAT_I420;
   std::vector<base::TimeDelta> output_timestamps;
+  std::vector<base::TimeDelta> dropped_output_timestamps;
   const gfx::ColorSpace expected_color_space =
       ExpectedColorSpace(pixel_format, pixel_format);
   VideoEncoder::OutputCB output_cb = base::BindLambdaForTesting(
       [&](VideoEncoderOutput output,
           std::optional<VideoEncoder::CodecDescription>) {
+        if (output.size == 0) {
+          dropped_output_timestamps.push_back(output.timestamp);
+          return;
+        }
         EXPECT_EQ(output.color_space, expected_color_space);
         output_timestamps.push_back(output.timestamp);
       });
@@ -634,6 +639,8 @@
   ASSERT_EQ(output_timestamps.size(), 2u);
   EXPECT_EQ(output_timestamps[0], base::Milliseconds(1));
   EXPECT_EQ(output_timestamps[1], base::Milliseconds(3));
+  ASSERT_EQ(dropped_output_timestamps.size(), 1u);
+  EXPECT_EQ(dropped_output_timestamps[0], base::Milliseconds(2));
 }
 
 TEST_F(VideoEncodeAcceleratorAdapterTest,
diff --git a/media/video/vpx_video_encoder.cc b/media/video/vpx_video_encoder.cc
index 666948d..899deb5eaa 100644
--- a/media/video/vpx_video_encoder.cc
+++ b/media/video/vpx_video_encoder.cc
@@ -12,6 +12,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
+#include "media/base/media_switches.h"
 #include "media/base/svc_scalability_mode.h"
 #include "media/base/timestamp_constants.h"
 #include "media/base/video_codecs.h"
@@ -88,7 +89,11 @@
     config->rc_min_quantizer = 12;
   }
   config->rc_resize_allowed = 0;
-  config->rc_dropframe_thresh = 0;  // Don't drop frames
+  // Only if latency_mode is real time, a frame might be dropped.
+  config->rc_dropframe_thresh =
+      opts.latency_mode == VideoEncoder::LatencyMode::Realtime
+          ? GetDefaultVideoEncoderDropFrameThreshold()
+          : 0;
   config->g_timebase.num = 1;
   config->g_timebase.den = base::Time::kMicrosecondsPerSecond;
 
@@ -491,8 +496,18 @@
                         VP9E_CONTENT_SCREEN);
     } else {
       static_thresh = 100;
-      // TODO(b/280363228): Set 2 when the latency mode is realtime.
-      vpx_codec_control(codec.get(), VP8E_SET_SCREEN_CONTENT_MODE, 1 /*On*/);
+      // Tune configs for screen sharing. The values are the same as WebRTC
+      // https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc
+      // 0: camera (default)
+      // 1: screen
+      // 2: screen with allowing drop frame.
+      unsigned int screen_content_mode = 1;
+      if (options.latency_mode == LatencyMode::Realtime &&
+          base::FeatureList::IsEnabled(kWebCodecsVideoEncoderFrameDrop)) {
+        screen_content_mode = 2;
+      }
+      vpx_codec_control(codec.get(), VP8E_SET_SCREEN_CONTENT_MODE,
+                        screen_content_mode);
     }
   }
   vpx_codec_control(codec.get(), VP8E_SET_STATIC_THRESHOLD, static_thresh);
@@ -670,8 +685,6 @@
     unsigned int index_in_temp_cycle =
         temporal_svc_frame_index_ % codec_config_.ts_periodicity;
     temporal_id = codec_config_.ts_layer_id[index_in_temp_cycle];
-    temporal_svc_frame_index_++;
-
     if (profile_ == VP8PROFILE_ANY) {
       auto* vp8_layers_flags = codec_config_.ts_number_layers == 2
                                    ? vp8_2layers_temporal_flags
@@ -815,24 +828,27 @@
     std::move(done_cb).Run(std::move(status));
     return;
   }
-  DrainOutputs(0, base::TimeDelta(), gfx::ColorSpace());
+  DrainOutputs(0, std::nullopt, gfx::ColorSpace());
   std::move(done_cb).Run(EncoderStatus::Codes::kOk);
 }
 
 void VpxVideoEncoder::DrainOutputs(int temporal_id,
-                                   base::TimeDelta ts,
+                                   std::optional<base::TimeDelta> ts,
                                    gfx::ColorSpace color_space) {
+  const bool flush = !ts.has_value();
+  bool dropped_frame = true;
   vpx_codec_iter_t iter = nullptr;
   const vpx_codec_cx_pkt_t* pkt = nullptr;
   while ((pkt = vpx_codec_get_cx_data(codec_.get(), &iter))) {
     if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
+      dropped_frame = false;
       VideoEncoderOutput result;
       result.key_frame = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
 
       if (result.key_frame) {
-        // If we got an unexpected key frame, temporal_svc_frame_index needs to
-        // be adjusted, because the next frame should have index 1.
-        temporal_svc_frame_index_ = 1;
+        // If we got an unexpected key frame, |temporal_svc_frame_index_| needs
+        // to be adjusted, because the next frame should have index 1.
+        temporal_svc_frame_index_ = 0;
         result.temporal_id = 0;
       } else {
         result.temporal_id = temporal_id;
@@ -840,7 +856,7 @@
 
       // We don't given timestamps to vpx_codec_encode() that's why
       // pkt->data.frame.pts can't be used here.
-      result.timestamp = ts;
+      result.timestamp = *ts;
       result.color_space = color_space;
       result.size = pkt->data.frame.sz;
       result.data = std::make_unique<uint8_t[]>(result.size);
@@ -848,6 +864,21 @@
       output_cb_.Run(std::move(result), {});
     }
   }
+
+  if (flush) {
+    return;
+  }
+
+  if (dropped_frame) {
+    VideoEncoderOutput result;
+    result.timestamp = *ts;
+    output_cb_.Run(std::move(result), {});
+    return;
+  }
+
+  if (codec_config_.ts_number_layers > 1) {
+    temporal_svc_frame_index_++;
+  }
 }
 
 void VpxVideoEncoder::RecreateVpxImageIfNeeded(vpx_img_fmt fmt,
diff --git a/media/video/vpx_video_encoder.h b/media/video/vpx_video_encoder.h
index 7a98a62..b5e437d 100644
--- a/media/video/vpx_video_encoder.h
+++ b/media/video/vpx_video_encoder.h
@@ -6,6 +6,7 @@
 #define MEDIA_VIDEO_VPX_VIDEO_ENCODER_H_
 
 #include <memory>
+#include <optional>
 #include <vector>
 
 #include "base/time/time.h"
@@ -41,7 +42,7 @@
  private:
   base::TimeDelta GetFrameDuration(const VideoFrame& frame);
   void DrainOutputs(int temporal_id,
-                    base::TimeDelta ts,
+                    std::optional<base::TimeDelta> ts,
                     gfx::ColorSpace color_space);
   void RecreateVpxImageIfNeeded(vpx_img_fmt fmt, bool needs_memory);
   void UpdateEncoderColorSpace();
diff --git a/net/extras/shared_dictionary/shared_dictionary_info.cc b/net/extras/shared_dictionary/shared_dictionary_info.cc
index 73d9121..d1ee5b77 100644
--- a/net/extras/shared_dictionary/shared_dictionary_info.cc
+++ b/net/extras/shared_dictionary/shared_dictionary_info.cc
@@ -11,6 +11,8 @@
     base::Time response_time,
     base::TimeDelta expiration,
     const std::string& match,
+    const std::string& match_dest_string,
+    const std::string& id,
     base::Time last_used_time,
     size_t size,
     const net::SHA256HashValue& hash,
@@ -20,6 +22,8 @@
       response_time_(response_time),
       expiration_(expiration),
       match_(match),
+      match_dest_string_(match_dest_string),
+      id_(id),
       last_used_time_(last_used_time),
       size_(size),
       hash_(hash),
diff --git a/net/extras/shared_dictionary/shared_dictionary_info.h b/net/extras/shared_dictionary/shared_dictionary_info.h
index 497bd07..91dad3b 100644
--- a/net/extras/shared_dictionary/shared_dictionary_info.h
+++ b/net/extras/shared_dictionary/shared_dictionary_info.h
@@ -24,6 +24,8 @@
                        base::Time response_time,
                        base::TimeDelta expiration,
                        const std::string& match,
+                       const std::string& match_dest_string,
+                       const std::string& id,
                        base::Time last_used_time,
                        size_t size,
                        const net::SHA256HashValue& hash,
@@ -44,6 +46,8 @@
   base::Time response_time() const { return response_time_; }
   base::TimeDelta expiration() const { return expiration_; }
   const std::string& match() const { return match_; }
+  const std::string& match_dest_string() const { return match_dest_string_; }
+  const std::string& id() const { return id_; }
   base::Time last_used_time() const { return last_used_time_; }
   size_t size() const { return size_; }
   const net::SHA256HashValue& hash() const { return hash_; }
@@ -76,6 +80,12 @@
   // The matching path pattern for the dictionary which was declared in
   // 'use-as-dictionary' response header's `match` option.
   std::string match_;
+  // The comma separated matching destinations for the dictionary which was
+  // declared in 'use-as-dictionary' response header's `match-dest` option.
+  std::string match_dest_string_;
+  // The Id for the dictionary which was declared in 'use-as-dictionary'
+  // response header's `id` option.
+  std::string id_;
   // The time when the dictionary was last used.
   base::Time last_used_time_;
   // The size of the dictionary binary.
diff --git a/net/extras/sqlite/sqlite_persistent_shared_dictionary_store.cc b/net/extras/sqlite/sqlite_persistent_shared_dictionary_store.cc
index 1e14dbd..376a00e 100644
--- a/net/extras/sqlite/sqlite_persistent_shared_dictionary_store.cc
+++ b/net/extras/sqlite/sqlite_persistent_shared_dictionary_store.cc
@@ -805,10 +805,14 @@
       LOG(WARNING) << "Invalid token";
       continue;
     }
-    result.emplace_back(GURL(url_string), response_time,
-                        expiration_time - response_time, match, last_used_time,
-                        size, *sha256_hash, *disk_cache_key_token,
-                        primary_key_in_database);
+    // TODO(crbug.com/1413922): Store `match_dest_string` and `id` in the
+    // database.
+    std::string match_dest_string;
+    std::string id;
+    result.emplace_back(
+        GURL(url_string), response_time, expiration_time - response_time, match,
+        match_dest_string, id, last_used_time, size, *sha256_hash,
+        *disk_cache_key_token, primary_key_in_database);
   }
   return base::ok(std::move(result));
 }
@@ -875,11 +879,15 @@
     url::Origin frame_origin = url::Origin::Create(GURL(frame_origin_string));
     SchemefulSite top_frame_site = SchemefulSite(GURL(top_frame_site_string));
 
+    // TODO(crbug.com/1413922): Store `match_dest_string` and `id` in the
+    // database.
+    std::string match_dest_string;
+    std::string id;
     result[SharedDictionaryIsolationKey(frame_origin, top_frame_site)]
         .emplace_back(GURL(url_string), response_time,
-                      expiration_time - response_time, match, last_used_time,
-                      size, *sha256_hash, *disk_cache_key_token,
-                      primary_key_in_database);
+                      expiration_time - response_time, match, match_dest_string,
+                      id, last_used_time, size, *sha256_hash,
+                      *disk_cache_key_token, primary_key_in_database);
   }
   return base::ok(std::move(result));
 }
diff --git a/net/extras/sqlite/sqlite_persistent_shared_dictionary_store_unittest.cc b/net/extras/sqlite/sqlite_persistent_shared_dictionary_store_unittest.cc
index 72befec..61cc32e 100644
--- a/net/extras/sqlite/sqlite_persistent_shared_dictionary_store_unittest.cc
+++ b/net/extras/sqlite/sqlite_persistent_shared_dictionary_store_unittest.cc
@@ -84,6 +84,7 @@
       SharedDictionaryInfo(GURL("https://a.example/dict"),
                            /*response_time=*/now,
                            /*expiration*/ base::Seconds(100), "/pattern*",
+                           /*match_dest_string=*/"", /*id=*/"",
                            /*last_used_time*/ now,
                            /*size=*/1000, SHA256HashValue({{0x00, 0x01}}),
                            /*disk_cache_key_token=*/token1,
@@ -96,6 +97,7 @@
       SharedDictionaryInfo(GURL("https://b.example/dict"),
                            /*response_time=*/now,
                            /*expiration*/ base::Seconds(100), "/pattern*",
+                           /*match_dest_string=*/"", /*id=*/"",
                            /*last_used_time*/ now + base::Seconds(1),
                            /*size=*/3000, SHA256HashValue({{0x00, 0x02}}),
                            /*disk_cache_key_token=*/token2,
@@ -108,6 +110,7 @@
       SharedDictionaryInfo(GURL("https://c.example/dict"),
                            /*response_time=*/now,
                            /*expiration*/ base::Seconds(100), "/pattern*",
+                           /*match_dest_string=*/"", /*id=*/"",
                            /*last_used_time*/ now + base::Seconds(2),
                            /*size=*/5000, SHA256HashValue({{0x00, 0x03}}),
                            /*disk_cache_key_token=*/token3,
@@ -120,6 +123,7 @@
       SharedDictionaryInfo(GURL("https://d.example/dict"),
                            /*response_time=*/now,
                            /*expiration*/ base::Seconds(100), "/pattern*",
+                           /*match_dest_string=*/"", /*id=*/"",
                            /*last_used_time*/ now + base::Seconds(3),
                            /*size=*/7000, SHA256HashValue({{0x00, 0x04}}),
                            /*disk_cache_key_token=*/token4,
@@ -133,8 +137,9 @@
 
   SharedDictionaryInfo updated_dict2 = SharedDictionaryInfo(
       dict2.url(), dict2.response_time(), dict2.expiration(), dict2.match(),
-      now + base::Seconds(4), dict2.size(), dict2.hash(),
-      dict2.disk_cache_key_token(), dict2.primary_key_in_database());
+      dict2.match_dest_string(), dict2.id(), now + base::Seconds(4),
+      dict2.size(), dict2.hash(), dict2.disk_cache_key_token(),
+      dict2.primary_key_in_database());
 
   return {dict1, updated_dict2, dict3, dict4};
 }
@@ -161,6 +166,8 @@
             /*response_time=*/base::Time::Now() - base::Seconds(10),
             /*expiration*/ base::Seconds(100),
             "/pattern*",
+            /*match_dest_string=*/"",
+            /*id=*/"",
             /*last_used_time*/ base::Time::Now(),
             /*size=*/1000,
             SHA256HashValue({{0x00, 0x01}}),
@@ -670,6 +677,7 @@
           GURL("https://origin1.test/dict"),
           /*response_time=*/base::Time::Now() - base::Seconds(10),
           /*expiration*/ base::Seconds(100), "/pattern1*",
+          /*match_dest_string=*/"", /*id=*/"",
           /*last_used_time*/ base::Time::Now(),
           /*size=*/1000, SHA256HashValue({{0x00, 0x01}}),
           /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -679,6 +687,7 @@
           GURL("https://origin2.test/dict"),
           /*response_time=*/base::Time::Now() - base::Seconds(20),
           /*expiration*/ base::Seconds(200), "/pattern2*",
+          /*match_dest_string=*/"", /*id=*/"",
           /*last_used_time*/ base::Time::Now(),
           /*size=*/2000, SHA256HashValue({{0x00, 0x02}}),
           /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -694,6 +703,7 @@
           GURL("https://origin.test/dict"),
           /*response_time=*/base::Time::Now() - base::Seconds(10),
           /*expiration*/ base::Seconds(100), "/pattern1*",
+          /*match_dest_string=*/"", /*id=*/"",
           /*last_used_time*/ base::Time::Now(),
           /*size=*/1000, SHA256HashValue({{0x00, 0x01}}),
           /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -703,6 +713,7 @@
           GURL("https://origin.test/dict"),
           /*response_time=*/base::Time::Now() - base::Seconds(20),
           /*expiration*/ base::Seconds(200), "/pattern2*",
+          /*match_dest_string=*/"", /*id=*/"",
           /*last_used_time*/ base::Time::Now(),
           /*size=*/2000, SHA256HashValue({{0x00, 0x02}}),
           /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -718,6 +729,7 @@
           GURL("https://origin.test/dict"),
           /*response_time=*/base::Time::Now() - base::Seconds(10),
           /*expiration*/ base::Seconds(100), "/pattern*",
+          /*match_dest_string=*/"", /*id=*/"",
           /*last_used_time*/ base::Time::Now(),
           /*size=*/1000, SHA256HashValue({{0x00, 0x01}}),
           /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -727,6 +739,7 @@
           GURL("https://origin.test/dict"),
           /*response_time=*/base::Time::Now() - base::Seconds(20),
           /*expiration*/ base::Seconds(200), "/pattern*",
+          /*match_dest_string=*/"", /*id=*/"",
           /*last_used_time*/ base::Time::Now(),
           /*size=*/2000, SHA256HashValue({{0x00, 0x02}}),
           /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -847,7 +860,8 @@
   SharedDictionaryInfo dictionary_info(
       dictionary_info_.url(),
       /*response_time*/ base::Time::Now(), dictionary_info_.expiration(),
-      dictionary_info_.match(),
+      dictionary_info_.match(), dictionary_info_.match_dest_string(),
+      dictionary_info_.id(),
       /*last_used_time*/ base::Time::Now(), dictionary_info_.size() + 1,
       SHA256HashValue({{0x00, 0x02}}),
       /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -889,6 +903,7 @@
           GURL("https://a.example/dict"),
           /*response_time=*/base::Time::Now(),
           /*expiration*/ base::Seconds(100), "/pattern*",
+          /*match_dest_string=*/"", /*id=*/"",
           /*last_used_time*/ base::Time::Now(),
           /*size=*/max_size_per_site + 1, SHA256HashValue({{0x00, 0x01}}),
           /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -920,7 +935,8 @@
   auto dict1 = SharedDictionaryInfo(
       GURL("https://a.example/dict"),
       /*response_time=*/base::Time::Now(),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/max_size_per_site, SHA256HashValue({{0x00, 0x01}}),
       /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -939,7 +955,8 @@
   auto dict2 = SharedDictionaryInfo(
       GURL("https://b.example/dict"),
       /*response_time=*/base::Time::Now(),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/max_size_per_site / 2, SHA256HashValue({{0x00, 0x02}}),
       /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -957,7 +974,8 @@
   auto dict3 = SharedDictionaryInfo(
       GURL("https://c.example/dict"),
       /*response_time=*/base::Time::Now(),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/max_size_per_site / 2, SHA256HashValue({{0x00, 0x03}}),
       /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -980,7 +998,8 @@
   auto dict4 = SharedDictionaryInfo(
       GURL("https://d.example/dict"),
       /*response_time=*/base::Time::Now(),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/1, SHA256HashValue({{0x00, 0x04}}),
       /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -1012,7 +1031,8 @@
   auto dict1 = SharedDictionaryInfo(
       GURL("https://a.example/dict"),
       /*response_time=*/base::Time::Now(),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/100, SHA256HashValue({{0x00, 0x01}}),
       /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -1031,7 +1051,8 @@
   auto dict2 = SharedDictionaryInfo(
       GURL("https://b.example/dict"),
       /*response_time=*/base::Time::Now(),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/200, SHA256HashValue({{0x00, 0x02}}),
       /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -1049,7 +1070,8 @@
   auto dict3 = SharedDictionaryInfo(
       GURL("https://c.example/dict"),
       /*response_time=*/base::Time::Now(),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/400, SHA256HashValue({{0x00, 0x03}}),
       /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -1072,7 +1094,8 @@
   auto dict4 = SharedDictionaryInfo(
       GURL("https://d.example/dict"),
       /*response_time=*/base::Time::Now(),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/800, SHA256HashValue({{0x00, 0x04}}),
       /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -1105,7 +1128,8 @@
   auto dict1 = SharedDictionaryInfo(
       GURL("https://a.example/dict"),
       /*response_time=*/base::Time::Now(),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/100, SHA256HashValue({{0x00, 0x01}}),
       /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -1124,7 +1148,8 @@
   auto dict2 = SharedDictionaryInfo(
       GURL("https://b.example/dict"),
       /*response_time=*/base::Time::Now(),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/200, SHA256HashValue({{0x00, 0x02}}),
       /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -1142,7 +1167,8 @@
   auto dict3 = SharedDictionaryInfo(
       GURL("https://c.example/dict"),
       /*response_time=*/base::Time::Now(),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/400, SHA256HashValue({{0x00, 0x03}}),
       /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -1165,7 +1191,8 @@
   auto dict4 = SharedDictionaryInfo(
       GURL("https://d.example/dict"),
       /*response_time=*/base::Time::Now(),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/800, SHA256HashValue({{0x00, 0x04}}),
       /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -1197,7 +1224,8 @@
   auto dict1 = SharedDictionaryInfo(
       GURL("https://a.example/dict"),
       /*response_time=*/base::Time::Now(),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/100, SHA256HashValue({{0x00, 0x01}}),
       /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -1216,7 +1244,8 @@
   auto dict2 = SharedDictionaryInfo(
       GURL("https://b.example/dict"),
       /*response_time=*/base::Time::Now(),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/200, SHA256HashValue({{0x00, 0x02}}),
       /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -1234,7 +1263,8 @@
   auto dict3 = SharedDictionaryInfo(
       GURL("https://c.example/dict"),
       /*response_time=*/base::Time::Now(),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/400, SHA256HashValue({{0x00, 0x03}}),
       /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -1257,7 +1287,8 @@
   auto dict4 = SharedDictionaryInfo(
       GURL("https://d.example/dict"),
       /*response_time=*/base::Time::Now(),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/800, SHA256HashValue({{0x00, 0x04}}),
       /*disk_cache_key_token=*/base::UnguessableToken::Create(),
@@ -1923,7 +1954,8 @@
   SharedDictionaryInfo dict1 = SharedDictionaryInfo(
       GURL("https://a.example/dict"),
       /*response_time=*/base::Time::Now() - base::Seconds(4),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/1000, SHA256HashValue({{0x00, 0x01}}),
       /*disk_cache_key_token=*/token1,
@@ -1935,7 +1967,8 @@
   SharedDictionaryInfo dict2 = SharedDictionaryInfo(
       GURL("https://b.example/dict"),
       /*response_time=*/base::Time::Now() - base::Seconds(3),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/3000, SHA256HashValue({{0x00, 0x02}}),
       /*disk_cache_key_token=*/token2,
@@ -1947,7 +1980,8 @@
   SharedDictionaryInfo dict3 = SharedDictionaryInfo(
       GURL("https://c.example/dict"),
       /*response_time=*/base::Time::Now() - base::Seconds(2),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/5000, SHA256HashValue({{0x00, 0x03}}),
       /*disk_cache_key_token=*/token3,
@@ -1959,7 +1993,8 @@
   SharedDictionaryInfo dict4 = SharedDictionaryInfo(
       GURL("https://d.example/dict"),
       /*response_time=*/base::Time::Now() - base::Seconds(1),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/7000, SHA256HashValue({{0x00, 0x04}}),
       /*disk_cache_key_token=*/token4,
@@ -1999,7 +2034,8 @@
   SharedDictionaryInfo dict1 = SharedDictionaryInfo(
       GURL("https://a3.example/dict"),
       /*response_time=*/base::Time::Now() - base::Seconds(4),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/1000, SHA256HashValue({{0x00, 0x01}}),
       /*disk_cache_key_token=*/token1,
@@ -2013,7 +2049,8 @@
   SharedDictionaryInfo dict2 = SharedDictionaryInfo(
       GURL("https://b3.example/dict"),
       /*response_time=*/base::Time::Now() - base::Seconds(3),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/3000, SHA256HashValue({{0x00, 0x02}}),
       /*disk_cache_key_token=*/token2,
@@ -2027,7 +2064,8 @@
   SharedDictionaryInfo dict3 = SharedDictionaryInfo(
       GURL("https://c3.example/dict"),
       /*response_time=*/base::Time::Now() - base::Seconds(2),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/5000, SHA256HashValue({{0x00, 0x03}}),
       /*disk_cache_key_token=*/token3,
@@ -2041,7 +2079,8 @@
   SharedDictionaryInfo dict4 = SharedDictionaryInfo(
       GURL("https://d3.example/dict"),
       /*response_time=*/base::Time::Now() - base::Seconds(1),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/7000, SHA256HashValue({{0x00, 0x04}}),
       /*disk_cache_key_token=*/token4,
@@ -2112,6 +2151,7 @@
       SharedDictionaryInfo(GURL("https://a1.example/dict"),
                            /*response_time=*/base::Time::Now(),
                            /*expiration*/ base::Seconds(100), "/pattern*",
+                           /*match_dest_string=*/"", /*id=*/"",
                            /*last_used_time*/ base::Time::Now(),
                            /*size=*/1000, SHA256HashValue({{0x00, 0x01}}),
                            /*disk_cache_key_token=*/token1,
@@ -2127,6 +2167,7 @@
       SharedDictionaryInfo(GURL("https://a2.example/dict"),
                            /*response_time=*/base::Time::Now(),
                            /*expiration*/ base::Seconds(100), "/pattern*",
+                           /*match_dest_string=*/"", /*id=*/"",
                            /*last_used_time*/ base::Time::Now(),
                            /*size=*/2000, SHA256HashValue({{0x00, 0x02}}),
                            /*disk_cache_key_token=*/token2,
@@ -2142,6 +2183,7 @@
       SharedDictionaryInfo(GURL("https://a3.example/dict"),
                            /*response_time=*/base::Time::Now(),
                            /*expiration*/ base::Seconds(100), "/pattern*",
+                           /*match_dest_string=*/"", /*id=*/"",
                            /*last_used_time*/ base::Time::Now(),
                            /*size=*/4000, SHA256HashValue({{0x00, 0x03}}),
                            /*disk_cache_key_token=*/token3,
@@ -2157,6 +2199,7 @@
       SharedDictionaryInfo(GURL("https://a4.example/dict"),
                            /*response_time=*/base::Time::Now(),
                            /*expiration*/ base::Seconds(100), "/pattern*",
+                           /*match_dest_string=*/"", /*id=*/"",
                            /*last_used_time*/ base::Time::Now(),
                            /*size=*/8000, SHA256HashValue({{0x00, 0x04}}),
                            /*disk_cache_key_token=*/token4,
@@ -2191,6 +2234,7 @@
       SharedDictionaryInfo(GURL("https://a1.example/dict1"),
                            /*response_time=*/base::Time::Now(),
                            /*expiration*/ base::Seconds(100), "/pattern1*",
+                           /*match_dest_string=*/"", /*id=*/"",
                            /*last_used_time*/ base::Time::Now(),
                            /*size=*/1000, SHA256HashValue({{0x00, 0x01}}),
                            /*disk_cache_key_token=*/token1_1,
@@ -2203,6 +2247,7 @@
       SharedDictionaryInfo(GURL("https://a1.example/dict1"),
                            /*response_time=*/base::Time::Now(),
                            /*expiration*/ base::Seconds(100), "/pattern2*",
+                           /*match_dest_string=*/"", /*id=*/"",
                            /*last_used_time*/ base::Time::Now(),
                            /*size=*/2000, SHA256HashValue({{0x00, 0x02}}),
                            /*disk_cache_key_token=*/token1_2,
@@ -2216,6 +2261,7 @@
       SharedDictionaryInfo(GURL("https://a2.example/dict"),
                            /*response_time=*/base::Time::Now(),
                            /*expiration*/ base::Seconds(100), "/pattern*",
+                           /*match_dest_string=*/"", /*id=*/"",
                            /*last_used_time*/ base::Time::Now(),
                            /*size=*/4000, SHA256HashValue({{0x00, 0x03}}),
                            /*disk_cache_key_token=*/token2,
@@ -2243,6 +2289,7 @@
       SharedDictionaryInfo(GURL("https://a.example/dict"),
                            /*response_time=*/now,
                            /*expiration*/ base::Seconds(100), "/pattern*",
+                           /*match_dest_string=*/"", /*id=*/"",
                            /*last_used_time*/ now,
                            /*size=*/1000, SHA256HashValue({{0x00, 0x01}}),
                            /*disk_cache_key_token=*/token1,
@@ -2255,6 +2302,7 @@
       SharedDictionaryInfo(GURL("https://b.example/dict"),
                            /*response_time=*/now + base::Seconds(1),
                            /*expiration*/ base::Seconds(99), "/pattern*",
+                           /*match_dest_string=*/"", /*id=*/"",
                            /*last_used_time*/ now,
                            /*size=*/3000, SHA256HashValue({{0x00, 0x02}}),
                            /*disk_cache_key_token=*/token2,
@@ -2267,6 +2315,7 @@
       SharedDictionaryInfo(GURL("https://c.example/dict"),
                            /*response_time=*/now + base::Seconds(1),
                            /*expiration*/ base::Seconds(100), "/pattern*",
+                           /*match_dest_string=*/"", /*id=*/"",
                            /*last_used_time*/ now,
                            /*size=*/5000, SHA256HashValue({{0x00, 0x03}}),
                            /*disk_cache_key_token=*/token3,
@@ -2279,6 +2328,7 @@
       SharedDictionaryInfo(GURL("https://d.example/dict"),
                            /*response_time=*/now + base::Seconds(2),
                            /*expiration*/ base::Seconds(99), "/pattern*",
+                           /*match_dest_string=*/"", /*id=*/"",
                            /*last_used_time*/ now,
                            /*size=*/7000, SHA256HashValue({{0x00, 0x04}}),
                            /*disk_cache_key_token=*/token4,
@@ -2466,6 +2516,7 @@
       SharedDictionaryInfo(GURL("https://a.example/dict"),
                            /*response_time=*/now,
                            /*expiration*/ base::Seconds(100), "/pattern*",
+                           /*match_dest_string=*/"", /*id=*/"",
                            /*last_used_time*/ now,
                            /*size=*/1000, SHA256HashValue({{0x00, 0x01}}),
                            /*disk_cache_key_token=*/token1,
@@ -2478,6 +2529,7 @@
       SharedDictionaryInfo(GURL("https://b.example/dict"),
                            /*response_time=*/now,
                            /*expiration*/ base::Seconds(100), "/pattern*",
+                           /*match_dest_string=*/"", /*id=*/"",
                            /*last_used_time*/ now + base::Seconds(1),
                            /*size=*/3000, SHA256HashValue({{0x00, 0x02}}),
                            /*disk_cache_key_token=*/token2,
@@ -2507,7 +2559,8 @@
   SharedDictionaryInfo dict1 = SharedDictionaryInfo(
       GURL("https://a.example/dict"),
       /*response_time=*/base::Time::Now() - base::Seconds(4),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/1000, SHA256HashValue({{0x00, 0x01}}),
       /*disk_cache_key_token=*/token1,
@@ -2520,7 +2573,8 @@
   SharedDictionaryInfo dict2 = SharedDictionaryInfo(
       GURL("https://b.example/dict"),
       /*response_time=*/base::Time::Now() - base::Seconds(3),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/3000, SHA256HashValue({{0x00, 0x02}}),
       /*disk_cache_key_token=*/token2,
@@ -2540,7 +2594,8 @@
   SharedDictionaryInfo dict1 = SharedDictionaryInfo(
       GURL("https://a.example/dict"),
       /*response_time=*/base::Time::Now() - base::Seconds(4),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/1000, SHA256HashValue({{0x00, 0x01}}),
       /*disk_cache_key_token=*/token1,
@@ -2554,7 +2609,8 @@
   SharedDictionaryInfo dict2 = SharedDictionaryInfo(
       GURL("https://b.example/dict"),
       /*response_time=*/base::Time::Now() - base::Seconds(3),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/3000, SHA256HashValue({{0x00, 0x02}}),
       /*disk_cache_key_token=*/token2,
@@ -2567,7 +2623,8 @@
   SharedDictionaryInfo dict3 = SharedDictionaryInfo(
       GURL("https://c.example/dict"),
       /*response_time=*/base::Time::Now() - base::Seconds(2),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/5000, SHA256HashValue({{0x00, 0x03}}),
       /*disk_cache_key_token=*/token3,
@@ -2579,7 +2636,8 @@
   SharedDictionaryInfo dict4 = SharedDictionaryInfo(
       GURL("https://d.example/dict"),
       /*response_time=*/base::Time::Now() - base::Seconds(1),
-      /*expiration*/ base::Seconds(100), "/pattern*",
+      /*expiration*/ base::Seconds(100), "/pattern*", /*match_dest_string=*/"",
+      /*id=*/"",
       /*last_used_time*/ base::Time::Now(),
       /*size=*/7000, SHA256HashValue({{0x00, 0x04}}),
       /*disk_cache_key_token=*/token4,
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index 36dc957..5fa5161 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -147,9 +147,6 @@
   // Enables QUIC support.
   bool enable_quic = true;
 
-  // If true, HTTPS URLs can be sent to QUIC proxies.
-  bool enable_quic_proxies_for_https_urls = false;
-
   // If non-empty, QUIC will only be spoken to hosts in this list.
   base::flat_set<std::string> quic_host_allowlist;
 
diff --git a/net/http/http_stream_factory_job.cc b/net/http/http_stream_factory_job.cc
index f269fd2f..15cad31 100644
--- a/net/http/http_stream_factory_job.cc
+++ b/net/http/http_stream_factory_job.cc
@@ -733,11 +733,6 @@
     return ERR_UNSAFE_PORT;
   }
 
-  if (!session_->params().enable_quic_proxies_for_https_urls &&
-      proxy_info_.is_quic() && request_info_.url.SchemeIsCryptographic()) {
-    return ERR_NOT_IMPLEMENTED;
-  }
-
   next_state_ = STATE_WAIT;
   return OK;
 }
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index d1cca834..01eb1da 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -6329,7 +6329,6 @@
 TEST_P(QuicNetworkTransactionTest, QuicProxyConnectHttpsServer) {
   DisablePriorityHeader();
   session_params_.enable_quic = true;
-  session_params_.enable_quic_proxies_for_https_urls = true;
 
   const auto kQuicProxyChain =
       ProxyChain::ForIpProtection({ProxyServer::FromSchemeHostAndPort(
@@ -6423,7 +6422,6 @@
 TEST_P(QuicNetworkTransactionTest, QuicProxyConnectSpdyServer) {
   DisablePriorityHeader();
   session_params_.enable_quic = true;
-  session_params_.enable_quic_proxies_for_https_urls = true;
 
   const auto kQuicProxyChain =
       ProxyChain::ForIpProtection({ProxyServer::FromSchemeHostAndPort(
@@ -6519,7 +6517,6 @@
 TEST_P(QuicNetworkTransactionTest, QuicProxyConnectReuseTransportSocket) {
   DisablePriorityHeader();
   session_params_.enable_quic = true;
-  session_params_.enable_quic_proxies_for_https_urls = true;
 
   const auto kQuicProxyChain =
       ProxyChain::ForIpProtection({ProxyServer::FromSchemeHostAndPort(
@@ -6648,7 +6645,6 @@
 TEST_P(QuicNetworkTransactionTest, QuicProxyConnectReuseQuicSession) {
   DisablePriorityHeader();
   session_params_.enable_quic = true;
-  session_params_.enable_quic_proxies_for_https_urls = true;
 
   const auto kQuicProxyChain =
       ProxyChain::ForIpProtection({ProxyServer::FromSchemeHostAndPort(
@@ -6807,7 +6803,6 @@
 TEST_P(QuicNetworkTransactionTest, QuicProxyConnectNoReuseDifferentChains) {
   DisablePriorityHeader();
   session_params_.enable_quic = true;
-  session_params_.enable_quic_proxies_for_https_urls = true;
 
   const ProxyServer kQuicProxyServer{ProxyServer::SCHEME_QUIC,
                                      HostPortPair("proxy.example.org", 443)};
@@ -6967,7 +6962,6 @@
 TEST_P(QuicNetworkTransactionTest, QuicProxyConnectFailure) {
   DisablePriorityHeader();
   session_params_.enable_quic = true;
-  session_params_.enable_quic_proxies_for_https_urls = true;
   proxy_resolution_service_ =
       ConfiguredProxyResolutionService::CreateFixedFromProxyChainsForTest(
           {ProxyChain::ForIpProtection({ProxyServer::FromSchemeHostAndPort(
@@ -7022,7 +7016,6 @@
 TEST_P(QuicNetworkTransactionTest, QuicProxyQuicConnectionError) {
   DisablePriorityHeader();
   session_params_.enable_quic = true;
-  session_params_.enable_quic_proxies_for_https_urls = true;
   proxy_resolution_service_ =
       ConfiguredProxyResolutionService::CreateFixedFromProxyChainsForTest(
           {ProxyChain::ForIpProtection({ProxyServer::FromSchemeHostAndPort(
@@ -7066,7 +7059,6 @@
 TEST_P(QuicNetworkTransactionTest, QuicProxyConnectBadCertificate) {
   DisablePriorityHeader();
   session_params_.enable_quic = true;
-  session_params_.enable_quic_proxies_for_https_urls = true;
 
   const auto kQuicProxyChain =
       ProxyChain::ForIpProtection({ProxyServer::FromSchemeHostAndPort(
@@ -7202,7 +7194,6 @@
   const char kConfiguredUserAgent[] = "Configured User-Agent";
   const char kRequestUserAgent[] = "Request User-Agent";
   session_params_.enable_quic = true;
-  session_params_.enable_quic_proxies_for_https_urls = true;
   proxy_resolution_service_ =
       ConfiguredProxyResolutionService::CreateFixedFromProxyChainsForTest(
           {ProxyChain::ForIpProtection({ProxyServer::FromSchemeHostAndPort(
@@ -7256,7 +7247,6 @@
 TEST_P(QuicNetworkTransactionTest, QuicProxyRequestPriority) {
   DisablePriorityHeader();
   session_params_.enable_quic = true;
-  session_params_.enable_quic_proxies_for_https_urls = true;
   proxy_resolution_service_ =
       ConfiguredProxyResolutionService::CreateFixedFromProxyChainsForTest(
           {ProxyChain::ForIpProtection({ProxyServer::FromSchemeHostAndPort(
@@ -7303,7 +7293,6 @@
 // HTTP/2 stream dependency and weights given the request priority.
 TEST_P(QuicNetworkTransactionTest, QuicProxyMultipleRequestsError) {
   session_params_.enable_quic = true;
-  session_params_.enable_quic_proxies_for_https_urls = true;
   proxy_resolution_service_ =
       ConfiguredProxyResolutionService::CreateFixedFromProxyChainsForTest(
           {ProxyChain::ForIpProtection({ProxyServer::FromSchemeHostAndPort(
@@ -7388,7 +7377,6 @@
         false);
 
     session_params_.enable_quic = true;
-    session_params_.enable_quic_proxies_for_https_urls = true;
     proxy_resolution_service_ =
         ConfiguredProxyResolutionService::CreateFixedFromProxyChainsForTest(
             {ProxyChain::ForIpProtection({ProxyServer::FromSchemeHostAndPort(
@@ -7825,7 +7813,6 @@
       features::kPartitionConnectionsByNetworkIsolationKey);
 
   session_params_.enable_quic = true;
-  session_params_.enable_quic_proxies_for_https_urls = true;
   proxy_resolution_service_ =
       ConfiguredProxyResolutionService::CreateFixedFromProxyChainsForTest(
           {ProxyChain::ForIpProtection({ProxyServer::FromSchemeHostAndPort(
diff --git a/sandbox/win/src/app_container_test.cc b/sandbox/win/src/app_container_test.cc
index 82ec288c..fa2ef15 100644
--- a/sandbox/win/src/app_container_test.cc
+++ b/sandbox/win/src/app_container_test.cc
@@ -459,19 +459,20 @@
   EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(L"CheckIsAppContainer"));
 }
 
-// TODO(crbug.com/1523707): Windows 11 ARM64 dbg seems to return 0xC0000005
-// (access violation) instead of SBOX_TEST_SECOND_ERROR.
-#if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_ARM64) && !defined(NDEBUG)
-#define MAYBE_ChildProcessMitigationLowBox DISABLED_ChildProcessMitigationLowBox
-#else
-#define MAYBE_ChildProcessMitigationLowBox ChildProcessMitigationLowBox
-#endif
-TEST_F(AppContainerTest, MAYBE_ChildProcessMitigationLowBox) {
+TEST_F(AppContainerTest, ChildProcessMitigationLowBox) {
   if (!features::IsAppContainerSandboxSupported()) {
     return;
   }
 
   TestRunner runner(JobLevel::kUnprotected, USER_UNPROTECTED, USER_UNPROTECTED);
+
+#if defined(ARCH_CPU_ARM64) && !defined(NDEBUG)
+  // TODO(crbug.com/1524390) A DPLOG issued when CreateProcess() fails conflicts
+  // with Csrss lockdown on Win11 ARM64 - so allow Csrss to allow the process to
+  // run the right exitcode and not an access violation crash.
+  runner.SetDisableCsrss(false);
+#endif  // defined(ARCH_CPU_ARM64) && !defined(NDEBUG)
+
   EXPECT_EQ(SBOX_ALL_OK,
             runner.GetPolicy()->GetConfig()->SetLowBox(kAppContainerSid));
 
diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc
index 039022a..c7610938 100644
--- a/services/network/cors/cors_url_loader.cc
+++ b/services/network/cors/cors_url_loader.cc
@@ -379,7 +379,7 @@
     // `HttpNetworkTransaction` builds the request header just before sending it
     // to the server.
     shared_dictionary_storage_->GetDictionary(
-        request_.url,
+        request_.url, request_.destination,
         base::BindOnce(
             [](base::WeakPtr<CorsURLLoader> loader,
                std::unique_ptr<SharedDictionary> shared_dictionary) {
diff --git a/services/network/cors/cors_url_loader_factory.cc b/services/network/cors/cors_url_loader_factory.cc
index 52d459e..625a517 100644
--- a/services/network/cors/cors_url_loader_factory.cc
+++ b/services/network/cors/cors_url_loader_factory.cc
@@ -415,11 +415,6 @@
       }
     }
 
-    mojo::PendingRemote<mojom::URLLoaderNetworkServiceObserver> observer_remote;
-    if (url_loader_network_service_observer_.is_bound()) {
-      url_loader_network_service_observer_->Clone(
-          observer_remote.InitWithNewPipeAndPassReceiver());
-    }
     auto loader = std::make_unique<CorsURLLoader>(
         std::move(receiver), process_id_, request_id, options,
         base::BindOnce(&CorsURLLoaderFactory::DestroyCorsURLLoader,
diff --git a/services/network/cors/cors_url_loader_shared_dictionary_unittest.cc b/services/network/cors/cors_url_loader_shared_dictionary_unittest.cc
index 4b4f094a..68f82ce 100644
--- a/services/network/cors/cors_url_loader_shared_dictionary_unittest.cc
+++ b/services/network/cors/cors_url_loader_shared_dictionary_unittest.cc
@@ -134,7 +134,8 @@
               dictionary_map.begin()->first);
 
     ASSERT_EQ(1u, dictionary_map.begin()->second.size());
-    EXPECT_EQ("/path*", dictionary_map.begin()->second.begin()->first);
+    EXPECT_EQ(std::make_tuple("/path*", std::set<mojom::RequestDestination>()),
+              dictionary_map.begin()->second.begin()->first);
     const auto& dictionary_info =
         dictionary_map.begin()->second.begin()->second;
     EXPECT_EQ(dictionary_url, dictionary_info.url());
@@ -151,7 +152,8 @@
 
   const std::map<
       url::SchemeHostPort,
-      std::map<std::string, SharedDictionaryStorageInMemory::DictionaryInfo>>&
+      std::map<std::tuple<std::string, std::set<mojom::RequestDestination>>,
+               SharedDictionaryStorageInMemory::DictionaryInfo>>&
   GetInMemoryDictionaryMap(SharedDictionaryStorage* storage) {
     return static_cast<SharedDictionaryStorageInMemory*>(storage)
         ->GetDictionaryMap();
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index 504594f..a7ceb66 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -24,6 +24,7 @@
 import "services/network/public/mojom/default_credentials.mojom";
 import "services/network/public/mojom/devtools_observer.mojom";
 import "services/network/public/mojom/restricted_udp_socket.mojom";
+import "services/network/public/mojom/fetch_api.mojom";
 import "services/network/public/mojom/first_party_sets_access_delegate.mojom";
 import "services/network/public/mojom/host_resolver.mojom";
 import "services/network/public/mojom/http_cache_backend_file_operations.mojom";
@@ -616,13 +617,25 @@
 };
 
 // Represents a shared dictionary.
+// Spec: https://datatracker.ietf.org/doc/draft-ietf-httpbis-compression-dictionary/
 struct SharedDictionaryInfo {
+  // The "match" value of the Use-As-Dictionary header.
   string match;
+  // The "match-dest" value of the Use-As-Dictionary header.
+  array<RequestDestination> match_dest;
+  // The "id" value of the Use-As-Dictionary header.
+  string id;
+  // The URL of the dictionary.
   url.mojom.Url dictionary_url;
+  // The time when Chrome received the dictionary.
   mojo_base.mojom.Time response_time;
+  // The time when this dictionary will be unusable.
   mojo_base.mojom.TimeDelta expiration;
+  // The time when this dictionary was used in the last time.
   mojo_base.mojom.Time last_used_time;
+  // The size of the dictionary binary.
   uint64 size;
+  // The SHA256 hash of the dictionary binary.
   SHA256HashValue hash;
 };
 
diff --git a/services/network/shared_dictionary/shared_dictionary_constants.cc b/services/network/shared_dictionary/shared_dictionary_constants.cc
index ea3d042..f374b50 100644
--- a/services/network/shared_dictionary/shared_dictionary_constants.cc
+++ b/services/network/shared_dictionary/shared_dictionary_constants.cc
@@ -24,8 +24,10 @@
 const char kContentDictionaryHeaderName[] = "content-dictionary";
 
 const char kOptionNameMatch[] = "match";
+const char kOptionNameMatchDest[] = "match-dest";
 const char kOptionNameExpires[] = "expires";
 const char kOptionNameType[] = "type";
+const char kOptionNameId[] = "id";
 
 size_t GetDictionarySizeLimit() {
   return g_dictionary_size_limit;
diff --git a/services/network/shared_dictionary/shared_dictionary_constants.h b/services/network/shared_dictionary/shared_dictionary_constants.h
index f96e2a7..1d893e2 100644
--- a/services/network/shared_dictionary/shared_dictionary_constants.h
+++ b/services/network/shared_dictionary/shared_dictionary_constants.h
@@ -55,6 +55,9 @@
 // The dictionary option name of "match".
 COMPONENT_EXPORT(NETWORK_SERVICE) extern const char kOptionNameMatch[];
 
+// The dictionary option name of "match-dest".
+COMPONENT_EXPORT(NETWORK_SERVICE) extern const char kOptionNameMatchDest[];
+
 // The dictionary option name of "expires".
 // This will not be used when V2 backend is enabled.
 COMPONENT_EXPORT(NETWORK_SERVICE) extern const char kOptionNameExpires[];
@@ -62,6 +65,11 @@
 // The dictionary option name of "type".
 COMPONENT_EXPORT(NETWORK_SERVICE) extern const char kOptionNameType[];
 
+// The dictionary option name of "id".
+COMPONENT_EXPORT(NETWORK_SERVICE) extern const char kOptionNameId[];
+// The max length of dictionary id.
+inline constexpr uint64_t kDictionaryIdMaxLength = 1024;
+
 }  // namespace network::shared_dictionary
 
 #endif  // SERVICES_NETWORK_SHARED_DICTIONARY_SHARED_DICTIONARY_CONSTANTS_H_
diff --git a/services/network/shared_dictionary/shared_dictionary_manager.h b/services/network/shared_dictionary/shared_dictionary_manager.h
index f65b59c3..2d9a700 100644
--- a/services/network/shared_dictionary/shared_dictionary_manager.h
+++ b/services/network/shared_dictionary/shared_dictionary_manager.h
@@ -137,6 +137,11 @@
     const DictionaryInfoType& info) {
   auto mojo_info = network::mojom::SharedDictionaryInfo::New();
   mojo_info->match = info.match();
+  for (const auto dest : info.match_dest()) {
+    mojo_info->match_dest.push_back(dest);
+  }
+  std::sort(mojo_info->match_dest.begin(), mojo_info->match_dest.end());
+  mojo_info->id = info.id();
   mojo_info->dictionary_url = info.url();
   mojo_info->response_time = info.response_time();
   mojo_info->expiration = info.expiration();
diff --git a/services/network/shared_dictionary/shared_dictionary_manager_in_memory.cc b/services/network/shared_dictionary/shared_dictionary_manager_in_memory.cc
index 6305f2f..c277486 100644
--- a/services/network/shared_dictionary/shared_dictionary_manager_in_memory.cc
+++ b/services/network/shared_dictionary/shared_dictionary_manager_in_memory.cc
@@ -51,8 +51,12 @@
  public:
   EvictionCandidate(raw_ptr<SharedDictionaryStorageInMemory> storage,
                     const url::SchemeHostPort& host,
-                    const std::string& match)
-      : storage_(storage), host_(host), match_(match) {}
+                    const std::string& match,
+                    const std::set<mojom::RequestDestination>& match_dest)
+      : storage_(storage),
+        host_(host),
+        match_(match),
+        match_dest_(match_dest) {}
 
   EvictionCandidate(const EvictionCandidate&) = default;
   EvictionCandidate& operator=(const EvictionCandidate&) = default;
@@ -63,11 +67,15 @@
   const url::SchemeHostPort& host() const { return host_; }
   raw_ptr<SharedDictionaryStorageInMemory> storage() const { return storage_; }
   const std::string& match() const { return match_; }
+  const std::set<mojom::RequestDestination> match_dest() const {
+    return match_dest_;
+  }
 
  private:
   raw_ptr<SharedDictionaryStorageInMemory> storage_;
   url::SchemeHostPort host_;
   std::string match_;
+  std::set<mojom::RequestDestination> match_dest_;
 };
 
 }  // namespace
@@ -189,7 +197,7 @@
     total_size -= dict_ref.dict()->size();
     eviction_candidates.emplace_back(
         dict_ref.storage(), url::SchemeHostPort(dict_ref.dict()->url()),
-        dict_ref.dict()->match());
+        dict_ref.dict()->match(), dict_ref.dict()->match_dest());
     if ((max_size == 0 || size_low_watermark >= total_size) &&
         eviction_candidates.size() >= to_be_removed_count) {
       break;
@@ -197,7 +205,8 @@
   }
   dictionaries.clear();  // Unneeded, and may ref. about-to-be-deleted things.
   for (auto& candidate : eviction_candidates) {
-    candidate.storage()->DeleteDictionary(candidate.host(), candidate.match());
+    candidate.storage()->DeleteDictionary(candidate.host(), candidate.match(),
+                                          candidate.match_dest());
   }
 }
 
diff --git a/services/network/shared_dictionary/shared_dictionary_manager_on_disk.cc b/services/network/shared_dictionary/shared_dictionary_manager_on_disk.cc
index 4e1a69c..1697014 100644
--- a/services/network/shared_dictionary/shared_dictionary_manager_on_disk.cc
+++ b/services/network/shared_dictionary/shared_dictionary_manager_on_disk.cc
@@ -15,7 +15,9 @@
 #include "base/unguessable_token.h"
 #include "net/base/net_errors.h"
 #include "net/disk_cache/disk_cache.h"
+#include "services/network/public/cpp/request_destination.h"
 #include "services/network/shared_dictionary/shared_dictionary_storage_on_disk.h"
+#include "services/network/shared_dictionary/simple_url_pattern_matcher.h"
 
 namespace network {
 namespace {
@@ -29,6 +31,17 @@
   return base::UnguessableToken::Deserialize(token->high(), token->low());
 }
 
+std::string ToCommaSeparatedString(
+    const std::set<mojom::RequestDestination>& match_dest) {
+  std::vector<std::string_view> destinations;
+  for (auto dest : match_dest) {
+    std::string_view result = RequestDestinationToString(
+        dest, EmptyRequestDestinationOption::kUseFiveCharEmptyString);
+    destinations.push_back(result);
+  }
+  return base::JoinString(destinations, ",");
+}
+
 }  // namespace
 
 class SharedDictionaryManagerOnDisk::ClearDataTask
@@ -535,7 +548,9 @@
               return;
             }
             for (auto& info : result.value()) {
-              dictionaries.push_back(ToMojoSharedDictionaryInfo(info));
+              dictionaries.push_back(ToMojoSharedDictionaryInfo(
+                  SharedDictionaryStorageOnDisk::WrappedDictionaryInfo(
+                      info, /*matcher=*/nullptr)));
             }
             std::move(callback).Run(std::move(dictionaries));
           },
@@ -565,6 +580,8 @@
     base::Time response_time,
     base::TimeDelta expiration,
     const std::string& match,
+    const std::set<mojom::RequestDestination>& match_dest,
+    const std::string& id,
     base::OnceCallback<void(net::SharedDictionaryInfo)> callback) {
   const base::UnguessableToken disk_cache_key_token =
       base::UnguessableToken::Create();
@@ -574,7 +591,8 @@
       base::BindOnce(
           &SharedDictionaryManagerOnDisk::OnDictionaryWrittenInDiskCache,
           weak_factory_.GetWeakPtr(), isolation_key, url, response_time,
-          expiration, match, disk_cache_key_token, std::move(callback)),
+          expiration, match, match_dest, id, disk_cache_key_token,
+          std::move(callback)),
       disk_cache_.GetWeakPtr());
   writer->Initialize();
   return writer;
@@ -586,6 +604,8 @@
     base::Time response_time,
     base::TimeDelta expiration,
     const std::string& match,
+    const std::set<mojom::RequestDestination>& match_dest,
+    const std::string& id,
     const base::UnguessableToken& disk_cache_key_token,
     base::OnceCallback<void(net::SharedDictionaryInfo)> callback,
     SharedDictionaryWriterOnDisk::Result result,
@@ -601,10 +621,10 @@
     return;
   }
   base::Time last_used_time = base::Time::Now();
-  net::SharedDictionaryInfo info(url, response_time, expiration, match,
-                                 last_used_time, size, hash,
-                                 disk_cache_key_token,
-                                 /*primary_key_in_database=*/std::nullopt);
+  net::SharedDictionaryInfo info(
+      url, response_time, expiration, match, ToCommaSeparatedString(match_dest),
+      id, last_used_time, size, hash, disk_cache_key_token,
+      /*primary_key_in_database=*/std::nullopt);
   metadata_store_.RegisterDictionary(
       isolation_key, info,
       /*max_size_per_site*/ cache_max_size_ / 2,
diff --git a/services/network/shared_dictionary/shared_dictionary_manager_on_disk.h b/services/network/shared_dictionary/shared_dictionary_manager_on_disk.h
index db7fbda..4e1d877 100644
--- a/services/network/shared_dictionary/shared_dictionary_manager_on_disk.h
+++ b/services/network/shared_dictionary/shared_dictionary_manager_on_disk.h
@@ -5,6 +5,8 @@
 #ifndef SERVICES_NETWORK_SHARED_DICTIONARY_SHARED_DICTIONARY_MANAGER_ON_DISK_H_
 #define SERVICES_NETWORK_SHARED_DICTIONARY_SHARED_DICTIONARY_MANAGER_ON_DISK_H_
 
+#include <optional>
+#include <set>
 #include <string>
 
 #include "base/functional/callback.h"
@@ -30,6 +32,9 @@
 }  // namespace disk_cache
 
 namespace network {
+namespace mojom {
+enum class RequestDestination : int32_t;
+}  // namespace mojom
 
 class SharedDictionaryStorage;
 
@@ -89,6 +94,8 @@
       base::Time response_time,
       base::TimeDelta expiration,
       const std::string& match,
+      const std::set<mojom::RequestDestination>& match_dest,
+      const std::string& id,
       base::OnceCallback<void(net::SharedDictionaryInfo)> callback);
 
   void UpdateDictionaryLastUsedTime(net::SharedDictionaryInfo& info);
@@ -132,6 +139,8 @@
       base::Time response_time,
       base::TimeDelta expiration,
       const std::string& match,
+      const std::set<mojom::RequestDestination>& match_dest,
+      const std::string& id,
       const base::UnguessableToken& disk_cache_key_token,
       base::OnceCallback<void(net::SharedDictionaryInfo)> callback,
       SharedDictionaryWriterOnDisk::Result result,
diff --git a/services/network/shared_dictionary/shared_dictionary_manager_on_disk_unittest.cc b/services/network/shared_dictionary/shared_dictionary_manager_on_disk_unittest.cc
index ff27841..1725412 100644
--- a/services/network/shared_dictionary/shared_dictionary_manager_on_disk_unittest.cc
+++ b/services/network/shared_dictionary/shared_dictionary_manager_on_disk_unittest.cc
@@ -199,8 +199,8 @@
   static base::UnguessableToken GetDiskCacheKeyTokenOfFirstDictionary(
       const std::map<
           url::SchemeHostPort,
-          std::map<std::string,
-                   SharedDictionaryStorageOnDisk::DictionaryInfoWithMatcher>>&
+          std::map<std::tuple<std::string, std::set<mojom::RequestDestination>>,
+                   SharedDictionaryStorageOnDisk::WrappedDictionaryInfo>>&
           dictionary_map,
       const std::string& scheme_host_port_str) {
     auto it =
@@ -223,8 +223,8 @@
   }
   const std::map<
       url::SchemeHostPort,
-      std::map<std::string,
-               SharedDictionaryStorageOnDisk::DictionaryInfoWithMatcher>>&
+      std::map<std::tuple<std::string, std::set<mojom::RequestDestination>>,
+               SharedDictionaryStorageOnDisk::WrappedDictionaryInfo>>&
   GetOnDiskDictionaryMap(SharedDictionaryStorage* storage) {
     return static_cast<SharedDictionaryStorageOnDisk*>(storage)
         ->GetDictionaryMapForTesting();
@@ -307,7 +307,8 @@
 
   // Check the returned dictionary from GetDictionarySync().
   std::unique_ptr<SharedDictionary> dict1 =
-      storage->GetDictionarySync(GURL("https://origin.test/testfile?1"));
+      storage->GetDictionarySync(GURL("https://origin.test/testfile?1"),
+                                 mojom::RequestDestination::kEmpty);
   ASSERT_TRUE(dict1);
   {
     base::RunLoop run_loop;
@@ -319,7 +320,8 @@
     run_loop.Run();
   }
   std::unique_ptr<SharedDictionary> dict2 =
-      storage->GetDictionarySync(GURL("https://origin.test/testfile?2"));
+      storage->GetDictionarySync(GURL("https://origin.test/testfile?2"),
+                                 mojom::RequestDestination::kEmpty);
   ASSERT_TRUE(dict2);
   // `dict2` shares the same RefCountedSharedDictionary with `dict1`. So
   // ReadAll() must synchronously return OK.
@@ -373,7 +375,8 @@
 
   // GetDictionarySync() must return nullptr, after `manager` was deleted.
   std::unique_ptr<SharedDictionary> dict =
-      storage->GetDictionarySync(GURL("https://origin.test/testfile?1"));
+      storage->GetDictionarySync(GURL("https://origin.test/testfile?1"),
+                                 mojom::RequestDestination::kEmpty);
   EXPECT_FALSE(dict);
 }
 
@@ -419,8 +422,8 @@
   }
 
   // Check the returned dictionary from GetDictionarySync().
-  std::unique_ptr<SharedDictionary> dict1 =
-      storage->GetDictionarySync(GURL("https://origin.test/testfile"));
+  std::unique_ptr<SharedDictionary> dict1 = storage->GetDictionarySync(
+      GURL("https://origin.test/testfile"), mojom::RequestDestination::kEmpty);
   ASSERT_TRUE(dict1);
 
   // The disk cache entry must exist.
@@ -446,8 +449,8 @@
   // The disk cache entry should have been doomed.
   EXPECT_FALSE(DiskCacheEntryExists(manager.get(), disk_cache_key_token1));
 
-  std::unique_ptr<SharedDictionary> dict2 =
-      storage->GetDictionarySync(GURL("https://origin.test/testfile"));
+  std::unique_ptr<SharedDictionary> dict2 = storage->GetDictionarySync(
+      GURL("https://origin.test/testfile"), mojom::RequestDestination::kEmpty);
   ASSERT_TRUE(dict2);
 
   // We can read the new dictionary from `dict2`.
@@ -488,11 +491,13 @@
     FlushCacheTasks();
 
     std::unique_ptr<SharedDictionary> dict1 =
-        storage->GetDictionarySync(GURL("https://origin.test/testfile1"));
+        storage->GetDictionarySync(GURL("https://origin.test/testfile1"),
+                                   mojom::RequestDestination::kEmpty);
     ASSERT_TRUE(dict1);
 
     std::unique_ptr<SharedDictionary> dict2 =
-        storage->GetDictionarySync(GURL("https://origin.test/testfile2"));
+        storage->GetDictionarySync(GURL("https://origin.test/testfile2"),
+                                   mojom::RequestDestination::kEmpty);
     ASSERT_TRUE(dict2);
 
     net::TestCompletionCallback read_callback1;
@@ -527,12 +532,12 @@
   ASSERT_EQ(1u, dictionary_map.size());
   ASSERT_EQ(2u, dictionary_map.begin()->second.size());
 
-  std::unique_ptr<SharedDictionary> dict1 =
-      storage->GetDictionarySync(GURL("https://origin.test/testfile1"));
+  std::unique_ptr<SharedDictionary> dict1 = storage->GetDictionarySync(
+      GURL("https://origin.test/testfile1"), mojom::RequestDestination::kEmpty);
   ASSERT_TRUE(dict1);
 
-  std::unique_ptr<SharedDictionary> dict2 =
-      storage->GetDictionarySync(GURL("https://origin.test/testfile2"));
+  std::unique_ptr<SharedDictionary> dict2 = storage->GetDictionarySync(
+      GURL("https://origin.test/testfile2"), mojom::RequestDestination::kEmpty);
   ASSERT_TRUE(dict2);
 
   net::TestCompletionCallback read_callback1;
@@ -578,10 +583,11 @@
       manager->GetStorage(isolation_key);
   ASSERT_TRUE(storage);
 
-  EXPECT_FALSE(
-      storage->GetDictionarySync(GURL("https://origin.test/testfile")));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/testfile"),
+                                          mojom::RequestDestination::kEmpty));
   std::unique_ptr<SharedDictionary> dict;
   storage->GetDictionary(GURL("https://origin.test/testfile"),
+                         mojom::RequestDestination::kEmpty,
                          base::BindLambdaForTesting(
                              [&](std::unique_ptr<SharedDictionary> dictionary) {
                                dict = std::move(dictionary);
@@ -672,7 +678,8 @@
     }
 
     std::unique_ptr<SharedDictionary> dict =
-        storage->GetDictionarySync(GURL("https://origin.test/testfile1"));
+        storage->GetDictionarySync(GURL("https://origin.test/testfile1"),
+                                   mojom::RequestDestination::kEmpty);
     ASSERT_TRUE(dict);
 
     // Reading the dictionary should fail because the disk cache is broken.
@@ -685,7 +692,8 @@
     // After failing to read the disk cache entry, MismatchingEntryDeletionTask
     // cleans all dictionary in the metadata store.
     EXPECT_FALSE(
-        storage->GetDictionarySync(GURL("https://origin.test/testfile1")));
+        storage->GetDictionarySync(GURL("https://origin.test/testfile1"),
+                                   mojom::RequestDestination::kEmpty));
     EXPECT_TRUE(GetOnDiskDictionaryMap(storage.get()).empty());
   }
 }
@@ -744,7 +752,8 @@
     EXPECT_FALSE(GetOnDiskDictionaryMap(storage.get()).empty());
 
     std::unique_ptr<SharedDictionary> dict =
-        storage->GetDictionarySync(GURL("https://origin.test/testfile"));
+        storage->GetDictionarySync(GURL("https://origin.test/testfile"),
+                                   mojom::RequestDestination::kEmpty);
     ASSERT_TRUE(dict);
 
     // We can read the new dictionary.
@@ -873,7 +882,8 @@
     task_environment_.FastForwardBy(base::Seconds(1));
 
     std::unique_ptr<SharedDictionary> dict1 =
-        storage->GetDictionarySync(GURL("https://origin.test/testfile?1"));
+        storage->GetDictionarySync(GURL("https://origin.test/testfile?1"),
+                                   mojom::RequestDestination::kEmpty);
     base::Time last_used_time_after_first_get_dict =
         dictionary_map.begin()->second.begin()->second.last_used_time();
 
@@ -881,7 +891,8 @@
     task_environment_.FastForwardBy(base::Seconds(1));
 
     std::unique_ptr<SharedDictionary> dict2 =
-        storage->GetDictionarySync(GURL("https://origin.test/testfile?2"));
+        storage->GetDictionarySync(GURL("https://origin.test/testfile?2"),
+                                   mojom::RequestDestination::kEmpty);
     last_used_time_after_second_get_dict =
         dictionary_map.begin()->second.begin()->second.last_used_time();
     EXPECT_NE(initial_last_used_time, last_used_time_after_first_get_dict);
@@ -956,8 +967,8 @@
     task_environment_.FastForwardBy(base::Hours(12));
 
     // Get a dictionary before calling ClearData().
-    std::unique_ptr<SharedDictionary> dict =
-        storage->GetDictionarySync(GURL("https://target.test/p3?"));
+    std::unique_ptr<SharedDictionary> dict = storage->GetDictionarySync(
+        GURL("https://target.test/p3?"), mojom::RequestDestination::kEmpty);
     ASSERT_TRUE(dict);
 
     base::RunLoop run_loop;
@@ -976,13 +987,23 @@
         ElementsAre(
             Pair(url::SchemeHostPort(GURL("https://origin.test/")),
                  ElementsAre(
-                     Pair("/p1*", DictionaryUrlIs("https://origin.test/1")),
-                     Pair("/p2*", DictionaryUrlIs("https://origin.test/2")),
-                     Pair("/p3*", DictionaryUrlIs("https://origin.test/3")))),
+                     Pair(std::make_tuple(
+                              "/p1*", std::set<mojom::RequestDestination>()),
+                          DictionaryUrlIs("https://origin.test/1")),
+                     Pair(std::make_tuple(
+                              "/p2*", std::set<mojom::RequestDestination>()),
+                          DictionaryUrlIs("https://origin.test/2")),
+                     Pair(std::make_tuple(
+                              "/p3*", std::set<mojom::RequestDestination>()),
+                          DictionaryUrlIs("https://origin.test/3")))),
             Pair(url::SchemeHostPort(GURL("https://target.test/")),
                  ElementsAre(
-                     Pair("/p1*", DictionaryUrlIs("https://target.test/1")),
-                     Pair("/p4*", DictionaryUrlIs("https://target.test/4"))))));
+                     Pair(std::make_tuple(
+                              "/p1*", std::set<mojom::RequestDestination>()),
+                          DictionaryUrlIs("https://target.test/1")),
+                     Pair(std::make_tuple(
+                              "/p4*", std::set<mojom::RequestDestination>()),
+                          DictionaryUrlIs("https://target.test/4"))))));
 
     // We can still read the deleted dictionary from `dict`.
     net::TestCompletionCallback read_callback;
@@ -1012,13 +1033,23 @@
       ElementsAre(
           Pair(url::SchemeHostPort(GURL("https://origin.test/")),
                ElementsAre(
-                   Pair("/p1*", DictionaryUrlIs("https://origin.test/1")),
-                   Pair("/p2*", DictionaryUrlIs("https://origin.test/2")),
-                   Pair("/p3*", DictionaryUrlIs("https://origin.test/3")))),
+                   Pair(std::make_tuple("/p1*",
+                                        std::set<mojom::RequestDestination>()),
+                        DictionaryUrlIs("https://origin.test/1")),
+                   Pair(std::make_tuple("/p2*",
+                                        std::set<mojom::RequestDestination>()),
+                        DictionaryUrlIs("https://origin.test/2")),
+                   Pair(std::make_tuple("/p3*",
+                                        std::set<mojom::RequestDestination>()),
+                        DictionaryUrlIs("https://origin.test/3")))),
           Pair(url::SchemeHostPort(GURL("https://target.test/")),
                ElementsAre(
-                   Pair("/p1*", DictionaryUrlIs("https://target.test/1")),
-                   Pair("/p4*", DictionaryUrlIs("https://target.test/4"))))));
+                   Pair(std::make_tuple("/p1*",
+                                        std::set<mojom::RequestDestination>()),
+                        DictionaryUrlIs("https://target.test/1")),
+                   Pair(std::make_tuple("/p4*",
+                                        std::set<mojom::RequestDestination>()),
+                        DictionaryUrlIs("https://target.test/4"))))));
 }
 
 TEST_P(SharedDictionaryManagerOnDiskTest, ClearDataSerializedOperation) {
@@ -1038,12 +1069,16 @@
   EXPECT_THAT(
       GetOnDiskDictionaryMap(storage.get()),
       ElementsAre(
-          Pair(url::SchemeHostPort(GURL("https://target1.test/")),
-               ElementsAre(
-                   Pair("/p*", DictionaryUrlIs("https://target1.test/d")))),
-          Pair(url::SchemeHostPort(GURL("https://target2.test/")),
-               ElementsAre(
-                   Pair("/p*", DictionaryUrlIs("https://target2.test/d"))))));
+          Pair(
+              url::SchemeHostPort(GURL("https://target1.test/")),
+              ElementsAre(Pair(
+                  std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+                  DictionaryUrlIs("https://target1.test/d")))),
+          Pair(
+              url::SchemeHostPort(GURL("https://target2.test/")),
+              ElementsAre(Pair(
+                  std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+                  DictionaryUrlIs("https://target2.test/d"))))));
 
   base::RunLoop run_loop1;
   manager->ClearData(base::Time(), base::Time::Max(),
@@ -1061,11 +1096,13 @@
 
   // The dictionary of "https://target2.test/" must still alive, because the
   // operation of ClearData is serialized.
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target2.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target2.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target2.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target2.test/d"))))));
 
   run_loop2.Run();
 
@@ -1096,8 +1133,8 @@
     FlushCacheTasks();
 
     // Get a dictionary before calling ClearDataForIsolationKey().
-    std::unique_ptr<SharedDictionary> dict =
-        storage1->GetDictionarySync(GURL("https://origin1.test/p?"));
+    std::unique_ptr<SharedDictionary> dict = storage1->GetDictionarySync(
+        GURL("https://origin1.test/p?"), mojom::RequestDestination::kEmpty);
     ASSERT_TRUE(dict);
 
     base::RunLoop run_loop;
@@ -1106,11 +1143,13 @@
 
     // The dictionaries for `isolation_key1` must have been deleted.
     EXPECT_TRUE(GetOnDiskDictionaryMap(storage1.get()).empty());
-    EXPECT_THAT(GetOnDiskDictionaryMap(storage2.get()),
-                ElementsAre(Pair(
-                    url::SchemeHostPort(GURL("https://origin1.test/")),
-                    ElementsAre(Pair(
-                        "/p*", DictionaryUrlIs("https://origin1.test/d"))))));
+    EXPECT_THAT(
+        GetOnDiskDictionaryMap(storage2.get()),
+        ElementsAre(Pair(
+            url::SchemeHostPort(GURL("https://origin1.test/")),
+            ElementsAre(Pair(
+                std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+                DictionaryUrlIs("https://origin1.test/d"))))));
 
     // We can still read the deleted dictionary from `dict`.
     net::TestCompletionCallback read_callback;
@@ -1137,11 +1176,13 @@
   task_environment_.RunUntilIdle();
 
   EXPECT_TRUE(GetOnDiskDictionaryMap(storage1.get()).empty());
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage2.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://origin1.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://origin1.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage2.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://origin1.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://origin1.test/d"))))));
 }
 
 TEST_P(SharedDictionaryManagerOnDiskTest, ExpiredDictionaryDeletionOnReload) {
@@ -1182,11 +1223,13 @@
   task_environment_.RunUntilIdle();
 
   // The first dictionary must have been deleted.
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target2.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target2.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target2.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target2.test/d"))))));
   EXPECT_FALSE(DiskCacheEntryExists(manager.get(), token1));
   EXPECT_TRUE(DiskCacheEntryExists(manager.get(), token2));
 }
@@ -1211,11 +1254,13 @@
   // Move the clock forward by 10 second.
   task_environment_.FastForwardBy(base::Seconds(10));
   // The first dictionary still exists.
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target1.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target1.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target1.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target1.test/d"))))));
   EXPECT_TRUE(DiskCacheEntryExists(manager.get(), token1));
 
   // Write a second dictionary.
@@ -1227,11 +1272,13 @@
       GetOnDiskDictionaryMap(storage.get()), "https://target2.test/");
 
   // The first dictionary must have been deleted.
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target2.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target2.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target2.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target2.test/d"))))));
   EXPECT_FALSE(DiskCacheEntryExists(manager.get(), token1));
   EXPECT_TRUE(DiskCacheEntryExists(manager.get(), token2));
 }
@@ -1255,11 +1302,13 @@
   // Move the clock forward by 10 second.
   task_environment_.FastForwardBy(base::Seconds(10));
   // The first dictionary still exists.
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target1.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target1.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target1.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target1.test/d"))))));
 
   // Set the max size to kTestData1.size() * 100
   manager->SetCacheMaxSize(kTestData1.size() * 100);
@@ -1291,11 +1340,13 @@
   // Move the clock forward by 10 second.
   task_environment_.FastForwardBy(base::Seconds(10));
   // The first dictionary still exists.
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target1.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target1.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target1.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target1.test/d"))))));
 
   base::RunLoop run_loop;
   manager->ClearData(
@@ -1330,11 +1381,13 @@
   // Move the clock forward by 10 second.
   task_environment_.FastForwardBy(base::Seconds(10));
   // The first dictionary still exists.
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target1.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target1.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target1.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target1.test/d"))))));
 
   base::RunLoop run_loop;
   manager->ClearDataForIsolationKey(
@@ -1393,11 +1446,13 @@
   task_environment_.RunUntilIdle();
 
   // Only the third dictionary exists.
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target3.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target3.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target3.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target3.test/d"))))));
   EXPECT_FALSE(DiskCacheEntryExists(manager.get(), token1));
   EXPECT_FALSE(DiskCacheEntryExists(manager.get(), token2));
   EXPECT_TRUE(DiskCacheEntryExists(manager.get(), token3));
@@ -1435,11 +1490,13 @@
   task_environment_.RunUntilIdle();
 
   // Only the third dictionary exists.
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target3.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target3.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target3.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target3.test/d"))))));
   EXPECT_FALSE(DiskCacheEntryExists(manager.get(), token1));
   EXPECT_FALSE(DiskCacheEntryExists(manager.get(), token2));
   EXPECT_TRUE(DiskCacheEntryExists(manager.get(), token3));
@@ -1488,16 +1545,20 @@
   task_environment_.FastForwardBy(base::Seconds(1));
 
   // Both the dictinaries exist.
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage1.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target1.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target1.test/d"))))));
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage2.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target2.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target2.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage1.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target1.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target1.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage2.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target2.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target2.test/d"))))));
   EXPECT_TRUE(DiskCacheEntryExists(manager.get(), token1));
   EXPECT_TRUE(DiskCacheEntryExists(manager.get(), token2));
 
@@ -1510,11 +1571,13 @@
   // Only the third dictionary exists.
   EXPECT_TRUE(GetOnDiskDictionaryMap(storage1.get()).empty());
   EXPECT_TRUE(GetOnDiskDictionaryMap(storage2.get()).empty());
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage3.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target3.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target3.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage3.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target3.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target3.test/d"))))));
 
   EXPECT_FALSE(DiskCacheEntryExists(manager.get(), token1));
   EXPECT_FALSE(DiskCacheEntryExists(manager.get(), token2));
@@ -1552,11 +1615,13 @@
   FlushCacheTasks();
   base::UnguessableToken token1 = GetDiskCacheKeyTokenOfFirstDictionary(
       GetOnDiskDictionaryMap(storage1.get()), "https://target1.test/");
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage1.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target1.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target1.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage1.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target1.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target1.test/d"))))));
   EXPECT_TRUE(DiskCacheEntryExists(manager.get(), token1));
   task_environment_.FastForwardBy(base::Seconds(1));
 
@@ -1566,11 +1631,13 @@
   FlushCacheTasks();
   base::UnguessableToken token2 = GetDiskCacheKeyTokenOfFirstDictionary(
       GetOnDiskDictionaryMap(storage2.get()), "https://target2.test/");
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage2.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target2.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target2.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage2.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target2.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target2.test/d"))))));
   EXPECT_TRUE(DiskCacheEntryExists(manager.get(), token2));
   task_environment_.FastForwardBy(base::Seconds(1));
 
@@ -1580,19 +1647,23 @@
   FlushCacheTasks();
   base::UnguessableToken token3 = GetDiskCacheKeyTokenOfFirstDictionary(
       GetOnDiskDictionaryMap(storage3.get()), "https://target3.test/");
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage3.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target3.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target3.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage3.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target3.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target3.test/d"))))));
   EXPECT_TRUE(DiskCacheEntryExists(manager.get(), token3));
 
   // The first dictionary must still exist.
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage1.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target1.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target1.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage1.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target1.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target1.test/d"))))));
   EXPECT_TRUE(DiskCacheEntryExists(manager.get(), token1));
 
   // The second dictionary must have been deleted because the size limit per
@@ -1632,11 +1703,13 @@
   FlushCacheTasks();
   base::UnguessableToken token1 = GetDiskCacheKeyTokenOfFirstDictionary(
       GetOnDiskDictionaryMap(storage1.get()), "https://target1.test/");
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage1.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target1.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target1.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage1.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target1.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target1.test/d"))))));
   EXPECT_TRUE(DiskCacheEntryExists(manager.get(), token1));
   task_environment_.FastForwardBy(base::Seconds(1));
 
@@ -1646,11 +1719,13 @@
   FlushCacheTasks();
   base::UnguessableToken token2 = GetDiskCacheKeyTokenOfFirstDictionary(
       GetOnDiskDictionaryMap(storage2.get()), "https://target2.test/");
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage2.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target2.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target2.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage2.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target2.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target2.test/d"))))));
   EXPECT_TRUE(DiskCacheEntryExists(manager.get(), token2));
   task_environment_.FastForwardBy(base::Seconds(1));
 
@@ -1663,12 +1738,16 @@
   EXPECT_THAT(
       GetOnDiskDictionaryMap(storage2.get()),
       ElementsAre(
-          Pair(url::SchemeHostPort(GURL("https://target2.test/")),
-               ElementsAre(
-                   Pair("/p*", DictionaryUrlIs("https://target2.test/d")))),
-          Pair(url::SchemeHostPort(GURL("https://target3.test/")),
-               ElementsAre(
-                   Pair("/p*", DictionaryUrlIs("https://target3.test/d"))))));
+          Pair(
+              url::SchemeHostPort(GURL("https://target2.test/")),
+              ElementsAre(Pair(
+                  std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+                  DictionaryUrlIs("https://target2.test/d")))),
+          Pair(
+              url::SchemeHostPort(GURL("https://target3.test/")),
+              ElementsAre(Pair(
+                  std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+                  DictionaryUrlIs("https://target3.test/d"))))));
   EXPECT_TRUE(DiskCacheEntryExists(manager.get(), token3));
 
   // Register the fourth dictionary.
@@ -1677,28 +1756,34 @@
   FlushCacheTasks();
   base::UnguessableToken token4 = GetDiskCacheKeyTokenOfFirstDictionary(
       GetOnDiskDictionaryMap(storage3.get()), "https://target4.test/");
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage3.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target4.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target4.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage3.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target4.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target4.test/d"))))));
   EXPECT_TRUE(DiskCacheEntryExists(manager.get(), token4));
 
   // The first dictionary must still exist.
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage1.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target1.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target1.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage1.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target1.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target1.test/d"))))));
   EXPECT_TRUE(DiskCacheEntryExists(manager.get(), token1));
 
   // The third dictionary must still exist. But the second dictionary must have
   // been deleted because the count limit per site is 2 (4 / 2).
-  EXPECT_THAT(GetOnDiskDictionaryMap(storage2.get()),
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target3.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target3.test/d"))))));
+  EXPECT_THAT(
+      GetOnDiskDictionaryMap(storage2.get()),
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target3.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target3.test/d"))))));
   EXPECT_FALSE(DiskCacheEntryExists(manager.get(), token2));
   EXPECT_TRUE(DiskCacheEntryExists(manager.get(), token3));
 }
@@ -1749,8 +1834,8 @@
   task_environment_.FastForwardBy(base::Seconds(1));
 
   // Call GetDictionary to update the last used time of the dictionary 1.
-  std::unique_ptr<SharedDictionary> dict1 =
-      storage->GetDictionarySync(GURL("https://target1.test/path?"));
+  std::unique_ptr<SharedDictionary> dict1 = storage->GetDictionarySync(
+      GURL("https://target1.test/path?"), mojom::RequestDestination::kEmpty);
   ASSERT_TRUE(dict1);
 
   // Set the max size to kTestData1.size() * 3. The low water mark will be
@@ -1763,12 +1848,16 @@
   EXPECT_THAT(
       GetOnDiskDictionaryMap(storage.get()),
       ElementsAre(
-          Pair(url::SchemeHostPort(GURL("https://target1.test/")),
-               ElementsAre(
-                   Pair("/p*", DictionaryUrlIs("https://target1.test/d")))),
-          Pair(url::SchemeHostPort(GURL("https://target4.test/")),
-               ElementsAre(
-                   Pair("/p*", DictionaryUrlIs("https://target4.test/d"))))));
+          Pair(
+              url::SchemeHostPort(GURL("https://target1.test/")),
+              ElementsAre(Pair(
+                  std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+                  DictionaryUrlIs("https://target1.test/d")))),
+          Pair(
+              url::SchemeHostPort(GURL("https://target4.test/")),
+              ElementsAre(Pair(
+                  std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+                  DictionaryUrlIs("https://target4.test/d"))))));
   EXPECT_TRUE(DiskCacheEntryExists(manager.get(), token1));
   EXPECT_FALSE(DiskCacheEntryExists(manager.get(), token2));
   EXPECT_FALSE(DiskCacheEntryExists(manager.get(), token3));
@@ -1850,11 +1939,13 @@
     FlushCacheTasks();
 
     const auto& dictionary_map = GetOnDiskDictionaryMap(storage.get());
-    EXPECT_THAT(dictionary_map,
-                ElementsAre(Pair(
-                    url::SchemeHostPort(GURL("https://target1.test/")),
-                    ElementsAre(Pair(
-                        "/p*", DictionaryUrlIs("https://target1.test/d"))))));
+    EXPECT_THAT(
+        dictionary_map,
+        ElementsAre(Pair(
+            url::SchemeHostPort(GURL("https://target1.test/")),
+            ElementsAre(Pair(
+                std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+                DictionaryUrlIs("https://target1.test/d"))))));
 
     DoomDiskCacheEntry(manager.get(),
                        GetDiskCacheKeyTokenOfFirstDictionary(
@@ -1999,11 +2090,13 @@
       0, 1);
 
   const auto& dictionary_map = GetOnDiskDictionaryMap(storage.get());
-  EXPECT_THAT(dictionary_map,
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target1.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target1.test/d"))))));
+  EXPECT_THAT(
+      dictionary_map,
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target1.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target1.test/d"))))));
 }
 
 TEST_P(SharedDictionaryManagerOnDiskTest,
@@ -2031,11 +2124,13 @@
   FlushCacheTasks();
 
   const auto& dictionary_map = GetOnDiskDictionaryMap(storage.get());
-  EXPECT_THAT(dictionary_map,
-              ElementsAre(Pair(
-                  url::SchemeHostPort(GURL("https://target1.test/")),
-                  ElementsAre(Pair(
-                      "/p*", DictionaryUrlIs("https://target1.test/d"))))));
+  EXPECT_THAT(
+      dictionary_map,
+      ElementsAre(Pair(
+          url::SchemeHostPort(GURL("https://target1.test/")),
+          ElementsAre(Pair(
+              std::make_tuple("/p*", std::set<mojom::RequestDestination>()),
+              DictionaryUrlIs("https://target1.test/d"))))));
   histogram_tester.ExpectUniqueSample(
       "Net.SharedDictionaryManagerOnDisk.InvalidDiskCacheEntryCount", 0, 1);
   histogram_tester.ExpectUniqueSample(
diff --git a/services/network/shared_dictionary/shared_dictionary_manager_unittest.cc b/services/network/shared_dictionary/shared_dictionary_manager_unittest.cc
index f2994e4..8dc0e4c7 100644
--- a/services/network/shared_dictionary/shared_dictionary_manager_unittest.cc
+++ b/services/network/shared_dictionary/shared_dictionary_manager_unittest.cc
@@ -224,15 +224,16 @@
   }
   const std::map<
       url::SchemeHostPort,
-      std::map<std::string, SharedDictionaryStorageInMemory::DictionaryInfo>>&
+      std::map<std::tuple<std::string, std::set<mojom::RequestDestination>>,
+               SharedDictionaryStorageInMemory::DictionaryInfo>>&
   GetInMemoryDictionaryMap(SharedDictionaryStorage* storage) {
     return static_cast<SharedDictionaryStorageInMemory*>(storage)
         ->GetDictionaryMap();
   }
   const std::map<
       url::SchemeHostPort,
-      std::map<std::string,
-               SharedDictionaryStorageOnDisk::DictionaryInfoWithMatcher>>&
+      std::map<std::tuple<std::string, std::set<mojom::RequestDestination>>,
+               SharedDictionaryStorageOnDisk::WrappedDictionaryInfo>>&
   GetOnDiskDictionaryMap(SharedDictionaryStorage* storage) {
     return static_cast<SharedDictionaryStorageOnDisk*>(storage)
         ->GetDictionaryMapForTesting();
@@ -341,14 +342,16 @@
     FlushCacheTasks();
   }
 
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin1.test/p?")));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin1.test/p?"),
+                                         mojom::RequestDestination::kEmpty));
 
   storage.reset();
 
   // Even after resetting `storage`, `storage` should be in `manager`'s
   // `cached_storages_`. So the metadata is still in the memory.
   storage = manager->GetStorage(isolation_key);
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin1.test/p?")));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin1.test/p?"),
+                                         mojom::RequestDestination::kEmpty));
 }
 
 TEST_P(SharedDictionaryManagerTest, CachedStorageEvicted) {
@@ -367,7 +370,8 @@
     FlushCacheTasks();
   }
 
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin1.test/p?")));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin1.test/p?"),
+                                         mojom::RequestDestination::kEmpty));
 
   storage.reset();
 
@@ -382,7 +386,8 @@
   // Even after creating 10 (kCachedStorageMaxSize) storages, the first storage
   // should still be in the cache.
   storage = manager->GetStorage(isolation_key);
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin1.test/p?")));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin1.test/p?"),
+                                         mojom::RequestDestination::kEmpty));
   storage.reset();
 
   for (int i = 0; i < 10; ++i) {
@@ -396,7 +401,8 @@
   // When we create 11 (kCachedStorageMaxSize + 1) storages, the first storage
   // must be evicted
   storage = manager->GetStorage(isolation_key);
-  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin1.test/p?")));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin1.test/p?"),
+                                          mojom::RequestDestination::kEmpty));
 }
 
 TEST_P(SharedDictionaryManagerTest,
@@ -420,14 +426,16 @@
     FlushCacheTasks();
   }
 
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin1.test/p?")));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin1.test/p?"),
+                                         mojom::RequestDestination::kEmpty));
 
   storage.reset();
 
   // If `manager` has observed moderate memory pressure, it should not cache the
   // stoarge.
   storage = manager->GetStorage(isolation_key);
-  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin1.test/p?")));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin1.test/p?"),
+                                          mojom::RequestDestination::kEmpty));
 }
 
 TEST_P(SharedDictionaryManagerTest,
@@ -451,14 +459,16 @@
     FlushCacheTasks();
   }
 
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin1.test/p?")));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin1.test/p?"),
+                                         mojom::RequestDestination::kEmpty));
 
   storage.reset();
 
   // If `manager` has observed critical memory pressure, it should not cache the
   // stoarge.
   storage = manager->GetStorage(isolation_key);
-  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin1.test/p?")));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin1.test/p?"),
+                                          mojom::RequestDestination::kEmpty));
 }
 
 TEST_P(SharedDictionaryManagerTest,
@@ -477,7 +487,8 @@
     FlushCacheTasks();
   }
 
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin1.test/p?")));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin1.test/p?"),
+                                         mojom::RequestDestination::kEmpty));
 
   storage.reset();
 
@@ -489,7 +500,8 @@
   // If `manager` observed moderate memory pressure, it should clear the cached
   // storage.
   storage = manager->GetStorage(isolation_key);
-  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin1.test/p?")));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin1.test/p?"),
+                                          mojom::RequestDestination::kEmpty));
 }
 
 TEST_P(SharedDictionaryManagerTest,
@@ -508,7 +520,8 @@
     FlushCacheTasks();
   }
 
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin1.test/p?")));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin1.test/p?"),
+                                         mojom::RequestDestination::kEmpty));
 
   storage.reset();
 
@@ -520,7 +533,8 @@
   // If `manager` observed critical memory pressure, it should clear the cached
   // storage.
   storage = manager->GetStorage(isolation_key);
-  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin1.test/p?")));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin1.test/p?"),
+                                          mojom::RequestDestination::kEmpty));
 }
 
 TEST_P(SharedDictionaryManagerTest, NoWriterForNoUseAsDictionaryHeader) {
@@ -718,6 +732,180 @@
   }
 }
 
+TEST_P(SharedDictionaryManagerTest, WriterForUseAsDictionaryIdOption) {
+  std::unique_ptr<SharedDictionaryManager> manager =
+      CreateSharedDictionaryManager();
+  net::SharedDictionaryIsolationKey isolation_key(url::Origin::Create(kUrl1),
+                                                  kSite1);
+
+  scoped_refptr<SharedDictionaryStorage> storage =
+      manager->GetStorage(isolation_key);
+  ASSERT_TRUE(storage);
+
+  struct {
+    std::string header_string;
+    bool expect_success_v1;
+    bool expect_success_v2;
+    std::string expected_id;
+  } kTestCases[] = {
+      // Valid `id` value.
+      {"match=\"test\", id=\"test_id\"", /*expect_success_v1=*/true,
+       /*expect_success_v2=*/true, /*expected_id=*/"test_id"},
+      // `id` should not be a list.
+      {"match=\"test\", id=(\"id1\" \"id2\")", /*expect_success_v1=*/true,
+       /*expect_success_v2=*/false},
+      // `id` can be 1024 characters long.
+      {base::StrCat({"match=\"test\", id=\"", std::string(1024, 'x'), "\""}),
+       /*expect_success_v1=*/true,
+       /*expect_success_v2=*/true, /*expected_id=*/std::string(1024, 'x')},
+      // `id` too long.
+      {base::StrCat({"match=\"test\", id=\"", std::string(1025, 'x'), "\""}),
+       /*expect_success_v1=*/true,
+       /*expect_success_v2=*/false},
+  };
+  for (const auto& testcase : kTestCases) {
+    SCOPED_TRACE(base::StringPrintf("header_string: %s",
+                                    testcase.header_string.c_str()));
+    scoped_refptr<net::HttpResponseHeaders> headers =
+        net::HttpResponseHeaders::TryToCreate(base::StrCat(
+            {"HTTP/1.1 200 OK\n", shared_dictionary::kUseAsDictionaryHeaderName,
+             ": ", testcase.header_string, "\n", kDefaultCacheControlHeader,
+             "\n"}));
+    ASSERT_TRUE(headers);
+    scoped_refptr<SharedDictionaryWriter> writer = storage->MaybeCreateWriter(
+        GURL("https://origin1.test/testfile.txt"),
+        /*request_time=*/base::Time::Now(), /*response_time=*/base::Time::Now(),
+        *headers,
+        /*was_fetched_via_cache=*/false,
+        /*access_allowed_check_callback=*/base::BindOnce([]() {
+          return true;
+        }));
+    switch (GetVersion()) {
+      case features::CompressionDictionaryTransportBackendVersion::kV1:
+        EXPECT_EQ(testcase.expect_success_v1, !!writer);
+        continue;
+      case features::CompressionDictionaryTransportBackendVersion::kV2:
+        EXPECT_EQ(testcase.expect_success_v2, !!writer);
+        break;
+    }
+    if (!writer) {
+      continue;
+    }
+    writer->Append(kTestData1.c_str(), kTestData1.size());
+    writer->Finish();
+    if (GetManagerType() == TestManagerType::kOnDisk) {
+      FlushCacheTasks();
+      // TODO(crbug.com/1413922): Currently `id` is not supported by the disk
+      // cache backend.
+      continue;
+    }
+    std::vector<network::mojom::SharedDictionaryInfoPtr> result =
+        GetSharedDictionaryInfo(manager.get(), isolation_key);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_EQ(testcase.expected_id, result[0]->id);
+  }
+}
+
+TEST_P(SharedDictionaryManagerTest, WriterForUseAsDictionaryMatchDestOption) {
+  std::unique_ptr<SharedDictionaryManager> manager =
+      CreateSharedDictionaryManager();
+  net::SharedDictionaryIsolationKey isolation_key(url::Origin::Create(kUrl1),
+                                                  kSite1);
+
+  scoped_refptr<SharedDictionaryStorage> storage =
+      manager->GetStorage(isolation_key);
+  ASSERT_TRUE(storage);
+
+  struct {
+    std::string header_string;
+    bool expect_success_v1;
+    bool expect_success_v2;
+    std::vector<mojom::RequestDestination> expected_match_dest;
+  } kTestCases[] = {
+      // No `match-dest` value.
+      {"match=\"test\"", /*expect_success_v1=*/true,
+       /*expect_success_v2=*/true, /*expected_match_dest=*/{}},
+      // Valid `match-dest` value.
+      {"match=\"test\", match-dest=(\"document\")", /*expect_success_v1=*/true,
+       /*expect_success_v2=*/true,
+       /*expected_match_dest=*/{mojom::RequestDestination::kDocument}},
+      // `match-dest` must be a list.
+      {"match=\"test\", match-dest=\"document\"", /*expect_success_v1=*/true,
+       /*expect_success_v2=*/false},
+      // Unknown `match-dest` value should be treated as empty.
+      {"match=\"test\", match-dest=(\"unknown\")", /*expect_success_v1=*/true,
+       /*expect_success_v2=*/true,
+       /*expected_match_dest=*/{}},
+      //`match-dest` should not be a sf-token.
+      // https://github.com/httpwg/http-extensions/issues/2723
+      {"match=\"test\", match-dest=(document)", /*expect_success_v1=*/true,
+       /*expect_success_v2=*/false},
+      // Valid `match-dest` value "".
+      {"match=\"test\", match-dest=(\"\")", /*expect_success_v1=*/true,
+       /*expect_success_v2=*/true,
+       /*expected_match_dest=*/{mojom::RequestDestination::kEmpty}},
+      // Valid `match-dest` value ("document" "frame" "iframe").
+      {"match=\"test\", match-dest=(\"document\" \"frame\" \"iframe\")",
+       /*expect_success_v1=*/true,
+       /*expect_success_v2=*/true,
+       /*expected_match_dest=*/
+       {mojom::RequestDestination::kDocument, mojom::RequestDestination::kFrame,
+        mojom::RequestDestination::kIframe}},
+      // Valid `match-dest` value ("document" "frame" "iframe" "").
+      {"match=\"test\", match-dest=(\"document\" \"\")",
+       /*expect_success_v1=*/true,
+       /*expect_success_v2=*/true,
+       /*expected_match_dest=*/
+       {mojom::RequestDestination::kEmpty,
+        mojom::RequestDestination::kDocument}},
+
+  };
+  for (const auto& testcase : kTestCases) {
+    base::RunLoop run_loop;
+    manager->ClearDataForIsolationKey(isolation_key, run_loop.QuitClosure());
+    run_loop.Run();
+    SCOPED_TRACE(base::StringPrintf("header_string: %s",
+                                    testcase.header_string.c_str()));
+    scoped_refptr<net::HttpResponseHeaders> headers =
+        net::HttpResponseHeaders::TryToCreate(base::StrCat(
+            {"HTTP/1.1 200 OK\n", shared_dictionary::kUseAsDictionaryHeaderName,
+             ": ", testcase.header_string, "\n", kDefaultCacheControlHeader,
+             "\n"}));
+    ASSERT_TRUE(headers);
+    scoped_refptr<SharedDictionaryWriter> writer = storage->MaybeCreateWriter(
+        GURL("https://origin1.test/testfile.txt"),
+        /*request_time=*/base::Time::Now(), /*response_time=*/base::Time::Now(),
+        *headers,
+        /*was_fetched_via_cache=*/false,
+        /*access_allowed_check_callback=*/base::BindOnce([]() {
+          return true;
+        }));
+    switch (GetVersion()) {
+      case features::CompressionDictionaryTransportBackendVersion::kV1:
+        EXPECT_EQ(testcase.expect_success_v1, !!writer);
+        continue;
+      case features::CompressionDictionaryTransportBackendVersion::kV2:
+        EXPECT_EQ(testcase.expect_success_v2, !!writer);
+        break;
+    }
+    if (!writer) {
+      continue;
+    }
+    writer->Append(kTestData1.c_str(), kTestData1.size());
+    writer->Finish();
+    if (GetManagerType() == TestManagerType::kOnDisk) {
+      FlushCacheTasks();
+      // TODO(crbug.com/1413922): Currently `match-dest` is not supported by the
+      // disk cache backend.
+      continue;
+    }
+    std::vector<network::mojom::SharedDictionaryInfoPtr> result =
+        GetSharedDictionaryInfo(manager.get(), isolation_key);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_EQ(testcase.expected_match_dest, result[0]->match_dest);
+  }
+}
+
 TEST_P(SharedDictionaryManagerTest, InvalidMatch) {
   std::unique_ptr<SharedDictionaryManager> manager =
       CreateSharedDictionaryManager();
@@ -923,13 +1111,14 @@
   }
 
   // Check the returned dictionary from GetDictionarySync().
-  EXPECT_TRUE(
-      storage->GetDictionarySync(GURL("https://origin1.test/testfile")));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin1.test/testfile"),
+                                         mojom::RequestDestination::kEmpty));
   // Different origin.
-  EXPECT_FALSE(
-      storage->GetDictionarySync(GURL("https://origin2.test/testfile")));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin2.test/testfile"),
+                                          mojom::RequestDestination::kEmpty));
   // No matching dictionary.
-  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin1.test/test")));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin1.test/test"),
+                                          mojom::RequestDestination::kEmpty));
 }
 
 TEST_P(SharedDictionaryManagerTest, WriteAndReadDictionary) {
@@ -961,7 +1150,8 @@
 
   // Check the returned dictionary from GetDictionarySync().
   std::unique_ptr<SharedDictionary> dict =
-      storage->GetDictionarySync(GURL("https://origin1.test/testfile?hello"));
+      storage->GetDictionarySync(GURL("https://origin1.test/testfile?hello"),
+                                 mojom::RequestDestination::kEmpty);
   ASSERT_TRUE(dict);
   EXPECT_EQ(data1.size() + data2.size(), dict->size());
   EXPECT_EQ(sha256, dict->hash());
@@ -997,7 +1187,9 @@
                 dictionary_map.begin()->first);
 
       EXPECT_EQ(1u, dictionary_map.begin()->second.size());
-      EXPECT_EQ("/testfile*", dictionary_map.begin()->second.begin()->first);
+      EXPECT_EQ(
+          std::make_tuple("/testfile*", std::set<mojom::RequestDestination>()),
+          dictionary_map.begin()->second.begin()->first);
       const auto& dictionary_info =
           dictionary_map.begin()->second.begin()->second;
       EXPECT_EQ(GURL("https://origin1.test/dict"), dictionary_info.url());
@@ -1018,7 +1210,9 @@
                 dictionary_map.begin()->first);
 
       EXPECT_EQ(1u, dictionary_map.begin()->second.size());
-      EXPECT_EQ("/testfile*", dictionary_map.begin()->second.begin()->first);
+      EXPECT_EQ(
+          std::make_tuple("/testfile*", std::set<mojom::RequestDestination>()),
+          dictionary_map.begin()->second.begin()->first);
       const auto& dictionary_info =
           dictionary_map.begin()->second.begin()->second;
       EXPECT_EQ(GURL("https://origin1.test/dict"), dictionary_info.url());
@@ -1051,7 +1245,8 @@
   if (GetManagerType() == TestManagerType::kOnDisk) {
     FlushCacheTasks();
   }
-  auto dict = storage->GetDictionarySync(GURL("https://origin1.test/testfile"));
+  auto dict = storage->GetDictionarySync(GURL("https://origin1.test/testfile"),
+                                         mojom::RequestDestination::kEmpty);
   ASSERT_TRUE(dict);
   net::TestCompletionCallback read_callback;
   EXPECT_EQ(net::OK,
@@ -1075,7 +1270,8 @@
   if (GetManagerType() == TestManagerType::kOnDisk) {
     FlushCacheTasks();
   }
-  auto dict = storage->GetDictionarySync(GURL("https://origin1.test/testfile"));
+  auto dict = storage->GetDictionarySync(GURL("https://origin1.test/testfile"),
+                                         mojom::RequestDestination::kEmpty);
   ASSERT_TRUE(dict);
   net::TestCompletionCallback read_callback;
   EXPECT_EQ(net::OK,
@@ -1134,7 +1330,8 @@
 
   // Check the returned dictionary from GetDictionarySync().
   std::unique_ptr<SharedDictionary> dict =
-      storage->GetDictionarySync(GURL("https://origin1.test/testfile?hello"));
+      storage->GetDictionarySync(GURL("https://origin1.test/testfile?hello"),
+                                 mojom::RequestDestination::kEmpty);
   EXPECT_FALSE(dict);
 }
 
@@ -1170,9 +1367,12 @@
     FlushCacheTasks();
   }
 
-  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin1.test/p1?")));
-  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin2.test/p2?")));
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin3.test/p3?")));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin1.test/p1?"),
+                                          mojom::RequestDestination::kEmpty));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin2.test/p2?"),
+                                          mojom::RequestDestination::kEmpty));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin3.test/p3?"),
+                                         mojom::RequestDestination::kEmpty));
 }
 
 TEST_P(SharedDictionaryManagerTest, CacheEvictionZeroMaxSizeCountExceeded) {
@@ -1203,7 +1403,8 @@
 
   for (size_t i = 0; i < kCacheMaxCount; ++i) {
     EXPECT_TRUE(storages[i]->GetDictionarySync(
-        GURL(base::StringPrintf("https://origin.test/p%03" PRIuS "?", i))));
+        GURL(base::StringPrintf("https://origin.test/p%03" PRIuS "?", i)),
+        mojom::RequestDestination::kEmpty));
     task_environment_.FastForwardBy(base::Seconds(1));
   }
 
@@ -1232,14 +1433,16 @@
   // kCacheMaxCount * 0.9.
   for (size_t i = 0; i < kCacheMaxCount - kCacheMaxCount * 0.9; ++i) {
     EXPECT_FALSE(storages[i]->GetDictionarySync(
-        GURL(base::StringPrintf("https://origin.test/p%03" PRIuS "?", i))));
+        GURL(base::StringPrintf("https://origin.test/p%03" PRIuS "?", i)),
+        mojom::RequestDestination::kEmpty));
   }
 
   // Newer dictionaries must not be deleted.
   for (size_t i = kCacheMaxCount - kCacheMaxCount * 0.9 + 1;
        i <= kCacheMaxCount; ++i) {
     EXPECT_TRUE(storages[i]->GetDictionarySync(
-        GURL(base::StringPrintf("https://origin.test/p%03" PRIuS "?", i))));
+        GURL(base::StringPrintf("https://origin.test/p%03" PRIuS "?", i)),
+        mojom::RequestDestination::kEmpty));
   }
 }
 
@@ -1272,18 +1475,23 @@
   if (GetManagerType() == TestManagerType::kOnDisk) {
     FlushCacheTasks();
   }
-  EXPECT_TRUE(storage1->GetDictionarySync(GURL("https://origin1.test/p1?")));
+  EXPECT_TRUE(storage1->GetDictionarySync(GURL("https://origin1.test/p1?"),
+                                          mojom::RequestDestination::kEmpty));
   task_environment_.FastForwardBy(base::Seconds(1));
-  EXPECT_TRUE(storage2->GetDictionarySync(GURL("https://origin2.test/p2?")));
+  EXPECT_TRUE(storage2->GetDictionarySync(GURL("https://origin2.test/p2?"),
+                                          mojom::RequestDestination::kEmpty));
   task_environment_.FastForwardBy(base::Seconds(1));
   WriteDictionary(storage3.get(), GURL("https://origin3.test/d1"), "p3*",
                   {kTestData1});
   if (GetManagerType() == TestManagerType::kOnDisk) {
     FlushCacheTasks();
   }
-  EXPECT_FALSE(storage1->GetDictionarySync(GURL("https://origin1.test/p1?")));
-  EXPECT_FALSE(storage2->GetDictionarySync(GURL("https://origin2.test/p2?")));
-  EXPECT_TRUE(storage3->GetDictionarySync(GURL("https://origin3.test/p3?")));
+  EXPECT_FALSE(storage1->GetDictionarySync(GURL("https://origin1.test/p1?"),
+                                           mojom::RequestDestination::kEmpty));
+  EXPECT_FALSE(storage2->GetDictionarySync(GURL("https://origin2.test/p2?"),
+                                           mojom::RequestDestination::kEmpty));
+  EXPECT_TRUE(storage3->GetDictionarySync(GURL("https://origin3.test/p3?"),
+                                          mojom::RequestDestination::kEmpty));
 }
 
 TEST_P(SharedDictionaryManagerTest, CacheEvictionAfterUpdatingLastUsedTime) {
@@ -1324,8 +1532,8 @@
   task_environment_.FastForwardBy(base::Seconds(1));
 
   // Call GetDictionary to update the last used time of the dictionary 1-1.
-  std::unique_ptr<SharedDictionary> dict1 =
-      storage1->GetDictionarySync(GURL("https://origin1.test/p1?"));
+  std::unique_ptr<SharedDictionary> dict1 = storage1->GetDictionarySync(
+      GURL("https://origin1.test/p1?"), mojom::RequestDestination::kEmpty);
   ASSERT_TRUE(dict1);
 
   // Set the max size to kTestData1.size() * 3. The low water mark will be
@@ -1336,10 +1544,14 @@
     FlushCacheTasks();
   }
 
-  EXPECT_TRUE(storage1->GetDictionarySync(GURL("https://origin1.test/p1?")));
-  EXPECT_FALSE(storage1->GetDictionarySync(GURL("https://origin1.test/p2?")));
-  EXPECT_FALSE(storage2->GetDictionarySync(GURL("https://origin2.test/p1?")));
-  EXPECT_TRUE(storage2->GetDictionarySync(GURL("https://origin2.test/p2?")));
+  EXPECT_TRUE(storage1->GetDictionarySync(GURL("https://origin1.test/p1?"),
+                                          mojom::RequestDestination::kEmpty));
+  EXPECT_FALSE(storage1->GetDictionarySync(GURL("https://origin1.test/p2?"),
+                                           mojom::RequestDestination::kEmpty));
+  EXPECT_FALSE(storage2->GetDictionarySync(GURL("https://origin2.test/p1?"),
+                                           mojom::RequestDestination::kEmpty));
+  EXPECT_TRUE(storage2->GetDictionarySync(GURL("https://origin2.test/p2?"),
+                                          mojom::RequestDestination::kEmpty));
 }
 
 TEST_P(SharedDictionaryManagerTest, CacheEvictionPerSiteSizeExceeded) {
@@ -1371,11 +1583,14 @@
   if (GetManagerType() == TestManagerType::kOnDisk) {
     FlushCacheTasks();
   }
-  EXPECT_TRUE(storage1->GetDictionarySync(GURL("https://origin1.test/p?")));
+  EXPECT_TRUE(storage1->GetDictionarySync(GURL("https://origin1.test/p?"),
+                                          mojom::RequestDestination::kEmpty));
   task_environment_.FastForwardBy(base::Seconds(1));
-  EXPECT_TRUE(storage2->GetDictionarySync(GURL("https://origin2.test/p?")));
+  EXPECT_TRUE(storage2->GetDictionarySync(GURL("https://origin2.test/p?"),
+                                          mojom::RequestDestination::kEmpty));
   task_environment_.FastForwardBy(base::Seconds(1));
-  EXPECT_TRUE(storage3->GetDictionarySync(GURL("https://origin3.test/p?")));
+  EXPECT_TRUE(storage3->GetDictionarySync(GURL("https://origin3.test/p?"),
+                                          mojom::RequestDestination::kEmpty));
   task_environment_.FastForwardBy(base::Seconds(1));
 
   WriteDictionary(storage1.get(), GURL("https://origin4.test/d"), "p*",
@@ -1383,10 +1598,14 @@
   if (GetManagerType() == TestManagerType::kOnDisk) {
     FlushCacheTasks();
   }
-  EXPECT_FALSE(storage1->GetDictionarySync(GURL("https://origin1.test/p?")));
-  EXPECT_TRUE(storage2->GetDictionarySync(GURL("https://origin2.test/p?")));
-  EXPECT_TRUE(storage3->GetDictionarySync(GURL("https://origin3.test/p?")));
-  EXPECT_TRUE(storage1->GetDictionarySync(GURL("https://origin4.test/p?")));
+  EXPECT_FALSE(storage1->GetDictionarySync(GURL("https://origin1.test/p?"),
+                                           mojom::RequestDestination::kEmpty));
+  EXPECT_TRUE(storage2->GetDictionarySync(GURL("https://origin2.test/p?"),
+                                          mojom::RequestDestination::kEmpty));
+  EXPECT_TRUE(storage3->GetDictionarySync(GURL("https://origin3.test/p?"),
+                                          mojom::RequestDestination::kEmpty));
+  EXPECT_TRUE(storage1->GetDictionarySync(GURL("https://origin4.test/p?"),
+                                          mojom::RequestDestination::kEmpty));
 }
 
 TEST_P(SharedDictionaryManagerTest,
@@ -1413,7 +1632,8 @@
 
   for (size_t i = 0; i < cache_max_count_per_site; ++i) {
     EXPECT_TRUE(storage->GetDictionarySync(
-        GURL(base::StringPrintf("https://origin.test/p%03" PRIuS "?", i))));
+        GURL(base::StringPrintf("https://origin.test/p%03" PRIuS "?", i)),
+        mojom::RequestDestination::kEmpty));
     task_environment_.FastForwardBy(base::Seconds(1));
   }
 
@@ -1428,12 +1648,14 @@
   }
   task_environment_.FastForwardBy(base::Seconds(1));
 
-  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/p000?")));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/p000?"),
+                                          mojom::RequestDestination::kEmpty));
 
   // Newer dictionaries must not be evicted.
   for (size_t i = 1; i <= cache_max_count_per_site; ++i) {
     EXPECT_TRUE(storage->GetDictionarySync(
-        GURL(base::StringPrintf("https://origin.test/p%03" PRIuS "?", i))));
+        GURL(base::StringPrintf("https://origin.test/p%03" PRIuS "?", i)),
+        mojom::RequestDestination::kEmpty));
   }
 }
 
@@ -1463,7 +1685,8 @@
 
   for (size_t i = 0; i < cache_max_count_per_site; ++i) {
     EXPECT_TRUE(storage->GetDictionarySync(
-        GURL(base::StringPrintf("https://origin.test/p%03" PRIuS "?", i))));
+        GURL(base::StringPrintf("https://origin.test/p%03" PRIuS "?", i)),
+        mojom::RequestDestination::kEmpty));
     task_environment_.FastForwardBy(base::Seconds(1));
   }
 
@@ -1478,12 +1701,14 @@
   }
   task_environment_.FastForwardBy(base::Seconds(1));
 
-  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/p000?")));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/p000?"),
+                                          mojom::RequestDestination::kEmpty));
 
   // Newer dictionaries must not be evicted.
   for (size_t i = 1; i <= cache_max_count_per_site; ++i) {
     EXPECT_TRUE(storage->GetDictionarySync(
-        GURL(base::StringPrintf("https://origin.test/p%03" PRIuS "?", i))));
+        GURL(base::StringPrintf("https://origin.test/p%03" PRIuS "?", i)),
+        mojom::RequestDestination::kEmpty));
   }
 }
 
@@ -1513,7 +1738,8 @@
 
   for (size_t i = 0; i < cache_max_count_per_site; ++i) {
     EXPECT_TRUE(storage->GetDictionarySync(
-        GURL(base::StringPrintf("https://origin.test/p%03" PRIuS "?", i))));
+        GURL(base::StringPrintf("https://origin.test/p%03" PRIuS "?", i)),
+        mojom::RequestDestination::kEmpty));
     task_environment_.FastForwardBy(base::Seconds(1));
   }
 
@@ -1530,13 +1756,16 @@
 
   // The last dictionary size is kTestData1.size() * 2. So the oldest two
   // dictionaries must be evicted.
-  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/p000?")));
-  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/p001?")));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/p000?"),
+                                          mojom::RequestDestination::kEmpty));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/p001?"),
+                                          mojom::RequestDestination::kEmpty));
 
   // Newer dictionaries must not be deleted.
   for (size_t i = 2; i <= cache_max_count_per_site; ++i) {
     EXPECT_TRUE(storage->GetDictionarySync(
-        GURL(base::StringPrintf("https://origin.test/p%03" PRIuS "?", i))));
+        GURL(base::StringPrintf("https://origin.test/p%03" PRIuS "?", i)),
+        mojom::RequestDestination::kEmpty));
   }
 }
 
@@ -1570,9 +1799,12 @@
                      run_loop.QuitClosure());
   run_loop.Run();
 
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p1?")));
-  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/p2?")));
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p3?")));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p1?"),
+                                         mojom::RequestDestination::kEmpty));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/p2?"),
+                                          mojom::RequestDestination::kEmpty));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p3?"),
+                                         mojom::RequestDestination::kEmpty));
 }
 
 TEST_P(SharedDictionaryManagerTest, ClearDataMatchTopFrameSite) {
@@ -1605,9 +1837,12 @@
                      run_loop.QuitClosure());
   run_loop.Run();
 
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p1?")));
-  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/p2?")));
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p3?")));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p1?"),
+                                         mojom::RequestDestination::kEmpty));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/p2?"),
+                                          mojom::RequestDestination::kEmpty));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p3?"),
+                                         mojom::RequestDestination::kEmpty));
 }
 
 TEST_P(SharedDictionaryManagerTest, ClearDataMatchDictionaryUrl) {
@@ -1640,9 +1875,12 @@
                      run_loop.QuitClosure());
   run_loop.Run();
 
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://target.test/p1?")));
-  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://target.test/p2?")));
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://target.test/p3?")));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://target.test/p1?"),
+                                         mojom::RequestDestination::kEmpty));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://target.test/p2?"),
+                                          mojom::RequestDestination::kEmpty));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://target.test/p3?"),
+                                         mojom::RequestDestination::kEmpty));
 }
 
 TEST_P(SharedDictionaryManagerTest, ClearDataNullUrlMatcher) {
@@ -1672,9 +1910,12 @@
       base::RepeatingCallback<bool(const GURL&)>(), run_loop.QuitClosure());
   run_loop.Run();
 
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p1?")));
-  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/p2?")));
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p3?")));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p1?"),
+                                         mojom::RequestDestination::kEmpty));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/p2?"),
+                                          mojom::RequestDestination::kEmpty));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p3?"),
+                                         mojom::RequestDestination::kEmpty));
 }
 
 TEST_P(SharedDictionaryManagerTest, ClearDataDoNotInvalidateActiveDictionary) {
@@ -1703,8 +1944,8 @@
   }
 
   // Get a dictionary before calling ClearData().
-  std::unique_ptr<SharedDictionary> dict =
-      storage->GetDictionarySync(GURL("https://origin.test/p2?"));
+  std::unique_ptr<SharedDictionary> dict = storage->GetDictionarySync(
+      GURL("https://origin.test/p2?"), mojom::RequestDestination::kEmpty);
   ASSERT_TRUE(dict);
 
   base::RunLoop run_loop;
@@ -1713,9 +1954,12 @@
       base::RepeatingCallback<bool(const GURL&)>(), run_loop.QuitClosure());
   run_loop.Run();
 
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p1?")));
-  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/p2?")));
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p3?")));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p1?"),
+                                         mojom::RequestDestination::kEmpty));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/p2?"),
+                                          mojom::RequestDestination::kEmpty));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p3?"),
+                                         mojom::RequestDestination::kEmpty));
 
   // We can still read the deleted dictionary from `dict`.
   net::TestCompletionCallback read_callback;
@@ -1754,19 +1998,27 @@
     FlushCacheTasks();
   }
 
-  EXPECT_TRUE(storage1->GetDictionarySync(GURL("https://origin1.test/p1?")));
-  EXPECT_TRUE(storage1->GetDictionarySync(GURL("https://origin1.test/p2?")));
-  EXPECT_TRUE(storage2->GetDictionarySync(GURL("https://origin2.test/p1?")));
-  EXPECT_TRUE(storage2->GetDictionarySync(GURL("https://origin2.test/p2?")));
+  EXPECT_TRUE(storage1->GetDictionarySync(GURL("https://origin1.test/p1?"),
+                                          mojom::RequestDestination::kEmpty));
+  EXPECT_TRUE(storage1->GetDictionarySync(GURL("https://origin1.test/p2?"),
+                                          mojom::RequestDestination::kEmpty));
+  EXPECT_TRUE(storage2->GetDictionarySync(GURL("https://origin2.test/p1?"),
+                                          mojom::RequestDestination::kEmpty));
+  EXPECT_TRUE(storage2->GetDictionarySync(GURL("https://origin2.test/p2?"),
+                                          mojom::RequestDestination::kEmpty));
 
   base::RunLoop run_loop;
   manager->ClearDataForIsolationKey(isolation_key1, run_loop.QuitClosure());
   run_loop.Run();
 
-  EXPECT_FALSE(storage1->GetDictionarySync(GURL("https://origin1.test/p1?")));
-  EXPECT_FALSE(storage1->GetDictionarySync(GURL("https://origin1.test/p2?")));
-  EXPECT_TRUE(storage2->GetDictionarySync(GURL("https://origin2.test/p1?")));
-  EXPECT_TRUE(storage2->GetDictionarySync(GURL("https://origin2.test/p2?")));
+  EXPECT_FALSE(storage1->GetDictionarySync(GURL("https://origin1.test/p1?"),
+                                           mojom::RequestDestination::kEmpty));
+  EXPECT_FALSE(storage1->GetDictionarySync(GURL("https://origin1.test/p2?"),
+                                           mojom::RequestDestination::kEmpty));
+  EXPECT_TRUE(storage2->GetDictionarySync(GURL("https://origin2.test/p1?"),
+                                          mojom::RequestDestination::kEmpty));
+  EXPECT_TRUE(storage2->GetDictionarySync(GURL("https://origin2.test/p2?"),
+                                          mojom::RequestDestination::kEmpty));
 }
 
 TEST_P(SharedDictionaryManagerTest, GetUsageInfo) {
@@ -1861,7 +2113,8 @@
 
   task_environment_.FastForwardBy(base::Seconds(1));
   // Update `last_used_time`.
-  EXPECT_TRUE(storage1->GetDictionarySync(GURL("https://origin1.test/p2?")));
+  EXPECT_TRUE(storage1->GetDictionarySync(GURL("https://origin1.test/p2?"),
+                                          mojom::RequestDestination::kEmpty));
 
   std::vector<network::mojom::SharedDictionaryInfoPtr> result1 =
       GetSharedDictionaryInfo(manager.get(), isolation_key1);
@@ -1980,22 +2233,28 @@
 
   task_environment_.FastForwardBy(base::Seconds(4));
 
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p1?")));
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p2?")));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p1?"),
+                                         mojom::RequestDestination::kEmpty));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p2?"),
+                                         mojom::RequestDestination::kEmpty));
 
   task_environment_.FastForwardBy(base::Seconds(1));
 
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p1?")));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p1?"),
+                                         mojom::RequestDestination::kEmpty));
 
   EXPECT_EQ(2u, GetSharedDictionaryInfo(manager.get(), isolation_key).size());
-  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/p2?")));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/p2?"),
+                                          mojom::RequestDestination::kEmpty));
   EXPECT_EQ(1u, GetSharedDictionaryInfo(manager.get(), isolation_key).size());
 
   task_environment_.FastForwardBy(base::Seconds(4));
-  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p1?")));
+  EXPECT_TRUE(storage->GetDictionarySync(GURL("https://origin.test/p1?"),
+                                         mojom::RequestDestination::kEmpty));
   task_environment_.FastForwardBy(base::Seconds(1));
   EXPECT_EQ(1u, GetSharedDictionaryInfo(manager.get(), isolation_key).size());
-  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/p1?")));
+  EXPECT_FALSE(storage->GetDictionarySync(GURL("https://origin.test/p1?"),
+                                          mojom::RequestDestination::kEmpty));
   EXPECT_TRUE(GetSharedDictionaryInfo(manager.get(), isolation_key).empty());
 }
 
diff --git a/services/network/shared_dictionary/shared_dictionary_network_transaction.cc b/services/network/shared_dictionary/shared_dictionary_network_transaction.cc
index 0549a09..d90972a2 100644
--- a/services/network/shared_dictionary/shared_dictionary_network_transaction.cc
+++ b/services/network/shared_dictionary/shared_dictionary_network_transaction.cc
@@ -34,7 +34,9 @@
 #include "net/http/http_request_info.h"
 #include "net/ssl/ssl_private_key.h"
 #include "services/network/public/cpp/features.h"
+#include "services/network/public/cpp/request_destination.h"
 #include "services/network/public/cpp/shared_dictionary_encoding_names.h"
+#include "services/network/public/mojom/fetch_api.mojom-shared.h"
 #include "services/network/shared_dictionary/shared_dictionary.h"
 #include "services/network/shared_dictionary/shared_dictionary_constants.h"
 #include "services/network/shared_dictionary/shared_dictionary_manager.h"
@@ -213,8 +215,22 @@
   // `shared_dictionary_` may have been already set if this transaction was
   // restarted
   if (!shared_dictionary_) {
-    shared_dictionary_ =
-        shared_dictionary_storage_->GetDictionarySync(request_url);
+    // This method is called via net/ layer where we can't get
+    // mojom::RequestDestination from the request. So retrieves the destination
+    // from the request headers.
+    std::optional<mojom::RequestDestination> destination;
+    std::string destination_string;
+    if (request_headers->GetHeader("sec-fetch-dest", &destination_string)) {
+      destination = RequestDestinationFromString(
+          destination_string,
+          EmptyRequestDestinationOption::kUseFiveCharEmptyString);
+    }
+    if (destination) {
+      shared_dictionary_ = shared_dictionary_storage_->GetDictionarySync(
+          request_url, *destination);
+    } else {
+      shared_dictionary_.reset();
+    }
   }
   if (!shared_dictionary_) {
     return;
diff --git a/services/network/shared_dictionary/shared_dictionary_network_transaction_unittest.cc b/services/network/shared_dictionary/shared_dictionary_network_transaction_unittest.cc
index b00a2327..976b2a7 100644
--- a/services/network/shared_dictionary/shared_dictionary_network_transaction_unittest.cc
+++ b/services/network/shared_dictionary/shared_dictionary_network_transaction_unittest.cc
@@ -123,23 +123,30 @@
 
   // SharedDictionaryStorage
   std::unique_ptr<SharedDictionary> GetDictionarySync(
-      const GURL& url) override {
+      const GURL& url,
+      mojom::RequestDestination destination) override {
     return std::move(dictionary_);
   }
   void GetDictionary(const GURL& url,
+                     mojom::RequestDestination destination,
                      base::OnceCallback<void(std::unique_ptr<SharedDictionary>)>
                          callback) override {}
   scoped_refptr<SharedDictionaryWriter> CreateWriter(
       const GURL& url,
       base::Time response_time,
       base::TimeDelta expiration,
-      const std::string& match) override {
+      const std::string& match,
+      const std::set<mojom::RequestDestination>& match_dest,
+      const std::string& id) override {
     return nullptr;
   }
-  bool IsAlreadyRegistered(const GURL& url,
-                           base::Time response_time,
-                           base::TimeDelta expiration,
-                           const std::string& match) override {
+  bool IsAlreadyRegistered(
+      const GURL& url,
+      base::Time response_time,
+      base::TimeDelta expiration,
+      const std::string& match,
+      const std::set<mojom::RequestDestination>& match_dest,
+      const std::string& id) override {
     return false;
   }
 
@@ -266,7 +273,7 @@
     .url = "https://test.example/test",
     .method = "GET",
     .request_time = base::Time(),
-    .request_headers = "",
+    .request_headers = "sec-fetch-dest: document\r\n",
     .load_flags = net::LOAD_CAN_USE_SHARED_DICTIONARY,
     .transport_info = TestSpdyTransportInfo(),
     .status = "HTTP/1.1 200 OK",
@@ -292,7 +299,7 @@
     .url = "https://test.example/test",
     .method = "GET",
     .request_time = base::Time(),
-    .request_headers = "",
+    .request_headers = "sec-fetch-dest: document\r\n",
     .load_flags = net::LOAD_CAN_USE_SHARED_DICTIONARY,
     .transport_info = TestSpdyTransportInfo(),
     .status = "HTTP/1.1 200 OK",
@@ -318,7 +325,7 @@
     .url = "https://test.example/test",
     .method = "GET",
     .request_time = base::Time(),
-    .request_headers = "",
+    .request_headers = "sec-fetch-dest: document\r\n",
     .load_flags = net::LOAD_CAN_USE_SHARED_DICTIONARY,
     .transport_info = TestSpdyTransportInfo(),
     .status = "HTTP/1.1 200 OK",
diff --git a/services/network/shared_dictionary/shared_dictionary_storage.cc b/services/network/shared_dictionary/shared_dictionary_storage.cc
index 3c1c0ed4..27bd5da 100644
--- a/services/network/shared_dictionary/shared_dictionary_storage.cc
+++ b/services/network/shared_dictionary/shared_dictionary_storage.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <optional>
 #include <string_view>
+#include <vector>
 
 #include "base/containers/contains.h"
 #include "base/feature_list.h"
@@ -17,6 +18,8 @@
 #include "net/http/http_response_headers.h"
 #include "net/http/structured_headers.h"
 #include "services/network/public/cpp/features.h"
+#include "services/network/public/cpp/request_destination.h"
+#include "services/network/public/mojom/fetch_api.mojom-shared.h"
 #include "services/network/shared_dictionary/shared_dictionary_constants.h"
 #include "services/network/shared_dictionary/shared_dictionary_writer.h"
 #include "url/gurl.h"
@@ -31,18 +34,24 @@
 class DictionaryHeaderInfo {
  public:
   DictionaryHeaderInfo(std::string match,
+                       std::set<network::mojom::RequestDestination> match_dest,
                        std::optional<base::TimeDelta> expiration,
-                       std::string type)
+                       std::string type,
+                       std::string id)
       : match(std::move(match)),
+        match_dest(std::move(match_dest)),
         expiration(expiration),
-        type(std::move(type)) {}
+        type(std::move(type)),
+        id(std::move(id)) {}
   ~DictionaryHeaderInfo() = default;
 
   std::string match;
+  std::set<network::mojom::RequestDestination> match_dest;
   // TODO(crbug.com/1413922): Stop using std::optional when we remove V1 backend
   // support.
   std::optional<base::TimeDelta> expiration;
   std::string type;
+  std::string id;
 };
 
 std::optional<DictionaryHeaderInfo> ParseDictionaryHeaderInfo(
@@ -61,15 +70,26 @@
     return std::nullopt;
   }
 
-  // Don't use the value of `expires` in the `Use-As-Dictionary` response header
-  // when V2 backend is enabled.
-  const bool check_expires_dictionary_value =
+  const bool is_v1 =
       features::kCompressionDictionaryTransportBackendVersion.Get() ==
       features::CompressionDictionaryTransportBackendVersion::kV1;
+  // Don't use the value of `expires` in the `Use-As-Dictionary` response header
+  // when V2 backend is enabled.
+  const bool check_expires_dictionary_value = is_v1;
+  // Don't use the value of `match-dest` in the `Use-As-Dictionary` response
+  // header when V1 backend is enabled.
+  const bool check_match_dest_dictionary_value = !is_v1;
+  // Don't use the value of `id` in the `Use-As-Dictionary` response header when
+  // V1 backend is enabled.
+  const bool check_id_dictionary_value = !is_v1;
 
   std::optional<std::string> match_value;
+  // Maybe we don't need to support multiple match-dest.
+  // https://github.com/httpwg/http-extensions/issues/2722
+  std::set<network::mojom::RequestDestination> match_dest_values;
   std::optional<base::TimeDelta> expires_value;
   std::string type_value = std::string(kDefaultTypeRaw);
+  std::string id_value;
   for (const auto& entry : dictionary.value()) {
     if (entry.first == shared_dictionary::kOptionNameMatch) {
       if ((entry.second.member.size() != 1u) ||
@@ -77,6 +97,26 @@
         return std::nullopt;
       }
       match_value = entry.second.member.front().item.GetString();
+    } else if (check_match_dest_dictionary_value &&
+               entry.first == shared_dictionary::kOptionNameMatchDest) {
+      if (!entry.second.member_is_inner_list) {
+        // `match-dest` must be a list.
+        return std::nullopt;
+      }
+      for (const auto& item : entry.second.member) {
+        if (!item.item.is_string()) {
+          return std::nullopt;
+        }
+        // We use the empty string "" for RequestDestination::kEmpty in
+        // `match-dest`.
+        std::optional<network::mojom::RequestDestination> dest_value =
+            RequestDestinationFromString(
+                item.item.GetString(),
+                EmptyRequestDestinationOption::kUseTheEmptyString);
+        if (dest_value) {
+          match_dest_values.insert(*dest_value);
+        }
+      }
     } else if (check_expires_dictionary_value &&
                entry.first == shared_dictionary::kOptionNameExpires) {
       if ((entry.second.member.size() != 1u) ||
@@ -91,6 +131,16 @@
         return std::nullopt;
       }
       type_value = entry.second.member.front().item.GetString();
+    } else if (check_id_dictionary_value &&
+               entry.first == shared_dictionary::kOptionNameId) {
+      if ((entry.second.member.size() != 1u) ||
+          !entry.second.member.front().item.is_string()) {
+        return std::nullopt;
+      }
+      id_value = entry.second.member.front().item.GetString();
+      if (id_value.size() > shared_dictionary::kDictionaryIdMaxLength) {
+        return std::nullopt;
+      }
     }
   }
 
@@ -114,8 +164,9 @@
   if (!match_value) {
     return std::nullopt;
   }
-  return DictionaryHeaderInfo(std::move(*match_value), std::move(expires_value),
-                              std::move(type_value));
+  return DictionaryHeaderInfo(
+      std::move(*match_value), std::move(match_dest_values),
+      std::move(expires_value), std::move(type_value), std::move(id_value));
 }
 
 }  // namespace
@@ -167,7 +218,8 @@
   // dictionary storage has its own cache eviction logic, which is different
   // from the HTTP Caches's eviction logic.
   if (was_fetched_via_cache &&
-      IsAlreadyRegistered(url, response_time, expiration, info->match)) {
+      IsAlreadyRegistered(url, response_time, expiration, info->match,
+                          info->match_dest, info->id)) {
     return nullptr;
   }
 
@@ -175,7 +227,8 @@
     return nullptr;
   }
 
-  return CreateWriter(url, response_time, expiration, info->match);
+  return CreateWriter(url, response_time, expiration, info->match,
+                      info->match_dest, info->id);
 }
 
 }  // namespace network
diff --git a/services/network/shared_dictionary/shared_dictionary_storage.h b/services/network/shared_dictionary/shared_dictionary_storage.h
index 99d64754..a73c7fa8 100644
--- a/services/network/shared_dictionary/shared_dictionary_storage.h
+++ b/services/network/shared_dictionary/shared_dictionary_storage.h
@@ -10,6 +10,7 @@
 #include <string>
 
 #include "base/component_export.h"
+#include "base/containers/contains.h"
 #include "base/functional/callback.h"
 #include "base/memory/ref_counted.h"
 #include "base/strings/pattern.h"
@@ -24,6 +25,9 @@
 }  // namespace net
 
 namespace network {
+namespace mojom {
+enum class RequestDestination : int32_t;
+}  // namespace mojom
 
 class SharedDictionary;
 class SharedDictionaryWriter;
@@ -39,7 +43,8 @@
   // Returns a matching SharedDictionary for `url`. If the metadata has not been
   // read from the database, this method returns nullptr.
   virtual std::unique_ptr<SharedDictionary> GetDictionarySync(
-      const GURL& url) = 0;
+      const GURL& url,
+      mojom::RequestDestination destination) = 0;
 
   // If the metadata has already been read from the database, this method calls
   // `callback` synchronously with a matching `SharedDictionary`. Otherwise,
@@ -47,6 +52,7 @@
   // `callback` with a matching `SharedDictionary`.
   virtual void GetDictionary(
       const GURL& url,
+      mojom::RequestDestination destination,
       base::OnceCallback<void(std::unique_ptr<SharedDictionary>)> callback) = 0;
 
   // Returns a SharedDictionaryWriter if `headers` has a valid
@@ -75,13 +81,18 @@
       const GURL& url,
       base::Time response_time,
       base::TimeDelta expiration,
-      const std::string& match) = 0;
+      const std::string& match,
+      const std::set<mojom::RequestDestination>& match_dest,
+      const std::string& id) = 0;
 
   // Called to avoid registering the same dictionary from the disk cache.
-  virtual bool IsAlreadyRegistered(const GURL& url,
-                                   base::Time response_time,
-                                   base::TimeDelta expiration,
-                                   const std::string& match) = 0;
+  virtual bool IsAlreadyRegistered(
+      const GURL& url,
+      base::Time response_time,
+      base::TimeDelta expiration,
+      const std::string& match,
+      const std::set<mojom::RequestDestination>& match_dest,
+      const std::string& id) = 0;
 };
 
 // Returns a matching dictionary for `url` from `dictionary_info_map`.
@@ -90,9 +101,12 @@
 // DictionaryInfoType.
 template <class DictionaryInfoType>
 DictionaryInfoType* GetMatchingDictionaryFromDictionaryInfoMap(
-    std::map<url::SchemeHostPort, std::map<std::string, DictionaryInfoType>>&
-        dictionary_info_map,
-    const GURL& url) {
+    std::map<
+        url::SchemeHostPort,
+        std::map<std::tuple<std::string, std::set<mojom::RequestDestination>>,
+                 DictionaryInfoType>>& dictionary_info_map,
+    const GURL& url,
+    mojom::RequestDestination destination) {
   auto it = dictionary_info_map.find(url::SchemeHostPort(url));
   if (it == dictionary_info_map.end()) {
     return nullptr;
@@ -100,13 +114,18 @@
   DictionaryInfoType* matched_info = nullptr;
   for (auto& item : it->second) {
     DictionaryInfoType& info = item.second;
-    CHECK_EQ(info.match(), item.first);
+    CHECK(std::make_tuple(info.match(), info.match_dest()) == item.first);
     if (matched_info &&
         ((matched_info->match().size() > info.match().size()) ||
          (matched_info->match().size() == info.match().size() &&
           matched_info->response_time() > info.response_time()))) {
       continue;
     }
+    // When `match_dest` is empty, we don't check the `destination`.
+    if (!info.match_dest().empty() &&
+        !base::Contains(info.match_dest(), destination)) {
+      continue;
+    }
     if (!info.matcher()) {
       // This is for V1 backend.
       // TODO(crbug.com/1413922): Remove this after V1 backend is removed.
@@ -130,23 +149,27 @@
 // DictionaryInfoType.
 template <class DictionaryInfoType>
 bool IsAlreadyRegisteredInDictionaryInfoMap(
-    std::map<url::SchemeHostPort, std::map<std::string, DictionaryInfoType>>&
-        dictionary_info_map,
+    std::map<
+        url::SchemeHostPort,
+        std::map<std::tuple<std::string, std::set<mojom::RequestDestination>>,
+                 DictionaryInfoType>>& dictionary_info_map,
     const GURL& url,
     base::Time response_time,
     base::TimeDelta expiration,
-    const std::string& match) {
+    const std::string& match,
+    const std::set<mojom::RequestDestination>& match_dest,
+    const std::string& id) {
   auto it1 = dictionary_info_map.find(url::SchemeHostPort(url));
   if (it1 == dictionary_info_map.end()) {
     return false;
   }
-  auto it2 = it1->second.find(match);
+  auto it2 = it1->second.find(std::make_tuple(match, match_dest));
   if (it2 == it1->second.end()) {
     return false;
   }
   return it2->second.url() == url &&
          it2->second.response_time() == response_time &&
-         it2->second.expiration() == expiration;
+         it2->second.expiration() == expiration && it2->second.id() == id;
 }
 
 }  // namespace network
diff --git a/services/network/shared_dictionary/shared_dictionary_storage_in_memory.cc b/services/network/shared_dictionary/shared_dictionary_storage_in_memory.cc
index 0cc0d45..68a3815e 100644
--- a/services/network/shared_dictionary/shared_dictionary_storage_in_memory.cc
+++ b/services/network/shared_dictionary/shared_dictionary_storage_in_memory.cc
@@ -30,16 +30,19 @@
 SharedDictionaryStorageInMemory::~SharedDictionaryStorageInMemory() = default;
 
 std::unique_ptr<SharedDictionary>
-SharedDictionaryStorageInMemory::GetDictionarySync(const GURL& url) {
-  DictionaryInfo* info =
-      GetMatchingDictionaryFromDictionaryInfoMap(dictionary_info_map_, url);
+SharedDictionaryStorageInMemory::GetDictionarySync(
+    const GURL& url,
+    mojom::RequestDestination destination) {
+  DictionaryInfo* info = GetMatchingDictionaryFromDictionaryInfoMap(
+      dictionary_info_map_, url, destination);
 
   if (!info) {
     return nullptr;
   }
 
   if (info->response_time() + info->expiration() <= base::Time::Now()) {
-    DeleteDictionary(url::SchemeHostPort(info->url()), info->match());
+    DeleteDictionary(url::SchemeHostPort(info->url()), info->match(),
+                     info->match_dest());
     return nullptr;
   }
   info->set_last_used_time(base::Time::Now());
@@ -49,16 +52,18 @@
 
 void SharedDictionaryStorageInMemory::GetDictionary(
     const GURL& url,
+    mojom::RequestDestination destination,
     base::OnceCallback<void(std::unique_ptr<SharedDictionary>)> callback) {
-  std::move(callback).Run(GetDictionarySync(url));
+  std::move(callback).Run(GetDictionarySync(url, destination));
 }
 
 void SharedDictionaryStorageInMemory::DeleteDictionary(
     const url::SchemeHostPort& host,
-    const std::string& match) {
+    const std::string& match,
+    const std::set<mojom::RequestDestination>& match_dest) {
   auto it = dictionary_info_map_.find(host);
   if (it != dictionary_info_map_.end()) {
-    it->second.erase(match);
+    it->second.erase(std::make_tuple(match, match_dest));
     if (it->second.empty()) {
       dictionary_info_map_.erase(it);
     }
@@ -102,10 +107,13 @@
 }
 
 scoped_refptr<SharedDictionaryWriter>
-SharedDictionaryStorageInMemory::CreateWriter(const GURL& url,
-                                              base::Time response_time,
-                                              base::TimeDelta expiration,
-                                              const std::string& match) {
+SharedDictionaryStorageInMemory::CreateWriter(
+    const GURL& url,
+    base::Time response_time,
+    base::TimeDelta expiration,
+    const std::string& match,
+    const std::set<mojom::RequestDestination>& match_dest,
+    const std::string& id) {
   std::unique_ptr<SimpleUrlPatternMatcher> matcher;
   if (NeedToUseUrlPatternMatcher()) {
     auto matcher_create_result = SimpleUrlPatternMatcher::Create(match, url);
@@ -117,16 +125,19 @@
   return base::MakeRefCounted<SharedDictionaryWriterInMemory>(
       base::BindOnce(&SharedDictionaryStorageInMemory::OnDictionaryWritten,
                      weak_factory_.GetWeakPtr(), url, response_time, expiration,
-                     match, std::move(matcher)));
+                     match, std::move(matcher), match_dest, id));
 }
 
 bool SharedDictionaryStorageInMemory::IsAlreadyRegistered(
     const GURL& url,
     base::Time response_time,
     base::TimeDelta expiration,
-    const std::string& match) {
-  return IsAlreadyRegisteredInDictionaryInfoMap(
-      dictionary_info_map_, url, response_time, expiration, match);
+    const std::string& match,
+    const std::set<mojom::RequestDestination>& match_dest,
+    const std::string& id) {
+  return IsAlreadyRegisteredInDictionaryInfoMap(dictionary_info_map_, url,
+                                                response_time, expiration,
+                                                match, match_dest, id);
 }
 
 void SharedDictionaryStorageInMemory::OnDictionaryWritten(
@@ -135,6 +146,8 @@
     base::TimeDelta expiration,
     const std::string& match,
     std::unique_ptr<SimpleUrlPatternMatcher> matcher,
+    const std::set<mojom::RequestDestination>& match_dest,
+    const std::string& id,
     SharedDictionaryWriterInMemory::Result result,
     scoped_refptr<net::IOBuffer> data,
     size_t size,
@@ -143,9 +156,10 @@
     return;
   }
   dictionary_info_map_[url::SchemeHostPort(url)].insert_or_assign(
-      match, DictionaryInfo(url, response_time, expiration, match,
-                            /*last_used_time=*/base::Time::Now(), data, size,
-                            hash, std::move(matcher)));
+      std::make_tuple(match, match_dest),
+      DictionaryInfo(url, response_time, expiration, match, match_dest, id,
+                     /*last_used_time=*/base::Time::Now(), data, size, hash,
+                     std::move(matcher)));
   if (manager_) {
     manager_->MaybeRunCacheEvictionPerSite(isolation_key_.top_frame_site());
     manager_->MaybeRunCacheEviction();
@@ -157,6 +171,8 @@
     base::Time response_time,
     base::TimeDelta expiration,
     const std::string& match,
+    std::set<mojom::RequestDestination> match_dest,
+    const std::string& id,
     base::Time last_used_time,
     scoped_refptr<net::IOBuffer> data,
     size_t size,
@@ -166,6 +182,8 @@
       response_time_(response_time),
       expiration_(expiration),
       match_(match),
+      match_dest_(std::move(match_dest)),
+      id_(id),
       last_used_time_(last_used_time),
       data_(std::move(data)),
       size_(size),
diff --git a/services/network/shared_dictionary/shared_dictionary_storage_in_memory.h b/services/network/shared_dictionary/shared_dictionary_storage_in_memory.h
index f06ad369..503c6f9 100644
--- a/services/network/shared_dictionary/shared_dictionary_storage_in_memory.h
+++ b/services/network/shared_dictionary/shared_dictionary_storage_in_memory.h
@@ -6,6 +6,7 @@
 #define SERVICES_NETWORK_SHARED_DICTIONARY_SHARED_DICTIONARY_STORAGE_IN_MEMORY_H_
 
 #include <map>
+#include <optional>
 #include <set>
 
 #include "base/containers/unique_ptr_adapters.h"
@@ -43,6 +44,8 @@
                    base::Time response_time,
                    base::TimeDelta expiration,
                    const std::string& match,
+                   std::set<mojom::RequestDestination> match_dest,
+                   const std::string& id,
                    base::Time last_used_time,
                    scoped_refptr<net::IOBuffer> data,
                    size_t size,
@@ -61,6 +64,10 @@
     const base::Time& response_time() const { return response_time_; }
     base::TimeDelta expiration() const { return expiration_; }
     const std::string& match() const { return match_; }
+    const std::set<mojom::RequestDestination>& match_dest() const {
+      return match_dest_;
+    }
+    const std::string& id() const { return id_; }
     const base::Time& last_used_time() const { return last_used_time_; }
     const scoped_refptr<net::IOBuffer>& data() const { return data_; }
     size_t size() const { return size_; }
@@ -76,6 +83,8 @@
     base::Time response_time_;
     base::TimeDelta expiration_;
     std::string match_;
+    std::set<mojom::RequestDestination> match_dest_;
+    std::string id_;
     base::Time last_used_time_;
     scoped_refptr<net::IOBuffer> data_;
     size_t size_;
@@ -94,27 +103,39 @@
       const SharedDictionaryStorageInMemory&) = delete;
 
   // SharedDictionaryStorage
-  std::unique_ptr<SharedDictionary> GetDictionarySync(const GURL& url) override;
+  std::unique_ptr<SharedDictionary> GetDictionarySync(
+      const GURL& url,
+      mojom::RequestDestination destination) override;
   void GetDictionary(const GURL& url,
+                     mojom::RequestDestination destination,
                      base::OnceCallback<void(std::unique_ptr<SharedDictionary>)>
                          callback) override;
   scoped_refptr<SharedDictionaryWriter> CreateWriter(
       const GURL& url,
       base::Time response_time,
       base::TimeDelta expiration,
-      const std::string& match) override;
-  bool IsAlreadyRegistered(const GURL& url,
-                           base::Time response_time,
-                           base::TimeDelta expiration,
-                           const std::string& match) override;
+      const std::string& match,
+      const std::set<mojom::RequestDestination>& match_dest,
+      const std::string& id) override;
+  bool IsAlreadyRegistered(
+      const GURL& url,
+      base::Time response_time,
+      base::TimeDelta expiration,
+      const std::string& match,
+      const std::set<mojom::RequestDestination>& match_dest,
+      const std::string& id) override;
 
-  const std::map<url::SchemeHostPort, std::map<std::string, DictionaryInfo>>&
+  const std::map<
+      url::SchemeHostPort,
+      std::map<std::tuple<std::string, std::set<mojom::RequestDestination>>,
+               DictionaryInfo>>&
   GetDictionaryMap() {
     return dictionary_info_map_;
   }
 
   void DeleteDictionary(const url::SchemeHostPort& host,
-                        const std::string& match);
+                        const std::string& match,
+                        const std::set<mojom::RequestDestination>& match_dest);
   void ClearData(base::Time start_time,
                  base::Time end_time,
                  base::RepeatingCallback<bool(const GURL&)> url_matcher);
@@ -127,21 +148,27 @@
   ~SharedDictionaryStorageInMemory() override;
 
   // Called when SharedDictionaryWriterInMemory::Finish() is called.
-  void OnDictionaryWritten(const GURL& url,
-                           base::Time response_time,
-                           base::TimeDelta expiration,
-                           const std::string& match,
-                           std::unique_ptr<SimpleUrlPatternMatcher> matcher,
-                           SharedDictionaryWriterInMemory::Result result,
-                           scoped_refptr<net::IOBuffer> data,
-                           size_t size,
-                           const net::SHA256HashValue& hash);
+  void OnDictionaryWritten(
+      const GURL& url,
+      base::Time response_time,
+      base::TimeDelta expiration,
+      const std::string& match,
+      std::unique_ptr<SimpleUrlPatternMatcher> matcher,
+      const std::set<mojom::RequestDestination>& match_dest,
+      const std::string& id,
+      SharedDictionaryWriterInMemory::Result result,
+      scoped_refptr<net::IOBuffer> data,
+      size_t size,
+      const net::SHA256HashValue& hash);
 
   base::WeakPtr<SharedDictionaryManagerInMemory> manager_;
   const net::SharedDictionaryIsolationKey isolation_key_;
   base::ScopedClosureRunner on_deleted_closure_runner_;
 
-  std::map<url::SchemeHostPort, std::map<std::string, DictionaryInfo>>
+  std::map<
+      url::SchemeHostPort,
+      std::map<std::tuple<std::string, std::set<mojom::RequestDestination>>,
+               DictionaryInfo>>
       dictionary_info_map_;
   base::WeakPtrFactory<SharedDictionaryStorageInMemory> weak_factory_{this};
 };
diff --git a/services/network/shared_dictionary/shared_dictionary_storage_on_disk.cc b/services/network/shared_dictionary/shared_dictionary_storage_on_disk.cc
index 90cb38c..26773a88 100644
--- a/services/network/shared_dictionary/shared_dictionary_storage_on_disk.cc
+++ b/services/network/shared_dictionary/shared_dictionary_storage_on_disk.cc
@@ -11,11 +11,13 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/pattern.h"
 #include "base/strings/strcat.h"
+#include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_id_helper.h"
 #include "net/base/io_buffer.h"
+#include "services/network/public/cpp/request_destination.h"
 #include "services/network/shared_dictionary/shared_dictionary_manager_on_disk.h"
 #include "services/network/shared_dictionary/shared_dictionary_on_disk.h"
 #include "services/network/shared_dictionary/shared_dictionary_writer_on_disk.h"
@@ -44,6 +46,23 @@
       time_delta);
 }
 
+std::set<mojom::RequestDestination> ToRequestDestinationSet(
+    std::string_view input) {
+  const std::vector<std::string_view> dest_strings = base::SplitStringPiece(
+      input, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+  std::set<mojom::RequestDestination> destinations;
+  for (const auto dest_string : dest_strings) {
+    auto dest = RequestDestinationFromString(
+        dest_string, EmptyRequestDestinationOption::kUseFiveCharEmptyString);
+    if (!dest) {
+      LOG(ERROR) << "Invalid request destination string: " << dest_string;
+      continue;
+    }
+    destinations.insert(*dest);
+  }
+  return destinations;
+}
+
 }  // namespace
 
 // This is a RefCounted subclass of SharedDictionaryOnDisk. This is used to
@@ -105,18 +124,19 @@
   scoped_refptr<RefCountedSharedDictionary> ref_counted_shared_dictionary_;
 };
 
-SharedDictionaryStorageOnDisk::DictionaryInfoWithMatcher::
-    DictionaryInfoWithMatcher(net::SharedDictionaryInfo info,
-                              std::unique_ptr<SimpleUrlPatternMatcher> matcher)
+SharedDictionaryStorageOnDisk::WrappedDictionaryInfo::WrappedDictionaryInfo(
+    net::SharedDictionaryInfo info,
+    std::unique_ptr<SimpleUrlPatternMatcher> matcher)
     : net::SharedDictionaryInfo(std::move(info)),
-      matcher_(std::move(matcher)) {}
-SharedDictionaryStorageOnDisk::DictionaryInfoWithMatcher::
-    ~DictionaryInfoWithMatcher() = default;
-SharedDictionaryStorageOnDisk::DictionaryInfoWithMatcher::
-    DictionaryInfoWithMatcher(DictionaryInfoWithMatcher&&) = default;
-SharedDictionaryStorageOnDisk::DictionaryInfoWithMatcher&
-SharedDictionaryStorageOnDisk::DictionaryInfoWithMatcher::operator=(
-    DictionaryInfoWithMatcher&&) = default;
+      matcher_(std::move(matcher)),
+      match_dest_(ToRequestDestinationSet(match_dest_string())) {}
+SharedDictionaryStorageOnDisk::WrappedDictionaryInfo::~WrappedDictionaryInfo() =
+    default;
+SharedDictionaryStorageOnDisk::WrappedDictionaryInfo::WrappedDictionaryInfo(
+    WrappedDictionaryInfo&&) = default;
+SharedDictionaryStorageOnDisk::WrappedDictionaryInfo&
+SharedDictionaryStorageOnDisk::WrappedDictionaryInfo::operator=(
+    WrappedDictionaryInfo&&) = default;
 
 SharedDictionaryStorageOnDisk::SharedDictionaryStorageOnDisk(
     base::WeakPtr<SharedDictionaryManagerOnDisk> manager,
@@ -144,7 +164,9 @@
 SharedDictionaryStorageOnDisk::~SharedDictionaryStorageOnDisk() = default;
 
 std::unique_ptr<SharedDictionary>
-SharedDictionaryStorageOnDisk::GetDictionarySync(const GURL& url) {
+SharedDictionaryStorageOnDisk::GetDictionarySync(
+    const GURL& url,
+    mojom::RequestDestination destination) {
   if (!get_dictionary_called_) {
     get_dictionary_called_ = true;
     base::UmaHistogramBoolean(
@@ -155,8 +177,8 @@
   if (!manager_) {
     return nullptr;
   }
-  net::SharedDictionaryInfo* info =
-      GetMatchingDictionaryFromDictionaryInfoMap(dictionary_info_map_, url);
+  net::SharedDictionaryInfo* info = GetMatchingDictionaryFromDictionaryInfoMap(
+      dictionary_info_map_, url, destination);
   if (!info) {
     return nullptr;
   }
@@ -193,21 +215,25 @@
 
 void SharedDictionaryStorageOnDisk::GetDictionary(
     const GURL& url,
+    mojom::RequestDestination destination,
     base::OnceCallback<void(std::unique_ptr<SharedDictionary>)> callback) {
   if (is_metadata_ready_) {
-    std::move(callback).Run(GetDictionarySync(url));
+    std::move(callback).Run(GetDictionarySync(url, destination));
     return;
   }
-  pending_get_dictionary_tasks_.emplace_back(
-      base::BindOnce(&SharedDictionaryStorageOnDisk::GetDictionary,
-                     weak_factory_.GetWeakPtr(), url, std::move(callback)));
+  pending_get_dictionary_tasks_.emplace_back(base::BindOnce(
+      &SharedDictionaryStorageOnDisk::GetDictionary, weak_factory_.GetWeakPtr(),
+      url, destination, std::move(callback)));
 }
 
 scoped_refptr<SharedDictionaryWriter>
-SharedDictionaryStorageOnDisk::CreateWriter(const GURL& url,
-                                            base::Time response_time,
-                                            base::TimeDelta expiration,
-                                            const std::string& match) {
+SharedDictionaryStorageOnDisk::CreateWriter(
+    const GURL& url,
+    base::Time response_time,
+    base::TimeDelta expiration,
+    const std::string& match,
+    const std::set<mojom::RequestDestination>& match_dest,
+    const std::string& id) {
   if (!manager_) {
     return nullptr;
   }
@@ -221,7 +247,7 @@
     matcher = std::move(matcher_create_result.value());
   }
   return manager_->CreateWriter(
-      isolation_key_, url, response_time, expiration, match,
+      isolation_key_, url, response_time, expiration, match, match_dest, id,
       base::BindOnce(&SharedDictionaryStorageOnDisk::OnDictionaryWritten,
                      weak_factory_.GetWeakPtr(), std::move(matcher)));
 }
@@ -230,9 +256,12 @@
     const GURL& url,
     base::Time response_time,
     base::TimeDelta expiration,
-    const std::string& match) {
-  return IsAlreadyRegisteredInDictionaryInfoMap(
-      dictionary_info_map_, url, response_time, expiration, match);
+    const std::string& match,
+    const std::set<mojom::RequestDestination>& match_dest,
+    const std::string& id) {
+  return IsAlreadyRegisteredInDictionaryInfoMap(dictionary_info_map_, url,
+                                                response_time, expiration,
+                                                match, match_dest, id);
 }
 
 void SharedDictionaryStorageOnDisk::OnDatabaseRead(
@@ -258,9 +287,10 @@
       }
       matcher = std::move(matcher_create_result.value());
     }
-
-    dictionary_info_map_[scheme_host_port].insert(std::make_pair(
-        match, DictionaryInfoWithMatcher(std::move(info), std::move(matcher))));
+    WrappedDictionaryInfo wrapped_info(std::move(info), std::move(matcher));
+    auto key = std::make_tuple(match, wrapped_info.match_dest());
+    dictionary_info_map_[scheme_host_port].insert(
+        std::make_pair(std::move(key), std::move(wrapped_info)));
   }
 
   auto callbacks = std::move(pending_get_dictionary_tasks_);
@@ -272,11 +302,12 @@
 void SharedDictionaryStorageOnDisk::OnDictionaryWritten(
     std::unique_ptr<SimpleUrlPatternMatcher> matcher,
     net::SharedDictionaryInfo info) {
-  const url::SchemeHostPort scheme_host_port = url::SchemeHostPort(info.url());
-  const std::string match = info.match();
-  (dictionary_info_map_[scheme_host_port])
-      .insert_or_assign(match, DictionaryInfoWithMatcher(std::move(info),
-                                                         std::move(matcher)));
+  WrappedDictionaryInfo wrapped_info(std::move(info), std::move(matcher));
+  const url::SchemeHostPort scheme_host_port =
+      url::SchemeHostPort(wrapped_info.url());
+  auto key = std::make_tuple(wrapped_info.match(), wrapped_info.match_dest());
+  dictionary_info_map_[scheme_host_port].insert_or_assign(
+      key, std::move(wrapped_info));
 }
 
 void SharedDictionaryStorageOnDisk::OnRefCountedSharedDictionaryDeleted(
diff --git a/services/network/shared_dictionary/shared_dictionary_storage_on_disk.h b/services/network/shared_dictionary/shared_dictionary_storage_on_disk.h
index 13e28d9..2a826147 100644
--- a/services/network/shared_dictionary/shared_dictionary_storage_on_disk.h
+++ b/services/network/shared_dictionary/shared_dictionary_storage_on_disk.h
@@ -33,6 +33,26 @@
 // A SharedDictionaryStorage which is managed by SharedDictionaryManagerOnDisk.
 class SharedDictionaryStorageOnDisk : public SharedDictionaryStorage {
  public:
+  class WrappedDictionaryInfo : public net::SharedDictionaryInfo {
+   public:
+    WrappedDictionaryInfo(net::SharedDictionaryInfo info,
+                          std::unique_ptr<SimpleUrlPatternMatcher> matcher);
+    ~WrappedDictionaryInfo();
+    WrappedDictionaryInfo(const WrappedDictionaryInfo&) = delete;
+    WrappedDictionaryInfo& operator=(const WrappedDictionaryInfo&) = delete;
+    WrappedDictionaryInfo(WrappedDictionaryInfo&&);
+    WrappedDictionaryInfo& operator=(WrappedDictionaryInfo&&);
+
+    const std::set<mojom::RequestDestination>& match_dest() const {
+      return match_dest_;
+    }
+    const SimpleUrlPatternMatcher* matcher() const { return matcher_.get(); }
+
+   private:
+    std::unique_ptr<SimpleUrlPatternMatcher> matcher_;
+    std::set<mojom::RequestDestination> match_dest_;
+  };
+
   SharedDictionaryStorageOnDisk(
       base::WeakPtr<SharedDictionaryManagerOnDisk> manager,
       const net::SharedDictionaryIsolationKey& isolation_key,
@@ -43,19 +63,27 @@
       const SharedDictionaryStorageOnDisk&) = delete;
 
   // SharedDictionaryStorage
-  std::unique_ptr<SharedDictionary> GetDictionarySync(const GURL& url) override;
+  std::unique_ptr<SharedDictionary> GetDictionarySync(
+      const GURL& url,
+      mojom::RequestDestination destination) override;
   void GetDictionary(const GURL& url,
+                     mojom::RequestDestination destination,
                      base::OnceCallback<void(std::unique_ptr<SharedDictionary>)>
                          callback) override;
   scoped_refptr<SharedDictionaryWriter> CreateWriter(
       const GURL& url,
       base::Time response_time,
       base::TimeDelta expiration,
-      const std::string& match) override;
-  bool IsAlreadyRegistered(const GURL& url,
-                           base::Time response_time,
-                           base::TimeDelta expiration,
-                           const std::string& match) override;
+      const std::string& match,
+      const std::set<mojom::RequestDestination>& match_dest,
+      const std::string& id) override;
+  bool IsAlreadyRegistered(
+      const GURL& url,
+      base::Time response_time,
+      base::TimeDelta expiration,
+      const std::string& match,
+      const std::set<mojom::RequestDestination>& match_dest,
+      const std::string& id) override;
 
   // Called from `SharedDictionaryManagerOnDisk` when dictionary has been
   // deleted.
@@ -72,23 +100,6 @@
   class RefCountedSharedDictionary;
   class WrappedSharedDictionary;
 
-  class DictionaryInfoWithMatcher : public net::SharedDictionaryInfo {
-   public:
-    DictionaryInfoWithMatcher(net::SharedDictionaryInfo info,
-                              std::unique_ptr<SimpleUrlPatternMatcher> matcher);
-    ~DictionaryInfoWithMatcher();
-    DictionaryInfoWithMatcher(const DictionaryInfoWithMatcher&) = delete;
-    DictionaryInfoWithMatcher& operator=(const DictionaryInfoWithMatcher&) =
-        delete;
-    DictionaryInfoWithMatcher(DictionaryInfoWithMatcher&&);
-    DictionaryInfoWithMatcher& operator=(DictionaryInfoWithMatcher&&);
-
-    const SimpleUrlPatternMatcher* matcher() const { return matcher_.get(); }
-
-   private:
-    std::unique_ptr<SimpleUrlPatternMatcher> matcher_;
-  };
-
   void OnDatabaseRead(
       net::SQLitePersistentSharedDictionaryStore::DictionaryListOrError result);
   void OnDictionaryWritten(std::unique_ptr<SimpleUrlPatternMatcher> matcher,
@@ -96,8 +107,10 @@
   void OnRefCountedSharedDictionaryDeleted(
       const base::UnguessableToken& disk_cache_key_token);
 
-  const std::map<url::SchemeHostPort,
-                 std::map<std::string, DictionaryInfoWithMatcher>>&
+  const std::map<
+      url::SchemeHostPort,
+      std::map<std::tuple<std::string, std::set<mojom::RequestDestination>>,
+               WrappedDictionaryInfo>>&
   GetDictionaryMapForTesting() {
     return dictionary_info_map_;
   }
@@ -105,9 +118,12 @@
   base::WeakPtr<SharedDictionaryManagerOnDisk> manager_;
   const net::SharedDictionaryIsolationKey isolation_key_;
   base::ScopedClosureRunner on_deleted_closure_runner_;
-  std::map<url::SchemeHostPort,
-           std::map<std::string, DictionaryInfoWithMatcher>>
+  std::map<
+      url::SchemeHostPort,
+      std::map<std::tuple<std::string, std::set<mojom::RequestDestination>>,
+               WrappedDictionaryInfo>>
       dictionary_info_map_;
+
   std::map<base::UnguessableToken, raw_ptr<RefCountedSharedDictionary>>
       dictionaries_;
 
diff --git a/services/webnn/dml/adapter.cc b/services/webnn/dml/adapter.cc
index 9e24b66..a9af33a 100644
--- a/services/webnn/dml/adapter.cc
+++ b/services/webnn/dml/adapter.cc
@@ -59,28 +59,32 @@
 base::expected<scoped_refptr<Adapter>, mojom::ErrorPtr> Adapter::Create(
     ComPtr<IDXGIAdapter> dxgi_adapter,
     DML_FEATURE_LEVEL min_feature_level_required) {
-  PlatformFunctions* platformFunctions = PlatformFunctions::GetInstance();
-  if (!platformFunctions) {
+  PlatformFunctions* platform_functions = PlatformFunctions::GetInstance();
+  if (!platform_functions) {
     return base::unexpected(
         CreateError(mojom::Error::Code::kUnknownError,
                     "Failed to load all required libraries or functions "
                     "on this platform."));
   }
 
-  if (is_debug_layer_enabled_) {
+  bool is_d3d12_debug_layer_enabled = false;
+  // Enable the d3d12 debug layer mainly for services_unittests.exe.
+  if (enable_d3d12_debug_layer_for_testing_) {
     // Enable the D3D12 debug layer.
     // Must be called before the D3D12 device is created.
     auto d3d12_get_debug_interface_proc =
-        platformFunctions->d3d12_get_debug_interface_proc();
+        platform_functions->d3d12_get_debug_interface_proc();
     ComPtr<ID3D12Debug> d3d12_debug;
     if (SUCCEEDED(d3d12_get_debug_interface_proc(IID_PPV_ARGS(&d3d12_debug)))) {
       d3d12_debug->EnableDebugLayer();
+      is_d3d12_debug_layer_enabled = true;
     }
   }
 
   // Create d3d12 device.
   ComPtr<ID3D12Device> d3d12_device;
-  auto d3d12_create_device_proc = platformFunctions->d3d12_create_device_proc();
+  auto d3d12_create_device_proc =
+      platform_functions->d3d12_create_device_proc();
   HRESULT hr = d3d12_create_device_proc(
       dxgi_adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&d3d12_device));
   if (FAILED(hr)) {
@@ -90,19 +94,24 @@
                                         "Failed to create D3D12 device."));
   };
 
-  DML_CREATE_DEVICE_FLAGS flags = DML_CREATE_DEVICE_FLAG_NONE;
+  // The d3d12 debug layer can also be enabled via Microsoft (R) DirectX Control
+  // Panel (dxcpl.exe) for any executable apps by users.
+  if (!is_d3d12_debug_layer_enabled) {
+    ComPtr<ID3D12DebugDevice> debug_device;
+    // Ignore failure.
+    d3d12_device->QueryInterface(IID_PPV_ARGS(&debug_device));
+    is_d3d12_debug_layer_enabled = (debug_device != nullptr);
+  }
 
   // Enable the DML debug layer if the D3D12 debug layer was enabled.
-  if (is_debug_layer_enabled_) {
-    ComPtr<ID3D12DebugDevice> debug_device;
-    if (SUCCEEDED(d3d12_device->QueryInterface(IID_PPV_ARGS(&debug_device)))) {
-      flags |= DML_CREATE_DEVICE_FLAG_DEBUG;
-    }
+  DML_CREATE_DEVICE_FLAGS flags = DML_CREATE_DEVICE_FLAG_NONE;
+  if (is_d3d12_debug_layer_enabled) {
+    flags |= DML_CREATE_DEVICE_FLAG_DEBUG;
   }
 
   // Create dml device.
   ComPtr<IDMLDevice> dml_device;
-  auto dml_create_device_proc = platformFunctions->dml_create_device_proc();
+  auto dml_create_device_proc = platform_functions->dml_create_device_proc();
   hr = dml_create_device_proc(d3d12_device.Get(), flags,
                               IID_PPV_ARGS(&dml_device));
   if (FAILED(hr)) {
@@ -137,7 +146,7 @@
 // static
 void Adapter::EnableDebugLayerForTesting() {
   CHECK_IS_TEST();
-  is_debug_layer_enabled_ = true;
+  enable_d3d12_debug_layer_for_testing_ = true;
 }
 
 Adapter::Adapter(ComPtr<IDXGIAdapter> dxgi_adapter,
@@ -174,6 +183,6 @@
 
 Adapter* Adapter::instance_ = nullptr;
 
-bool Adapter::is_debug_layer_enabled_ = false;
+bool Adapter::enable_d3d12_debug_layer_for_testing_ = false;
 
 }  // namespace webnn::dml
diff --git a/services/webnn/dml/adapter.h b/services/webnn/dml/adapter.h
index 6d9054e2..9b8a7ad 100644
--- a/services/webnn/dml/adapter.h
+++ b/services/webnn/dml/adapter.h
@@ -95,7 +95,7 @@
 
   DML_FEATURE_LEVEL max_feature_level_supported_ = DML_FEATURE_LEVEL_1_0;
 
-  static bool is_debug_layer_enabled_;
+  static bool enable_d3d12_debug_layer_for_testing_;
 
   static Adapter* instance_;
 };
diff --git a/testing/buildbot/chrome.gpu.fyi.json b/testing/buildbot/chrome.gpu.fyi.json
index a93a4367..f67afbc 100644
--- a/testing/buildbot/chrome.gpu.fyi.json
+++ b/testing/buildbot/chrome.gpu.fyi.json
@@ -20,6 +20,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle",
         "name": "context_lost_passthrough_tests JACUZZI_RELEASE_LKGM",
         "resultdb": {
@@ -49,6 +50,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle",
         "name": "expected_color_pixel_passthrough_test JACUZZI_RELEASE_LKGM",
         "precommit_args": [
@@ -78,6 +80,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc",
         "name": "gpu_process_launch_tests JACUZZI_RELEASE_LKGM",
         "resultdb": {
@@ -102,6 +105,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc",
         "name": "hardware_accelerated_feature_tests JACUZZI_RELEASE_LKGM",
         "resultdb": {
@@ -130,6 +134,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc --force_high_performance_gpu",
         "name": "info_collection_tests JACUZZI_RELEASE_LKGM",
         "resultdb": {
@@ -160,6 +165,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle",
         "name": "pixel_skia_gold_passthrough_test JACUZZI_RELEASE_LKGM",
         "precommit_args": [
@@ -190,6 +196,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc --use-cmd-decoder=passthrough --use-gl=angle",
         "name": "screenshot_sync_passthrough_tests JACUZZI_RELEASE_LKGM",
         "resultdb": {
@@ -215,6 +222,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc",
         "name": "trace_test JACUZZI_RELEASE_LKGM",
         "resultdb": {
@@ -240,6 +248,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc",
         "name": "webcodecs_tests JACUZZI_RELEASE_LKGM",
         "resultdb": {
@@ -267,6 +276,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc --use-gl=angle --use-angle=gles --use-cmd-decoder=passthrough --force_high_performance_gpu",
         "name": "webgl2_conformance_gles_passthrough_tests JACUZZI_RELEASE_LKGM",
         "resultdb": {
@@ -294,6 +304,7 @@
         ],
         "autotest_name": "chromium_Graphics",
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "extra_browser_args": "--log-level=0 --js-flags=--expose-gc --use-gl=angle --use-angle=gles --use-cmd-decoder=passthrough --force_high_performance_gpu",
         "name": "webgl_conformance_gles_passthrough_tests JACUZZI_RELEASE_LKGM",
         "resultdb": {
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json
index 553b00c1..748c051 100644
--- a/testing/buildbot/chrome.json
+++ b/testing/buildbot/chrome.json
@@ -1677,6 +1677,7 @@
       {
         "autotest_name": "chromium",
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "name": "base_unittests JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM",
         "test": "base_unittests",
         "test_id_prefix": "ninja://base:base_unittests/",
@@ -1686,6 +1687,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "name": "chrome_all_tast_tests JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM",
         "shards": 20,
         "tast_expr": "STUB_STRING_TO_RUN_TAST_TESTS",
@@ -1700,6 +1702,7 @@
         "autotest_name": "tast.chrome-from-gcs",
         "ci_only": true,
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "experiment_percentage": 100,
         "name": "chrome_criticalstaging_tast_tests JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM",
         "shards": 3,
@@ -1715,6 +1718,7 @@
         "autotest_name": "tast.chrome-from-gcs",
         "ci_only": true,
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "experiment_percentage": 100,
         "name": "chrome_disabled_tast_tests JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM",
         "shards": 2,
@@ -1729,6 +1733,7 @@
       {
         "autotest_name": "chromium",
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "name": "chromeos_integration_tests JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM",
         "test": "chromeos_integration_tests",
         "test_id_prefix": "ninja://chrome/test:chromeos_integration_tests/",
@@ -1753,6 +1758,7 @@
         "autotest_name": "chromium",
         "cros_board": "octopus",
         "cros_model": "casta",
+        "dut_pool": "chrome",
         "name": "base_unittests OCTOPUS_RELEASE_CHROME_FROM_TLS_LKGM",
         "test": "base_unittests",
         "test_id_prefix": "ninja://base:base_unittests/",
@@ -1763,6 +1769,7 @@
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "octopus",
         "cros_model": "casta",
+        "dut_pool": "chrome",
         "name": "chrome_all_tast_tests OCTOPUS_RELEASE_CHROME_FROM_TLS_LKGM",
         "shards": 15,
         "tast_expr": "STUB_STRING_TO_RUN_TAST_TESTS",
@@ -1871,6 +1878,7 @@
       {
         "autotest_name": "chromium",
         "cros_board": "volteer",
+        "dut_pool": "chrome",
         "name": "base_unittests VOLTEER_RELEASE_LKGM",
         "test": "base_unittests",
         "test_id_prefix": "ninja://base:base_unittests/",
@@ -1880,6 +1888,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "volteer",
+        "dut_pool": "chrome",
         "name": "chrome_all_tast_tests VOLTEER_RELEASE_LKGM",
         "shards": 15,
         "tast_expr": "STUB_STRING_TO_RUN_TAST_TESTS",
@@ -1894,6 +1903,7 @@
         "autotest_name": "tast.chrome-from-gcs",
         "ci_only": true,
         "cros_board": "volteer",
+        "dut_pool": "chrome",
         "experiment_percentage": 100,
         "name": "chrome_criticalstaging_tast_tests VOLTEER_RELEASE_LKGM",
         "shards": 3,
@@ -1909,6 +1919,7 @@
         "autotest_name": "tast.chrome-from-gcs",
         "ci_only": true,
         "cros_board": "volteer",
+        "dut_pool": "chrome",
         "experiment_percentage": 100,
         "name": "chrome_disabled_tast_tests VOLTEER_RELEASE_LKGM",
         "shards": 2,
@@ -1923,6 +1934,7 @@
       {
         "autotest_name": "chromium",
         "cros_board": "volteer",
+        "dut_pool": "chrome",
         "name": "chromeos_integration_tests VOLTEER_RELEASE_LKGM",
         "test": "chromeos_integration_tests",
         "test_id_prefix": "ninja://chrome/test:chromeos_integration_tests/",
@@ -2474,6 +2486,7 @@
       {
         "autotest_name": "chromium",
         "cros_board": "strongbad",
+        "dut_pool": "chrome",
         "name": "chromeos_integration_tests STRONGBAD_RELEASE_LKGM",
         "test": "chromeos_integration_tests",
         "test_id_prefix": "ninja://chrome/test:chromeos_integration_tests/",
@@ -2483,6 +2496,7 @@
       {
         "autotest_name": "tast.lacros-from-gcs",
         "cros_board": "strongbad",
+        "dut_pool": "chrome",
         "name": "lacros_all_tast_tests STRONGBAD_RELEASE_LKGM",
         "resultdb": {
           "enable": true,
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 8a81b8a..f04d7bf 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -1385,6 +1385,7 @@
         "bucket": "chromiumos-image-archive",
         "cros_board": "trogdor",
         "cros_img": "trogdor-public/R123-15763.0.0",
+        "dut_pool": "chromium",
         "name": "chromeos_integration_tests TROGDOR_PUBLIC_LKGM",
         "test": "chromeos_integration_tests",
         "test_id_prefix": "ninja://chrome/test:chromeos_integration_tests/",
@@ -1395,6 +1396,7 @@
         "bucket": "chromiumos-image-archive",
         "cros_board": "trogdor",
         "cros_img": "trogdor-public/R123-15763.0.0",
+        "dut_pool": "chromium",
         "name": "lacros_all_tast_tests TROGDOR_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -5309,9 +5311,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6283.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6284.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 123.0.6283.0",
+        "description": "Run with ash-chrome version 123.0.6284.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5321,8 +5323,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v123.0.6283.0",
-              "revision": "version:123.0.6283.0"
+              "location": "lacros_version_skew_tests_v123.0.6284.0",
+              "revision": "version:123.0.6284.0"
             }
           ],
           "dimensions": {
@@ -5465,9 +5467,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6283.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6284.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 123.0.6283.0",
+        "description": "Run with ash-chrome version 123.0.6284.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5477,8 +5479,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v123.0.6283.0",
-              "revision": "version:123.0.6283.0"
+              "location": "lacros_version_skew_tests_v123.0.6284.0",
+              "revision": "version:123.0.6284.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json
index df8d767..cc8c46f 100644
--- a/testing/buildbot/chromium.coverage.json
+++ b/testing/buildbot/chromium.coverage.json
@@ -20464,9 +20464,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6283.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6284.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 123.0.6283.0",
+        "description": "Run with ash-chrome version 123.0.6284.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -20476,8 +20476,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v123.0.6283.0",
-              "revision": "version:123.0.6283.0"
+              "location": "lacros_version_skew_tests_v123.0.6284.0",
+              "revision": "version:123.0.6284.0"
             }
           ],
           "dimensions": {
@@ -20614,9 +20614,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6283.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6284.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 123.0.6283.0",
+        "description": "Run with ash-chrome version 123.0.6284.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -20626,8 +20626,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v123.0.6283.0",
-              "revision": "version:123.0.6283.0"
+              "location": "lacros_version_skew_tests_v123.0.6284.0",
+              "revision": "version:123.0.6284.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index fba3518a..366e2a1 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -4652,6 +4652,7 @@
         "autotest_name": "tast.chrome-from-gcs",
         "bucket": "chromiumos-image-archive",
         "cros_board": "jacuzzi",
+        "dut_pool": "chromium",
         "name": "chrome_all_tast_tests JACUZZI_CQ_PUBLIC_LKGM",
         "public_builder": "cros_test_platform_public",
         "public_builder_bucket": "testplatform-public",
@@ -4669,6 +4670,7 @@
         "bucket": "chromiumos-image-archive",
         "ci_only": true,
         "cros_board": "jacuzzi",
+        "dut_pool": "chromium",
         "experiment_percentage": 100,
         "name": "chrome_criticalstaging_tast_tests JACUZZI_CQ_PUBLIC_LKGM",
         "public_builder": "cros_test_platform_public",
@@ -4687,6 +4689,7 @@
         "bucket": "chromiumos-image-archive",
         "ci_only": true,
         "cros_board": "jacuzzi",
+        "dut_pool": "chromium",
         "experiment_percentage": 100,
         "name": "chrome_disabled_tast_tests JACUZZI_CQ_PUBLIC_LKGM",
         "public_builder": "cros_test_platform_public",
@@ -4711,6 +4714,7 @@
         "autotest_name": "tast.chrome-from-gcs",
         "bucket": "chromiumos-image-archive",
         "cros_board": "octopus",
+        "dut_pool": "chromium",
         "name": "chrome_all_tast_tests OCTOPUS_PUBLIC_LKGM",
         "shards": 15,
         "tast_expr": "STUB_STRING_TO_RUN_TAST_TESTS",
@@ -42478,9 +42482,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6283.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6284.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 123.0.6283.0",
+        "description": "Run with ash-chrome version 123.0.6284.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -42489,8 +42493,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v123.0.6283.0",
-              "revision": "version:123.0.6283.0"
+              "location": "lacros_version_skew_tests_v123.0.6284.0",
+              "revision": "version:123.0.6284.0"
             }
           ],
           "dimensions": {
@@ -42628,9 +42632,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6283.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6284.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 123.0.6283.0",
+        "description": "Run with ash-chrome version 123.0.6284.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -42639,8 +42643,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v123.0.6283.0",
-              "revision": "version:123.0.6283.0"
+              "location": "lacros_version_skew_tests_v123.0.6284.0",
+              "revision": "version:123.0.6284.0"
             }
           ],
           "dimensions": {
@@ -43960,9 +43964,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6283.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6284.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 123.0.6283.0",
+        "description": "Run with ash-chrome version 123.0.6284.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -43971,8 +43975,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v123.0.6283.0",
-              "revision": "version:123.0.6283.0"
+              "location": "lacros_version_skew_tests_v123.0.6284.0",
+              "revision": "version:123.0.6284.0"
             }
           ],
           "dimensions": {
@@ -44110,9 +44114,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6283.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6284.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 123.0.6283.0",
+        "description": "Run with ash-chrome version 123.0.6284.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -44121,8 +44125,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v123.0.6283.0",
-              "revision": "version:123.0.6283.0"
+              "location": "lacros_version_skew_tests_v123.0.6284.0",
+              "revision": "version:123.0.6284.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 0b0e409e..112037cc 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -16507,12 +16507,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6283.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6284.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 123.0.6283.0",
+        "description": "Run with ash-chrome version 123.0.6284.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -16522,8 +16522,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v123.0.6283.0",
-              "revision": "version:123.0.6283.0"
+              "location": "lacros_version_skew_tests_v123.0.6284.0",
+              "revision": "version:123.0.6284.0"
             }
           ],
           "dimensions": {
@@ -16683,12 +16683,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6283.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6284.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 123.0.6283.0",
+        "description": "Run with ash-chrome version 123.0.6284.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -16698,8 +16698,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v123.0.6283.0",
-              "revision": "version:123.0.6283.0"
+              "location": "lacros_version_skew_tests_v123.0.6284.0",
+              "revision": "version:123.0.6284.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/internal.chromeos.fyi.json b/testing/buildbot/internal.chromeos.fyi.json
index 717eaecd..2195e1a 100644
--- a/testing/buildbot/internal.chromeos.fyi.json
+++ b/testing/buildbot/internal.chromeos.fyi.json
@@ -1525,6 +1525,7 @@
       {
         "autotest_name": "chromium",
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "name": "base_unittests JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM",
         "test": "base_unittests",
         "test_id_prefix": "ninja://base:base_unittests/",
@@ -1534,6 +1535,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "name": "chrome_all_tast_tests JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM",
         "shards": 20,
         "tast_expr": "STUB_STRING_TO_RUN_TAST_TESTS",
@@ -1548,6 +1550,7 @@
         "autotest_name": "tast.chrome-from-gcs",
         "ci_only": true,
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "experiment_percentage": 100,
         "name": "chrome_criticalstaging_tast_tests JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM",
         "shards": 3,
@@ -1563,6 +1566,7 @@
         "autotest_name": "tast.chrome-from-gcs",
         "ci_only": true,
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "experiment_percentage": 100,
         "name": "chrome_disabled_tast_tests JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM",
         "shards": 2,
@@ -1577,6 +1581,7 @@
       {
         "autotest_name": "chromium",
         "cros_board": "jacuzzi",
+        "dut_pool": "chrome",
         "name": "chromeos_integration_tests JACUZZI_RELEASE_CHROME_FROM_TLS_LKGM",
         "test": "chromeos_integration_tests",
         "test_id_prefix": "ninja://chrome/test:chromeos_integration_tests/",
@@ -1596,6 +1601,7 @@
         "autotest_name": "chromium",
         "cros_board": "octopus",
         "cros_model": "casta",
+        "dut_pool": "chrome",
         "name": "base_unittests OCTOPUS_RELEASE_CHROME_FROM_TLS_LKGM",
         "test": "base_unittests",
         "test_id_prefix": "ninja://base:base_unittests/",
@@ -1606,6 +1612,7 @@
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "octopus",
         "cros_model": "casta",
+        "dut_pool": "chrome",
         "name": "chrome_all_tast_tests OCTOPUS_RELEASE_CHROME_FROM_TLS_LKGM",
         "shards": 15,
         "tast_expr": "STUB_STRING_TO_RUN_TAST_TESTS",
@@ -1630,6 +1637,7 @@
       {
         "autotest_name": "chromium",
         "cros_board": "trogdor",
+        "dut_pool": "chrome",
         "name": "base_unittests TROGDOR_RELEASE_LKGM",
         "test": "base_unittests",
         "test_id_prefix": "ninja://base:base_unittests/",
@@ -1639,6 +1647,7 @@
       {
         "autotest_name": "tast.chrome-from-gcs",
         "cros_board": "trogdor",
+        "dut_pool": "chrome",
         "name": "chrome_all_tast_tests TROGDOR_RELEASE_LKGM",
         "shards": 20,
         "tast_expr": "STUB_STRING_TO_RUN_TAST_TESTS",
@@ -1652,6 +1661,7 @@
       {
         "autotest_name": "chromium",
         "cros_board": "trogdor",
+        "dut_pool": "chrome",
         "name": "chromeos_integration_tests TROGDOR_RELEASE_LKGM",
         "test": "chromeos_integration_tests",
         "test_id_prefix": "ninja://chrome/test:chromeos_integration_tests/",
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 8aa7644..00e161f5 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -121,6 +121,7 @@
       'cros_board': 'jacuzzi',
       'use_lkgm': True,
       'bucket': 'chromiumos-image-archive',
+      'dut_pool': 'chromium',
       'public_builder': 'cros_test_platform_public',
       'public_builder_bucket': 'testplatform-public',
     },
@@ -130,6 +131,7 @@
     'skylab': {
       'cros_board': 'jacuzzi',
       'use_lkgm': True,
+      'dut_pool': 'chrome',
     },
   },
   'CROS_JACUZZI_RELEASE_LKGM': {
@@ -137,6 +139,7 @@
     'skylab': {
       'cros_board': 'jacuzzi',
       'use_lkgm': True,
+      'dut_pool': 'chrome',
     },
   },
   'CROS_OCTOPUS_PUBLIC_LKGM': {
@@ -145,6 +148,7 @@
       'cros_board': 'octopus',
       'use_lkgm': True,
       'bucket': 'chromiumos-image-archive',
+      'dut_pool': 'chromium',
     },
   },
   'CROS_OCTOPUS_RELEASE_CHROME_FROM_TLS_ASH_LKGM': {
@@ -153,6 +157,7 @@
       'cros_board': 'octopus',
       'cros_model': 'casta',
       'use_lkgm': True,
+      'dut_pool': 'chrome',
     },
   },
   'CROS_PUFF_RELEASE_BETA': {
@@ -192,6 +197,7 @@
     'skylab': {
       'cros_board': 'strongbad',
       'use_lkgm': True,
+      'dut_pool': 'chrome',
     },
   },
   'CROS_TROGDOR_PUBLIC_LKGM': {
@@ -200,6 +206,7 @@
       'cros_board': 'trogdor',
       'cros_img': 'trogdor-public/R123-15763.0.0',
       'bucket': 'chromiumos-image-archive',
+      'dut_pool': 'chromium',
     },
   },
   'CROS_TROGDOR_RELEASE_ASH_LKGM': {
@@ -207,6 +214,7 @@
     'skylab': {
       'cros_board': 'trogdor',
       'use_lkgm': True,
+      'dut_pool': 'chrome',
     },
   },
   'CROS_VOLTEER_PUBLIC_LKGM': {
@@ -238,6 +246,7 @@
     'skylab': {
       'cros_board': 'volteer',
       'use_lkgm': True,
+      'dut_pool': 'chrome',
     },
   },
   'DISABLE_FIELD_TRIAL_CONFIG': {
@@ -307,16 +316,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'identifier': 'Lacros version skew testing ash canary',
-    'description': 'Run with ash-chrome version 123.0.6283.0',
+    'description': 'Run with ash-chrome version 123.0.6284.0',
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6283.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v123.0.6284.0/test_ash_chrome',
     ],
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v123.0.6283.0',
-          'revision': 'version:123.0.6283.0',
+          'location': 'lacros_version_skew_tests_v123.0.6284.0',
+          'revision': 'version:123.0.6284.0',
         },
       ],
     },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 2388e13..9356053 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -5971,33 +5971,6 @@
             ]
         }
     ],
-    "DesktopTabGroupsInProductHelp": [
-        {
-            "platforms": [
-                "chromeos",
-                "chromeos_lacros",
-                "fuchsia",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "EnabledIPH_20220401",
-                    "params": {
-                        "availability": ">0",
-                        "event_many_tabs_opened": "name:sixth_tab_opened;comparator:>0;window:1;storage:365",
-                        "event_trigger": "name:tab_groups_new_group_iph_triggered;comparator:<5;window:365;storage:365",
-                        "event_used": "name:tab_group_created;comparator:==0;window:365;storage:365",
-                        "session_rate": "<3"
-                    },
-                    "enable_features": [
-                        "IPH_DesktopTabGroupsNewGroup"
-                    ]
-                }
-            ]
-        }
-    ],
     "DesktopViewsWidgetLayering": [
         {
             "platforms": [
diff --git a/third_party/android_deps/build.gradle b/third_party/android_deps/build.gradle
index 98d5d57..ae0f7f6 100644
--- a/third_party/android_deps/build.gradle
+++ b/third_party/android_deps/build.gradle
@@ -119,6 +119,7 @@
     compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20"
     compile "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
     compile "org.jetbrains.kotlinx:kotlinx-coroutines-guava:1.6.4"
+    compile "org.jetbrains.kotlin:kotlin-parcelize-runtime:1.9.22"
 
     // Needed by androidx.macrobenchmarks
     androidTestCompile "com.squareup.wire:wire-runtime-jvm:4.4.3"
diff --git a/third_party/android_deps/buildSrc/src/main/groovy/ChromiumDepGraph.groovy b/third_party/android_deps/buildSrc/src/main/groovy/ChromiumDepGraph.groovy
index 03f3ed2..bab350c6 100644
--- a/third_party/android_deps/buildSrc/src/main/groovy/ChromiumDepGraph.groovy
+++ b/third_party/android_deps/buildSrc/src/main/groovy/ChromiumDepGraph.groovy
@@ -276,6 +276,8 @@
             resolveVersion: '1.8.20'),
         org_jetbrains_kotlin_kotlin_stdlib_common: new PropertyOverride(
             resolveVersion: '1.8.20'),
+        org_jetbrains_kotlin_kotlin_parcelize_runtime: new PropertyOverride(
+            overrideLatest: true),
         io_grpc_grpc_binder: new PropertyOverride(
             licenseUrl: 'https://www.apache.org/licenses/LICENSE-2.0.txt',
             licenseName: 'Apache 2.0'),
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime/3pp/3pp.pb b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime/3pp/3pp.pb
new file mode 100644
index 0000000..d743b51b
--- /dev/null
+++ b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime/3pp/3pp.pb
@@ -0,0 +1,16 @@
+# 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.
+
+# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+
+create {
+  source {
+    script { name: "fetch.py" }
+  }
+}
+
+upload {
+  pkg_prefix: "chromium/third_party/android_deps/libs"
+  universal: true
+}
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime/3pp/fetch.py b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime/3pp/fetch.py
new file mode 100755
index 0000000..554f6b77
--- /dev/null
+++ b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime/3pp/fetch.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python3
+# 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.
+
+# This is generated, do not edit. Update BuildConfigGenerator.groovy and
+# 3ppFetch.template instead.
+
+import pathlib
+import sys
+
+_3PP_DIR = pathlib.Path(__file__).resolve().parent
+sys.path.insert(0, str(_3PP_DIR.parents[2]))
+import fetch_common
+
+_REPO_URL = 'https://repo.maven.apache.org/maven2'
+SPEC = fetch_common.Spec(repo_url=_REPO_URL,
+                         group_name='org/jetbrains/kotlin',
+                         module_name='kotlin-android-extensions-runtime',
+                         file_ext='jar',
+                         patch_version='cr1',
+                         version_override='1.9.22',
+                         version_filter=None)
+
+
+if __name__ == '__main__':
+    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime/OWNERS b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime/OWNERS
new file mode 100644
index 0000000..aea47a05
--- /dev/null
+++ b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime/OWNERS
@@ -0,0 +1 @@
+file://third_party/android_deps/OWNERS
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime/3pp/3pp.pb b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime/3pp/3pp.pb
new file mode 100644
index 0000000..d743b51b
--- /dev/null
+++ b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime/3pp/3pp.pb
@@ -0,0 +1,16 @@
+# 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.
+
+# This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+
+create {
+  source {
+    script { name: "fetch.py" }
+  }
+}
+
+upload {
+  pkg_prefix: "chromium/third_party/android_deps/libs"
+  universal: true
+}
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime/3pp/fetch.py b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime/3pp/fetch.py
new file mode 100755
index 0000000..a3bf2b6f
--- /dev/null
+++ b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime/3pp/fetch.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python3
+# 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.
+
+# This is generated, do not edit. Update BuildConfigGenerator.groovy and
+# 3ppFetch.template instead.
+
+import pathlib
+import sys
+
+_3PP_DIR = pathlib.Path(__file__).resolve().parent
+sys.path.insert(0, str(_3PP_DIR.parents[2]))
+import fetch_common
+
+_REPO_URL = 'https://repo.maven.apache.org/maven2'
+SPEC = fetch_common.Spec(repo_url=_REPO_URL,
+                         group_name='org/jetbrains/kotlin',
+                         module_name='kotlin-parcelize-runtime',
+                         file_ext='jar',
+                         patch_version='cr1',
+                         version_override='1.9.22',
+                         version_filter=None)
+
+
+if __name__ == '__main__':
+    fetch_common.main(SPEC)
diff --git a/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime/OWNERS b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime/OWNERS
new file mode 100644
index 0000000..aea47a05
--- /dev/null
+++ b/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime/OWNERS
@@ -0,0 +1 @@
+file://third_party/android_deps/OWNERS
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 7387209..d32e6a3 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -1227,7 +1227,7 @@
 
 const base::FeatureParam<bool>
     kLCPCriticalPathPredictorEnableElementLocatorPerformanceImprovements{
-        &kLCPCriticalPathPredictor, "lcpp_enable_perf_improvements", false};
+        &kLCPCriticalPathPredictor, "lcpp_enable_perf_improvements", true};
 
 const base::FeatureParam<bool>
     kLCPCriticalPathPredictorImageLoadPriorityEnabledForHTMLImageElement{
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
index ef833aa..492cca6 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
@@ -1071,6 +1071,28 @@
         .Test(*this, scope, builder, options);
   }
   {
+    // Test conv2d operator for explicit padding are not same as the calculated
+    // padding with kSameUpper, input, filter size, stride and dilation that
+    // are used by CalculateConv2dPadding function.
+    auto* options = MLConv2dOptions::Create();
+    options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc);
+    options->setFilterLayout(V8MLConv2dFilterOperandLayout::Enum::kOhwi);
+    // The paddings are {1, 1, 1, 1} with calculating by CalculateConv2dPadding
+    // function.
+    options->setPadding({2, 2, 1, 1});
+    options->setStrides({2, 2});
+    Conv2dTester<float>{
+        .input = {.data_type = V8MLOperandDataType::Enum::kFloat32,
+                  .dimensions = {1, 7, 5, 1},
+                  .values = Vector<float>(35, 1.0)},
+        .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32,
+                   .dimensions = {1, 3, 3, 1},
+                   .values = Vector<float>(9, 1.0)},
+        .expected = {2.0, 3.0, 2.0, 6.0, 9.0, 6.0, 6.0, 9.0, 6.0, 6.0, 9.0, 6.0,
+                     2.0, 3.0, 2.0}}
+        .Test(*this, scope, builder, options);
+  }
+  {
     // Test fused conv2d operator for nhwc input layout and ohwi filter
     // layout, fusing with bias operand and relu activation.
     auto* options = MLConv2dOptions::Create();
@@ -1587,6 +1609,29 @@
         .expected = {11.0, 12.0, 15.0, 16.0}}
         .Test(*this, scope, options);
   }
+  {
+    // Test maxPool2d operator for explicit padding are not same as the
+    // calculated padding with kSameUpper, input size, window dimensions, stride
+    // and dilation that are used by CalculateConv2dPadding function.
+    auto* options = MLPool2dOptions::Create();
+    options->setLayout(V8MLInputOperandLayout::Enum::kNhwc);
+    // The paddings are {1, 1, 1, 1} with calculating by CalculateConv2dPadding
+    // function.
+    options->setPadding({2, 2, 1, 1});
+    options->setWindowDimensions({3, 3});
+    options->setStrides({2, 2});
+    Pool2dTester<float>{
+        .kind = Pool2dKind::kMax,
+        .input = {.data_type = V8MLOperandDataType::Enum::kFloat32,
+                  .dimensions = {1, 7, 5, 1},
+                  .values = {2.0, 3.0, 2.0, 6.0, 9.0, 2.0, 3.0, 2.0, 6.0,
+                             9.0, 2.0, 3.0, 2.0, 6.0, 9.0, 2.0, 3.0, 2.0,
+                             6.0, 9.0, 2.0, 3.0, 2.0, 6.0, 9.0, 2.0, 3.0,
+                             2.0, 6.0, 9.0, 2.0, 3.0, 2.0, 6.0, 9.0}},
+        .expected = {3.0, 6.0, 9.0, 3.0, 6.0, 9.0, 3.0, 6.0, 9.0, 3.0, 6.0, 9.0,
+                     3.0, 6.0, 9.0}}
+        .Test(*this, scope, options);
+  }
 }
 
 // Because reshape Node runs copy operator, ReshapeTester just checks the
@@ -2074,8 +2119,7 @@
 };
 
 TEST_P(MLGraphTest, PadTest) {
-  SKIP_TEST_ON_UNSUPPORTED_BACKEND(BackendType::kModelLoader);
-  V8TestingScope scope;
+  MLGraphV8TestingScope scope;
   auto* builder =
       CreateMLGraphBuilder(scope.GetExecutionContext(), scope.GetScriptState(),
                            scope.GetExceptionState());
@@ -2106,6 +2150,34 @@
                      8., 8., 4., 5., 6., 8., 8., 8., 8., 8., 8., 8., 8., 8.}}
         .Test(*this, scope, builder, options);
   }
+  // Reflection and Symmetric padding mode are not implemented on XNNPACK.
+  SKIP_TEST_ON_UNSUPPORTED_BACKEND(BackendType::kXnnpack);
+  {
+    // Test pad with mode = "reflection".
+    auto* options = MLPadOptions::Create();
+    options->setMode("reflection");
+    PadTester<float>{.input = {.data_type = V8MLOperandDataType::Enum::kFloat32,
+                               .dimensions = {1, 1, 2, 3},
+                               .values = {0, 1, 2, 3, 4, 5}},
+                     .beginning_padding = {0, 0, 1, 2},
+                     .ending_padding = {0, 0, 1, 2},
+                     .expected = {5, 4, 3, 4, 5, 4, 3, 2, 1, 0, 1, 2, 1, 0,
+                                  5, 4, 3, 4, 5, 4, 3, 2, 1, 0, 1, 2, 1, 0}}
+        .Test(*this, scope, builder, options);
+  }
+  {
+    // Test pad with mode = "symmetric".
+    auto* options = MLPadOptions::Create();
+    options->setMode("symmetric");
+    PadTester<float>{.input = {.data_type = V8MLOperandDataType::Enum::kFloat32,
+                               .dimensions = {1, 2, 3, 1},
+                               .values = {0, 1, 2, 3, 4, 5}},
+                     .beginning_padding = {0, 1, 2, 0},
+                     .ending_padding = {0, 1, 2, 0},
+                     .expected = {1, 0, 0, 1, 2, 2, 1, 1, 0, 0, 1, 2, 2, 1,
+                                  4, 3, 3, 4, 5, 5, 4, 4, 3, 3, 4, 5, 5, 4}}
+        .Test(*this, scope, builder, options);
+  }
 }
 
 template <typename T>
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_model_loader.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_model_loader.cc
index c19119f0..8e79068b 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_model_loader.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test_model_loader.cc
@@ -128,12 +128,23 @@
                tflite::ops::builtin::Register_MINIMUM(),
                /* min_version = */ 1,
                /* max_version = */ 4);
+    AddBuiltin(tflite::BuiltinOperator_MIRROR_PAD,
+               tflite::ops::builtin::Register_MIRROR_PAD(),
+               /* min_version = */ 1,
+               /* max_version = */ 2);
     AddBuiltin(tflite::BuiltinOperator_MUL,
                tflite::ops::builtin::Register_MUL(),
                /* min_version = */ 1,
                /* max_version = */ 4);
     AddBuiltin(tflite::BuiltinOperator_NEG,
                tflite::ops::builtin::Register_NEG());
+    AddBuiltin(tflite::BuiltinOperator_PAD,
+               tflite::ops::builtin::Register_PAD(),
+               /* min_version = */ 1,
+               /* max_version = */ 2);
+    AddBuiltin(tflite::BuiltinOperator_PADV2,
+               tflite::ops::builtin::Register_PADV2(), /* min_version = */ 1,
+               /* max_version = */ 2);
     AddBuiltin(tflite::BuiltinOperator_POW,
                tflite::ops::builtin::Register_POW());
     AddBuiltin(tflite::BuiltinOperator_RELU,
@@ -213,65 +224,8 @@
   std::unique_ptr<tflite::Interpreter> interpreter_;
 };
 
-}  // namespace
-
-class FakeWebNNModel : public blink_mojom::Model {
- public:
-  FakeWebNNModel() : runtime_(std::make_unique<TfLiteRuntime>()) {}
-  FakeWebNNModel(const FakeWebNNModel&) = delete;
-  FakeWebNNModel(FakeWebNNModel&&) = delete;
-  ~FakeWebNNModel() override = default;
-
-  FakeMLModelLoader::LoadFn CreateFromThis() {
-    return WTF::BindRepeating(&FakeWebNNModel::OnCreateModel,
-                              WTF::Unretained(this));
-  }
-
- private:
-  void OnCreateModel(mojo_base::BigBuffer buffer,
-                     blink_mojom::ModelLoader::LoadCallback callback) {
-    blink_mojom::ModelInfoPtr info = blink_mojom::ModelInfo::New();
-    EXPECT_EQ(runtime_->Load(buffer, info), kTfLiteOk);
-    // Hold the flatbuffer for computing with tflite runtime.
-    buffer_ = std::move(buffer);
-
-    receiver_.reset();
-    std::move(callback).Run(blink_mojom::LoadModelResult::kOk,
-                            receiver_.BindNewPipeAndPassRemote(),
-                            std::move(info));
-  }
-
-  // Override methods from blink_mojom::Model.
-  void Compute(const WTF::HashMap<WTF::String, WTF::Vector<uint8_t>>& input,
-               blink_mojom::Model::ComputeCallback callback) override {
-    WTF::HashMap<WTF::String, WTF::Vector<uint8_t>> named_output;
-    EXPECT_EQ(runtime_->Compute(input, named_output), kTfLiteOk);
-    std::move(callback).Run(blink_mojom::ComputeResult::kOk, named_output);
-  }
-
-  mojo::Receiver<blink_mojom::Model> receiver_{this};
-  std::unique_ptr<TfLiteRuntime> runtime_;
-  // The buffer of tflite model must be alive for computing.
-  mojo_base::BigBuffer buffer_;
-};
-
 class MLGraphTestTfLite : public MLGraphTestBase {};
 
-ScopedMLService::ScopedMLService()
-    : loader_(std::make_unique<FakeMLModelLoader>()),
-      model_(std::make_unique<FakeWebNNModel>()),
-      ml_service_(std::make_unique<FakeMLService>()) {}
-
-ScopedMLService::~ScopedMLService() = default;
-
-void ScopedMLService::SetUpMLService(V8TestingScope& scope) {
-  ml_service_->SetCreateModelLoader(loader_->CreateFromThis());
-  loader_->SetLoad(model_->CreateFromThis());
-
-  ml_service_binder_ =
-      std::make_unique<ScopedSetMLServiceBinder>(ml_service_.get(), scope);
-}
-
 template <typename T>
 struct ElementWiseAddTester {
   OperandInfo<T> lhs;
@@ -403,40 +357,6 @@
   }
 };
 
-TEST_P(MLGraphTestTfLite, BuildGraphWithTfliteModel) {
-  MLGraphV8TestingScope scope;
-
-  {
-    // Test element-wise add operator for two 1-D tensors.
-    ElementWiseAddTester<float>{
-        .lhs = {.data_type = V8MLOperandDataType::Enum::kFloat32,
-                .dimensions = {2},
-                .values = {1.0, 2.0}},
-        .rhs = {.data_type = V8MLOperandDataType::Enum::kFloat32,
-                .dimensions = {2},
-                .values = {3.0, 4.0}},
-        .expected = {.data_type = V8MLOperandDataType::Enum::kFloat32,
-                     .dimensions = {2},
-                     .values = {4.0, 6.0}}}
-        .Test(*this, scope);
-  }
-  {
-    // Test element-wise add operator for 1-D tensor broadcasting to 2-D
-    // tensor.
-    ElementWiseAddTester<float>{
-        .lhs = {.data_type = V8MLOperandDataType::Enum::kFloat32,
-                .dimensions = {2, 2},
-                .values = {1.0, 2.0, 3.0, 4.0}},
-        .rhs = {.data_type = V8MLOperandDataType::Enum::kFloat32,
-                .dimensions = {2},
-                .values = {5.0, 6.0}},
-        .expected = {.data_type = V8MLOperandDataType::Enum::kFloat32,
-                     .dimensions = {2, 2},
-                     .values = {6.0, 8.0, 8.0, 10.0}}}
-        .Test(*this, scope);
-  }
-}
-
 template <typename T>
 struct EluTester {
   OperandInfo<T> input;
@@ -479,6 +399,123 @@
   }
 };
 
+template <typename T>
+struct Conv2dExceptionTester {
+  OperandInfo<T> input;
+  OperandInfo<T> filter;
+  String error_message;
+
+  void Test(MLGraphTestTfLite& helper,
+            V8TestingScope& scope,
+            MLGraphBuilder* builder,
+            MLConv2dOptions* options = MLConv2dOptions::Create()) {
+    // Build the graph.
+    auto* input_operand =
+        BuildInput(builder, "input", input.dimensions, input.data_type,
+                   scope.GetExceptionState());
+    auto* filter_operand =
+        BuildConstant(builder, filter.dimensions, filter.data_type,
+                      filter.values, scope.GetExceptionState());
+    auto* output_operand =
+        BuildConv2d(scope, builder, input_operand, filter_operand, options);
+    auto [graph, build_exception] =
+        helper.BuildGraph(scope, builder, {{"output", output_operand}});
+    ASSERT_THAT(graph, testing::IsNull());
+    EXPECT_EQ(build_exception->message(), error_message);
+  }
+};
+
+}  // namespace
+
+class FakeWebNNModel : public blink_mojom::Model {
+ public:
+  FakeWebNNModel() : runtime_(std::make_unique<TfLiteRuntime>()) {}
+  FakeWebNNModel(const FakeWebNNModel&) = delete;
+  FakeWebNNModel(FakeWebNNModel&&) = delete;
+  ~FakeWebNNModel() override = default;
+
+  FakeMLModelLoader::LoadFn CreateFromThis() {
+    return WTF::BindRepeating(&FakeWebNNModel::OnCreateModel,
+                              WTF::Unretained(this));
+  }
+
+ private:
+  void OnCreateModel(mojo_base::BigBuffer buffer,
+                     blink_mojom::ModelLoader::LoadCallback callback) {
+    blink_mojom::ModelInfoPtr info = blink_mojom::ModelInfo::New();
+    EXPECT_EQ(runtime_->Load(buffer, info), kTfLiteOk);
+    // Hold the flatbuffer for computing with tflite runtime.
+    buffer_ = std::move(buffer);
+
+    receiver_.reset();
+    std::move(callback).Run(blink_mojom::LoadModelResult::kOk,
+                            receiver_.BindNewPipeAndPassRemote(),
+                            std::move(info));
+  }
+
+  // Override methods from blink_mojom::Model.
+  void Compute(const WTF::HashMap<WTF::String, WTF::Vector<uint8_t>>& input,
+               blink_mojom::Model::ComputeCallback callback) override {
+    WTF::HashMap<WTF::String, WTF::Vector<uint8_t>> named_output;
+    EXPECT_EQ(runtime_->Compute(input, named_output), kTfLiteOk);
+    std::move(callback).Run(blink_mojom::ComputeResult::kOk, named_output);
+  }
+
+  mojo::Receiver<blink_mojom::Model> receiver_{this};
+  std::unique_ptr<TfLiteRuntime> runtime_;
+  // The buffer of tflite model must be alive for computing.
+  mojo_base::BigBuffer buffer_;
+};
+
+ScopedMLService::ScopedMLService()
+    : loader_(std::make_unique<FakeMLModelLoader>()),
+      model_(std::make_unique<FakeWebNNModel>()),
+      ml_service_(std::make_unique<FakeMLService>()) {}
+
+ScopedMLService::~ScopedMLService() = default;
+
+void ScopedMLService::SetUpMLService(V8TestingScope& scope) {
+  ml_service_->SetCreateModelLoader(loader_->CreateFromThis());
+  loader_->SetLoad(model_->CreateFromThis());
+
+  ml_service_binder_ =
+      std::make_unique<ScopedSetMLServiceBinder>(ml_service_.get(), scope);
+}
+
+TEST_P(MLGraphTestTfLite, BuildGraphWithTfliteModel) {
+  MLGraphV8TestingScope scope;
+
+  {
+    // Test element-wise add operator for two 1-D tensors.
+    ElementWiseAddTester<float>{
+        .lhs = {.data_type = V8MLOperandDataType::Enum::kFloat32,
+                .dimensions = {2},
+                .values = {1.0, 2.0}},
+        .rhs = {.data_type = V8MLOperandDataType::Enum::kFloat32,
+                .dimensions = {2},
+                .values = {3.0, 4.0}},
+        .expected = {.data_type = V8MLOperandDataType::Enum::kFloat32,
+                     .dimensions = {2},
+                     .values = {4.0, 6.0}}}
+        .Test(*this, scope);
+  }
+  {
+    // Test element-wise add operator for 1-D tensor broadcasting to 2-D
+    // tensor.
+    ElementWiseAddTester<float>{
+        .lhs = {.data_type = V8MLOperandDataType::Enum::kFloat32,
+                .dimensions = {2, 2},
+                .values = {1.0, 2.0, 3.0, 4.0}},
+        .rhs = {.data_type = V8MLOperandDataType::Enum::kFloat32,
+                .dimensions = {2},
+                .values = {5.0, 6.0}},
+        .expected = {.data_type = V8MLOperandDataType::Enum::kFloat32,
+                     .dimensions = {2, 2},
+                     .values = {6.0, 8.0, 8.0, 10.0}}}
+        .Test(*this, scope);
+  }
+}
+
 TEST_P(MLGraphTestTfLite, EluTest) {
   MLGraphV8TestingScope scope;
   {
@@ -520,6 +557,30 @@
   }
 }
 
+TEST_P(MLGraphTestTfLite, Conv2dTest) {
+  MLGraphV8TestingScope scope;
+  auto* builder =
+      CreateMLGraphBuilder(scope.GetExecutionContext(), scope.GetScriptState(),
+                           scope.GetExceptionState());
+  {
+    // Test conv2d operator for overflow padding.
+    auto* options = MLConv2dOptions::Create();
+    options->setInputLayout(V8MLInputOperandLayout::Enum::kNhwc);
+    options->setFilterLayout(V8MLConv2dFilterOperandLayout::Enum::kOhwi);
+    options->setPadding({1294967295, 1294967295, 1, 1});
+    options->setStrides({2, 2});
+    Conv2dExceptionTester<float>{
+        .input = {.data_type = V8MLOperandDataType::Enum::kFloat32,
+                  .dimensions = {1, 7, 5, 1},
+                  .values = Vector<float>(35, 1.0)},
+        .filter = {.data_type = V8MLOperandDataType::Enum::kFloat32,
+                   .dimensions = {1, 3, 3, 1},
+                   .values = Vector<float>(9, 1.0)},
+        .error_message = "The input dimension or padding is too large."}
+        .Test(*this, scope, builder, options);
+  }
+}
+
 const TestVariety kGraphTestModelLoaderVariety[] = {
     {BackendType::kModelLoader, ExecutionMode::kAsync},
 };
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_tflite_converter.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_tflite_converter.cc
index a249c1a..adee4042 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_tflite_converter.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_tflite_converter.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_conv_2d_options.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_elu_options.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_leaky_relu_options.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_pad_options.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_pool_2d_options.h"
 #include "third_party/blink/renderer/modules/ml/webnn/ml_activation.h"
 #include "third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.h"
@@ -95,9 +96,16 @@
   return operator_code_index;
 }
 
+// Holds tflite padding mode and the explicit padding if needed.
+struct TfLitePadding {
+  tflite::Padding mode;
+  // The explicit paddings are used to create TfLite Pad operator.
+  absl::optional<Vector<uint32_t>> paddings;
+};
+
 // Helper to get tflite padding mode for convolution 2d or pooling 2d.
 template <typename OptionsType>
-base::expected<tflite::Padding, String> GetTfLitePaddingMode(
+base::expected<TfLitePadding, String> GetTfLitePaddingMode(
     const OptionsType* options,
     const webnn::Size2d<uint32_t>& input,
     const webnn::Size2d<uint32_t>& filter,
@@ -112,7 +120,7 @@
       const auto explicit_padding = options->getPaddingOr(no_padding);
       CHECK_EQ(explicit_padding.size(), 4u);
       if (explicit_padding == no_padding) {
-        return tflite::Padding_VALID;
+        return TfLitePadding{.mode = tflite::Padding_VALID};
       } else {
         // Convert the explicit padding to tflite same padding mode, throw
         // exception if the calculated padding with kSameUpper are not the same
@@ -129,10 +137,10 @@
             padding_height->begin, padding_height->end, padding_width->begin,
             padding_width->end};
         if (explicit_padding == upper_padding) {
-          return tflite::Padding_SAME;
+          return TfLitePadding{.mode = tflite::Padding_SAME};
         } else {
-          return base::unexpected(
-              "The explicit padding are not supported in tflite.");
+          return TfLitePadding{.mode = tflite::Padding_VALID,
+                               .paddings = explicit_padding};
         }
       }
     }
@@ -140,7 +148,7 @@
       // Tflite same padding is the additional ending padding of the spatial
       // input dimensions by default.
       // https://www.tensorflow.org/api_docs/python/tf/nn#same_padding
-      return tflite::Padding_SAME;
+      return TfLitePadding{.mode = tflite::Padding_SAME};
     case V8MLAutoPad::Enum::kSameLower:
       // The values in the padding array are ignored, so we don't need to
       // calculate if it's tflite same padding.
@@ -185,36 +193,116 @@
   return activation;
 }
 
+template <typename T>
+struct TensorInfo {
+  tflite::TensorType type;
+  Vector<int32_t> dimensions;
+  Vector<T> values;
+};
+
 template <typename DataType>
-uint32_t SerializeZeroBiasBuffer(V8MLOperandDataType::Enum data_type,
-                                 uint32_t output_channels,
-                                 flatbuffers::FlatBufferBuilder& builder,
-                                 Vector<BufferOffset>& buffers,
-                                 Vector<TensorOffset>& tensors) {
+int32_t SerializeTensorWithBuffer(const TensorInfo<DataType>& tensor_info,
+                                  flatbuffers::FlatBufferBuilder& builder,
+                                  Vector<BufferOffset>& buffers,
+                                  Vector<TensorOffset>& tensors) {
   // Create `tflite::Buffer` for the empty tensors.
   const auto buffer_index = base::checked_cast<uint32_t>(buffers.size());
-  const std::vector<DataType> empty_data(output_channels);
+  const auto& tensor_data = tensor_info.values;
   buffers.emplace_back(tflite::CreateBuffer(
       builder,
-      builder.CreateVector(reinterpret_cast<const uint8_t*>(empty_data.data()),
-                           empty_data.size() * sizeof(DataType))));
+      builder.CreateVector(reinterpret_cast<const uint8_t*>(tensor_data.data()),
+                           tensor_data.size() * sizeof(DataType))));
 
-  // Create `tflite::Tensor` with the output channels and the index of buffer.
+  // Create `tflite::Tensor` with the dimensions and the index of buffer.
   const int32_t tensor_index = base::checked_cast<int32_t>(tensors.size());
-  const auto dimensions = builder.CreateVector<int32_t>(
-      {base::checked_cast<int32_t>(output_channels)});
-  const auto operand_type = BlinkOperandTypeToTFLite(data_type);
+  const auto dimensions = builder.CreateVector<int32_t>(tensor_info.dimensions);
   tensors.emplace_back(tflite::CreateTensor(builder, std::move(dimensions),
-                                            operand_type, buffer_index));
+                                            tensor_info.type, buffer_index));
 
   return tensor_index;
 }
 
+base::expected<int32_t, String> SerializeExplicitPad(
+    const MLOperand* input_operand,
+    const int32_t input_tensor_index,
+    const Vector<uint32_t>& paddings,
+    flatbuffers::FlatBufferBuilder& builder,
+    Vector<OperatorCodeOffset>& operator_codes,
+    Vector<OperatorOffset>& operators,
+    Vector<BufferOffset>& buffers,
+    Vector<TensorOffset>& tensors) {
+  // WebNN explicit padding is in [beginning_height, ending_height,
+  // beginning_width, ending_width] sequence.
+  const auto padding_rank = paddings.size();
+  CHECK_EQ(padding_rank, 4u);
+
+  // TfLite padding is an integer tensor array filled with pre and post padding.
+  // For NHWC input layout, the sequence will be [[0, 0], [beginning_height,
+  // ending_height], [beginning_width, ending_width], [0, 0]].
+  Vector<int32_t> tflite_paddings(padding_rank);
+  tflite_paddings.InsertAt(tflite_paddings.begin() + 2, paddings.data(),
+                           paddings.size());
+
+  // The shape of padding is [n, 2], where n is the rank of input as described
+  // here https://www.tensorflow.org/mlir/tfl_ops#tflmirror_pad_tflmirrorpadop.
+  const Vector<int32_t> paddings_shape{
+      {base::checked_cast<int32_t>(padding_rank), 2}};
+  const TensorInfo<int32_t> paddings_info = {.type = tflite::TensorType_INT32,
+                                             .dimensions = paddings_shape,
+                                             .values = tflite_paddings};
+  const auto padding_tensor_index = SerializeTensorWithBuffer<int32_t>(
+      paddings_info, builder, buffers, tensors);
+
+  // Create `tflite::Tensor` for the output operand of explicit padding operator
+  // with the dimensions and data type.
+  const Vector<uint32_t>& input_shape = input_operand->Dimensions();
+  CHECK_EQ(input_shape.size(), 4u);
+  Vector<int32_t> output_shape;
+  output_shape.reserve(padding_rank);
+  for (size_t i = 0; i < padding_rank; ++i) {
+    auto checked_dimension = base::MakeCheckedNum<int32_t>(input_shape[i]);
+    // Calculate output height with padding beginning and ending height.
+    if (i == 1) {
+      checked_dimension +=
+          base::MakeCheckedNum<int32_t>(paddings[0]) + paddings[1];
+    } else if (i == 2) {
+      // Calculate output width with padding beginning and ending width.
+      checked_dimension +=
+          base::MakeCheckedNum<int32_t>(paddings[2]) + paddings[3];
+    }
+    if (!checked_dimension.IsValid()) {
+      return base::unexpected("The input dimension or padding is too large.");
+    }
+    output_shape.push_back(checked_dimension.ValueOrDie());
+  }
+
+  const tflite::TensorType input_tensor_type =
+      BlinkOperandTypeToTFLite(input_operand->DataType());
+  const int32_t output_tensor_index =
+      base::checked_cast<int32_t>(tensors.size());
+  tensors.emplace_back(tflite::CreateTensor(
+      builder, builder.CreateVector<int32_t>(output_shape), input_tensor_type));
+
+  // Create `tflite::Operator` with the tensor index of inputs and outputs
+  // operand. The type of operation is determined by the index of the operator
+  // code.
+  std::array<int32_t, 2> op_inputs = {input_tensor_index, padding_tensor_index};
+  const auto operator_code_index = GetOperatorCodeIndex(
+      tflite::BuiltinOperator_PAD, builder, operator_codes);
+  const std::array<int32_t, 1> op_outputs = {output_tensor_index};
+  operators.emplace_back(tflite::CreateOperator(
+      builder, operator_code_index, builder.CreateVector<int32_t>(op_inputs),
+      builder.CreateVector<int32_t>(op_outputs)));
+
+  return output_tensor_index;
+}
+
 base::expected<OperatorOffset, String> SerializeConv2d(
     const OperandToIndexMap& operand_to_index_map,
     const MLOperator* conv2d,
     flatbuffers::FlatBufferBuilder& builder,
     Vector<OperatorCodeOffset>& operator_codes,
+    Vector<OperatorOffset>& operators,
     Vector<BufferOffset>& buffers,
     Vector<TensorOffset>& tensors) {
   const int32_t input_index =
@@ -299,6 +387,19 @@
     return base::unexpected(padding_mode.error());
   }
 
+  // Insert a Pad operator before TfLite Conv2d if needed for explicit padding.
+  absl::optional<int32_t> explicit_pad_index;
+  const auto& explicit_padding = padding_mode->paddings;
+  if (explicit_padding) {
+    const auto serialization_result = SerializeExplicitPad(
+        input, input_index, explicit_padding.value(), builder, operator_codes,
+        operators, buffers, tensors);
+    if (!serialization_result.has_value()) {
+      return base::unexpected(serialization_result.error());
+    }
+    explicit_pad_index = serialization_result.value();
+  }
+
   tflite::BuiltinOperator operator_kind;
   tflite::BuiltinOptions builtin_options_type = tflite::BuiltinOptions_NONE;
   flatbuffers::Offset<void> builtin_options = 0;
@@ -306,7 +407,7 @@
     const uint32_t depth_multiplier = 1;
     operator_kind = tflite::BuiltinOperator_DEPTHWISE_CONV_2D;
     builtin_options = tflite::CreateDepthwiseConv2DOptions(
-                          builder, padding_mode.value(), stride_size2d.width,
+                          builder, padding_mode->mode, stride_size2d.width,
                           stride_size2d.height, depth_multiplier, activation,
                           dilation_size2d.width, dilation_size2d.height)
                           .Union();
@@ -314,7 +415,7 @@
   } else {
     operator_kind = tflite::BuiltinOperator_CONV_2D;
     builtin_options = tflite::CreateConv2DOptions(
-                          builder, padding_mode.value(), stride_size2d.width,
+                          builder, padding_mode->mode, stride_size2d.width,
                           stride_size2d.height, activation,
                           dilation_size2d.width, dilation_size2d.height)
                           .Union();
@@ -336,11 +437,17 @@
     if (input->DataType() != V8MLOperandDataType::Enum::kFloat32) {
       return base::unexpected("The data type of input is not supported.");
     }
-    bias_index = SerializeZeroBiasBuffer<float>(
-        input->DataType(), output_channels, builder, buffers, tensors);
+    const TensorInfo<float> zero_buffer_info = {
+        .type = BlinkOperandTypeToTFLite(input->DataType()),
+        .dimensions = {base::checked_cast<int32_t>(output_channels)},
+        .values = Vector<float>(output_channels)};
+    bias_index = SerializeTensorWithBuffer<float>(zero_buffer_info, builder,
+                                                  buffers, tensors);
   }
-  const std::vector<int32_t> op_inputs = {input_index, filter_index,
-                                          bias_index};
+
+  const std::vector<int32_t> op_inputs = {
+      explicit_pad_index ? explicit_pad_index.value() : input_index,
+      filter_index, bias_index};
   const std::vector<int32_t> op_outputs = {output_index};
   return tflite::CreateOperator(builder, operator_code_index,
                                 builder.CreateVector<int32_t>(op_inputs),
@@ -399,11 +506,109 @@
       builder.CreateVector<int32_t>(operator_outputs));
 }
 
+base::expected<OperatorOffset, String> SerializePad(
+    const OperandToIndexMap& operand_to_index_map,
+    const MLOperator* pad,
+    flatbuffers::FlatBufferBuilder& builder,
+    Vector<OperatorCodeOffset>& operator_codes,
+    Vector<BufferOffset>& buffers,
+    Vector<TensorOffset>& tensors) {
+  const MLPadOperator* pad_operator = static_cast<const MLPadOperator*>(pad);
+  const int32_t input_index =
+      GetOperatorInputIndex(pad_operator, operand_to_index_map);
+  const int32_t output_index =
+      GetOperatorOutputIndex(pad_operator, operand_to_index_map);
+
+  // Paddings is an integer tensor array filled with pre and post padding.
+  const Vector<uint32_t>& pre_paddings = pad_operator->BeginningPadding();
+  const Vector<uint32_t>& post_paddings = pad_operator->EndingPadding();
+  CHECK_EQ(pre_paddings.size(), post_paddings.size());
+  Vector<int32_t> paddings(pre_paddings.size() + post_paddings.size());
+  for (size_t i = 0; i < pre_paddings.size(); ++i) {
+    auto checked_pre_padding = base::MakeCheckedNum<int32_t>(pre_paddings[i]);
+    auto checked_post_padding = base::MakeCheckedNum<int32_t>(post_paddings[i]);
+    if (!checked_pre_padding.IsValid() || !checked_post_padding.IsValid()) {
+      return base::unexpected("The padding is too large.");
+    }
+    paddings[i * 2] = checked_pre_padding.ValueOrDie();
+    paddings[i * 2 + 1] = checked_post_padding.ValueOrDie();
+  }
+
+  // The shape of padding is [n, 2], where n is the rank of input as described
+  // here https://www.tensorflow.org/mlir/tfl_ops#tflmirror_pad_tflmirrorpadop.
+  const Vector<int32_t> paddings_shape{
+      {base::checked_cast<int32_t>(pre_paddings.size()), 2}};
+  const TensorInfo<int32_t> paddings_info = {.type = tflite::TensorType_INT32,
+                                             .dimensions = paddings_shape,
+                                             .values = paddings};
+  const auto paddings_index = SerializeTensorWithBuffer<int32_t>(
+      paddings_info, builder, buffers, tensors);
+
+  // Create the inputs of operator with the index of input and paddings, the
+  // index of padding value will be pushed back into the vector if the padding
+  // mode is Constant.
+  std::vector<int32_t> op_inputs = {input_index, paddings_index};
+  const MLPadOptions* options =
+      static_cast<const MLPadOptions*>(pad_operator->Options());
+  CHECK(options);
+  tflite::BuiltinOptions builtin_options_type = tflite::BuiltinOptions_NONE;
+  flatbuffers::Offset<void> builtin_options = 0;
+  tflite::BuiltinOperator operator_code;
+  switch (options->mode().AsEnum()) {
+    case blink::V8MLPaddingMode::Enum::kReflection: {
+      operator_code = tflite::BuiltinOperator_MIRROR_PAD;
+      builtin_options_type = tflite::BuiltinOptions_MirrorPadOptions;
+      builtin_options =
+          CreateMirrorPadOptions(builder, tflite::MirrorPadMode_REFLECT)
+              .Union();
+      break;
+    }
+    case blink::V8MLPaddingMode::Enum::kSymmetric: {
+      operator_code = tflite::BuiltinOperator_MIRROR_PAD;
+      builtin_options_type = tflite::BuiltinOptions_MirrorPadOptions;
+      builtin_options =
+          CreateMirrorPadOptions(builder, tflite::MirrorPadMode_SYMMETRIC)
+              .Union();
+      break;
+    }
+    case blink::V8MLPaddingMode::Enum::kConstant: {
+      operator_code = tflite::BuiltinOperator_PADV2;
+      builtin_options = tflite::CreatePadV2Options(builder).Union();
+      float padding_value = options->value();
+      const TensorInfo<float> padding_value_info = {
+          .type = tflite::TensorType_FLOAT32,
+          .dimensions = {1},
+          .values = {padding_value}};
+      const auto padding_value_index = SerializeTensorWithBuffer<float>(
+          padding_value_info, builder, buffers, tensors);
+      op_inputs.push_back(padding_value_index);
+      break;
+    }
+    case blink::V8MLPaddingMode::Enum::kEdge:
+      return base::unexpected(
+          "The edge padding mode is not supported in tflite schema.");
+  }
+
+  // Create `tflite::Operator` with the tensor index of inputs and outputs
+  // operand. The type of operation is determined by the index of the operator
+  // code.
+  const auto operator_code_index =
+      GetOperatorCodeIndex(operator_code, builder, operator_codes);
+  const std::array<int32_t, 1> op_outputs = {output_index};
+  return tflite::CreateOperator(builder, operator_code_index,
+                                builder.CreateVector<int32_t>(op_inputs),
+                                builder.CreateVector<int32_t>(op_outputs),
+                                builtin_options_type, builtin_options);
+}
+
 base::expected<OperatorOffset, String> SerializePool2d(
     const OperandToIndexMap& operand_to_index_map,
     const MLOperator* pool2d,
     flatbuffers::FlatBufferBuilder& builder,
-    Vector<OperatorCodeOffset>& operator_codes) {
+    Vector<OperatorCodeOffset>& operator_codes,
+    Vector<OperatorOffset>& operators,
+    Vector<BufferOffset>& buffers,
+    Vector<TensorOffset>& tensors) {
   const int32_t input_index =
       GetOperatorInputIndex(pool2d, operand_to_index_map);
   const int32_t output_index =
@@ -465,6 +670,18 @@
   if (!padding_mode.has_value()) {
     return base::unexpected(padding_mode.error());
   }
+  // Insert a Pad operator before TfLite Pool2d if needed for explicit padding.
+  absl::optional<int32_t> explicit_pad_index;
+  const auto& explicit_padding = padding_mode->paddings;
+  if (explicit_padding) {
+    const auto serialization_result = SerializeExplicitPad(
+        input, input_index, explicit_padding.value(), builder, operator_codes,
+        operators, buffers, tensors);
+    if (!serialization_result.has_value()) {
+      return base::unexpected(serialization_result.error());
+    }
+    explicit_pad_index = serialization_result.value();
+  }
 
   tflite::BuiltinOperator operator_kind;
   switch (pool2d->Kind()) {
@@ -479,7 +696,7 @@
   }
 
   const auto pool_2d_options = CreatePool2DOptions(
-      builder, padding_mode.value(), stride_size2d.width, stride_size2d.height,
+      builder, padding_mode->mode, stride_size2d.width, stride_size2d.height,
       filter_size2d.width, filter_size2d.height,
       tflite::ActivationFunctionType_NONE);
 
@@ -488,7 +705,8 @@
   // code.
   const auto operator_code_index =
       GetOperatorCodeIndex(operator_kind, builder, operator_codes);
-  const std::vector<int32_t> op_inputs = {input_index};
+  const std::vector<int32_t> op_inputs = {
+      explicit_pad_index ? explicit_pad_index.value() : input_index};
   const std::vector<int32_t> op_outputs = {output_index};
   return tflite::CreateOperator(
       builder, operator_code_index, builder.CreateVector<int32_t>(op_inputs),
@@ -705,7 +923,7 @@
     case MLOperator::OperatorKind::kConv2d: {
       const auto conv2d_result =
           SerializeConv2d(operand_to_index_map, op, builder_, operator_codes_,
-                          buffers_, tensors_);
+                          operators_, buffers_, tensors_);
       // Some conv2d attributes are not supported in tflite schema.
       if (!conv2d_result.has_value()) {
         return base::unexpected(conv2d_result.error());
@@ -792,11 +1010,22 @@
       operator_offset = SerializeLeakyRelu(operand_to_index_map, op, builder_,
                                            operator_codes_);
       break;
+    case MLOperator::OperatorKind::kPad: {
+      const auto pad_result = SerializePad(operand_to_index_map, op, builder_,
+                                           operator_codes_, buffers_, tensors_);
+      // The Edge padding model is not supported in tflite schema.
+      if (!pad_result.has_value()) {
+        return base::unexpected(pad_result.error());
+      }
+      operator_offset = pad_result.value();
+      break;
+    }
     case MLOperator::OperatorKind::kAveragePool2d:
       [[fallthrough]];
     case MLOperator::OperatorKind::kMaxPool2d: {
       const auto pool2d_result =
-          SerializePool2d(operand_to_index_map, op, builder_, operator_codes_);
+          SerializePool2d(operand_to_index_map, op, builder_, operator_codes_,
+                          operators_, buffers_, tensors_);
       // Some pool2d attributes are not supported in tflite schema.
       if (!pool2d_result.has_value()) {
         return base::unexpected(pool2d_result.error());
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_operator.h b/third_party/blink/renderer/modules/ml/webnn/ml_operator.h
index bca3cb8..af2820a5 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_operator.h
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_operator.h
@@ -116,7 +116,7 @@
   MLOperator(const MLOperator&) = delete;
   MLOperator& operator=(const MLOperator&) = delete;
 
-  ~MLOperator();
+  virtual ~MLOperator();
 
   void Trace(Visitor* visitor) const;
 
@@ -156,7 +156,7 @@
   MLConcatOperator(const MLConcatOperator&) = delete;
   MLConcatOperator& operator=(const MLConcatOperator&) = delete;
 
-  ~MLConcatOperator();
+  ~MLConcatOperator() override;
 
   uint32_t Axis() const;
 
@@ -174,7 +174,7 @@
   MLPadOperator(const MLPadOperator&) = delete;
   MLPadOperator& operator=(const MLPadOperator&) = delete;
 
-  ~MLPadOperator();
+  ~MLPadOperator() override;
 
   const Vector<uint32_t>& BeginningPadding() const;
   const Vector<uint32_t>& EndingPadding() const;
@@ -193,7 +193,7 @@
   MLSliceOperator(const MLSliceOperator&) = delete;
   MLSliceOperator& operator=(const MLSliceOperator&) = delete;
 
-  ~MLSliceOperator();
+  ~MLSliceOperator() override;
 
   const Vector<uint32_t>& Starts() const;
   const Vector<uint32_t>& Sizes() const;
@@ -215,7 +215,7 @@
   MLSplitOperator(const MLSplitOperator&) = delete;
   MLSplitOperator& operator=(const MLSplitOperator&) = delete;
 
-  ~MLSplitOperator();
+  ~MLSplitOperator() override;
 
   bool IsEvenSplit() const;
   uint32_t SplitNumber() const;
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
index 5b00983..38023c536 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
@@ -1311,6 +1311,14 @@
 
   MarkCodecActive();
 
+  if (output.size == 0) {
+    // The encoder drops a frame.WebCodecs doesn't specify a way of signaling
+    // a frame was dropped. For now, the output callback is not invoked for the
+    // dropped frame. TODO(https://www.w3.org/TR/webcodecs/#encodedvideochunk):
+    // Notify a client that a frame is dropped.
+    return;
+  }
+
   auto buffer =
       media::DecoderBuffer::FromArray(std::move(output.data), output.size);
   buffer->set_timestamp(output.timestamp);
diff --git a/third_party/blink/renderer/platform/bindings/no_alloc_direct_call_host.cc b/third_party/blink/renderer/platform/bindings/no_alloc_direct_call_host.cc
index f4d803c..e89a347b 100644
--- a/third_party/blink/renderer/platform/bindings/no_alloc_direct_call_host.cc
+++ b/third_party/blink/renderer/platform/bindings/no_alloc_direct_call_host.cc
@@ -7,9 +7,6 @@
 
 namespace blink {
 
-NoAllocDirectCallHost::NoAllocDirectCallHost()
-    : heap_handle_(ThreadState::Current()->cpp_heap().GetHeapHandle()) {}
-
 void NoAllocDirectCallHost::PostDeferrableAction(DeferrableAction&& action) {
   if (IsInFastMode()) {
     deferred_actions_.push_back(std::move(action));
diff --git a/third_party/blink/renderer/platform/bindings/no_alloc_direct_call_host.h b/third_party/blink/renderer/platform/bindings/no_alloc_direct_call_host.h
index 0eadbba6..1922625 100644
--- a/third_party/blink/renderer/platform/bindings/no_alloc_direct_call_host.h
+++ b/third_party/blink/renderer/platform/bindings/no_alloc_direct_call_host.h
@@ -44,8 +44,6 @@
 // NoAllocDirectCall extended IDL attribute.
 class PLATFORM_EXPORT NoAllocDirectCallHost {
  public:
-  NoAllocDirectCallHost();
-
   using DeferrableAction = base::OnceCallback<void()>;
 
   // Methods called from the implementations of APIs that use NoAllocDirectCall.
@@ -76,15 +74,10 @@
   // Methods used by NoAllocDirectCallScope
   //========================================
 
-  cppgc::HeapHandle& heap_handle() { return *heap_handle_; }
   void EnterNoAllocDirectCallScope(v8::FastApiCallbackOptions*);
   void ExitNoAllocDirectCallScope();
 
  private:
-  // We cache the heap handle here to avoid accessing thread-local storage
-  // (ThreadState::Current) on each NADC method call.
-  const raw_ref<cppgc::HeapHandle, ExperimentalRenderer> heap_handle_;
-
   WTF::Vector<DeferrableAction> deferred_actions_;
   raw_ptr<v8::FastApiCallbackOptions, ExperimentalRenderer> callback_options_ =
       nullptr;
@@ -99,7 +92,6 @@
 
  private:
   NoAllocDirectCallHost* const host_;
-  const cppgc::subtle::DisallowGarbageCollectionScope disallow_gc_;
 };
 
 // We use inline definitions for the methods used in bindings boilerplate that
@@ -123,7 +115,7 @@
 inline NoAllocDirectCallScope::NoAllocDirectCallScope(
     NoAllocDirectCallHost* host,
     v8::FastApiCallbackOptions* callback_options)
-    : host_(host), disallow_gc_(host->heap_handle()) {
+    : host_(host) {
   host_->EnterNoAllocDirectCallScope(callback_options);
 }
 
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index 445d8939..89c1e8c4 100755
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -2025,6 +2025,16 @@
     },
     {
         'paths': [
+            'third_party/blink/renderer/modules/ml/webnn/ml_graph_tflite_converter.cc',
+            'third_party/blink/renderer/modules/ml/webnn/ml_graph_test_model_loader.cc',
+        ],
+        'allowed': [
+            'flatbuffers::.+',
+            'tflite::.+',
+        ]
+    },
+    {
+        'paths': [
             'third_party/blink/renderer/modules/ad_auction/',
             'third_party/blink/renderer/modules/shared_storage/',
         ],
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/fetch-later/activate-post-when-document-alive.https-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/fetch-later/activate-post-when-document-alive.https-expected.txt
new file mode 100644
index 0000000..533d1dff
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/fetch-later/activate-post-when-document-alive.https-expected.txt
@@ -0,0 +1,110 @@
+Tests that appropriate Network domain events are dispatched for a fetchLater POST request when its Document is alive.
+Network.requestWillBeSent{
+    documentURL : <string>
+    frameId : <string>
+    hasUserGesture : false
+    initiator : {
+        type : script
+        url : https://127.0.0.1:8443/
+    }
+    loaderId : <string>
+    redirectHasExtraInfo : false
+    request : {
+        hasPostData : true
+        headers : {
+            Accept : */*
+            Content-Type : text/plain;charset=UTF-8
+            Referer : https://127.0.0.1:8443/inspector-protocol/resources/inspector-protocol-page.html
+            User-Agent : <string>
+            sec-ch-ua : "content_shell";v="999"
+            sec-ch-ua-mobile : ?0
+            sec-ch-ua-platform : "Unknown"
+        }
+        initialPriority : High
+        method : POST
+        mixedContentType : blockable
+        postData : {"foo":"bar"}
+        postDataEntries : [
+            [0] : {
+                bytes : eyJmb28iOiJiYXIifQ==
+            }
+        ]
+        referrerPolicy : strict-origin-when-cross-origin
+        url : https://127.0.0.1:8443/devtools/network/resources/resource.php
+    }
+    requestId : <string>
+    timestamp : <number>
+    type : Fetch
+    wallTime : <number>
+}
+Network.responseReceived{
+    frameId : <string>
+    hasExtraInfo : false
+    loaderId : <string>
+    requestId : <string>
+    response : {
+        alternateProtocolUsage : unspecifiedReason
+        charset : 
+        connectionId : <number>
+        connectionReused : true
+        encodedDataLength : 334
+        fromDiskCache : false
+        fromPrefetchCache : false
+        fromServiceWorker : false
+        headers : {
+            Access-Control-Allow-Origin : *
+            Cache-Control : no-store, no-cache, must-revalidate
+            Connection : Keep-Alive
+            Content-Length : 11
+            Content-Type : text/plain
+            Date : <string>
+            Expires : Thu, 01 Dec 2003 16:00:00 GMT
+            Keep-Alive : timeout=10
+            Pragma : no-cache
+            Server : Apache
+            X-Powered-By : <string>
+        }
+        mimeType : text/plain
+        protocol : http/1.1
+        remoteIPAddress : 127.0.0.1
+        remotePort : 8443
+        responseTime : <number>
+        securityState : insecure
+        status : 200
+        statusText : OK
+        timing : {
+            connectEnd : -1
+            connectStart : -1
+            dnsEnd : -1
+            dnsStart : -1
+            proxyEnd : -1
+            proxyStart : -1
+            pushEnd : 0
+            pushStart : 0
+            receiveHeadersEnd : <number>
+            receiveHeadersStart : <number>
+            requestTime : <number>
+            sendEnd : <number>
+            sendStart : <number>
+            sslEnd : -1
+            sslStart : -1
+            workerFetchStart : -1
+            workerReady : -1
+            workerRespondWithSettled : -1
+            workerStart : -1
+        }
+        url : https://127.0.0.1:8443/devtools/network/resources/resource.php
+    }
+    timestamp : <number>
+    type : Fetch
+}
+Network.loadingFinished{
+    encodedDataLength : 345
+    requestId : <string>
+    timestamp : <number>
+}
+Unable to get fetchLater response body{
+    code : -32000
+    message : No resource with given identifier found
+}
+
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/fetch-later/activate-post-when-document-alive.https.js b/third_party/blink/web_tests/http/tests/inspector-protocol/fetch-later/activate-post-when-document-alive.https.js
new file mode 100644
index 0000000..362fed83
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/fetch-later/activate-post-when-document-alive.https.js
@@ -0,0 +1,44 @@
+(async function(/** @type {import('test_runner').TestRunner} */ testRunner) {
+  const {_, session, dp} = await testRunner.startBlank(
+      `Tests that appropriate Network domain events are dispatched for a fetchLater POST request when its Document is alive.`);
+
+  dp.Page.enable();
+  dp.Page.reload();
+  await dp.Page.onceLoadEventFired();
+
+  const gatherNetworkEvents =
+      await testRunner.loadScript('resources/gather-network-events.js');
+  const events = gatherNetworkEvents(testRunner, dp, {requests: 1, log: true});
+
+  await session.evaluateAsync(async () => {
+    const url = '/devtools/network/resources/resource.php';
+
+    function waitForActivated(fetchLaterResult) {
+      function waitFor(result) {
+        if (result && result.activated) {
+          return result;
+        }
+        return new Promise(resolve => setTimeout(resolve, 100))
+            .then(() => waitFor(fetchLaterResult));
+      }
+      return waitFor();
+    }
+    return waitForActivated(fetchLater(url, {
+      activateAfter: 0,
+      method: 'POST',
+      body: JSON.stringify({foo: 'bar'})
+    }));
+  });
+
+  const requestId = (await events)
+                        .find(event => event.params.type === 'Fetch')
+                        ?.params.requestId;
+  const msg = await dp.Network.getResponseBody({requestId: requestId});
+  if (msg.error) {
+    testRunner.log(msg.error, 'Unable to get fetchLater response body');
+  } else {
+    testRunner.log(msg.result, 'fetchLater response body');
+  }
+
+  testRunner.completeTest();
+})
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/system-wake-lock/idlharness-worker.https.window-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/system-wake-lock/idlharness-worker.https.window-expected.txt
deleted file mode 100644
index 4abf76bd..0000000
--- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/system-wake-lock/idlharness-worker.https.window-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Traceback (most recent call last):\n  File "/b/s/w/ir/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py", line 511, in run_func\n    self.result = True, self.func(self.protocol, self.url, self.timeout)\n  File "/b/s/w/ir/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py", line 612, in do_testharness\n    done, rv = handler(result)\n  File "/b/s/w/ir/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/base.py", line 738, in __call__\n    return callback(url, payload)\n  File "/b/s/w/ir/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/base.py", line 753, in process_action\n    with ActionContext(self.logger, self.protocol, payload.get("context")):\n  File "/b/s/w/ir/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/base.py", line 795, in __enter__\n    self.protocol.testdriver.switch_to_window(self.context, self.initial_window)\n  File "/b/s/w/ir/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/protocol.py", line 501, in switch_to_window\n    raise Exception("Window with id %s not found" % wptrunner_id)\nException: Window with id False not found\n
-Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/system-wake-lock/idlharness.https.window-expected.txt b/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/system-wake-lock/idlharness.https.window-expected.txt
deleted file mode 100644
index 4abf76bd..0000000
--- a/third_party/blink/web_tests/platform/linux-chrome/wpt_internal/system-wake-lock/idlharness.https.window-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Traceback (most recent call last):\n  File "/b/s/w/ir/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py", line 511, in run_func\n    self.result = True, self.func(self.protocol, self.url, self.timeout)\n  File "/b/s/w/ir/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py", line 612, in do_testharness\n    done, rv = handler(result)\n  File "/b/s/w/ir/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/base.py", line 738, in __call__\n    return callback(url, payload)\n  File "/b/s/w/ir/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/base.py", line 753, in process_action\n    with ActionContext(self.logger, self.protocol, payload.get("context")):\n  File "/b/s/w/ir/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/base.py", line 795, in __enter__\n    self.protocol.testdriver.switch_to_window(self.context, self.initial_window)\n  File "/b/s/w/ir/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/protocol.py", line 501, in switch_to_window\n    raise Exception("Window with id %s not found" % wptrunner_id)\nException: Window with id False not found\n
-Harness: the test ran to completion.
diff --git "a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters-a-area.window_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters-a-area.window_exclude=\050file_javascript_mailto\051-expected.txt"
index 59640ce..66798a9 100644
--- "a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters-a-area.window_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters-a-area.window_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,17 +1,5 @@
 This is a testharness.js-based test.
-Found 118 FAIL, 0 TIMEOUT, 0 NOTRUN.
-[FAIL] <a>: Setting <a://example.net>.protocol = 'b'
-  assert_equals: expected "b://example.net" but got "b:"
-[FAIL] <area>: Setting <a://example.net>.protocol = 'b'
-  assert_equals: expected "b://example.net" but got "b:"
-[FAIL] <a>: Setting <a://example.net>.protocol = 'B' Upper-case ASCII is lower-cased
-  assert_equals: expected "b://example.net" but got "b:"
-[FAIL] <area>: Setting <a://example.net>.protocol = 'B' Upper-case ASCII is lower-cased
-  assert_equals: expected "b://example.net" but got "b:"
-[FAIL] <a>: Setting <a://example.net>.protocol = 'bC0+-.'
-  assert_equals: expected "bc0+-.://example.net" but got "bc0+-.:"
-[FAIL] <area>: Setting <a://example.net>.protocol = 'bC0+-.'
-  assert_equals: expected "bc0+-.://example.net" but got "bc0+-.:"
+Found 112 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] <a>: Setting <ssh://me@example.net>.protocol = 'http' Can’t switch from non-special scheme to special
   assert_equals: expected "ssh://me@example.net" but got "http://me@example.net/"
 [FAIL] <area>: Setting <ssh://me@example.net>.protocol = 'http' Can’t switch from non-special scheme to special
@@ -45,17 +33,17 @@
 [FAIL] <area>: Setting <http://example.net>.username = '\0	\n\r !"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~€Éé' UTF-8 percent encoding with the userinfo encode set.
   assert_equals: expected "http://%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" but got "http://%00%01%09%0A%0D%1F%20!%22%23$%&%27()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/"
 [FAIL] <a>: Setting <sc:///>.username = 'x'
-  assert_equals: expected "sc:///" but got "sc:/"
+  assert_equals: expected "sc:///" but got "sc://x@/"
 [FAIL] <area>: Setting <sc:///>.username = 'x'
-  assert_equals: expected "sc:///" but got "sc:/"
+  assert_equals: expected "sc:///" but got "sc://x@/"
 [FAIL] <a>: Setting <http://example.net>.password = '\0	\n\r !"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~€Éé' UTF-8 percent encoding with the userinfo encode set.
   assert_equals: expected "http://:%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" but got "http://:%00%01%09%0A%0D%1F%20!%22%23$%&%27()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/"
 [FAIL] <area>: Setting <http://example.net>.password = '\0	\n\r !"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~€Éé' UTF-8 percent encoding with the userinfo encode set.
   assert_equals: expected "http://:%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" but got "http://:%00%01%09%0A%0D%1F%20!%22%23$%&%27()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/"
 [FAIL] <a>: Setting <sc:///>.password = 'x'
-  assert_equals: expected "sc:///" but got "sc:/"
+  assert_equals: expected "sc:///" but got "sc://:x@/"
 [FAIL] <area>: Setting <sc:///>.password = 'x'
-  assert_equals: expected "sc:///" but got "sc:/"
+  assert_equals: expected "sc:///" but got "sc://:x@/"
 [FAIL] <a>: Setting <sc://x/>.host = '	'
   assert_equals: expected "sc:///" but got "sc://x/"
 [FAIL] <area>: Setting <sc://x/>.host = '	'
diff --git a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters-a-area.window_include=javascript-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters-a-area.window_include=javascript-expected.txt
index 1be80c3..0732e22 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters-a-area.window_include=javascript-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters-a-area.window_include=javascript-expected.txt
@@ -1,12 +1,4 @@
 This is a testharness.js-based test.
-[FAIL] <a>: Setting <javascript://x/>.username = 'wario'
-  assert_equals: expected "javascript://wario@x/" but got "javascript:/"
-[FAIL] <area>: Setting <javascript://x/>.username = 'wario'
-  assert_equals: expected "javascript://wario@x/" but got "javascript:/"
-[FAIL] <a>: Setting <javascript://x/>.password = 'bowser'
-  assert_equals: expected "javascript://:bowser@x/" but got "javascript:/"
-[FAIL] <area>: Setting <javascript://x/>.password = 'bowser'
-  assert_equals: expected "javascript://:bowser@x/" but got "javascript:/"
 [FAIL] <a>: Setting <javascript://x/>.port = '12'
   assert_equals: expected "javascript://x:12/" but got "javascript://x/"
 [FAIL] <area>: Setting <javascript://x/>.port = '12'
diff --git a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters-stripping.any-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters-stripping.any-expected.txt
index c4c581f9..1667d2b 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters-stripping.any-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters-stripping.any-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 124 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 64 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] Setting protocol with leading U+0009 (https:)
   assert_equals: property expected "http:" but got "https:"
 [FAIL] Setting protocol with U+0009 before inserted colon (https:)
@@ -12,18 +12,6 @@
   assert_equals: property expected "http:" but got "https:"
 [FAIL] Setting protocol with U+000D before inserted colon (https:)
   assert_equals: property expected "http:" but got "https:"
-[FAIL] Setting username with leading U+0000 (wpt++:)
-  assert_equals: property expected "%00test" but got ""
-[FAIL] Setting username with middle U+0000 (wpt++:)
-  assert_equals: property expected "te%00st" but got ""
-[FAIL] Setting username with trailing U+0000 (wpt++:)
-  assert_equals: property expected "test%00" but got ""
-[FAIL] Setting password with leading U+0000 (wpt++:)
-  assert_equals: property expected "%00test" but got ""
-[FAIL] Setting password with middle U+0000 (wpt++:)
-  assert_equals: property expected "te%00st" but got ""
-[FAIL] Setting password with trailing U+0000 (wpt++:)
-  assert_equals: property expected "test%00" but got ""
 [FAIL] Setting port with middle U+0000 (wpt++:)
   assert_equals: property expected "90" but got "8000"
 [FAIL] Setting port with trailing U+0000 (wpt++:)
@@ -34,34 +22,10 @@
   assert_equals: property expected "/te%00st" but got "/path"
 [FAIL] Setting pathname with trailing U+0000 (wpt++:)
   assert_equals: property expected "/test%00" but got "/path"
-[FAIL] Setting search with leading U+0000 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?%00test#fragment" but got "wpt++:/path?%00test#fragment"
-[FAIL] Setting search with middle U+0000 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?te%00st#fragment" but got "wpt++:/path?te%00st#fragment"
-[FAIL] Setting search with trailing U+0000 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test%00#fragment" but got "wpt++:/path?test%00#fragment"
-[FAIL] Setting hash with leading U+0000 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#%00test" but got "wpt++:/path?query#%00test"
-[FAIL] Setting hash with middle U+0000 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#te%00st" but got "wpt++:/path?query#te%00st"
-[FAIL] Setting hash with trailing U+0000 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test%00" but got "wpt++:/path?query#test%00"
 [FAIL] Setting protocol with leading U+0009 (wpt++:)
   assert_equals: property expected "wpt--:" but got "wpt++:"
 [FAIL] Setting protocol with U+0009 before inserted colon (wpt++:)
   assert_equals: property expected "wpt--:" but got "wpt++:"
-[FAIL] Setting username with leading U+0009 (wpt++:)
-  assert_equals: property expected "%09test" but got ""
-[FAIL] Setting username with middle U+0009 (wpt++:)
-  assert_equals: property expected "te%09st" but got ""
-[FAIL] Setting username with trailing U+0009 (wpt++:)
-  assert_equals: property expected "test%09" but got ""
-[FAIL] Setting password with leading U+0009 (wpt++:)
-  assert_equals: property expected "%09test" but got ""
-[FAIL] Setting password with middle U+0009 (wpt++:)
-  assert_equals: property expected "te%09st" but got ""
-[FAIL] Setting password with trailing U+0009 (wpt++:)
-  assert_equals: property expected "test%09" but got ""
 [FAIL] Setting host with leading U+0009 (wpt++:)
   assert_equals: property expected "test:8000" but got "host:8000"
 [FAIL] Setting hostname with leading U+0009 (wpt++:)
@@ -86,34 +50,10 @@
   assert_equals: property expected "/test" but got "/path"
 [FAIL] Setting pathname with trailing U+0009 (wpt++:)
   assert_equals: property expected "/test" but got "/path"
-[FAIL] Setting search with leading U+0009 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test#fragment" but got "wpt++:/path?test#fragment"
-[FAIL] Setting search with middle U+0009 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test#fragment" but got "wpt++:/path?test#fragment"
-[FAIL] Setting search with trailing U+0009 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test#fragment" but got "wpt++:/path?test#fragment"
-[FAIL] Setting hash with leading U+0009 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test" but got "wpt++:/path?query#test"
-[FAIL] Setting hash with middle U+0009 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test" but got "wpt++:/path?query#test"
-[FAIL] Setting hash with trailing U+0009 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test" but got "wpt++:/path?query#test"
 [FAIL] Setting protocol with leading U+000A (wpt++:)
   assert_equals: property expected "wpt--:" but got "wpt++:"
 [FAIL] Setting protocol with U+000A before inserted colon (wpt++:)
   assert_equals: property expected "wpt--:" but got "wpt++:"
-[FAIL] Setting username with leading U+000A (wpt++:)
-  assert_equals: property expected "%0Atest" but got ""
-[FAIL] Setting username with middle U+000A (wpt++:)
-  assert_equals: property expected "te%0Ast" but got ""
-[FAIL] Setting username with trailing U+000A (wpt++:)
-  assert_equals: property expected "test%0A" but got ""
-[FAIL] Setting password with leading U+000A (wpt++:)
-  assert_equals: property expected "%0Atest" but got ""
-[FAIL] Setting password with middle U+000A (wpt++:)
-  assert_equals: property expected "te%0Ast" but got ""
-[FAIL] Setting password with trailing U+000A (wpt++:)
-  assert_equals: property expected "test%0A" but got ""
 [FAIL] Setting host with leading U+000A (wpt++:)
   assert_equals: property expected "test:8000" but got "host:8000"
 [FAIL] Setting hostname with leading U+000A (wpt++:)
@@ -138,34 +78,10 @@
   assert_equals: property expected "/test" but got "/path"
 [FAIL] Setting pathname with trailing U+000A (wpt++:)
   assert_equals: property expected "/test" but got "/path"
-[FAIL] Setting search with leading U+000A (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test#fragment" but got "wpt++:/path?test#fragment"
-[FAIL] Setting search with middle U+000A (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test#fragment" but got "wpt++:/path?test#fragment"
-[FAIL] Setting search with trailing U+000A (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test#fragment" but got "wpt++:/path?test#fragment"
-[FAIL] Setting hash with leading U+000A (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test" but got "wpt++:/path?query#test"
-[FAIL] Setting hash with middle U+000A (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test" but got "wpt++:/path?query#test"
-[FAIL] Setting hash with trailing U+000A (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test" but got "wpt++:/path?query#test"
 [FAIL] Setting protocol with leading U+000D (wpt++:)
   assert_equals: property expected "wpt--:" but got "wpt++:"
 [FAIL] Setting protocol with U+000D before inserted colon (wpt++:)
   assert_equals: property expected "wpt--:" but got "wpt++:"
-[FAIL] Setting username with leading U+000D (wpt++:)
-  assert_equals: property expected "%0Dtest" but got ""
-[FAIL] Setting username with middle U+000D (wpt++:)
-  assert_equals: property expected "te%0Dst" but got ""
-[FAIL] Setting username with trailing U+000D (wpt++:)
-  assert_equals: property expected "test%0D" but got ""
-[FAIL] Setting password with leading U+000D (wpt++:)
-  assert_equals: property expected "%0Dtest" but got ""
-[FAIL] Setting password with middle U+000D (wpt++:)
-  assert_equals: property expected "te%0Dst" but got ""
-[FAIL] Setting password with trailing U+000D (wpt++:)
-  assert_equals: property expected "test%0D" but got ""
 [FAIL] Setting host with leading U+000D (wpt++:)
   assert_equals: property expected "test:8000" but got "host:8000"
 [FAIL] Setting hostname with leading U+000D (wpt++:)
@@ -190,30 +106,6 @@
   assert_equals: property expected "/test" but got "/path"
 [FAIL] Setting pathname with trailing U+000D (wpt++:)
   assert_equals: property expected "/test" but got "/path"
-[FAIL] Setting search with leading U+000D (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test#fragment" but got "wpt++:/path?test#fragment"
-[FAIL] Setting search with middle U+000D (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test#fragment" but got "wpt++:/path?test#fragment"
-[FAIL] Setting search with trailing U+000D (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test#fragment" but got "wpt++:/path?test#fragment"
-[FAIL] Setting hash with leading U+000D (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test" but got "wpt++:/path?query#test"
-[FAIL] Setting hash with middle U+000D (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test" but got "wpt++:/path?query#test"
-[FAIL] Setting hash with trailing U+000D (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test" but got "wpt++:/path?query#test"
-[FAIL] Setting username with leading U+001F (wpt++:)
-  assert_equals: property expected "%1Ftest" but got ""
-[FAIL] Setting username with middle U+001F (wpt++:)
-  assert_equals: property expected "te%1Fst" but got ""
-[FAIL] Setting username with trailing U+001F (wpt++:)
-  assert_equals: property expected "test%1F" but got ""
-[FAIL] Setting password with leading U+001F (wpt++:)
-  assert_equals: property expected "%1Ftest" but got ""
-[FAIL] Setting password with middle U+001F (wpt++:)
-  assert_equals: property expected "te%1Fst" but got ""
-[FAIL] Setting password with trailing U+001F (wpt++:)
-  assert_equals: property expected "test%1F" but got ""
 [FAIL] Setting host with leading U+001F (wpt++:)
   assert_equals: property expected "%1Ftest:8000" but got "host:8000"
 [FAIL] Setting hostname with leading U+001F (wpt++:)
@@ -236,17 +128,5 @@
   assert_equals: property expected "/te%1Fst" but got "/path"
 [FAIL] Setting pathname with trailing U+001F (wpt++:)
   assert_equals: property expected "/test%1F" but got "/path"
-[FAIL] Setting search with leading U+001F (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?%1Ftest#fragment" but got "wpt++:/path?%1Ftest#fragment"
-[FAIL] Setting search with middle U+001F (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?te%1Fst#fragment" but got "wpt++:/path?te%1Fst#fragment"
-[FAIL] Setting search with trailing U+001F (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test%1F#fragment" but got "wpt++:/path?test%1F#fragment"
-[FAIL] Setting hash with leading U+001F (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#%1Ftest" but got "wpt++:/path?query#%1Ftest"
-[FAIL] Setting hash with middle U+001F (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#te%1Fst" but got "wpt++:/path?query#te%1Fst"
-[FAIL] Setting hash with trailing U+001F (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test%1F" but got "wpt++:/path?query#test%1F"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters-stripping.any.worker-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters-stripping.any.worker-expected.txt
index c4c581f9..1667d2b 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters-stripping.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters-stripping.any.worker-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 124 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 64 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] Setting protocol with leading U+0009 (https:)
   assert_equals: property expected "http:" but got "https:"
 [FAIL] Setting protocol with U+0009 before inserted colon (https:)
@@ -12,18 +12,6 @@
   assert_equals: property expected "http:" but got "https:"
 [FAIL] Setting protocol with U+000D before inserted colon (https:)
   assert_equals: property expected "http:" but got "https:"
-[FAIL] Setting username with leading U+0000 (wpt++:)
-  assert_equals: property expected "%00test" but got ""
-[FAIL] Setting username with middle U+0000 (wpt++:)
-  assert_equals: property expected "te%00st" but got ""
-[FAIL] Setting username with trailing U+0000 (wpt++:)
-  assert_equals: property expected "test%00" but got ""
-[FAIL] Setting password with leading U+0000 (wpt++:)
-  assert_equals: property expected "%00test" but got ""
-[FAIL] Setting password with middle U+0000 (wpt++:)
-  assert_equals: property expected "te%00st" but got ""
-[FAIL] Setting password with trailing U+0000 (wpt++:)
-  assert_equals: property expected "test%00" but got ""
 [FAIL] Setting port with middle U+0000 (wpt++:)
   assert_equals: property expected "90" but got "8000"
 [FAIL] Setting port with trailing U+0000 (wpt++:)
@@ -34,34 +22,10 @@
   assert_equals: property expected "/te%00st" but got "/path"
 [FAIL] Setting pathname with trailing U+0000 (wpt++:)
   assert_equals: property expected "/test%00" but got "/path"
-[FAIL] Setting search with leading U+0000 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?%00test#fragment" but got "wpt++:/path?%00test#fragment"
-[FAIL] Setting search with middle U+0000 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?te%00st#fragment" but got "wpt++:/path?te%00st#fragment"
-[FAIL] Setting search with trailing U+0000 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test%00#fragment" but got "wpt++:/path?test%00#fragment"
-[FAIL] Setting hash with leading U+0000 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#%00test" but got "wpt++:/path?query#%00test"
-[FAIL] Setting hash with middle U+0000 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#te%00st" but got "wpt++:/path?query#te%00st"
-[FAIL] Setting hash with trailing U+0000 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test%00" but got "wpt++:/path?query#test%00"
 [FAIL] Setting protocol with leading U+0009 (wpt++:)
   assert_equals: property expected "wpt--:" but got "wpt++:"
 [FAIL] Setting protocol with U+0009 before inserted colon (wpt++:)
   assert_equals: property expected "wpt--:" but got "wpt++:"
-[FAIL] Setting username with leading U+0009 (wpt++:)
-  assert_equals: property expected "%09test" but got ""
-[FAIL] Setting username with middle U+0009 (wpt++:)
-  assert_equals: property expected "te%09st" but got ""
-[FAIL] Setting username with trailing U+0009 (wpt++:)
-  assert_equals: property expected "test%09" but got ""
-[FAIL] Setting password with leading U+0009 (wpt++:)
-  assert_equals: property expected "%09test" but got ""
-[FAIL] Setting password with middle U+0009 (wpt++:)
-  assert_equals: property expected "te%09st" but got ""
-[FAIL] Setting password with trailing U+0009 (wpt++:)
-  assert_equals: property expected "test%09" but got ""
 [FAIL] Setting host with leading U+0009 (wpt++:)
   assert_equals: property expected "test:8000" but got "host:8000"
 [FAIL] Setting hostname with leading U+0009 (wpt++:)
@@ -86,34 +50,10 @@
   assert_equals: property expected "/test" but got "/path"
 [FAIL] Setting pathname with trailing U+0009 (wpt++:)
   assert_equals: property expected "/test" but got "/path"
-[FAIL] Setting search with leading U+0009 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test#fragment" but got "wpt++:/path?test#fragment"
-[FAIL] Setting search with middle U+0009 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test#fragment" but got "wpt++:/path?test#fragment"
-[FAIL] Setting search with trailing U+0009 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test#fragment" but got "wpt++:/path?test#fragment"
-[FAIL] Setting hash with leading U+0009 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test" but got "wpt++:/path?query#test"
-[FAIL] Setting hash with middle U+0009 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test" but got "wpt++:/path?query#test"
-[FAIL] Setting hash with trailing U+0009 (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test" but got "wpt++:/path?query#test"
 [FAIL] Setting protocol with leading U+000A (wpt++:)
   assert_equals: property expected "wpt--:" but got "wpt++:"
 [FAIL] Setting protocol with U+000A before inserted colon (wpt++:)
   assert_equals: property expected "wpt--:" but got "wpt++:"
-[FAIL] Setting username with leading U+000A (wpt++:)
-  assert_equals: property expected "%0Atest" but got ""
-[FAIL] Setting username with middle U+000A (wpt++:)
-  assert_equals: property expected "te%0Ast" but got ""
-[FAIL] Setting username with trailing U+000A (wpt++:)
-  assert_equals: property expected "test%0A" but got ""
-[FAIL] Setting password with leading U+000A (wpt++:)
-  assert_equals: property expected "%0Atest" but got ""
-[FAIL] Setting password with middle U+000A (wpt++:)
-  assert_equals: property expected "te%0Ast" but got ""
-[FAIL] Setting password with trailing U+000A (wpt++:)
-  assert_equals: property expected "test%0A" but got ""
 [FAIL] Setting host with leading U+000A (wpt++:)
   assert_equals: property expected "test:8000" but got "host:8000"
 [FAIL] Setting hostname with leading U+000A (wpt++:)
@@ -138,34 +78,10 @@
   assert_equals: property expected "/test" but got "/path"
 [FAIL] Setting pathname with trailing U+000A (wpt++:)
   assert_equals: property expected "/test" but got "/path"
-[FAIL] Setting search with leading U+000A (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test#fragment" but got "wpt++:/path?test#fragment"
-[FAIL] Setting search with middle U+000A (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test#fragment" but got "wpt++:/path?test#fragment"
-[FAIL] Setting search with trailing U+000A (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test#fragment" but got "wpt++:/path?test#fragment"
-[FAIL] Setting hash with leading U+000A (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test" but got "wpt++:/path?query#test"
-[FAIL] Setting hash with middle U+000A (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test" but got "wpt++:/path?query#test"
-[FAIL] Setting hash with trailing U+000A (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test" but got "wpt++:/path?query#test"
 [FAIL] Setting protocol with leading U+000D (wpt++:)
   assert_equals: property expected "wpt--:" but got "wpt++:"
 [FAIL] Setting protocol with U+000D before inserted colon (wpt++:)
   assert_equals: property expected "wpt--:" but got "wpt++:"
-[FAIL] Setting username with leading U+000D (wpt++:)
-  assert_equals: property expected "%0Dtest" but got ""
-[FAIL] Setting username with middle U+000D (wpt++:)
-  assert_equals: property expected "te%0Dst" but got ""
-[FAIL] Setting username with trailing U+000D (wpt++:)
-  assert_equals: property expected "test%0D" but got ""
-[FAIL] Setting password with leading U+000D (wpt++:)
-  assert_equals: property expected "%0Dtest" but got ""
-[FAIL] Setting password with middle U+000D (wpt++:)
-  assert_equals: property expected "te%0Dst" but got ""
-[FAIL] Setting password with trailing U+000D (wpt++:)
-  assert_equals: property expected "test%0D" but got ""
 [FAIL] Setting host with leading U+000D (wpt++:)
   assert_equals: property expected "test:8000" but got "host:8000"
 [FAIL] Setting hostname with leading U+000D (wpt++:)
@@ -190,30 +106,6 @@
   assert_equals: property expected "/test" but got "/path"
 [FAIL] Setting pathname with trailing U+000D (wpt++:)
   assert_equals: property expected "/test" but got "/path"
-[FAIL] Setting search with leading U+000D (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test#fragment" but got "wpt++:/path?test#fragment"
-[FAIL] Setting search with middle U+000D (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test#fragment" but got "wpt++:/path?test#fragment"
-[FAIL] Setting search with trailing U+000D (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test#fragment" but got "wpt++:/path?test#fragment"
-[FAIL] Setting hash with leading U+000D (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test" but got "wpt++:/path?query#test"
-[FAIL] Setting hash with middle U+000D (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test" but got "wpt++:/path?query#test"
-[FAIL] Setting hash with trailing U+000D (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test" but got "wpt++:/path?query#test"
-[FAIL] Setting username with leading U+001F (wpt++:)
-  assert_equals: property expected "%1Ftest" but got ""
-[FAIL] Setting username with middle U+001F (wpt++:)
-  assert_equals: property expected "te%1Fst" but got ""
-[FAIL] Setting username with trailing U+001F (wpt++:)
-  assert_equals: property expected "test%1F" but got ""
-[FAIL] Setting password with leading U+001F (wpt++:)
-  assert_equals: property expected "%1Ftest" but got ""
-[FAIL] Setting password with middle U+001F (wpt++:)
-  assert_equals: property expected "te%1Fst" but got ""
-[FAIL] Setting password with trailing U+001F (wpt++:)
-  assert_equals: property expected "test%1F" but got ""
 [FAIL] Setting host with leading U+001F (wpt++:)
   assert_equals: property expected "%1Ftest:8000" but got "host:8000"
 [FAIL] Setting hostname with leading U+001F (wpt++:)
@@ -236,17 +128,5 @@
   assert_equals: property expected "/te%1Fst" but got "/path"
 [FAIL] Setting pathname with trailing U+001F (wpt++:)
   assert_equals: property expected "/test%1F" but got "/path"
-[FAIL] Setting search with leading U+001F (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?%1Ftest#fragment" but got "wpt++:/path?%1Ftest#fragment"
-[FAIL] Setting search with middle U+001F (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?te%1Fst#fragment" but got "wpt++:/path?te%1Fst#fragment"
-[FAIL] Setting search with trailing U+001F (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?test%1F#fragment" but got "wpt++:/path?test%1F#fragment"
-[FAIL] Setting hash with leading U+001F (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#%1Ftest" but got "wpt++:/path?query#%1Ftest"
-[FAIL] Setting hash with middle U+001F (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#te%1Fst" but got "wpt++:/path?query#te%1Fst"
-[FAIL] Setting hash with trailing U+001F (wpt++:)
-  assert_equals: href expected "wpt++://username:password@host:8000/path?query#test%1F" but got "wpt++:/path?query#test%1F"
 Harness: the test ran to completion.
 
diff --git "a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
index bba4df1..9e34b6c 100644
--- "a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,11 +1,5 @@
 This is a testharness.js-based test.
-Found 63 FAIL, 0 TIMEOUT, 0 NOTRUN.
-[FAIL] URL: Setting <a://example.net>.protocol = 'b'
-  assert_equals: expected "b://example.net" but got "b:"
-[FAIL] URL: Setting <a://example.net>.protocol = 'B' Upper-case ASCII is lower-cased
-  assert_equals: expected "b://example.net" but got "b:"
-[FAIL] URL: Setting <a://example.net>.protocol = 'bC0+-.'
-  assert_equals: expected "bc0+-.://example.net" but got "bc0+-.:"
+Found 60 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] URL: Setting <ssh://me@example.net>.protocol = 'http' Can’t switch from non-special scheme to special
   assert_equals: expected "ssh://me@example.net" but got "http://me@example.net/"
 [FAIL] URL: Setting <ssh://me@example.net>.protocol = 'https'
@@ -23,11 +17,11 @@
 [FAIL] URL: Setting <http://example.net>.username = '\0	\n\r !"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~€Éé' UTF-8 percent encoding with the userinfo encode set.
   assert_equals: expected "http://%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" but got "http://%00%01%09%0A%0D%1F%20!%22%23$%&%27()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/"
 [FAIL] URL: Setting <sc:///>.username = 'x'
-  assert_equals: expected "sc:///" but got "sc:/"
+  assert_equals: expected "sc:///" but got "sc://x@/"
 [FAIL] URL: Setting <http://example.net>.password = '\0	\n\r !"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~€Éé' UTF-8 percent encoding with the userinfo encode set.
   assert_equals: expected "http://:%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" but got "http://:%00%01%09%0A%0D%1F%20!%22%23$%&%27()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/"
 [FAIL] URL: Setting <sc:///>.password = 'x'
-  assert_equals: expected "sc:///" but got "sc:/"
+  assert_equals: expected "sc:///" but got "sc://:x@/"
 [FAIL] URL: Setting <sc://x/>.host = '	'
   assert_equals: expected "sc:///" but got "sc://x/"
 [FAIL] URL: Setting <sc://x/>.host = '\n'
diff --git a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters.any.worker_include=javascript-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters.any.worker_include=javascript-expected.txt
index 3cb4699e9..b02a04d3 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters.any.worker_include=javascript-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters.any.worker_include=javascript-expected.txt
@@ -1,8 +1,4 @@
 This is a testharness.js-based test.
-[FAIL] URL: Setting <javascript://x/>.username = 'wario'
-  assert_equals: expected "javascript://wario@x/" but got "javascript:/"
-[FAIL] URL: Setting <javascript://x/>.password = 'bowser'
-  assert_equals: expected "javascript://:bowser@x/" but got "javascript:/"
 [FAIL] URL: Setting <javascript://x/>.port = '12'
   assert_equals: expected "javascript://x:12/" but got "javascript://x/"
 Harness: the test ran to completion.
diff --git "a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt"
index bba4df1..9e34b6c 100644
--- "a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,11 +1,5 @@
 This is a testharness.js-based test.
-Found 63 FAIL, 0 TIMEOUT, 0 NOTRUN.
-[FAIL] URL: Setting <a://example.net>.protocol = 'b'
-  assert_equals: expected "b://example.net" but got "b:"
-[FAIL] URL: Setting <a://example.net>.protocol = 'B' Upper-case ASCII is lower-cased
-  assert_equals: expected "b://example.net" but got "b:"
-[FAIL] URL: Setting <a://example.net>.protocol = 'bC0+-.'
-  assert_equals: expected "bc0+-.://example.net" but got "bc0+-.:"
+Found 60 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] URL: Setting <ssh://me@example.net>.protocol = 'http' Can’t switch from non-special scheme to special
   assert_equals: expected "ssh://me@example.net" but got "http://me@example.net/"
 [FAIL] URL: Setting <ssh://me@example.net>.protocol = 'https'
@@ -23,11 +17,11 @@
 [FAIL] URL: Setting <http://example.net>.username = '\0	\n\r !"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~€Éé' UTF-8 percent encoding with the userinfo encode set.
   assert_equals: expected "http://%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" but got "http://%00%01%09%0A%0D%1F%20!%22%23$%&%27()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/"
 [FAIL] URL: Setting <sc:///>.username = 'x'
-  assert_equals: expected "sc:///" but got "sc:/"
+  assert_equals: expected "sc:///" but got "sc://x@/"
 [FAIL] URL: Setting <http://example.net>.password = '\0	\n\r !"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~€Éé' UTF-8 percent encoding with the userinfo encode set.
   assert_equals: expected "http://:%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/" but got "http://:%00%01%09%0A%0D%1F%20!%22%23$%&%27()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/"
 [FAIL] URL: Setting <sc:///>.password = 'x'
-  assert_equals: expected "sc:///" but got "sc:/"
+  assert_equals: expected "sc:///" but got "sc://:x@/"
 [FAIL] URL: Setting <sc://x/>.host = '	'
   assert_equals: expected "sc:///" but got "sc://x/"
 [FAIL] URL: Setting <sc://x/>.host = '\n'
diff --git a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters.any_include=javascript-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters.any_include=javascript-expected.txt
index 3cb4699e9..b02a04d3 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters.any_include=javascript-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/external/wpt/url/url-setters.any_include=javascript-expected.txt
@@ -1,8 +1,4 @@
 This is a testharness.js-based test.
-[FAIL] URL: Setting <javascript://x/>.username = 'wario'
-  assert_equals: expected "javascript://wario@x/" but got "javascript:/"
-[FAIL] URL: Setting <javascript://x/>.password = 'bowser'
-  assert_equals: expected "javascript://:bowser@x/" but got "javascript:/"
 [FAIL] URL: Setting <javascript://x/>.port = '12'
   assert_equals: expected "javascript://x:12/" but got "javascript://x/"
 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/wpt_internal/system-wake-lock/idlharness-worker.https.window.js b/third_party/blink/web_tests/wpt_internal/system-wake-lock/idlharness-worker.https.window.js
index 546b085..fe5d1d2b 100644
--- a/third_party/blink/web_tests/wpt_internal/system-wake-lock/idlharness-worker.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/system-wake-lock/idlharness-worker.https.window.js
@@ -4,8 +4,6 @@
 'use strict';
 
 promise_test(async t => {
-  await test_driver.set_permission(
-      { name: 'system-wake-lock' }, 'granted', false);
-
+  await test_driver.set_permission({ name: 'system-wake-lock' }, 'granted');
   await fetch_tests_from_worker(new Worker('resources/idlharness-worker.js'));
 }, 'Run idlharness tests in a worker.');
diff --git a/third_party/blink/web_tests/wpt_internal/system-wake-lock/idlharness.https.window.js b/third_party/blink/web_tests/wpt_internal/system-wake-lock/idlharness.https.window.js
index 305c351..f80e27c 100644
--- a/third_party/blink/web_tests/wpt_internal/system-wake-lock/idlharness.https.window.js
+++ b/third_party/blink/web_tests/wpt_internal/system-wake-lock/idlharness.https.window.js
@@ -18,7 +18,7 @@
     });
 
     await test_driver.set_permission(
-        { name: 'system-wake-lock' }, 'granted', false);
+        { name: 'system-wake-lock' }, 'granted');
     self.sentinel = await navigator.wakeLock.request('system');
     self.sentinel.release();
   }
diff --git a/third_party/catapult b/third_party/catapult
index c2c3cef..f092a86 160000
--- a/third_party/catapult
+++ b/third_party/catapult
@@ -1 +1 @@
-Subproject commit c2c3cef34d1a1cee17fffcf34c98a6a9a352d064
+Subproject commit f092a8625f3f04979970ace175bd99c2f4196c08
diff --git a/third_party/depot_tools b/third_party/depot_tools
index 0696c428..120efcb 160000
--- a/third_party/depot_tools
+++ b/third_party/depot_tools
@@ -1 +1 @@
-Subproject commit 0696c428b04513254d3b3e0b1fba5e5afdb11cf4
+Subproject commit 120efcb475aa5f8c6f38c4598c602f4713015112
diff --git a/third_party/devtools-frontend-internal b/third_party/devtools-frontend-internal
index 30cbeb8..d27a6b8 160000
--- a/third_party/devtools-frontend-internal
+++ b/third_party/devtools-frontend-internal
@@ -1 +1 @@
-Subproject commit 30cbeb81ec54e2be41b6de16ad50353ea798740d
+Subproject commit d27a6b83a969ae8c9a02df0e03e5756a1f4c521a
diff --git a/third_party/skia b/third_party/skia
index de3f398..c29a207 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit de3f3987a8365b51e4f0546442f8d990a376e192
+Subproject commit c29a20702356a118d09d173755d66315b16127cf
diff --git a/third_party/webrtc b/third_party/webrtc
index 1df2690..1188d08 160000
--- a/third_party/webrtc
+++ b/third_party/webrtc
@@ -1 +1 @@
-Subproject commit 1df269099fcb3c8e7474786a21bcdd32335c43ed
+Subproject commit 1188d0849f18baf91ab0061781ea1a521363b8bd
diff --git a/tools/metrics/histograms/metadata/accessibility/histograms.xml b/tools/metrics/histograms/metadata/accessibility/histograms.xml
index bf838d1..2349b75 100644
--- a/tools/metrics/histograms/metadata/accessibility/histograms.xml
+++ b/tools/metrics/histograms/metadata/accessibility/histograms.xml
@@ -743,7 +743,7 @@
 
 <histogram
     name="Accessibility.CrosDictation.ListeningDuration.OnDeviceRecognition"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>katie@chromium.org</owner>
   <owner>chrome-a11y-core@google.com</owner>
   <summary>
@@ -775,7 +775,7 @@
 </histogram>
 
 <histogram name="Accessibility.CrosDictation.PumpkinSucceeded"
-    enum="BooleanUsage" expires_after="2024-06-02">
+    enum="BooleanUsage" expires_after="2024-08-04">
   <owner>akihiroota@chromium.org</owner>
   <owner>chrome-a11y-core@google.com</owner>
   <summary>
@@ -793,7 +793,7 @@
 </histogram>
 
 <histogram name="Accessibility.CrosDictation.UsedOnDeviceSpeech"
-    enum="BooleanUsage" expires_after="2024-06-02">
+    enum="BooleanUsage" expires_after="2024-08-04">
   <owner>katie@chromium.org</owner>
   <owner>chrome-a11y-core@google.com</owner>
   <summary>
@@ -957,7 +957,7 @@
 </histogram>
 
 <histogram name="Accessibility.CrosSelectToSpeak.SentenceNavigationMethod"
-    enum="CrosSelectToSpeakActivationMethod" expires_after="2024-06-02">
+    enum="CrosSelectToSpeakActivationMethod" expires_after="2024-08-04">
   <owner>ajitnarayanan@google.com</owner>
   <owner>chrome-a11y-core@google.com</owner>
   <summary>
@@ -1777,7 +1777,7 @@
 </histogram>
 
 <histogram name="Accessibility.PdfOcr.InaccessiblePdfPageCount" units="count"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>kyungjunlee@google.com</owner>
   <owner>chrome-a11y-core@google.com</owner>
   <summary>
@@ -1787,7 +1787,7 @@
 </histogram>
 
 <histogram name="Accessibility.PdfOcr.MostDetectedLanguageInOcrData"
-    enum="LocaleCodeISO639" expires_after="2024-06-01">
+    enum="LocaleCodeISO639" expires_after="2024-08-04">
   <owner>kyungjunlee@google.com</owner>
   <owner>chrome-a11y-core@google.com</owner>
   <summary>
@@ -1797,7 +1797,7 @@
 </histogram>
 
 <histogram name="Accessibility.PdfOcr.PDFImages" enum="PdfOcrRequestStatus"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>kyungjunlee@google.com</owner>
   <owner>chrome-a11y-core@google.com</owner>
   <summary>
@@ -1811,7 +1811,7 @@
 </histogram>
 
 <histogram name="Accessibility.PdfOcr.UserAcceptLanguage"
-    enum="LocaleCodeISO639" expires_after="2024-06-01">
+    enum="LocaleCodeISO639" expires_after="2024-08-04">
   <owner>kyungjunlee@google.com</owner>
   <owner>chrome-a11y-core@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml
index 76d886f..8a92613f 100644
--- a/tools/metrics/histograms/metadata/android/histograms.xml
+++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -775,7 +775,7 @@
 </histogram>
 
 <histogram name="Android.ContactsPicker.ContactCount" units="Contacts"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>finnur@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <summary>
@@ -785,7 +785,7 @@
 </histogram>
 
 <histogram name="Android.ContactsPicker.DialogAction"
-    enum="ContactsPickerDialogAction" expires_after="2024-06-01">
+    enum="ContactsPickerDialogAction" expires_after="2024-08-04">
   <owner>finnur@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <summary>
@@ -795,7 +795,7 @@
 </histogram>
 
 <histogram name="Android.ContactsPicker.PropertiesRequested"
-    enum="ContactsPickerProperties" expires_after="2024-06-01">
+    enum="ContactsPickerProperties" expires_after="2024-08-04">
   <owner>finnur@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <summary>
@@ -806,7 +806,7 @@
 </histogram>
 
 <histogram name="Android.ContactsPicker.PropertiesUserRejected"
-    enum="ContactsPickerProperties" expires_after="2024-06-01">
+    enum="ContactsPickerProperties" expires_after="2024-08-04">
   <owner>finnur@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <summary>
@@ -816,7 +816,7 @@
 </histogram>
 
 <histogram name="Android.ContactsPicker.SelectCount" units="Contacts"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>finnur@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <summary>
@@ -827,7 +827,7 @@
 </histogram>
 
 <histogram name="Android.ContactsPicker.SelectPercentage" units="%"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>finnur@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <summary>
@@ -838,7 +838,7 @@
 </histogram>
 
 <histogram name="Android.CpuAbiBitnessSupport" enum="CpuAbiBitnessSupport"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>bartekn@chromium.org</owner>
   <owner>lizeb@chromium.org</owner>
   <summary>
@@ -919,7 +919,7 @@
 </histogram>
 
 <histogram name="Android.DeviceAuthenticator.AuthSource"
-    enum="DeviceAuthSource" expires_after="2024-06-04">
+    enum="DeviceAuthSource" expires_after="2024-08-04">
   <owner>ioanap@chromium.org</owner>
   <owner>fhorschig@chromium.org</owner>
   <owner>theocristea@google.com</owner>
@@ -1306,7 +1306,7 @@
 </histogram>
 
 <histogram name="Android.Event.ActionDown" enum="InputDeviceSource"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>mvanouwerkerk@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
   <owner>src/chrome/android/OWNERS</owner>
@@ -1908,7 +1908,7 @@
 </histogram>
 
 <histogram name="Android.MediaPickerShown" enum="MediaPickerShown"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>finnur@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
@@ -2246,7 +2246,7 @@
 </histogram>
 
 <histogram name="Android.MultipleUserProfilesState"
-    enum="MultipleUserProfilesState" expires_after="2024-06-02">
+    enum="MultipleUserProfilesState" expires_after="2024-08-04">
   <owner>ckitagawa@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
   <owner>bartekn@chromium.org</owner>
@@ -3335,7 +3335,7 @@
 </histogram>
 
 <histogram name="Android.PhotoPicker.DialogAction"
-    enum="PhotoPickerDialogAction" expires_after="2024-06-01">
+    enum="PhotoPickerDialogAction" expires_after="2024-08-04">
   <owner>finnur@chromium.org</owner>
   <owner>twellington@chromium.org</owner>
   <summary>
@@ -3489,7 +3489,7 @@
 </histogram>
 
 <histogram name="Android.PlayServices.ShortVersion" enum="GmsShortVersionCode"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>twellington@chromium.org</owner>
   <owner>tedchoc@chromium.org</owner>
   <summary>
@@ -3963,7 +3963,7 @@
 </histogram>
 
 <histogram name="Android.Sync.ActualSyncedTabCountPercentage"
-    units="% of tab count" expires_after="2024-06-02">
+    units="% of tab count" expires_after="2024-08-04">
   <owner>bjfong@google.com</owner>
   <owner>ckitagawa@chromium.org</owner>
   <summary>
@@ -4153,7 +4153,7 @@
 </histogram>
 
 <histogram name="Android.TabStrip.PlaceholderStripLeftoverTabsCount"
-    units="tabs" expires_after="2024-06-02">
+    units="tabs" expires_after="2024-08-04">
   <owner>nemco@google.com</owner>
   <owner>skavuluru@google.com</owner>
   <owner>twellington@chromium.org</owner>
@@ -4173,7 +4173,7 @@
 
 <histogram
     name="Android.TabStrip.PlaceholderStripTabsCreatedDuringRestoreCount"
-    units="tabs" expires_after="2024-06-02">
+    units="tabs" expires_after="2024-08-04">
   <owner>nemco@google.com</owner>
   <owner>skavuluru@google.com</owner>
   <owner>twellington@chromium.org</owner>
@@ -4277,7 +4277,7 @@
 </histogram>
 
 <histogram name="Android.TabStrip.TitleBitmapFactory.getTitleBitmap.Duration"
-    units="ms" expires_after="2024-04-01">
+    units="ms" expires_after="2024-08-04">
   <owner>peilinwang@google.com</owner>
   <summary>
     The duration of TitleBitmapFactory.getTitleBitmap, recorded once per call.
@@ -4481,7 +4481,7 @@
 </histogram>
 
 <histogram name="Android.VersionCode" enum="VersionCode"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>bartekn@chromium.org</owner>
   <owner>lizeb@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/apps/histograms.xml b/tools/metrics/histograms/metadata/apps/histograms.xml
index ccf3fe1..d4e19ec2 100644
--- a/tools/metrics/histograms/metadata/apps/histograms.xml
+++ b/tools/metrics/histograms/metadata/apps/histograms.xml
@@ -720,7 +720,7 @@
 </histogram>
 
 <histogram name="Apps.AppList.Keyword.NumberOfKeywordsInQuery" units="count"
-    expires_after="2024-04-28">
+    expires_after="2024-08-04">
   <owner>chenjih@chromium.org</owner>
   <owner>dgrebenyuk@chromium.org</owner>
   <summary>
@@ -1134,7 +1134,7 @@
 </histogram>
 
 <histogram name="Apps.AppList.Search.Session2.{LauncherSearchEntryPoint}"
-    enum="LauncherSearchSessionConclusion" expires_after="2024-06-02">
+    enum="LauncherSearchSessionConclusion" expires_after="2024-08-04">
   <owner>yulunwu@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>tbarzic@chromium.org</owner>
@@ -1278,7 +1278,7 @@
 
 <histogram
     name="Apps.AppList.SortDiscoveryDurationAfterEducationNudgeV2.{TabletOrClamshell}"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>andrewxu@chromium.org</owner>
   <owner>tbarzic@chromium.org</owner>
   <summary>
@@ -1915,7 +1915,7 @@
 </histogram>
 
 <histogram name="Apps.AppsCount.{AppType}" units="Apps"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>nancylingwang@chromium.org</owner>
   <owner>chromeos-apps-foundation-team@google.com</owner>
   <component>Platform&gt;Apps&gt;Foundation</component>
@@ -1929,7 +1929,7 @@
 </histogram>
 
 <histogram name="Apps.AppsCountPerInstallReason.{AppType}.{InstallReason}"
-    units="Apps" expires_after="2024-06-01">
+    units="Apps" expires_after="2024-08-04">
   <owner>nancylingwang@chromium.org</owner>
   <owner>chromeos-apps-foundation-team@google.com</owner>
   <component>Platform&gt;Apps&gt;Foundation</component>
@@ -2065,7 +2065,7 @@
 </histogram>
 
 <histogram name="Apps.DefaultAppLaunch{DefaultAppLaunchSource}"
-    enum="DefaultAppName" expires_after="2024-06-01">
+    enum="DefaultAppName" expires_after="2024-08-04">
   <owner>nancylingwang@chromium.org</owner>
   <owner>chromeos-apps-foundation-team@google.com</owner>
   <owner>cros-peripherals@google.com</owner>
@@ -2531,7 +2531,7 @@
 </histogram>
 
 <histogram name="Apps.RunningDuration.{AppType}" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>nancylingwang@chromium.org</owner>
   <owner>chromeos-apps-foundation-team@google.com</owner>
   <component>Platform&gt;Apps&gt;Foundation</component>
@@ -2716,7 +2716,7 @@
 </histogram>
 
 <histogram name="Apps.UsageTime.{AppType}" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>nancylingwang@chromium.org</owner>
   <owner>chromeos-apps-foundation-team@google.com</owner>
   <component>Platform&gt;Apps&gt;Foundation</component>
@@ -2728,7 +2728,7 @@
 </histogram>
 
 <histogram name="Apps.UsageTimeV2.{AppTypeV2}" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>nancylingwang@chromium.org</owner>
   <owner>chromeos-apps-foundation-team@google.com</owner>
   <component>Platform&gt;Apps&gt;Foundation</component>
diff --git a/tools/metrics/histograms/metadata/arc/histograms.xml b/tools/metrics/histograms/metadata/arc/histograms.xml
index 342a9dfa..7955ddc7 100644
--- a/tools/metrics/histograms/metadata/arc/histograms.xml
+++ b/tools/metrics/histograms/metadata/arc/histograms.xml
@@ -553,7 +553,7 @@
 </histogram>
 
 <histogram name="Arc.AppSync.InitialSession.InstalledAppSize" units="MB"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>batoon@google.com</owner>
   <owner>arc-core@google.com</owner>
   <summary>
@@ -577,7 +577,7 @@
 </histogram>
 
 <histogram name="Arc.AppSync.InitialSession.NumApps{ArcSyncAppTypes}"
-    units="apps" expires_after="2024-06-02">
+    units="apps" expires_after="2024-08-04">
   <owner>batoon@google.com</owner>
   <owner>arc-core@google.com</owner>
   <summary>
@@ -785,7 +785,7 @@
 
 <histogram
     name="Arc.CloudDpc{TimedCloudDpcOp}.TimeDelta{SuccessFailure}{ArcUserTypes}"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>batoon@google.com</owner>
   <owner>mhasank@google.com</owner>
   <owner>arc-commercial@google.com</owner>
@@ -1367,7 +1367,7 @@
 </histogram>
 
 <histogram name="Arc.NearbyShare.ArcBridgeFailure"
-    enum="NearbyShareArcBridgeFailResult" expires_after="2024-03-27">
+    enum="NearbyShareArcBridgeFailResult" expires_after="2024-08-04">
   <owner>alanding@google.com</owner>
   <owner>arc-app-dev@google.com</owner>
   <summary>
@@ -2293,7 +2293,7 @@
 </histogram>
 
 <histogram name="Arc.VmDataMigration.GetAndroidDataInfoDuration" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>momohatt@google.com</owner>
   <owner>youkichihosoi@google.com</owner>
   <owner>arc-storage@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index f6864c57..d0e571a 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -1229,7 +1229,7 @@
 </histogram>
 
 <histogram name="Ash.BrowserDataMigrator.MoveMigrator.TaskStatus"
-    enum="MoveMigratorTaskStatus" expires_after="2024-06-02">
+    enum="MoveMigratorTaskStatus" expires_after="2024-08-04">
   <owner>ythjkt@chromium.org</owner>
   <owner>hidehiko@chromium.org</owner>
   <summary>
@@ -1626,7 +1626,7 @@
 
 <histogram
     name="Ash.CaptureModeController.AudioRecordingMode.{TabletOrClamshell}"
-    enum="AudioRecordingMode" expires_after="2024-06-01">
+    enum="AudioRecordingMode" expires_after="2024-08-04">
   <owner>afakhry@chromium.org</owner>
   <owner>gzadina@google.com</owner>
   <summary>
@@ -1749,7 +1749,7 @@
 
 <histogram
     name="Ash.CaptureModeController.GameDashboard.SaveLocation.{TabletOrClamshell}"
-    enum="CaptureModeSaveToLocation" expires_after="2024-05-27">
+    enum="CaptureModeSaveToLocation" expires_after="2024-08-04">
   <owner>michelefan@chromium.org</owner>
   <owner>gzadina@google.com</owner>
   <summary>
@@ -1969,7 +1969,7 @@
 
 <histogram
     name="Ash.CaptureModeController.{Client}.AudioRecordingMode.{TabletOrClamshell}"
-    enum="AudioRecordingMode" expires_after="2024-06-01">
+    enum="AudioRecordingMode" expires_after="2024-08-04">
   <owner>afakhry@chromium.org</owner>
   <owner>gzadina@google.com</owner>
   <summary>
@@ -1984,7 +1984,7 @@
 
 <histogram
     name="Ash.CaptureModeController.{Client}.CaptureConfiguration.{TabletOrClamshell}"
-    enum="CaptureModeConfiguration" expires_after="2024-05-27">
+    enum="CaptureModeConfiguration" expires_after="2024-08-04">
   <owner>michelefan@chromium.org</owner>
   <owner>gzadina@google.com</owner>
   <summary>
@@ -2230,7 +2230,7 @@
 </histogram>
 
 <histogram name="Ash.Desks.CustomNamePercentage" units="%"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>benbecker@google.com</owner>
   <owner>janetmac@chromium.org</owner>
   <summary>
@@ -3889,7 +3889,7 @@
 </histogram>
 
 <histogram name="Ash.HotseatTransition.Drag.PresentationTime" units="ms"
-    expires_after="2024-05-30">
+    expires_after="2024-08-04">
   <owner>anasalazar@chromium.org</owner>
   <owner>newcomer@chromium.org</owner>
   <summary>
@@ -4259,7 +4259,7 @@
 </histogram>
 
 <histogram base="true" name="Ash.LoginAnimation.Jank" units="%"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>oshima@chromium.org</owner>
   <owner>chromeos-wmp@google.com</owner>
 <!-- Name completed by histogram_suffixes
@@ -5134,7 +5134,7 @@
   </summary>
 </histogram>
 
-<histogram name="Ash.Overview.Items" units="units" expires_after="2024-06-01">
+<histogram name="Ash.Overview.Items" units="units" expires_after="2024-08-04">
   <owner>sammiequon@chromium.org</owner>
   <owner>nupurjain@chromium.org</owner>
   <summary>
@@ -5186,7 +5186,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.SelectionDepth" units="items"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>sammiequon@chromium.org</owner>
   <owner>nupurjain@chromium.org</owner>
   <owner>tclaiborne@chromium.org</owner>
@@ -5208,7 +5208,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.TimeBetweenActiveWindowChanges" units="seconds"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>sammiequon@chromium.org</owner>
   <owner>nupurjain@chromium.org</owner>
   <summary>
@@ -5220,7 +5220,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.TimeBetweenUse" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>sammiequon@chromium.org</owner>
   <owner>nupurjain@chromium.org</owner>
   <summary>
@@ -5231,7 +5231,7 @@
 </histogram>
 
 <histogram name="Ash.Overview.TimeInOverview" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>sammiequon@chromium.org</owner>
   <owner>nupurjain@chromium.org</owner>
   <summary>
@@ -5435,7 +5435,7 @@
 </histogram>
 
 <histogram name="Ash.Personalization.DynamicColor.ToggleButton"
-    enum="BooleanEnabled" expires_after="2024-06-02">
+    enum="BooleanEnabled" expires_after="2024-08-04">
   <owner>ericamlee@google.com</owner>
   <owner>assistive-eng@google.com</owner>
   <summary>
@@ -5476,7 +5476,7 @@
 
 <histogram name="Ash.Personalization.KeyboardBacklight.DisplayType.Settled"
     enum="PersonalizationKeyboardBacklightDisplayType"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>thuongphan@chromium.org</owner>
   <owner>assistive-eng@google.com</owner>
   <summary>
@@ -6504,7 +6504,7 @@
 </histogram>
 
 <histogram name="Ash.Shelf.Palette.Usage" enum="PaletteTrayOptions"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>dmblack@google.com</owner>
   <owner>alexandrahill@google.com</owner>
   <summary>
@@ -6718,7 +6718,7 @@
 </histogram>
 
 <histogram name="Ash.Smoothness.PercentDroppedFrames_1sWindow2{Stage}"
-    units="%" expires_after="2024-06-02">
+    units="%" expires_after="2024-08-04">
   <owner>xiyuan@chromium.org</owner>
   <owner>cros-sw-perf@google.com</owner>
   <summary>
@@ -6851,7 +6851,7 @@
 </histogram>
 
 <histogram name="Ash.SplitView.ResizeWindowCount.{DeviceUIMode}" units="count"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>xdai@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>nupurjain@chromium.org</owner>
@@ -6917,7 +6917,7 @@
 </histogram>
 
 <histogram name="Ash.SplitView.{EngagementTime}.{DeviceUIMode}" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>xdai@chromium.org</owner>
   <owner>zxdan@chromium.org</owner>
   <owner>nupurjain@chromium.org</owner>
@@ -6968,7 +6968,7 @@
 </histogram>
 
 <histogram name="Ash.SplitViewResize.AnimationSmoothness.DividerAnimation"
-    units="%" expires_after="2024-06-02">
+    units="%" expires_after="2024-08-04">
   <owner>sammiequon@chromium.org</owner>
   <owner>xdai@chromium.org</owner>
   <summary>
@@ -7262,7 +7262,7 @@
 </histogram>
 
 <histogram name="Ash.TouchView.TouchViewActive" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm-corexp@google.com</owner>
   <summary>
@@ -7271,14 +7271,14 @@
 </histogram>
 
 <histogram name="Ash.TouchView.TouchViewActivePercentage" units="%"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm-corexp@google.com</owner>
   <summary>The proportion of time spent in TouchView during a session.</summary>
 </histogram>
 
 <histogram name="Ash.TouchView.TouchViewActiveTotal" units="minutes"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm-corexp@google.com</owner>
   <summary>The total time that TouchView is active during a session.</summary>
@@ -7295,7 +7295,7 @@
 </histogram>
 
 <histogram name="Ash.TouchView.TouchViewInactiveTotal" units="minutes"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>xdai@chromium.org</owner>
   <owner>chromeos-wm-corexp@google.com</owner>
   <summary>
@@ -7620,7 +7620,7 @@
 </histogram>
 
 <histogram name="Ash.Wallpaper.GooglePhotos.Api.{Api}.RefreshCount"
-    units="count" expires_after="2024-06-02">
+    units="count" expires_after="2024-08-04">
   <owner>thuongphan@google.com</owner>
   <owner>cowmoo@google.com</owner>
   <owner>assistive-eng@google.com</owner>
@@ -7674,7 +7674,7 @@
 </histogram>
 
 <histogram name="Ash.Wallpaper.GooglePhotos.Source2"
-    enum="WallpaperGooglePhotosSource" expires_after="2024-06-02">
+    enum="WallpaperGooglePhotosSource" expires_after="2024-08-04">
   <owner>thuongphan@google.com</owner>
   <owner>cowmoo@google.com</owner>
   <owner>assistive-eng@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/ash_clipboard/histograms.xml b/tools/metrics/histograms/metadata/ash_clipboard/histograms.xml
index 8db6b5b..ec4f778 100644
--- a/tools/metrics/histograms/metadata/ash_clipboard/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash_clipboard/histograms.xml
@@ -36,7 +36,7 @@
 </histogram>
 
 <histogram name="Ash.Clipboard.ConsecutivePastes" units="times"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -46,7 +46,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.ConsecutivePastes" units="times"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -61,7 +61,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.ContextMenu.DisplayFormatDeleted"
-    enum="ClipboardHistoryDisplayFormat" expires_after="2024-06-01">
+    enum="ClipboardHistoryDisplayFormat" expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -75,7 +75,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.ContextMenu.DisplayFormatPasted"
-    enum="ClipboardHistoryDisplayFormat" expires_after="2024-06-01">
+    enum="ClipboardHistoryDisplayFormat" expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -90,7 +90,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.ContextMenu.DisplayFormatShown"
-    enum="ClipboardHistoryDisplayFormat" expires_after="2024-06-01">
+    enum="ClipboardHistoryDisplayFormat" expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -100,7 +100,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.ContextMenu.MenuOptionSelected"
-    units="index" expires_after="2024-06-01">
+    units="index" expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -110,7 +110,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.ContextMenu.NumberOfItemsShown"
-    units="Items Shown" expires_after="2024-06-01">
+    units="Items Shown" expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -120,7 +120,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.ContextMenu.ShowMenu"
-    enum="ClipboardHistoryTriggerType" expires_after="2024-06-01">
+    enum="ClipboardHistoryTriggerType" expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -130,7 +130,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.ContextMenu.UserJourneyTime" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -141,7 +141,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.ControlToVDelayV2" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -158,7 +158,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.ControlVHeldTime" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -169,7 +169,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.ImageModelRequest.Lifetime" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -182,7 +182,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.ImageModelRequest.Runtime" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -193,7 +193,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.ImageModelRequest.StopReason"
-    enum="RequestStopReason" expires_after="2024-06-01">
+    enum="RequestStopReason" expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -203,7 +203,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.Nudges.{NudgeType}.ShownCount"
-    enum="BooleanHit" expires_after="2024-06-01">
+    enum="BooleanHit" expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -225,7 +225,7 @@
 
 <histogram
     name="Ash.ClipboardHistory.Nudges.{NudgeType}.ToFeature{Action}TimeV2"
-    units="seconds" expires_after="2024-06-01">
+    units="seconds" expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -252,7 +252,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.Operation"
-    enum="ClipboardHistoryOperation" expires_after="2024-06-01">
+    enum="ClipboardHistoryOperation" expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -271,7 +271,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.PasteSource"
-    enum="ClipboardHistoryTriggerType" expires_after="2024-06-01">
+    enum="ClipboardHistoryTriggerType" expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -282,7 +282,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.PasteType"
-    enum="ClipboardHistoryPasteType" expires_after="2024-06-01">
+    enum="ClipboardHistoryPasteType" expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -292,7 +292,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.ReorderType"
-    enum="ClipboardHistoryReorderType" expires_after="2024-06-01">
+    enum="ClipboardHistoryReorderType" expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -302,7 +302,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.UrlTitleFetcher.IsPrimaryProfileActive"
-    enum="BooleanActive" expires_after="2024-06-01">
+    enum="BooleanActive" expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -313,7 +313,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.UrlTitleFetcher.NumProfiles"
-    units="count" expires_after="2024-06-01">
+    units="count" expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
@@ -324,7 +324,7 @@
 </histogram>
 
 <histogram name="Ash.ClipboardHistory.UrlTitleFetcher.UrlFound"
-    enum="BooleanHit" expires_after="2024-06-01">
+    enum="BooleanHit" expires_after="2024-08-04">
   <owner>ckincaid@chromium.org</owner>
   <owner>multipaste@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/ash_user_education/histograms.xml b/tools/metrics/histograms/metadata/ash_user_education/histograms.xml
index 6f0a419..df208a5 100644
--- a/tools/metrics/histograms/metadata/ash_user_education/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash_user_education/histograms.xml
@@ -137,7 +137,7 @@
 </histogram>
 
 <histogram name="Ash.WelcomeTour.Aborted.Reason"
-    enum="WelcomeTourAbortedReason" expires_after="2024-06-01">
+    enum="WelcomeTourAbortedReason" expires_after="2024-08-04">
   <owner>angusmclean@google.com</owner>
   <owner>dmblack@google.com</owner>
   <summary>
@@ -146,7 +146,7 @@
 </histogram>
 
 <histogram name="Ash.WelcomeTour.Prevented.Reason"
-    enum="WelcomeTourPreventedReason" expires_after="2024-06-01">
+    enum="WelcomeTourPreventedReason" expires_after="2024-08-04">
   <owner>angusmclean@google.com</owner>
   <owner>dmblack@google.com</owner>
   <summary>
@@ -157,14 +157,14 @@
 </histogram>
 
 <histogram name="Ash.WelcomeTour.Step.Aborted" enum="WelcomeTourStep"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>angusmclean@google.com</owner>
   <owner>dmblack@google.com</owner>
   <summary>Records that the Welcome Tour was aborted on a given step.</summary>
 </histogram>
 
 <histogram name="Ash.WelcomeTour.Step.Duration.{Step}" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>angusmclean@google.com</owner>
   <owner>dmblack@google.com</owner>
   <summary>
@@ -183,7 +183,7 @@
 </histogram>
 
 <histogram name="Ash.WelcomeTour.Step.Shown" enum="WelcomeTourStep"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>angusmclean@google.com</owner>
   <owner>dmblack@google.com</owner>
   <summary>
@@ -194,7 +194,7 @@
 </histogram>
 
 <histogram name="Ash.WelcomeTour.{Completion}.Duration" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>angusmclean@google.com</owner>
   <owner>dmblack@google.com</owner>
   <summary>
@@ -205,7 +205,7 @@
 </histogram>
 
 <histogram name="Ash.WelcomeTour.{Completion}.Interaction.Count"
-    enum="WelcomeTourInteraction" expires_after="2024-06-01">
+    enum="WelcomeTourInteraction" expires_after="2024-08-04">
   <owner>angusmclean@google.com</owner>
   <owner>dmblack@google.com</owner>
   <summary>
@@ -217,7 +217,7 @@
 
 <histogram
     name="Ash.WelcomeTour.{Completion}.Interaction.FirstTime.{Interaction}"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>angusmclean@google.com</owner>
   <owner>dmblack@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml
index 2b65a6e..6dec92a 100644
--- a/tools/metrics/histograms/metadata/autofill/histograms.xml
+++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -859,7 +859,7 @@
 </histogram>
 
 <histogram name="Autofill.Autocomplete.SingleEntryRemovalMethod"
-    enum="AutofillSingleEntryRemovalMethod" expires_after="2024-06-02">
+    enum="AutofillSingleEntryRemovalMethod" expires_after="2024-08-04">
   <owner>jkeitel@google.com</owner>
   <owner>chrome-autofill-team@google.com</owner>
   <summary>
@@ -2605,7 +2605,7 @@
 </histogram>
 
 <histogram name="Autofill.LabelInference.InferredLabelSource.AtSubmission2"
-    enum="InferredLabelSource" expires_after="2024-06-02">
+    enum="InferredLabelSource" expires_after="2024-08-04">
   <owner>fleimgruber@google.com</owner>
   <owner>chrome-autofill-team@google.com</owner>
   <summary>
@@ -3085,7 +3085,7 @@
 
 <histogram
     name="Autofill.OfferNotificationBubbleOffer.FreeListingCouponOffer.FromHistoryCluster"
-    enum="BooleanYesNo" expires_after="2024-06-01">
+    enum="BooleanYesNo" expires_after="2024-08-04">
   <owner>meiliang@chromium.org</owner>
   <owner>chrome-shopping@google.com</owner>
   <summary>
@@ -3096,7 +3096,7 @@
 </histogram>
 
 <histogram name="Autofill.OfferNotificationBubbleOffer.{BubbleType}"
-    enum="BooleanPreviouslyShown" expires_after="2024-06-02">
+    enum="BooleanPreviouslyShown" expires_after="2024-08-04">
   <owner>siyua@chromium.org</owner>
   <owner>jsaul@google.com</owner>
   <owner>payments-autofill-team@google.com</owner>
@@ -3110,7 +3110,7 @@
 
 <histogram
     name="Autofill.OfferNotificationBubblePromoCodeButtonClicked.FreeListingCouponOffer.FromHistoryCluster"
-    enum="BooleanYesNo" expires_after="2024-06-01">
+    enum="BooleanYesNo" expires_after="2024-08-04">
   <owner>meiliang@chromium.org</owner>
   <owner>chrome-shopping@google.com</owner>
   <summary>
@@ -3300,7 +3300,7 @@
 
 <histogram
     name="Autofill.PageLoadsWithOfferIconShowing.FreeListingCouponOffer.FromHistoryCluster"
-    enum="BooleanYesNo" expires_after="2024-06-01">
+    enum="BooleanYesNo" expires_after="2024-08-04">
   <owner>meiliang@chromium.org</owner>
   <owner>chrome-shopping@google.com</owner>
   <summary>
@@ -3705,7 +3705,7 @@
 </histogram>
 
 <histogram name="Autofill.ProfileImport.InaccessibleFieldsRemoved.ByFieldType"
-    enum="AutofillSettingsVisibleTypes" expires_after="2024-06-02">
+    enum="AutofillSettingsVisibleTypes" expires_after="2024-08-04">
   <owner>fleimgruber@google.com</owner>
   <owner>chrome-autofill-team@google.com</owner>
   <summary>
@@ -3715,7 +3715,7 @@
 </histogram>
 
 <histogram name="Autofill.ProfileImport.InaccessibleFieldsRemoved.Total"
-    enum="Boolean" expires_after="2024-06-02">
+    enum="Boolean" expires_after="2024-08-04">
   <owner>fleimgruber@google.com</owner>
   <owner>chrome-autofill-team@google.com</owner>
   <summary>
@@ -4486,7 +4486,7 @@
 </histogram>
 
 <histogram name="Autofill.ShadowPredictions.{SourcePair}"
-    enum="AutofillPredictionsComparisonResult" expires_after="2024-06-02">
+    enum="AutofillPredictionsComparisonResult" expires_after="2024-08-04">
   <owner>schwering@google.com</owner>
   <owner>fleimgruber@google.com</owner>
   <owner>chrome-autofill-team@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/blink/histograms.xml b/tools/metrics/histograms/metadata/blink/histograms.xml
index ac03ec1..6741b3fb 100644
--- a/tools/metrics/histograms/metadata/blink/histograms.xml
+++ b/tools/metrics/histograms/metadata/blink/histograms.xml
@@ -116,7 +116,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.Accessibility.UpdateTime"
-    units="microseconds" expires_after="2024-06-01">
+    units="microseconds" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>ikilpatrick@chromium.org</owner>
@@ -137,7 +137,7 @@
 
 <histogram base="true"
     name="Blink.AnchorElementMetricsIntersectionObserver.UpdateTime"
-    units="microseconds" expires_after="2024-06-01">
+    units="microseconds" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -319,7 +319,7 @@
 </histogram>
 
 <histogram name="Blink.Canvas.GetImageData.WillReadFrequently"
-    enum="BooleanWillReadFrequently" expires_after="2024-06-02">
+    enum="BooleanWillReadFrequently" expires_after="2024-08-04">
   <owner>aaronhk@chromium.org</owner>
   <owner>junov@chromium.org</owner>
   <summary>
@@ -328,7 +328,7 @@
 </histogram>
 
 <histogram name="Blink.Canvas.GPUFallbackToCPU"
-    enum="CanvasGPUFallbackToCPUScenario" expires_after="2024-06-02">
+    enum="CanvasGPUFallbackToCPUScenario" expires_after="2024-08-04">
   <owner>aaronhk@chromium.org</owner>
   <owner>fserb@chromium.org</owner>
   <summary>Logs the occurrences of canvas fallback from GPU to CPU.</summary>
@@ -395,7 +395,7 @@
 </histogram>
 
 <histogram name="Blink.Canvas.RasterDuration{BlinkCanvasRasterDurationType}"
-    units="microseconds" expires_after="2024-06-02">
+    units="microseconds" expires_after="2024-08-04">
   <owner>aaronhk@chromium.org</owner>
   <owner>fserb@chromium.org</owner>
   <summary>
@@ -446,7 +446,7 @@
 </histogram>
 
 <histogram name="Blink.Canvas.ResourceProviderType"
-    enum="CanvasResourceProviderType" expires_after="2024-06-02">
+    enum="CanvasResourceProviderType" expires_after="2024-08-04">
   <owner>aaronhk@chromium.org</owner>
   <owner>fserb@chromium.org</owner>
   <summary>Records the type of resource provider used for a canvas.</summary>
@@ -705,7 +705,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.CompositingCommit.UpdateTime"
-    units="microseconds" expires_after="2024-06-01">
+    units="microseconds" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -726,7 +726,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.CompositingInputs.UpdateTime"
-    units="microseconds" expires_after="2024-06-01">
+    units="microseconds" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -780,7 +780,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.ContentDocumentUpdate.UpdateTime"
-    units="microseconds" expires_after="2024-06-01">
+    units="microseconds" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -884,7 +884,7 @@
 </histogram>
 
 <histogram name="Blink.CullRect.UpdateTime" units="microseconds"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>pdr@chromium.org</owner>
   <owner>wangxianzhu@chromium.org</owner>
   <owner>paint-dev@chromium.org</owner>
@@ -1074,7 +1074,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.DisplayLockIntersectionObserver.UpdateTime"
-    units="microseconds" expires_after="2024-06-01">
+    units="microseconds" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -1095,7 +1095,7 @@
   </summary>
 </histogram>
 
-<histogram name="Blink.EffectiveZoom" units="%" expires_after="2024-06-02">
+<histogram name="Blink.EffectiveZoom" units="%" expires_after="2024-08-04">
   <owner>pdr@chromium.org</owner>
   <owner>paint-dev@chromium.org</owner>
   <summary>
@@ -1207,7 +1207,7 @@
 </histogram>
 
 <histogram name="Blink.FedCm.AutoReauthn.BlockedByPreventSilentAccess"
-    enum="Boolean" expires_after="2024-04-08">
+    enum="Boolean" expires_after="2024-08-04">
   <owner>npm@chromium.org</owner>
   <owner>web-identity-eng@google.com</owner>
   <summary>
@@ -1545,7 +1545,7 @@
 </histogram>
 
 <histogram name="Blink.FedCm.RpContext" enum="FedCmRpContext"
-    expires_after="2024-05-18">
+    expires_after="2024-08-04">
   <owner>npm@chromium.org</owner>
   <owner>web-identity-eng@google.com</owner>
   <summary>
@@ -2049,7 +2049,7 @@
 </histogram>
 
 <histogram name="Blink.Fonts.FontServiceThread.MatchFamilyNameTime"
-    units="microseconds" expires_after="2024-04-19">
+    units="microseconds" expires_after="2024-08-04">
   <owner>nidhijaju@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
@@ -2061,7 +2061,7 @@
 </histogram>
 
 <histogram name="Blink.Fonts.FontServiceThread.OpenStreamTime"
-    units="microseconds" expires_after="2024-04-19">
+    units="microseconds" expires_after="2024-08-04">
   <owner>nidhijaju@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
@@ -2083,7 +2083,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.ForcedStyleAndLayout.UpdateTime"
-    units="microseconds" expires_after="2024-06-01">
+    units="microseconds" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -2489,7 +2489,7 @@
 </histogram>
 
 <histogram name="Blink.ImageDecoders.Avif.CleanAperture"
-    enum="AVIFCleanApertureType" expires_after="2024-05-31">
+    enum="AVIFCleanApertureType" expires_after="2024-08-04">
   <owner>wtc@google.com</owner>
   <owner>jzern@google.com</owner>
   <owner>
@@ -2520,7 +2520,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.ImplCompositorCommit.UpdateTime"
-    units="microseconds" expires_after="2024-06-01">
+    units="microseconds" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -2542,7 +2542,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.IntersectionObservation.UpdateTime"
-    units="microseconds" expires_after="2024-06-01">
+    units="microseconds" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -2564,7 +2564,7 @@
 
 <histogram base="true"
     name="Blink.IntersectionObservationInternalCount.UpdateTime" units="count"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>szager@chromium.org</owner>
@@ -2577,7 +2577,7 @@
 
 <histogram base="true"
     name="Blink.IntersectionObservationJavascriptCount.UpdateTime"
-    units="count" expires_after="2024-06-01">
+    units="count" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>szager@chromium.org</owner>
@@ -2589,7 +2589,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.JavascriptDocumentUpdate.UpdateTime"
-    units="microseconds" expires_after="2024-06-01">
+    units="microseconds" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -2614,7 +2614,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.JavascriptIntersectionObserver.UpdateTime"
-    units="microseconds" expires_after="2024-06-01">
+    units="microseconds" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -2667,7 +2667,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.Layout.UpdateTime" units="microseconds"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -2710,7 +2710,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.LazyLoadIntersectionObserver.UpdateTime"
-    units="microseconds" expires_after="2024-06-01">
+    units="microseconds" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -2751,7 +2751,7 @@
 </histogram>
 
 <histogram name="Blink.LCPP.LCPElementLocatorSize" units="bytes"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>kouhei@chromium.org</owner>
   <owner>
     src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS
@@ -2905,7 +2905,7 @@
 </histogram>
 
 <histogram name="Blink.LCPP.PrefetchFontCount" units="count"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>
     src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS
@@ -3029,7 +3029,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.MainFrame.UpdateTime" units="microseconds"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -3049,7 +3049,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.MediaIntersectionObserver.UpdateTime"
-    units="microseconds" expires_after="2024-06-01">
+    units="microseconds" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -3217,7 +3217,7 @@
 </histogram>
 
 <histogram name="Blink.OffscreenCanvas.NewOffscreenCanvas" enum="Boolean"
-    expires_after="2024-04-01">
+    expires_after="2024-08-04">
   <owner>aaronhk@chromium.org</owner>
   <owner>fserb@chromium.org</owner>
   <summary>
@@ -3263,7 +3263,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.Paint.UpdateTime" units="microseconds"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -3283,7 +3283,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.ParseStyleSheet.UpdateTime"
-    units="microseconds" expires_after="2024-06-01">
+    units="microseconds" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>cduvall@chromium.org</owner>
@@ -3350,7 +3350,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.PrePaint.UpdateTime" units="microseconds"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -3686,7 +3686,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.ServiceDocumentUpdate.UpdateTime"
-    units="microseconds" expires_after="2024-06-01">
+    units="microseconds" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -3859,7 +3859,7 @@
 </histogram>
 
 <histogram name="Blink.SpeculationRules.LoadOutcome"
-    enum="SpeculationRulesLoadOutcome" expires_after="2024-06-02">
+    enum="SpeculationRulesLoadOutcome" expires_after="2024-08-04">
   <owner>jbroman@chromium.org</owner>
   <owner>src/third_party/blink/renderer/core/speculation_rules/OWNERS</owner>
   <summary>
@@ -3869,7 +3869,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.Style.UpdateTime" units="microseconds"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -3901,7 +3901,7 @@
 </histogram>
 
 <histogram name="Blink.UpdateViewportIntersection.UpdateTime"
-    units="microseconds" expires_after="2024-06-01">
+    units="microseconds" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -4310,7 +4310,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.UserDrivenDocumentUpdate.UpdateTime"
-    units="microseconds" expires_after="2024-06-01">
+    units="microseconds" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -4398,7 +4398,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.VisualUpdateDelay.UpdateTime"
-    units="microseconds" expires_after="2024-06-01">
+    units="microseconds" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>szager@chromium.org</owner>
@@ -4413,7 +4413,7 @@
 </histogram>
 
 <histogram base="true" name="Blink.WaitForCommit.UpdateTime"
-    units="microseconds" expires_after="2024-06-01">
+    units="microseconds" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="BlinkUpdateTimeSuffixes" -->
 
   <owner>pdr@chromium.org</owner>
@@ -4524,7 +4524,7 @@
 </histogram>
 
 <histogram name="Blink.{Host}.RenderTaskDuration.{Context}.{Filter}"
-    units="microseconds" expires_after="2024-06-02">
+    units="microseconds" expires_after="2024-08-04">
   <owner>junov@chromium.org</owner>
   <owner>fserb@chromium.org</owner>
   <owner>aaronhk@chromium.org</owner>
@@ -4562,7 +4562,7 @@
 </histogram>
 
 <histogram name="Blink.{Host}.{Heap}.{Context}" units="KB"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>junov@chromium.org</owner>
   <owner>fserb@chromium.org</owner>
   <owner>aaronhk@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/bluetooth/histograms.xml b/tools/metrics/histograms/metadata/bluetooth/histograms.xml
index 76cc23fd..32dab3e 100644
--- a/tools/metrics/histograms/metadata/bluetooth/histograms.xml
+++ b/tools/metrics/histograms/metadata/bluetooth/histograms.xml
@@ -331,7 +331,7 @@
 </histogram>
 
 <histogram name="Bluetooth.ChromeOS.FastPair.ConnectDevice.Result"
-    enum="BooleanSuccess" expires_after="2024-06-02">
+    enum="BooleanSuccess" expires_after="2024-08-04">
   <owner>jackshira@google.com</owner>
   <owner>dclasson@google.com</owner>
   <owner>brandosocarras@google.com</owner>
@@ -385,7 +385,7 @@
 </histogram>
 
 <histogram name="Bluetooth.ChromeOS.FastPair.DeviceMetadataFetcher.Result"
-    enum="BooleanSuccess" expires_after="2024-06-02">
+    enum="BooleanSuccess" expires_after="2024-08-04">
   <owner>jackshira@google.com</owner>
   <owner>dclasson@google.com</owner>
   <owner>brandosocarras@google.com</owner>
@@ -397,7 +397,7 @@
 </histogram>
 
 <histogram name="Bluetooth.ChromeOS.FastPair.Discovered.Version"
-    enum="FastPairVersion" expires_after="2024-06-02">
+    enum="FastPairVersion" expires_after="2024-08-04">
   <owner>jackshira@google.com</owner>
   <owner>dclasson@google.com</owner>
   <owner>brandosocarras@google.com</owner>
@@ -635,7 +635,7 @@
 </histogram>
 
 <histogram name="Bluetooth.ChromeOS.FastPair.FootprintsFetcher.Delete.Result"
-    enum="BooleanSuccess" expires_after="2024-06-02">
+    enum="BooleanSuccess" expires_after="2024-08-04">
   <owner>jackshira@google.com</owner>
   <owner>dclasson@google.com</owner>
   <owner>brandosocarras@google.com</owner>
@@ -649,7 +649,7 @@
 </histogram>
 
 <histogram name="Bluetooth.ChromeOS.FastPair.FootprintsFetcher.Get.Result"
-    enum="BooleanSuccess" expires_after="2024-06-02">
+    enum="BooleanSuccess" expires_after="2024-08-04">
   <owner>jackshira@google.com</owner>
   <owner>dclasson@google.com</owner>
   <owner>brandosocarras@google.com</owner>
@@ -663,7 +663,7 @@
 </histogram>
 
 <histogram name="Bluetooth.ChromeOS.FastPair.FootprintsFetcher.Post.Result"
-    enum="BooleanSuccess" expires_after="2024-06-02">
+    enum="BooleanSuccess" expires_after="2024-08-04">
   <owner>jackshira@google.com</owner>
   <owner>dclasson@google.com</owner>
   <owner>brandosocarras@google.com</owner>
@@ -729,7 +729,7 @@
 
 <histogram
     name="Bluetooth.ChromeOS.FastPair.GattConnection.EffectiveSuccessRate"
-    enum="BooleanSuccess" expires_after="2024-06-02">
+    enum="BooleanSuccess" expires_after="2024-08-04">
   <owner>jackshira@google.com</owner>
   <owner>dclasson@google.com</owner>
   <owner>brandosocarras@google.com</owner>
@@ -904,7 +904,7 @@
 </histogram>
 
 <histogram name="Bluetooth.ChromeOS.FastPair.KeyBasedPairing.Write.Result"
-    enum="BooleanSuccess" expires_after="2024-06-02">
+    enum="BooleanSuccess" expires_after="2024-08-04">
   <owner>jackshira@google.com</owner>
   <owner>dclasson@google.com</owner>
   <owner>brandosocarras@google.com</owner>
@@ -1183,7 +1183,7 @@
 </histogram>
 
 <histogram name="Bluetooth.ChromeOS.FastPair.Passkey.Write.Result"
-    enum="BooleanSuccess" expires_after="2024-06-02">
+    enum="BooleanSuccess" expires_after="2024-08-04">
   <owner>jackshira@google.com</owner>
   <owner>dclasson@google.com</owner>
   <owner>brandosocarras@google.com</owner>
@@ -1384,7 +1384,7 @@
 </histogram>
 
 <histogram name="Bluetooth.ChromeOS.FastPair.SavedDevices.DeviceCount"
-    units="devices" expires_after="2024-06-02">
+    units="devices" expires_after="2024-08-04">
   <owner>jackshira@google.com</owner>
   <owner>dclasson@google.com</owner>
   <owner>brandosocarras@google.com</owner>
@@ -1398,7 +1398,7 @@
 
 <histogram
     name="Bluetooth.ChromeOS.FastPair.SavedDevices.GetSavedDevices.Result"
-    enum="BooleanSuccess" expires_after="2024-06-02">
+    enum="BooleanSuccess" expires_after="2024-08-04">
   <owner>jackshira@google.com</owner>
   <owner>dclasson@google.com</owner>
   <owner>brandosocarras@google.com</owner>
@@ -1489,7 +1489,7 @@
 </histogram>
 
 <histogram name="Bluetooth.ChromeOS.FastPair.Scanner.StartSession.Result"
-    enum="BooleanSuccess" expires_after="2024-06-02">
+    enum="BooleanSuccess" expires_after="2024-08-04">
   <owner>jackshira@google.com</owner>
   <owner>dclasson@google.com</owner>
   <owner>brandosocarras@google.com</owner>
@@ -1502,7 +1502,7 @@
 </histogram>
 
 <histogram name="Bluetooth.ChromeOS.FastPair.TotalGattConnectionTime"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>jackshira@google.com</owner>
   <owner>dclasson@google.com</owner>
   <owner>brandosocarras@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/bookmarks/histograms.xml b/tools/metrics/histograms/metadata/bookmarks/histograms.xml
index 49feed32..04d25cc 100644
--- a/tools/metrics/histograms/metadata/bookmarks/histograms.xml
+++ b/tools/metrics/histograms/metadata/bookmarks/histograms.xml
@@ -695,7 +695,7 @@
 </histogram>
 
 <histogram name="PowerBookmarks.SidePanel.Search.CTR"
-    enum="BookmarksSidePanelSearchCTREvent" expires_after="2024-06-02">
+    enum="BookmarksSidePanelSearchCTREvent" expires_after="2024-08-04">
   <owner>emshack@chromium.org</owner>
   <owner>chrome-desktop-sea@google.com</owner>
   <component>UI&gt;Browser&gt;PowerBookmarks</component>
@@ -707,7 +707,7 @@
 </histogram>
 
 <histogram name="PowerBookmarks.SidePanel.SortTypeShown"
-    enum="BookmarksSidePanelSortType" expires_after="2024-06-02">
+    enum="BookmarksSidePanelSortType" expires_after="2024-08-04">
   <owner>emshack@chromium.org</owner>
   <owner>chrome-desktop-sea@google.com</owner>
   <component>UI&gt;Browser&gt;PowerBookmarks</component>
@@ -718,7 +718,7 @@
 </histogram>
 
 <histogram name="PowerBookmarks.SidePanel.ViewTypeShown"
-    enum="BookmarksSidePanelViewType" expires_after="2024-06-02">
+    enum="BookmarksSidePanelViewType" expires_after="2024-08-04">
   <owner>emshack@chromium.org</owner>
   <owner>chrome-desktop-sea@google.com</owner>
   <component>UI&gt;Browser&gt;PowerBookmarks</component>
diff --git a/tools/metrics/histograms/metadata/browser/histograms.xml b/tools/metrics/histograms/metadata/browser/histograms.xml
index 43bbd4f..a452bcd 100644
--- a/tools/metrics/histograms/metadata/browser/histograms.xml
+++ b/tools/metrics/histograms/metadata/browser/histograms.xml
@@ -365,7 +365,7 @@
 </histogram>
 
 <histogram name="Browser.MainThreadsCongestion.Used" units="janks"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>pmonette@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -429,7 +429,7 @@
 </histogram>
 
 <histogram name="Browser.MainThreadsCongestion{UsageScenario}" units="janks"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>pmonette@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -789,7 +789,7 @@
 </histogram>
 
 <histogram name="Browser.Tabs.TabSwitchResult3{TabSwitchingType}"
-    enum="TabSwitchResult2" expires_after="2024-06-02">
+    enum="TabSwitchResult2" expires_after="2024-08-04">
   <owner>fdoray@chromium.org</owner>
   <owner>joenotcharles@google.com</owner>
   <owner>catan-team@chromium.org</owner>
@@ -801,7 +801,7 @@
 </histogram>
 
 <histogram name="Browser.Tabs.TotalIncompleteSwitchDuration3{TabSwitchingType}"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>fdoray@chromium.org</owner>
   <owner>jonross@chromium.org</owner>
   <owner>joenotcharles@google.com</owner>
@@ -815,7 +815,7 @@
 </histogram>
 
 <histogram name="Browser.Tabs.TotalSwitchDuration3{TabSwitchingType}"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>jonross@chromium.org</owner>
   <owner>joenotcharles@google.com</owner>
   <owner>catan-team@chromium.org</owner>
@@ -1430,7 +1430,7 @@
 </histogram>
 
 <histogram name="SidePanel.{SidePanelEntry}.TimeFromEntryTriggerToShown"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>corising@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/chrome/histograms.xml b/tools/metrics/histograms/metadata/chrome/histograms.xml
index 0ced643..9745a17 100644
--- a/tools/metrics/histograms/metadata/chrome/histograms.xml
+++ b/tools/metrics/histograms/metadata/chrome/histograms.xml
@@ -33,7 +33,7 @@
 </histogram>
 
 <histogram name="Chrome.BuildState.BuildStateUpdateType"
-    enum="BuildStateUpdateType" expires_after="2024-06-02">
+    enum="BuildStateUpdateType" expires_after="2024-08-04">
   <owner>ajgo@chromium.org</owner>
   <owner>anunoy@chromium.org</owner>
   <summary>
@@ -149,7 +149,7 @@
 </histogram>
 
 <histogram name="Chrome.Lacros.Smoothness.PercentDroppedFrames_1sWindow2"
-    units="%" expires_after="2024-06-02">
+    units="%" expires_after="2024-08-04">
   <owner>xiyuan@chromium.org</owner>
   <owner>cros-sw-perf@google.com</owner>
   <summary>
@@ -159,7 +159,7 @@
 </histogram>
 
 <histogram name="Chrome.ProcessSingleton.NotifyResult" enum="NotifyResult"
-    expires_after="2024-06-04">
+    expires_after="2024-08-04">
   <owner>gab@chromium.org</owner>
   <owner>etienneb@chromium.org</owner>
   <summary>
@@ -168,14 +168,14 @@
 </histogram>
 
 <histogram name="Chrome.ProcessSingleton.RemoteHungProcessTerminateReason"
-    enum="RemoteHungProcessTerminateReason" expires_after="2024-06-04">
+    enum="RemoteHungProcessTerminateReason" expires_after="2024-08-04">
   <owner>gab@chromium.org</owner>
   <owner>etienneb@chromium.org</owner>
   <summary>The reason of remote hang processes termination.</summary>
 </histogram>
 
 <histogram name="Chrome.ProcessSingleton.RemoteProcessInteractionResult"
-    enum="RemoteProcessInteractionResult" expires_after="2024-06-04">
+    enum="RemoteProcessInteractionResult" expires_after="2024-08-04">
   <owner>gab@chromium.org</owner>
   <owner>etienneb@chromium.org</owner>
   <summary>
@@ -195,7 +195,7 @@
 </histogram>
 
 <histogram name="Chrome.ProcessSingleton.TerminateProcessErrorCode.Windows"
-    enum="WinGetLastError" expires_after="2024-06-04">
+    enum="WinGetLastError" expires_after="2024-08-04">
   <owner>gab@chromium.org</owner>
   <owner>etienneb@chromium.org</owner>
   <summary>
@@ -205,7 +205,7 @@
 </histogram>
 
 <histogram name="Chrome.ProcessSingleton.TerminateProcessTime" units="ms"
-    expires_after="2024-06-04">
+    expires_after="2024-08-04">
   <owner>gab@chromium.org</owner>
   <owner>etienneb@chromium.org</owner>
   <summary>
@@ -245,7 +245,7 @@
 </histogram>
 
 <histogram name="Chrome.ProcessSingleton.TimeToNotify" units="ms"
-    expires_after="2024-06-04">
+    expires_after="2024-08-04">
   <owner>etienneb@chromium.org</owner>
   <owner>gab@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/chromeos/histograms.xml b/tools/metrics/histograms/metadata/chromeos/histograms.xml
index 79e97b1d..cedcfd19 100644
--- a/tools/metrics/histograms/metadata/chromeos/histograms.xml
+++ b/tools/metrics/histograms/metadata/chromeos/histograms.xml
@@ -197,7 +197,7 @@
 </variants>
 
 <histogram name="ChromeOS.AnomalousProcCount.AttemptedMemfdExec"
-    units="processes" expires_after="2024-06-02">
+    units="processes" expires_after="2024-08-04">
   <owner>enlightened@chromium.org</owner>
   <owner>chromeos-hardening@google.com</owner>
   <summary>
@@ -213,7 +213,7 @@
 </histogram>
 
 <histogram name="ChromeOS.AnomalousProcCount.ForbiddenIntersection"
-    units="processes" expires_after="2024-06-02">
+    units="processes" expires_after="2024-08-04">
   <owner>enlightened@chromium.org</owner>
   <owner>chromeos-hardening@google.com</owner>
   <summary>
@@ -809,7 +809,7 @@
 
 <histogram
     name="ChromeOS.CertProvisioning.Event{CertProvisioningProtocolVersion}.{CertProvisioningScope}"
-    enum="CertProvisioningEvent" expires_after="2024-06-02">
+    enum="CertProvisioningEvent" expires_after="2024-08-04">
   <owner>miersh@google.com</owner>
   <owner>pmarko@chromium.org</owner>
   <summary>
@@ -891,7 +891,7 @@
 </histogram>
 
 <histogram name="ChromeOS.CWP.JankinessTriggerStatus"
-    enum="ChromeOSJankinessTriggerStatus" expires_after="2024-06-02">
+    enum="ChromeOSJankinessTriggerStatus" expires_after="2024-08-04">
   <owner>gmx@chromium.org</owner>
   <owner>cwp-team@google.com</owner>
   <summary>
@@ -1017,7 +1017,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Debugd.Perf.{FunctionName}" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>enlightened@google.com</owner>
   <owner>jorgelo@google.com</owner>
   <owner>chromeos-security-core@google.com</owner>
@@ -1188,7 +1188,7 @@
 </histogram>
 
 <histogram name="ChromeOS.FeatureUsage.{FeatureName}" enum="FeatureUsageEvent"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>rsorokin@chromium.org</owner>
   <owner>cros-oac@google.com</owner>
   <summary>
@@ -1200,7 +1200,7 @@
 </histogram>
 
 <histogram name="ChromeOS.FeatureUsage.{FeatureName}.Usetime" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>rsorokin@chromium.org</owner>
   <owner>cros-oac@google.com</owner>
   <summary>
@@ -1327,7 +1327,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Gaia.CreateAccount.IsFirstUser" enum="Boolean"
-    expires_after="2024-05-30">
+    expires_after="2024-08-04">
   <owner>thv@google.com</owner>
   <owner>cros-growth@google.com</owner>
   <summary>
@@ -1349,7 +1349,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Gaia.Done.Oobe.NewAccount" enum="BooleanNewAccount"
-    expires_after="2024-05-30">
+    expires_after="2024-08-04">
   <owner>thv@google.com</owner>
   <owner>cros-growth@google.com</owner>
   <summary>
@@ -1412,7 +1412,7 @@
 </histogram>
 
 <histogram name="ChromeOS.HardwareVerifier.TimeToFinish" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>itspeter@chromium.org</owner>
   <owner>stimim@chromium.org</owner>
   <owner>chromeos-runtime-probe@google.com</owner>
@@ -1422,7 +1422,7 @@
 </histogram>
 
 <histogram name="ChromeOS.HardwareVerifier.TimeToProbe" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>itspeter@chromium.org</owner>
   <owner>stimim@chromium.org</owner>
   <owner>chromeos-runtime-probe@google.com</owner>
@@ -1747,7 +1747,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Inputs.ModifierKeyCombo.{KeyboardType}" units="hash"
-    expires_after="2024-05-26">
+    expires_after="2024-08-04">
   <owner>dpad@chromium.org</owner>
   <owner>cros-peripherals@google.com</owner>
   <summary>
@@ -1767,7 +1767,7 @@
 
 <histogram
     name="ChromeOS.Inputs.TouchscreenUsage.Temporary.{TimePeriod}.{Mode}"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
 <!-- TODO(b/270610982): Remove excess time periods once an optimal time period has been selected. -->
 
   <owner>wmahon@google.com</owner>
@@ -2328,7 +2328,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Sandboxing.NoNewPrivsProcPercentage" units="%"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>enlightened@chromium.org</owner>
   <owner>chromeos-hardening@google.com</owner>
   <summary>
@@ -2342,7 +2342,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Sandboxing.NonInitNsProcPercentage" units="%"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>enlightened@chromium.org</owner>
   <owner>chromeos-hardening@google.com</owner>
   <summary>
@@ -2356,7 +2356,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Sandboxing.NonRootProcPercentage" units="%"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>enlightened@chromium.org</owner>
   <owner>chromeos-hardening@google.com</owner>
   <summary>
@@ -2370,7 +2370,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Sandboxing.SecCompCoverage" units="%"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>enlightened@chromium.org</owner>
   <owner>chromeos-hardening@google.com</owner>
   <summary>
@@ -2384,7 +2384,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Sandboxing.UnprivProcPercentage" units="%"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>enlightened@chromium.org</owner>
   <owner>chromeos-hardening@google.com</owner>
   <summary>
@@ -2545,7 +2545,7 @@
 </histogram>
 
 <histogram name="ChromeOS.SecurityAnomaly" enum="SecurityAnomaly"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>jorgelo@chromium.org</owner>
   <owner>chromeos-hardening@google.com</owner>
   <summary>
@@ -2927,7 +2927,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Settings.Device.{DeviceType}.SetSettingsSucceeded"
-    enum="Boolean" expires_after="2024-06-02">
+    enum="Boolean" expires_after="2024-08-04">
   <owner>dpad@google.com</owner>
   <owner>cros-peripherals@google.com</owner>
   <summary>
@@ -3410,7 +3410,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Stability.{Severity}" enum="CrashSeverityProductType"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>mutexlox@google.com</owner>
   <owner>palaksh@google.com</owner>
   <owner>kendraketsui@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/commerce/histograms.xml b/tools/metrics/histograms/metadata/commerce/histograms.xml
index f6c1cff..9f2d8495 100644
--- a/tools/metrics/histograms/metadata/commerce/histograms.xml
+++ b/tools/metrics/histograms/metadata/commerce/histograms.xml
@@ -454,7 +454,7 @@
 </histogram>
 
 <histogram name="Commerce.PriceInsights.OmniboxIconClicked"
-    enum="PriceInsightsIconLabelType" expires_after="2024-06-02">
+    enum="PriceInsightsIconLabelType" expires_after="2024-08-04">
   <owner>zhiyuancai@chromium.org</owner>
   <owner>ayman@chromium.org</owner>
   <owner>chrome-shopping@google.com</owner>
@@ -466,7 +466,7 @@
 </histogram>
 
 <histogram name="Commerce.PriceInsights.OmniboxIconShown"
-    enum="PriceInsightsIconLabelType" expires_after="2024-06-02">
+    enum="PriceInsightsIconLabelType" expires_after="2024-08-04">
   <owner>zhiyuancai@chromium.org</owner>
   <owner>ayman@chromium.org</owner>
   <owner>chrome-shopping@google.com</owner>
@@ -531,7 +531,7 @@
 </histogram>
 
 <histogram name="Commerce.PriceTracking.PriceInsightsSidePanel.{Action}"
-    enum="PriceInsightsPriceBucket" expires_after="2024-06-02">
+    enum="PriceInsightsPriceBucket" expires_after="2024-08-04">
   <owner>yuezhanggg@chromium.org</owner>
   <owner>zhiyuancai@chromium.org</owner>
   <summary>
@@ -546,7 +546,7 @@
 </histogram>
 
 <histogram name="Commerce.PriceTracking.PriceTrackedProductCount"
-    units="subscriptions" expires_after="2024-06-04">
+    units="subscriptions" expires_after="2024-08-04">
   <owner>ayman@chromium.org</owner>
   <owner>mdjones@chromium.org</owner>
   <owner>chrome-shopping@google.org</owner>
@@ -685,7 +685,7 @@
 </histogram>
 
 <histogram name="Commerce.{FeatureName}.IconInteractionState"
-    enum="CommerceIconInteractionState" expires_after="2024-06-01">
+    enum="CommerceIconInteractionState" expires_after="2024-08-04">
   <owner>josephjoopark@chromium.org</owner>
   <owner>mdjones@chromium.org</owner>
   <owner>chrome-shopping@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/compose/histograms.xml b/tools/metrics/histograms/metadata/compose/histograms.xml
index 8e11c897..a83f448 100644
--- a/tools/metrics/histograms/metadata/compose/histograms.xml
+++ b/tools/metrics/histograms/metadata/compose/histograms.xml
@@ -33,7 +33,7 @@
 </variants>
 
 <histogram name="Compose.ContextMenu.CTR" enum="ComposeContextMenuCtrEvent"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>sophey@chromium.org</owner>
   <owner>chrome-compose-frontend@google.com</owner>
   <summary>
@@ -56,7 +56,7 @@
 </histogram>
 
 <histogram name="Compose.ContextMenu.ShowStatus" enum="ComposeShowStatus"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>sophey@chromium.org</owner>
   <owner>chrome-compose-frontend@google.com</owner>
   <summary>
@@ -101,7 +101,7 @@
 </histogram>
 
 <histogram name="Compose.Dialog.OpenLatency" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>cuianthony@chromium.org</owner>
   <owner>chrome-compose-frontend@google.com</owner>
   <summary>
@@ -264,7 +264,7 @@
 </histogram>
 
 <histogram name="Compose.{ComposeEvalLocation}Request.Status"
-    enum="ComposeResponseStatus" expires_after="2024-06-02">
+    enum="ComposeResponseStatus" expires_after="2024-08-04">
   <owner>cuianthony@chromium.org</owner>
   <owner>chrome-compose-frontend@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/compositing/histograms.xml b/tools/metrics/histograms/metadata/compositing/histograms.xml
index 9ad912a..d5ec835 100644
--- a/tools/metrics/histograms/metadata/compositing/histograms.xml
+++ b/tools/metrics/histograms/metadata/compositing/histograms.xml
@@ -1164,7 +1164,7 @@
 </histogram>
 
 <histogram name="Graphics.Smoothness.Jank3.All{Type}" units="%"
-    expires_after="2024-06-05">
+    expires_after="2024-08-04">
   <owner>jonross@chromium.org</owner>
   <owner>mjzhang@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
@@ -1191,7 +1191,7 @@
 </histogram>
 
 <histogram name="Graphics.Smoothness.Jank3.{Thread}{Sequence}" units="%"
-    expires_after="2024-06-05">
+    expires_after="2024-08-04">
   <owner>jonross@chromium.org</owner>
   <owner>mjzhang@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/content_extraction/histograms.xml b/tools/metrics/histograms/metadata/content_extraction/histograms.xml
index 3570b57b..ea1fe20 100644
--- a/tools/metrics/histograms/metadata/content_extraction/histograms.xml
+++ b/tools/metrics/histograms/metadata/content_extraction/histograms.xml
@@ -49,7 +49,7 @@
 </histogram>
 
 <histogram name="ContentExtraction.Inner{InnerType}.ValidResults"
-    enum="Boolean" expires_after="2024-03-31">
+    enum="Boolean" expires_after="2024-08-04">
   <owner>sky@chromium.org</owner>
   <owner>swarm-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/cookie/histograms.xml b/tools/metrics/histograms/metadata/cookie/histograms.xml
index 7c42f6d7..39f66106 100644
--- a/tools/metrics/histograms/metadata/cookie/histograms.xml
+++ b/tools/metrics/histograms/metadata/cookie/histograms.xml
@@ -486,7 +486,7 @@
 </histogram>
 
 <histogram name="Cookie.FirstPartySets.EnqueueingDelay.{QueryType}2" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>cfredric@chromium.org</owner>
   <owner>kaustubhag@chromium.org</owner>
   <summary>
@@ -520,7 +520,7 @@
 </histogram>
 
 <histogram name="Cookie.FirstPartySets.InitializationDuration.{Landmark}2"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>cfredric@chromium.org</owner>
   <owner>kaustubhag@chromium.org</owner>
   <summary>
@@ -577,7 +577,7 @@
 </histogram>
 
 <histogram name="Cookie.FirstPartySets.{Context}.DelayedQueriesCount"
-    units="queries" expires_after="2024-06-02">
+    units="queries" expires_after="2024-08-04">
   <owner>cfredric@chromium.org</owner>
   <owner>kaustubhag@chromium.org</owner>
   <summary>
@@ -595,7 +595,7 @@
 </histogram>
 
 <histogram name="Cookie.FirstPartySets.{Context}.MostDelayedQueryDelta"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>cfredric@chromium.org</owner>
   <owner>kaustubhag@chromium.org</owner>
   <summary>
@@ -627,7 +627,7 @@
 </histogram>
 
 <histogram name="Cookie.HasNonASCII.{CookieField}" enum="Boolean"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>bingler@chromium.org</owner>
   <owner>miketaylr@chromium.org</owner>
   <summary>
@@ -719,7 +719,7 @@
   </summary>
 </histogram>
 
-<histogram name="Cookie.NumKeys" units="keys" expires_after="2024-06-02">
+<histogram name="Cookie.NumKeys" units="keys" expires_after="2024-08-04">
   <owner>cfredric@chromium.org</owner>
   <owner>kaustubhag@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/cras/histograms.xml b/tools/metrics/histograms/metadata/cras/histograms.xml
index 2a2086e..59e8799 100644
--- a/tools/metrics/histograms/metadata/cras/histograms.xml
+++ b/tools/metrics/histograms/metadata/cras/histograms.xml
@@ -160,7 +160,7 @@
   </summary>
 </histogram>
 
-<histogram name="Cras.BusyloopLength" units="units" expires_after="2024-06-01">
+<histogram name="Cras.BusyloopLength" units="units" expires_after="2024-08-04">
   <owner>yuhsuan@chromium.org</owner>
   <owner>chromeos-audio@google.com</owner>
   <summary>
@@ -387,7 +387,7 @@
 </histogram>
 
 <histogram name="Cras.DlcManagerStatus.DlcStatus.{DlcType}"
-    enum="CrasDlcManagerDlcStatus" expires_after="2024-05-15">
+    enum="CrasDlcManagerDlcStatus" expires_after="2024-08-04">
   <owner>hunghsienchen@google.com</owner>
   <owner>chromeos-audio@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/cros/histograms.xml b/tools/metrics/histograms/metadata/cros/histograms.xml
index 44848d5..be1c341 100644
--- a/tools/metrics/histograms/metadata/cros/histograms.xml
+++ b/tools/metrics/histograms/metadata/cros/histograms.xml
@@ -45,7 +45,7 @@
 </histogram>
 
 <histogram name="CrosDisks.ArchiveType" enum="CrosDisksArchiveType"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>fdegros@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -54,7 +54,7 @@
 </histogram>
 
 <histogram name="CrosDisks.DeviceMediaType" enum="CrosDisksDeviceMediaType"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>fdegros@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -64,7 +64,7 @@
 </histogram>
 
 <histogram name="CrosDisks.FilesystemType" enum="CrosDisksFilesystemType"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>fdegros@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -84,7 +84,7 @@
 </histogram>
 
 <histogram name="CrosDisks.Fuse.FuseZip" enum="FuseZipError"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>fdegros@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -94,7 +94,7 @@
 </histogram>
 
 <histogram name="CrosDisks.Fuse.Rar2fs" enum="Rar2fsError"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>fdegros@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -104,7 +104,7 @@
 </histogram>
 
 <histogram name="CrosDisks.MountError.{FileSystem}" enum="PopularOSErrno"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>fdegros@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -145,7 +145,7 @@
 </histogram>
 
 <histogram name="CrosDisks.ReadOnlyFileSystemAfterError"
-    enum="CrosDisksFilesystemType" expires_after="2024-06-02">
+    enum="CrosDisksFilesystemType" expires_after="2024-08-04">
   <owner>fdegros@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -156,7 +156,7 @@
 </histogram>
 
 <histogram name="CrosDisks.UnmountError.{FileSystem}" enum="PopularOSErrno"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>fdegros@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -184,7 +184,7 @@
 </histogram>
 
 <histogram name="CrosDisksClient.FormatCompletedError"
-    enum="CrosDisksClientFormatError" expires_after="2024-06-02">
+    enum="CrosDisksClientFormatError" expires_after="2024-08-04">
   <owner>austinct@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -194,7 +194,7 @@
 </histogram>
 
 <histogram name="CrosDisksClient.FormatTime" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>austinct@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -203,7 +203,7 @@
 </histogram>
 
 <histogram name="CrosDisksClient.MountCompletedError"
-    enum="CrosDisksClientMountError" expires_after="2024-06-02">
+    enum="CrosDisksClientMountError" expires_after="2024-08-04">
   <owner>fdegros@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -213,7 +213,7 @@
 </histogram>
 
 <histogram name="CrosDisksClient.MountErrorMountType"
-    enum="CrosDisksMountTypeError" expires_after="2024-06-02">
+    enum="CrosDisksMountTypeError" expires_after="2024-08-04">
   <owner>fdegros@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -223,7 +223,7 @@
 </histogram>
 
 <histogram name="CrosDisksClient.MountTime" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>fdegros@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -232,7 +232,7 @@
 </histogram>
 
 <histogram name="CrosDisksClient.UnmountError" enum="CrosDisksClientMountError"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>fdegros@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -242,7 +242,7 @@
 </histogram>
 
 <histogram name="CrosDisksClient.UnmountTime" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>fdegros@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
index c7d0de2..75561be0 100644
--- a/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
+++ b/tools/metrics/histograms/metadata/custom_tabs/histograms.xml
@@ -363,7 +363,7 @@
 </histogram>
 
 <histogram name="CustomTabs.Minimized.ReceivedIntentReusingSession"
-    enum="Boolean" expires_after="2024-06-01">
+    enum="Boolean" expires_after="2024-08-04">
   <owner>sinansahin@google.com</owner>
   <owner>chrome-connective-tissue@google.com</owner>
   <summary>
@@ -385,7 +385,7 @@
 </histogram>
 
 <histogram name="CustomTabs.MinimizedFeatureAvailability"
-    enum="CustomTabsMinimizedFeatureAvailability" expires_after="2024-06-02">
+    enum="CustomTabsMinimizedFeatureAvailability" expires_after="2024-08-04">
   <owner>sinansahin@google.com</owner>
   <owner>chrome-connective-tissue@google.com</owner>
   <summary>
@@ -416,7 +416,7 @@
 </histogram>
 
 <histogram name="CustomTabs.PageInsights.Event" enum="PageInsightsEvent"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>jinsukkim@chromium.org</owner>
   <owner>chrome-connective-tissue@google.com</owner>
   <summary>
@@ -608,7 +608,7 @@
 </histogram>
 
 <histogram name="CustomTabs.SideSheetResizeType" enum="CustomTabsResizeType2"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>kgrosu@google.com</owner>
   <owner>chrome-connective-tissue@google.com</owner>
   <summary>
@@ -703,7 +703,7 @@
 </histogram>
 
 <histogram name="CustomTabs.TimeElapsedSinceMinimized.Destroyed" units="s"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>katzz@google.com</owner>
   <owner>chrome-connective-tissue@google.com</owner>
   <summary>
@@ -715,7 +715,7 @@
 </histogram>
 
 <histogram name="CustomTabs.TimeElapsedSinceMinimized.Maximized" units="s"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>katzz@google.com</owner>
   <owner>chrome-connective-tissue@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/download/histograms.xml b/tools/metrics/histograms/metadata/download/histograms.xml
index e656a99e..7c2b90a 100644
--- a/tools/metrics/histograms/metadata/download/histograms.xml
+++ b/tools/metrics/histograms/metadata/download/histograms.xml
@@ -100,7 +100,7 @@
 </histogram>
 
 <histogram name="Download.BandwidthOverallBytesPerSecond2" units="bytes/second"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>qinmin@chromium.org</owner>
   <summary>
     Overall bandwidth seen for a completed download. This includes all file
@@ -450,7 +450,7 @@
 </histogram>
 
 <histogram name="Download.Interstitial.UIAction"
-    enum="DownloadInterstitialUIAction" expires_after="2024-06-04">
+    enum="DownloadInterstitialUIAction" expires_after="2024-08-04">
   <owner>alexmitra@chromium.org</owner>
   <owner>clank-downloads@google.com</owner>
   <summary>
@@ -491,7 +491,7 @@
 </histogram>
 
 <histogram name="Download.IOSDownloadedFileAction" enum="DownloadedFileAction"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>sdefresne@chromium.org</owner>
   <owner>ewannpv@chromium.org</owner>
   <owner>mrefaat@chromium.org</owner>
@@ -526,7 +526,7 @@
 </histogram>
 
 <histogram name="Download.IOSDownloadFileResult" enum="DownloadFileResult"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>sdefresne@chromium.org</owner>
   <owner>ewannpv@chromium.org</owner>
   <owner>mrefaat@chromium.org</owner>
@@ -800,7 +800,7 @@
 </histogram>
 
 <histogram name="Download.Retry.InterruptReason" enum="InterruptReason"
-    expires_after="2024-06-03">
+    expires_after="2024-08-04">
   <owner>chlily@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/enterprise/histograms.xml b/tools/metrics/histograms/metadata/enterprise/histograms.xml
index 2975ca05..7f0f9276 100644
--- a/tools/metrics/histograms/metadata/enterprise/histograms.xml
+++ b/tools/metrics/histograms/metadata/enterprise/histograms.xml
@@ -792,7 +792,7 @@
 </histogram>
 
 <histogram name="Enterprise.DeviceSignals.Collection.{Variant}"
-    enum="DeviceSignalsSignalName" expires_after="2024-06-01">
+    enum="DeviceSignalsSignalName" expires_after="2024-08-04">
   <owner>seblalancette@chromium.org</owner>
   <owner>cbe-device-trust-eng@google.com</owner>
   <summary>
@@ -892,7 +892,7 @@
 </histogram>
 
 <histogram name="Enterprise.DeviceTrust.Key.LoadPersistedKeyResult"
-    enum="DTLoadPersistedKeyResult" expires_after="2024-06-01">
+    enum="DTLoadPersistedKeyResult" expires_after="2024-08-04">
   <owner>seblalancette@google.com</owner>
   <owner>cbe-device-trust-eng@google.com</owner>
   <summary>
@@ -917,7 +917,7 @@
 </histogram>
 
 <histogram name="Enterprise.DeviceTrust.Key.TrustLevel" enum="DTKeyTrustLevel"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>hmare@google.com</owner>
   <owner>rogerta@chromium.org</owner>
   <owner>seblalancette@chromium.org</owner>
@@ -929,7 +929,7 @@
 </histogram>
 
 <histogram name="Enterprise.DeviceTrust.Key.Type" enum="DTKeyType"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>hmare@google.com</owner>
   <owner>rogerta@chromium.org</owner>
   <owner>seblalancette@chromium.org</owner>
@@ -1152,7 +1152,7 @@
 </histogram>
 
 <histogram name="Enterprise.DeviceTrust.SyncSigningKey.UploadCode"
-    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2024-06-01">
+    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2024-08-04">
   <owner>seblalancette@chromium.org</owner>
   <owner>cbe-device-trust-eng@google.com</owner>
   <summary>
@@ -2009,7 +2009,7 @@
 </histogram>
 
 <histogram name="Enterprise.EnrollmentTime.Failure" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>asumaneev@google.com</owner>
   <owner>sergiyb@chromium.org</owner>
   <owner>chromeos-commercial-remote-management@google.com</owner>
@@ -2439,7 +2439,7 @@
 </histogram>
 
 <histogram name="Enterprise.PolicyUpdatePeriod.User" units="days"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>rbock@google.com</owner>
   <owner>igorcov@chromium.org</owner>
   <owner>chromeos-commercial-remote-management@google.com</owner>
@@ -2538,7 +2538,7 @@
 </histogram>
 
 <histogram name="Enterprise.ReportingEventUploadSuccess"
-    enum="EnterpriseReportingEventType" expires_after="2024-06-01">
+    enum="EnterpriseReportingEventType" expires_after="2024-08-04">
   <owner>xanth@google.com</owner>
   <owner>alshawwa@chromium.org</owner>
   <owner>domfc@chromium.org</owner>
@@ -2870,7 +2870,7 @@
 </histogram>
 
 <histogram name="Enterprise.UserPolicyChromeOS.InitialFetch.OAuth2Error"
-    enum="GoogleServiceAuthError" expires_after="2024-06-01">
+    enum="GoogleServiceAuthError" expires_after="2024-08-04">
   <owner>igorcov@chromium.org</owner>
   <owner>asumaneev@google.com</owner>
   <owner>chromeos-commercial-remote-management@google.com</owner>
@@ -2884,7 +2884,7 @@
 
 <histogram name="Enterprise.UserPolicyChromeOS.ReregistrationResult"
     enum="EnterpriseUserPolicyChromeOSReregistrationResult"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>hendrich@chromium.org</owner>
   <owner>rbock@google.com</owner>
   <owner>chromeos-commercial-remote-management@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/event/histograms.xml b/tools/metrics/histograms/metadata/event/histograms.xml
index bc0b935..5c4be8e 100644
--- a/tools/metrics/histograms/metadata/event/histograms.xml
+++ b/tools/metrics/histograms/metadata/event/histograms.xml
@@ -83,7 +83,7 @@
 </histogram>
 
 <histogram name="Event.GestureCreated" enum="UIEventType"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>kuscher@google.com</owner>
   <owner>input-dev@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/extensions/histograms.xml b/tools/metrics/histograms/metadata/extensions/histograms.xml
index 84036f24..85bd8eb 100644
--- a/tools/metrics/histograms/metadata/extensions/histograms.xml
+++ b/tools/metrics/histograms/metadata/extensions/histograms.xml
@@ -146,7 +146,7 @@
 </histogram>
 
 <histogram name="Extensions.ActiveScriptController.DeniedExtensions"
-    units="Extension Count" expires_after="2024-06-02">
+    units="Extension Count" expires_after="2024-08-04">
   <owner>rdevlin.cronin@chromium.org</owner>
   <owner>extensions-core@chromium.org</owner>
   <summary>
@@ -580,7 +580,7 @@
 </histogram>
 
 <histogram name="Extensions.CWSInfoService.NetworkResponseCodeOrError"
-    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2024-05-04">
+    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2024-08-04">
   <owner>anunoy@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -590,7 +590,7 @@
 </histogram>
 
 <histogram name="Extensions.CWSInfoService.NetworkRetriesTillSuccess"
-    units="retries" expires_after="2024-05-04">
+    units="retries" expires_after="2024-08-04">
   <owner>anunoy@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/families/histograms.xml b/tools/metrics/histograms/metadata/families/histograms.xml
index 447b42a..1175967 100644
--- a/tools/metrics/histograms/metadata/families/histograms.xml
+++ b/tools/metrics/histograms/metadata/families/histograms.xml
@@ -302,7 +302,7 @@
 </histogram>
 
 <histogram name="FamilyLinkUser.ClassifyUrlRequest.{Status}.Latency" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>tju@google.com</owner>
   <owner>chrome-kids-eng@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
index 21f7af8..0ae1ab2 100644
--- a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
+++ b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
@@ -138,8 +138,6 @@
   <variant name="IPH_DesktopPwaInstall" summary="desktop PWA install icon"/>
   <variant name="IPH_DesktopPWAsLinkCapturingLaunch"
       summary="PWA launch due to link capturing being enabled"/>
-  <variant name="IPH_DesktopTabGroupsNewGroup"
-      summary="creating a new tab group"/>
   <variant name="IPH_DownloadEsbPromo" summary="download ESB promo"/>
   <variant name="IPH_DownloadHome" summary="download home"/>
   <variant name="IPH_DownloadInfobarDownloadContinuing"
@@ -562,7 +560,7 @@
 </histogram>
 
 <histogram name="InProductHelp.DismissalReason.iOS"
-    enum="InProductHelpDismissalReason" expires_after="2024-06-02">
+    enum="InProductHelpDismissalReason" expires_after="2024-08-04">
   <owner>lpromero@google.com</owner>
   <owner>gambard@chromium.org</owner>
   <summary>
@@ -606,7 +604,7 @@
 </histogram>
 
 <histogram name="InProductHelp.SnoozeAction" enum="InProductHelpSnoozeAction"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>haileywang@chromium.org</owner>
   <owner>shaktisahu@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/file/histograms.xml b/tools/metrics/histograms/metadata/file/histograms.xml
index 3eecba7..8df7a502 100644
--- a/tools/metrics/histograms/metadata/file/histograms.xml
+++ b/tools/metrics/histograms/metadata/file/histograms.xml
@@ -514,7 +514,7 @@
 </histogram>
 
 <histogram name="FileBrowser.GoogleDrive.BulkPinning.Enabled"
-    enum="BooleanEnabled" expires_after="2024-06-01">
+    enum="BooleanEnabled" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -535,7 +535,7 @@
 </histogram>
 
 <histogram name="FileBrowser.GoogleDrive.BulkPinning.EnableDocsOffline"
-    enum="DocsOfflineEnableStatus" expires_after="2024-06-01">
+    enum="DocsOfflineEnableStatus" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -545,7 +545,7 @@
 </histogram>
 
 <histogram name="FileBrowser.GoogleDrive.BulkPinning.Listing.Error"
-    enum="GoogleDrive.BulkPinning.Stage" expires_after="2024-06-01">
+    enum="GoogleDrive.BulkPinning.Stage" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -556,7 +556,7 @@
 
 <histogram name="FileBrowser.GoogleDrive.BulkPinning.MultipleMountFailures"
     enum="GoogleDrive.BulkPinning.MountFailureReason"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>Records the reason DriveFS fails to mount consecutively</summary>
@@ -574,7 +574,7 @@
 </histogram>
 
 <histogram name="FileBrowser.GoogleDrive.BulkPinning.PinnedFiles"
-    enum="BooleanPinned" expires_after="2024-06-01">
+    enum="BooleanPinned" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -584,7 +584,7 @@
 </histogram>
 
 <histogram name="FileBrowser.GoogleDrive.BulkPinning.Pinning.Error"
-    enum="DriveFileError" expires_after="2024-06-01">
+    enum="DriveFileError" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -626,7 +626,7 @@
 </histogram>
 
 <histogram name="FileBrowser.GoogleDrive.BulkPinning.TimeSpentListing"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -641,7 +641,7 @@
 </histogram>
 
 <histogram name="FileBrowser.GoogleDrive.BulkPinning.ToDownloadMiB" units="MiB"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -654,7 +654,7 @@
 </histogram>
 
 <histogram name="FileBrowser.GoogleDrive.DailyDSSAvailabilityPercentage"
-    units="%" expires_after="2024-06-01">
+    units="%" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -668,7 +668,7 @@
 </histogram>
 
 <histogram name="FileBrowser.GoogleDrive.DSSAvailabilityPercentage" units="%"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -816,7 +816,7 @@
 </histogram>
 
 <histogram name="FileBrowser.OfficeFiles.Errors.OneDrive"
-    enum="OfficeOneDriveOpenErrors" expires_after="2024-06-02">
+    enum="OfficeOneDriveOpenErrors" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -826,7 +826,7 @@
 </histogram>
 
 <histogram name="FileBrowser.OfficeFiles.Errors.{CloudProvider}.MetricState"
-    enum="MetricState" expires_after="2024-06-02">
+    enum="MetricState" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -837,7 +837,7 @@
 
 <histogram
     name="FileBrowser.OfficeFiles.FileHandler.{RootType}.{ConnectionStatus}"
-    enum="OfficeFileHandler" expires_after="2024-06-02">
+    enum="OfficeFileHandler" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -856,7 +856,7 @@
 
 <histogram
     name="FileBrowser.OfficeFiles.FileOpen.Time.{Transfer}.{Size}.To.{CloudProvider}"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -888,7 +888,7 @@
 </histogram>
 
 <histogram name="FileBrowser.OfficeFiles.ODFS.AuthAttempt"
-    enum="BooleanInteractive" expires_after="2024-06-02">
+    enum="BooleanInteractive" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -898,7 +898,7 @@
 </histogram>
 
 <histogram name="FileBrowser.OfficeFiles.ODFS.AuthResult.Interactive"
-    enum="OfficeOneDriveAuthResultInteractive" expires_after="2024-06-02">
+    enum="OfficeOneDriveAuthResultInteractive" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -908,7 +908,7 @@
 </histogram>
 
 <histogram name="FileBrowser.OfficeFiles.ODFS.AuthResult.NonInteractive"
-    enum="OfficeOneDriveAuthResultNonInteractive" expires_after="2024-06-02">
+    enum="OfficeOneDriveAuthResultNonInteractive" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -918,7 +918,7 @@
 </histogram>
 
 <histogram name="FileBrowser.OfficeFiles.ODFS.DriveType"
-    enum="OfficeOneDriveType" expires_after="2024-06-02">
+    enum="OfficeOneDriveType" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -928,7 +928,7 @@
 </histogram>
 
 <histogram name="FileBrowser.OfficeFiles.ODFS.FileSize.{Direction}" units="KiB"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -942,7 +942,7 @@
 
 <histogram
     name="FileBrowser.OfficeFiles.ODFS.FileSystemProvider.Completion.{API-FSP}"
-    enum="FileSystemProviderOperationCompletion" expires_after="2024-06-02">
+    enum="FileSystemProviderOperationCompletion" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -955,7 +955,7 @@
 
 <histogram
     name="FileBrowser.OfficeFiles.ODFS.FileSystemProvider.Error.{API-FSP}"
-    enum="PlatformFileError" expires_after="2024-06-02">
+    enum="PlatformFileError" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -967,7 +967,7 @@
 
 <histogram
     name="FileBrowser.OfficeFiles.ODFS.FileSystemProvider.Time.{API-FSP}"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -978,7 +978,7 @@
 </histogram>
 
 <histogram name="FileBrowser.OfficeFiles.ODFS.GraphAPI.DeltaSize.{Case}"
-    units="count" expires_after="2024-06-02">
+    units="count" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -994,7 +994,7 @@
 
 <histogram
     name="FileBrowser.OfficeFiles.ODFS.GraphAPI.LastResponseCode.{GetDeltaCallType}"
-    enum="OfficeGraphAPIResult" expires_after="2024-06-02">
+    enum="OfficeGraphAPIResult" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -1007,7 +1007,7 @@
 
 <histogram
     name="FileBrowser.OfficeFiles.ODFS.GraphAPI.ResponseCode.{GraphAPIMethod}"
-    enum="OfficeGraphAPIResult" expires_after="2024-06-02">
+    enum="OfficeGraphAPIResult" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -1018,7 +1018,7 @@
 </histogram>
 
 <histogram name="FileBrowser.OfficeFiles.ODFS.GraphAPI.Time.{GraphAPIMethod}"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -1041,7 +1041,7 @@
 </histogram>
 
 <histogram name="FileBrowser.OfficeFiles.ODFS.Throughput.{Direction}"
-    units="KiB/s" expires_after="2024-06-02">
+    units="KiB/s" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -1054,7 +1054,7 @@
 </histogram>
 
 <histogram name="FileBrowser.OfficeFiles.ODFS.Version" units="version"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -1065,7 +1065,7 @@
 </histogram>
 
 <histogram name="FileBrowser.OfficeFiles.Open.CloudProvider"
-    enum="CloudProvider" expires_after="2024-06-02">
+    enum="CloudProvider" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -1077,7 +1077,7 @@
 </histogram>
 
 <histogram name="FileBrowser.OfficeFiles.Open.FileType.{CloudProvider}"
-    enum="OfficeOpenExtensions" expires_after="2024-06-02">
+    enum="OfficeOpenExtensions" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -1089,7 +1089,7 @@
 
 <histogram
     name="FileBrowser.OfficeFiles.Open.IOTaskError.{CloudProvider}.{Transfer}"
-    enum="PlatformFileError" expires_after="2024-06-02">
+    enum="PlatformFileError" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -1109,7 +1109,7 @@
 
 <histogram
     name="FileBrowser.OfficeFiles.Open.IOTaskError.{CloudProvider}.{Transfer}.MetricState"
-    enum="MetricState" expires_after="2024-06-02">
+    enum="MetricState" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -1126,7 +1126,7 @@
 </histogram>
 
 <histogram name="FileBrowser.OfficeFiles.Open.SourceVolume.{CloudProvider}"
-    enum="OfficeFilesSourceVolume" expires_after="2024-06-02">
+    enum="OfficeFilesSourceVolume" expires_after="2024-08-04">
   <owner>austinct@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -1148,7 +1148,7 @@
 
 <histogram
     name="FileBrowser.OfficeFiles.Open.SourceVolume.{CloudProvider}.MetricState"
-    enum="MetricState" expires_after="2024-06-02">
+    enum="MetricState" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -1159,7 +1159,7 @@
 </histogram>
 
 <histogram name="FileBrowser.OfficeFiles.Open.TransferRequired.{CloudProvider}"
-    enum="OfficeFilesTransferRequired" expires_after="2024-06-02">
+    enum="OfficeFilesTransferRequired" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -1171,7 +1171,7 @@
 
 <histogram
     name="FileBrowser.OfficeFiles.Open.TransferRequired.{CloudProvider}.MetricState"
-    enum="MetricState" expires_after="2024-06-02">
+    enum="MetricState" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -1182,7 +1182,7 @@
 </histogram>
 
 <histogram name="FileBrowser.OfficeFiles.Open.UploadResult.{CloudProvider}"
-    enum="OfficeFilesUploadResult" expires_after="2024-06-02">
+    enum="OfficeFilesUploadResult" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -1194,7 +1194,7 @@
 
 <histogram
     name="FileBrowser.OfficeFiles.Open.UploadResult.{CloudProvider}.MetricState"
-    enum="MetricState" expires_after="2024-06-02">
+    enum="MetricState" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -1205,7 +1205,7 @@
 </histogram>
 
 <histogram name="FileBrowser.OfficeFiles.Setup.CancelPage"
-    enum="OfficeSetupPage" expires_after="2024-06-02">
+    enum="OfficeSetupPage" expires_after="2024-08-04">
   <owner>austinct@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -1216,7 +1216,7 @@
 </histogram>
 
 <histogram name="FileBrowser.OfficeFiles.Setup.FileHandlerSelection"
-    enum="OfficeSetupFileHandler" expires_after="2024-06-02">
+    enum="OfficeSetupFileHandler" expires_after="2024-08-04">
   <owner>austinct@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -1227,7 +1227,7 @@
 
 <histogram
     name="FileBrowser.OfficeFiles.Setup.FirstTimeMicrosoft365Availability"
-    enum="Microsoft365Availability" expires_after="2024-06-02">
+    enum="Microsoft365Availability" expires_after="2024-08-04">
   <owner>austinct@chromium.org</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -1237,7 +1237,7 @@
 </histogram>
 
 <histogram name="FileBrowser.OfficeFiles.Setup.ODFSAvailability"
-    enum="BooleanAvailable" expires_after="2024-06-02">
+    enum="BooleanAvailable" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -1247,7 +1247,7 @@
 </histogram>
 
 <histogram name="FileBrowser.OfficeFiles.TaskResult.{CloudProvider}"
-    enum="OfficeTaskResult" expires_after="2024-06-02">
+    enum="OfficeTaskResult" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
@@ -1266,7 +1266,7 @@
 
 <histogram
     name="FileBrowser.OfficeFiles.TaskResult.{CloudProvider}.MetricState"
-    enum="MetricState" expires_after="2024-06-02">
+    enum="MetricState" expires_after="2024-08-04">
   <owner>simmonsjosh@google.com</owner>
   <owner>src/ui/file_manager/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/gpu/histograms.xml b/tools/metrics/histograms/metadata/gpu/histograms.xml
index 53a2354..02b8a9a 100644
--- a/tools/metrics/histograms/metadata/gpu/histograms.xml
+++ b/tools/metrics/histograms/metadata/gpu/histograms.xml
@@ -69,7 +69,7 @@
 </variants>
 
 <histogram name="ConfigureDisplays.External.Modeset.AttemptSucceeded"
-    enum="BooleanSuccess" expires_after="2024-06-02">
+    enum="BooleanSuccess" expires_after="2024-08-04">
   <owner>gildekel@chromium.org</owner>
   <owner>chromeos-gfx-display@chromium.org</owner>
   <summary>
@@ -82,7 +82,7 @@
 </histogram>
 
 <histogram name="ConfigureDisplays.External.Modeset.FinalStatus"
-    enum="BooleanSuccess" expires_after="2024-06-02">
+    enum="BooleanSuccess" expires_after="2024-08-04">
   <owner>gildekel@chromium.org</owner>
   <owner>chromeos-gfx-display@chromium.org</owner>
   <summary>
@@ -94,7 +94,7 @@
 </histogram>
 
 <histogram name="ConfigureDisplays.Internal.Modeset.AttemptSucceeded"
-    enum="BooleanSuccess" expires_after="2024-06-02">
+    enum="BooleanSuccess" expires_after="2024-08-04">
   <owner>gildekel@chromium.org</owner>
   <owner>chromeos-gfx-display@chromium.org</owner>
   <summary>
@@ -108,7 +108,7 @@
 </histogram>
 
 <histogram name="ConfigureDisplays.Internal.Modeset.FinalStatus"
-    enum="BooleanSuccess" expires_after="2024-06-02">
+    enum="BooleanSuccess" expires_after="2024-08-04">
   <owner>gildekel@chromium.org</owner>
   <owner>chromeos-gfx-display@chromium.org</owner>
   <summary>
@@ -136,7 +136,7 @@
 </histogram>
 
 <histogram name="ConfigureDisplays.Modeset.MstExternalDisplaysCount"
-    units="count" expires_after="2024-06-02">
+    units="count" expires_after="2024-08-04">
   <owner>gildekel@chromium.org</owner>
   <owner>chromeos-gfx-display@chromium.org</owner>
   <summary>
@@ -147,7 +147,7 @@
 </histogram>
 
 <histogram name="ConfigureDisplays.Modeset.MstExternalDisplaysPercentage"
-    units="%" expires_after="2024-06-02">
+    units="%" expires_after="2024-08-04">
   <owner>gildekel@chromium.org</owner>
   <owner>chromeos-gfx-display@chromium.org</owner>
   <summary>
@@ -158,7 +158,7 @@
 </histogram>
 
 <histogram name="ConfigureDisplays.Modeset.TotalExternalDisplaysCount"
-    units="count" expires_after="2024-06-02">
+    units="count" expires_after="2024-08-04">
   <owner>gildekel@chromium.org</owner>
   <owner>chromeos-gfx-display@chromium.org</owner>
   <summary>
@@ -169,7 +169,7 @@
 </histogram>
 
 <histogram name="ConfigureDisplays.{Connection}.Modeset.Success.RefreshRate"
-    units="Hz" expires_after="2024-06-02">
+    units="Hz" expires_after="2024-08-04">
   <owner>gildekel@chromium.org</owner>
   <owner>chromeos-gfx-display@chromium.org</owner>
   <summary>
@@ -183,7 +183,7 @@
 </histogram>
 
 <histogram name="ConfigureDisplays.{Connection}.Modeset.{Report}.Resolution"
-    enum="DisplayResolution" expires_after="2024-06-02">
+    enum="DisplayResolution" expires_after="2024-08-04">
   <owner>gildekel@chromium.org</owner>
   <owner>chromeos-gfx-display@chromium.org</owner>
   <summary>{Connection} {Report}</summary>
@@ -201,7 +201,7 @@
 </histogram>
 
 <histogram name="Display.External.BlockZeroSerialNumberType"
-    enum="BlockZeroSerialNumberType" expires_after="2024-06-02">
+    enum="BlockZeroSerialNumberType" expires_after="2024-08-04">
   <owner>gildekel@chromium.org</owner>
   <owner>chromeos-gfx-display@google.com</owner>
   <summary>
@@ -221,7 +221,7 @@
 </histogram>
 
 <histogram name="Display.External.ParseEdidOptionals" enum="ParseEdidOptionals"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>gildekel@chromium.org</owner>
   <owner>chromeos-gfx-display@google.com</owner>
   <summary>
@@ -231,7 +231,7 @@
 </histogram>
 
 <histogram name="Display.MultipleDisplays.GenerateId.CollisionDetection"
-    enum="BooleanDisplayIdCollision" expires_after="2024-06-02">
+    enum="BooleanDisplayIdCollision" expires_after="2024-08-04">
   <owner>gildekel@chromium.org</owner>
   <owner>chromeos-gfx-display@google.com</owner>
   <summary>
@@ -244,7 +244,7 @@
 </histogram>
 
 <histogram name="Display.ParseEdidFailure" enum="ParseEdidFailure"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>gildekel@chromium.org</owner>
   <owner>chromeos-gfx-display@google.com</owner>
   <summary>
@@ -265,7 +265,7 @@
 </histogram>
 
 <histogram name="GPU.ANGLE.D3D11CreateDeviceError" enum="Hresult"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>jonahr@google.com</owner>
   <owner>angle-team@google.com</owner>
   <summary>
@@ -904,7 +904,7 @@
 </histogram>
 
 <histogram name="Gpu.Graphite.GraphiteImageProviderAccessHitInCache"
-    enum="Boolean" expires_after="2024-06-01">
+    enum="Boolean" expires_after="2024-08-04">
   <owner>blundell@chromium.org</owner>
   <owner>sunnyps@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
@@ -1250,7 +1250,7 @@
 </histogram>
 
 <histogram name="GPU.SharedImage.BackingType" enum="SharedImageBackingType"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>kylechar@chromium.org</owner>
   <owner>chrome-gpu-metrics@google.com</owner>
   <summary>
@@ -1295,7 +1295,7 @@
 </histogram>
 
 <histogram name="GPU.SharedImage.IsRG88HardwareGMBSupported" enum="Boolean"
-    expires_after="2024-06-04">
+    expires_after="2024-08-04">
   <owner>hitawala@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
@@ -1330,7 +1330,7 @@
 </histogram>
 
 <histogram name="GPU.TransferCache.EntryFound" enum="BooleanYesNo"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>boliu@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
@@ -1340,7 +1340,7 @@
 </histogram>
 
 <histogram name="GPU.TransferCache.MaxHistoricalTimeSinceLastUse" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>boliu@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
@@ -1350,7 +1350,7 @@
 </histogram>
 
 <histogram name="GPU.TransferCache.ReusedTimes" units="Reuses"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>boliu@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
@@ -1360,7 +1360,7 @@
 </histogram>
 
 <histogram name="GPU.TransferCache.TimeSinceLastUse" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>boliu@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
@@ -1370,7 +1370,7 @@
 </histogram>
 
 <histogram name="GPU.TransferCache.TimeSinceLastUseOnDelete" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>boliu@chromium.org</owner>
   <owner>graphics-dev@chromium.org</owner>
   <summary>
@@ -1585,7 +1585,7 @@
 </histogram>
 
 <histogram name="GPU.{GraphiteDawnOrWebGPU}.{Cacheable}.CacheHit"
-    units="microseconds" expires_after="2024-06-02">
+    units="microseconds" expires_after="2024-08-04">
   <owner>lokokung@google.com</owner>
   <owner>mdb.webgpu-dev-team@google.com</owner>
   <summary>
@@ -1599,7 +1599,7 @@
 </histogram>
 
 <histogram name="GPU.{GraphiteDawnOrWebGPU}.{Cacheable}.CacheMiss"
-    units="microseconds" expires_after="2024-06-02">
+    units="microseconds" expires_after="2024-08-04">
   <owner>lokokung@google.com</owner>
   <owner>mdb.webgpu-dev-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/history/histograms.xml b/tools/metrics/histograms/metadata/history/histograms.xml
index fa9166983..3678349 100644
--- a/tools/metrics/histograms/metadata/history/histograms.xml
+++ b/tools/metrics/histograms/metadata/history/histograms.xml
@@ -429,7 +429,7 @@
 </histogram>
 
 <histogram name="History.Clusters.Actions.FinalState.Number{Event}"
-    units="count" expires_after="2024-06-02">
+    units="count" expires_after="2024-08-04">
   <owner>mcrouse@chromium.org</owner>
   <owner>chrome-journeys@google.com</owner>
   <component>UI&gt;Browser&gt;Journeys</component>
@@ -678,7 +678,7 @@
 
 <histogram
     name="History.Clusters.Backend.FilterClusterProcessor.ClusterFilterReason{Source}"
-    enum="ClusterFilterReason" expires_after="2024-04-28">
+    enum="ClusterFilterReason" expires_after="2024-08-04">
   <owner>sophiechang@chromium.org</owner>
   <owner>chrome-journeys@google.com</owner>
   <component>UI&gt;Browser&gt;Journeys</component>
@@ -712,7 +712,7 @@
 
 <histogram
     name="History.Clusters.Backend.GetMostRecentClusters.{Segment}{Source}"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>manukh@chromium.org</owner>
   <owner>chrome-journeys@google.com</owner>
   <component>UI&gt;Browser&gt;Journeys</component>
@@ -749,7 +749,7 @@
 
 <histogram
     name="History.Clusters.Backend.GetMostRecentClustersForUI.GetMostRecentPersistedClustersTimeHorizon{Source}"
-    units="hours" expires_after="2024-06-02">
+    units="hours" expires_after="2024-08-04">
   <owner>sophiechang@chromium.org</owner>
   <owner>chrome-journeys@google.com</owner>
   <component>UI&gt;Browser&gt;Journeys</component>
@@ -783,7 +783,7 @@
 
 <histogram
     name="History.Clusters.Backend.GetMostRecentClustersForUI.{Segment}{Source}"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>sophiechang@chromium.org</owner>
   <owner>chrome-journeys@google.com</owner>
   <component>UI&gt;Browser&gt;Journeys</component>
@@ -1090,7 +1090,7 @@
 
 <histogram
     name="History.Clusters.Backend.UpdateClusterTriggerability.{Segment}"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>manukh@chromium.org</owner>
   <owner>chrome-journeys@google.com</owner>
   <component>UI&gt;Browser&gt;Journeys</component>
@@ -1148,7 +1148,7 @@
 
 <histogram
     name="History.Clusters.Backend.WasClusterFiltered.{ClusterFilterReason}"
-    enum="BooleanFiltered" expires_after="2024-06-02">
+    enum="BooleanFiltered" expires_after="2024-08-04">
   <owner>mcrouse@chromium.org</owner>
   <owner>chrome-journeys@google.com</owner>
   <component>UI&gt;Browser&gt;Journeys</component>
@@ -1180,7 +1180,7 @@
 </histogram>
 
 <histogram name="History.Clusters.ContextClusterer.DbLatency.{Segment}"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>sophiechang@chromium.org</owner>
   <owner>chrome-journeys@google.com</owner>
   <component>UI&gt;Browser&gt;Journeys</component>
@@ -1263,7 +1263,7 @@
 
 <histogram
     name="History.Clusters.ContextClusterer.VisitProcessingLatency.{Segment}"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>sophiechang@chromium.org</owner>
   <owner>chrome-journeys@google.com</owner>
   <component>UI&gt;Browser&gt;Journeys</component>
@@ -1324,7 +1324,7 @@
 </histogram>
 
 <histogram name="History.Clusters.KeywordCache.LoadCachesFromPrefs.Latency"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>pnoland@chromium.org</owner>
   <owner>chrome-journeys@google.com</owner>
   <component>UI&gt;Browser&gt;Journeys</component>
@@ -1349,7 +1349,7 @@
 </histogram>
 
 <histogram name="History.Clusters.KeywordCache.WriteCache.{CacheType}.Latency"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>pnoland@chromium.org</owner>
   <owner>chrome-journeys@google.com</owner>
   <component>UI&gt;Browser&gt;Journeys</component>
@@ -1420,7 +1420,7 @@
 </histogram>
 
 <histogram name="History.Clusters.UIActions.Cluster.{ClusterAction}"
-    units="index" expires_after="2024-06-02">
+    units="index" expires_after="2024-08-04">
   <owner>mahmadi@chromium.org</owner>
   <owner>chrome-journeys@google.com</owner>
   <component>UI&gt;Browser&gt;Journeys</component>
@@ -1443,7 +1443,7 @@
 
 <histogram
     name="History.Clusters.UIActions.RelatedSearch.{RelatedSearchAction}"
-    units="index" expires_after="2024-06-02">
+    units="index" expires_after="2024-08-04">
   <owner>mahmadi@chromium.org</owner>
   <owner>chrome-journeys@google.com</owner>
   <component>UI&gt;Browser&gt;Journeys</component>
@@ -1471,7 +1471,7 @@
 </histogram>
 
 <histogram name="History.Clusters.UIActions.{VisitType}Visit.{VisitAction}"
-    units="index" expires_after="2024-06-02">
+    units="index" expires_after="2024-08-04">
   <owner>mahmadi@chromium.org</owner>
   <owner>chrome-journeys@google.com</owner>
   <component>UI&gt;Browser&gt;Journeys</component>
@@ -2109,7 +2109,7 @@
   </summary>
 </histogram>
 
-<histogram name="History.URLTableCount" units="URLs" expires_after="2024-06-02">
+<histogram name="History.URLTableCount" units="URLs" expires_after="2024-08-04">
   <owner>mpearson@chromium.org</owner>
   <owner>sky@chromium.org</owner>
   <component>UI&gt;Browser&gt;History</component>
@@ -2120,7 +2120,7 @@
 </histogram>
 
 <histogram name="History.VisitedLinks.HashTableLengthOnReaderInit"
-    units="entries" expires_after="2024-06-02">
+    units="entries" expires_after="2024-08-04">
   <owner>kyraseevers@chromium.org</owner>
   <owner>brgoldstein@google.com</owner>
   <summary>
@@ -2131,7 +2131,7 @@
 </histogram>
 
 <histogram name="History.VisitedLinks.HashTableSizeOnTableCreate" units="MB"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>kyraseevers@chromium.org</owner>
   <owner>brgoldstein@google.com</owner>
   <summary>
@@ -2141,7 +2141,7 @@
 </histogram>
 
 <histogram name="History.VisitedLinks.HashTableUsageOnLinkAdded"
-    units="fingerprints" expires_after="2024-06-02">
+    units="fingerprints" expires_after="2024-08-04">
   <owner>kyraseevers@chromium.org</owner>
   <owner>brgoldstein@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/holding_space/histograms.xml b/tools/metrics/histograms/metadata/holding_space/histograms.xml
index fa23b04..ed46695 100644
--- a/tools/metrics/histograms/metadata/holding_space/histograms.xml
+++ b/tools/metrics/histograms/metadata/holding_space/histograms.xml
@@ -89,7 +89,7 @@
 </histogram>
 
 <histogram name="HoldingSpace.Downloads.Action.All"
-    enum="HoldingSpaceDownloadsAction" expires_after="2024-06-01">
+    enum="HoldingSpaceDownloadsAction" expires_after="2024-08-04">
   <owner>dmblack@google.com</owner>
   <owner>alexandrahill@google.com</owner>
   <summary>
@@ -121,7 +121,7 @@
 </histogram>
 
 <histogram name="HoldingSpace.FilesAppChip.Action.All"
-    enum="HoldingSpaceFilesAppChipAction" expires_after="2024-06-01">
+    enum="HoldingSpaceFilesAppChipAction" expires_after="2024-08-04">
   <owner>dmblack@google.com</owner>
   <owner>alexandrahill@google.com</owner>
   <summary>
@@ -131,7 +131,7 @@
 </histogram>
 
 <histogram name="HoldingSpace.Item.Action.All" enum="HoldingSpaceItemAction"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>dmblack@google.com</owner>
   <owner>alexandrahill@google.com</owner>
   <summary>
@@ -191,7 +191,7 @@
 </histogram>
 
 <histogram name="HoldingSpace.Item.Action.{action}" enum="HoldingSpaceItemType"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>dmblack@google.com</owner>
   <owner>alexandrahill@google.com</owner>
   <summary>
@@ -202,7 +202,7 @@
 </histogram>
 
 <histogram name="HoldingSpace.Item.Action.{action}.Extension"
-    enum="HoldingSpaceExtension" expires_after="2024-06-01">
+    enum="HoldingSpaceExtension" expires_after="2024-08-04">
   <owner>dmblack@google.com</owner>
   <owner>alexandrahill@google.com</owner>
   <summary>
@@ -213,7 +213,7 @@
 </histogram>
 
 <histogram name="HoldingSpace.Item.Action.{action}.FileSystemType"
-    enum="HoldingSpaceFileSystemType" expires_after="2024-06-01">
+    enum="HoldingSpaceFileSystemType" expires_after="2024-08-04">
   <owner>dmblack@google.com</owner>
   <owner>alexandrahill@google.com</owner>
   <summary>
@@ -237,7 +237,7 @@
 
 <histogram
     name="HoldingSpace.Item.TotalCountV2.{type}.FileSystemType.{fs_type}"
-    units="items" expires_after="2024-06-01">
+    units="items" expires_after="2024-08-04">
   <owner>dmblack@google.com</owner>
   <owner>alexandrahill@google.com</owner>
   <summary>
@@ -263,7 +263,7 @@
 
 <histogram
     name="HoldingSpace.Item.VisibleCount.{type}.FileSystemType.{fs_type}"
-    units="items" expires_after="2024-06-01">
+    units="items" expires_after="2024-08-04">
   <owner>dmblack@google.com</owner>
   <owner>alexandrahill@google.com</owner>
   <summary>
@@ -276,7 +276,7 @@
 </histogram>
 
 <histogram name="HoldingSpace.Pod.Action.All" enum="HoldingSpacePodAction"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>dmblack@google.com</owner>
   <owner>alexandrahill@google.com</owner>
   <summary>
@@ -306,7 +306,7 @@
 </histogram>
 
 <histogram name="HoldingSpace.TimeFromFirstAvailabilityToFirstEntry" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>dmblack@google.com</owner>
   <owner>alexandrahill@google.com</owner>
   <summary>
@@ -316,7 +316,7 @@
 </histogram>
 
 <histogram name="HoldingSpace.TimeFromFirstEntryToFirstPin" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>dmblack@google.com</owner>
   <owner>alexandrahill@google.com</owner>
   <summary>
@@ -327,7 +327,7 @@
 </histogram>
 
 <histogram name="HoldingSpace.UserPreferences.PreviewsEnabled"
-    enum="BooleanEnabled" expires_after="2024-06-01">
+    enum="BooleanEnabled" expires_after="2024-08-04">
   <owner>dmblack@google.com</owner>
   <owner>alexandrahill@google.com</owner>
   <summary>
@@ -337,7 +337,7 @@
 </histogram>
 
 <histogram name="HoldingSpace.UserPreferences.SuggestionsExpanded"
-    enum="BooleanExpanded" expires_after="2024-06-01">
+    enum="BooleanExpanded" expires_after="2024-08-04">
   <owner>dmblack@google.com</owner>
   <owner>alexandrahill@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/input/histograms.xml b/tools/metrics/histograms/metadata/input/histograms.xml
index 65129ee..3266c9d 100644
--- a/tools/metrics/histograms/metadata/input/histograms.xml
+++ b/tools/metrics/histograms/metadata/input/histograms.xml
@@ -1509,7 +1509,7 @@
 </histogram>
 
 <histogram name="InputMethod.StylusHandwriting.GestureTime2" units="ms"
-    expires_after="2024-05-26">
+    expires_after="2024-08-04">
   <owner>alexmitra@chromium.org</owner>
   <owner>embedded-experience@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/ios/histograms.xml b/tools/metrics/histograms/metadata/ios/histograms.xml
index 406399bb..dc0282f 100644
--- a/tools/metrics/histograms/metadata/ios/histograms.xml
+++ b/tools/metrics/histograms/metadata/ios/histograms.xml
@@ -93,7 +93,7 @@
 </histogram>
 
 <histogram name="IOS.AppLauncher.AppURLHasChromeLaunchScheme" enum="Boolean"
-    expires_after="2024-05-30">
+    expires_after="2024-08-04">
   <owner>ajuma@chromium.org</owner>
   <owner>bling-fundamentals@google.com</owner>
   <summary>
@@ -778,7 +778,7 @@
 </histogram>
 
 <histogram name="IOS.DesktopPasswordPromo.Shown"
-    enum="DesktopIOSPasswordPromoImpression" expires_after="2024-06-02">
+    enum="DesktopIOSPasswordPromoImpression" expires_after="2024-08-04">
   <owner>nicolasmacbeth@google.com</owner>
   <owner>bling-get-set-up@google.com</owner>
   <summary>
@@ -789,7 +789,7 @@
 </histogram>
 
 <histogram name="IOS.DesktopPasswordPromo.{Impression}.Action"
-    enum="DesktopIOSPasswordPromoAction" expires_after="2024-06-02">
+    enum="DesktopIOSPasswordPromoAction" expires_after="2024-08-04">
   <owner>nicolasmacbeth@google.com</owner>
   <owner>bling-get-set-up@google.com</owner>
   <summary>
@@ -1011,7 +1011,7 @@
 </histogram>
 
 <histogram name="IOS.Frame.FirstInputDelay.MainFrame2" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>danieltwhite@chromium.org</owner>
   <owner>ajuma@chromium.org</owner>
   <summary>
@@ -1334,7 +1334,7 @@
 </histogram>
 
 <histogram name="IOS.MainFrameNavigationIsInLockdownMode" enum="Boolean"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>ajuma@chromium.org</owner>
   <owner>bling-fundamentals@google.com</owner>
   <summary>
@@ -1814,7 +1814,7 @@
 </histogram>
 
 <histogram name="IOS.Omnibox.DeviceSwitcherResult.{Context}"
-    enum="OmniboxDeviceSwitcherResult" expires_after="2024-06-02">
+    enum="OmniboxDeviceSwitcherResult" expires_after="2024-08-04">
   <owner>christianxu@chromium.org</owner>
   <owner>bling-team@google.com</owner>
   <summary>
@@ -1828,7 +1828,7 @@
 </histogram>
 
 <histogram name="IOS.Omnibox.Promo.Events.{Context}"
-    enum="OmniboxPositionChoiceScreenEvents" expires_after="2024-05-31">
+    enum="OmniboxPositionChoiceScreenEvents" expires_after="2024-08-04">
   <owner>christianxu@chromium.org</owner>
   <owner>bling-team@google.com</owner>
   <summary>
@@ -1843,7 +1843,7 @@
 </histogram>
 
 <histogram name="IOS.Omnibox.Promo.SelectedPosition.{Context}"
-    enum="OmniboxPromoSelectedPositions" expires_after="2024-05-31">
+    enum="OmniboxPromoSelectedPositions" expires_after="2024-08-04">
   <owner>christianxu@chromium.org</owner>
   <owner>bling-team@google.com</owner>
   <summary>
@@ -1880,7 +1880,7 @@
 </histogram>
 
 <histogram name="IOS.Omnibox.Promo.TimeOpen.{Context}" units="ms"
-    expires_after="2024-05-31">
+    expires_after="2024-08-04">
   <owner>christianxu@chromium.org</owner>
   <owner>bling-team@google.com</owner>
   <summary>
@@ -1901,7 +1901,7 @@
 </histogram>
 
 <histogram name="IOS.Omnibox.SteadyStatePositionAtStartup"
-    enum="OmniboxPositionType" expires_after="2024-06-02">
+    enum="OmniboxPositionType" expires_after="2024-08-04">
   <owner>christianxu@chromium.org</owner>
   <owner>bling-team@google.com</owner>
   <summary>
@@ -1920,7 +1920,7 @@
 </histogram>
 
 <histogram name="IOS.Omnibox.SuggestionsListScrolled.{PageClass}"
-    enum="Boolean" expires_after="2024-06-02">
+    enum="Boolean" expires_after="2024-08-04">
   <owner>christianxu@chromium.org</owner>
   <owner>stkhapugin@chromium.org</owner>
   <owner>bling-team@google.com</owner>
@@ -2169,7 +2169,7 @@
 </histogram>
 
 <histogram name="IOS.OverflowMenu.UserScrolledToEndAndStartedCustomization"
-    enum="Boolean" expires_after="2024-04-28">
+    enum="Boolean" expires_after="2024-08-04">
   <owner>rkgibson@google.com</owner>
   <owner>bling-team@google.com</owner>
   <summary>
@@ -3055,7 +3055,7 @@
 </histogram>
 
 <histogram name="IOS.SaveToPhotos" enum="IOSSaveToPhotosType"
-    expires_after="2024-05-26">
+    expires_after="2024-08-04">
   <owner>qpubert@chromium.org</owner>
   <owner>djean@chromium.org</owner>
   <summary>
@@ -3138,7 +3138,7 @@
 </histogram>
 
 <histogram name="IOS.SaveToPhotos.UploadSuccessLatency" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>qpubert@chromium.org</owner>
   <owner>djean@chromium.org</owner>
   <summary>
@@ -3282,7 +3282,7 @@
   </summary>
 </histogram>
 
-<histogram name="IOS.Snapshots.CacheSize" units="KB" expires_after="2024-06-02">
+<histogram name="IOS.Snapshots.CacheSize" units="KB" expires_after="2024-08-04">
   <owner>ajuma@chromium.org</owner>
   <owner>edchin@chromium.org</owner>
   <summary>
@@ -3310,7 +3310,7 @@
 </histogram>
 
 <histogram name="IOS.Spotlight.Availability" enum="IOSSpotlightAvailability"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>rohitrao@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
   <summary>
@@ -3321,14 +3321,14 @@
 </histogram>
 
 <histogram name="IOS.Spotlight.BookmarksIndexingDuration" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>olivierrobin@chromium.org</owner>
   <owner>rohitrao@chromium.org</owner>
   <summary>Time spent in Spotlight initial indexation of bookmarks.</summary>
 </histogram>
 
 <histogram name="IOS.Spotlight.BookmarksInitialIndexSize" units="units"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>olivierrobin@chromium.org</owner>
   <owner>rohitrao@chromium.org</owner>
   <summary>
@@ -3350,7 +3350,7 @@
 </histogram>
 
 <histogram name="IOS.Spotlight.DonatedIntentType"
-    enum="IOSSpotlightDonatedIntentType" expires_after="2024-06-01">
+    enum="IOSSpotlightDonatedIntentType" expires_after="2024-08-04">
   <owner>stkhapugin@chromium.org</owner>
   <owner>ameurhosni@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
@@ -3358,7 +3358,7 @@
 </histogram>
 
 <histogram name="IOS.Spotlight.LaunchedIntentType"
-    enum="IOSSpotlightDonatedIntentType" expires_after="2024-06-01">
+    enum="IOSSpotlightDonatedIntentType" expires_after="2024-08-04">
   <owner>stkhapugin@chromium.org</owner>
   <owner>ameurhosni@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
@@ -3368,14 +3368,14 @@
 </histogram>
 
 <histogram name="IOS.Spotlight.OpenTabsIndexingDuration" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>stkhapugin@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
   <summary>Time spent in Spotlight initial indexation of open tabs.</summary>
 </histogram>
 
 <histogram name="IOS.Spotlight.OpenTabsInitialIndexSize" units="units"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>stkhapugin@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
   <summary>Number of open tabs indexed during initial indexation.</summary>
@@ -3393,7 +3393,7 @@
 </histogram>
 
 <histogram name="IOS.Spotlight.Origin" enum="IOSSpotlightOrigin"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>olivierrobin@chromium.org</owner>
   <owner>rohitrao@chromium.org</owner>
   <summary>
@@ -3403,7 +3403,7 @@
 </histogram>
 
 <histogram name="IOS.Spotlight.ReadingListIndexingDuration" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>stkhapugin@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
   <summary>Time spent in Spotlight initial indexation of reading list.</summary>
@@ -3498,7 +3498,7 @@
 </histogram>
 
 <histogram name="IOS.TabGrid.TabSelected.TimeSinceLastActivation" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>gambard@chromium.org</owner>
   <owner>chromeleon@google.com</owner>
   <summary>
@@ -3572,7 +3572,7 @@
 </histogram>
 
 <histogram name="IOS.TabSwitcher.DragDropTabs"
-    enum="IOSTabSwitcherDragDropTabs" expires_after="2024-06-02">
+    enum="IOSTabSwitcherDragDropTabs" expires_after="2024-08-04">
   <owner>ewannpv@chromium.org</owner>
   <owner>gambard@chromium.org</owner>
   <owner>bling-team@google.com</owner>
@@ -3648,7 +3648,7 @@
 </histogram>
 
 <histogram name="IOS.TabSwitcher.PinnedTabs.DragOrigin"
-    enum="IOSTabSwitcherDragOrigin" expires_after="2024-05-26">
+    enum="IOSTabSwitcherDragOrigin" expires_after="2024-08-04">
   <owner>ewannpv@chromium.org</owner>
   <owner>bling-team@google.com</owner>
   <summary>Records the origin of dropped items in the pinned tab view.</summary>
@@ -3786,7 +3786,7 @@
 </histogram>
 
 <histogram name="IOS.Variations.CreateTrials.SeedExpiry"
-    enum="VariationsSeedExpiry" expires_after="2024-06-02">
+    enum="VariationsSeedExpiry" expires_after="2024-08-04">
   <owner>ginnyhuang@chromium.org</owner>
   <owner>bling-get-set-up@google.com</owner>
   <summary>
@@ -3825,7 +3825,7 @@
 </histogram>
 
 <histogram name="IOS.Variations.FirstRun.SeedFetchTime" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>ginnyhuang@chromium.org</owner>
   <owner>bling-get-set-up@google.com</owner>
   <summary>
@@ -3935,7 +3935,7 @@
 </histogram>
 
 <histogram name="IOS.WidgetKit.Action" enum="IOSWidgetKitAction"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>rkgibson@google.com</owner>
   <owner>muradyan@google.com</owner>
   <summary>
@@ -3945,7 +3945,7 @@
 </histogram>
 
 <histogram name="IOS.WidgetKit.{Status}" enum="IOSWidgetKitExtensionKind"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>rkgibson@google.com</owner>
   <owner>muradyan@chromium.org</owner>
   <summary>
@@ -4017,7 +4017,7 @@
 </histogram>
 
 <histogram name="ManualFallback.PresentedOptions.AllPasswords"
-    units="Credentials" expires_after="2024-06-02">
+    units="Credentials" expires_after="2024-08-04">
   <owner>tmartino@chromium.org</owner>
   <owner>djean@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/login/histograms.xml b/tools/metrics/histograms/metadata/login/histograms.xml
index 1a99a79..1662f0a8 100644
--- a/tools/metrics/histograms/metadata/login/histograms.xml
+++ b/tools/metrics/histograms/metadata/login/histograms.xml
@@ -47,17 +47,6 @@
   </summary>
 </histogram>
 
-<histogram name="Login.ArcContinueBootImpulseTime3" units="ms"
-    expires_after="2024-03-17">
-  <owner>mhasank@google.com</owner>
-  <owner>arc-core@google.com</owner>
-  <summary>
-    Tracks the time to execute arc-boot-continue impulse. This is emitted when
-    we successfully upgrade the ARC container from mini to full. This metrics
-    increases the number of buckets to 50 and a maximum duration of 40 seconds.
-  </summary>
-</histogram>
-
 <histogram name="Login.BrowserShutdownTime" units="ms"
     expires_after="2024-07-21">
   <owner>xiyuan@chromium.org</owner>
@@ -287,7 +276,7 @@
 </histogram>
 
 <histogram name="Login.StateKeyGenerationStatus"
-    enum="LoginStateKeyGenerationStatus" expires_after="2024-06-01">
+    enum="LoginStateKeyGenerationStatus" expires_after="2024-08-04">
   <owner>sergiyb@chromium.org</owner>
   <owner>chromeos-commercial-remote-management@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml
index a12d9e7..b3324903 100644
--- a/tools/metrics/histograms/metadata/media/histograms.xml
+++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -1218,7 +1218,7 @@
 </histogram>
 
 <histogram name="Media.Audio.Render.SystemDelay" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>fhernqvist@google.com</owner>
   <owner>olka@chromium.org</owner>
   <owner>webrtc-audio-uma@google.com</owner>
@@ -1379,7 +1379,7 @@
 </histogram>
 
 <histogram name="Media.Audio.{Type}.SystemGlitchDuration" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>fhernqvist@google.com</owner>
   <owner>olka@chromium.org</owner>
   <owner>webrtc-audio-uma@google.com</owner>
@@ -4415,7 +4415,7 @@
 </histogram>
 
 <histogram name="Media.Notification.Count" units="count"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>yrw@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
@@ -4436,7 +4436,7 @@
 </histogram>
 
 <histogram name="Media.Notification.Source" enum="MediaNotificationSource"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>yrw@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
@@ -4447,7 +4447,7 @@
 </histogram>
 
 <histogram name="Media.Notification.UserAction" enum="MediaSessionAction"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>yrw@chromium.org</owner>
   <owner>media-dev-uma@chromium.org</owner>
   <summary>
@@ -5279,7 +5279,7 @@
 </histogram>
 
 <histogram name="Media.Ui.GetDisplayMedia.{Flow}.DialogDuration" units="ms"
-    expires_after="2024-05-29">
+    expires_after="2024-08-04">
   <owner>tovep@chromium.org</owner>
   <owner>eladalon@chromium.org</owner>
   <summary>
@@ -6025,7 +6025,7 @@
 </histogram>
 
 <histogram name="Media.VideoCaptureManager.DesktopCaptureImplementationAndType"
-    enum="DesktopCaptureImplementationAndType" expires_after="2024-06-02">
+    enum="DesktopCaptureImplementationAndType" expires_after="2024-08-04">
   <owner>handellm@chromium.org</owner>
   <owner>ccameron@chromium.org</owner>
   <summary>
@@ -6591,7 +6591,7 @@
 </histogram>
 
 <histogram name="MediaRouter.Cast.Channel.Error"
-    enum="MediaRouterCastChannelError" expires_after="2024-05-19">
+    enum="MediaRouterCastChannelError" expires_after="2024-08-04">
   <owner>mfoltz@chromium.org</owner>
   <owner>openscreen-eng@google.com</owner>
   <summary>
@@ -6656,7 +6656,7 @@
 </histogram>
 
 <histogram name="MediaRouter.Cast.Mdns.Channel.Open_Failure" units="ms"
-    expires_after="2024-04-28">
+    expires_after="2024-08-04">
   <owner>mfoltz@chromium.org</owner>
   <owner>openscreen-eng@google.com</owner>
   <summary>
@@ -6703,7 +6703,7 @@
 </histogram>
 
 <histogram name="MediaRouter.CastStreaming.Audio.PlaybackOnReceiver"
-    enum="Boolean" expires_after="2024-06-02">
+    enum="Boolean" expires_after="2024-08-04">
   <owner>takumif@chromium.org</owner>
   <owner>muyaoxu@google.com</owner>
   <owner>openscreen-eng@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/memory/histograms.xml b/tools/metrics/histograms/metadata/memory/histograms.xml
index fe0d1fe..ce77168 100644
--- a/tools/metrics/histograms/metadata/memory/histograms.xml
+++ b/tools/metrics/histograms/metadata/memory/histograms.xml
@@ -131,7 +131,7 @@
 </histogram>
 
 <histogram name="HeapProfiling.InProcess.Enabled{Process}"
-    enum="BooleanEnabled" expires_after="2024-06-05">
+    enum="BooleanEnabled" expires_after="2024-08-04">
   <owner>joenotcharles@google.com</owner>
   <owner>chrome-memory@google.com</owner>
   <summary>
@@ -142,7 +142,7 @@
 </histogram>
 
 <histogram name="HeapProfiling.InProcess.SamplesPerSnapshot{Process}"
-    units="samples" expires_after="2024-06-05">
+    units="samples" expires_after="2024-08-04">
   <owner>joenotcharles@google.com</owner>
   <owner>chrome-memory@google.com</owner>
   <summary>
@@ -154,7 +154,7 @@
 
 <histogram
     name="HeapProfiling.InProcess.SnapshotInterval.{Platform}.{RecordingTime}{Process}"
-    units="ms" expires_after="2024-06-05">
+    units="ms" expires_after="2024-08-04">
   <owner>joenotcharles@google.com</owner>
   <owner>chrome-memory@google.com</owner>
   <summary>
@@ -1422,7 +1422,7 @@
 </histogram>
 
 <histogram name="Memory.NetworkService.SharedMemoryFootprint" units="MiB"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>mmenke@chromium.org</owner>
   <owner>morlovich@chromium.org</owner>
   <owner>erikchen@chromium.org</owner>
@@ -1788,7 +1788,7 @@
 </histogram>
 
 <histogram name="Memory.Renderer.EvictedLockedResources.{Source}" units="KB"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>jonross@chromium.org</owner>
   <owner>chrome-gpu-memory@google.com</owner>
   <summary>
@@ -2367,7 +2367,7 @@
 </histogram>
 
 <histogram name="Memory.VmmSwap.TotalBytesWrittenInAWeek" units="MiB"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>kawasin@google.com</owner>
   <owner>sstan@google.com</owner>
   <summary>
@@ -2378,7 +2378,7 @@
 </histogram>
 
 <histogram name="Memory.VmmSwap.{VmName}.ActiveAfterEnableDuration"
-    units="Hours" expires_after="2024-06-02">
+    units="Hours" expires_after="2024-08-04">
   <owner>kawasin@google.com</owner>
   <owner>sstan@google.com</owner>
   <summary>
@@ -2392,7 +2392,7 @@
 </histogram>
 
 <histogram name="Memory.VmmSwap.{VmName}.AvgPagesInFile" units="Pages"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>kawasin@google.com</owner>
   <owner>sstan@google.com</owner>
   <summary>
@@ -2405,7 +2405,7 @@
 </histogram>
 
 <histogram name="Memory.VmmSwap.{VmName}.DisableReason"
-    enum="VmmSwapDisableReason" expires_after="2024-06-02">
+    enum="VmmSwapDisableReason" expires_after="2024-08-04">
   <owner>kawasin@google.com</owner>
   <owner>sstan@google.com</owner>
   <summary>
@@ -2431,7 +2431,7 @@
 </histogram>
 
 <histogram name="Memory.VmmSwap.{VmName}.InactiveNoEnableDuration"
-    units="Hours" expires_after="2024-06-02">
+    units="Hours" expires_after="2024-08-04">
   <owner>kawasin@google.com</owner>
   <owner>sstan@google.com</owner>
   <summary>
@@ -2444,7 +2444,7 @@
 </histogram>
 
 <histogram name="Memory.VmmSwap.{VmName}.MinPagesInFile" units="Pages"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>kawasin@google.com</owner>
   <owner>sstan@google.com</owner>
   <summary>
@@ -2457,7 +2457,7 @@
 </histogram>
 
 <histogram name="Memory.VmmSwap.{VmName}.PageAverageDurationInFile"
-    units="Seconds" expires_after="2024-06-02">
+    units="Seconds" expires_after="2024-08-04">
   <owner>kawasin@google.com</owner>
   <owner>sstan@google.com</owner>
   <summary>
@@ -2471,7 +2471,7 @@
 </histogram>
 
 <histogram name="Memory.VmmSwap.{VmName}.PolicyResult"
-    enum="VmmSwapPolicyResult" expires_after="2024-06-02">
+    enum="VmmSwapPolicyResult" expires_after="2024-08-04">
   <owner>kawasin@google.com</owner>
   <owner>sstan@google.com</owner>
   <summary>
@@ -2484,7 +2484,7 @@
 </histogram>
 
 <histogram name="Memory.VmmSwap.{VmName}.State" enum="VmmSwapState"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>kawasin@google.com</owner>
   <owner>sstan@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/mobile/histograms.xml b/tools/metrics/histograms/metadata/mobile/histograms.xml
index 36b805d..f69af72 100644
--- a/tools/metrics/histograms/metadata/mobile/histograms.xml
+++ b/tools/metrics/histograms/metadata/mobile/histograms.xml
@@ -134,7 +134,7 @@
 </histogram>
 
 <histogram name="Mobile.ContextMenu.LensWebImageProcessTime" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>hujasonx@google.com</owner>
   <owner>lens-in-bling-team@google.com</owner>
   <summary>
@@ -165,7 +165,7 @@
 </histogram>
 
 <histogram name="Mobile.ContextMenu.{EntryPoint}.Actions" enum="IOSMenuAction"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>gambard@chromium.org</owner>
   <owner>bling-team@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml
index b2d3c55..61de702 100644
--- a/tools/metrics/histograms/metadata/navigation/histograms.xml
+++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -935,7 +935,7 @@
 
 <histogram
     name="Navigation.MainFrame.NewNavigation.IgnoreRestore.IsHTTPOrHTTPS.{DurationFromTo}.Time"
-    units="ms" expires_after="2024-04-20">
+    units="ms" expires_after="2024-08-04">
   <owner>chikamune@chromium.org</owner>
   <owner>yyanagisawa@chromium.org</owner>
   <owner>kouhei@chromium.org</owner>
@@ -1577,7 +1577,7 @@
 </histogram>
 
 <histogram name="NavigationSuggestion.Event2" enum="NavigationSuggestionEvent"
-    expires_after="2024-06-04">
+    expires_after="2024-08-04">
   <owner>meacer@chromium.org</owner>
   <owner>security-enamel@chromium.org</owner>
   <summary>
@@ -1706,7 +1706,7 @@
 </histogram>
 
 <histogram name="Prerender.Experimental.ActivationIPCDelay" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>lingqi@chromium.org</owner>
   <owner>chrome-prerendering@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml
index 5e52e4c..bec4441 100644
--- a/tools/metrics/histograms/metadata/net/histograms.xml
+++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -848,7 +848,7 @@
 </histogram>
 
 <histogram name="Net.CountOfRecentlyBrokenAlternativeServices" units="services"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -1216,7 +1216,7 @@
 </histogram>
 
 <histogram name="Net.DNS.HTTPSSVC.RecordHttps.{secure}.ExpectNoerror.DnsRcode"
-    enum="HttpssvcDnsRcode" expires_after="2024-06-01">
+    enum="HttpssvcDnsRcode" expires_after="2024-08-04">
   <owner>horo@chromium.org</owner>
   <owner>davidben@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
@@ -1230,7 +1230,7 @@
 </histogram>
 
 <histogram name="Net.DNS.HTTPSSVC.RecordHttps.{secure}.ExpectNoerror.Parsable"
-    enum="BooleanValid" expires_after="2024-06-01">
+    enum="BooleanValid" expires_after="2024-08-04">
   <owner>horo@chromium.org</owner>
   <owner>davidben@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
@@ -1271,7 +1271,7 @@
 
 <histogram
     name="Net.DNS.HTTPSSVC.RecordHttps.{secure}.ExpectNoerror.ResolveTimeExperimental"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>horo@chromium.org</owner>
   <owner>davidben@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
@@ -1284,7 +1284,7 @@
 
 <histogram
     name="Net.DNS.HTTPSSVC.RecordHttps.{secure}.ExpectNoerror.ResolveTimeRatio"
-    units="scaled ratio (% / 10)" expires_after="2024-06-01">
+    units="scaled ratio (% / 10)" expires_after="2024-08-04">
   <owner>horo@chromium.org</owner>
   <owner>davidben@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
@@ -1725,7 +1725,7 @@
 </histogram>
 
 <histogram name="Net.Fetch.CheckPoint.FetchManagerLoader"
-    enum="FetchManagerLoaderCheckPoint" expires_after="2024-06-01">
+    enum="FetchManagerLoaderCheckPoint" expires_after="2024-08-04">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
@@ -2010,7 +2010,7 @@
 </histogram>
 
 <histogram name="Net.HttpJob.ProxyTypeFailed" enum="ProxyScheme"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>rch@chromium.org</owner>
   <owner>djmitche@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
@@ -2024,7 +2024,7 @@
 </histogram>
 
 <histogram name="Net.HttpJob.ProxyTypeSuccess" enum="ProxyScheme"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>rch@chromium.org</owner>
   <owner>djmitche@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
@@ -2352,7 +2352,7 @@
 </histogram>
 
 <histogram name="Net.QuicConnection.ServerAllowsActiveMigrationForMultiPort"
-    enum="BooleanEnabled" expires_after="2024-06-02">
+    enum="BooleanEnabled" expires_after="2024-08-04">
   <owner>renjietang@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -2757,7 +2757,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.AbortedPendingStreamRequests"
-    units="stream requests" expires_after="2024-06-02">
+    units="stream requests" expires_after="2024-08-04">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3028,7 +3028,7 @@
 
 <histogram
     name="Net.QuicSession.ConnectionCloseErrorCodeServerIetfApplication{GQuicMissing}{ServerType}{HandshakeType}"
-    enum="QuicHttp3ErrorCodes" expires_after="2024-06-02">
+    enum="QuicHttp3ErrorCodes" expires_after="2024-08-04">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3061,7 +3061,7 @@
 
 <histogram
     name="Net.QuicSession.ConnectionCloseErrorCodeServerIetfTransport{GQuicMissing}{ServerType}{HandshakeType}"
-    enum="QuicTransportErrorCodes" expires_after="2024-06-02">
+    enum="QuicTransportErrorCodes" expires_after="2024-08-04">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3097,7 +3097,7 @@
 
 <histogram
     name="Net.QuicSession.ConnectionCloseErrorCode{Closer}{ServerType}{HandshakeType}"
-    enum="QuicErrorCodes" expires_after="2024-06-02">
+    enum="QuicErrorCodes" expires_after="2024-08-04">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3328,7 +3328,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.HandshakeConfirmedTime.ECH"
-    units="Milliseconds" expires_after="2024-06-02">
+    units="Milliseconds" expires_after="2024-08-04">
   <owner>davidben@chromium.org</owner>
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
@@ -3630,7 +3630,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.NumMigrations" units="units"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>renjietang@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>The number of successful migrations for a QUIC session.</summary>
@@ -3656,7 +3656,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.NumPendingStreamRequests"
-    units="stream requests" expires_after="2024-06-02">
+    units="stream requests" expires_after="2024-08-04">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3676,7 +3676,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.NumStreamsWaitingToWriteOnIdleTimeout"
-    units="streams" expires_after="2024-06-02">
+    units="streams" expires_after="2024-08-04">
   <owner>renjietang@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -3686,7 +3686,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.NumTotalStreams" units="units"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -4063,7 +4063,7 @@
 </histogram>
 
 <histogram name="Net.QuicSession.SendPacketSize" units="bytes"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -4463,7 +4463,7 @@
 </histogram>
 
 <histogram name="Net.QuicStreamFactory.ConnectionOnNonDefaultNetwork"
-    enum="BooleanSuccess" expires_after="2024-06-02">
+    enum="BooleanSuccess" expires_after="2024-08-04">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/quic/OWNERS</owner>
   <summary>
@@ -5167,7 +5167,7 @@
 </histogram>
 
 <histogram name="Net.SpdySession.RstStreamReceived" enum="Http2WireErrorCodes"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>bashi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -5222,7 +5222,7 @@
 </histogram>
 
 <histogram name="Net.SpdyStreamsAbandonedPerSession" units="units"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>
@@ -5231,7 +5231,7 @@
 </histogram>
 
 <histogram name="Net.SpdyStreamsPerSession" units="units"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>dschinazi@chromium.org</owner>
   <owner>src/net/OWNERS</owner>
   <summary>The number of streams issued over a single session.</summary>
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml
index 62f4d8fe..ffb6859 100644
--- a/tools/metrics/histograms/metadata/network/histograms.xml
+++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -77,7 +77,7 @@
 
 <histogram
     name="Network.Ash.Cellular.AllowTextMessages.Policy.SuppressionState"
-    enum="PolicyTextMessageSuppressionState" expires_after="2024-06-01">
+    enum="PolicyTextMessageSuppressionState" expires_after="2024-08-04">
   <owner>gordonseto@google.com</owner>
   <owner>cros-connectivity@google.com</owner>
   <summary>
@@ -88,7 +88,7 @@
 
 <histogram
     name="Network.Ash.Cellular.AllowTextMessages.TextMessageNotificationSuppressionState"
-    enum="NotificationSuppressionState" expires_after="2024-06-01">
+    enum="NotificationSuppressionState" expires_after="2024-08-04">
   <owner>gordonseto@google.com</owner>
   <owner>cros-connectivity@google.com</owner>
   <summary>
@@ -471,7 +471,7 @@
 </histogram>
 
 <histogram name="Network.Ash.Hotspot.Upstream.Cellular.Capability.AllowStatus"
-    enum="HotspotAllowStatus" expires_after="2024-04-01">
+    enum="HotspotAllowStatus" expires_after="2024-08-04">
   <owner>jiajunz@google.com</owner>
   <owner>cros-connectivity@google.com</owner>
   <summary>
@@ -484,7 +484,7 @@
 
 <histogram
     name="Network.Ash.Hotspot.Upstream.Cellular.Capability.AllowStatusAtLogin"
-    enum="HotspotAllowStatus" expires_after="2024-04-01">
+    enum="HotspotAllowStatus" expires_after="2024-08-04">
   <owner>jiajunz@google.com</owner>
   <owner>cros-connectivity@google.com</owner>
   <summary>
@@ -497,7 +497,7 @@
 
 <histogram
     name="Network.Ash.Hotspot.Upstream.Cellular.CheckReadiness.OperationResult"
-    enum="HotspotCheckReadinessResult" expires_after="2024-04-01">
+    enum="HotspotCheckReadinessResult" expires_after="2024-08-04">
   <owner>jiajunz@google.com</owner>
   <owner>cros-connectivity@google.com</owner>
   <summary>
@@ -508,7 +508,7 @@
 </histogram>
 
 <histogram name="Network.Ash.Hotspot.Upstream.Cellular.Disabled.Reason"
-    enum="HotspotDisableReason" expires_after="2024-06-02">
+    enum="HotspotDisableReason" expires_after="2024-08-04">
   <owner>jiajunz@google.com</owner>
   <owner>cros-connectivity@google.com</owner>
   <summary>
@@ -605,7 +605,7 @@
 
 <histogram
     name="Network.Ash.Hotspot.Upstream.Cellular.{Operation}.OperationResult"
-    enum="HotspotSetEnabledResult" expires_after="2024-06-02">
+    enum="HotspotSetEnabledResult" expires_after="2024-08-04">
   <owner>jiajunz@google.com</owner>
   <owner>cros-connectivity@google.com</owner>
   <summary>
@@ -1903,7 +1903,7 @@
 </histogram>
 
 <histogram name="Network.Ethernet.Policy.OncRecommendedFieldsWorkaroundAction"
-    enum="OncRecommendedFieldsWorkaroundAction" expires_after="2024-06-02">
+    enum="OncRecommendedFieldsWorkaroundAction" expires_after="2024-08-04">
   <owner>pmarko@google.com</owner>
   <owner>suprnet@google.com</owner>
   <summary>
@@ -1916,7 +1916,7 @@
 </histogram>
 
 <histogram name="Network.Mdns.{ServiceType}" enum="MdnsQueryType"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>nmuggli@google.com</owner>
   <owner>project-bolton@google.com</owner>
   <summary>
@@ -4227,7 +4227,7 @@
 </histogram>
 
 <histogram name="Network.Wifi.Synced.Connection.Result" enum="BooleanSuccess"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>jonmann@chromium.org</owner>
   <owner>crisrael@google.com</owner>
   <owner>chromeos-cross-device-eng@google.com</owner>
@@ -4297,7 +4297,7 @@
 
 <histogram
     name="Network.Wifi.Synced.UpdateOperation.GenerateLocalNetworkConfig.Result"
-    enum="BooleanSuccess" expires_after="2024-06-01">
+    enum="BooleanSuccess" expires_after="2024-08-04">
   <owner>jonmann@chromium.org</owner>
   <owner>crisrael@google.com</owner>
   <owner>chromeos-cross-device-eng@google.com</owner>
@@ -4606,7 +4606,7 @@
 </histogram>
 
 <histogram name="NetworkService.NetworkLoaderCompletionTime.{Source}"
-    units="ms" expires_after="2024-05-30">
+    units="ms" expires_after="2024-08-04">
   <owner>bashi@chromium.org</owner>
   <owner>blink-network-stack@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
index 4e51a44..5ae0e41 100644
--- a/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
+++ b/tools/metrics/histograms/metadata/new_tab_page/histograms.xml
@@ -35,7 +35,7 @@
 </histogram>
 
 <histogram name="NewTabPage.ActioniOS" enum="NewTabPageActioniOS"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>justincohen@chromium.org</owner>
   <owner>gambard@chromium.org</owner>
   <summary>
@@ -101,7 +101,7 @@
 </histogram>
 
 <histogram name="NewTabPage.BackgroundService.Images.Headers.ErrorDetected"
-    enum="NTPImageType" expires_after="2024-05-05">
+    enum="NTPImageType" expires_after="2024-08-04">
   <owner>pauladedeji@google.com</owner>
   <owner>danpeng@google.com</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1092,7 +1092,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Modules.Disabled{Interaction}" enum="NtpModules"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>romanarora@chromium.org</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1145,7 +1145,7 @@
 </histogram>
 
 <histogram name="NewTabPage.Modules.Enabled{Interaction}" enum="NtpModules"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>romanarora@chromium.org</owner>
   <owner>tiborg@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1452,7 +1452,7 @@
 </histogram>
 
 <histogram name="NewTabPage.NumberOfTiles" units="units"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>tiborg@chromium.org</owner>
   <owner>romanarora@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1469,7 +1469,7 @@
 </histogram>
 
 <histogram name="NewTabPage.OneGoogleBar.RequestLatency" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>tiborg@chromium.org</owner>
   <owner>romanarora@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1480,7 +1480,7 @@
 </histogram>
 
 <histogram name="NewTabPage.OneGoogleBar.ShownTime" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>tiborg@chromium.org</owner>
   <owner>romanarora@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1840,7 +1840,7 @@
 </histogram>
 
 <histogram name="NewTabPage.TimeSinceLastNTP" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>tiborg@chromium.org</owner>
   <owner>yyushkina@chromium.org</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1929,7 +1929,7 @@
 </histogram>
 
 <histogram name="NewTabPage.WallpaperSearch.GetResultProcessingLatency"
-    units="ms" expires_after="2024-04-28">
+    units="ms" expires_after="2024-08-04">
   <owner>tiborg@chromium.org</owner>
   <owner>rtatum@google.com</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1970,7 +1970,7 @@
 </histogram>
 
 <histogram name="NewTabPage.WallpaperSearch.SetResultThemeProcessingLatency"
-    units="ms" expires_after="2024-04-28">
+    units="ms" expires_after="2024-08-04">
   <owner>tiborg@chromium.org</owner>
   <owner>rtatum@google.com</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
@@ -1983,7 +1983,7 @@
 </histogram>
 
 <histogram name="NewTabPage.WallpaperSearch.Status"
-    enum="NtpWallpaperSearchStatus" expires_after="2024-04-28">
+    enum="NtpWallpaperSearchStatus" expires_after="2024-08-04">
   <owner>tiborg@chromium.org</owner>
   <owner>rtatum@google.com</owner>
   <owner>chrome-desktop-ntp@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/notifications/histograms.xml b/tools/metrics/histograms/metadata/notifications/histograms.xml
index 2ed7e38..1a23b76e 100644
--- a/tools/metrics/histograms/metadata/notifications/histograms.xml
+++ b/tools/metrics/histograms/metadata/notifications/histograms.xml
@@ -720,7 +720,7 @@
 </histogram>
 
 <histogram name="Notifications.PersistentNotificationThirdPartyCount"
-    enum="Boolean" expires_after="2024-05-19">
+    enum="Boolean" expires_after="2024-08-04">
   <owner>awillia@chromium.org</owner>
   <owner>peter@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/omnibox/histograms.xml b/tools/metrics/histograms/metadata/omnibox/histograms.xml
index 8041664..81df45d 100644
--- a/tools/metrics/histograms/metadata/omnibox/histograms.xml
+++ b/tools/metrics/histograms/metadata/omnibox/histograms.xml
@@ -1218,7 +1218,7 @@
 </histogram>
 
 <histogram name="Omnibox.NumberOfVisibleCharacters" units="characters"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>peilinwang@google.com</owner>
   <owner>woa-performance-bugs+jank@google.com</owner>
   <summary>
@@ -1472,7 +1472,7 @@
 </histogram>
 
 <histogram name="Omnibox.Search.CtrlEnter.ResolvedAsUrl" enum="Boolean"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>ender@google.com</owner>
   <owner>chrome-search@google.com</owner>
   <summary>
@@ -1486,7 +1486,7 @@
 </histogram>
 
 <histogram name="Omnibox.Search.CtrlEnter.Used" enum="BooleanUsage"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>ender@google.com</owner>
   <owner>chrome-search@google.com</owner>
   <summary>
@@ -1614,7 +1614,7 @@
 </histogram>
 
 <histogram name="Omnibox.SetText.Duration" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>peilinwang@google.com</owner>
   <owner>woa-performance-bugs+jank@google.com</owner>
   <summary>
@@ -1624,7 +1624,7 @@
 </histogram>
 
 <histogram name="Omnibox.SetText.TextLength" units="characters"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>peilinwang@google.com</owner>
   <owner>woa-performance-bugs+jank@google.com</owner>
   <summary>
@@ -1634,7 +1634,7 @@
 </histogram>
 
 <histogram name="Omnibox.setText.TruncatedTooMuch" enum="Boolean"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>peilinwang@google.com</owner>
   <owner>woa-performance-bugs+jank@google.com</owner>
   <summary>
@@ -2225,7 +2225,7 @@
 </histogram>
 
 <histogram name="Omnibox.SuggestTiles.SelectedTileIndex" units="position"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>ender@google.com</owner>
   <owner>mahmadi@chromium.org</owner>
   <summary>
@@ -2256,7 +2256,7 @@
 </histogram>
 
 <histogram name="Omnibox.SuggestTiles.TileTypeCount.{SuggestTileType}"
-    units="count" expires_after="2024-06-01">
+    units="count" expires_after="2024-08-04">
   <owner>ender@google.com</owner>
   <owner>mahmadi@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/oobe/histograms.xml b/tools/metrics/histograms/metadata/oobe/histograms.xml
index 1cfc1cb..3d7f5a66 100644
--- a/tools/metrics/histograms/metadata/oobe/histograms.xml
+++ b/tools/metrics/histograms/metadata/oobe/histograms.xml
@@ -939,7 +939,7 @@
 </histogram>
 
 <histogram name="OOBE.StepShownStatus2.{OOBEOnlyScreenName}"
-    enum="BooleanShown" expires_after="2024-06-02">
+    enum="BooleanShown" expires_after="2024-08-04">
   <owner>osamafathy@google.com</owner>
   <owner>cros-oobe@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index 43c74b92..a69e850 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -178,7 +178,7 @@
 </histogram>
 
 <histogram name="AccessCodeCast.Discovery.CastModeOnSuccess"
-    enum="AccessCodeCastCastMode" expires_after="2024-06-02">
+    enum="AccessCodeCastCastMode" expires_after="2024-08-04">
   <owner>bzielinski@google.com</owner>
   <owner>cros-edu-eng@google.com</owner>
   <summary>
@@ -316,7 +316,7 @@
 </histogram>
 
 <histogram name="AccessCodeCast.Ui.DialogCloseReason"
-    enum="AccessCodeCastDialogCloseReason" expires_after="2024-06-02">
+    enum="AccessCodeCastDialogCloseReason" expires_after="2024-08-04">
   <owner>bzielinski@google.com</owner>
   <owner>cros-edu-eng@google.com</owner>
   <summary>
@@ -326,7 +326,7 @@
 </histogram>
 
 <histogram name="AccessCodeCast.Ui.DialogLoadTime" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>bzielinski@google.com</owner>
   <owner>cros-edu-eng@google.com</owner>
   <summary>
@@ -1287,7 +1287,7 @@
 </histogram>
 
 <histogram name="Ads.InterestGroup.ServerAuction.EndToEndTime" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>behamilton@google.com</owner>
   <owner>pauljensen@chromium.org</owner>
   <owner>privacy-sandbox-dev@chromium.org</owner>
@@ -1325,7 +1325,7 @@
 </histogram>
 
 <histogram name="Ads.InterestGroup.ServerAuction.InvalidServerResponseReason"
-    enum="AuctionInvalidServerResponseReason" expires_after="M125">
+    enum="AuctionInvalidServerResponseReason" expires_after="2024-08-04">
   <owner>behamilton@google.com</owner>
   <owner>privacy-sandbox-dev@chromium.org</owner>
   <summary>
@@ -2869,7 +2869,7 @@
 </histogram>
 
 <histogram name="Conversions.AggregatableReport.NumContributionsPerReport2"
-    units="contribution" expires_after="2024-06-02">
+    units="contribution" expires_after="2024-08-04">
   <owner>linnan@chromium.org</owner>
   <owner>johnidel@chromium.org</owner>
   <owner>measurement-api-dev+metrics@google.com</owner>
@@ -3138,7 +3138,7 @@
 </histogram>
 
 <histogram name="Conversions.DebugReport.ReportRetrySucceedAggregatable"
-    enum="BooleanSuccess" expires_after="2024-06-02">
+    enum="BooleanSuccess" expires_after="2024-08-04">
   <owner>anthonygarant@chromium.org</owner>
   <owner>johnidel@chromium.org</owner>
   <owner>measurement-api-dev+metrics@google.com</owner>
@@ -3150,7 +3150,7 @@
 </histogram>
 
 <histogram name="Conversions.DebugReport.ReportRetrySucceedEventLevel"
-    enum="BooleanSuccess" expires_after="2024-06-02">
+    enum="BooleanSuccess" expires_after="2024-08-04">
   <owner>anthonygarant@chromium.org</owner>
   <owner>johnidel@chromium.org</owner>
   <owner>measurement-api-dev+metrics@google.com</owner>
@@ -3520,7 +3520,7 @@
 </histogram>
 
 <histogram name="Conversions.ReportRetrySucceedAggregatable"
-    enum="BooleanSuccess" expires_after="2024-06-02">
+    enum="BooleanSuccess" expires_after="2024-08-04">
   <owner>anthonygarant@chromium.org</owner>
   <owner>johnidel@chromium.org</owner>
   <owner>measurement-api-dev+metrics@google.com</owner>
@@ -3676,7 +3676,7 @@
 </histogram>
 
 <histogram name="Conversions.RequestSupportHeader"
-    enum="ConversionRequestSupportHeader" expires_after="2024-05-05">
+    enum="ConversionRequestSupportHeader" expires_after="2024-08-04">
   <owner>tquintanilla@chromium.org</owner>
   <owner>johnidel@chromium.org</owner>
   <owner>measurement-api-dev+metrics@google.com</owner>
@@ -3823,7 +3823,7 @@
 </histogram>
 
 <histogram name="Conversions.Storage.Sql.FileSizeSourcesPerOriginLimitReached2"
-    units="KB" expires_after="2024-06-02">
+    units="KB" expires_after="2024-08-04">
   <owner>tquintanilla@chromium.org</owner>
   <owner>johnidel@chromium.org</owner>
   <owner>measurement-api-dev+metrics@google.com</owner>
@@ -3836,7 +3836,7 @@
 
 <histogram
     name="Conversions.Storage.Sql.FileSizeSourcesPerOriginLimitReached2.PerSource"
-    units="bytes" expires_after="2024-06-02">
+    units="bytes" expires_after="2024-08-04">
   <owner>anthonygarant@chromium.org</owner>
   <owner>johnidel@chromium.org</owner>
   <owner>measurement-api-dev+metrics@google.com</owner>
@@ -3848,7 +3848,7 @@
 </histogram>
 
 <histogram name="Conversions.Storage.Sql.InitStatus2"
-    enum="ConversionStorageSqlInitStatus" expires_after="2024-06-02">
+    enum="ConversionStorageSqlInitStatus" expires_after="2024-08-04">
   <owner>johnidel@chromium.org</owner>
   <owner>csharrison@chromium.org</owner>
   <summary>
@@ -3943,7 +3943,7 @@
 </histogram>
 
 <histogram name="Conversions.{ReportType}.ReportRetriesTillSuccessOrFailure"
-    enum="ConversionReportSendRetryCount" expires_after="2024-06-02">
+    enum="ConversionReportSendRetryCount" expires_after="2024-08-04">
   <owner>tquintanilla@chromium.org</owner>
   <owner>johnidel@chromium.org</owner>
   <owner>measurement-api-dev+metrics@google.com</owner>
@@ -4328,7 +4328,7 @@
 </histogram>
 
 <histogram name="DemoMode.IdleLogoutWarningEvent"
-    enum="DemoModeIdleLogoutWarningEvent" expires_after="2024-05-24">
+    enum="DemoModeIdleLogoutWarningEvent" expires_after="2024-08-04">
   <owner>llin@chromium.org</owner>
   <owner>xiqiruan@chromium.org</owner>
   <owner>yilkal@chromium.org</owner>
@@ -4452,7 +4452,7 @@
 </histogram>
 
 <histogram name="DemoMode.UserClicksAndPresses" units="clicks"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>llin@chromium.org</owner>
   <owner>xiqiruan@chromium.org</owner>
   <owner>yilkal@chromium.org</owner>
@@ -5809,7 +5809,7 @@
 </histogram>
 
 <histogram name="FirstRun.LaunchSource" enum="FirstRunLaunchSource"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>jlebel@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
   <summary>
@@ -5900,7 +5900,7 @@
 </histogram>
 
 <histogram name="FirstRun.Sentinel.Created" enum="FirstRunSentinelResult"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>jlebel@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
   <summary>
@@ -5930,7 +5930,7 @@
 </histogram>
 
 <histogram name="FirstRun.Stage" enum="FirstRunStageResult"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>tinazwang@chromium.org</owner>
   <owner>bling-get-started@google.com</owner>
   <summary>
@@ -7576,7 +7576,7 @@
 </histogram>
 
 <histogram name="OSCrypt.AppBoundEncryption.Decrypt.ResultCode" enum="Hresult"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>wfh@chromium.org</owner>
   <owner>nparker@chromium.org</owner>
   <summary>
@@ -7587,7 +7587,7 @@
 </histogram>
 
 <histogram name="OSCrypt.AppBoundEncryption.Decrypt.ResultLastError"
-    enum="WinGetLastError" expires_after="2024-06-02">
+    enum="WinGetLastError" expires_after="2024-08-04">
   <owner>wfh@chromium.org</owner>
   <owner>nparker@chromium.org</owner>
   <summary>
@@ -7598,7 +7598,7 @@
 </histogram>
 
 <histogram name="OSCrypt.AppBoundEncryption.Decrypt.Time" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>wfh@chromium.org</owner>
   <owner>nparker@chromium.org</owner>
   <summary>
@@ -7609,7 +7609,7 @@
 </histogram>
 
 <histogram name="OSCrypt.AppBoundEncryption.Encrypt.ResultCode" enum="Hresult"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>wfh@chromium.org</owner>
   <owner>nparker@chromium.org</owner>
   <summary>
@@ -7621,7 +7621,7 @@
 </histogram>
 
 <histogram name="OSCrypt.AppBoundEncryption.Encrypt.ResultLastError"
-    enum="WinGetLastError" expires_after="2024-06-02">
+    enum="WinGetLastError" expires_after="2024-08-04">
   <owner>wfh@chromium.org</owner>
   <owner>nparker@chromium.org</owner>
   <summary>
@@ -7634,7 +7634,7 @@
 </histogram>
 
 <histogram name="OSCrypt.AppBoundEncryption.Encrypt.Time" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>wfh@chromium.org</owner>
   <owner>nparker@chromium.org</owner>
   <summary>
@@ -7814,7 +7814,7 @@
 </histogram>
 
 <histogram name="Ozone.TouchEventConverterEvdev.PalmTouchCount"
-    enum="BooleanDetected" expires_after="2024-06-01">
+    enum="BooleanDetected" expires_after="2024-08-04">
   <owner>jiwan@chromium.org</owner>
   <owner>robsc@chromium.org</owner>
   <summary>
@@ -7825,7 +7825,7 @@
 </histogram>
 
 <histogram name="Ozone.TouchEventConverterEvdev.RepeatedTouchCount"
-    enum="BooleanDetected" expires_after="2024-06-01">
+    enum="BooleanDetected" expires_after="2024-08-04">
   <owner>jiwan@chromium.org</owner>
   <owner>robsc@chromium.org</owner>
   <summary>
@@ -7837,7 +7837,7 @@
 </histogram>
 
 <histogram name="Ozone.TouchEventConverterEvdev.StylusSessionCount"
-    enum="BooleanDetected" expires_after="2024-06-01">
+    enum="BooleanDetected" expires_after="2024-08-04">
   <owner>jiwan@chromium.org</owner>
   <owner>robsc@chromium.org</owner>
   <summary>
@@ -7848,7 +7848,7 @@
 </histogram>
 
 <histogram name="Ozone.TouchEventConverterEvdev.StylusSessionLength"
-    units="duration" expires_after="2024-06-01">
+    units="duration" expires_after="2024-08-04">
   <owner>jiwan@chromium.org</owner>
   <owner>robsc@chromium.org</owner>
   <summary>
@@ -7895,7 +7895,7 @@
 </histogram>
 
 <histogram name="Ozone.TouchEventConverterEvdev.TouchSessionLength"
-    units="duration" expires_after="2024-06-01">
+    units="duration" expires_after="2024-08-04">
   <owner>jiwan@chromium.org</owner>
   <owner>robsc@chromium.org</owner>
   <summary>
@@ -7917,7 +7917,7 @@
 </histogram>
 
 <histogram name="Ozone.TouchEventConverterEvdev.TouchTypeBeforeStylus"
-    enum="TouchType" expires_after="2024-06-01">
+    enum="TouchType" expires_after="2024-08-04">
   <owner>jiwan@chromium.org</owner>
   <owner>robsc@chromium.org</owner>
   <summary>
@@ -9734,7 +9734,7 @@
 </histogram>
 
 <histogram name="SiteIsolatedCodeCache.WASM.Behaviour"
-    enum="SiteIsolatedCodeCacheWASMBehaviour" expires_after="2024-06-02">
+    enum="SiteIsolatedCodeCacheWASMBehaviour" expires_after="2024-08-04">
   <owner>awillia@chromium.org</owner>
   <owner>loading-dev@chromium.org</owner>
   <summary>
@@ -9860,7 +9860,7 @@
 </histogram>
 
 <histogram name="SpellCheck.CheckedWordsPerHour" units="words"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>basiaz@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -9870,7 +9870,7 @@
 </histogram>
 
 <histogram name="SpellCheck.Enabled2" enum="BooleanEnabled"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>basiaz@google.com</owner>
   <owner>chrome-language@google.com</owner>
   <summary>
@@ -10061,7 +10061,7 @@
 </histogram>
 
 <histogram name="SSORecallPromo.AccountsAvailable" units="units"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>jlebel@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
   <summary>
@@ -10080,7 +10080,7 @@
 </histogram>
 
 <histogram name="SSORecallPromo.PromoSeenCount" units="units"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>jlebel@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
   <summary>
@@ -11400,7 +11400,7 @@
 </histogram>
 
 <histogram name="WebDatabase.AutofillWebDataBackendImpl.OperationResult"
-    enum="AutofillWebDataBackendImplOperationResult" expires_after="2024-06-02">
+    enum="AutofillWebDataBackendImplOperationResult" expires_after="2024-08-04">
   <owner>battre@chromium.org</owner>
   <owner>asully@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/page/histograms.xml b/tools/metrics/histograms/metadata/page/histograms.xml
index 7d2a209..5257155 100644
--- a/tools/metrics/histograms/metadata/page/histograms.xml
+++ b/tools/metrics/histograms/metadata/page/histograms.xml
@@ -946,7 +946,7 @@
 </histogram>
 
 <histogram name="PageLoad.Clients.LCPP.PaintTiming.ActualLCPIndex"
-    units="Index(1 origin)" expires_after="2024-06-02">
+    units="Index(1 origin)" expires_after="2024-08-04">
   <owner>yoichio@chromium.org</owner>
   <owner>
     src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS
@@ -963,7 +963,7 @@
 
 <histogram
     name="PageLoad.Clients.LCPP.PaintTiming.NavigationToFirstContentfulPaint"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>kouhei@chromium.org</owner>
   <owner>
     src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS
@@ -977,7 +977,7 @@
 
 <histogram
     name="PageLoad.Clients.LCPP.PaintTiming.NavigationToLargestContentfulPaint"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>kouhei@chromium.org</owner>
   <owner>
     src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS
@@ -990,7 +990,7 @@
 </histogram>
 
 <histogram name="PageLoad.Clients.LCPP.PaintTiming.PredictHitIndex"
-    units="Index(1 origin)" expires_after="2024-06-02">
+    units="Index(1 origin)" expires_after="2024-08-04">
   <owner>yoichio@chromium.org</owner>
   <owner>
     src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS
@@ -1005,7 +1005,7 @@
 </histogram>
 
 <histogram name="PageLoad.Clients.LCPP.PaintTiming.PredictLCPResult"
-    enum="LcppPredictResult" expires_after="2024-06-02">
+    enum="LcppPredictResult" expires_after="2024-08-04">
   <owner>yoichio@chromium.org</owner>
   <owner>
     src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS
@@ -1278,7 +1278,7 @@
 
 <histogram
     name="PageLoad.Clients.ServiceWorker2.PaintTiming.{Timing}.{HandlerType}"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -1905,7 +1905,7 @@
 
 <histogram
     name="PageLoad.Experimental.NavigationTiming.NavigationStartToFirstLoaderCallback"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>nhiroki@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/password/histograms.xml b/tools/metrics/histograms/metadata/password/histograms.xml
index 2c9d0d43..28bd5bc4 100644
--- a/tools/metrics/histograms/metadata/password/histograms.xml
+++ b/tools/metrics/histograms/metadata/password/histograms.xml
@@ -313,7 +313,7 @@
 
 <histogram
     name="PasswordGeneration.EditsInGeneratedPassword.AlteredLengthIncreased"
-    enum="GeneratedPasswordAlteredLengthIncreased" expires_after="2024-05-26">
+    enum="GeneratedPasswordAlteredLengthIncreased" expires_after="2024-08-04">
   <owner>kazinova@google.com</owner>
   <owner>shaikhitdin@google.com</owner>
   <summary>
@@ -646,7 +646,7 @@
 </histogram>
 
 <histogram name="PasswordManager.AddCredentialFromSettings.AccountStoreUsed2"
-    enum="Boolean" expires_after="2024-04-12">
+    enum="Boolean" expires_after="2024-08-04">
   <owner>mamir@google.com</owner>
   <summary>
     Tracks which store is used when the user adds a new credential from
@@ -962,7 +962,7 @@
 </histogram>
 
 <histogram name="PasswordManager.BulkCheck.InsecureCredentials.Count"
-    units="credentials" expires_after="2024-06-02">
+    units="credentials" expires_after="2024-08-04">
   <owner>eic@google.com</owner>
   <owner>noemies@google.com</owner>
   <summary>
@@ -1047,7 +1047,7 @@
 </histogram>
 
 <histogram name="PasswordManager.BulkCheck.UserAction.IOS.General"
-    enum="PasswordCheckInteractionIOSWithoutContext" expires_after="2024-06-02">
+    enum="PasswordCheckInteractionIOSWithoutContext" expires_after="2024-08-04">
   <owner>eic@google.com</owner>
   <owner>noemies@google.com</owner>
   <summary>
@@ -1368,7 +1368,7 @@
 </histogram>
 
 <histogram name="PasswordManager.FilledCredentialWasFromAndroidApp2"
-    enum="PasswordManagerFilledAndroidCredentials" expires_after="M126">
+    enum="PasswordManagerFilledAndroidCredentials" expires_after="2024-08-04">
   <owner>vsemeniuk@google.com</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>
@@ -1429,7 +1429,7 @@
 </histogram>
 
 <histogram name="PasswordManager.FillingSuccessIOS" enum="BooleanSuccess"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>theocristea@google.com</owner>
   <owner>kazinova@google.com</owner>
   <owner>vsemeniuk@google.com</owner>
@@ -1520,7 +1520,7 @@
 </histogram>
 
 <histogram name="PasswordManager.HttpPasswordMigrationCount2"
-    units="saved credentials" expires_after="2024-06-02">
+    units="saved credentials" expires_after="2024-08-04">
   <owner>kazinova@google.com</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>
@@ -2070,7 +2070,7 @@
 </histogram>
 
 <histogram name="PasswordManager.MoveUIDismissalReason{UserSyncingType}"
-    enum="PasswordManagerUIDismissalReason" expires_after="2024-06-02">
+    enum="PasswordManagerUIDismissalReason" expires_after="2024-08-04">
   <owner>mamir@chromium.org</owner>
   <owner>treib@chromium.org</owner>
   <summary>
@@ -2248,7 +2248,7 @@
 <histogram
     name="PasswordManager.PasswordGenerationBottomSheet.InteractionResult"
     enum="PasswordManager.PasswordGenerationBottomSheet.InteractionResult"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>atsvirchkova@google.com</owner>
   <owner>ioanap@chromium.org</owner>
   <summary>
@@ -2309,7 +2309,7 @@
 
 <histogram name="PasswordManager.PasswordMigrationWarning.SheetStateAtClosing"
     enum="PasswordMigrationWarningSheetStateAtClosing"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>izuzic@google.com</owner>
   <owner>ioanap@chromium.org</owner>
   <summary>
@@ -2319,7 +2319,7 @@
 </histogram>
 
 <histogram name="PasswordManager.PasswordMigrationWarning.Trigger"
-    enum="PasswordMigrationWarningTriggers" expires_after="2024-06-02">
+    enum="PasswordMigrationWarningTriggers" expires_after="2024-08-04">
   <owner>izuzic@google.com</owner>
   <owner>ioanap@chromium.org</owner>
   <summary>
@@ -2329,7 +2329,7 @@
 </histogram>
 
 <histogram name="PasswordManager.PasswordMigrationWarning.UserAction"
-    enum="PasswordMigrationWarningUserActions" expires_after="2024-06-02">
+    enum="PasswordMigrationWarningUserActions" expires_after="2024-08-04">
   <owner>izuzic@google.com</owner>
   <owner>ioanap@chromium.org</owner>
   <summary>
@@ -3299,7 +3299,7 @@
 </histogram>
 
 <histogram name="PasswordManager.SingleUsername.PasswordFormHadUsernameField"
-    enum="PasswordFormHadUsernameField" expires_after="2024-06-02">
+    enum="PasswordFormHadUsernameField" expires_after="2024-08-04">
   <owner>kazinova@google.com</owner>
   <owner>shaikhitdin@google.com</owner>
   <summary>
@@ -3398,7 +3398,7 @@
 </histogram>
 
 <histogram name="PasswordManager.SuccessfulSubmissionIndicatorEvent"
-    enum="SubmissionIndicatorEvent" expires_after="2024-06-02">
+    enum="SubmissionIndicatorEvent" expires_after="2024-08-04">
   <owner>kazinova@google.com</owner>
   <owner>vasilii@chromium.org</owner>
   <summary>
@@ -3522,7 +3522,7 @@
 
 <histogram name="PasswordManager.TouchToFill.PasswordGeneration.TriggerOutcome"
     enum="TouchToFillPasswordGenerationTriggerOutcome"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>atsvirchkova@google.com</owner>
   <owner>ioanap@chromium.org</owner>
   <summary>
@@ -3537,7 +3537,7 @@
 </histogram>
 
 <histogram name="PasswordManager.TouchToFill.PasswordGeneration.UserChoice"
-    enum="GenerationDialogChoice" expires_after="2024-06-01">
+    enum="GenerationDialogChoice" expires_after="2024-08-04">
   <owner>atsvirchkova@google.com</owner>
   <owner>ioanap@chromium.org</owner>
   <summary>
@@ -3695,7 +3695,7 @@
 </histogram>
 
 <histogram name="PasswordManager.UPMUpdateSignInCredentialsSucces"
-    enum="Boolean" expires_after="2024-06-02">
+    enum="Boolean" expires_after="2024-08-04">
   <owner>izuzic@google.com</owner>
   <owner>ioanap@chromium.org</owner>
   <summary>
@@ -3873,7 +3873,7 @@
 
 <histogram
     name="PasswordManager.{Store}PasswordNotes.CountCredentialsWithNonEmptyNotes2"
-    units="count" expires_after="2024-06-02">
+    units="count" expires_after="2024-08-04">
   <owner>derinel@google.com</owner>
   <owner>mamir@chromium.org</owner>
   <summary>
@@ -3884,7 +3884,7 @@
 </histogram>
 
 <histogram name="PasswordManager.{Store}PasswordNotes.CountNotesPerCredential3"
-    units="count" expires_after="2024-06-02">
+    units="count" expires_after="2024-08-04">
   <owner>derinel@google.com</owner>
   <owner>mamir@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/permissions/histograms.xml b/tools/metrics/histograms/metadata/permissions/histograms.xml
index 1f90823e..1b1908b 100644
--- a/tools/metrics/histograms/metadata/permissions/histograms.xml
+++ b/tools/metrics/histograms/metadata/permissions/histograms.xml
@@ -1061,7 +1061,7 @@
 
 <histogram
     name="Permissions.QuietNotificationPrompts.{RegularProfileFiltered}IsEnabledInPrefs"
-    enum="BooleanEnabled" expires_after="2024-06-02">
+    enum="BooleanEnabled" expires_after="2024-08-04">
   <owner>andypaicu@chromium.org</owner>
   <owner>engedy@chromium.org</owner>
   <owner>hkamila@chromium.org</owner>
@@ -1340,7 +1340,7 @@
 </histogram>
 
 <histogram name="WebsiteSettings.OriginInfo.PermissionChanged.Allowed"
-    enum="ContentType" expires_after="2024-06-02">
+    enum="ContentType" expires_after="2024-08-04">
   <owner>andypaicu@chromium.org</owner>
   <owner>engedy@chromium.org</owner>
   <owner>hkamila@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/platform/histograms.xml b/tools/metrics/histograms/metadata/platform/histograms.xml
index deac039..43374f77 100644
--- a/tools/metrics/histograms/metadata/platform/histograms.xml
+++ b/tools/metrics/histograms/metadata/platform/histograms.xml
@@ -465,7 +465,7 @@
 </histogram>
 
 <histogram name="Platform.DiskUsageChronos" units="KB"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>sarthakkukreti@google.com</owner>
   <owner>chromeos-storage@google.com</owner>
   <summary>
@@ -475,7 +475,7 @@
   </summary>
 </histogram>
 
-<histogram name="Platform.DiskUsageVar" units="KB" expires_after="2024-06-01">
+<histogram name="Platform.DiskUsageVar" units="KB" expires_after="2024-08-04">
   <owner>sarthakkukreti@google.com</owner>
   <owner>chromeos-storage@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/power/histograms.xml b/tools/metrics/histograms/metadata/power/histograms.xml
index 6c39931..be5b897a 100644
--- a/tools/metrics/histograms/metadata/power/histograms.xml
+++ b/tools/metrics/histograms/metadata/power/histograms.xml
@@ -197,7 +197,7 @@
 </variants>
 
 <histogram name="PerformanceMonitor.AverageCPU8.Total{UsageScenario}"
-    units="1/100 %" expires_after="2024-06-02">
+    units="1/100 %" expires_after="2024-08-04">
   <owner>fdoray@chromium.org</owner>
   <owner>pmonette@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
@@ -209,7 +209,7 @@
 </histogram>
 
 <histogram name="PerformanceMonitor.AverageCPU8.{ProcessName}" units="1/100 %"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>fdoray@chromium.org</owner>
   <owner>pmonette@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
@@ -244,7 +244,7 @@
 </histogram>
 
 <histogram name="PerformanceMonitor.IdleWakeups2.Total{UsageScenario}"
-    units="WakeupsPerSecond" expires_after="2024-06-02">
+    units="WakeupsPerSecond" expires_after="2024-08-04">
   <owner>olivierli@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -256,7 +256,7 @@
 </histogram>
 
 <histogram name="PerformanceMonitor.IdleWakeups2.{ProcessName}"
-    units="WakeupsPerSecond" expires_after="2024-06-02">
+    units="WakeupsPerSecond" expires_after="2024-08-04">
   <owner>olivierli@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -275,7 +275,7 @@
 
 <histogram
     name="PerformanceMonitor.PackageExitIdleWakeups2.Total{UsageScenario}"
-    units="WakeupsPerSecond" expires_after="2024-06-02">
+    units="WakeupsPerSecond" expires_after="2024-08-04">
   <owner>olivierli@chromium.org</owner>
   <owner>catan-team@chromium.orgg</owner>
   <summary>
@@ -287,7 +287,7 @@
 </histogram>
 
 <histogram name="PerformanceMonitor.PackageExitIdleWakeups2.{ProcessName}"
-    units="WakeupsPerSecond" expires_after="2024-06-02">
+    units="WakeupsPerSecond" expires_after="2024-08-04">
   <owner>olivierli@chromium.org</owner>
   <owner>catan-team@chromium.orgg</owner>
   <summary>
@@ -652,7 +652,7 @@
 </histogram>
 
 <histogram name="Power.BatteryDischargeMode5{UsageScenario}{IntervalType}"
-    enum="BatteryDischargeMode" expires_after="2024-06-02">
+    enum="BatteryDischargeMode" expires_after="2024-08-04">
   <owner>etiennep@chromium.org</owner>
   <owner>olivierli@chromium.org</owner>
   <summary>
@@ -682,7 +682,7 @@
 </histogram>
 
 <histogram name="Power.BatteryDischargeRateMilliwatts6.TenMinutes"
-    units="milliwatts" expires_after="2024-06-02">
+    units="milliwatts" expires_after="2024-08-04">
   <owner>pmonette@chromium.org</owner>
   <owner>fdoray@chromium.org</owner>
   <summary>
@@ -699,7 +699,7 @@
 
 <histogram
     name="Power.BatteryDischargeRateMilliwatts6{UsageScenario}{IntervalType}{BatterySaverMode}"
-    units="milliwatts" expires_after="2024-06-02">
+    units="milliwatts" expires_after="2024-08-04">
   <owner>etiennep@chromium.org</owner>
   <owner>olivierli@chromium.org</owner>
   <owner>lgrey@chromium.org</owner>
@@ -726,7 +726,7 @@
 
 <histogram
     name="Power.BatteryDischargeRatePreciseMilliwatts{UsageScenario}{IntervalType}{BatterySaverMode}"
-    units="milliwatts" expires_after="2024-06-02">
+    units="milliwatts" expires_after="2024-08-04">
   <owner>pmonette@chromium.org</owner>
   <owner>catan-team@chromium.org</owner>
   <summary>
@@ -755,7 +755,7 @@
 
 <histogram
     name="Power.BatteryDischargeRateRelative5{UsageScenario}{IntervalType}{BatterySaverMode}"
-    units="hundredth of percent" expires_after="2024-06-02">
+    units="hundredth of percent" expires_after="2024-08-04">
   <owner>etiennep@chromium.org</owner>
   <owner>olivierli@chromium.org</owner>
   <owner>lgrey@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/preloading/histograms.xml b/tools/metrics/histograms/metadata/preloading/histograms.xml
index e0a4500..4add1107 100644
--- a/tools/metrics/histograms/metadata/preloading/histograms.xml
+++ b/tools/metrics/histograms/metadata/preloading/histograms.xml
@@ -110,7 +110,7 @@
 
 <histogram
     name="Preloading.Experimental.{ExperimentalPreloadingPrediction}.{GroundTruth}"
-    units="param" expires_after="2024-06-01">
+    units="param" expires_after="2024-08-04">
   <owner>isaboori@google.com</owner>
   <owner>spelchat@chromium.org</owner>
   <owner>jbroman@chromium.org</owner>
@@ -133,7 +133,7 @@
 </histogram>
 
 <histogram name="Preloading.Predictor.{PreloadingPredictor}.Precision"
-    enum="PredictorConfusionMatrix" expires_after="2024-06-01">
+    enum="PredictorConfusionMatrix" expires_after="2024-08-04">
   <owner>isaboori@google.com</owner>
   <owner>spelchat@chromium.org</owner>
   <owner>sreejakshetty@chromium.org</owner>
@@ -150,7 +150,7 @@
 </histogram>
 
 <histogram name="Preloading.Predictor.{PreloadingPredictor}.Recall"
-    enum="PredictorConfusionMatrix" expires_after="2024-06-01">
+    enum="PredictorConfusionMatrix" expires_after="2024-08-04">
   <owner>isaboori@google.com</owner>
   <owner>spelchat@chromium.org</owner>
   <owner>sreejakshetty@chromium.org</owner>
@@ -168,7 +168,7 @@
 
 <histogram
     name="Preloading.PrerenderBackNavigationEligibility.{PreloadingPredictor}"
-    enum="PrerenderBackNavigationEligibility" expires_after="2024-06-01">
+    enum="PrerenderBackNavigationEligibility" expires_after="2024-08-04">
   <owner>mcnee@chromium.org</owner>
   <owner>chrome-brapp-loading@chromium.org</owner>
   <summary>
@@ -180,7 +180,7 @@
 
 <histogram
     name="Preloading.{PreloadingType}.Attempt.{PreloadingPredictor}.Precision"
-    enum="PredictorConfusionMatrix" expires_after="2024-06-01">
+    enum="PredictorConfusionMatrix" expires_after="2024-08-04">
   <owner>isaboori@google.com</owner>
   <owner>spelchat@chromium.org</owner>
   <owner>sreejakshetty@chromium.org</owner>
@@ -200,7 +200,7 @@
 
 <histogram
     name="Preloading.{PreloadingType}.Attempt.{PreloadingPredictor}.Recall"
-    enum="PredictorConfusionMatrix" expires_after="2024-06-01">
+    enum="PredictorConfusionMatrix" expires_after="2024-08-04">
   <owner>isaboori@google.com</owner>
   <owner>spelchat@chromium.org</owner>
   <owner>sreejakshetty@chromium.org</owner>
@@ -221,7 +221,7 @@
 
 <histogram
     name="Preloading.{PreloadingType}.Attempt.{PreloadingPredictor}.TriggeringOutcome"
-    enum="PreloadingTriggeringOutcome" expires_after="2024-06-01">
+    enum="PreloadingTriggeringOutcome" expires_after="2024-08-04">
   <owner>spelchat@chromium.org</owner>
   <owner>sreejakshetty@chromium.org</owner>
   <owner>jbroman@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/printing/histograms.xml b/tools/metrics/histograms/metadata/printing/histograms.xml
index 4d6bafa..4beabb83 100644
--- a/tools/metrics/histograms/metadata/printing/histograms.xml
+++ b/tools/metrics/histograms/metadata/printing/histograms.xml
@@ -108,7 +108,7 @@
 
 <histogram
     name="Printing.CUPS.AutomaticPpdSetupResultOfUsbPrinterSupportingIpp"
-    enum="PrinterSetupResult" expires_after="2024-06-02">
+    enum="PrinterSetupResult" expires_after="2024-08-04">
   <owner>pawliczek@chromium.org</owner>
   <owner>bmgordon@chromium.org</owner>
   <owner>project-bolton@google.com</owner>
@@ -191,7 +191,7 @@
 </histogram>
 
 <histogram name="Printing.CUPS.JobResultForUsbPrintersWithIppAndPpd"
-    enum="PrintJobResult" expires_after="2024-06-02">
+    enum="PrintJobResult" expires_after="2024-08-04">
   <owner>pawliczek@chromium.org</owner>
   <owner>bmgordon@chromium.org</owner>
   <owner>project-bolton@google.com</owner>
@@ -378,7 +378,7 @@
 </histogram>
 
 <histogram name="Printing.CUPS.SavedPrintersCount" units="printers"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>gavinwill@chromium.org</owner>
   <owner>cros-peripherals@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/privacy/histograms.xml b/tools/metrics/histograms/metadata/privacy/histograms.xml
index 6cd2741..73ce60c 100644
--- a/tools/metrics/histograms/metadata/privacy/histograms.xml
+++ b/tools/metrics/histograms/metadata/privacy/histograms.xml
@@ -528,7 +528,7 @@
 
 <histogram
     name="PrivacySandbox.AggregationService.ReportSender.HttpResponseOrNetErrorCode"
-    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2024-04-28">
+    enum="CombinedHttpResponseAndNetErrorCode" expires_after="2024-08-04">
   <owner>alexmt@chromium.org</owner>
   <owner>linnan@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/profile/histograms.xml b/tools/metrics/histograms/metadata/profile/histograms.xml
index c1d9503..6c76e92 100644
--- a/tools/metrics/histograms/metadata/profile/histograms.xml
+++ b/tools/metrics/histograms/metadata/profile/histograms.xml
@@ -490,7 +490,7 @@
 </histogram>
 
 <histogram base="true" name="Profile.State.LastUsed" units="days"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>droger@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/readaloud/histograms.xml b/tools/metrics/histograms/metadata/readaloud/histograms.xml
index e7fbf93..d05badcf 100644
--- a/tools/metrics/histograms/metadata/readaloud/histograms.xml
+++ b/tools/metrics/histograms/metadata/readaloud/histograms.xml
@@ -29,7 +29,7 @@
 </variants>
 
 <histogram name="ReadAloud.DurationListened" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>andreaxg@google.com</owner>
   <owner>basiaz@google.com</owner>
   <owner>iwells@chromium.org</owner>
@@ -41,7 +41,7 @@
 </histogram>
 
 <histogram name="ReadAloud.DurationListened.LockedScreen" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>andreaxg@google.com</owner>
   <owner>basiaz@google.com</owner>
   <owner>iwells@chromium.org</owner>
@@ -53,7 +53,7 @@
 </histogram>
 
 <histogram name="ReadAloud.Eligibility.IneligiblityReason"
-    enum="ReadAloudIneligibilityReason" expires_after="2024-06-02">
+    enum="ReadAloudIneligibilityReason" expires_after="2024-08-04">
   <owner>andreaxg@google.com</owner>
   <owner>basiaz@google.com</owner>
   <owner>iwells@chromium.org</owner>
@@ -65,7 +65,7 @@
 </histogram>
 
 <histogram name="ReadAloud.Eligibility.IsUserEligible" enum="BooleanEligible"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>andreaxg@google.com</owner>
   <owner>basiaz@google.com</owner>
   <owner>iwells@chromium.org</owner>
@@ -76,7 +76,7 @@
 </histogram>
 
 <histogram name="ReadAloud.HighlightingEnabled" enum="BooleanEnabled"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>andreaxg@google.com</owner>
   <owner>basiaz@google.com</owner>
   <owner>iwells@chromium.org</owner>
@@ -98,7 +98,7 @@
 </histogram>
 
 <histogram name="ReadAloud.HighlightingSupported" enum="BooleanSupported"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>andreaxg@google.com</owner>
   <owner>basiaz@google.com</owner>
   <owner>iwells@chromium.org</owner>
@@ -109,7 +109,7 @@
 </histogram>
 
 <histogram name="ReadAloud.IsPageReadabilitySuccessful" enum="BooleanSuccess"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>andreaxg@google.com</owner>
   <owner>basiaz@google.com</owner>
   <owner>iwells@chromium.org</owner>
@@ -121,7 +121,7 @@
 </histogram>
 
 <histogram name="ReadAloud.IsPageReadable" enum="BooleanEligible"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>andreaxg@google.com</owner>
   <owner>basiaz@google.com</owner>
   <owner>iwells@chromium.org</owner>
@@ -133,7 +133,7 @@
 </histogram>
 
 <histogram name="ReadAloud.IsTabPlaybackCreationSuccessful"
-    enum="BooleanSuccess" expires_after="2024-06-02">
+    enum="BooleanSuccess" expires_after="2024-08-04">
   <owner>andreaxg@google.com</owner>
   <owner>basiaz@google.com</owner>
   <owner>iwells@chromium.org</owner>
@@ -144,7 +144,7 @@
 </histogram>
 
 <histogram name="ReadAloud.ReadAloudError.{Phase}" enum="ReadAloudErrorCode"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>andreaxg@google.com</owner>
   <owner>basiaz@google.com</owner>
   <owner>iwells@chromium.org</owner>
@@ -173,7 +173,7 @@
 </histogram>
 
 <histogram name="ReadAloud.ReadAloudUnsuportedError.{Phase}"
-    enum="RejectionReason" expires_after="2024-06-02">
+    enum="RejectionReason" expires_after="2024-08-04">
   <owner>andreaxg@google.com</owner>
   <owner>basiaz@google.com</owner>
   <owner>iwells@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/renderer/histograms.xml b/tools/metrics/histograms/metadata/renderer/histograms.xml
index 821e7bb4..bfd283a 100644
--- a/tools/metrics/histograms/metadata/renderer/histograms.xml
+++ b/tools/metrics/histograms/metadata/renderer/histograms.xml
@@ -373,7 +373,7 @@
 </histogram>
 
 <histogram name="Renderer.Images.HasOverfetchedCappedPixels" enum="Boolean"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>yoavweiss@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
index fc11c27..64920b2 100644
--- a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
+++ b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
@@ -631,7 +631,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.EsbPromotionFlow.IphShown"
-    enum="SafeBrowsingReferralMethod" expires_after="2024-06-02">
+    enum="SafeBrowsingReferralMethod" expires_after="2024-08-04">
   <owner>awado@google.com</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -1777,7 +1777,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.PageLoadToken.TokenCount" units="entries"
-    expires_after="2024-04-28">
+    expires_after="2024-08-04">
   <owner>xinghuilu@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/sb_client/histograms.xml b/tools/metrics/histograms/metadata/sb_client/histograms.xml
index da5fb82..271189b 100644
--- a/tools/metrics/histograms/metadata/sb_client/histograms.xml
+++ b/tools/metrics/histograms/metadata/sb_client/histograms.xml
@@ -420,7 +420,7 @@
 </histogram>
 
 <histogram name="SBClientDownload.{Encryption}DeepScanEvent3"
-    enum="SBDeepScanEvent" expires_after="2024-06-02">
+    enum="SBDeepScanEvent" expires_after="2024-08-04">
   <owner>drubery@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -606,7 +606,7 @@
 </histogram>
 
 <histogram name="SBClientPhishing.ImageEmbeddingModelVersionMatch"
-    enum="BooleanMatched" expires_after="2024-06-05">
+    enum="BooleanMatched" expires_after="2024-08-04">
   <owner>andysjlim@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
@@ -751,7 +751,7 @@
 </histogram>
 
 <histogram name="SBClientPhishing.RTLookupForceRequest"
-    enum="BooleanForceRequest" expires_after="2024-06-02">
+    enum="BooleanForceRequest" expires_after="2024-08-04">
   <owner>andysjlim@chromium.org</owner>
   <owner>chrome-counter-abuse-alerts@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/scheduler/histograms.xml b/tools/metrics/histograms/metadata/scheduler/histograms.xml
index 7efbcef..e36191d 100644
--- a/tools/metrics/histograms/metadata/scheduler/histograms.xml
+++ b/tools/metrics/histograms/metadata/scheduler/histograms.xml
@@ -38,7 +38,7 @@
 </histogram>
 
 <histogram name="Scheduling.MessagePumpTimeKeeper.{NamedThread}"
-    enum="MessagePumpPhases" expires_after="2024-05-31">
+    enum="MessagePumpPhases" expires_after="2024-08-04">
   <owner>gab@chromium.org</owner>
   <owner>fdoray@chromium.org</owner>
   <owner>spvw@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/search/histograms.xml b/tools/metrics/histograms/metadata/search/histograms.xml
index 9bed070..52bd1a3 100644
--- a/tools/metrics/histograms/metadata/search/histograms.xml
+++ b/tools/metrics/histograms/metadata/search/histograms.xml
@@ -137,7 +137,7 @@
 </histogram>
 
 <histogram name="Search.ChoiceScreenDefaultSearchEngineType"
-    enum="OmniboxSearchEngineType" expires_after="2024-06-02">
+    enum="OmniboxSearchEngineType" expires_after="2024-08-04">
   <owner>dgn@chromium.org</owner>
   <owner>jyammine@google.com</owner>
   <owner>chrome-waffle-eng@google.com</owner>
@@ -151,7 +151,7 @@
 </histogram>
 
 <histogram name="Search.ChoiceScreenEvents"
-    enum="SearchEngineChoiceScreenEvents" expires_after="2024-06-02">
+    enum="SearchEngineChoiceScreenEvents" expires_after="2024-08-04">
   <owner>samarchehade@chromium.org</owner>
   <owner>chrome-waffle-eng@google.com</owner>
   <summary>
@@ -164,7 +164,7 @@
 </histogram>
 
 <histogram name="Search.ChoiceScreenNavigationConditions"
-    enum="SearchEngineChoiceScreenConditions" expires_after="2024-06-02">
+    enum="SearchEngineChoiceScreenConditions" expires_after="2024-08-04">
   <owner>dgn@chromium.org</owner>
   <owner>muellerj@chromium.org</owner>
   <owner>chrome-waffle-eng@google.com</owner>
@@ -178,7 +178,7 @@
 </histogram>
 
 <histogram name="Search.ChoiceScreenProfileInitConditions"
-    enum="SearchEngineChoiceScreenConditions" expires_after="2024-06-02">
+    enum="SearchEngineChoiceScreenConditions" expires_after="2024-08-04">
   <owner>dgn@chromium.org</owner>
   <owner>muellerj@chromium.org</owner>
   <owner>chrome-waffle-eng@google.com</owner>
@@ -728,7 +728,7 @@
 </histogram>
 
 <histogram name="Search.Lens.ViewportDimensionsSent.Success" enum="Boolean"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>mercerd@google.com</owner>
   <owner>lens-chrome-eng@google.com</owner>
   <summary>
@@ -1092,7 +1092,7 @@
 </histogram>
 
 <histogram name="Search.SearchProviderOverrideStatus"
-    enum="SearchProviderOverrideStatus" expires_after="2024-06-01">
+    enum="SearchProviderOverrideStatus" expires_after="2024-08-04">
   <owner>dgn@chromium.org</owner>
   <owner>droger@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/security/histograms.xml b/tools/metrics/histograms/metadata/security/histograms.xml
index 7193c2a..455b23f 100644
--- a/tools/metrics/histograms/metadata/security/histograms.xml
+++ b/tools/metrics/histograms/metadata/security/histograms.xml
@@ -156,7 +156,7 @@
 </histogram>
 
 <histogram name="Security.HttpsFirstMode.InterstitialReason"
-    enum="HttpsFirstModeInterstitialReason" expires_after="2024-06-02">
+    enum="HttpsFirstModeInterstitialReason" expires_after="2024-08-04">
   <owner>meacer@chromium.org</owner>
   <owner>trusty-transport@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/segmentation_platform/histograms.xml b/tools/metrics/histograms/metadata/segmentation_platform/histograms.xml
index f8ba087..d0063f9 100644
--- a/tools/metrics/histograms/metadata/segmentation_platform/histograms.xml
+++ b/tools/metrics/histograms/metadata/segmentation_platform/histograms.xml
@@ -295,7 +295,7 @@
 </histogram>
 
 <histogram name="SegmentationPlatform.Init.CreationToInitializationLatency"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>ssid@chromium.org</owner>
   <owner>chrome-segmentation-platform@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/service/histograms.xml b/tools/metrics/histograms/metadata/service/histograms.xml
index 7de0d76..392434d 100644
--- a/tools/metrics/histograms/metadata/service/histograms.xml
+++ b/tools/metrics/histograms/metadata/service/histograms.xml
@@ -275,7 +275,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.DiskCache.InitResult" units="units"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
@@ -320,7 +320,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.EvaluateTopLevelScript.{ResultStatus}.Time"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -576,7 +576,7 @@
 
 <histogram
     name="ServiceWorker.LoadTiming.MainFrame.MainResource.AutoPreloadResponseReceivedToFetchHandlerEnd.{ServiceWorkerFetchResponseFromName}"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>sisidovski@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -598,7 +598,7 @@
 
 <histogram
     name="ServiceWorker.LoadTiming.MainFrame.MainResource.FetchHandlerEndToFallbackNetwork{EmbeddedWorkerInitialStatus}"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
@@ -620,7 +620,7 @@
 
 <histogram
     name="ServiceWorker.LoadTiming.MainFrame.MainResource.FetchHandlerEndToResponseReceived{EmbeddedWorkerInitialStatus}"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -641,7 +641,7 @@
 
 <histogram
     name="ServiceWorker.LoadTiming.MainFrame.MainResource.FetchHandlerStartToFetchHandlerEndByFetchResult_{ServiceWorkerFetchEventResult}"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -661,7 +661,7 @@
 
 <histogram
     name="ServiceWorker.LoadTiming.MainFrame.MainResource.FetchHandlerStartToFetchHandlerEnd{EmbeddedWorkerInitialStatus}"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -681,7 +681,7 @@
 
 <histogram
     name="ServiceWorker.LoadTiming.MainFrame.MainResource.FindRegistrationToCompleted{EmbeddedWorkerInitialStatus}"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -701,7 +701,7 @@
 
 <histogram
     name="ServiceWorker.LoadTiming.MainFrame.MainResource.FindRegistrationToFallbackNetwork{EmbeddedWorkerInitialStatus}"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -721,7 +721,7 @@
 
 <histogram
     name="ServiceWorker.LoadTiming.MainFrame.MainResource.FindRegistrationToRequestStart{EmbeddedWorkerInitialStatus}"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -740,7 +740,7 @@
 
 <histogram
     name="ServiceWorker.LoadTiming.MainFrame.MainResource.ForwardServiceWorkerToWorkerReady2{EmbeddedWorkerInitialStatus}{NavigationType}"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -803,7 +803,7 @@
 
 <histogram
     name="ServiceWorker.LoadTiming.MainFrame.MainResource.ResponseReceivedToCompleted2{ServiceWorkerResponseSource}{EmbeddedWorkerInitialStatus}"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
@@ -840,7 +840,7 @@
 
 <histogram
     name="ServiceWorker.LoadTiming.MainFrame.MainResource.StartToCompleted{EmbeddedWorkerInitialStatus}"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -860,7 +860,7 @@
 
 <histogram
     name="ServiceWorker.LoadTiming.MainFrame.MainResource.StartToFallbackNetwork{EmbeddedWorkerInitialStatus}"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -880,7 +880,7 @@
 
 <histogram
     name="ServiceWorker.LoadTiming.MainFrame.MainResource.StartToForwardServiceWorker{EmbeddedWorkerInitialStatus}"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
@@ -900,7 +900,7 @@
 
 <histogram
     name="ServiceWorker.LoadTiming.MainFrame.MainResource.WorkerReadyToFetchHandlerStart{EmbeddedWorkerInitialStatus}"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
@@ -943,7 +943,7 @@
 
 <histogram
     name="ServiceWorker.LoadTiming.Subresource.FetchHandlerEndToFallbackNetwork"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
@@ -1135,7 +1135,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.OnStarted.UpdatedFetchHandlerType"
-    enum="ServiceWorkerFetchHandlerType" expires_after="2024-06-01">
+    enum="ServiceWorkerFetchHandlerType" expires_after="2024-08-04">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -1212,7 +1212,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.RouterEvaluator.Error"
-    enum="ServiceWorkerRouterEvaluatorErrorEnums" expires_after="2024-04-01">
+    enum="ServiceWorkerRouterEvaluatorErrorEnums" expires_after="2024-08-04">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -1223,7 +1223,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.RouterEvaluator.MatchedFirstSourceType"
-    enum="ServiceWorkerRouterSourceType" expires_after="2024-06-05">
+    enum="ServiceWorkerRouterSourceType" expires_after="2024-08-04">
   <owner>sisidovski@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -1261,7 +1261,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.StartTiming.ClockConsistency"
-    enum="CrossProcessTimeDelta" expires_after="2024-06-01">
+    enum="CrossProcessTimeDelta" expires_after="2024-08-04">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -1280,7 +1280,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.StartTiming.Duration" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -1297,7 +1297,7 @@
 
 <histogram
     name="ServiceWorker.StartTiming.ReceivedStartWorkerToScriptEvaluationStart"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -1406,7 +1406,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.StartWorker.Status"
-    enum="ServiceWorkerStatusCode" expires_after="2024-06-01">
+    enum="ServiceWorkerStatusCode" expires_after="2024-08-04">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
@@ -1484,7 +1484,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.Storage.DeleteAndStartOverResult"
-    enum="ServiceWorkerDeleteAndStartOverResult" expires_after="2024-06-01">
+    enum="ServiceWorkerDeleteAndStartOverResult" expires_after="2024-08-04">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
@@ -1525,7 +1525,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.Storage.ReadInitialDataFromDB.Time" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -1570,7 +1570,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.Subresource.Fallbacked.Type2"
-    enum="ResourceType" expires_after="2024-06-01">
+    enum="ResourceType" expires_after="2024-08-04">
   <owner>yyanagisawa@google.com</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -1583,7 +1583,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.Subresource.Handled.Type2" enum="ResourceType"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>yyanagisawa@google.com</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
@@ -1596,7 +1596,7 @@
 </histogram>
 
 <histogram name="ServiceWorker.UpdateResourceSha256ChecksumsResult"
-    enum="ServiceWorkerStatusCode" expires_after="2024-06-01">
+    enum="ServiceWorkerStatusCode" expires_after="2024-08-04">
   <owner>sisidovski@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/session/histograms.xml b/tools/metrics/histograms/metadata/session/histograms.xml
index 4db5de0..c12bb1f6 100644
--- a/tools/metrics/histograms/metadata/session/histograms.xml
+++ b/tools/metrics/histograms/metadata/session/histograms.xml
@@ -72,7 +72,7 @@
 </histogram>
 
 <histogram name="Session.OpenedTabCounts" units="operations"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>rohitrao@chromium.org</owner>
   <owner>marq@chromium.org</owner>
   <summary>
@@ -888,7 +888,7 @@
 </histogram>
 
 <histogram name="Session.WebStates.NativeRestoreHasFetchers"
-    enum="BooleanHasFetchers" expires_after="2024-06-02">
+    enum="BooleanHasFetchers" expires_after="2024-08-04">
   <owner>ajuma@chromium.org</owner>
   <owner>michaeldo@chromium.org</owner>
   <summary>
@@ -920,7 +920,7 @@
 </histogram>
 
 <histogram name="Session.WebStates.NativeRestoreSessionFromCacheHasData"
-    enum="BooleanHasData" expires_after="2024-06-02">
+    enum="BooleanHasData" expires_after="2024-08-04">
   <owner>ajuma@chromium.org</owner>
   <owner>michaeldo@chromium.org</owner>
   <summary>
@@ -931,7 +931,7 @@
 </histogram>
 
 <histogram name="Session.WebStates.NativeRestoreSessionHasData"
-    enum="BooleanHasData" expires_after="2024-06-02">
+    enum="BooleanHasData" expires_after="2024-08-04">
   <owner>ajuma@chromium.org</owner>
   <owner>michaeldo@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/settings/histograms.xml b/tools/metrics/histograms/metadata/settings/histograms.xml
index 476cac0..a7efad5 100644
--- a/tools/metrics/histograms/metadata/settings/histograms.xml
+++ b/tools/metrics/histograms/metadata/settings/histograms.xml
@@ -232,7 +232,7 @@
 </histogram>
 
 <histogram name="Settings.PrivacyElementInteractions"
-    enum="SettingsPrivacyElementInteractions" expires_after="2024-06-02">
+    enum="SettingsPrivacyElementInteractions" expires_after="2024-08-04">
   <owner>harrisonsean@chromium.org</owner>
   <owner>msramek@chromium.org</owner>
   <owner>sauski@chromium.org</owner>
@@ -243,7 +243,7 @@
 </histogram>
 
 <histogram name="Settings.PrivacyGuide.EntryExit"
-    enum="SettingsPrivacyGuideInteractions" expires_after="2024-06-02">
+    enum="SettingsPrivacyGuideInteractions" expires_after="2024-08-04">
   <owner>harrisonsean@chromium.org</owner>
   <owner>rainhard@chromium.org</owner>
   <owner>chrome-privacy-controls@google.com</owner>
@@ -254,7 +254,7 @@
 </histogram>
 
 <histogram name="Settings.PrivacyGuide.FlowLength" units="steps"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>rainhard@chromium.org</owner>
   <owner>aisulu@google.com</owner>
   <owner>chrome-privacy-controls@google.com</owner>
@@ -266,7 +266,7 @@
 </histogram>
 
 <histogram name="Settings.PrivacyGuide.NextNavigation"
-    enum="SettingsPrivacyGuideInteractions" expires_after="2024-06-02">
+    enum="SettingsPrivacyGuideInteractions" expires_after="2024-08-04">
   <owner>harrisonsean@chromium.org</owner>
   <owner>rainhard@chromium.org</owner>
   <owner>chrome-privacy-controls@google.com</owner>
@@ -289,7 +289,7 @@
 
 <histogram name="Settings.PrivacyGuide.StepsEligibleAndReached"
     enum="SettingsPrivacyGuideStepsEligibleAndReached"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>rainhard@chromium.org</owner>
   <owner>aisulu@google.com</owner>
   <owner>chrome-privacy-controls@google.com</owner>
@@ -729,7 +729,7 @@
 
 <histogram name="Settings.SafetyHub.NotificationPermissionsModule.Interactions"
     enum="SafetyCheckNotificationsModuleInteractions"
-    expires_after="2024-05-30">
+    expires_after="2024-08-04">
   <owner>sideyilmaz@chromium.org</owner>
   <owner>aisulu@google.com</owner>
   <owner>chrome-privacy-controls@google.com</owner>
@@ -741,7 +741,7 @@
 </histogram>
 
 <histogram name="Settings.SafetyHub.NotificationPermissionsModule.ListCount"
-    units="suggestions" expires_after="2024-05-30">
+    units="suggestions" expires_after="2024-08-04">
   <owner>sideyilmaz@chromium.org</owner>
   <owner>aisulu@google.com</owner>
   <owner>chrome-privacy-controls@google.com</owner>
@@ -776,7 +776,7 @@
 
 <histogram name="Settings.SafetyHub.UnusedSitePermissionsModule.Interactions"
     enum="SafetyCheckUnusedSitePermissionsModuleInteractions"
-    expires_after="2024-05-30">
+    expires_after="2024-08-04">
   <owner>sideyilmaz@chromium.org</owner>
   <owner>aisulu@google.com</owner>
   <owner>chrome-privacy-controls@google.com</owner>
@@ -788,7 +788,7 @@
 </histogram>
 
 <histogram name="Settings.SafetyHub.UnusedSitePermissionsModule.ListCount"
-    units="suggestions" expires_after="2024-05-30">
+    units="suggestions" expires_after="2024-08-04">
   <owner>sideyilmaz@chromium.org</owner>
   <owner>aisulu@google.com</owner>
   <owner>chrome-privacy-controls@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/signin/histograms.xml b/tools/metrics/histograms/metadata/signin/histograms.xml
index 5ef9b24..a2a71c8 100644
--- a/tools/metrics/histograms/metadata/signin/histograms.xml
+++ b/tools/metrics/histograms/metadata/signin/histograms.xml
@@ -338,7 +338,7 @@
 </histogram>
 
 <histogram name="Signin.AccountTracker.SeedAccountInfo.IsAccountIdEmpty"
-    enum="BooleanEmpty" expires_after="2024-06-02">
+    enum="BooleanEmpty" expires_after="2024-08-04">
   <owner>msarda@chromium.org</owner>
   <owner>sinhak@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -1119,7 +1119,7 @@
 </histogram>
 
 <histogram name="Signin.IOSDeviceRestoreSignedInState"
-    enum="IOSDeviceRestoreSignedinState" expires_after="2024-06-02">
+    enum="IOSDeviceRestoreSignedinState" expires_after="2024-08-04">
   <owner>jlebel@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
   <summary>
@@ -1129,7 +1129,7 @@
 </histogram>
 
 <histogram name="Signin.IOSGaiaCookieStateOnSignedInNavigation"
-    enum="GaiaCookieStateOnSignedInNavigation" expires_after="2024-06-02">
+    enum="GaiaCookieStateOnSignedInNavigation" expires_after="2024-08-04">
   <owner>jlebel@chromium.org</owner>
   <owner>msarda@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -1144,7 +1144,7 @@
 </histogram>
 
 <histogram name="Signin.IOSNumberOfDeviceAccounts" units="accounts"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>jlebel@chromium.org</owner>
   <owner>msarda@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -1287,7 +1287,7 @@
 </histogram>
 
 <histogram name="Signin.LoadedIdentities.Count" units="identities"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>jlebel@chromium.org</owner>
   <owner>msarda@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -1396,7 +1396,7 @@
 </histogram>
 
 <histogram name="Signin.PAMInitialize.PrimaryAccountInfoState"
-    enum="PAMInitializePrimaryAccountInfoState" expires_after="2024-06-01">
+    enum="PAMInitializePrimaryAccountInfoState" expires_after="2024-08-04">
   <owner>msarda@chromium.org</owner>
   <owner>droger@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -1408,7 +1408,7 @@
 </histogram>
 
 <histogram name="Signin.PAMInitialize.PrimaryAccountPrefs"
-    enum="PAMInitializePrimaryAccountPrefs" expires_after="2024-06-01">
+    enum="PAMInitializePrimaryAccountPrefs" expires_after="2024-08-04">
   <owner>msarda@chromium.org</owner>
   <owner>droger@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
@@ -1495,7 +1495,7 @@
 
 <histogram
     name="Signin.Reconciler.RejectedRequestsDueToThrottler.{RequestType}"
-    units="requests" expires_after="2024-06-02">
+    units="requests" expires_after="2024-08-04">
   <owner>droger@chromium.org</owner>
   <owner>msarda@chromium.org</owner>
   <owner>msalama@chromium.org</owner>
@@ -1769,7 +1769,7 @@
 </histogram>
 
 <histogram base="true" name="Signin.SSOIdentityListRequest.CacheState"
-    enum="SigninSSOIdentityListRequestCacheState" expires_after="2024-06-02">
+    enum="SigninSSOIdentityListRequestCacheState" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="SigninSSOIdentityListRequestCacheRequestState" -->
 
   <owner>jlebel@chromium.org</owner>
@@ -1782,7 +1782,7 @@
 </histogram>
 
 <histogram base="true" name="Signin.SSOIdentityListRequest.Duration" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes name="SigninSSOIdentityListRequestDurationCacheState" -->
 
   <owner>jlebel@chromium.org</owner>
@@ -1795,7 +1795,7 @@
 
 <histogram
     name="Signin.SSOIdentityListRequest.FetchIdentitiesWithCallback.Duration"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>jlebel@chromium.org</owner>
   <owner>chrome-signin-team@google.com</owner>
   <summary>
@@ -2012,7 +2012,7 @@
 </histogram>
 
 <histogram name="Signin.TransactionalReauthUserAction"
-    enum="SigninReauthUserAction" expires_after="2024-06-02">
+    enum="SigninReauthUserAction" expires_after="2024-08-04">
 <!-- Name completed by histogram_suffixes
 name="TransactionalReauthEntryPoint" -->
 
diff --git a/tools/metrics/histograms/metadata/stability/histograms.xml b/tools/metrics/histograms/metadata/stability/histograms.xml
index 19aa4e9a..89a72269 100644
--- a/tools/metrics/histograms/metadata/stability/histograms.xml
+++ b/tools/metrics/histograms/metadata/stability/histograms.xml
@@ -520,7 +520,7 @@
 </histogram>
 
 <histogram name="Stability.MobileSessionShutdownType2"
-    enum="MobileSessionShutdownType" expires_after="2024-06-02">
+    enum="MobileSessionShutdownType" expires_after="2024-08-04">
   <owner>justincohen@chromium.org</owner>
   <owner>ajuma@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/startup/histograms.xml b/tools/metrics/histograms/metadata/startup/histograms.xml
index b1efaff..33c8620a2 100644
--- a/tools/metrics/histograms/metadata/startup/histograms.xml
+++ b/tools/metrics/histograms/metadata/startup/histograms.xml
@@ -501,7 +501,7 @@
 
 <histogram
     name="Startup.Android.PrivacySandbox.DialogNotShownDueToTabLaunchedFromExternalApp"
-    enum="Boolean" expires_after="2024-06-02">
+    enum="Boolean" expires_after="2024-08-04">
   <owner>tommasin@chromium.org</owner>
   <owner>kartoffel-core-eng@google.com</owner>
   <summary>
@@ -828,7 +828,7 @@
 </histogram>
 
 <histogram name="Startup.GPU.LoadTime.ApplicationStartToGpuInitialized"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>spvw@chromium.org</owner>
   <owner>etienneb@chromium.org</owner>
   <summary>
@@ -851,7 +851,7 @@
 </histogram>
 
 <histogram name="Startup.GPU.LoadTime.ChromeMainToGpuInitialized" units="ms"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>spvw@chromium.org</owner>
   <owner>etienneb@chromium.org</owner>
   <summary>
@@ -865,7 +865,7 @@
 </histogram>
 
 <histogram name="Startup.GPU.LoadTime.ProcessCreationToGpuInitialized"
-    units="ms" expires_after="2024-06-01">
+    units="ms" expires_after="2024-08-04">
   <owner>spvw@chromium.org</owner>
   <owner>etienneb@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/storage/histograms.xml b/tools/metrics/histograms/metadata/storage/histograms.xml
index b21f1cc0..b470d3af 100644
--- a/tools/metrics/histograms/metadata/storage/histograms.xml
+++ b/tools/metrics/histograms/metadata/storage/histograms.xml
@@ -432,7 +432,7 @@
 </histogram>
 
 <histogram name="Storage.ClearSiteDataHeader.Parameters"
-    enum="ClearSiteDataParameters" expires_after="2024-06-02">
+    enum="ClearSiteDataParameters" expires_after="2024-08-04">
   <owner>estade@chromium.org</owner>
   <owner>chrome-owp-storage@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/sync/histograms.xml b/tools/metrics/histograms/metadata/sync/histograms.xml
index 2f84304..b038b29 100644
--- a/tools/metrics/histograms/metadata/sync/histograms.xml
+++ b/tools/metrics/histograms/metadata/sync/histograms.xml
@@ -241,7 +241,7 @@
 </histogram>
 
 <histogram name="Sync.BookmarksGUIDDuplicates" enum="BookmarksGUIDDuplicates"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>mastiz@chromium.org</owner>
   <owner>rushans@google.com</owner>
   <component>Services&gt;Sync</component>
@@ -460,7 +460,7 @@
 </histogram>
 
 <histogram name="Sync.CryptographerReady" enum="SyncCryptographerReadyState"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>mmoskvitin@google.com</owner>
   <owner>mastiz@chromium.org</owner>
   <component>Services&gt;Sync</component>
@@ -823,7 +823,7 @@
 </histogram>
 
 <histogram name="Sync.ModelTypeBlockedDueToUndecryptableUpdate"
-    enum="SyncModelTypes" expires_after="2024-06-02">
+    enum="SyncModelTypes" expires_after="2024-08-04">
   <owner>victorvianna@google.com</owner>
   <owner>mastiz@chromium.org</owner>
   <component>Services&gt;Sync</component>
@@ -850,7 +850,7 @@
 </histogram>
 
 <histogram name="Sync.ModelTypeCommitMessageHasDepletedQuota"
-    enum="SyncModelTypes" expires_after="2024-04-28">
+    enum="SyncModelTypes" expires_after="2024-08-04">
   <owner>rushans@google.com</owner>
   <owner>treib@chromium.org</owner>
   <component>Services&gt;Sync</component>
@@ -1398,7 +1398,7 @@
 </histogram>
 
 <histogram name="Sync.SharingMessage.CommitResult"
-    enum="SyncSharingMessageCommitErrorCode" expires_after="2024-05-05">
+    enum="SyncSharingMessageCommitErrorCode" expires_after="2024-08-04">
   <owner>rushans@google.com</owner>
   <owner>treib@chromium.org</owner>
   <component>Services&gt;Sync</component>
@@ -1473,7 +1473,7 @@
 </histogram>
 
 <histogram name="Sync.SyncablePrefValueChanged" enum="SyncablePref"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>ankushkush@google.com</owner>
   <owner>treib@chromium.org</owner>
   <component>Services&gt;Sync</component>
@@ -1484,7 +1484,7 @@
 </histogram>
 
 <histogram name="Sync.SyncableServiceStartTime{SyncModelType}" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>ankushkush@google.com</owner>
   <owner>treib@chromium.org</owner>
   <component>Services&gt;Sync</component>
@@ -1597,7 +1597,7 @@
 </histogram>
 
 <histogram name="Sync.SyncToSigninMigration.ReadingListMigrationStep"
-    enum="SyncToSigninMigrationReadingListStep" expires_after="2024-05-01">
+    enum="SyncToSigninMigrationReadingListStep" expires_after="2024-08-04">
   <owner>treib@chromium.org</owner>
   <owner>mastiz@chromium.org</owner>
   <component>Services&gt;Sync</component>
@@ -1627,7 +1627,7 @@
 
 <histogram
     name="Sync.SyncToSigninMigrationDecision{SyncToSigninMigrationMode}{SyncModelTypeForSyncToSigninMigration}"
-    enum="SyncToSigninMigrationDataTypeDecision" expires_after="2024-05-01">
+    enum="SyncToSigninMigrationDataTypeDecision" expires_after="2024-08-04">
   <owner>treib@chromium.org</owner>
   <owner>mastiz@chromium.org</owner>
   <component>Services&gt;Sync</component>
@@ -1643,7 +1643,7 @@
 </histogram>
 
 <histogram name="Sync.SyncToSigninMigrationOutcome" enum="BooleanSuccess"
-    expires_after="2024-05-01">
+    expires_after="2024-08-04">
   <owner>treib@chromium.org</owner>
   <owner>mastiz@chromium.org</owner>
   <component>Services&gt;Sync</component>
@@ -1670,7 +1670,7 @@
 </histogram>
 
 <histogram name="Sync.SyncToSigninMigrationOutcome.PasswordsFileMove"
-    enum="PlatformFileError" expires_after="2024-05-01">
+    enum="PlatformFileError" expires_after="2024-08-04">
   <owner>treib@chromium.org</owner>
   <owner>mastiz@chromium.org</owner>
   <component>Services&gt;Sync</component>
@@ -1683,7 +1683,7 @@
 </histogram>
 
 <histogram name="Sync.SyncToSigninMigrationTime" units="ms"
-    expires_after="2024-05-01">
+    expires_after="2024-08-04">
   <owner>treib@chromium.org</owner>
   <owner>mastiz@chromium.org</owner>
   <component>Services&gt;Sync</component>
@@ -1726,7 +1726,7 @@
 </histogram>
 
 <histogram name="Sync.TrustedVaultAccessTokenFetchSuccess" enum="Boolean"
-    expires_after="2024-06-04">
+    expires_after="2024-08-04">
   <owner>mmoskvitin@google.com</owner>
   <owner>mastiz@chromium.org</owner>
   <component>Services&gt;Sync</component>
diff --git a/tools/metrics/histograms/metadata/tab/histograms.xml b/tools/metrics/histograms/metadata/tab/histograms.xml
index aefccf90..77bf49b 100644
--- a/tools/metrics/histograms/metadata/tab/histograms.xml
+++ b/tools/metrics/histograms/metadata/tab/histograms.xml
@@ -406,7 +406,7 @@
 </histogram>
 
 <histogram name="Tab.PerceivedRestoreTime" units="ms"
-    expires_after="2024-05-19">
+    expires_after="2024-08-04">
   <owner>ckitagawa@chromium.org</owner>
   <owner>dtrainor@chromium.org</owner>
   <owner>yfriedman@chromium.org</owner>
@@ -447,7 +447,7 @@
 </histogram>
 
 <histogram name="Tab.RendererTermination.AliveRenderersCount" units="renderers"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>ajuma@chromium.org</owner>
   <owner>bling-fundamentals@google.com</owner>
   <summary>
@@ -510,7 +510,7 @@
 </histogram>
 
 <histogram name="Tab.StateAtRendererTermination" enum="TabForegroundState"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>gambard@chromium.org</owner>
   <owner>olivierrobin@chromium.org</owner>
   <summary>
@@ -988,7 +988,7 @@
   <summary>[Android and iOS] The number of tabs opened at cold launch.</summary>
 </histogram>
 
-<histogram name="Tabs.CountAtStartup2" units="tabs" expires_after="2024-05-19">
+<histogram name="Tabs.CountAtStartup2" units="tabs" expires_after="2024-08-04">
   <owner>marq@chromium.org</owner>
   <owner>chromeleon@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/uma/histograms.xml b/tools/metrics/histograms/metadata/uma/histograms.xml
index 298de5a..efc112c 100644
--- a/tools/metrics/histograms/metadata/uma/histograms.xml
+++ b/tools/metrics/histograms/metadata/uma/histograms.xml
@@ -450,7 +450,7 @@
 </histogram>
 
 <histogram name="UMA.MetricsReporting.Toggle" enum="MetricsReportingChange"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>asvitkine@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
@@ -645,7 +645,7 @@
 </histogram>
 
 <histogram name="UMA.PersistentAllocator.{PersistentAllocatorType}.UsedPct"
-    units="%" expires_after="2024-06-01">
+    units="%" expires_after="2024-08-04">
   <owner>asvitkine@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
@@ -947,7 +947,7 @@
 </histogram>
 
 <histogram name="UMA.TruncatedEvents.UserAction" units="events"
-    expires_after="2024-07-28">
+    expires_after="2024-08-04">
   <owner>rkaplow@chromium.org</owner>
   <owner>src/base/metrics/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/update_engine/histograms.xml b/tools/metrics/histograms/metadata/update_engine/histograms.xml
index a6876bc..2ab2539 100644
--- a/tools/metrics/histograms/metadata/update_engine/histograms.xml
+++ b/tools/metrics/histograms/metadata/update_engine/histograms.xml
@@ -39,7 +39,7 @@
 </histogram>
 
 <histogram name="UpdateEngine.Attempt.DownloadErrorCode"
-    enum="UpdateEngineDownloadErrorCode" expires_after="2024-06-02">
+    enum="UpdateEngineDownloadErrorCode" expires_after="2024-08-04">
   <owner>kimjae@chromium.org</owner>
   <owner>chromeos-core-services@google.com</owner>
   <summary>
@@ -54,7 +54,7 @@
 </histogram>
 
 <histogram name="UpdateEngine.Attempt.DownloadSource"
-    enum="UpdateEngineDownloadSource" expires_after="2024-06-02">
+    enum="UpdateEngineDownloadSource" expires_after="2024-08-04">
   <owner>kimjae@chromium.org</owner>
   <owner>chromeos-core-services@google.com</owner>
   <summary>
@@ -68,7 +68,7 @@
 </histogram>
 
 <histogram name="UpdateEngine.Attempt.DurationMinutes" units="minutes"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>kimjae@chromium.org</owner>
   <owner>chromeos-core-services@google.com</owner>
   <summary>
@@ -96,7 +96,7 @@
 </histogram>
 
 <histogram name="UpdateEngine.Attempt.InternalErrorCode"
-    enum="UpdateEngineErrorCode" expires_after="2024-06-02">
+    enum="UpdateEngineErrorCode" expires_after="2024-08-04">
   <owner>kimjae@chromium.org</owner>
   <owner>chromeos-core-services@google.com</owner>
   <summary>
@@ -181,7 +181,7 @@
 </histogram>
 
 <histogram name="UpdateEngine.Attempt.Result" enum="UpdateEngineAttemptResult"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>kimjae@chromium.org</owner>
   <owner>chromeos-core-services@google.com</owner>
   <summary>
@@ -284,7 +284,7 @@
 </histogram>
 
 <histogram name="UpdateEngine.Check.Result" enum="UpdateEngineCheckResult"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>kimjae@chromium.org</owner>
   <owner>chromeos-core-services@google.com</owner>
   <summary>
@@ -391,7 +391,7 @@
 </histogram>
 
 <histogram name="UpdateEngine.ConsumerAutoUpdate" enum="BooleanOptedOut"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>yuanpengni@chromium.org</owner>
   <owner>chromeos-core-services@google.com</owner>
   <summary>
@@ -488,7 +488,7 @@
 </histogram>
 
 <histogram name="UpdateEngine.FailedUpdateCount" units="count"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>kimjae@chromium.org</owner>
   <owner>chromeos-core-services@google.com</owner>
   <summary>
@@ -581,7 +581,7 @@
 </histogram>
 
 <histogram name="UpdateEngine.SuccessfulUpdate.AttemptCount" units="count"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>kimjae@chromium.org</owner>
   <owner>chromeos-core-services@google.com</owner>
   <summary>
@@ -690,7 +690,7 @@
 </histogram>
 
 <histogram name="UpdateEngine.SuccessfulUpdate.PayloadType"
-    enum="UpdateEnginePayloadFormat" expires_after="2024-06-02">
+    enum="UpdateEnginePayloadFormat" expires_after="2024-08-04">
   <owner>kimjae@chromium.org</owner>
   <owner>chromeos-core-services@google.com</owner>
   <summary>
@@ -717,7 +717,7 @@
 </histogram>
 
 <histogram name="UpdateEngine.SuccessfulUpdate.TotalDurationMinutes"
-    units="minutes" expires_after="2024-06-02">
+    units="minutes" expires_after="2024-08-04">
   <owner>kimjae@chromium.org</owner>
   <owner>chromeos-core-services@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/v8/histograms.xml b/tools/metrics/histograms/metadata/v8/histograms.xml
index 6ab9ab7..cda9415d 100644
--- a/tools/metrics/histograms/metadata/v8/histograms.xml
+++ b/tools/metrics/histograms/metadata/v8/histograms.xml
@@ -1136,14 +1136,14 @@
 </histogram>
 
 <histogram name="V8.GCIncrementalMarkingStart" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>hpayer@chromium.org</owner>
   <owner>v8-memory-sheriffs@google.com</owner>
   <summary>Time spent in starting incremental marking.</summary>
 </histogram>
 
 <histogram name="V8.GCIncrementalMarkingSum" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>mlippautz@chromium.org</owner>
   <owner>v8-memory-sheriffs@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/variations/histograms.xml b/tools/metrics/histograms/metadata/variations/histograms.xml
index 0265396c..b1a3a01 100644
--- a/tools/metrics/histograms/metadata/variations/histograms.xml
+++ b/tools/metrics/histograms/metadata/variations/histograms.xml
@@ -235,7 +235,7 @@
 </histogram>
 
 <histogram name="Variations.Headers.RequestContextCategory"
-    enum="VariationsHeadersRequestContextCategory" expires_after="2024-06-02">
+    enum="VariationsHeadersRequestContextCategory" expires_after="2024-08-04">
   <owner>asvitkine@chromium.org</owner>
   <owner>jwd@chromium.org</owner>
   <owner>caitlinfischer@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/web_apk/histograms.xml b/tools/metrics/histograms/metadata/web_apk/histograms.xml
index b57362a..529291f6 100644
--- a/tools/metrics/histograms/metadata/web_apk/histograms.xml
+++ b/tools/metrics/histograms/metadata/web_apk/histograms.xml
@@ -34,7 +34,7 @@
 </variants>
 
 <histogram name="WebApk.AppIdentityDialog.PendingImageUpdateDiffValue"
-    units="%" expires_after="2024-06-01">
+    units="%" expires_after="2024-08-04">
   <owner>finnur@chromium.org</owner>
   <owner>src/chrome/android/webapk/OWNERS</owner>
   <summary>
@@ -47,7 +47,7 @@
 </histogram>
 
 <histogram name="WebApk.AppIdentityDialog.PendingImageUpdateDiffValueScaled"
-    units="%" expires_after="2024-06-01">
+    units="%" expires_after="2024-08-04">
   <owner>finnur@chromium.org</owner>
   <owner>src/chrome/android/webapk/OWNERS</owner>
   <summary>
@@ -202,7 +202,7 @@
 </histogram>
 
 <histogram name="WebApk.Session.TotalDuration3{WebApkDistributorType}"
-    units="ms" expires_after="2024-06-02">
+    units="ms" expires_after="2024-08-04">
   <owner>hartmanng@chromium.org</owner>
   <owner>src/chrome/android/webapk/OWNERS</owner>
   <summary>
@@ -277,7 +277,7 @@
 </histogram>
 
 <histogram name="WebApk.Update.NumStaleUpdateRequestFiles" units="files"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>hartmanng@chromium.org</owner>
   <owner>src/chrome/android/webapk/OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/web_rtc/histograms.xml b/tools/metrics/histograms/metadata/web_rtc/histograms.xml
index d494548..0f94b2e4 100644
--- a/tools/metrics/histograms/metadata/web_rtc/histograms.xml
+++ b/tools/metrics/histograms/metadata/web_rtc/histograms.xml
@@ -294,7 +294,7 @@
 </histogram>
 
 <histogram name="WebRTC.Audio.AudioInterruptionMs" units="ms"
-    expires_after="2024-06-02">
+    expires_after="2024-08-04">
   <owner>hlundin@chromium.org</owner>
   <owner>ivoc@chromium.org</owner>
   <owner>webrtc-audio-uma@google.com</owner>
@@ -992,7 +992,7 @@
 </histogram>
 
 <histogram name="WebRTC.DesktopCapture.FrameRate.{CapturerType}" units="fps"
-    expires_after="2024-05-30">
+    expires_after="2024-08-04">
   <owner>henrika@chromium.org</owner>
   <owner>webrtc-dev@chromium.org</owner>
   <summary>
@@ -1020,7 +1020,7 @@
 </histogram>
 
 <histogram name="WebRTC.DesktopCapture.RefreshRate.{CapturerType}" units="fps"
-    expires_after="2024-05-30">
+    expires_after="2024-08-04">
   <owner>henrika@chromium.org</owner>
   <owner>webrtc-dev@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/webapps/histograms.xml b/tools/metrics/histograms/metadata/webapps/histograms.xml
index 21a0a20..f09a4c6 100644
--- a/tools/metrics/histograms/metadata/webapps/histograms.xml
+++ b/tools/metrics/histograms/metadata/webapps/histograms.xml
@@ -715,7 +715,7 @@
 </histogram>
 
 <histogram name="WebApp.IconDownloader.Result"
-    enum="WebAppIconDownloaderResult" expires_after="2024-06-02">
+    enum="WebAppIconDownloaderResult" expires_after="2024-08-04">
   <owner>dmurph@chromium.org</owner>
   <owner>desktop-pwas-team@google.com</owner>
   <summary>
@@ -1251,7 +1251,7 @@
 
 <histogram
     name="WebApp.Preinstalled.WindowExperiment.{UserGroup}.{LinkCapturingChange}"
-    enum="DefaultAppName" expires_after="2024-05-05">
+    enum="DefaultAppName" expires_after="2024-08-04">
   <owner>glenrob@chromium.org</owner>
   <owner>desktop-pwas-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/windows/histograms.xml b/tools/metrics/histograms/metadata/windows/histograms.xml
index 94de37a..bbd9c50 100644
--- a/tools/metrics/histograms/metadata/windows/histograms.xml
+++ b/tools/metrics/histograms/metadata/windows/histograms.xml
@@ -102,7 +102,7 @@
 </histogram>
 
 <histogram name="Windows.HypervPresent" enum="BooleanEnabled"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>rkc@chromium.org</owner>
   <owner>vnagarnaik@google.com</owner>
   <owner>rockot@chromium.org</owner>
@@ -210,7 +210,7 @@
 </histogram>
 
 <histogram name="Windows.ProcessorFamily" enum="ProcessorFamily"
-    expires_after="2024-06-01">
+    expires_after="2024-08-04">
   <owner>rkc@chromium.org</owner>
   <owner>vnagarnaik@google.com</owner>
   <owner>rockot@chromium.org</owner>
diff --git a/tools/perf/contrib/shared_storage/README.md b/tools/perf/contrib/shared_storage/README.md
new file mode 100644
index 0000000..191dc89
--- /dev/null
+++ b/tools/perf/contrib/shared_storage/README.md
@@ -0,0 +1,60 @@
+<!-- Copyright 2024 The Chromium Authors
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file.
+-->
+
+# Shared Storage Performance Benchmarks
+
+## Overview
+
+This directory houses performance benchmark tests for the Shared Storage API.
+
+See the
+[Shared Storage API Explainer](https://github.com/WICG/shared-storage/blob/main/README.md)
+for more details about the API itself.
+
+## How to Run
+
+This assumes you are in the root directory of a local
+[chromium checkout](https://chromium.googlesource.com/chromium/src/+/main/docs/get_the_code.md).
+
+Select one of the available shared storage benchmarks, where the qualifier
+describes the size of the database after setup and prior to the test:
+* `shared_storage.fresh`
+* `shared_storage.small`
+* `shared_storage.medium`
+* `shared_storage.large`
+
+Select a browser type:
+* `system`
+* `stable`
+
+Run the following bash command, substituting in your chosen benchmark and
+browser type:
+```bash
+tools/perf/run_benchmark shared_storage.small --browser=system
+```
+
+Optionally, you can qualify your command further as follows:
+* `--story-filter=STORY_FILTER`
+        Only use stories whose names match the given filter regexp.
+* `--iterations=ITERATIONS`
+        Override the default number of action iterations per story with the
+        given number.
+* `--verbose-cpu-metrics`
+        Enables non-UMA CPU metrics.
+* `--verbose-memory-metrics`
+        Enables non-UMA memory metrics.
+* `-v`, `--verbose`
+        Increase verbosity level (repeat as needed).
+
+More options can be found by running:
+```bash
+tools/perf/run_benchmark run --help
+
+```
+
+For example, a modified version of the original benchmark command is:
+```bash
+tools/perf/run_benchmark shared_storage.small --browser=system --story-filter=Append --iterations=5 --verbose-cpu-metrics --verbose-memory-metrics --verbose
+```
diff --git a/tools/perf/contrib/shared_storage/fresh_with_worklet.html b/tools/perf/contrib/shared_storage/fresh_with_worklet.html
new file mode 100644
index 0000000..7694b91
--- /dev/null
+++ b/tools/perf/contrib/shared_storage/fresh_with_worklet.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Shared Storage Test, Start Fresh</title>
+  <script>
+    window.sharedStorage.worklet.addModule('worklet.js');
+    window.sharedStorage.clear();
+  </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/tools/perf/contrib/shared_storage/large_with_worklet.html b/tools/perf/contrib/shared_storage/large_with_worklet.html
new file mode 100644
index 0000000..b0ae7445
--- /dev/null
+++ b/tools/perf/contrib/shared_storage/large_with_worklet.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Shared Storage Test, Large DB</title>
+  <script>
+    window.sharedStorage.worklet.addModule('worklet.js');
+    window.sharedStorage.clear();
+    for (let i = 0; i < 9000; i++) {
+      sharedStorage.set(i.toString(), 'x');
+    }
+  </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/tools/perf/contrib/shared_storage/medium_with_worklet.html b/tools/perf/contrib/shared_storage/medium_with_worklet.html
new file mode 100644
index 0000000..ed87188fa
--- /dev/null
+++ b/tools/perf/contrib/shared_storage/medium_with_worklet.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Shared Storage Test, Medium DB</title>
+  <script>
+    window.sharedStorage.worklet.addModule('worklet.js');
+    window.sharedStorage.clear();
+    for (let i = 0; i < 1000; i++) {
+      sharedStorage.set(i.toString(), 'x');
+    }
+  </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/tools/perf/contrib/shared_storage/page_set.py b/tools/perf/contrib/shared_storage/page_set.py
new file mode 100644
index 0000000..5fda3fd
--- /dev/null
+++ b/tools/perf/contrib/shared_storage/page_set.py
@@ -0,0 +1,278 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import json
+import logging
+import os
+import py_utils
+import six
+from socket import timeout
+
+from telemetry import story
+from telemetry.internal.backends.chrome_inspector import websocket
+from telemetry.page import page as page_module
+from telemetry.page import shared_page_state
+
+# Timeouts in seconds.
+_ACTION_TIMEOUT = 2
+_NAVIGATION_TIMEOUT = 90
+
+# Placeholder substring for index value in the action script template.
+_INDEX_PLACEHOLDER = '{{ index }}'
+
+# Note that the true default number of iterations is defined by
+# `_DEFAULT_NUM_ITERATIONS` in
+# tools/perf/contrib/shared_storage/shared_storage.py.
+_PLACEHOLDER_ITERATIONS = 10
+
+
+# Replaces `_INDEX_PLACEHOLDER` in a param value with the index value.
+def _Render(template, index):
+  if not isinstance(template, str):
+    raise TypeError("Expected template to be a str, but got " +
+                    str(type(template)))
+  if not isinstance(index, int):
+    raise TypeError("Expected index to be an int, but got " + str(type(index)))
+  return template.replace(_INDEX_PLACEHOLDER, str(index))
+
+
+# Replaces `_INDEX_PLACEHOLDER` in an event dict with the index value.
+def _RenderEvent(event_template, index):
+  if not isinstance(event_template, dict):
+    raise TypeError("Expected event_template to be a dict, but got " +
+                    str(type(event_template)))
+  if 'params' not in event_template:
+    return event_template
+  new_params = {
+      key: _Render(event_template['params'][key], index)
+      for key in event_template['params']
+  }
+  return {
+      key: event_template[key] if key != 'params' else new_params
+      for key in event_template
+  }
+
+
+# Replaces `_INDEX_PLACEHOLDER` in a list of event dicts with the index value.
+def _RenderEvents(events_template, index):
+  if not isinstance(events_template, list):
+    raise TypeError("Expected events_template to be a list, but got " +
+                    str(type(events_template)))
+  return [_RenderEvent(event, index) for event in events_template]
+
+
+# Extracts origin from a URL.
+def _GetOriginFromURL(url):
+  parse_result = six.moves.urllib.parse.urlparse(url)
+  return '://'.join([parse_result[0], parse_result[1]])
+
+
+class _MetaSharedStorageStory(type):
+  """Metaclass for SharedStorageStory."""
+
+  @property
+  def ABSTRACT_STORY(cls):
+    """Class field marking whether the class is abstract.
+
+    If true, the story will NOT be instantiated and added to a Shared Storage
+    story set. This field is NOT inherited by subclasses (that's why it's
+    defined on the metaclass).
+    """
+    return cls.__dict__.get('ABSTRACT_STORY', False)
+
+
+class SharedStorageStory(
+    six.with_metaclass(_MetaSharedStorageStory, page_module.Page)):
+  """Abstract base class for SharedStorage user stories."""
+
+  NAME = NotImplemented
+  ABSTRACT_STORY = True
+  # The setup script is run once per story, before the first iteration of the
+  # action script.
+  SETUP_SCRIPT = ""
+  # The shared storage events that should happen in the setup, as a list of
+  # dictionaries.
+  # See the docstring of `InspectorBackend.WaitForSharedStorageEvents()` in
+  # third_party/catapult/telemetry/telemetry/internal/backends/chrome_inspector
+  # /inspector_backend.py for more information.
+  EXPECTED_SETUP_EVENTS = []
+  # Template for script of the action to be iterated. Instances of
+  # `_INDEX_PLACEHOLDER` will be replaced with the value of iteration's index.
+  ACTION_SCRIPT_TEMPLATE = NotImplemented
+  # The shared storage events that should happen in the action, as a list of
+  # dictionaries.
+  # See the docstring of `InspectorBackend.WaitForSharedStorageEvents()` in
+  # third_party/catapult/telemetry/telemetry/internal/backends/chrome_inspector
+  # /inspector_backend.py for more information.
+  EXPECTED_ACTION_EVENTS_TEMPLATE = NotImplemented
+  # Whether the page should be reloaded after each action iteration in order to
+  # refresh the database.
+  RENAVIGATE_AFTER_ACTION = False
+
+  def __init__(self,
+               story_set,
+               url,
+               shared_page_state_class,
+               enable_memory_metric,
+               iterations=_PLACEHOLDER_ITERATIONS,
+               verbosity=0):
+    super(SharedStorageStory,
+          self).__init__(shared_page_state_class=shared_page_state_class,
+                         page_set=story_set,
+                         name=self.NAME,
+                         url=url)
+    self._enable_memory_metric = enable_memory_metric
+    self._iterations = iterations
+    self._verbosity = verbosity
+
+  # TODO(crbug.com/1516507): Wait for relevant Shared Storage timing histograms
+  # to be recorded in each step, rather than simply the event notifications.
+  #
+  # Note that this will require retrieving histograms from renderer processes;
+  # the current DevTools Protocol 'Browser.getHistograms' method only retrieves
+  # browser-process histograms.
+  #
+  # Alternatively, implement the ability to log what the expected histogram
+  # total counts should be at the end of the test run.
+  def RunPageInteractions(self, action_runner):
+    action_runner.tab.WaitForDocumentReadyStateToBeComplete(_NAVIGATION_TIMEOUT)
+    self.LogMetadataIfVerbose(action_runner, False)
+
+    action_runner.tab.EnableSharedStorageNotifications()
+    self._RunSharedStorageSetUp(action_runner)
+
+    for index in range(self._iterations):
+      try:
+        self._RunSharedStorageAction(action_runner, index)
+      except timeout as t:
+        logging.warning("%s's action timed out after %d seconds: %s" %
+                        (self.NAME, _ACTION_TIMEOUT, repr(t)))
+      except websocket.WebSocketTimeoutException as w:
+        logging.warning("%s's action timed out after %d seconds: %s" %
+                        (self.NAME, _ACTION_TIMEOUT, repr(w)))
+
+      # Reload the page if necessary. Otherwise, skip.
+      if self.RENAVIGATE_AFTER_ACTION:
+        url = self.file_path_url_with_scheme if self.is_file else self.url
+        action_runner.Navigate(url,
+                               self.script_to_evaluate_on_commit,
+                               timeout_in_seconds=_NAVIGATION_TIMEOUT)
+        action_runner.tab.WaitForDocumentReadyStateToBeComplete(
+            _NAVIGATION_TIMEOUT)
+        action_runner.tab.ClearSharedStorageNotifications()
+
+    if self._enable_memory_metric:
+      action_runner.MeasureMemory(deterministic_mode=True)
+
+    self.LogMetadataIfVerbose(action_runner, True)
+
+    # Navigate away to an untracked page to trigger recording of metrics
+    # requiring document destruction.
+    action_runner.Navigate('about:blank',
+                           self.script_to_evaluate_on_commit,
+                           timeout_in_seconds=_NAVIGATION_TIMEOUT)
+    action_runner.tab.DisableSharedStorageNotifications()
+
+  def _RunSharedStorageSetUp(self, action_runner):
+    if self.SETUP_SCRIPT == "":
+      logging.info("no setup")
+      return
+    logging.info("".join(["running set up: ", self.SETUP_SCRIPT]))
+    action_runner.tab.EvaluateJavaScript(self.SETUP_SCRIPT, promise=True)
+    action_runner.tab.WaitForSharedStorageEvents(self.EXPECTED_SETUP_EVENTS,
+                                                 mode='strict',
+                                                 timeout=_ACTION_TIMEOUT)
+    action_runner.tab.ClearSharedStorageNotifications()
+
+  def _RunSharedStorageAction(self, action_runner, index):
+    logging.info("".join([
+        "running iteration ",
+        str(index + 1), ": ", self.ACTION_SCRIPT_TEMPLATE
+    ]))
+    if self.ACTION_SCRIPT_TEMPLATE.find(_INDEX_PLACEHOLDER) != -1:
+      action_runner.tab.EvaluateJavaScript(self.ACTION_SCRIPT_TEMPLATE,
+                                           promise=True,
+                                           index=index)
+    else:
+      action_runner.tab.EvaluateJavaScript(self.ACTION_SCRIPT_TEMPLATE,
+                                           promise=True)
+    expected_events = _RenderEvents(self.EXPECTED_ACTION_EVENTS_TEMPLATE,
+                                    index=index)
+    action_runner.tab.WaitForSharedStorageEvents(expected_events,
+                                                 mode='strict',
+                                                 timeout=_ACTION_TIMEOUT)
+    action_runner.tab.ClearSharedStorageNotifications()
+
+  def LogMetadataIfVerbose(self, action_runner, is_post):
+    if self._verbosity < 1:
+      return
+    prefix = 'Post' if is_post else 'Pre'
+    template = "-test shared storage metadata:\norigin: %s\n%s\n"
+    try:
+      origin = _GetOriginFromURL(action_runner.tab.url)
+      metadata = action_runner.tab.GetSharedStorageMetadata(origin)
+      json_data = json.dumps(metadata, indent=2)
+      log_msg = prefix + (template % (origin, json_data))
+      logging.info(log_msg)
+    except timeout as t:
+      logging.warning("%s timed out getting %s-test metadata: %s" %
+                      (self.NAME, prefix, repr(t)))
+    except websocket.WebSocketTimeoutException as w:
+      logging.warning("%s timed out getting %s-test metadata: %s" %
+                      (self.NAME, prefix, repr(w)))
+
+
+def IterAllSharedStorageStoryClasses():
+  """Generator for SharedStorage stories.
+
+  Yields:
+    All appropriate SharedStorageStory subclasses defining stories.
+  """
+  start_dir = os.path.dirname(os.path.abspath(__file__))
+  # Sort the classes by their names so that their order is stable and
+  # deterministic.
+  for unused_cls_name, cls in sorted(
+      py_utils.discover.DiscoverClasses(
+          start_dir=start_dir,
+          top_level_dir=os.path.dirname(start_dir),
+          base_class=SharedStorageStory).items()):
+    yield cls
+
+
+class SharedStorageStorySet(story.StorySet):
+
+  def __init__(self,
+               url,
+               enable_memory_metric,
+               user_agent='desktop',
+               iterations=_PLACEHOLDER_ITERATIONS,
+               verbosity=0):
+    super(SharedStorageStorySet, self).__init__()
+    if user_agent == 'mobile':
+      shared_page_state_class = shared_page_state.SharedMobilePageState
+    elif user_agent == 'desktop':
+      shared_page_state_class = shared_page_state.SharedDesktopPageState
+    else:
+      raise ValueError('user_agent %s is unrecognized' % user_agent)
+
+    def IncludeStory(story_class):
+      return not story_class.ABSTRACT_STORY
+
+    for story_class in IterAllSharedStorageStoryClasses():
+      if IncludeStory(story_class):
+        if user_agent == 'mobile':
+          # Extra browser args are disabled in the mobile user agent
+          story_class.EXTRA_BROWSER_ARGUMENTS = []
+          logging.warning(''.join([
+              'Extra browser arguments are not ',
+              'available; unable to enable shared ',
+              'storage from the command line.'
+          ]))
+        self.AddStory(
+            story_class(self,
+                        url=url,
+                        shared_page_state_class=shared_page_state_class,
+                        enable_memory_metric=enable_memory_metric,
+                        iterations=iterations,
+                        verbosity=verbosity))
diff --git a/tools/perf/contrib/shared_storage/pages.py b/tools/perf/contrib/shared_storage/pages.py
new file mode 100644
index 0000000..3223a287
--- /dev/null
+++ b/tools/perf/contrib/shared_storage/pages.py
@@ -0,0 +1,609 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from contrib.shared_storage.page_set import SharedStorageStory
+
+
+class SharedStorageDocumentSetStory(SharedStorageStory):
+  NAME = "SharedStorageDocumentSet"
+  ABSTRACT_STORY = False
+  ACTION_SCRIPT_TEMPLATE = """
+  window.sharedStorage.set('a{{ index }}', 'b{{ index }}');
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentSet',
+      'params': {
+          'key': 'a{{ index }}',
+          'value': 'b{{ index }}'
+      }
+  }]
+
+
+class SharedStorageDocumentAppendStory(SharedStorageStory):
+  NAME = "SharedStorageDocumentAppend"
+  ABSTRACT_STORY = False
+  ACTION_SCRIPT_TEMPLATE = """
+  window.sharedStorage.append('a{{ index }}', 'b{{ index }}');
+  window.sharedStorage.append('a{{ index }}', 'c{{ index }}');
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentAppend',
+      'params': {
+          'key': 'a{{ index }}',
+          'value': 'b{{ index }}'
+      }
+  }, {
+      'type': 'documentAppend',
+      'params': {
+          'key': 'a{{ index }}',
+          'value': 'c{{ index }}'
+      }
+  }]
+
+
+class SharedStorageDocumentDeleteStory(SharedStorageStory):
+  NAME = "SharedStorageDocumentDelete"
+  ABSTRACT_STORY = False
+  ACTION_SCRIPT_TEMPLATE = """
+  window.sharedStorage.set('a{{ index }}', 'b{{ index }}');
+  window.sharedStorage.delete('a{{ index }}');
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentSet',
+      'params': {
+          'key': 'a{{ index }}',
+          'value': 'b{{ index }}'
+      }
+  }, {
+      'type': 'documentDelete',
+      'params': {
+          'key': 'a{{ index }}'
+      }
+  }]
+
+
+class SharedStorageDocumentClearStory(SharedStorageStory):
+  NAME = "SharedStorageDocumentClear"
+  ABSTRACT_STORY = False
+  ACTION_SCRIPT_TEMPLATE = """
+  window.sharedStorage.set('a{{ index }}', 'b{{ index }}')
+  window.sharedStorage.clear()
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentSet',
+      'params': {
+          'key': 'a{{ index }}',
+          'value': 'b{{ index }}'
+      }
+  }, {
+      'type': 'documentClear'
+  }]
+
+
+class SharedStorageWorkletRunSetStory(SharedStorageStory):
+  NAME = "SharedStorageWorkletRunSet"
+  ABSTRACT_STORY = False
+  ACTION_SCRIPT_TEMPLATE = """
+  sharedStorage.run('run-set-operation',
+                    {data: {'key': 'a{{ index }}',
+                            'value': 'b{{ index }}'},
+                     keepAlive: true});
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentRun'
+  }, {
+      'type': 'workletSet',
+      'params': {
+          'key': 'a{{ index }}',
+          'value': 'b{{ index }}'
+      }
+  }]
+
+
+class SharedStorageWorkletSelectURLSetStory(SharedStorageStory):
+  NAME = "SharedStorageWorkletSelectURLSet"
+  ABSTRACT_STORY = False
+  ACTION_SCRIPT_TEMPLATE = """
+  sharedStorage.selectURL('selecturl-set-operation',
+                          [{url: 'with_worklet.html'}],
+                          {data: {'key': 'a{{ index }}',
+                                  'value': 'b{{ index }}'},
+                           keepAlive: true});
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentSelectURL'
+  }, {
+      'type': 'workletSet',
+      'params': {
+          'key': 'a{{ index }}',
+          'value': 'b{{ index }}'
+      }
+  }]
+
+
+class SharedStorageWorkletRunAppendStory(SharedStorageStory):
+  NAME = "SharedStorageWorkletRunAppend"
+  ABSTRACT_STORY = False
+  ACTION_SCRIPT_TEMPLATE = """
+  sharedStorage.run('run-append-operation',
+                    {data: {'key': 'a{{ index }}',
+                            'value': 'b{{ index }}'},
+                     keepAlive: true});
+  sharedStorage.run('run-append-operation',
+                    {data: {'key': 'a{{ index }}',
+                            'value': 'c{{ index }}'},
+                     keepAlive: true});
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentRun'
+  }, {
+      'type': 'documentRun'
+  }, {
+      'type': 'workletAppend',
+      'params': {
+          'key': 'a{{ index }}',
+          'value': 'b{{ index }}'
+      }
+  }, {
+      'type': 'workletAppend',
+      'params': {
+          'key': 'a{{ index }}',
+          'value': 'c{{ index }}'
+      }
+  }]
+
+
+class SharedStorageWorkletSelectURLAppendStory(SharedStorageStory):
+  NAME = "SharedStorageWorkletSelectURLAppend"
+  ABSTRACT_STORY = False
+  ACTION_SCRIPT_TEMPLATE = """
+  sharedStorage.selectURL('selecturl-append-operation',
+                          [{url: 'with_worklet.html'}],
+                          {data: {'key': 'a{{ index }}',
+                                  'value': 'b{{ index }}'},
+                           keepAlive: true});
+  sharedStorage.selectURL('selecturl-append-operation',
+                          [{url: 'with_worklet.html'}],
+                          {data: {'key': 'a{{ index }}',
+                                  'value': 'c{{ index }}'},
+                           keepAlive: true});
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentSelectURL'
+  }, {
+      'type': 'documentSelectURL'
+  }, {
+      'type': 'workletAppend',
+      'params': {
+          'key': 'a{{ index }}',
+          'value': 'b{{ index }}'
+      }
+  }, {
+      'type': 'workletAppend',
+      'params': {
+          'key': 'a{{ index }}',
+          'value': 'c{{ index }}'
+      }
+  }]
+
+
+class SharedStorageWorkletRunDeleteStory(SharedStorageStory):
+  NAME = "SharedStorageWorkletRunDelete"
+  ABSTRACT_STORY = False
+  ACTION_SCRIPT_TEMPLATE = """
+  sharedStorage.set('a{{ index }}', 'any');
+  sharedStorage.run('run-delete-operation',
+                    {data: {'key': 'a{{ index }}'},
+                     keepAlive: true});
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentSet',
+      'params': {
+          'key': 'a{{ index }}',
+          'value': 'any'
+      }
+  }, {
+      'type': 'documentRun'
+  }, {
+      'type': 'workletDelete',
+      'params': {
+          'key': 'a{{ index }}'
+      }
+  }]
+
+
+class SharedStorageWorkletSelectURLDeleteStory(SharedStorageStory):
+  NAME = "SharedStorageWorkletSelectURLDelete"
+  ABSTRACT_STORY = False
+  ACTION_SCRIPT_TEMPLATE = """
+  sharedStorage.set('a{{ index }}', 'any');
+  sharedStorage.selectURL('selecturl-delete-operation',
+                          [{url: 'with_worklet.html'}],
+                          {data: {'key': 'a{{ index }}'},
+                           keepAlive: true});
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentSet',
+      'params': {
+          'key': 'a{{ index }}',
+          'value': 'any'
+      }
+  }, {
+      'type': 'documentSelectURL'
+  }, {
+      'type': 'workletDelete',
+      'params': {
+          'key': 'a{{ index }}'
+      }
+  }]
+
+
+class SharedStorageWorkletRunClearStory(SharedStorageStory):
+  NAME = "SharedStorageWorkletRunClear"
+  ABSTRACT_STORY = False
+  ACTION_SCRIPT_TEMPLATE = """
+  sharedStorage.set('a{{ index }}', 'any');
+  sharedStorage.run('run-clear-operation',
+                    {keepAlive: true});
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentSet',
+      'params': {
+          'key': 'a{{ index }}',
+          'value': 'any'
+      }
+  }, {
+      'type': 'documentRun'
+  }, {
+      'type': 'workletClear'
+  }]
+  RENAVIGATE_AFTER_ACTION = True
+
+
+class SharedStorageWorkletSelectURLClearStory(SharedStorageStory):
+  NAME = "SharedStorageWorkletSelectURLClear"
+  ABSTRACT_STORY = False
+  ACTION_SCRIPT_TEMPLATE = """
+  sharedStorage.set('a{{ index }}', 'any');
+  sharedStorage.selectURL('selecturl-clear-operation',
+                          [{url: 'with_worklet.html'}],
+                          {keepAlive: true});
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentSet',
+      'params': {
+          'key': 'a{{ index }}',
+          'value': 'any'
+      }
+  }, {
+      'type': 'documentSelectURL'
+  }, {
+      'type': 'workletClear'
+  }]
+  RENAVIGATE_AFTER_ACTION = True
+
+
+class SharedStorageWorkletRunGetStory(SharedStorageStory):
+  NAME = "SharedStorageWorkletRunGet"
+  ABSTRACT_STORY = False
+  SETUP_SCRIPT = """
+  sharedStorage.set('k0', 'v0');
+  """
+  EXPECTED_SETUP_EVENTS = [{
+      'type': 'documentSet',
+      'params': {
+          'key': 'k0',
+          'value': 'v0'
+      }
+  }]
+  ACTION_SCRIPT_TEMPLATE = """
+  sharedStorage.run('run-get-operation',
+                    {data: {'key': 'k0'},
+                     keepAlive: true});
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentRun'
+  }, {
+      'type': 'workletGet',
+      'params': {
+          'key': 'k0'
+      }
+  }]
+
+
+class SharedStorageWorkletSelectURLGetStory(SharedStorageStory):
+  NAME = "SharedStorageWorkletSelectURLGet"
+  ABSTRACT_STORY = False
+  SETUP_SCRIPT = """
+  sharedStorage.set('k0', 'v0')
+  """
+  EXPECTED_SETUP_EVENTS = [{
+      'type': 'documentSet',
+      'params': {
+          'key': 'k0',
+          'value': 'v0'
+      }
+  }]
+  ACTION_SCRIPT_TEMPLATE = """
+  sharedStorage.selectURL('selecturl-get-operation',
+                          [{url: 'with_worklet.html'}],
+                          {data: {'key': 'k0'},
+                           keepAlive: true});
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentSelectURL'
+  }, {
+      'type': 'workletGet',
+      'params': {
+          'key': 'k0'
+      }
+  }]
+
+
+class SharedStorageWorkletRunLengthStory(SharedStorageStory):
+  NAME = "SharedStorageWorkletRunLength"
+  ABSTRACT_STORY = False
+  SETUP_SCRIPT = """
+  sharedStorage.set('k0', 'v0')
+  sharedStorage.set('k1', 'v1')
+  sharedStorage.set('k2', 'v2')
+  """
+  EXPECTED_SETUP_EVENTS = [{
+      'type': 'documentSet',
+      'params': {
+          'key': 'k0',
+          'value': 'v0'
+      }
+  }, {
+      'type': 'documentSet',
+      'params': {
+          'key': 'k1',
+          'value': 'v1'
+      }
+  }, {
+      'type': 'documentSet',
+      'params': {
+          'key': 'k2',
+          'value': 'v2'
+      }
+  }]
+  ACTION_SCRIPT_TEMPLATE = """
+  sharedStorage.run('run-length-operation',
+                    {keepAlive: true});
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentRun'
+  }, {
+      'type': 'workletLength'
+  }]
+
+
+class SharedStorageWorkletSelectURLLengthStory(SharedStorageStory):
+  NAME = "SharedStorageWorkletSelectURLLength"
+  ABSTRACT_STORY = False
+  SETUP_SCRIPT = """
+  sharedStorage.set('k0', 'v0');
+  sharedStorage.set('k1', 'v1');
+  sharedStorage.set('k2', 'v2');
+  """
+  EXPECTED_SETUP_EVENTS = [{
+      'type': 'documentSet',
+      'params': {
+          'key': 'k0',
+          'value': 'v0'
+      }
+  }, {
+      'type': 'documentSet',
+      'params': {
+          'key': 'k1',
+          'value': 'v1'
+      }
+  }, {
+      'type': 'documentSet',
+      'params': {
+          'key': 'k2',
+          'value': 'v2'
+      }
+  }]
+  ACTION_SCRIPT_TEMPLATE = """
+  sharedStorage.selectURL('selecturl-length-operation',
+                          [{url: 'with_worklet.html'}],
+                          {keepAlive: true});
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentSelectURL'
+  }, {
+      'type': 'workletLength'
+  }]
+
+
+class SharedStorageWorkletRunKeysStory(SharedStorageStory):
+  NAME = "SharedStorageWorkletRunKeys"
+  ABSTRACT_STORY = False
+  SETUP_SCRIPT = """
+  sharedStorage.set('k0', 'v0')
+  sharedStorage.set('k1', 'v1')
+  sharedStorage.set('k2', 'v2')
+  """
+  EXPECTED_SETUP_EVENTS = [{
+      'type': 'documentSet',
+      'params': {
+          'key': 'k0',
+          'value': 'v0'
+      }
+  }, {
+      'type': 'documentSet',
+      'params': {
+          'key': 'k1',
+          'value': 'v1'
+      }
+  }, {
+      'type': 'documentSet',
+      'params': {
+          'key': 'k2',
+          'value': 'v2'
+      }
+  }]
+  ACTION_SCRIPT_TEMPLATE = """
+  sharedStorage.run('run-keys-operation',
+                    {keepAlive: true});
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentRun'
+  }, {
+      'type': 'workletKeys'
+  }]
+
+
+class SharedStorageWorkletSelectURLKeysStory(SharedStorageStory):
+  NAME = "SharedStorageWorkletSelectURLKeys"
+  ABSTRACT_STORY = False
+  SETUP_SCRIPT = """
+  sharedStorage.set('k0', 'v0');
+  sharedStorage.set('k1', 'v1');
+  sharedStorage.set('k2', 'v2');
+  """
+  EXPECTED_SETUP_EVENTS = [{
+      'type': 'documentSet',
+      'params': {
+          'key': 'k0',
+          'value': 'v0'
+      }
+  }, {
+      'type': 'documentSet',
+      'params': {
+          'key': 'k1',
+          'value': 'v1'
+      }
+  }, {
+      'type': 'documentSet',
+      'params': {
+          'key': 'k2',
+          'value': 'v2'
+      }
+  }]
+  ACTION_SCRIPT_TEMPLATE = """
+  sharedStorage.selectURL('selecturl-keys-operation',
+                          [{url: 'with_worklet.html'}],
+                          {keepAlive: true});
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentSelectURL'
+  }, {
+      'type': 'workletKeys'
+  }]
+
+
+class SharedStorageWorkletRunEntriesStory(SharedStorageStory):
+  NAME = "SharedStorageWorkletRunEntries"
+  ABSTRACT_STORY = False
+  SETUP_SCRIPT = """
+  sharedStorage.set('k0', 'v0')
+  sharedStorage.set('k1', 'v1')
+  sharedStorage.set('k2', 'v2')
+  """
+  EXPECTED_SETUP_EVENTS = [{
+      'type': 'documentSet',
+      'params': {
+          'key': 'k0',
+          'value': 'v0'
+      }
+  }, {
+      'type': 'documentSet',
+      'params': {
+          'key': 'k1',
+          'value': 'v1'
+      }
+  }, {
+      'type': 'documentSet',
+      'params': {
+          'key': 'k2',
+          'value': 'v2'
+      }
+  }]
+  ACTION_SCRIPT_TEMPLATE = """
+  sharedStorage.run('run-entries-operation',
+                    {keepAlive: true});
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentRun'
+  }, {
+      'type': 'workletEntries'
+  }]
+
+
+class SharedStorageWorkletSelectURLEntriesStory(SharedStorageStory):
+  NAME = "SharedStorageWorkletSelectURLEntries"
+  ABSTRACT_STORY = False
+  SETUP_SCRIPT = """
+  sharedStorage.set('k0', 'v0');
+  sharedStorage.set('k1', 'v1');
+  sharedStorage.set('k2', 'v2');
+  """
+  EXPECTED_SETUP_EVENTS = [{
+      'type': 'documentSet',
+      'params': {
+          'key': 'k0',
+          'value': 'v0'
+      }
+  }, {
+      'type': 'documentSet',
+      'params': {
+          'key': 'k1',
+          'value': 'v1'
+      }
+  }, {
+      'type': 'documentSet',
+      'params': {
+          'key': 'k2',
+          'value': 'v2'
+      }
+  }]
+  ACTION_SCRIPT_TEMPLATE = """
+  sharedStorage.selectURL('selecturl-entries-operation',
+                          [{url: 'with_worklet.html'}],
+                          {keepAlive: true});
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentSelectURL'
+  }, {
+      'type': 'workletEntries'
+  }]
+
+
+class SharedStorageWorkletRunRemainingBudgetStory(SharedStorageStory):
+  NAME = "SharedStorageWorkletRunRemainingBudget"
+  ABSTRACT_STORY = False
+  ACTION_SCRIPT_TEMPLATE = """
+  sharedStorage.run('run-remainingbudget-operation',
+                    {keepAlive: true});
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentRun'
+  }, {
+      'type': 'workletRemainingBudget'
+  }]
+
+
+class SharedStorageWorkletSelectURLRemainingBudgetStory(SharedStorageStory):
+  NAME = "SharedStorageWorkletSelectURLRemainingBudget"
+  ABSTRACT_STORY = False
+  ACTION_SCRIPT_TEMPLATE = """
+  sharedStorage.selectURL('selecturl-remainingbudget-operation',
+                          [{url: 'with_worklet.html'}],
+                          {keepAlive: true});
+  """
+  EXPECTED_ACTION_EVENTS_TEMPLATE = [{
+      'type': 'documentSelectURL'
+  }, {
+      'type': 'workletRemainingBudget'
+  }]
+
+
+class SharedStorageDocumentAddModuleStory(SharedStorageStory):
+  NAME = "SharedStorageDocumentAddModule"
+  ABSTRACT_STORY = False
+  ACTION_SCRIPT_TEMPLATE = """"""
+  EXPECTED_ACTION_EVENTS_TEMPLATE = []
+  RENAVIGATE_AFTER_ACTION = True
diff --git a/tools/perf/contrib/shared_storage/shared_storage.py b/tools/perf/contrib/shared_storage/shared_storage.py
new file mode 100644
index 0000000..316b46f
--- /dev/null
+++ b/tools/perf/contrib/shared_storage/shared_storage.py
@@ -0,0 +1,179 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from benchmarks import memory
+from contrib.shared_storage import page_set
+from core import perf_benchmark
+
+from telemetry import benchmark
+from telemetry.timeline import chrome_trace_category_filter
+from telemetry.web_perf import timeline_based_measurement
+
+# Shared-storage-related histograms to measure.
+_SHARED_STORAGE_UMA_HISTOGRAMS = [
+    "Storage.SharedStorage.Document.Timing.AddModule",
+    "Storage.SharedStorage.Document.Timing.Append",
+    "Storage.SharedStorage.Document.Timing.Clear",
+    "Storage.SharedStorage.Document.Timing.Delete",
+    "Storage.SharedStorage.Document.Timing.Run",
+    "Storage.SharedStorage.Document.Timing.Run.ExecutedInWorklet",
+    "Storage.SharedStorage.Document.Timing.SelectURL",
+    "Storage.SharedStorage.Document.Timing.SelectURL.ExecutedInWorklet",
+    "Storage.SharedStorage.Document.Timing.Set",
+    "Storage.SharedStorage.OnShutdown.NumSqlErrors",
+    "Storage.SharedStorage.Worklet.Timing.Append",
+    "Storage.SharedStorage.Worklet.Timing.Clear",
+    "Storage.SharedStorage.Worklet.Timing.Delete",
+    "Storage.SharedStorage.Worklet.Timing.Entries.Next",
+    "Storage.SharedStorage.Worklet.Timing.Get",
+    "Storage.SharedStorage.Worklet.Timing.Keys.Next",
+    "Storage.SharedStorage.Worklet.Timing.Length",
+    "Storage.SharedStorage.Worklet.Timing.RemainingBudget",
+    "Storage.SharedStorage.Worklet.Timing.Set",
+    "Storage.SharedStorage.Worklet.Timing.Values.Next",
+]
+
+# Default number of times to run each shared storage action in a story.
+_DEFAULT_NUM_ITERATIONS = 10
+
+# Minimum trace buffer size (in KB) to be used.
+_MIN_TRACE_BUFFER_SIZE = 200000
+
+
+class SharedStoragePerfBase(perf_benchmark.PerfBenchmark):
+  URL = 'file://fresh_with_worklet.html'
+  verbose_cpu_metrics = False
+  verbose_memory_metrics = False
+  iterations = _DEFAULT_NUM_ITERATIONS
+  verbosity = 0
+
+  @classmethod
+  def AddBenchmarkCommandLineArgs(cls, parser):
+    parser.add_option('--user-agent',
+                      action='store',
+                      type='string',
+                      default='desktop',
+                      help="Options are 'desktop' (the default) and 'mobile'.")
+    parser.add_option('--verbose-cpu-metrics',
+                      action='store_true',
+                      help='Enables non-UMA CPU metrics.')
+    parser.add_option('--verbose-memory-metrics',
+                      action='store_true',
+                      help='Enables non-UMA memory metrics.')
+    parser.add_option(
+        '--iterations',
+        action='store',
+        type='int',
+        default=_DEFAULT_NUM_ITERATIONS,
+        help='Number of times to repeat the test action for each test run.')
+
+  @classmethod
+  def ProcessCommandLineArgs(cls, parser, args):
+    cls.verbose_cpu_metrics = args.verbose_cpu_metrics
+    cls.verbose_memory_metrics = args.verbose_memory_metrics
+    cls.iterations = args.iterations
+    if cls.iterations <= 0:
+      raise ValueError('Got invalid value %d for iterations' % cls.iterations)
+
+  def SetExtraBrowserOptions(self, options):
+    # `options` is an instance of `browser_options.BrowserOptions`.
+    if self.verbose_memory_metrics:
+      memory.SetExtraBrowserOptionsForMemoryMeasurement(options)
+
+    options.AppendExtraBrowserArgs([
+        ''.join([
+            '--enable-features=',
+            'SharedStorageAPI:SharedStorageDebugDisabledMessage/true,',
+            'FencedFrames:implementation_type/mparch,',
+            'FencedFramesDefaultMode,', 'PrivacySandboxAdsAPIsOverride,',
+            'DefaultAllowPrivacySandboxAttestations'
+        ]), '--enable-privacy-sandbox-ads-apis'
+    ])
+
+  def CustomizeOptions(self, finder_options, possible_browser=None):
+    #`finder_options` is an instance of `browser_options.BrowserFinderOptions`.
+    #
+    # Normally, a subclass of `perf_benchmark.PerfBenchmark` should only
+    # override  SetExtraBrowserOptions to add more browser options rather than
+    # overriding CustomizeOptions. We need to access the `finder_options` to
+    # read the verbosity level, however, and this seems to be the best way to
+    # do it.
+    super(SharedStoragePerfBase, self).CustomizeOptions(finder_options)
+    self.verbosity = finder_options.verbosity
+
+  def CreateCoreTimelineBasedMeasurementOptions(self):
+    category_filter = chrome_trace_category_filter.CreateLowOverheadFilter()
+    if self.verbose_memory_metrics:
+      tbm_options = memory.CreateCoreTimelineBasedMemoryMeasurementOptions()
+
+      # The memory options only include the filters needed for memory
+      # measurement. We reintroduce the filters required for other metrics.
+      tbm_options.ExtendTraceCategoryFilter(
+          category_filter.filter_string.split(','))
+    else:
+      tbm_options = timeline_based_measurement.Options(category_filter)
+
+    buffer_size = self.iterations * _MIN_TRACE_BUFFER_SIZE
+    tbm_options.config.chrome_trace_config.SetTraceBufferSizeInKb(buffer_size)
+
+    for histogram in _SHARED_STORAGE_UMA_HISTOGRAMS:
+      tbm_options.config.chrome_trace_config.EnableUMAHistograms(histogram)
+
+    tbm_options.AddTimelineBasedMetric('umaMetric')
+    if self.verbose_cpu_metrics:
+      tbm_options.AddTimelineBasedMetric('limitedCpuTimeMetric')
+    return tbm_options
+
+  def CreateStorySet(self, options):
+    # `options` is an instance of `timeline_based_measurement.Options`.
+    return page_set.SharedStorageStorySet(
+        url=self.URL,
+        enable_memory_metric=self.verbose_memory_metrics,
+        user_agent=options.user_agent,
+        iterations=self.iterations,
+        verbosity=self.verbosity)
+
+
+@benchmark.Info(emails=['cammie@chromium.org'],
+                component='Blink>Storage>SharedStorage',
+                documentation_url='')
+class SharedStoragePerfFreshDB(SharedStoragePerfBase):
+  URL = "file://fresh_with_worklet.html"
+
+  @classmethod
+  def Name(cls):
+    return 'shared_storage.fresh'
+
+
+@benchmark.Info(emails=['cammie@chromium.org'],
+                component='Blink>Storage>SharedStorage',
+                documentation_url='')
+class SharedStoragePerfSmallDB(SharedStoragePerfBase):
+  URL = "file://small_with_worklet.html"
+
+  @classmethod
+  def Name(cls):
+    return 'shared_storage.small'
+
+
+@benchmark.Info(emails=['cammie@chromium.org'],
+                component='Blink>Storage>SharedStorage',
+                documentation_url='')
+class SharedStoragePerfMediumDB(SharedStoragePerfBase):
+  URL = "file://medium_with_worklet.html"
+
+  @classmethod
+  def Name(cls):
+    return 'shared_storage.medium'
+
+
+@benchmark.Info(emails=['cammie@chromium.org'],
+                component='Blink>Storage>SharedStorage',
+                documentation_url='')
+class SharedStoragePerfLargeDB(SharedStoragePerfBase):
+  URL = "file://large_with_worklet.html"
+
+  @classmethod
+  def Name(cls):
+    return 'shared_storage.large'
diff --git a/tools/perf/contrib/shared_storage/small_with_worklet.html b/tools/perf/contrib/shared_storage/small_with_worklet.html
new file mode 100644
index 0000000..a953ffeb
--- /dev/null
+++ b/tools/perf/contrib/shared_storage/small_with_worklet.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Shared Storage Test, Small DB</title>
+  <script>
+    window.sharedStorage.worklet.addModule('worklet.js');
+    window.sharedStorage.clear();
+    for (let i = 0; i < 10; i++) {
+      sharedStorage.set(i.toString(), 'x');
+    }
+  </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/tools/perf/contrib/shared_storage/worklet.js b/tools/perf/contrib/shared_storage/worklet.js
new file mode 100644
index 0000000..6e667b4
--- /dev/null
+++ b/tools/perf/contrib/shared_storage/worklet.js
@@ -0,0 +1,174 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+class RunSetOperation {
+  async run(data) {
+    if (data && data.hasOwnProperty('key') && data.hasOwnProperty('value')) {
+      await sharedStorage.set(data['key'], data['value']);
+    } else {
+      console.error('received data: ' + JSON.stringify(data));
+    }
+  }
+}
+
+class SelectURLSetOperation {
+  async run(urls, data) {
+    if (data && data.hasOwnProperty('key') && data.hasOwnProperty('value')) {
+      await sharedStorage.set(data['key'], data['value']);
+      return 0;
+    }
+    return -1;
+  }
+}
+
+class RunAppendOperation {
+  async run(data) {
+    if (data && data.hasOwnProperty('key') && data.hasOwnProperty('value')) {
+      await sharedStorage.append(data['key'], data['value']);
+    }
+  }
+}
+
+class SelectURLAppendOperation {
+  async run(urls, data) {
+    if (data && data.hasOwnProperty('key') && data.hasOwnProperty('value')) {
+      await sharedStorage.append(data['key'], data['value']);
+      return 0;
+    }
+    return -1;
+  }
+}
+
+class RunDeleteOperation {
+  async run(data) {
+    if (data && data.hasOwnProperty('key')) {
+      await sharedStorage.delete(data['key']);
+    }
+  }
+}
+
+class SelectURLDeleteOperation {
+  async run(urls, data) {
+    if (data && data.hasOwnProperty('key')) {
+      await sharedStorage.delete(data['key']);
+      return 0;
+    }
+    return -1;
+  }
+}
+
+class RunClearOperation {
+  async run() {
+    await sharedStorage.clear();
+  }
+}
+
+class SelectURLClearOperation {
+  async run(urls) {
+    await sharedStorage.clear();
+    return 0;
+  }
+}
+
+class RunGetOperation {
+  async run(data) {
+    if (data && data.hasOwnProperty('key')) {
+      console.log(await sharedStorage.get(data['key']));
+    }
+  }
+}
+
+class SelectURLGetOperation {
+  async run(urls, data) {
+    if (data && data.hasOwnProperty('key')) {
+      console.log(await sharedStorage.get(data['key']));
+      return 0;
+    }
+    return -1;
+  }
+}
+
+class RunLengthOperation {
+  async run() {
+    const length = await sharedStorage.length();
+    console.log(length);
+  }
+}
+
+class SelectURLLengthOperation {
+  async run(urls) {
+    const length = await sharedStorage.length();
+    console.log(length);
+    return 0;
+  }
+}
+
+class RunKeysOperation {
+  async run() {
+    for await (const key of sharedStorage.keys()) {
+      console.log(key);
+    }
+  }
+}
+
+class SelectURLKeysOperation {
+  async run(urls) {
+    for await (const key of sharedStorage.keys()) {
+      console.log(key);
+    }
+    return 0;
+  }
+}
+
+class RunEntriesOperation {
+  async run() {
+    for await (const [key, value] of sharedStorage.entries()) {
+      console.log(key + ';' + value);
+    }
+  }
+}
+
+class SelectURLEntriesOperation {
+  async run(urls) {
+    for await (const [key, value] of sharedStorage.entries()) {
+      console.log(key + ';' + value);
+    }
+    return 0;
+  }
+}
+
+class RunRemainingBudgetOperation {
+  async run() {
+    const remainingBudget = await sharedStorage.remainingBudget();
+    console.log(remainingBudget);
+  }
+}
+
+class SelectURLRemainingBudgetOperation {
+  async run(urls) {
+    const remainingBudget = await sharedStorage.remainingBudget();
+    console.log(remainingBudget);
+    return 0;
+  }
+}
+
+register('run-set-operation', RunSetOperation);
+register('selecturl-set-operation', SelectURLSetOperation);
+register('run-append-operation', RunAppendOperation);
+register('selecturl-append-operation', SelectURLAppendOperation);
+register('run-delete-operation', RunDeleteOperation);
+register('selecturl-delete-operation', SelectURLDeleteOperation);
+register('run-clear-operation', RunClearOperation);
+register('selecturl-clear-operation', SelectURLClearOperation);
+register('run-get-operation', RunGetOperation);
+register('selecturl-get-operation', SelectURLGetOperation);
+register('run-length-operation', RunLengthOperation);
+register('selecturl-length-operation', SelectURLLengthOperation);
+register('run-keys-operation', RunKeysOperation);
+register('selecturl-keys-operation', SelectURLKeysOperation);
+register('run-entries-operation', RunEntriesOperation);
+register('selecturl-entries-operation', SelectURLEntriesOperation);
+register('run-remainingbudget-operation', RunRemainingBudgetOperation);
+register(
+    'selecturl-remainingbudget-operation', SelectURLRemainingBudgetOperation);
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 70a8364..334338b8 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,16 +5,16 @@
             "full_remote_path": "perfetto-luci-artifacts/v42.0/linux-arm64/trace_processor_shell"
         },
         "win": {
-            "hash": "f2c6b8d097054a1dbc1aeb47e10d17e3eab62744",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/e7e3adbde3052fa8c453eec0aa909b826540dbd9/trace_processor_shell.exe"
+            "hash": "7de412f93bacd7427c6db87ceb751aad749a23e6",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/786ec3a414ad41aa627a88b83c7fd9bae5d59136/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "46739eeb4b8f2a65a8a0aac57743767e6407f7bb",
             "full_remote_path": "perfetto-luci-artifacts/v42.0/linux-arm/trace_processor_shell"
         },
         "mac": {
-            "hash": "2580362caa500ef18d61f3a0273b6191c855c9c9",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/e7e3adbde3052fa8c453eec0aa909b826540dbd9/trace_processor_shell"
+            "hash": "968385b9366246c8caef326994fd74ea893e1a98",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/786ec3a414ad41aa627a88b83c7fd9bae5d59136/trace_processor_shell"
         },
         "mac_arm64": {
             "hash": "789f24a091d50faafdd5d7c5096bb923d073f138",
diff --git a/tools/typescript/validate_tsconfig.py b/tools/typescript/validate_tsconfig.py
index bfb57ba1..b4fdab01b 100644
--- a/tools/typescript/validate_tsconfig.py
+++ b/tools/typescript/validate_tsconfig.py
@@ -120,6 +120,9 @@
       # TODO(b/314827247): Migrate media_app_ui to TypeScript and remove
       # exception.
       'ash/webui/media_app_ui/',
+      # TODO(b/313562946): Migrate help_app_ui mojo pipeline to TypeScript and
+      # remove.
+      'ash/webui/help_app_ui/',
       # TODO(b/315002705): Migrate shimless_rma to TypeScript and remove
       # exception.
       'ash/webui/shimless_rma/',
diff --git a/ui/file_manager/base/js/convert_to_ts.py b/ui/file_manager/base/js/convert_to_ts.py
index cb458cfc..a632612 100644
--- a/ui/file_manager/base/js/convert_to_ts.py
+++ b/ui/file_manager/base/js/convert_to_ts.py
@@ -652,11 +652,11 @@
             register_testcase(js_path)
 
         # Process the JS file content and save as JS file.
-        # ts_content = process_js_file(js_path)
-        # replace_file(js_path, ts_content)
+        ts_content = process_js_file(js_path)
+        replace_file(js_path, ts_content)
 
         # Rename to TS.
-        # run_git_mv(str(js_path))
+        run_git_mv(str(js_path))
 
 
 def main():
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn
index debd258f..679d4cdb 100644
--- a/ui/gl/BUILD.gn
+++ b/ui/gl/BUILD.gn
@@ -310,7 +310,6 @@
       "hdr_metadata_helper_win.h",
       "swap_chain_presenter.cc",
       "swap_chain_presenter.h",
-      "vsync_observer.h",
       "vsync_provider_win.cc",
       "vsync_provider_win.h",
       "vsync_thread_win.cc",
diff --git a/ui/gl/dcomp_presenter.cc b/ui/gl/dcomp_presenter.cc
index 358ac6d..c46e6ce 100644
--- a/ui/gl/dcomp_presenter.cc
+++ b/ui/gl/dcomp_presenter.cc
@@ -21,15 +21,6 @@
 
 namespace gl {
 
-namespace {
-
-bool SupportsLowLatencyPresentation() {
-  return base::FeatureList::IsEnabled(
-      features::kDirectCompositionLowLatencyPresentation);
-}
-
-}  // namespace
-
 DCompPresenter::PendingFrame::PendingFrame(
     Microsoft::WRL::ComPtr<ID3D11Query> query,
     PresentationCallback callback)
@@ -39,12 +30,8 @@
 DCompPresenter::PendingFrame& DCompPresenter::PendingFrame::operator=(
     PendingFrame&& other) = default;
 
-DCompPresenter::DCompPresenter(GLDisplayEGL* display,
-                               VSyncCallback vsync_callback,
-                               const Settings& settings)
-    : vsync_callback_(std::move(vsync_callback)),
-      vsync_thread_(VSyncThreadWin::GetInstance()),
-      task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()),
+DCompPresenter::DCompPresenter(GLDisplayEGL* display, const Settings& settings)
+    : task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()),
       max_pending_frames_(settings.max_pending_frames),
       layer_tree_(std::make_unique<DCLayerTree>(
           settings.disable_nv12_dynamic_textures,
@@ -80,8 +67,9 @@
     std::move(frame.callback).Run(gfx::PresentationFeedback::Failure());
   pending_frames_.clear();
 
-  if (vsync_thread_started_)
-    vsync_thread_->RemoveObserver(this);
+  if (observing_vsync_) {
+    VSyncThreadWin::GetInstance()->RemoveObserver(this);
+  }
 
   // Freeing DComp resources such as visuals and surfaces causes the
   // device to become 'dirty'. We must commit the changes to the device
@@ -106,17 +94,11 @@
 }
 
 gfx::VSyncProvider* DCompPresenter::GetVSyncProvider() {
-  return vsync_thread_->vsync_provider();
+  return VSyncThreadWin::GetInstance()->vsync_provider();
 }
 
 void DCompPresenter::OnVSync(base::TimeTicks vsync_time,
                              base::TimeDelta interval) {
-  // Main thread will run vsync callback in low latency presentation mode.
-  if (VSyncCallbackEnabled() && !SupportsLowLatencyPresentation()) {
-    DCHECK(vsync_callback_);
-    vsync_callback_.Run(vsync_time, interval);
-  }
-
   task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&DCompPresenter::HandleVSyncOnMainThread,
@@ -174,18 +156,6 @@
   return true;
 }
 
-bool DCompPresenter::SupportsGpuVSync() const {
-  return true;
-}
-
-void DCompPresenter::SetGpuVSyncEnabled(bool enabled) {
-  {
-    base::AutoLock auto_lock(vsync_callback_enabled_lock_);
-    vsync_callback_enabled_ = enabled;
-  }
-  StartOrStopVSyncThread();
-}
-
 bool DCompPresenter::SupportsDelegatedInk() {
   return layer_tree_->SupportsDelegatedInk();
 }
@@ -225,30 +195,20 @@
                                              base::TimeDelta interval) {
   last_vsync_time_ = vsync_time;
   last_vsync_interval_ = interval;
-
   CheckPendingFrames();
-  if (SupportsLowLatencyPresentation() && VSyncCallbackEnabled() &&
-      pending_frames_.size() < max_pending_frames_) {
-    DCHECK(vsync_callback_);
-    vsync_callback_.Run(vsync_time, interval);
-  }
 }
 
 void DCompPresenter::StartOrStopVSyncThread() {
-  bool start_vsync_thread = VSyncCallbackEnabled() || !pending_frames_.empty();
-  if (vsync_thread_started_ == start_vsync_thread)
+  bool needs_vsync = !pending_frames_.empty();
+  if (observing_vsync_ == needs_vsync) {
     return;
-  vsync_thread_started_ = start_vsync_thread;
-  if (start_vsync_thread) {
-    vsync_thread_->AddObserver(this);
-  } else {
-    vsync_thread_->RemoveObserver(this);
   }
-}
-
-bool DCompPresenter::VSyncCallbackEnabled() const {
-  base::AutoLock auto_lock(vsync_callback_enabled_lock_);
-  return vsync_callback_enabled_;
+  observing_vsync_ = needs_vsync;
+  if (needs_vsync) {
+    VSyncThreadWin::GetInstance()->AddObserver(this);
+  } else {
+    VSyncThreadWin::GetInstance()->RemoveObserver(this);
+  }
 }
 
 void DCompPresenter::CheckPendingFrames() {
diff --git a/ui/gl/dcomp_presenter.h b/ui/gl/dcomp_presenter.h
index 487661e..001ef2a 100644
--- a/ui/gl/dcomp_presenter.h
+++ b/ui/gl/dcomp_presenter.h
@@ -22,7 +22,7 @@
 #include "ui/gl/gl_export.h"
 #include "ui/gl/gl_surface_egl.h"
 #include "ui/gl/presenter.h"
-#include "ui/gl/vsync_observer.h"
+#include "ui/gl/vsync_thread_win.h"
 
 namespace base {
 class SequencedTaskRunner;
@@ -41,12 +41,9 @@
 
 // This class owns the DComp layer tree and its presentation. It does not own
 // the root surface.
-class GL_EXPORT DCompPresenter : public Presenter, public VSyncObserver {
+class GL_EXPORT DCompPresenter : public Presenter,
+                                 public VSyncThreadWin::VSyncObserver {
  public:
-  using VSyncCallback =
-      base::RepeatingCallback<void(base::TimeTicks, base::TimeDelta)>;
-  using OverlayHDRInfoUpdateCallback = base::RepeatingClosure;
-
   struct Settings {
     bool disable_nv12_dynamic_textures = false;
     bool disable_vp_auto_hdr = false;
@@ -59,7 +56,6 @@
   };
 
   DCompPresenter(GLDisplayEGL* display,
-                 VSyncCallback vsync_callback,
                  const Settings& settings);
 
   DCompPresenter(const DCompPresenter&) = delete;
@@ -77,8 +73,6 @@
               bool has_alpha) override;
   bool SetDrawRectangle(const gfx::Rect& rect) override;
   bool SupportsViewporter() const override;
-  bool SupportsGpuVSync() const override;
-  void SetGpuVSyncEnabled(bool enabled) override;
   // This schedules an overlay plane to be displayed on the next SwapBuffers
   // or PostSubBuffer call. Overlay planes must be scheduled before every swap
   // to remain in the layer tree. This surface's backbuffer doesn't have to be
@@ -138,23 +132,15 @@
 
   void StartOrStopVSyncThread();
 
-  bool VSyncCallbackEnabled() const;
-
   void HandleVSyncOnMainThread(base::TimeTicks vsync_time,
                                base::TimeDelta interval);
 
   ChildWindowWin child_window_;
 
   Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_;
-
-  const VSyncCallback vsync_callback_;
-
-  const raw_ptr<VSyncThreadWin> vsync_thread_;
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
-  bool vsync_thread_started_ = false;
-  bool vsync_callback_enabled_ GUARDED_BY(vsync_callback_enabled_lock_) = false;
-  mutable base::Lock vsync_callback_enabled_lock_;
+  bool observing_vsync_ = false;
 
   // Queue of pending presentation callbacks.
   base::circular_deque<PendingFrame> pending_frames_;
diff --git a/ui/gl/dcomp_presenter_unittest.cc b/ui/gl/dcomp_presenter_unittest.cc
index 3a17cc8f..8955368 100644
--- a/ui/gl/dcomp_presenter_unittest.cc
+++ b/ui/gl/dcomp_presenter_unittest.cc
@@ -243,8 +243,7 @@
     DCompPresenter::Settings settings;
     scoped_refptr<DCompPresenter> presenter =
         base::MakeRefCounted<DCompPresenter>(
-            gl::GLSurfaceEGL::GetGLDisplayEGL(),
-            DCompPresenter::VSyncCallback(), settings);
+            gl::GLSurfaceEGL::GetGLDisplayEGL(), settings);
     EXPECT_TRUE(presenter->Initialize());
 
     // ImageTransportSurfaceDelegate::AddChildWindowToBrowser() is called in
diff --git a/ui/gl/delegated_ink_point_renderer_gpu_unittest.cc b/ui/gl/delegated_ink_point_renderer_gpu_unittest.cc
index d02c7db5e..a24221d2 100644
--- a/ui/gl/delegated_ink_point_renderer_gpu_unittest.cc
+++ b/ui/gl/delegated_ink_point_renderer_gpu_unittest.cc
@@ -134,8 +134,7 @@
   void CreateDirectCompositionSurfaceWin() {
     DirectCompositionSurfaceWin::Settings settings;
     surface_ = base::MakeRefCounted<DirectCompositionSurfaceWin>(
-        gl::GLSurfaceEGL::GetGLDisplayEGL(),
-        DirectCompositionSurfaceWin::VSyncCallback(), settings);
+        gl::GLSurfaceEGL::GetGLDisplayEGL(), settings);
     EXPECT_TRUE(surface_->Initialize(GLSurfaceFormat()));
 
     // ImageTransportSurfaceDelegate::AddChildWindowToBrowser() is called in
diff --git a/ui/gl/direct_composition_surface_win.cc b/ui/gl/direct_composition_surface_win.cc
index 3ec43c5..7601b80 100644
--- a/ui/gl/direct_composition_surface_win.cc
+++ b/ui/gl/direct_composition_surface_win.cc
@@ -18,19 +18,9 @@
 #include "ui/gl/direct_composition_child_surface_win.h"
 #include "ui/gl/direct_composition_support.h"
 #include "ui/gl/gl_angle_util_win.h"
-#include "ui/gl/vsync_thread_win.h"
 
 namespace gl {
 
-namespace {
-
-bool SupportsLowLatencyPresentation() {
-  return base::FeatureList::IsEnabled(
-      features::kDirectCompositionLowLatencyPresentation);
-}
-
-}  // namespace
-
 DirectCompositionSurfaceWin::PendingFrame::PendingFrame(
     Microsoft::WRL::ComPtr<ID3D11Query> query,
     PresentationCallback callback)
@@ -44,12 +34,9 @@
 
 DirectCompositionSurfaceWin::DirectCompositionSurfaceWin(
     GLDisplayEGL* display,
-    VSyncCallback vsync_callback,
     const Settings& settings)
     : GLSurfaceEGL(display),
       d3d11_device_(GetDirectCompositionD3D11Device()),
-      vsync_callback_(std::move(vsync_callback)),
-      vsync_thread_(VSyncThreadWin::GetInstance()),
       task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()),
       max_pending_frames_(settings.max_pending_frames),
       root_surface_(new DirectCompositionChildSurfaceWin(
@@ -91,8 +78,9 @@
     std::move(frame.callback).Run(gfx::PresentationFeedback::Failure());
   pending_frames_.clear();
 
-  if (vsync_thread_started_)
-    vsync_thread_->RemoveObserver(this);
+  if (observing_vsync_) {
+    VSyncThreadWin::GetInstance()->RemoveObserver(this);
+  }
 
   root_surface_->Destroy();
   // Freeing DComp resources such as visuals and surfaces causes the
@@ -161,7 +149,7 @@
 }
 
 gfx::VSyncProvider* DirectCompositionSurfaceWin::GetVSyncProvider() {
-  return vsync_thread_->vsync_provider();
+  return VSyncThreadWin::GetInstance()->vsync_provider();
 }
 
 void DirectCompositionSurfaceWin::SetVSyncEnabled(bool enabled) {
@@ -170,12 +158,6 @@
 
 void DirectCompositionSurfaceWin::OnVSync(base::TimeTicks vsync_time,
                                           base::TimeDelta interval) {
-  // Main thread will run vsync callback in low latency presentation mode.
-  if (VSyncCallbackEnabled() && !SupportsLowLatencyPresentation()) {
-    DCHECK(vsync_callback_);
-    vsync_callback_.Run(vsync_time, interval);
-  }
-
   task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&DirectCompositionSurfaceWin::HandleVSyncOnMainThread,
@@ -230,18 +212,6 @@
   return root_surface_->GetDrawOffset();
 }
 
-bool DirectCompositionSurfaceWin::SupportsGpuVSync() const {
-  return true;
-}
-
-void DirectCompositionSurfaceWin::SetGpuVSyncEnabled(bool enabled) {
-  {
-    base::AutoLock auto_lock(vsync_callback_enabled_lock_);
-    vsync_callback_enabled_ = enabled;
-  }
-  StartOrStopVSyncThread();
-}
-
 bool DirectCompositionSurfaceWin::SupportsDelegatedInk() {
   return layer_tree_->SupportsDelegatedInk();
 }
@@ -292,30 +262,20 @@
     base::TimeDelta interval) {
   last_vsync_time_ = vsync_time;
   last_vsync_interval_ = interval;
-
   CheckPendingFrames();
-  if (SupportsLowLatencyPresentation() && VSyncCallbackEnabled() &&
-      pending_frames_.size() < max_pending_frames_) {
-    DCHECK(vsync_callback_);
-    vsync_callback_.Run(vsync_time, interval);
-  }
 }
 
 void DirectCompositionSurfaceWin::StartOrStopVSyncThread() {
-  bool start_vsync_thread = VSyncCallbackEnabled() || !pending_frames_.empty();
-  if (vsync_thread_started_ == start_vsync_thread)
+  bool needs_vsync = !pending_frames_.empty();
+  if (observing_vsync_ == needs_vsync) {
     return;
-  vsync_thread_started_ = start_vsync_thread;
-  if (start_vsync_thread) {
-    vsync_thread_->AddObserver(this);
-  } else {
-    vsync_thread_->RemoveObserver(this);
   }
-}
-
-bool DirectCompositionSurfaceWin::VSyncCallbackEnabled() const {
-  base::AutoLock auto_lock(vsync_callback_enabled_lock_);
-  return vsync_callback_enabled_;
+  observing_vsync_ = needs_vsync;
+  if (needs_vsync) {
+    VSyncThreadWin::GetInstance()->AddObserver(this);
+  } else {
+    VSyncThreadWin::GetInstance()->RemoveObserver(this);
+  }
 }
 
 void DirectCompositionSurfaceWin::CheckPendingFrames() {
diff --git a/ui/gl/direct_composition_surface_win.h b/ui/gl/direct_composition_surface_win.h
index e9d21087..e285ae9 100644
--- a/ui/gl/direct_composition_surface_win.h
+++ b/ui/gl/direct_composition_surface_win.h
@@ -21,7 +21,7 @@
 #include "ui/gl/child_window_win.h"
 #include "ui/gl/gl_export.h"
 #include "ui/gl/gl_surface_egl.h"
-#include "ui/gl/vsync_observer.h"
+#include "ui/gl/vsync_thread_win.h"
 
 namespace base {
 class SequencedTaskRunner;
@@ -39,8 +39,9 @@
 class DCLayerTree;
 class DirectCompositionChildSurfaceWin;
 
-class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL,
-                                              public VSyncObserver {
+class GL_EXPORT DirectCompositionSurfaceWin
+    : public GLSurfaceEGL,
+      public VSyncThreadWin::VSyncObserver {
  public:
   using VSyncCallback =
       base::RepeatingCallback<void(base::TimeTicks, base::TimeDelta)>;
@@ -59,7 +60,6 @@
 
   DirectCompositionSurfaceWin(
       GLDisplayEGL* display,
-      VSyncCallback vsync_callback,
       const DirectCompositionSurfaceWin::Settings& settings);
 
   DirectCompositionSurfaceWin(const DirectCompositionSurfaceWin&) = delete;
@@ -94,8 +94,6 @@
   bool SupportsProtectedVideo() const override;
   bool SetDrawRectangle(const gfx::Rect& rect) override;
   gfx::Vector2d GetDrawOffset() const override;
-  bool SupportsGpuVSync() const override;
-  void SetGpuVSyncEnabled(bool enabled) override;
   // This schedules an overlay plane to be displayed on the next SwapBuffers
   // or PostSubBuffer call. Overlay planes must be scheduled before every swap
   // to remain in the layer tree. This surface's backbuffer doesn't have to be
@@ -157,8 +155,6 @@
 
   void StartOrStopVSyncThread();
 
-  bool VSyncCallbackEnabled() const;
-
   void HandleVSyncOnMainThread(base::TimeTicks vsync_time,
                                base::TimeDelta interval);
 
@@ -166,14 +162,10 @@
 
   Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_;
 
-  const VSyncCallback vsync_callback_;
-
   const raw_ptr<VSyncThreadWin> vsync_thread_;
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
-  bool vsync_thread_started_ = false;
-  bool vsync_callback_enabled_ GUARDED_BY(vsync_callback_enabled_lock_) = false;
-  mutable base::Lock vsync_callback_enabled_lock_;
+  bool observing_vsync_ = false;
 
   // Queue of pending presentation callbacks.
   base::circular_deque<PendingFrame> pending_frames_;
diff --git a/ui/gl/direct_composition_surface_win_unittest.cc b/ui/gl/direct_composition_surface_win_unittest.cc
index 8b31058..90155dc 100644
--- a/ui/gl/direct_composition_surface_win_unittest.cc
+++ b/ui/gl/direct_composition_surface_win_unittest.cc
@@ -167,8 +167,7 @@
     DirectCompositionSurfaceWin::Settings settings;
     scoped_refptr<DirectCompositionSurfaceWin> surface =
         base::MakeRefCounted<DirectCompositionSurfaceWin>(
-            gl::GLSurfaceEGL::GetGLDisplayEGL(),
-            DirectCompositionSurfaceWin::VSyncCallback(), settings);
+            gl::GLSurfaceEGL::GetGLDisplayEGL(), settings);
     EXPECT_TRUE(surface->Initialize(GLSurfaceFormat()));
 
     // ImageTransportSurfaceDelegate::AddChildWindowToBrowser() is called in
diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc
index e7719109..f246705 100644
--- a/ui/gl/gl_surface.cc
+++ b/ui/gl/gl_surface.cc
@@ -207,10 +207,6 @@
   return nullptr;
 }
 
-bool GLSurface::SupportsGpuVSync() const {
-  return false;
-}
-
 bool GLSurface::SupportsDelegatedInk() {
   return false;
 }
@@ -221,8 +217,6 @@
   NOTREACHED();
 }
 
-void GLSurface::SetGpuVSyncEnabled(bool enabled) {}
-
 GLSurface* GLSurface::GetCurrent() {
   return current_surface;
 }
diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h
index 688744a..755bd926 100644
--- a/ui/gl/gl_surface.h
+++ b/ui/gl/gl_surface.h
@@ -256,10 +256,6 @@
   // Return the interface used for querying EGL timestamps.
   virtual EGLTimestampClient* GetEGLTimestampClient();
 
-  virtual bool SupportsGpuVSync() const;
-
-  virtual void SetGpuVSyncEnabled(bool enabled);
-
   virtual void SetFrameRate(float frame_rate) {}
   static GLSurface* GetCurrent();
 
diff --git a/ui/gl/gl_switches.cc b/ui/gl/gl_switches.cc
index 5df7f1d..239ff372 100644
--- a/ui/gl/gl_switches.cc
+++ b/ui/gl/gl_switches.cc
@@ -196,11 +196,6 @@
              "DCompVisualTreeOptimization",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-// Use presentation feedback event queries (must be enabled) to limit latency.
-BASE_FEATURE(kDirectCompositionLowLatencyPresentation,
-             "DirectCompositionLowLatencyPresentation",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 // Allow overlay swapchain to present on all GPUs even if they only support
 // software overlays. GPU deny lists limit it to NVIDIA only at the moment.
 BASE_FEATURE(kDirectCompositionSoftwareOverlays,
diff --git a/ui/gl/gl_switches.h b/ui/gl/gl_switches.h
index 2c38ed1..816f050c 100644
--- a/ui/gl/gl_switches.h
+++ b/ui/gl/gl_switches.h
@@ -92,8 +92,6 @@
 GL_EXPORT BASE_DECLARE_FEATURE(kDCompTripleBufferRootSwapChain);
 GL_EXPORT BASE_DECLARE_FEATURE(kDCompTripleBufferVideoSwapChain);
 GL_EXPORT BASE_DECLARE_FEATURE(kDCompVisualTreeOptimization);
-GL_EXPORT BASE_DECLARE_FEATURE(kDirectCompositionGpuVSync);
-GL_EXPORT BASE_DECLARE_FEATURE(kDirectCompositionLowLatencyPresentation);
 GL_EXPORT BASE_DECLARE_FEATURE(kDirectCompositionSoftwareOverlays);
 GL_EXPORT BASE_DECLARE_FEATURE(kDirectCompositionLetterboxVideoOptimization);
 GL_EXPORT BASE_DECLARE_FEATURE(kDirectCompositionUnlimitedOverlays);
diff --git a/ui/gl/presenter.cc b/ui/gl/presenter.cc
index d50d1b0..f8c72a8 100644
--- a/ui/gl/presenter.cc
+++ b/ui/gl/presenter.cc
@@ -31,10 +31,6 @@
   return false;
 }
 
-bool Presenter::SupportsGpuVSync() const {
-  return false;
-}
-
 bool Presenter::ScheduleOverlayPlane(
     OverlayImage image,
     std::unique_ptr<gfx::GpuFence> gpu_fence,
@@ -60,4 +56,4 @@
   return true;
 }
 
-}  // namespace gl
\ No newline at end of file
+}  // namespace gl
diff --git a/ui/gl/presenter.h b/ui/gl/presenter.h
index b0e795f..02e90ab 100644
--- a/ui/gl/presenter.h
+++ b/ui/gl/presenter.h
@@ -80,8 +80,6 @@
   virtual bool SupportsViewporter() const;
   virtual bool SupportsPlaneGpuFences() const;
 
-  virtual bool SupportsGpuVSync() const;
-  virtual void SetGpuVSyncEnabled(bool enabled) {}
   virtual void SetVSyncDisplayID(int64_t display_id) {}
 
   // Resizes the presenter, returning success.
diff --git a/ui/gl/vsync_observer.h b/ui/gl/vsync_observer.h
deleted file mode 100644
index 6ad72a8..0000000
--- a/ui/gl/vsync_observer.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GL_VSYNC_OBSERVER_H_
-#define UI_GL_VSYNC_OBSERVER_H_
-
-#include "base/time/time.h"
-
-namespace gl {
-class GL_EXPORT VSyncObserver {
- public:
-  // Called on vsync thread.
-  virtual void OnVSync(base::TimeTicks vsync_time,
-                       base::TimeDelta interval) = 0;
-
- protected:
-  virtual ~VSyncObserver() {}
-};
-}  // namespace gl
-
-#endif  // UI_GL_VSYNC_OBSERVER_H_
diff --git a/ui/gl/vsync_thread_win.cc b/ui/gl/vsync_thread_win.cc
index 079c6f7..ef94a1f4 100644
--- a/ui/gl/vsync_thread_win.cc
+++ b/ui/gl/vsync_thread_win.cc
@@ -11,21 +11,14 @@
 #include "base/time/time.h"
 #include "base/trace_event/typed_macros.h"
 #include "base/win/windows_version.h"
-#include "ui/gl/gl_angle_util_win.h"
+#include "ui/gl/direct_composition_support.h"
 #include "ui/gl/gl_features.h"
-#include "ui/gl/vsync_observer.h"
 
 namespace gl {
 namespace {
 Microsoft::WRL::ComPtr<IDXGIOutput> DXGIOutputFromMonitor(
     HMONITOR monitor,
-    const Microsoft::WRL::ComPtr<ID3D11Device>& d3d11_device) {
-  Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device;
-  if (FAILED(d3d11_device.As(&dxgi_device))) {
-    DLOG(ERROR) << "Failed to retrieve DXGI device";
-    return nullptr;
-  }
-
+    IDXGIDevice* dxgi_device) {
   Microsoft::WRL::ComPtr<IDXGIAdapter> dxgi_adapter;
   if (FAILED(dxgi_device->GetAdapter(&dxgi_adapter))) {
     DLOG(ERROR) << "Failed to retrieve DXGI adapter";
@@ -54,18 +47,26 @@
 
 // static
 VSyncThreadWin* VSyncThreadWin::GetInstance() {
-  return base::Singleton<VSyncThreadWin>::get();
+  static VSyncThreadWin* vsync_thread = []() -> VSyncThreadWin* {
+    Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device(
+        GetDirectCompositionD3D11Device());
+    if (!d3d11_device) {
+      return nullptr;
+    }
+    Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device;
+    CHECK_EQ(d3d11_device.As(&dxgi_device), S_OK);
+    return new VSyncThreadWin(std::move(dxgi_device));
+  }();
+  return vsync_thread;
 }
 
-VSyncThreadWin::VSyncThreadWin()
+VSyncThreadWin::VSyncThreadWin(Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device)
     : vsync_thread_("GpuVSyncThread"),
       vsync_provider_(gfx::kNullAcceleratedWidget),
-      d3d11_device_(QueryD3D11DeviceObjectFromANGLE()) {
-  DCHECK(d3d11_device_);
-
+      dxgi_device_(std::move(dxgi_device)) {
+  CHECK(dxgi_device_);
   is_suspended_ =
       base::PowerMonitor::AddPowerSuspendObserverAndReturnSuspendedState(this);
-
   vsync_thread_.StartWithOptions(
       base::Thread::Options(base::ThreadType::kDisplayCritical));
 }
@@ -150,7 +151,7 @@
   const HMONITOR monitor = MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY);
   if (primary_monitor_ != monitor) {
     primary_monitor_ = monitor;
-    primary_output_ = DXGIOutputFromMonitor(monitor, d3d11_device_);
+    primary_output_ = DXGIOutputFromMonitor(monitor, dxgi_device_.Get());
   }
 
   const base::TimeTicks wait_for_vblank_start_time = base::TimeTicks::Now();
diff --git a/ui/gl/vsync_thread_win.h b/ui/gl/vsync_thread_win.h
index df2e1a3..dcd65250 100644
--- a/ui/gl/vsync_thread_win.h
+++ b/ui/gl/vsync_thread_win.h
@@ -15,18 +15,11 @@
 #include "ui/gl/gl_export.h"
 #include "ui/gl/vsync_provider_win.h"
 
-namespace base {
-template <typename T>
-struct DefaultSingletonTraits;
-}  // namespace base
-
 namespace gl {
-class VSyncObserver;
 // Helper singleton that wraps a thread for calling IDXGIOutput::WaitForVBlank()
 // for the primary monitor, and notifies observers on the same thread. Observers
 // can be added or removed on the main thread, and the vsync thread goes to
-// sleep if there are no observers. This is used by DirectCompositionSurfaceWin
-// to plumb vsync signal back to the display compositor's BeginFrameSource.
+// sleep if there are no observers. This is used by ExternalBeginFrameSourceWin.
 class GL_EXPORT VSyncThreadWin final : public base::PowerSuspendObserver {
  public:
   static VSyncThreadWin* GetInstance();
@@ -38,6 +31,15 @@
   void OnSuspend() final;
   void OnResume() final;
 
+  class GL_EXPORT VSyncObserver {
+   public:
+    // Called on vsync thread.
+    virtual void OnVSync(base::TimeTicks vsync_time,
+                         base::TimeDelta interval) = 0;
+
+   protected:
+    virtual ~VSyncObserver() {}
+  };
   // These methods are not rentrancy safe, and shouldn't be called inside
   // VSyncObserver::OnVSync.  It's safe to assume that these can be called only
   // from the main thread.
@@ -47,9 +49,7 @@
   gfx::VSyncProvider* vsync_provider() { return &vsync_provider_; }
 
  private:
-  friend struct base::DefaultSingletonTraits<VSyncThreadWin>;
-
-  VSyncThreadWin();
+  explicit VSyncThreadWin(Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device);
   ~VSyncThreadWin() final;
 
   void PostTaskIfNeeded();
@@ -59,7 +59,7 @@
 
   // Used on vsync thread only after initialization.
   VSyncProviderWin vsync_provider_;
-  const Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_;
+  const Microsoft::WRL::ComPtr<IDXGIDevice> dxgi_device_;
   HMONITOR primary_monitor_ = nullptr;
   Microsoft::WRL::ComPtr<IDXGIOutput> primary_output_;
 
diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
index bd34894..18fbb29 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -1227,6 +1227,9 @@
   state.bounds_dip = AdjustBoundsToConstraintsDIP(state.bounds_dip);
   state.size_px =
       gfx::ScaleToEnclosingRect(state.bounds_dip, state.window_scale).size();
+  // This will ensure that if insets at the time of the request changed, a new
+  // frame is produced when the state is applied.
+  state.insets = GetDecorationInsetsInDIP();
 
   StateRequest req{.state = state, .serial = serial};
   if (in_flight_requests_.empty()) {
@@ -1351,16 +1354,23 @@
   // Latch the most up to date state we have a frame back for.
   auto old_state = latched_state_;
   latched_state_ = req.state;
+  auto old_latched_insets = latched_insets_;
+  latched_insets_ = GetDecorationInsetsInDIP();
 
   // Update the geometry if the bounds are different or the window scale has
-  // been changed. If geometry is not updated on window scale update, the insets
-  // are set in a wrong way. That is, aura provides insets in pixels, which are
-  // converted by the device scale factor known from the display. It can be
-  // different from the one that the |latch_state_.window_scale| has. As a
-  // result, the geometry is set with wrong values as Wayland requires them to
-  // be in DIP.
+  // been changed or if the insets have changed since the last latched request.
+  // If geometry is not updated on window scale update, the insets are set in a
+  // wrong way. That is, aura provides insets in pixels, which are converted by
+  // the device scale factor known from the display. It can be different from
+  // the one that the |latch_state_.window_scale| has. As a result, the geometry
+  // is set with wrong values as Wayland requires them to be in DIP.
   if (req.state.bounds_dip.size() != old_state.bounds_dip.size() ||
-      req.state.window_scale != old_state.window_scale) {
+      req.state.window_scale != old_state.window_scale ||
+      // If insets change that is a geometry change even when the bounds or
+      // scale remain the same. The updated insets may not be known at the time
+      // of the request, hence the need to check this if there are changes in
+      // insets since it latched the last time.
+      old_latched_insets != latched_insets_) {
     SetWindowGeometry(req.state.bounds_dip.size());
   }
   UpdateWindowMask();
diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h
index 696852a..64c47ba 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.h
+++ b/ui/ozone/platform/wayland/host/wayland_window.h
@@ -652,6 +652,9 @@
   // server. See the comments on applied_state_ for further explanation.
   PlatformWindowDelegate::State latched_state_;
 
+  // Stores the insets in DIP at the time of the last latched state.
+  gfx::Insets latched_insets_;
+
   // In-flight state requests. Once a frame comes from the GPU
   // process with the appropriate viz sequence number, ack_configure request
   // with |serial| will be sent to the Wayland compositor if needed.
diff --git a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
index 48b6710..f89eb1d 100644
--- a/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window_unittest.cc
@@ -580,6 +580,57 @@
   }
 }
 
+// Checks that geometry is set when decoration insets change even when bounds or
+// scale don't.
+TEST_P(WaylandWindowTest, OnlyChangeDecorationInsets) {
+  // The bounds never change throughout this test
+  constexpr gfx::Rect kBounds{980, 1188};
+
+  window_->SetBoundsInDIP(kBounds);
+
+  auto state = InitializeWlArrayWithActivatedState();
+
+  PostToServerAndWait([id = surface_id_](wl::TestWaylandServerThread* server) {
+    wl::TestOutput* output = server->output();
+    // Send the window to |output|.
+    wl::MockSurface* surface = server->GetObject<wl::MockSurface>(id);
+    ASSERT_TRUE(surface);
+    wl_surface_send_enter(surface->resource(), output->resource());
+  });
+
+  const auto kInitialInsets = gfx::Insets::TLBR(20, 36, 52, 36);
+  auto bounds_with_insets = kBounds;
+  bounds_with_insets.Inset(kInitialInsets);
+  EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0);
+  PostToServerAndWait([id = surface_id_, bounds_with_insets](
+                          wl::TestWaylandServerThread* server) {
+    wl::MockSurface* surface = server->GetObject<wl::MockSurface>(id);
+    ASSERT_TRUE(surface);
+    wl::MockXdgSurface* xdg_surface = surface->xdg_surface();
+    EXPECT_CALL(*xdg_surface, SetWindowGeometry(bounds_with_insets));
+  });
+  window_->SetDecorationInsets(&kInitialInsets);
+  AdvanceFrameToCurrent(window_.get(), delegate_);
+
+  const auto kNewInsets = gfx::Insets::TLBR(10, 10, 10, 10);
+  bounds_with_insets = kBounds;
+  bounds_with_insets.Inset(kNewInsets);
+  EXPECT_CALL(delegate_, OnBoundsChanged(_)).Times(0);
+  PostToServerAndWait([id = surface_id_, bounds_with_insets](
+                          wl::TestWaylandServerThread* server) {
+    wl::MockSurface* surface = server->GetObject<wl::MockSurface>(id);
+    ASSERT_TRUE(surface);
+    wl::MockXdgSurface* xdg_surface = surface->xdg_surface();
+    EXPECT_CALL(*xdg_surface, SetWindowGeometry(bounds_with_insets));
+  });
+
+  // Change insets here so that these are detected when a new state is requested
+  // from the server.
+  window_->SetDecorationInsets(&kNewInsets);
+  SendConfigureEvent(surface_id_, bounds_with_insets.size(), state);
+  AdvanceFrameToCurrent(window_.get(), delegate_);
+}
+
 #if BUILDFLAG(IS_LINUX)
 // Checks that when the window gets some of its edges tiled, it notifies the
 // delegate appropriately.
diff --git a/ui/platform_window/platform_window_delegate.cc b/ui/platform_window/platform_window_delegate.cc
index 8745072..76da3be 100644
--- a/ui/platform_window/platform_window_delegate.cc
+++ b/ui/platform_window/platform_window_delegate.cc
@@ -24,7 +24,8 @@
     const State& old) const {
   // Changing the bounds origin won't produce a new frame. Anything else will.
   return old.bounds_dip.size() != bounds_dip.size() || old.size_px != size_px ||
-         old.window_scale != window_scale || old.raster_scale != raster_scale;
+         old.window_scale != window_scale || old.raster_scale != raster_scale ||
+         old.insets != insets;
 }
 
 std::string PlatformWindowDelegate::State::ToString() const {
@@ -34,6 +35,7 @@
   result << ", size_px = " << size_px.ToString();
   result << ", window_scale = " << window_scale;
   result << ", raster_scale = " << raster_scale;
+  result << ", insets = " << insets.ToString();
   result << "}";
   return result.str();
 }
diff --git a/ui/platform_window/platform_window_delegate.h b/ui/platform_window/platform_window_delegate.h
index a4bbae764..4d54c42 100644
--- a/ui/platform_window/platform_window_delegate.h
+++ b/ui/platform_window/platform_window_delegate.h
@@ -116,9 +116,10 @@
   // This is used by OnStateChanged and currently only by ozone/wayland.
   struct COMPONENT_EXPORT(PLATFORM_WINDOW) State {
     bool operator==(const State& rhs) const {
-      return std::tie(bounds_dip, size_px, window_scale, raster_scale) ==
-             std::tie(rhs.bounds_dip, rhs.size_px, rhs.window_scale,
-                      rhs.raster_scale);
+      return std::tie(bounds_dip, size_px, window_scale, raster_scale,
+                      insets) == std::tie(rhs.bounds_dip, rhs.size_px,
+                                          rhs.window_scale, rhs.raster_scale,
+                                          rhs.insets);
     }
 
     // Bounds in DIP.
@@ -133,6 +134,10 @@
     // Scale to raster the window at.
     float raster_scale = 1.0;
 
+    // Insets in DIP. Used in platforms where window decorations are drawn by
+    // the client.
+    gfx::Insets insets;
+
     // Returns true if updating from the given State |old| to this state
     // should produce a frame.
     bool ProducesFrameOnUpdateFrom(const State& old) const;
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
index 75ab145..ca2cf6e 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
@@ -200,6 +200,8 @@
 
   views::corewm::TooltipController* tooltip_controller();
 
+  void ScheduleRelayout();
+
  private:
   FRIEND_TEST_ALL_PREFIXES(DesktopWindowTreeHostPlatformTest,
                            UpdateWindowShapeFromWindowMask);
@@ -207,8 +209,6 @@
                            MakesParentChildRelationship);
   FRIEND_TEST_ALL_PREFIXES(DesktopWindowTreeHostPlatformTest, OnRotateFocus);
 
-  void ScheduleRelayout();
-
   // Set visibility and fire OnNativeWidgetVisibilityChanged() if it changed.
   void SetVisible(bool visible);
 
diff --git a/url/gurl_unittest.cc b/url/gurl_unittest.cc
index e638e6b9..8e22fbc4 100644
--- a/url/gurl_unittest.cc
+++ b/url/gurl_unittest.cc
@@ -392,6 +392,26 @@
     std::optional<std::string_view> expected;
   };
 
+  using ApplyReplacementsFunc = GURL(const GURL&);
+
+  struct ReplaceCase {
+    std::string_view base;
+    ApplyReplacementsFunc* apply_replacements;
+    std::string_view expected;
+  };
+
+  struct ReplaceHostCase {
+    std::string_view base;
+    std::string_view replacement_host;
+    std::string_view expected;
+  };
+
+  struct ReplacePathCase {
+    std::string_view base;
+    std::string_view replacement_path;
+    std::string_view expected;
+  };
+
   void TestResolve(const ResolveCase& resolve_case) {
     SCOPED_TRACE(testing::Message() << "base: " << resolve_case.base
                                     << ", relative: " << resolve_case.relative);
@@ -405,6 +425,27 @@
     }
   }
 
+  void TestReplace(const ReplaceCase& replace) {
+    GURL output = replace.apply_replacements(GURL(replace.base));
+    EXPECT_EQ(output.spec(), replace.expected);
+  }
+
+  void TestReplaceHost(const ReplaceHostCase& replace) {
+    GURL url(replace.base);
+    GURL::Replacements replacements;
+    replacements.SetHostStr(replace.replacement_host);
+    GURL output = url.ReplaceComponents(replacements);
+    EXPECT_EQ(output.spec(), replace.expected);
+  }
+
+  void TestReplacePath(const ReplacePathCase& replace) {
+    GURL url(replace.base);
+    GURL::Replacements replacements;
+    replacements.SetPathStr(replace.replacement_path);
+    GURL output = url.ReplaceComponents(replacements);
+    EXPECT_EQ(output.spec(), replace.expected);
+  }
+
   bool use_standard_compliant_non_special_scheme_url_parsing_;
 
  private:
@@ -688,21 +729,6 @@
              return url.ReplaceComponents(replacements);
            },
        .expected = "http://www.google.com/"},
-      {.base = "http://www.google.com/foo/bar.html?foo#bar",
-       .apply_replacements =
-           +[](const GURL& url) {
-             GURL::Replacements replacements;
-             replacements.SetSchemeStr("javascript");
-             replacements.ClearUsername();
-             replacements.ClearPassword();
-             replacements.ClearHost();
-             replacements.ClearPort();
-             replacements.SetPathStr("window.open('foo');");
-             replacements.ClearQuery();
-             replacements.ClearRef();
-             return url.ReplaceComponents(replacements);
-           },
-       .expected = "javascript:window.open('foo');"},
       {.base = "file:///C:/foo/bar.txt",
        .apply_replacements =
            +[](const GURL& url) {
@@ -772,7 +798,66 @@
   }
 }
 
-TEST(GURLTest, ClearFragmentOnDataUrl) {
+TEST_P(GURLTypedTest, Replacements) {
+  // Test flag-dependent behavior.
+  // Existing tests in GURLTest::Replacements cover common cases.
+
+  if (use_standard_compliant_non_special_scheme_url_parsing_) {
+    ReplaceCase replace_cases[] = {
+        {.base = "git:/a1/a2?a3=a4#a5",
+         .apply_replacements =
+             +[](const GURL& url) {
+               GURL::Replacements replacements;
+               replacements.SetHostStr("b1");
+               replacements.SetPortStr("99");
+               replacements.SetPathStr("b2");
+               replacements.SetQueryStr("b3=b4");
+               replacements.SetRefStr("b5");
+               return url.ReplaceComponents(replacements);
+             },
+         .expected = "git://b1:99/b2?b3=b4#b5"},
+    };
+    for (const ReplaceCase& c : replace_cases) {
+      TestReplace(c);
+    }
+
+    ReplaceHostCase replace_host_cases[] = {
+        {"git:/", "host", "git://host/"},
+        {"git:/a", "host", "git://host/a"},
+        {"git://", "host", "git://host"},
+        {"git:///", "host", "git://host/"},
+        {"git://h/a", "host", "git://host/a"}};
+    for (const ReplaceHostCase& c : replace_host_cases) {
+      TestReplaceHost(c);
+    }
+
+    ReplacePathCase replace_path_cases[] = {
+        {"git:/", "a", "git:/a"},
+        {"git://", "a", "git:///a"},
+        {"git:///", "a", "git:///a"},
+        {"git://host", "a", "git://host/a"},
+        {"git://host/b", "a", "git://host/a"}};
+    for (const ReplacePathCase& c : replace_path_cases) {
+      TestReplacePath(c);
+    }
+  } else {
+    // Non-compliant behaviors.
+    ReplaceHostCase replace_host_cases[] = {
+        {"git://host", "h2", "git://host"},
+    };
+    for (const ReplaceHostCase& c : replace_host_cases) {
+      TestReplaceHost(c);
+    }
+
+    // Non-compliant behaviors.
+    ReplacePathCase replace_path_cases[] = {{"git://host", "path", "git:path"}};
+    for (const ReplacePathCase& c : replace_path_cases) {
+      TestReplacePath(c);
+    }
+  }
+}
+
+TEST(GURLTypedTest, ClearFragmentOnDataUrl) {
   // http://crbug.com/291747 - a data URL may legitimately have trailing
   // whitespace in the spec after the ref is cleared. Test this does not trigger
   // the Parsed importing validation DCHECK in GURL.
diff --git a/url/third_party/mozilla/url_parse.cc b/url/third_party/mozilla/url_parse.cc
index 7703748c..ca192c1a 100644
--- a/url/third_party/mozilla/url_parse.cc
+++ b/url/third_party/mozilla/url_parse.cc
@@ -468,12 +468,15 @@
 
 // The main parsing function for non-special scheme URLs.
 template <typename CHAR>
-void DoParseNonSpecialURL(const CHAR* spec, int spec_len, Parsed* parsed) {
+void DoParseNonSpecialURL(const CHAR* spec,
+                          int spec_len,
+                          bool trim_path_end,
+                          Parsed* parsed) {
   DCHECK(spec_len >= 0);
 
   // Strip leading & trailing spaces and control characters.
   int begin = 0;
-  TrimURL(spec, &begin, &spec_len);
+  TrimURL(spec, &begin, &spec_len, trim_path_end);
 
   int after_scheme;
   if (DoExtractScheme(spec, spec_len, &parsed->scheme)) {
@@ -1074,11 +1077,25 @@
 }
 
 void ParseNonSpecialURL(const char* url, int url_len, Parsed* parsed) {
-  DoParseNonSpecialURL(url, url_len, parsed);
+  DoParseNonSpecialURL(url, url_len, /*trim_path_end=*/true, parsed);
 }
 
 void ParseNonSpecialURL(const char16_t* url, int url_len, Parsed* parsed) {
-  DoParseNonSpecialURL(url, url_len, parsed);
+  DoParseNonSpecialURL(url, url_len, /*trim_path_end=*/true, parsed);
+}
+
+void ParseNonSpecialURLInternal(const char* url,
+                                int url_len,
+                                bool trim_path_end,
+                                Parsed* parsed) {
+  DoParseNonSpecialURL(url, url_len, trim_path_end, parsed);
+}
+
+void ParseNonSpecialURLInternal(const char16_t* url,
+                                int url_len,
+                                bool trim_path_end,
+                                Parsed* parsed) {
+  DoParseNonSpecialURL(url, url_len, trim_path_end, parsed);
 }
 
 void ParsePathURL(const char* url,
diff --git a/url/url_canon.h b/url/url_canon.h
index 8c48f98..e877869 100644
--- a/url/url_canon.h
+++ b/url/url_canon.h
@@ -1017,6 +1017,22 @@
                         CanonOutput* output,
                         Parsed* new_parsed);
 
+// For non-special URLs.
+COMPONENT_EXPORT(URL)
+bool ReplaceNonSpecialURL(const char* base,
+                          const Parsed& base_parsed,
+                          const Replacements<char>& replacements,
+                          CharsetConverter* query_converter,
+                          CanonOutput& output,
+                          Parsed& new_parsed);
+COMPONENT_EXPORT(URL)
+bool ReplaceNonSpecialURL(const char* base,
+                          const Parsed& base_parsed,
+                          const Replacements<char16_t>& replacements,
+                          CharsetConverter* query_converter,
+                          CanonOutput& output,
+                          Parsed& new_parsed);
+
 // Filesystem URLs can only have the path, query, or ref replaced.
 // All other components will be ignored.
 COMPONENT_EXPORT(URL)
diff --git a/url/url_canon_internal.cc b/url/url_canon_internal.cc
index 5e1bcdd..f060d06 100644
--- a/url/url_canon_internal.cc
+++ b/url/url_canon_internal.cc
@@ -19,6 +19,7 @@
 #include "base/bits.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/utf_string_conversion_utils.h"
+#include "url/url_features.h"
 
 namespace url {
 
@@ -383,11 +384,15 @@
   DoOverrideComponent(repl_source.password, repl_parsed.password,
                       &source->password, &parsed->password);
 
-  // Our host should be empty if not present, so override the default setup.
   DoOverrideComponent(repl_source.host, repl_parsed.host, &source->host,
                       &parsed->host);
-  if (parsed->host.len == -1)
-    parsed->host.len = 0;
+  if (!url::IsUsingStandardCompliantNonSpecialSchemeURLParsing()) {
+    // For backward compatibility, the following is probably required while the
+    // flag is disabled by default.
+    if (parsed->host.len == -1) {
+      parsed->host.len = 0;
+    }
+  }
 
   DoOverrideComponent(repl_source.port, repl_parsed.port, &source->port,
                       &parsed->port);
diff --git a/url/url_canon_non_special_url.cc b/url/url_canon_non_special_url.cc
index eb567b4..8d745e2 100644
--- a/url/url_canon_non_special_url.cc
+++ b/url/url_canon_non_special_url.cc
@@ -129,4 +129,43 @@
                                      query_converter, output, new_parsed);
 }
 
+bool ReplaceNonSpecialURL(const char* base,
+                          const Parsed& base_parsed,
+                          const Replacements<char>& replacements,
+                          CharsetConverter* query_converter,
+                          CanonOutput& output,
+                          Parsed& new_parsed) {
+  if (base_parsed.has_opaque_path) {
+    return ReplacePathURL(base, base_parsed, replacements, &output,
+                          &new_parsed);
+  }
+
+  URLComponentSource<char> source(base);
+  Parsed parsed(base_parsed);
+  SetupOverrideComponents(base, replacements, &source, &parsed);
+  return DoCanonicalizeNonSpecialURL(source, parsed, query_converter, output,
+                                     new_parsed);
+}
+
+// For 16-bit replacements, we turn all the replacements into UTF-8 so the
+// regular code path can be used.
+bool ReplaceNonSpecialURL(const char* base,
+                          const Parsed& base_parsed,
+                          const Replacements<char16_t>& replacements,
+                          CharsetConverter* query_converter,
+                          CanonOutput& output,
+                          Parsed& new_parsed) {
+  if (base_parsed.has_opaque_path) {
+    return ReplacePathURL(base, base_parsed, replacements, &output,
+                          &new_parsed);
+  }
+
+  RawCanonOutput<1024> utf8;
+  URLComponentSource<char> source(base);
+  Parsed parsed(base_parsed);
+  SetupUTF16OverrideComponents(base, replacements, &utf8, &source, &parsed);
+  return DoCanonicalizeNonSpecialURL(source, parsed, query_converter, output,
+                                     new_parsed);
+}
+
 }  // namespace url
diff --git a/url/url_canon_unittest.cc b/url/url_canon_unittest.cc
index b8052aa7..02d8d1b 100644
--- a/url/url_canon_unittest.cc
+++ b/url/url_canon_unittest.cc
@@ -2963,7 +2963,7 @@
                          &parsed);
     } else {
       ParsePathURL(relative_case.base.data(), relative_case.base.size(),
-                   /*trim_path_end=*/false, &parsed);
+                   /*trim_path_end=*/true, &parsed);
     }
 
     // First see if it is relative.
diff --git a/url/url_parse_internal.h b/url/url_parse_internal.h
index 35cc9b7..8dd3f94f 100644
--- a/url/url_parse_internal.h
+++ b/url/url_parse_internal.h
@@ -85,6 +85,18 @@
                        Component* query,
                        Component* ref);
 
+// Internal functions in url_parse.cc that parse non-special URLs, which are
+// similar to `ParseNonSpecialURL` functions in url_parse.h, but with
+// `trim_path_end` parameter that controls whether to trim path end or not.
+void ParseNonSpecialURLInternal(const char* url,
+                                int url_len,
+                                bool trim_path_end,
+                                Parsed* parsed);
+void ParseNonSpecialURLInternal(const char16_t* url,
+                                int url_len,
+                                bool trim_path_end,
+                                Parsed* parsed);
+
 // Given a spec and a pointer to the character after the colon following the
 // special scheme, this parses it and fills in the structure, Every item in the
 // parsed structure is filled EXCEPT for the scheme, which is untouched.
diff --git a/url/url_util.cc b/url/url_util.cc
index a92d585..1687595 100644
--- a/url/url_util.cc
+++ b/url/url_util.cc
@@ -297,7 +297,7 @@
   } else {
     // Non-special scheme URLs like data: and javascript:.
     if (url::IsUsingStandardCompliantNonSpecialSchemeURLParsing()) {
-      ParseNonSpecialURL(spec, spec_len, &parsed_input);
+      ParseNonSpecialURLInternal(spec, spec_len, trim_path_end, &parsed_input);
       success =
           CanonicalizeNonSpecialURL(spec, spec_len, parsed_input,
                                     charset_converter, *output, *output_parsed);
@@ -492,11 +492,15 @@
     return ReplaceStandardURL(spec, parsed, replacements, scheme_type,
                               charset_converter, output, out_parsed);
   }
-  if (DoCompareSchemeComponent(spec, parsed.scheme, url::kMailToScheme)) {
+  if (!IsUsingStandardCompliantNonSpecialSchemeURLParsing() &&
+      DoCompareSchemeComponent(spec, parsed.scheme, url::kMailToScheme)) {
     return ReplaceMailtoURL(spec, parsed, replacements, output, out_parsed);
   }
 
-  // Default is a path URL.
+  if (IsUsingStandardCompliantNonSpecialSchemeURLParsing()) {
+    return ReplaceNonSpecialURL(spec, parsed, replacements, charset_converter,
+                                *output, *out_parsed);
+  }
   return ReplacePathURL(spec, parsed, replacements, output, out_parsed);
 }
 
diff --git a/url/url_util_unittest.cc b/url/url_util_unittest.cc
index 3e425215..936c521 100644
--- a/url/url_util_unittest.cc
+++ b/url/url_util_unittest.cc
@@ -421,7 +421,8 @@
     if (url::IsUsingStandardCompliantNonSpecialSchemeURLParsing()) {
       ParseNonSpecialURL(test.base, strlen(test.base), &base_parsed);
     } else {
-      ParsePathURL(test.base, strlen(test.base), false, &base_parsed);
+      ParsePathURL(test.base, strlen(test.base), /*trim_path_end=*/true,
+                   &base_parsed);
     }
 
     std::string resolved;
@@ -766,7 +767,8 @@
     if (url::IsUsingStandardCompliantNonSpecialSchemeURLParsing()) {
       ParseNonSpecialURL(test.base.data(), test.base.size(), &base_parsed);
     } else {
-      ParsePathURL(test.base.data(), test.base.size(), false, &base_parsed);
+      ParsePathURL(test.base.data(), test.base.size(), /*trim_path_end=*/true,
+                   &base_parsed);
     }
 
     std::string resolved;
diff --git a/v8 b/v8
index 28312d3..f243ba1 160000
--- a/v8
+++ b/v8
@@ -1 +1 @@
-Subproject commit 28312d3b2ac96a3a325a4a761851c15808a75c12
+Subproject commit f243ba1bf4f7673ff645e31af0370f22e968d19d