diff --git a/DEPS b/DEPS
index 1b8f9db..a0158ff6 100644
--- a/DEPS
+++ b/DEPS
@@ -308,7 +308,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'b4162f6c282524637f0c1fc751809fe68597c02c',
+  'skia_revision': '93912d50850d3f783e2e4dc51bda5667e798dddb',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -316,7 +316,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '3b470cf502e9846e0c355a826cd844a4cf46fda0',
+  'angle_revision': 'df2e7bd7c99e27868947f887355ad11979f6d492',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -359,7 +359,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
-  'freetype_revision': 'a46424228f0998a72c715f32e18dca8a7a764c1f',
+  'freetype_revision': '68399b4244d85a1acc18ce669176b531b2eb7e32',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -383,7 +383,7 @@
   # 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.
-  'chromium_variations_revision': '1545704ff52cfb5119f3693c9a9e971594e9cb43',
+  'chromium_variations_revision': 'ac4104d893a647c86da29a4b3a2a7ba5dd393380',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
@@ -1004,7 +1004,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '23089ba269532c066446db34718544703ecf039e',
+    '5581d135e7c2a518da3872aa95fe0d94d259d1bf',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1163,7 +1163,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'UiIzVBfVIy9mCbzMX3fEPiFC3Vez6AiL1NueeljGtEUC',
+          'version': 'wca_lJQ6FRpEyA5uKD90LCn02gX5VM9Z4mniCykiW-AC',
       },
     ],
     'condition': 'checkout_android',
@@ -1460,7 +1460,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '28ece72a5d752a5e36e62124979b18530e610f6b',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'af58dae320bbe5b28ff312cca870ecbdb6751763',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -2133,7 +2133,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@f1dcf238ad742f936794809f28b0ad0511b6585b',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@e2486aa9a1f0cb28dfa714232dcd1d0d5ec5dca4',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '56300b29fbfcc693ee6609ddad3fdd5b7a449a21',
@@ -2285,7 +2285,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/eche_app/app',
-        'version': 'yT7ULoxNB4ej3D1KDKz8x2izFXFsMqWIfGtuxKlJPQoC',
+        'version': 'R5j2nxwBfmK703n29nR7emkjwrBf-pQtgXywpHbPRSsC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/browser/BUILD.gn b/android_webview/browser/BUILD.gn
index 7efcfb75..4c37d46 100644
--- a/android_webview/browser/BUILD.gn
+++ b/android_webview/browser/BUILD.gn
@@ -270,6 +270,7 @@
     "//components/network_hints/browser",
     "//components/origin_trials:browser",
     "//components/origin_trials:common",
+    "//components/os_crypt/async/browser",
     "//components/page_load_metrics/browser",
     "//components/permissions",
     "//components/policy:generated",
diff --git a/android_webview/browser/DEPS b/android_webview/browser/DEPS
index 9f9f50f..5c4c2ac4 100644
--- a/android_webview/browser/DEPS
+++ b/android_webview/browser/DEPS
@@ -30,6 +30,7 @@
   "+components/network_hints/browser",
   "+components/optimization_guide/core/bloom_filter.h",
   "+components/origin_trials",
+  "+components/os_crypt/async",
   "+components/page_load_metrics/browser",
   "+components/permissions",
   "+components/policy/core/browser",
diff --git a/android_webview/browser/aw_browser_process.cc b/android_webview/browser/aw_browser_process.cc
index 9d28556..c3f4c12 100644
--- a/android_webview/browser/aw_browser_process.cc
+++ b/android_webview/browser/aw_browser_process.cc
@@ -21,6 +21,7 @@
 #include "components/component_updater/android/component_loader_policy.h"
 #include "components/crash/core/common/crash_key.h"
 #include "components/embedder_support/origin_trials/origin_trials_settings_storage.h"
+#include "components/os_crypt/async/browser/os_crypt_async.h"
 #include "components/safe_browsing/core/common/features.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -69,6 +70,12 @@
 
   origin_trials_settings_storage_ =
       std::make_unique<embedder_support::OriginTrialsSettingsStorage>();
+
+  // Initialize OSCryptAsync with no providers. This delegates all encryption
+  // operations to OSCrypt.
+  os_crypt_async_ = std::make_unique<os_crypt_async::OSCryptAsync>(
+      std::vector<
+          std::pair<size_t, std::unique_ptr<os_crypt_async::KeyProvider>>>());
 }
 
 AwBrowserProcess::~AwBrowserProcess() {
@@ -83,6 +90,9 @@
   pref_change_registrar_.Add(prefs::kAuthAndroidNegotiateAccountType,
                              auth_pref_callback);
 
+  // Trigger async initialization of OSCrypt key providers.
+  std::ignore = os_crypt_async_->GetInstance(base::DoNothing());
+
   InitSafeBrowsing();
 }
 
@@ -193,6 +203,10 @@
   return safe_browsing_ui_manager_.get();
 }
 
+os_crypt_async::OSCryptAsync* AwBrowserProcess::GetOSCryptAsync() const {
+  return os_crypt_async_.get();
+}
+
 // static
 void AwBrowserProcess::RegisterNetworkContextLocalStatePrefs(
     PrefRegistrySimple* pref_registry) {
diff --git a/android_webview/browser/aw_browser_process.h b/android_webview/browser/aw_browser_process.h
index a318438..021cfa8a 100644
--- a/android_webview/browser/aw_browser_process.h
+++ b/android_webview/browser/aw_browser_process.h
@@ -16,6 +16,7 @@
 #include "android_webview/browser/safe_browsing/aw_safe_browsing_ui_manager.h"
 #include "base/feature_list.h"
 #include "base/memory/raw_ptr.h"
+#include "components/os_crypt/async/browser/os_crypt_async.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_service.h"
 #include "components/safe_browsing/android/remote_database_manager.h"
@@ -77,6 +78,10 @@
   // Called on UI and IO threads.
   AwSafeBrowsingUIManager* GetSafeBrowsingUIManager() const;
 
+  // Obtain the browser instance of OSCryptAsync, which should be used for data
+  // encryption.
+  os_crypt_async::OSCryptAsync* GetOSCryptAsync() const;
+
   static void RegisterNetworkContextLocalStatePrefs(
       PrefRegistrySimple* pref_registry);
   static void RegisterEnterpriseAuthenticationAppLinkPolicyPref(
@@ -137,6 +142,7 @@
   std::unique_ptr<EnterpriseAuthenticationAppLinkManager> app_link_manager_;
   std::unique_ptr<embedder_support::OriginTrialsSettingsStorage>
       origin_trials_settings_storage_;
+  std::unique_ptr<os_crypt_async::OSCryptAsync> os_crypt_async_;
 };
 
 }  // namespace android_webview
diff --git a/android_webview/browser/aw_content_browser_client_receiver_bindings.cc b/android_webview/browser/aw_content_browser_client_receiver_bindings.cc
index 4e1a3b05..8aff5033 100644
--- a/android_webview/browser/aw_content_browser_client_receiver_bindings.cc
+++ b/android_webview/browser/aw_content_browser_client_receiver_bindings.cc
@@ -287,9 +287,6 @@
 void AwContentBrowserClient::
     RegisterMojoBinderPoliciesForSameOriginPrerendering(
         content::MojoBinderPolicyMap& policy_map) {
-  if (!base::FeatureList::IsEnabled(features::kWebViewPrerender2)) {
-    return;
-  }
   policy_map.SetAssociatedPolicy<page_load_metrics::mojom::PageLoadMetrics>(
       content::MojoBinderAssociatedPolicy::kGrant);
 }
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
index a04bd771..fd322fd 100644
--- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
+++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -989,6 +989,7 @@
         Flag.baseFeature(
                 BlinkFeatures.STATIC_ANIMATION_OPTIMIZATION,
                 "Optimize handling of static properties during animations."),
+        Flag.baseFeature("LazyBindJsInjection"),
         // Add new commandline switches and features above. The final entry should have a
         // trailing comma for cleaner diffs.
     };
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index c2e381c8..aa52952 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -974,6 +974,8 @@
     "picker/metrics/picker_feature_usage_metrics.h",
     "picker/metrics/picker_performance_metrics.cc",
     "picker/metrics/picker_performance_metrics.h",
+    "picker/metrics/picker_session_metrics.cc",
+    "picker/metrics/picker_session_metrics.h",
     "picker/model/picker_model.cc",
     "picker/model/picker_model.h",
     "picker/model/picker_search_results_section.cc",
@@ -3134,7 +3136,6 @@
     "//ash/in_session_auth",
     "//ash/keyboard/ui",
     "//ash/login/resources:resources_grit",
-    "//ash/picker/metrics",
     "//ash/public/cpp/ambient/proto",
     "//ash/public/mojom:hid_preserving_bluetooth_state_controller",
     "//ash/quick_pair",
@@ -4288,7 +4289,6 @@
     "//ash/in_session_auth",
     "//ash/keyboard/ui",
     "//ash/keyboard/ui:test_support",
-    "//ash/picker/metrics",
     "//ash/public/cpp",
     "//ash/public/cpp:test_support",
     "//ash/public/cpp:unit_tests",
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 615b147..d49502d 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -7165,7 +7165,7 @@
         Drive Files
       </message>
       <message name="IDS_PICKER_LOCAL_FILES_CATEGORY_LABEL" translateable="false" desc="Label of the Picker list item which can be clicked to show local file results.">
-        My Files
+        This Chromebook
       </message>
       <message name="IDS_PICKER_DATES_TIMES_CATEGORY_LABEL" translateable="false" desc="Label of the Picker list item which can be clicked to show date and time results.">
         Dates &amp; Times
diff --git a/ash/birch/birch_item.cc b/ash/birch/birch_item.cc
index e3d3143..2a47c9eb 100644
--- a/ash/birch/birch_item.cc
+++ b/ash/birch/birch_item.cc
@@ -111,6 +111,7 @@
     : BirchItem(title, GetSubtitle(start_time, end_time, all_day_event)),
       start_time_(start_time),
       end_time_(end_time),
+      all_day_event_(all_day_event),
       calendar_url_(calendar_url),
       conference_url_(conference_url),
       event_id_(event_id) {
diff --git a/ash/birch/birch_item.h b/ash/birch/birch_item.h
index 064ee707..00af35a 100644
--- a/ash/birch/birch_item.h
+++ b/ash/birch/birch_item.h
@@ -120,6 +120,7 @@
 
   const base::Time& start_time() const { return start_time_; }
   const base::Time& end_time() const { return end_time_; }
+  bool all_day_event() const { return all_day_event_; }
   const GURL& calendar_url() const { return calendar_url_; }
   const GURL& conference_url() const { return conference_url_; }
   const std::string& event_id() const { return event_id_; }
@@ -139,6 +140,7 @@
 
   base::Time start_time_;
   base::Time end_time_;
+  bool all_day_event_;
   // Link to the event in the Google Calendar UI.
   GURL calendar_url_;
   // Video conferencing URL (e.g. Google Meet).
diff --git a/ash/birch/birch_ranker.cc b/ash/birch/birch_ranker.cc
index 5e9bae6..b646496e 100644
--- a/ash/birch/birch_ranker.cc
+++ b/ash/birch/birch_ranker.cc
@@ -37,7 +37,14 @@
   bool found_tomorrow_event = false;
 
   for (BirchCalendarItem& item : *items) {
-    // Ongoing events have priority in the morning.
+    // All-day events have low priority. We only show all-day events from today
+    // (e.g. ongoing all-day events).
+    if (item.all_day_event() && IsOngoingEvent(item)) {
+      item.set_ranking(36.f);
+      continue;
+    }
+
+    // Non-all-day ongoing events have priority in the morning.
     if (is_morning && IsOngoingEvent(item)) {
       item.set_ranking(6.f);
       continue;
@@ -50,7 +57,7 @@
       continue;
     }
 
-    // Ongoing events have medium priority all day.
+    // Non-all-day ongoing events have medium priority all day.
     if (IsOngoingEvent(item)) {
       item.set_ranking(9.f);
       continue;
diff --git a/ash/birch/birch_ranker_unittest.cc b/ash/birch/birch_ranker_unittest.cc
index 36b17ac5..0765198 100644
--- a/ash/birch/birch_ranker_unittest.cc
+++ b/ash/birch/birch_ranker_unittest.cc
@@ -183,6 +183,59 @@
   EXPECT_FLOAT_EQ(items[0].ranking(), 9.f);
 }
 
+TEST(BirchRankerTest, RankCalendarItems_AllDayEvent) {
+  base::test::ScopedRestoreDefaultTimezone timezone("Etc/GMT");
+
+  // Simulate 3 PM.
+  base::Time now = TimeFromString("22 Feb 2024 15:00 UTC");
+  BirchRanker ranker(now);
+
+  // Create an ongoing event (2 PM to 4 PM).
+  BirchCalendarItem item0(
+      u"Ongoing",
+      /*start_time=*/TimeFromString("22 Feb 2024 14:00 UTC"),
+      /*end_time=*/TimeFromString("22 Feb 2024 16:00 UTC"),
+      /*calendar_url=*/GURL(),
+      /*conference_url=*/GURL(),
+      /*event_id=*/"",
+      /*all_day_event=*/false);
+
+  // Create an all-day event for today.
+  BirchCalendarItem item1(
+      u"All Day",
+      /*start_time=*/TimeFromString("22 Feb 2024 00:00 UTC"),
+      /*end_time=*/TimeFromString("23 Feb 2024 00:00 UTC"),
+      /*calendar_url=*/GURL(),
+      /*conference_url=*/GURL(),
+      /*event_id=*/"",
+      /*all_day_event=*/true);
+
+  // Create an all-day event for tomorrow.
+  BirchCalendarItem item2(
+      u"All Day",
+      /*start_time=*/TimeFromString("23 Feb 2024 00:00 UTC"),
+      /*end_time=*/TimeFromString("24 Feb 2024 00:00 UTC"),
+      /*calendar_url=*/GURL(),
+      /*conference_url=*/GURL(),
+      /*event_id=*/"",
+      /*all_day_event=*/true);
+  std::vector<BirchCalendarItem> items = {item2, item1, item0};
+
+  ranker.RankCalendarItems(&items);
+
+  ASSERT_EQ(3u, items.size());
+
+  // The events are sorted by start time so today's all day event is first. It
+  // has low priority.
+  EXPECT_FLOAT_EQ(items[0].ranking(), 36.f);
+
+  // The non-all-day ongoing event has higher priority.
+  EXPECT_FLOAT_EQ(items[1].ranking(), 9.f);
+
+  // The all-day event for tomorrow is not ranked.
+  EXPECT_FLOAT_EQ(items[2].ranking(), std::numeric_limits<float>::max());
+}
+
 TEST(BirchRankerTest, RankAttachmentItems_Morning) {
   base::test::ScopedRestoreDefaultTimezone timezone("Etc/GMT");
 
diff --git a/ash/picker/metrics/BUILD.gn b/ash/picker/metrics/BUILD.gn
deleted file mode 100644
index ac425e7..0000000
--- a/ash/picker/metrics/BUILD.gn
+++ /dev/null
@@ -1,26 +0,0 @@
-# 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("//build/config/chromeos/ui_mode.gni")
-
-assert(is_chromeos_ash)
-
-# PickerSessionMetrics class is dependent on
-# //components/metrics/structured:structured_events,
-# which is a static_library. As a result, we cannot put PickerSessionMetrics
-# class into //ash:ash, which is a component, otherwise unit tests would fail in
-# debug mode, where is_component_build is set to true by default.
-static_library("metrics") {
-  sources = [
-    "picker_session_metrics.cc",
-    "picker_session_metrics.h",
-  ]
-
-  deps = [
-    "//ash/public/cpp:cpp",
-    "//base",
-    "//components/metrics/structured:structured_events",
-    "//ui/base/ime",
-  ]
-}
diff --git a/ash/picker/metrics/picker_session_metrics.h b/ash/picker/metrics/picker_session_metrics.h
index 88a5fab..1a9a40d 100644
--- a/ash/picker/metrics/picker_session_metrics.h
+++ b/ash/picker/metrics/picker_session_metrics.h
@@ -8,6 +8,7 @@
 #include <optional>
 #include <string>
 
+#include "ash/ash_export.h"
 #include "ash/public/cpp/picker/picker_category.h"
 #include "ash/public/cpp/picker/picker_search_result.h"
 
@@ -18,7 +19,7 @@
 namespace ash {
 
 // Records metrics for a session of using Picker.
-class PickerSessionMetrics {
+class ASH_EXPORT PickerSessionMetrics {
  public:
   // These values are persisted to logs. Entries should not be renumbered and
   // numeric values should never be reused.
diff --git a/ash/picker/search/picker_category_search_unittest.cc b/ash/picker/search/picker_category_search_unittest.cc
index 7f09b0c9..f138e35c 100644
--- a/ash/picker/search/picker_category_search_unittest.cc
+++ b/ash/picker/search/picker_category_search_unittest.cc
@@ -53,43 +53,43 @@
         // Exact match
         TestCase{
             .available_categories = {PickerCategory::kLocalFiles},
-            .query = u"My Files",
+            .query = u"This Chromebook",
             .expected_categories = {PickerCategory::kLocalFiles},
         },
         // Case-insensitive match
         TestCase{
             .available_categories = {PickerCategory::kLocalFiles},
-            .query = u"mY fIlEs",
+            .query = u"tHiS cHrOmEbOoK",
             .expected_categories = {PickerCategory::kLocalFiles},
         },
         // Prefix match
         TestCase{
             .available_categories = {PickerCategory::kLocalFiles},
-            .query = u"m",
+            .query = u"t",
             .expected_categories = {PickerCategory::kLocalFiles},
         },
         // Prefix match in second word
         TestCase{
             .available_categories = {PickerCategory::kLocalFiles},
-            .query = u"fi",
+            .query = u"ch",
             .expected_categories = {PickerCategory::kLocalFiles},
         },
         // Substring match
         TestCase{
             .available_categories = {PickerCategory::kLocalFiles},
-            .query = u"iles",
+            .query = u"rome",
             .expected_categories = {},
         },
         // Category unavailable
         TestCase{
             .available_categories = {PickerCategory::kLinks},
-            .query = u"My Files",
+            .query = u"This Chromebook",
             .expected_categories = {},
         },
         // Not matched
         TestCase{
             .available_categories = {PickerCategory::kLocalFiles},
-            .query = u"My Files1",
+            .query = u"This Chromebookz",
             .expected_categories = {},
         }));
 
diff --git a/ash/shell.cc b/ash/shell.cc
index f1fb292..d673f9fd 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -672,6 +672,10 @@
   return shell_delegate_->GetDeskProfilesDelegate();
 }
 
+WebAuthNDialogController* Shell::webauthn_dialog_controller() {
+  return webauthn_dialog_controller_.get();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Shell, private:
 
diff --git a/ash/shell.h b/ash/shell.h
index f946ec1..fb25a07 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -173,6 +173,7 @@
 class InputDeviceSettingsControllerImpl;
 class InputDeviceSettingsDispatcher;
 class InputDeviceTracker;
+class WebAuthNDialogController;
 class WebAuthNDialogControllerImpl;
 class KeyAccessibilityEnabler;
 class KeyboardBacklightColorController;
@@ -601,9 +602,7 @@
     return human_presence_orientation_controller_.get();
   }
   ImeControllerImpl* ime_controller() { return ime_controller_.get(); }
-  WebAuthNDialogControllerImpl* webauthn_dialog_controller() {
-    return webauthn_dialog_controller_.get();
-  }
+  WebAuthNDialogController* webauthn_dialog_controller();
   InSessionAuthDialogControllerImpl* in_session_auth_dialog_controller() {
     return in_session_auth_dialog_controller_.get();
   }
diff --git a/ash/system/mahi/mahi_panel_drag_controller_unittest.cc b/ash/system/mahi/mahi_panel_drag_controller_unittest.cc
index 818537f..52b29d3 100644
--- a/ash/system/mahi/mahi_panel_drag_controller_unittest.cc
+++ b/ash/system/mahi/mahi_panel_drag_controller_unittest.cc
@@ -31,6 +31,17 @@
   }
   ~MahiPanelDragControllerTest() override = default;
 
+  // AshTestBase:
+  void SetUp() override {
+    AshTestBase::SetUp();
+    ui_controller_.OpenMahiPanel(GetPrimaryDisplay().id());
+  }
+
+  void TearDown() override {
+    ui_controller_.CloseMahiPanel();
+    AshTestBase::TearDown();
+  }
+
   MahiUiController& ui_controller() { return ui_controller_; }
 
  private:
@@ -40,9 +51,7 @@
   chromeos::ScopedMahiManagerSetter scoped_manager_setter_{&mock_mahi_manager_};
 };
 
-// TODO(crbug.com/339619327): Test is flaky.
-TEST_F(MahiPanelDragControllerTest, DISABLED_MouseDragRepositionsPanel) {
-  ui_controller().OpenMahiPanel(GetPrimaryDisplay().id());
+TEST_F(MahiPanelDragControllerTest, MouseDragRepositionsPanel) {
   views::Widget* panel_widget = ui_controller().mahi_panel_widget();
   constexpr gfx::Rect kInitialBounds(100, 100, 200, 300);
   panel_widget->SetBounds(kInitialBounds);
@@ -56,9 +65,7 @@
             kInitialBounds + kDragOffset);
 }
 
-// TODO(crbug.com/339619327): Test is flaky.
-TEST_F(MahiPanelDragControllerTest, DISABLED_GestureDragRepositionsPanel) {
-  ui_controller().OpenMahiPanel(GetPrimaryDisplay().id());
+TEST_F(MahiPanelDragControllerTest, GestureDragRepositionsPanel) {
   views::Widget* panel_widget = ui_controller().mahi_panel_widget();
   constexpr gfx::Rect kInitialBounds(100, 100, 200, 300);
   panel_widget->SetBounds(kInitialBounds);
diff --git a/ash/system/media/media_tray.cc b/ash/system/media/media_tray.cc
index 4e3f737..e4c53aa5 100644
--- a/ash/system/media/media_tray.cc
+++ b/ash/system/media/media_tray.cc
@@ -105,12 +105,21 @@
         l10n_util::GetStringUTF16(IDS_ASH_GLOBAL_MEDIA_CONTROLS_TITLE));
     title_label_->SetAutoColorReadabilityEnabled(false);
 
+    // Media tray should always be pinned to shelf when we are opening the
+    // dialog.
+    DCHECK(MediaTray::IsPinnedToShelf());
+    pin_button_ = AddChildView(std::make_unique<MediaTray::PinButton>());
+
     if (base::FeatureList::IsEnabled(
             media::kGlobalMediaControlsCrOSUpdatedUI)) {
       title_label_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
       TypographyProvider::Get()->StyleLabel(TypographyToken::kCrosTitle1,
                                             *title_label_);
       SetPreferredSize(gfx::Size(kWideTrayMenuWidth, kTitleViewHeight));
+
+      // Makes the title in the center of the card horizontally.
+      title_label_->SetBorder(views::CreateEmptyBorder(
+          gfx::Insets::TLBR(0, pin_button_->GetPreferredSize().width(), 0, 0)));
     } else {
       title_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
       title_label_->SetFontList(views::Label::GetDefaultFontList().Derive(
@@ -118,12 +127,6 @@
           gfx::Font::Weight::MEDIUM));
       SetPreferredSize(gfx::Size(kTrayMenuWidth, kTitleViewHeight));
     }
-
-    // Media tray should always be pinned to shelf when we are opening the
-    // dialog.
-    DCHECK(MediaTray::IsPinnedToShelf());
-    pin_button_ = AddChildView(std::make_unique<MediaTray::PinButton>());
-
     box_layout->SetFlexForView(title_label_, 1);
   }
 
diff --git a/ash/system/video_conference/video_conference_tray_pixeltest.cc b/ash/system/video_conference/video_conference_tray_pixeltest.cc
index 391d0add..f424fe1 100644
--- a/ash/system/video_conference/video_conference_tray_pixeltest.cc
+++ b/ash/system/video_conference/video_conference_tray_pixeltest.cc
@@ -36,9 +36,7 @@
   // AshTestBase:
   void SetUp() override {
     scoped_feature_list_.InitWithFeatures(
-        /*enabled_features=*/{chromeos::features::kJellyroll,
-                              features::kVcStopAllScreenShare,
-                              chromeos::features::kJelly,
+        /*enabled_features=*/{features::kVcStopAllScreenShare,
                               features::kFeatureManagementVideoConference},
         /*disabled_features=*/{features::kVcBackgroundReplace});
     // TODO(b/334375880): Add a specific pixel test for the feature
diff --git a/ash/webui/os_feedback_ui/os_feedback_ui.cc b/ash/webui/os_feedback_ui/os_feedback_ui.cc
index 7f7603f..604f1eeb 100644
--- a/ash/webui/os_feedback_ui/os_feedback_ui.cc
+++ b/ash/webui/os_feedback_ui/os_feedback_ui.cc
@@ -119,6 +119,7 @@
       {"bluetoothLogsMessage", IDS_FEEDBACK_TOOL_BLUETOOTH_LOGS_MESSAGE},
       {"wifiDebugLogsInfo", IDS_FEEDBACK_TOOL_WIFI_DEBUG_LOGS_CHECKBOX},
       {"wifiDebugLogsMessage", IDS_FEEDBACK_TOOL_WIFI_DEBUG_LOGS_MESSAGE},
+      {"wifiDebugLogsTitle", IDS_FEEDBACK_TOOL_WIFI_DEBUG_LOGS_TITLE},
       {"linkCrossDeviceDogfoodFeedbackInfo",
        IDS_FEEDBACK_TOOL_LINK_CROSS_DEVICE_DOGFOOD_FEEDBACK_INFO},
       {"linkCrossDeviceDogfoodFeedbackMessage",
diff --git a/ash/webui/os_feedback_ui/resources/share_data_page.html b/ash/webui/os_feedback_ui/resources/share_data_page.html
index ed9be920..16343b7 100644
--- a/ash/webui/os_feedback_ui/resources/share_data_page.html
+++ b/ash/webui/os_feedback_ui/resources/share_data_page.html
@@ -403,6 +403,9 @@
   </div>
 </cr-dialog>
 <cr-dialog id="wifiDebugLogsDialog">
+  <div id="wifiDebugLogsDialogTitle" slot="title">
+    [[i18n('wifiDebugLogsTitle')]]
+  </div>
   <div slot="body">
     [[i18n('wifiDebugLogsMessage')]]
   </div>
diff --git a/chrome/MAJOR_BRANCH_DATE b/chrome/MAJOR_BRANCH_DATE
index a5f277cf..3740d214 100644
--- a/chrome/MAJOR_BRANCH_DATE
+++ b/chrome/MAJOR_BRANCH_DATE
@@ -1 +1 @@
-MAJOR_BRANCH_DATE=2024-04-16
+MAJOR_BRANCH_DATE=2024-05-14
diff --git a/chrome/VERSION b/chrome/VERSION
index 223f365..da27972 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
-MAJOR=126
+MAJOR=127
 MINOR=0
-BUILD=6478
+BUILD=6479
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index ef0682d1..5683fe0 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -2945,6 +2945,7 @@
       "//chrome/browser/banners/android:javatests",
       "//chrome/browser/download/internal/android:javatests",
       "//chrome/browser/engagement/android:javatests",
+      "//chrome/browser/facilitated_payments/ui/android/internal:javatests",
       "//chrome/browser/flags:javatests",
       "//chrome/browser/gesturenav/android:javatests",
       "//chrome/browser/password_check/android:test_java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/settings/FinancialAccountsManagementFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/settings/FinancialAccountsManagementFragmentTest.java
index 86d249f..c6b275c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/settings/FinancialAccountsManagementFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/settings/FinancialAccountsManagementFragmentTest.java
@@ -192,7 +192,7 @@
 
         String expectedPrefSummary =
                 String.format(
-                        "Pix  •  %s •• %s",
+                        "Pix  •  %s ••••%s",
                         activity.getString(R.string.bank_account_type_checking),
                         PIX_BANK_ACCOUNT.getAccountNumberSuffix());
         Preference bankAccountPref = getBankAccountPreference(activity, PIX_BANK_ACCOUNT);
diff --git a/chrome/android/profiles/arm.newest.txt b/chrome/android/profiles/arm.newest.txt
index 6def4baa..473120b 100644
--- a/chrome/android/profiles/arm.newest.txt
+++ b/chrome/android/profiles/arm.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-126.0.6476.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-arm-126.0.6477.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 669dd35..0a860a8 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -11291,7 +11291,7 @@
 
       <!-- Saved Tab Group V2 -->
       <message name="IDS_TABS_TITLE_CXMENU" desc="The label of the 'Tabs' title in the context menu of a saved tab group.">
-        Tabs
+        Tabs in group
       </message>
       <if expr="not use_titlecase">
         <message name="IDS_SAVED_TAB_GROUP_TABS_COUNT" desc="Title of unnamed saved tab group in Everything menu. [ICU_Syntax]">
@@ -11320,11 +11320,17 @@
       <message name="IDS_TAB_GROUP_DELETION_DIALOG_BODY_SYNCED_DELETE" desc=". Displayed in the Tab Group Deletion Dialog.">
         This will delete the group from all devices signed into Chrome with this Google Account.
       </message>
-
       <message name="IDS_TAB_GROUP_DELETION_DIALOG_BODY_SYNCED_UNGROUP" desc="The body text for ungrouping. Displayed in the Tab Group Deletion Dialog.">
         The tabs will remain open on this device but the group will be deleted from all devices signed into Chrome with this Google Account.
       </message>
 
+      <message name="IDS_TAB_GROUP_DELETION_DIALOG_BODY_NOT_SYNCED_DELETE" desc=". Displayed in the Tab Group Deletion Dialog.">
+        This will permanently delete the group from your device.
+      </message>
+      <message name="IDS_TAB_GROUP_DELETION_DIALOG_BODY_NOT_SYNCED_UNGROUP" desc="The body text for ungrouping. Displayed in the Tab Group Deletion Dialog.">
+        The tabs will remain open on this device but the group will be permanently deleted.
+      </message>
+
       <if expr="use_titlecase">
         <!-- Dont Ask -->
         <message name="IDS_TAB_GROUP_DELETION_DIALOG_DONT_ASK" desc="The label for a checkbox that prevents the dialg from ever showing again on this device. Displayed in the Tab Group Deletion Dialog.">
diff --git a/chrome/app/generated_resources_grd/IDS_TABS_TITLE_CXMENU.png.sha1 b/chrome/app/generated_resources_grd/IDS_TABS_TITLE_CXMENU.png.sha1
index 962eda4..df88fa2 100644
--- a/chrome/app/generated_resources_grd/IDS_TABS_TITLE_CXMENU.png.sha1
+++ b/chrome/app/generated_resources_grd/IDS_TABS_TITLE_CXMENU.png.sha1
@@ -1 +1 @@
-229effe0a163b245740e904e03fc077750d136e1
\ No newline at end of file
+09a2c5d7a11111bd42d7c3370a85be4c2f03c7df
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_TAB_GROUP_DELETION_DIALOG_BODY_NOT_SYNCED_DELETE.png.sha1 b/chrome/app/generated_resources_grd/IDS_TAB_GROUP_DELETION_DIALOG_BODY_NOT_SYNCED_DELETE.png.sha1
new file mode 100644
index 0000000..204030b
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_TAB_GROUP_DELETION_DIALOG_BODY_NOT_SYNCED_DELETE.png.sha1
@@ -0,0 +1 @@
+dae84f2075a802d89bc6fab78543658b174d75e0
\ No newline at end of file
diff --git a/chrome/app/generated_resources_grd/IDS_TAB_GROUP_DELETION_DIALOG_BODY_NOT_SYNCED_UNGROUP.png.sha1 b/chrome/app/generated_resources_grd/IDS_TAB_GROUP_DELETION_DIALOG_BODY_NOT_SYNCED_UNGROUP.png.sha1
new file mode 100644
index 0000000..760019f
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_TAB_GROUP_DELETION_DIALOG_BODY_NOT_SYNCED_UNGROUP.png.sha1
@@ -0,0 +1 @@
+0739bc58d16d8dab8876526b1514b75dc3c76870
\ No newline at end of file
diff --git a/chrome/app/gmc_strings.grdp b/chrome/app/gmc_strings.grdp
index 4fd5eb1..043b1e5 100644
--- a/chrome/app/gmc_strings.grdp
+++ b/chrome/app/gmc_strings.grdp
@@ -59,6 +59,6 @@
    Report an issue with Google Cast
   </message>
   <message name="IDS_MEDIA_TOOLBAR_CONTEXT_SHOW_OTHER_SESSIONS" desc="Title of a menu item which, on click, toggles (shows or hides) Cast sessions started by other devices on the same network.">
-   Show other Cast sessions
+   Show other cast sessions
   </message>
 </grit-part>
diff --git a/chrome/app/media_router_strings.grdp b/chrome/app/media_router_strings.grdp
index cd02554..f2fe1fe 100644
--- a/chrome/app/media_router_strings.grdp
+++ b/chrome/app/media_router_strings.grdp
@@ -70,10 +70,10 @@
     </message>
   </if>
   <message name="IDS_MEDIA_ROUTER_ISSUE_CREATE_ROUTE_USER_PENDING_AUTHORIZATION" desc="Title of a notification shown while waiting for the user to accept or reject the cast request.">
-      Accept Cast request on your <ph name="DEVICE_NAME">$1</ph>.
+      Accept cast request on your <ph name="DEVICE_NAME">$1</ph>.
   </message>
   <message name="IDS_MEDIA_ROUTER_ISSUE_CREATE_ROUTE_USER_NOT_ALLOWED" desc="Title of an issue shown when the user rejects the cast request.">
-      Make sure to accept the Cast request on your <ph name="DEVICE_NAME">$1</ph>.
+      Make sure to accept the cast request on your <ph name="DEVICE_NAME">$1</ph>.
   </message>
   <message name="IDS_MEDIA_ROUTER_ISSUE_CREATE_ROUTE_NOTIFICATION_DISABLED" desc="Title of an issue shown when the notifications on the reciever device is disabled.">
       Make sure notifications are turned on on your <ph name="DEVICE_NAME">$1</ph>.
@@ -97,7 +97,7 @@
     No devices found. Open a help center article in a new tab.
   </message>
   <message name="IDS_MEDIA_ROUTER_DESTINATION_MISSING" desc="Link to display when no Cast destinations are found which, on click, opens a page to the Chromecast help center explaining possible reasons why none are detected.">
-    No Cast destinations found. Need help?
+    No cast destinations found. Need help?
   </message>
   <message name="IDS_MEDIA_ROUTER_SINK_AVAILABLE" desc="Text shown as the status of a Cast destination that the user can Cast to." meaning="Device status shown in Cast dialog">
     Available
@@ -171,7 +171,7 @@
     Optimize fullscreen casting?
   </message>
   <message name="IDS_MEDIA_ROUTER_REMOTING_DIALOG_BODY_TEXT" desc="Body text shown in the dialog to enable/disable Media Remoting. Media Remoting is a feature that can be enabled during a Cast session for improved playback.">
-    Get better quality video and save battery life. Video will play only on your Cast-enabled screen.
+    Get better quality video and save battery life. Video will play only on your cast-enabled screen.
   </message>
   <message name="IDS_MEDIA_ROUTER_REMOTING_DIALOG_CHECKBOX" desc="Label for the checkbox that the user can click on to get their preference to enable/disable Media Remoting recorded. Media Remoting is a feature that can be enabled during a Cast session for improved playback.">
     Don't ask again
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index c9ff70a..041e881 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3144,6 +3144,8 @@
       "content_settings/request_desktop_site_web_contents_observer_android.cc",
       "content_settings/request_desktop_site_web_contents_observer_android.h",
       "data_sharing/android/data_sharing_service_factory_android.cc",
+      "data_sharing/data_sharing_ui_delegate_android.cc",
+      "data_sharing/data_sharing_ui_delegate_android.h",
       "device_reauth/android/device_authenticator_android.cc",
       "device_reauth/android/device_authenticator_android.h",
       "device_reauth/android/device_authenticator_bridge.h",
@@ -5963,8 +5965,14 @@
       "supervised_user/chromeos/supervised_user_web_content_handler_impl.h",
       "usb/usb_pinned_notification.cc",
       "usb/usb_pinned_notification.h",
+      "webauthn/chromeos/passkey_authenticator.cc",
+      "webauthn/chromeos/passkey_authenticator.h",
       "webauthn/chromeos/passkey_dialog_controller.cc",
       "webauthn/chromeos/passkey_dialog_controller.h",
+      "webauthn/chromeos/passkey_discovery.cc",
+      "webauthn/chromeos/passkey_discovery.h",
+      "webauthn/chromeos/passkey_in_session_auth.cc",
+      "webauthn/chromeos/passkey_in_session_auth.h",
       "webauthn/chromeos/passkey_service.cc",
       "webauthn/chromeos/passkey_service.h",
       "webauthn/chromeos/passkey_service_factory.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index b518d93..0063a49 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -5182,6 +5182,10 @@
     {"draw-edge-to-edge", flag_descriptions::kDrawEdgeToEdgeName,
      flag_descriptions::kDrawEdgeToEdgeDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kDrawEdgeToEdge)},
+    {"draw-key-native-edge-to-edge",
+     flag_descriptions::kDrawKeyNativeEdgeToEdgeName,
+     flag_descriptions::kDrawKeyNativeEdgeToEdgeDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kDrawKeyNativeEdgeToEdge)},
     {"draw-native-edge-to-edge", flag_descriptions::kDrawNativeEdgeToEdgeName,
      flag_descriptions::kDrawNativeEdgeToEdgeDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kDrawNativeEdgeToEdge)},
diff --git a/chrome/browser/ash/arc/tracing/arc_system_stat_collector_unittest.cc b/chrome/browser/ash/arc/tracing/arc_system_stat_collector_unittest.cc
index b8521d5ce..f69a986 100644
--- a/chrome/browser/ash/arc/tracing/arc_system_stat_collector_unittest.cc
+++ b/chrome/browser/ash/arc/tracing/arc_system_stat_collector_unittest.cc
@@ -26,7 +26,7 @@
   base::FilePath base_path;
   base::PathService::Get(chrome::DIR_TEST_DATA, &base_path);
   const base::FilePath path =
-      base_path.Append("arc_graphics_tracing").Append(name);
+      base_path.Append("arc_overview_tracing").Append(name);
   base::ScopedFD result(open(path.value().c_str(), O_RDONLY));
   DCHECK_GE(result.get(), 0);
   return result;
@@ -68,7 +68,7 @@
   base::FilePath base_path;
   base::PathService::Get(chrome::DIR_TEST_DATA, &base_path);
   const base::FilePath path =
-      base_path.Append("arc_graphics_tracing").Append("system_stat_collector");
+      base_path.Append("arc_overview_tracing").Append("system_stat_collector");
   std::string json_content;
   ASSERT_TRUE(base::ReadFileToString(path, &json_content));
   ArcSystemStatCollector collector;
diff --git a/chrome/browser/ash/arc/tracing/arc_tracing_model_unittest.cc b/chrome/browser/ash/arc/tracing/arc_tracing_model_unittest.cc
index ce7da1a..b3838d0 100644
--- a/chrome/browser/ash/arc/tracing/arc_tracing_model_unittest.cc
+++ b/chrome/browser/ash/arc/tracing/arc_tracing_model_unittest.cc
@@ -119,7 +119,7 @@
   base::FilePath base_path;
   base::PathService::Get(chrome::DIR_TEST_DATA, &base_path);
   const base::FilePath tracing_path =
-      base_path.Append("arc_graphics_tracing").Append(name);
+      base_path.Append("arc_overview_tracing").Append(name);
   std::string json_data;
   base::ReadFileToString(tracing_path, &json_data);
   DCHECK(!json_data.empty());
@@ -162,7 +162,7 @@
   base::FilePath base_path;
   base::PathService::Get(chrome::DIR_TEST_DATA, &base_path);
   const base::FilePath tracing_path =
-      base_path.Append("arc_graphics_tracing").Append("trace.dat.gz");
+      base_path.Append("arc_overview_tracing").Append("trace.dat.gz");
 
   std::string tracing_data_compressed;
   ASSERT_TRUE(base::ReadFileToString(tracing_path, &tracing_data_compressed));
@@ -550,7 +550,7 @@
   base::FilePath base_path;
   base::PathService::Get(chrome::DIR_TEST_DATA, &base_path);
   const base::FilePath tracing_path =
-      base_path.Append("arc_graphics_tracing").Append("trace_time.dat");
+      base_path.Append("arc_overview_tracing").Append("trace_time.dat");
 
   std::string tracing_data;
   ASSERT_TRUE(base::ReadFileToString(tracing_path, &tracing_data));
@@ -597,7 +597,7 @@
 TEST_F(ArcTracingModelTest, AsynchronousSystemEvents) {
   base::FilePath base_path;
   base::PathService::Get(chrome::DIR_TEST_DATA, &base_path);
-  const base::FilePath tracing_path = base_path.Append("arc_graphics_tracing")
+  const base::FilePath tracing_path = base_path.Append("arc_overview_tracing")
                                           .Append("trace_async_events.json");
   std::string tracing_data;
   base::ReadFileToString(tracing_path, &tracing_data);
diff --git a/chrome/browser/ash/arc/tracing/overview_tracing_handler_unittest.cc b/chrome/browser/ash/arc/tracing/overview_tracing_handler_unittest.cc
index 1d3c3a7..05ac82b 100644
--- a/chrome/browser/ash/arc/tracing/overview_tracing_handler_unittest.cc
+++ b/chrome/browser/ash/arc/tracing/overview_tracing_handler_unittest.cc
@@ -64,11 +64,6 @@
         base::BindRepeating(&OverviewTracingHandlerTest::OnGraphicsModelReady,
                             weak_ptr_factory_.GetWeakPtr()));
 
-    local_pref_service_ = std::make_unique<TestingPrefServiceSimple>();
-    TestingBrowserProcess::GetGlobal()->SetLocalState(
-        local_pref_service_.get());
-    arc::prefs::RegisterLocalStatePrefs(local_pref_service_->registry());
-
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         ash::switches::kEnableArcVm);
 
@@ -83,9 +78,6 @@
   void TearDown() override {
     icu::TimeZone::setDefault(*saved_tz_);
 
-    TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr);
-    local_pref_service_.reset();
-
     handler_.reset();
     wm_helper_.reset();
 
@@ -129,8 +121,6 @@
   std::vector<std::string> events_;
   base::Value model_;
 
-  std::unique_ptr<TestingPrefServiceSimple> local_pref_service_;
-
   base::WeakPtrFactory<OverviewTracingHandlerTest> weak_ptr_factory_;
 };
 
diff --git a/chrome/browser/ash/crosapi/automation_ash.cc b/chrome/browser/ash/crosapi/automation_ash.cc
index add71aa1..65711581 100644
--- a/chrome/browser/ash/crosapi/automation_ash.cc
+++ b/chrome/browser/ash/crosapi/automation_ash.cc
@@ -47,6 +47,7 @@
   for (auto& client : automation_client_remotes_) {
     client->Disable();
   }
+  desktop_enabled_ = false;
 }
 
 void AutomationAsh::DispatchAccessibilityEvents(
@@ -95,8 +96,11 @@
     mojo::PendingReceiver<crosapi::mojom::Automation> automation) {
   mojo::Remote<mojom::AutomationClient> remote(std::move(automation_client));
 
-  if (desktop_enabled_)
+  if (desktop_enabled_) {
     remote->Enable();
+  } else {
+    remote->Disable();
+  }
 
   automation_client_remotes_.Add(std::move(remote));
   automation_receivers_.Add(this, std::move(automation));
diff --git a/chrome/browser/ash/input_method/native_input_method_engine_observer.cc b/chrome/browser/ash/input_method/native_input_method_engine_observer.cc
index 41c85b1d..1092716 100644
--- a/chrome/browser/ash/input_method/native_input_method_engine_observer.cc
+++ b/chrome/browser/ash/input_method/native_input_method_engine_observer.cc
@@ -873,6 +873,11 @@
     const std::string& engine_id,
     int context_id,
     const TextInputMethod::InputContext& context) {
+  if (IsJapaneseEngine(engine_id)) {
+    UMA_HISTOGRAM_BOOLEAN(
+        "InputMethod.PhysicalKeyboard.Japanese.OnFocusMigratedToSystemPk",
+        !ShouldInitializeJpPrefsFromLegacyConfig(*prefs_));
+  }
   text_client_ =
       TextClient{.context_id = context_id, .state = TextClientState::kPending};
   if (chromeos::features::IsOrcaEnabled() && editor_event_sink_) {
diff --git a/chrome/browser/ash/login/screens/osauth/password_selection_screen_browsertest.cc b/chrome/browser/ash/login/screens/osauth/password_selection_screen_browsertest.cc
index 4cf2bd0..a50379c 100644
--- a/chrome/browser/ash/login/screens/osauth/password_selection_screen_browsertest.cc
+++ b/chrome/browser/ash/login/screens/osauth/password_selection_screen_browsertest.cc
@@ -253,7 +253,9 @@
             PasswordSelectionScreen::Result::LOCAL_PASSWORD_FORCED);
 }
 
-IN_PROC_BROWSER_TEST_F(PasswordSelectionScreenTest, RecoveryGaiaPassword) {
+// TODO(crbug.com/337379954): Flaky on linux-chromeos-chrome.
+IN_PROC_BROWSER_TEST_F(PasswordSelectionScreenTest,
+                       DISABLED_RecoveryGaiaPassword) {
   StartLogin();
   auto user_context = BorrowUserContext();
   LoginDisplayHost::default_host()
diff --git a/chrome/browser/ash/login/session/user_session_initializer.cc b/chrome/browser/ash/login/session/user_session_initializer.cc
index 32b9def..451974cb 100644
--- a/chrome/browser/ash/login/session/user_session_initializer.cc
+++ b/chrome/browser/ash/login/session/user_session_initializer.cc
@@ -288,8 +288,7 @@
   if (is_primary_user) {
     DCHECK_EQ(primary_profile_, profile);
 
-    // Ensure that the `BirchKeyedService` for `profile` is created. It is
-    // created one per user in a multiprofile session.
+    // Ensure that one `BirchKeyedService` is created for the primary profile.
     BirchKeyedServiceFactory::GetInstance()->GetService(profile);
 
     // Ensure that PhoneHubManager and EcheAppManager are created for the
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 367d47be..85ef068 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -26,6 +26,7 @@
         <structure type="lottie" name="IDR_WEBAUTHN_GPM_PIN_DARK" file="resources/webauthn/gpm_pin_dark.json" compress="brotli" />
         <structure type="lottie" name="IDR_WEBAUTHN_LAPTOP_LIGHT" file="resources/webauthn/laptop_light.json" compress="brotli" />
         <structure type="lottie" name="IDR_WEBAUTHN_LAPTOP_DARK" file="resources/webauthn/laptop_dark.json" compress="brotli" />
+        <structure type="lottie" name="IDR_WEBAUTHN_GPM_INCOGNITO" file="resources/webauthn/gpm_incognito.json" compress="brotli" />
       </if>
     </structures>
     <includes>
@@ -185,11 +186,11 @@
         <include name="IDR_SYS_INTERNALS_IMAGE_MEMORY_SVG" file="resources\chromeos\sys_internals\img\memory.svg" type="BINDATA" />
         <include name="IDR_SYS_INTERNALS_IMAGE_ZRAM_SVG" file="resources\chromeos\sys_internals\img\zram.svg" type="BINDATA" />
         <include name="IDR_SMART_DIM_20190521_EXAMPLE_PREPROCESSOR_CONFIG_PB" file="ash\power\ml\smart_dim\20190521_example_preprocessor_config.pb" type="BINDATA" />
-        <include name="IDR_ARC_OVERVIEW_TRACING_HTML" file="resources\chromeos\arc_graphics_tracing\arc_overview_tracing.html" type="BINDATA"/>
-        <include name="IDR_ARC_OVERVIEW_TRACING_JS" file="resources\chromeos\arc_graphics_tracing\arc_overview_tracing.js" type="BINDATA" />
-        <include name="IDR_ARC_OVERVIEW_TRACING_UI_JS" file="resources\chromeos\arc_graphics_tracing\arc_overview_tracing_ui.js" type="BINDATA" />
-        <include name="IDR_ARC_TRACING_UI_JS" file="resources\chromeos\arc_graphics_tracing\arc_tracing_ui.js" type="BINDATA" />
-        <include name="IDR_ARC_TRACING_CSS" file="resources\chromeos\arc_graphics_tracing\arc_tracing.css" type="BINDATA" />
+        <include name="IDR_ARC_OVERVIEW_TRACING_HTML" file="resources\chromeos\arc_overview_tracing\arc_overview_tracing.html" type="BINDATA"/>
+        <include name="IDR_ARC_OVERVIEW_TRACING_JS" file="resources\chromeos\arc_overview_tracing\arc_overview_tracing.js" type="BINDATA" />
+        <include name="IDR_ARC_OVERVIEW_TRACING_UI_JS" file="resources\chromeos\arc_overview_tracing\arc_overview_tracing_ui.js" type="BINDATA" />
+        <include name="IDR_ARC_TRACING_UI_JS" file="resources\chromeos\arc_overview_tracing\arc_tracing_ui.js" type="BINDATA" />
+        <include name="IDR_ARC_TRACING_CSS" file="resources\chromeos\arc_overview_tracing\arc_tracing.css" type="BINDATA" />
         <include name="IDR_ARC_POWER_CONTROL_HTML" file="resources\chromeos\arc_power_control\arc_power_control.html" type="BINDATA"/>
         <include name="IDR_ARC_POWER_CONTROL_JS" file="resources\chromeos\arc_power_control\arc_power_control.js" type="BINDATA" />
         <include name="IDR_ARC_POWER_CONTROL_CSS" file="resources\chromeos\arc_power_control\arc_power_control.css" type="BINDATA" />
diff --git a/chrome/browser/chromeos/printing/print_preview/print_view_manager_cros.cc b/chrome/browser/chromeos/printing/print_preview/print_view_manager_cros.cc
index 995cb7ff..67b3171 100644
--- a/chrome/browser/chromeos/printing/print_preview/print_view_manager_cros.cc
+++ b/chrome/browser/chromeos/printing/print_preview/print_view_manager_cros.cc
@@ -17,7 +17,10 @@
 
 PrintViewManagerCros::PrintViewManagerCros(content::WebContents* web_contents)
     : PrintViewManagerCrosBase(web_contents),
-      content::WebContentsUserData<PrintViewManagerCros>(*web_contents) {}
+      content::WebContentsUserData<PrintViewManagerCros>(*web_contents),
+      token_(base::UnguessableToken::Create()) {}
+
+PrintViewManagerCros::~PrintViewManagerCros() = default;
 
 // static
 void PrintViewManagerCros::BindPrintManagerHost(
diff --git a/chrome/browser/chromeos/printing/print_preview/print_view_manager_cros.h b/chrome/browser/chromeos/printing/print_preview/print_view_manager_cros.h
index f6504b1..b93d1da 100644
--- a/chrome/browser/chromeos/printing/print_preview/print_view_manager_cros.h
+++ b/chrome/browser/chromeos/printing/print_preview/print_view_manager_cros.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_CHROMEOS_PRINTING_PRINT_PREVIEW_PRINT_VIEW_MANAGER_CROS_H_
 #define CHROME_BROWSER_CHROMEOS_PRINTING_PRINT_PREVIEW_PRINT_VIEW_MANAGER_CROS_H_
 
+#include "base/unguessable_token.h"
 #include "chrome/browser/chromeos/printing/print_preview/print_view_manager_cros_base.h"
 #include "components/printing/common/print.mojom-forward.h"
 #include "content/public/browser/web_contents_user_data.h"
@@ -28,7 +29,7 @@
   PrintViewManagerCros(const PrintViewManagerCros&) = delete;
   PrintViewManagerCros& operator=(const PrintViewManagerCros&) = delete;
 
-  ~PrintViewManagerCros() override = default;
+  ~PrintViewManagerCros() override;
 
   static void BindPrintManagerHost(
       mojo::PendingAssociatedReceiver<::printing::mojom::PrintManagerHost>
@@ -64,6 +65,10 @@
 
   // The current RFH that is print previewing.
   raw_ptr<content::RenderFrameHost> render_frame_host_ = nullptr;
+  // Unique ID of the webcontent tied to this instance. This token is created
+  // by this class and is passed to clients interested in identifying the
+  // webcontents.
+  base::UnguessableToken token_;
 
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 };
diff --git a/chrome/browser/client_hints/client_hints_browsertest.cc b/chrome/browser/client_hints/client_hints_browsertest.cc
index 69d28bd..22a6e50 100644
--- a/chrome/browser/client_hints/client_hints_browsertest.cc
+++ b/chrome/browser/client_hints/client_hints_browsertest.cc
@@ -4876,40 +4876,6 @@
       << main_frame_ua_form_factors_observed();
 }
 
-class GreaseEnterprisePolicyTest : public ClientHintsBrowserTest {
-  void SetUpInProcessBrowserTestFixture() override {
-    policy::PolicyTest::SetUpInProcessBrowserTestFixture();
-    policy::PolicyMap policies;
-    SetPolicy(&policies, policy::key::kUserAgentClientHintsGREASEUpdateEnabled,
-              std::optional<base::Value>(false));
-    provider_.UpdateChromePolicy(policies);
-  }
-};
-
-// Makes sure that the enterprise policy is able to prevent updated GREASE.
-IN_PROC_BROWSER_TEST_F(GreaseEnterprisePolicyTest, GreaseEnterprisePolicyTest) {
-  const GURL gurl = accept_ch_url();
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
-  std::string ua_ch_result = main_frame_ua_observed();
-
-  ASSERT_TRUE(SawOldGrease(ua_ch_result));
-}
-IN_PROC_BROWSER_TEST_F(GreaseEnterprisePolicyTest,
-                       GreaseEnterprisePolicyDynamicRefreshTest) {
-  const GURL gurl = accept_ch_url();
-  // Reset the policy that was already set to false in the setup, then see if
-  // the change is reflected in the sec-ch-ua header without requiring a
-  // browser restart.
-  policy::PolicyMap policies;
-  SetPolicy(&policies, policy::key::kUserAgentClientHintsGREASEUpdateEnabled,
-            std::optional<base::Value>(true));
-  provider_.UpdateChromePolicy(policies);
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
-  std::string ua_ch_result = main_frame_ua_observed();
-
-  ASSERT_TRUE(SawUpdatedGrease(ua_ch_result) && !SawOldGrease(ua_ch_result));
-}
-
 // Tests that user-agent reduction on a redirect request.
 class RedirectUaReductionBrowserTest : public InProcessBrowserTest {
  public:
diff --git a/chrome/browser/compose/chrome_compose_client.cc b/chrome/browser/compose/chrome_compose_client.cc
index 76cdc70..d0899b0 100644
--- a/chrome/browser/compose/chrome_compose_client.cc
+++ b/chrome/browser/compose/chrome_compose_client.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/segmentation_platform/segmentation_platform_service_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/translate/chrome_translate_client.h"
 #include "chrome/browser/ui/browser.h"
@@ -76,11 +77,15 @@
 ChromeComposeClient::ChromeComposeClient(content::WebContents* web_contents)
     : content::WebContentsObserver(web_contents),
       content::WebContentsUserData<ChromeComposeClient>(*web_contents),
-      translate_language_provider_(new TranslateLanguageProvider()) {
+      translate_language_provider_(new TranslateLanguageProvider()),
+      profile_(
+          Profile::FromBrowserContext(GetWebContents().GetBrowserContext())),
+      nudge_tracker_(segmentation_platform::SegmentationPlatformServiceFactory::
+                         GetForProfile(profile_),
+                     this) {
   auto ukm_source_id =
       GetWebContents().GetPrimaryMainFrame()->GetPageUkmSourceId();
   page_ukm_tracker_ = std::make_unique<compose::PageUkmTracker>(ukm_source_id);
-  profile_ = Profile::FromBrowserContext(GetWebContents().GetBrowserContext());
   opt_guide_ = OptimizationGuideKeyedServiceFactory::GetForProfile(profile_);
   pref_service_ = profile_->GetPrefs();
   proactive_nudge_enabled_.Init(prefs::kEnableProactiveNudge, pref_service_);
diff --git a/chrome/browser/compose/chrome_compose_client.h b/chrome/browser/compose/chrome_compose_client.h
index 47eb60c..4f0effc 100644
--- a/chrome/browser/compose/chrome_compose_client.h
+++ b/chrome/browser/compose/chrome_compose_client.h
@@ -271,7 +271,7 @@
 
   // A state machine that decides whether the proactive nudge should be shown at
   // a given moment.
-  compose::ProactiveNudgeTracker nudge_tracker_{this};
+  compose::ProactiveNudgeTracker nudge_tracker_;
 
   // Observer for autofill field focus changes. This is used to prevent showing
   // the saved state notification on a previous focused field when an autofill
diff --git a/chrome/browser/compose/proactive_nudge_tracker.cc b/chrome/browser/compose/proactive_nudge_tracker.cc
index d57e997..4467608 100644
--- a/chrome/browser/compose/proactive_nudge_tracker.cc
+++ b/chrome/browser/compose/proactive_nudge_tracker.cc
@@ -5,13 +5,23 @@
 #include "chrome/browser/compose/proactive_nudge_tracker.h"
 
 #include "components/compose/core/browser/config.h"
+#include "components/segmentation_platform/public/constants.h"
 
 namespace compose {
 
-ProactiveNudgeTracker::ProactiveNudgeTracker(Delegate* delegate)
-    : delegate_(delegate) {}
+ProactiveNudgeTracker::State::State() = default;
+ProactiveNudgeTracker::State::~State() = default;
+
+ProactiveNudgeTracker::ProactiveNudgeTracker(
+    segmentation_platform::SegmentationPlatformService* segmentation_service,
+    Delegate* delegate)
+    : segmentation_service_(segmentation_service), delegate_(delegate) {}
 
 void ProactiveNudgeTracker::StartObserving(content::WebContents* web_contents) {
+  if (!SegmentationStateIsValid()) {
+    // Unable to show proactive nudge if configuration is not consistent.
+    return;
+  }
   autofill_managers_observation_.Observe(
       web_contents, autofill::ScopedAutofillManagersObservation::
                         InitializationPolicy::kObservePreexistingManagers);
@@ -22,6 +32,10 @@
 bool ProactiveNudgeTracker::ProactiveNudgeRequestedForFormField(
     const autofill::FormFieldData& field_to_track) {
   DVLOG(2) << "ProactiveNudgeTracker: ProactiveNudgeRequestedForFormField";
+  if (!SegmentationStateIsValid()) {
+    // Unable to show proactive nudge if configuration is not consistent.
+    return false;
+  }
   if (MatchesCurrentField(field_to_track.renderer_form_id(),
                           field_to_track.global_id())) {
     DVLOG(2) << "ProactiveNudgeTracker: Init with matching field";
@@ -33,29 +47,44 @@
   }
 
   // Reset to UNINITIALIZED, then immediately transition to WAITING.
-  timer_.Stop();
-  state_ = State();
+  ResetState();
+  state_ = std::make_unique<State>();
 
   state_->form = field_to_track.renderer_form_id();
   state_->field = field_to_track.global_id();
   state_->initial_text_value = field_to_track.value();
 
-  auto delay = compose::GetComposeConfig().proactive_nudge_delay;
+  if (compose::GetComposeConfig().proactive_nudge_segmentation) {
+    segmentation_platform::PredictionOptions options;
+    options.on_demand_execution = true;
+    segmentation_service_->GetClassificationResult(
+        segmentation_platform::kComposePromotionKey, options, nullptr,
+        base::BindOnce(&ProactiveNudgeTracker::GotClassificationResult,
+                       weak_ptr_factory_.GetWeakPtr(), state_->AsWeakPtr()));
+  } else {
+    state_->segmentation_result = true;
+  }
+
+  base::TimeDelta delay = compose::GetComposeConfig().proactive_nudge_delay;
   if (delay == base::Milliseconds(0)) {
+    state_->timer_complete = true;
+  } else {
+    state_->timer.Start(FROM_HERE,
+                        compose::GetComposeConfig().proactive_nudge_delay, this,
+                        &ProactiveNudgeTracker::ShowTimerElapsed);
+  }
+
+  if (state_->segmentation_result && state_->timer_complete) {
+    // If the timer is 0-duration and no segmentation result is required, then
+    // just transition to Shown state directly before returning true.
     state_->show_state = ShowState::kShown;
     return true;
   }
-
-  timer_.Start(FROM_HERE, compose::GetComposeConfig().proactive_nudge_delay,
-               this, &ProactiveNudgeTracker::ShowTimerElapsed);
   return false;
 }
+
 void ProactiveNudgeTracker::FocusChangedInPage() {
-  if (!state_) {
-    return;
-  }
-  state_ = std::nullopt;
-  timer_.Stop();
+  ResetState();
 }
 
 void ProactiveNudgeTracker::OnAfterFocusOnFormField(
@@ -66,34 +95,67 @@
   // If this focus is on the current field, we are (presumably) already focused
   // and this is a no-op. Also, if we are not currently in the WAITING state,
   // this is a no-op.
-  if (MatchesCurrentField(form, field) || state_ == std::nullopt) {
+  if (MatchesCurrentField(form, field) || state_ == nullptr) {
     return;
   }
 
   // Now we should transition to the UNINITIALIZED state.
-  state_ = std::nullopt;
-  timer_.Stop();
+  ResetState();
+}
+
+bool ProactiveNudgeTracker::SegmentationStateIsValid() {
+  return !compose::GetComposeConfig().proactive_nudge_segmentation ||
+         segmentation_service_ != nullptr;
+}
+
+void ProactiveNudgeTracker::ResetState() {
+  weak_ptr_factory_.InvalidateWeakPtrs();
+  state_.reset();
 }
 
 void ProactiveNudgeTracker::ShowTimerElapsed() {
+  DVLOG(2) << "ProactiveNudgeTracker: ShowTimerElapsed";
   // If we are not in the WAITING state, this timer is stale, we should ignore
   // it.
   if (!state_ || state_->show_state != ShowState::kWaiting) {
     return;
   }
 
-  // Transition to the SHOWN state.
-  delegate_->ShowProactiveNudge(state_->form, state_->field);
-  state_->show_state = ShowState::kCanBeShown;
+  state_->timer_complete = true;
+  MaybeShowProactiveNudge();
+}
+
+void ProactiveNudgeTracker::MaybeShowProactiveNudge() {
+  DVLOG(2) << "ProactiveNudgeTracker: MaybeShowProactiveNudge ";
+  if (state_ && state_->segmentation_result.value_or(false) &&
+      state_->timer_complete) {
+    // Transition to the SHOWN state.
+    delegate_->ShowProactiveNudge(state_->form, state_->field);
+    state_->show_state = ShowState::kCanBeShown;
+  }
+}
+
+void ProactiveNudgeTracker::GotClassificationResult(
+    base::WeakPtr<State> state,
+    const segmentation_platform::ClassificationResult& result) {
+  if (!state || state->show_state != ShowState::kWaiting) {
+    return;
+  }
+
+  if (result.status != segmentation_platform::PredictionStatus::kSucceeded) {
+    // Do not want to continue with proactive nudge if the segmentation platform
+    // had a failure.
+    ResetState();
+    return;
+  }
+  state->segmentation_result = result.ordered_labels[0] ==
+                               segmentation_platform::kComposePrmotionLabelShow;
+  MaybeShowProactiveNudge();
 }
 
 bool ProactiveNudgeTracker::MatchesCurrentField(autofill::FormGlobalId form,
                                                 autofill::FieldGlobalId field) {
-  if (state_ == std::nullopt) {
-    return false;
-  }
-
-  return state_->form == form && state_->field == field;
+  return state_ && state_->form == form && state_->field == field;
 }
 
 }  // namespace compose
diff --git a/chrome/browser/compose/proactive_nudge_tracker.h b/chrome/browser/compose/proactive_nudge_tracker.h
index a2f058c..41e2b10 100644
--- a/chrome/browser/compose/proactive_nudge_tracker.h
+++ b/chrome/browser/compose/proactive_nudge_tracker.h
@@ -9,9 +9,11 @@
 #include <string>
 
 #include "base/memory/raw_ref.h"
+#include "base/memory/weak_ptr.h"
 #include "components/autofill/content/browser/scoped_autofill_managers_observation.h"
 #include "components/autofill/core/browser/ui/suggestion.h"
 #include "components/autofill/core/common/unique_ids.h"
+#include "components/segmentation_platform/public/segmentation_platform_service.h"
 
 namespace compose {
 
@@ -47,14 +49,24 @@
 
   enum class ShowState { kWaiting, kCanBeShown, kShown };
 
-  struct State {
+  class State : public base::SupportsWeakPtr<State> {
+   public:
+    State();
+    virtual ~State();
+
     autofill::FormGlobalId form;
     autofill::FieldGlobalId field;
     std::u16string initial_text_value;
+    std::optional<bool> segmentation_result = std::nullopt;
+    base::OneShotTimer timer;
+    bool timer_complete = false;
+
     ShowState show_state = ShowState::kWaiting;
   };
 
-  explicit ProactiveNudgeTracker(Delegate* delegate);
+  ProactiveNudgeTracker(
+      segmentation_platform::SegmentationPlatformService* segmentation_service,
+      Delegate* delegate);
 
   ~ProactiveNudgeTracker() override;
 
@@ -82,16 +94,25 @@
                                autofill::FieldGlobalId field) override;
 
  private:
+  bool SegmentationStateIsValid();
+  void ResetState();
   void ShowTimerElapsed();
+  void GotClassificationResult(
+      base::WeakPtr<State> state,
+      const segmentation_platform::ClassificationResult& result);
+  void MaybeShowProactiveNudge();
   bool MatchesCurrentField(autofill::FormGlobalId form,
                            autofill::FieldGlobalId field);
 
-  std::optional<State> state_;
-  base::OneShotTimer timer_;
+  std::unique_ptr<State> state_;
+
+  raw_ptr<segmentation_platform::SegmentationPlatformService>
+      segmentation_service_;
   raw_ptr<Delegate> delegate_;
 
   autofill::ScopedAutofillManagersObservation autofill_managers_observation_{
       this};
+  base::WeakPtrFactory<ProactiveNudgeTracker> weak_ptr_factory_{this};
 };
 
 }  // namespace compose
diff --git a/chrome/browser/compose/proactive_nudge_tracker_unittest.cc b/chrome/browser/compose/proactive_nudge_tracker_unittest.cc
index 35cfb0c6..4166b353 100644
--- a/chrome/browser/compose/proactive_nudge_tracker_unittest.cc
+++ b/chrome/browser/compose/proactive_nudge_tracker_unittest.cc
@@ -5,13 +5,18 @@
 #include "chrome/browser/compose/proactive_nudge_tracker.h"
 
 #include "base/test/task_environment.h"
+#include "base/test/test_future.h"
 #include "components/autofill/core/common/autofill_test_utils.h"
 #include "components/autofill/core/common/form_field_data.h"
 #include "components/autofill/core/common/unique_ids.h"
 #include "components/compose/core/browser/config.h"
+#include "components/segmentation_platform/public/constants.h"
+#include "components/segmentation_platform/public/testing/mock_segmentation_platform_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using testing::_;
+
 namespace compose {
 
 class MockProactiveNudgeTrackerDelegate
@@ -23,7 +28,7 @@
               (override));
 };
 
-class ProactiveNudgeTrackerTest : public testing::Test {
+class ProactiveNudgeTrackerTest : public testing::TestWithParam<bool> {
  public:
   ProactiveNudgeTrackerTest() = default;
 
@@ -34,10 +39,29 @@
   ~ProactiveNudgeTrackerTest() override = default;
 
   void SetUp() override {
-    testing::Test::SetUp();
-    nudge_tracker_ = std::make_unique<ProactiveNudgeTracker>(&delegate_);
+    testing::TestWithParam<bool>::SetUp();
+    compose::GetMutableConfigForTesting().proactive_nudge_segmentation =
+        GetParam();
+    nudge_tracker_ = std::make_unique<ProactiveNudgeTracker>(
+        &segmentation_service_, &delegate_);
+
+    if (uses_segmentation()) {
+      SetSegmentationResult();
+    } else {
+      EXPECT_CALL(segmentation_service(), GetClassificationResult(_, _, _, _))
+          .Times(0);
+    }
   }
 
+  void TearDown() override {
+    testing::TestWithParam<bool>::TearDown();
+    compose::ResetConfigForTesting();
+  }
+
+  segmentation_platform::MockSegmentationPlatformService&
+  segmentation_service() {
+    return segmentation_service_;
+  }
   MockProactiveNudgeTrackerDelegate& delegate() { return delegate_; }
   base::test::SingleThreadTaskEnvironment& task_environment() {
     return task_environment_;
@@ -52,6 +76,32 @@
     return f;
   }
 
+  void SetSegmentationResult(std::string label = "Show") {
+    ON_CALL(segmentation_service(), GetClassificationResult(_, _, _, _))
+        .WillByDefault(testing::WithArg<3>(testing::Invoke(
+            [label](
+                segmentation_platform::ClassificationResultCallback callback) {
+              auto result = segmentation_platform::ClassificationResult(
+                  segmentation_platform::PredictionStatus::kSucceeded);
+              result.ordered_labels = {label};
+              std::move(callback).Run(result);
+            })));
+  }
+
+  // This helper function is a shortcut to adding a test future to listen for
+  // compose responses.
+  void BindFutureToSegmentationRequest(
+      base::test::TestFuture<
+          segmentation_platform::ClassificationResultCallback>& future) {
+    ON_CALL(segmentation_service(), GetClassificationResult(_, _, _, _))
+        .WillByDefault(testing::WithArg<3>(testing::Invoke(
+            [&](segmentation_platform::ClassificationResultCallback cb) {
+              future.SetValue(std::move(cb));
+            })));
+  }
+
+  bool uses_segmentation() { return GetParam(); }
+
  private:
   base::test::SingleThreadTaskEnvironment task_environment_{
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
@@ -59,10 +109,16 @@
 
   testing::NiceMock<MockProactiveNudgeTrackerDelegate> delegate_;
 
+  testing::NiceMock<segmentation_platform::MockSegmentationPlatformService>
+      segmentation_service_;
   std::unique_ptr<ProactiveNudgeTracker> nudge_tracker_;
 };
 
-TEST_F(ProactiveNudgeTrackerTest, TestWait) {
+TEST_P(ProactiveNudgeTrackerTest, TestWait) {
+  base::test::TestFuture<segmentation_platform::ClassificationResultCallback>
+      future;
+  BindFutureToSegmentationRequest(future);
+
   auto field = CreateTestFormFieldData();
   EXPECT_CALL(delegate(),
               ShowProactiveNudge(field.renderer_form_id(), field.global_id()))
@@ -73,10 +129,41 @@
   EXPECT_FALSE(nudge_tracker().ProactiveNudgeRequestedForFormField(field));
 
   task_environment().FastForwardBy(base::Seconds(4));
+  if (uses_segmentation()) {
+    EXPECT_FALSE(nudge_tracker().ProactiveNudgeRequestedForFormField(field));
+    auto result = segmentation_platform::ClassificationResult(
+        segmentation_platform::PredictionStatus::kSucceeded);
+    result.ordered_labels = {"Show"};
+    future.Take().Run(result);
+  }
   EXPECT_TRUE(nudge_tracker().ProactiveNudgeRequestedForFormField(field));
 }
 
-TEST_F(ProactiveNudgeTrackerTest, TestFocusChangePreventsNudge) {
+TEST_P(ProactiveNudgeTrackerTest, TestWaitSegmentationFirst) {
+  base::test::TestFuture<segmentation_platform::ClassificationResultCallback>
+      future;
+  BindFutureToSegmentationRequest(future);
+
+  auto field = CreateTestFormFieldData();
+  EXPECT_CALL(delegate(),
+              ShowProactiveNudge(field.renderer_form_id(), field.global_id()))
+      .Times(1);
+
+  EXPECT_FALSE(nudge_tracker().ProactiveNudgeRequestedForFormField(field));
+  if (uses_segmentation()) {
+    auto result = segmentation_platform::ClassificationResult(
+        segmentation_platform::PredictionStatus::kSucceeded);
+    result.ordered_labels = {"Show"};
+    future.Take().Run(result);
+  }
+  // Should not nudge if nudge is requested too soon.
+  EXPECT_FALSE(nudge_tracker().ProactiveNudgeRequestedForFormField(field));
+
+  task_environment().FastForwardBy(base::Seconds(4));
+  EXPECT_TRUE(nudge_tracker().ProactiveNudgeRequestedForFormField(field));
+}
+
+TEST_P(ProactiveNudgeTrackerTest, TestFocusChangePreventsNudge) {
   auto field = CreateTestFormFieldData();
   EXPECT_CALL(delegate(),
               ShowProactiveNudge(field.renderer_form_id(), field.global_id()))
@@ -89,7 +176,7 @@
   EXPECT_FALSE(nudge_tracker().ProactiveNudgeRequestedForFormField(field));
 }
 
-TEST_F(ProactiveNudgeTrackerTest, TestTrackingDifferentFormField) {
+TEST_P(ProactiveNudgeTrackerTest, TestTrackingDifferentFormField) {
   auto field = CreateTestFormFieldData();
   EXPECT_CALL(delegate(),
               ShowProactiveNudge(field.renderer_form_id(), field.global_id()))
@@ -102,12 +189,11 @@
 
   EXPECT_FALSE(nudge_tracker().ProactiveNudgeRequestedForFormField(field));
   EXPECT_FALSE(nudge_tracker().ProactiveNudgeRequestedForFormField(field2));
-
   task_environment().FastForwardBy(base::Seconds(4));
   EXPECT_FALSE(nudge_tracker().ProactiveNudgeRequestedForFormField(field));
 }
 
-TEST_F(ProactiveNudgeTrackerTest, TestFocusChangeInUninitializedState) {
+TEST_P(ProactiveNudgeTrackerTest, TestFocusChangeInUninitializedState) {
   auto field = CreateTestFormFieldData();
   EXPECT_CALL(delegate(),
               ShowProactiveNudge(field.renderer_form_id(), field.global_id()))
@@ -117,19 +203,62 @@
   task_environment().FastForwardBy(base::Seconds(4));
 }
 
-TEST_F(ProactiveNudgeTrackerTest, TestNoNudgeDelay) {
+TEST_P(ProactiveNudgeTrackerTest, TestNoNudgeDelay) {
   compose::Config& config = compose::GetMutableConfigForTesting();
   config.proactive_nudge_delay = base::Milliseconds(0);
 
   auto field = CreateTestFormFieldData();
-  EXPECT_CALL(delegate(),
-              ShowProactiveNudge(field.renderer_form_id(), field.global_id()))
-      .Times(0);
-
-  EXPECT_TRUE(nudge_tracker().ProactiveNudgeRequestedForFormField(field));
-
-  // Wait just in case the timer could be pending.
-  task_environment().FastForwardBy(base::Seconds(4));
+  if (uses_segmentation()) {
+    base::test::TestFuture<segmentation_platform::ClassificationResultCallback>
+        future;
+    BindFutureToSegmentationRequest(future);
+    EXPECT_CALL(delegate(),
+                ShowProactiveNudge(field.renderer_form_id(), field.global_id()))
+        .Times(1);
+    EXPECT_FALSE(nudge_tracker().ProactiveNudgeRequestedForFormField(field));
+    auto result = segmentation_platform::ClassificationResult(
+        segmentation_platform::PredictionStatus::kSucceeded);
+    result.ordered_labels = {"Show"};
+    future.Take().Run(result);
+  } else {
+    EXPECT_CALL(delegate(),
+                ShowProactiveNudge(field.renderer_form_id(), field.global_id()))
+        .Times(0);
+    EXPECT_TRUE(nudge_tracker().ProactiveNudgeRequestedForFormField(field));
+    // Wait just in case the timer could be pending.
+    task_environment().FastForwardBy(base::Seconds(4));
+  }
 }
 
+TEST_P(ProactiveNudgeTrackerTest, SegmentationDoesNotSucceed) {
+  base::test::TestFuture<segmentation_platform::ClassificationResultCallback>
+      future;
+  auto field = CreateTestFormFieldData();
+  if (uses_segmentation()) {
+    BindFutureToSegmentationRequest(future);
+  }
+
+  EXPECT_CALL(delegate(),
+              ShowProactiveNudge(field.renderer_form_id(), field.global_id()))
+      .Times(uses_segmentation() ? 0 : 1);
+
+  EXPECT_FALSE(nudge_tracker().ProactiveNudgeRequestedForFormField(field));
+  task_environment().FastForwardBy(base::Seconds(4));
+
+  if (uses_segmentation()) {
+    EXPECT_FALSE(nudge_tracker().ProactiveNudgeRequestedForFormField(field));
+    auto result = segmentation_platform::ClassificationResult(
+        segmentation_platform::PredictionStatus::kSucceeded);
+    result.ordered_labels = {
+        segmentation_platform::kComposePrmotionLabelDontShow};
+    future.Take().Run(result);
+  }
+
+  EXPECT_NE(uses_segmentation(),
+            nudge_tracker().ProactiveNudgeRequestedForFormField(field));
+}
+
+INSTANTIATE_TEST_SUITE_P(ProactiveNudgeTrackerTest,
+                         ProactiveNudgeTrackerTest,
+                         ::testing::Bool());
 }  // namespace compose
diff --git a/chrome/browser/data_sharing/BUILD.gn b/chrome/browser/data_sharing/BUILD.gn
index d09fcab..5145412 100644
--- a/chrome/browser/data_sharing/BUILD.gn
+++ b/chrome/browser/data_sharing/BUILD.gn
@@ -11,7 +11,10 @@
 if (is_android) {
   android_library("factory_java") {
     srcjar_deps = [ ":jni_headers" ]
-    sources = [ "android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingServiceFactory.java" ]
+    sources = [
+      "android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingServiceFactory.java",
+      "android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingUIDelegateAndroid.java",
+    ]
 
     deps = [
       ":ui_delegate_java",
@@ -21,6 +24,7 @@
       "//components/data_sharing/public:public_java",
       "//third_party/androidx:androidx_annotation_annotation_java",
       "//third_party/jni_zero:jni_zero_java",
+      "//url:url_java",
     ]
   }
 
@@ -79,6 +83,8 @@
       "//chrome/browser/tab:java",
       "//components/data_sharing/public:public_java",
       "//third_party/androidx:androidx_annotation_annotation_java",
+      "//third_party/jni_zero:jni_zero_java",
+      "//url:url_java",
     ]
     if (defined(enable_data_sharing_internal) && enable_data_sharing_internal) {
       jar_excluded_patterns = [ "*/DataSharingUIDelegateImpl.class" ]
@@ -126,6 +132,9 @@
   }
 
   generate_jni("jni_headers") {
-    sources = [ "android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingServiceFactory.java" ]
+    sources = [
+      "android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingServiceFactory.java",
+      "android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingUIDelegateAndroid.java",
+    ]
   }
 }
diff --git a/chrome/browser/data_sharing/DEPS b/chrome/browser/data_sharing/DEPS
index a384902..2d2a5921 100644
--- a/chrome/browser/data_sharing/DEPS
+++ b/chrome/browser/data_sharing/DEPS
@@ -2,5 +2,5 @@
   # Minimize dependencies on internal code, but allow service construction.
   "+components/data_sharing/internal/data_sharing_service_impl.h",
   "+components/data_sharing/internal/empty_data_sharing_service.h",
-  "+components/data_sharing/internal/mock_data_sharing_service.h",
+  "+components/data_sharing/test_support/mock_data_sharing_service.h",
 ]
diff --git a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingServiceFactory.java b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingServiceFactory.java
index 4cc2bac..6c6ba214 100644
--- a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingServiceFactory.java
+++ b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingServiceFactory.java
@@ -50,7 +50,7 @@
 
     /**
      * A factory method to create or retrieve a {@link DataSharingUIDelegate} object for a given
-     * profile.
+     * profile. TODO(b/339685767): Deprecate this function.
      *
      * @return The {@link DataSharingUIDelegate} for the given profile.
      */
diff --git a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingUIDelegateAndroid.java b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingUIDelegateAndroid.java
new file mode 100644
index 0000000..aa5564e
--- /dev/null
+++ b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingUIDelegateAndroid.java
@@ -0,0 +1,81 @@
+// 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.data_sharing;
+
+import android.app.Activity;
+import android.content.Context;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+
+import org.jni_zero.CalledByNative;
+
+import org.chromium.base.Callback;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.components.data_sharing.DataSharingUIDelegate;
+import org.chromium.components.data_sharing.configs.AvatarConfig;
+import org.chromium.components.data_sharing.configs.GroupMemberConfig;
+import org.chromium.components.data_sharing.configs.MemberPickerConfig;
+import org.chromium.url.GURL;
+
+import java.util.List;
+
+class DataSharingUIDelegateAndroid implements DataSharingUIDelegate {
+
+    private final DataSharingUIDelegate mDelegate;
+
+    DataSharingUIDelegateAndroid(Profile profile) {
+        mDelegate = new DataSharingUIDelegateImpl(profile);
+    }
+
+    @CalledByNative
+    private static DataSharingUIDelegateAndroid create(Profile profile) {
+        return new DataSharingUIDelegateAndroid(profile);
+    }
+
+    @Override
+    public void showMemberPicker(
+            @NonNull Activity activity,
+            @NonNull ViewGroup view,
+            MemberPickerListener memberResult,
+            MemberPickerConfig config) {
+        mDelegate.showMemberPicker(activity, view, memberResult, config);
+    }
+
+    @Override
+    public void showFullPicker(
+            @NonNull Activity activity,
+            @NonNull ViewGroup view,
+            MemberPickerListener memberResult,
+            MemberPickerConfig config) {
+        mDelegate.showFullPicker(activity, view, memberResult, config);
+    }
+
+    @Override
+    public void showAvatars(
+            @NonNull Context context,
+            List<ViewGroup> views,
+            List<String> emails,
+            Callback<Boolean> success,
+            AvatarConfig config) {
+        mDelegate.showAvatars(context, views, emails, success, config);
+    }
+
+    @Override
+    public void createGroupMemberListView(
+            @NonNull Activity activity,
+            @NonNull ViewGroup view,
+            String groupId,
+            String tokenSecret,
+            GroupMemberConfig config) {
+        mDelegate.createGroupMemberListView(activity, view, groupId, tokenSecret, config);
+    }
+
+    @Override
+    @CalledByNative
+    public void handleShareURLIntercepted(GURL url) {
+        // TODO(haileywang): Implement redirecting to the recipient/inviter flow.
+    }
+}
diff --git a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingUIDelegateImpl.java b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingUIDelegateImpl.java
index 28de9a3..9a7bd39 100644
--- a/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingUIDelegateImpl.java
+++ b/chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing/DataSharingUIDelegateImpl.java
@@ -17,6 +17,7 @@
 import org.chromium.components.data_sharing.configs.AvatarConfig;
 import org.chromium.components.data_sharing.configs.GroupMemberConfig;
 import org.chromium.components.data_sharing.configs.MemberPickerConfig;
+import org.chromium.url.GURL;
 
 import java.util.List;
 
@@ -58,4 +59,7 @@
             String groupId,
             String tokenSecret,
             GroupMemberConfig config) {}
+
+    @Override
+    public void handleShareURLIntercepted(GURL url) {}
 }
diff --git a/chrome/browser/data_sharing/data_sharing_navigation_throttle_unittest.cc b/chrome/browser/data_sharing/data_sharing_navigation_throttle_unittest.cc
index 80cb129f..a06a9be 100644
--- a/chrome/browser/data_sharing/data_sharing_navigation_throttle_unittest.cc
+++ b/chrome/browser/data_sharing/data_sharing_navigation_throttle_unittest.cc
@@ -7,8 +7,8 @@
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/data_sharing/data_sharing_service_factory.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "components/data_sharing/internal/mock_data_sharing_service.h"
 #include "components/data_sharing/public/features.h"
+#include "components/data_sharing/test_support/mock_data_sharing_service.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/mock_navigation_handle.h"
 
diff --git a/chrome/browser/data_sharing/data_sharing_service_factory.cc b/chrome/browser/data_sharing/data_sharing_service_factory.cc
index b5bc8b0..a6339f1 100644
--- a/chrome/browser/data_sharing/data_sharing_service_factory.cc
+++ b/chrome/browser/data_sharing/data_sharing_service_factory.cc
@@ -14,11 +14,16 @@
 #include "components/data_sharing/internal/data_sharing_service_impl.h"
 #include "components/data_sharing/internal/empty_data_sharing_service.h"
 #include "components/data_sharing/public/data_sharing_service.h"
+#include "components/data_sharing/public/data_sharing_ui_delegate.h"
 #include "components/data_sharing/public/features.h"
 #include "components/sync/model/model_type_store_service.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/storage_partition.h"
 
+#if BUILDFLAG(IS_ANDROID)
+#include "chrome/browser/data_sharing/data_sharing_ui_delegate_android.h"
+#endif  // BUILDFLAG(IS_ANDROID)
+
 namespace data_sharing {
 // static
 DataSharingServiceFactory* DataSharingServiceFactory::GetInstance() {
@@ -52,13 +57,18 @@
   }
 
   Profile* profile = Profile::FromBrowserContext(context);
+  std::unique_ptr<DataSharingUIDelegate> ui_delegate;
+#if BUILDFLAG(IS_ANDROID)
+  ui_delegate = std::make_unique<DataSharingUIDelegateAndroid>(profile);
+#endif  // BUILDFLAG(IS_ANDROID)
+
   return new DataSharingServiceImpl(
       profile->GetDefaultStoragePartition()
           ->GetURLLoaderFactoryForBrowserProcess(),
       IdentityManagerFactory::GetForProfile(profile),
       ModelTypeStoreServiceFactory::GetForProfile(profile)->GetStoreFactory(),
       chrome::GetChannel(),
-      /*sdk_delegate=*/nullptr);
+      /*sdk_delegate=*/nullptr, std::move(ui_delegate));
 }
 
 }  // namespace data_sharing
diff --git a/chrome/browser/data_sharing/data_sharing_ui_delegate_android.cc b/chrome/browser/data_sharing/data_sharing_ui_delegate_android.cc
new file mode 100644
index 0000000..6e0989e7
--- /dev/null
+++ b/chrome/browser/data_sharing/data_sharing_ui_delegate_android.cc
@@ -0,0 +1,30 @@
+// 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 "chrome/browser/data_sharing/data_sharing_ui_delegate_android.h"
+
+#include "base/android/jni_string.h"
+#include "chrome/browser/data_sharing/jni_headers/DataSharingUIDelegateAndroid_jni.h"
+#include "chrome/browser/profiles/profile_android.h"
+#include "url/android/gurl_android.h"
+#include "url/gurl.h"
+
+namespace data_sharing {
+
+DataSharingUIDelegateAndroid::DataSharingUIDelegateAndroid(Profile* profile) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  auto j_profile = ProfileAndroid::FromProfile(profile)->GetJavaObject();
+  java_obj_.Reset(
+      env, Java_DataSharingUIDelegateAndroid_create(env, j_profile).obj());
+}
+
+DataSharingUIDelegateAndroid::~DataSharingUIDelegateAndroid() = default;
+
+void DataSharingUIDelegateAndroid::HandleShareURLIntercepted(const GURL& url) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_DataSharingUIDelegateAndroid_handleShareURLIntercepted(
+      env, java_obj_, url::GURLAndroid::FromNativeGURL(env, url));
+}
+
+}  // namespace data_sharing
diff --git a/chrome/browser/data_sharing/data_sharing_ui_delegate_android.h b/chrome/browser/data_sharing/data_sharing_ui_delegate_android.h
new file mode 100644
index 0000000..d12bbfc
--- /dev/null
+++ b/chrome/browser/data_sharing/data_sharing_ui_delegate_android.h
@@ -0,0 +1,33 @@
+// 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 CHROME_BROWSER_DATA_SHARING_DATA_SHARING_UI_DELEGATE_ANDROID_H_
+#define CHROME_BROWSER_DATA_SHARING_DATA_SHARING_UI_DELEGATE_ANDROID_H_
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/supports_user_data.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/data_sharing/public/data_sharing_ui_delegate.h"
+
+using base::android::ScopedJavaGlobalRef;
+
+namespace data_sharing {
+
+// Android side implementation of a DataSharingUIDelegate.
+class DataSharingUIDelegateAndroid : public DataSharingUIDelegate {
+ public:
+  explicit DataSharingUIDelegateAndroid(Profile* profile);
+  ~DataSharingUIDelegateAndroid() override;
+
+  // DataSharingUIDelegate implementation.
+  void HandleShareURLIntercepted(const GURL& url) override;
+
+ private:
+  ScopedJavaGlobalRef<jobject> java_obj_;
+};
+
+}  // namespace data_sharing
+
+#endif  // CHROME_BROWSER_DATA_SHARING_DATA_SHARING_UI_DELEGATE_ANDROID_H_
diff --git a/chrome/browser/facilitated_payments/ui/android/BUILD.gn b/chrome/browser/facilitated_payments/ui/android/BUILD.gn
index 606b05d..45b9393 100644
--- a/chrome/browser/facilitated_payments/ui/android/BUILD.gn
+++ b/chrome/browser/facilitated_payments/ui/android/BUILD.gn
@@ -43,5 +43,8 @@
 android_library("public_java") {
   sources = [ "java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsComponent.java" ]
 
-  deps = [ "//components/browser_ui/bottomsheet/android:java" ]
+  deps = [
+    "//components/autofill/android:payments_autofill_java",
+    "//components/browser_ui/bottomsheet/android:java",
+  ]
 }
diff --git a/chrome/browser/facilitated_payments/ui/android/internal/BUILD.gn b/chrome/browser/facilitated_payments/ui/android/internal/BUILD.gn
index 963a8803..4846410b 100644
--- a/chrome/browser/facilitated_payments/ui/android/internal/BUILD.gn
+++ b/chrome/browser/facilitated_payments/ui/android/internal/BUILD.gn
@@ -13,6 +13,7 @@
   resources_package = "org.chromium.chrome.browser.facilitated_payments"
 
   sources = [
+    "java/src/org/chromium/chrome/browser/facilitated_payments/BankAccountViewBinder.java",
     "java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsCoordinator.java",
     "java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsMediator.java",
     "java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsProperties.java",
@@ -29,6 +30,7 @@
     "//chrome/browser/facilitated_payments/ui/android:public_java",
     "//chrome/browser/touch_to_fill/common/android:java",
     "//chrome/browser/touch_to_fill/common/android:java_resources",
+    "//components/autofill/android:payments_autofill_java",
     "//components/browser_ui/bottomsheet/android:java",
     "//content/public/android:content_full_java",
     "//third_party/androidx:androidx_annotation_annotation_java",
@@ -42,6 +44,7 @@
 
 android_resources("java_resources") {
   sources = [
+    "java/res/layout/bank_account_item.xml",
     "java/res/layout/facilitated_payments_payment_methods_sheet_header_item.xml",
     "java/res/values/dimens.xml",
   ]
@@ -51,26 +54,48 @@
   testonly = true
   resources_package = "org.chromium.chrome.browser.facilitated_payments"
 
-  sources = [
-    "java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsViewBridgeTest.java",
-    "java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsViewTest.java",
-  ]
+  sources = [ "java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsViewBridgeTest.java" ]
 
   deps = [
     ":java",
     "//base:base_junit_test_support",
     "//chrome/android:chrome_java",
-    "//chrome/browser/facilitated_payments/ui/android:public_java",
     "//components/browser_ui/bottomsheet/android:factory_java",
     "//components/browser_ui/bottomsheet/android:java",
     "//components/browser_ui/bottomsheet/android:manager_java",
-    "//content/public/android:content_full_java",
+    "//content/public/android:content_java",
     "//third_party/androidx:androidx_test_core_java",
     "//third_party/androidx:androidx_test_runner_java",
     "//third_party/hamcrest:hamcrest_core_java",
     "//third_party/hamcrest:hamcrest_library_java",
     "//third_party/junit",
     "//third_party/mockito:mockito_java",
-    "//ui/android:ui_no_recycler_view_java",
+    "//ui/android:ui_java",
+  ]
+}
+
+android_library("javatests") {
+  testonly = true
+  resources_package = "org.chromium.chrome.browser.facilitated_payments"
+  sources = [ "java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsViewTest.java" ]
+
+  deps = [
+    ":java",
+    ":java_resources",
+    "//base:base_java_test_support",
+    "//chrome/android:chrome_public_base_module_java_for_test",
+    "//chrome/browser/flags:java",
+    "//chrome/browser/touch_to_fill/common/android:java_resources",
+    "//chrome/test/android:chrome_java_integration_test_support",
+    "//components/browser_ui/bottomsheet/android:java",
+    "//components/browser_ui/bottomsheet/android:manager_java",
+    "//components/browser_ui/bottomsheet/android/test:java",
+    "//third_party/android_deps:espresso_java",
+    "//third_party/androidx:androidx_recyclerview_recyclerview_java",
+    "//third_party/androidx:androidx_test_runner_java",
+    "//third_party/hamcrest:hamcrest_java",
+    "//third_party/junit",
+    "//third_party/mockito:mockito_java",
+    "//ui/android:ui_java",
   ]
 }
diff --git a/chrome/browser/facilitated_payments/ui/android/internal/java/res/layout/bank_account_item.xml b/chrome/browser/facilitated_payments/ui/android/internal/java/res/layout/bank_account_item.xml
new file mode 100644
index 0000000..2f6f8da
--- /dev/null
+++ b/chrome/browser/facilitated_payments/ui/android/internal/java/res/layout/bank_account_item.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+<!-- TODO(b/340328974) Only the first and end suggestions should have curved background. -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:background="@drawable/touch_to_fill_credential_background_modern_rounded_all"
+    android:descendantFocusability="blocksDescendants"
+    android:layout_height="wrap_content"
+    android:layout_width="match_parent"
+    android:layout_marginBottom="2dp"
+    android:layout_marginHorizontal="8dp"
+    android:orientation="vertical"
+    android:padding="16dp">
+
+    <TextView
+        android:id="@+id/bank_name"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:maxLines="1"
+        android:textAppearance="@style/TextAppearance.TextLarge.Primary"/>
+
+    <TextView
+        android:id="@+id/bank_account_summary"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:maxLines="1"
+        android:textAppearance="@style/TextAppearance.TextMedium.Secondary"/>
+</LinearLayout>
diff --git a/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/BankAccountViewBinder.java b/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/BankAccountViewBinder.java
new file mode 100644
index 0000000..4b8e6f4
--- /dev/null
+++ b/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/BankAccountViewBinder.java
@@ -0,0 +1,42 @@
+// 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.facilitated_payments;
+
+import static org.chromium.chrome.browser.facilitated_payments.FacilitatedPaymentsPaymentMethodsProperties.BankAccountProperties.BANK_ACCOUNT_SUMMARY;
+import static org.chromium.chrome.browser.facilitated_payments.FacilitatedPaymentsPaymentMethodsProperties.BankAccountProperties.BANK_NAME;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.chromium.chrome.browser.facilitated_payments.FacilitatedPaymentsPaymentMethodsProperties.BankAccountProperties;
+import org.chromium.ui.modelutil.PropertyKey;
+import org.chromium.ui.modelutil.PropertyModel;
+
+/**
+ * Provides functions that map changes of {@link BankAccountProperties} in a {@link PropertyModel}
+ * to the suitable method in {@link FacilitatedPaymentsPaymentMethodsView}.
+ */
+class BankAccountViewBinder {
+    static View createBankAccountItemView(ViewGroup parent) {
+        return LayoutInflater.from(parent.getContext())
+                .inflate(R.layout.bank_account_item, parent, false);
+    }
+
+    static void bindBankAccountItemView(PropertyModel model, View view, PropertyKey propertyKey) {
+        if (propertyKey == BANK_NAME) {
+            TextView bankName = view.findViewById(R.id.bank_name);
+            bankName.setText(model.get(BANK_NAME));
+        } else if (propertyKey == BANK_ACCOUNT_SUMMARY) {
+            TextView bankAccountSummary = view.findViewById(R.id.bank_account_summary);
+            bankAccountSummary.setText(model.get(BANK_ACCOUNT_SUMMARY));
+        } else {
+            assert false : "Unhandled update to property:" + propertyKey;
+        }
+    }
+
+    private BankAccountViewBinder() {}
+}
diff --git a/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsCoordinator.java b/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsCoordinator.java
index dc866d45..f9b7532 100644
--- a/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsCoordinator.java
+++ b/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsCoordinator.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.facilitated_payments;
 
+import static org.chromium.chrome.browser.facilitated_payments.FacilitatedPaymentsPaymentMethodsProperties.ItemType.BANK_ACCOUNT;
 import static org.chromium.chrome.browser.facilitated_payments.FacilitatedPaymentsPaymentMethodsProperties.ItemType.HEADER;
 import static org.chromium.chrome.browser.facilitated_payments.FacilitatedPaymentsPaymentMethodsProperties.SHEET_ITEMS;
 import static org.chromium.chrome.browser.facilitated_payments.FacilitatedPaymentsPaymentMethodsProperties.VISIBLE;
@@ -12,6 +13,7 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import org.chromium.components.autofill.payments.BankAccount;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -31,15 +33,15 @@
     @Override
     public void initialize(Context context, BottomSheetController bottomSheetController) {
         mFacilitatedPaymentsPaymentMethodsModel = createModel();
-        mMediator.initialize(mFacilitatedPaymentsPaymentMethodsModel);
+        mMediator.initialize(context, mFacilitatedPaymentsPaymentMethodsModel);
         setUpModelChangeProcessors(
                 mFacilitatedPaymentsPaymentMethodsModel,
                 new FacilitatedPaymentsPaymentMethodsView(context, bottomSheetController));
     }
 
     @Override
-    public void showSheet() {
-        mMediator.showSheet();
+    public void showSheet(BankAccount[] bankAccounts) {
+        mMediator.showSheet(bankAccounts);
     }
 
     /**
@@ -72,6 +74,10 @@
                 HEADER,
                 FacilitatedPaymentsPaymentMethodsViewBinder::createHeaderItemView,
                 FacilitatedPaymentsPaymentMethodsViewBinder::bindHeaderView);
+        adapter.registerType(
+                BANK_ACCOUNT,
+                BankAccountViewBinder::createBankAccountItemView,
+                BankAccountViewBinder::bindBankAccountItemView);
         view.getSheetItemListView().setAdapter(adapter);
     }
 
diff --git a/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsMediator.java b/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsMediator.java
index 0af1080..b40423a 100644
--- a/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsMediator.java
+++ b/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsMediator.java
@@ -4,13 +4,23 @@
 
 package org.chromium.chrome.browser.facilitated_payments;
 
+import static org.chromium.chrome.browser.facilitated_payments.FacilitatedPaymentsPaymentMethodsProperties.BankAccountProperties.BANK_ACCOUNT_SUMMARY;
+import static org.chromium.chrome.browser.facilitated_payments.FacilitatedPaymentsPaymentMethodsProperties.BankAccountProperties.BANK_NAME;
 import static org.chromium.chrome.browser.facilitated_payments.FacilitatedPaymentsPaymentMethodsProperties.HeaderProperties.DESCRIPTION_ID;
 import static org.chromium.chrome.browser.facilitated_payments.FacilitatedPaymentsPaymentMethodsProperties.HeaderProperties.IMAGE_DRAWABLE_ID;
 import static org.chromium.chrome.browser.facilitated_payments.FacilitatedPaymentsPaymentMethodsProperties.HeaderProperties.TITLE_ID;
+import static org.chromium.chrome.browser.facilitated_payments.FacilitatedPaymentsPaymentMethodsProperties.ItemType.BANK_ACCOUNT;
 import static org.chromium.chrome.browser.facilitated_payments.FacilitatedPaymentsPaymentMethodsProperties.SHEET_ITEMS;
 import static org.chromium.chrome.browser.facilitated_payments.FacilitatedPaymentsPaymentMethodsProperties.VISIBLE;
 
+import android.content.Context;
+
+import androidx.annotation.VisibleForTesting;
+
+import org.chromium.chrome.browser.facilitated_payments.FacilitatedPaymentsPaymentMethodsProperties.BankAccountProperties;
 import org.chromium.chrome.browser.facilitated_payments.FacilitatedPaymentsPaymentMethodsProperties.HeaderProperties;
+import org.chromium.components.autofill.payments.AccountType;
+import org.chromium.components.autofill.payments.BankAccount;
 import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
 import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
 import org.chromium.ui.modelutil.PropertyModel;
@@ -20,16 +30,27 @@
  * reacts to events like clicks.
  */
 class FacilitatedPaymentsPaymentMethodsMediator {
+    private Context mContext;
     private PropertyModel mModel;
 
-    void initialize(PropertyModel model) {
+    void initialize(Context context, PropertyModel model) {
+        mContext = context;
         mModel = model;
     }
 
-    void showSheet() {
+    void showSheet(BankAccount[] bankAccounts) {
+        if (bankAccounts == null || bankAccounts.length == 0) {
+            return;
+        }
+
         ModelList sheetItems = mModel.get(SHEET_ITEMS);
         sheetItems.clear();
 
+        for (BankAccount bankAccount : bankAccounts) {
+            final PropertyModel model = createBankAccountModel(mContext, bankAccount);
+            sheetItems.add(new ListItem(BANK_ACCOUNT, model));
+        }
+
         sheetItems.add(0, buildHeader());
         mModel.set(VISIBLE, true);
     }
@@ -43,4 +64,42 @@
                         .with(TITLE_ID, R.string.pix_payment_methods_bottom_sheet_title)
                         .build());
     }
+
+    @VisibleForTesting
+    static PropertyModel createBankAccountModel(Context context, BankAccount bankAccount) {
+        PropertyModel.Builder bankAccountModelBuilder =
+                new PropertyModel.Builder(BankAccountProperties.NON_TRANSFORMING_KEYS)
+                        .with(BANK_NAME, bankAccount.getBankName())
+                        .with(
+                                BANK_ACCOUNT_SUMMARY,
+                                getBankAccountSummaryString(context, bankAccount));
+        return bankAccountModelBuilder.build();
+    }
+
+    private static String getBankAccountSummaryString(Context context, BankAccount bankAccount) {
+        return context.getResources()
+                .getString(
+                        R.string.settings_pix_bank_account_identifer,
+                        getBankAccountTypeString(context, bankAccount.getAccountType()),
+                        bankAccount.getAccountNumberSuffix());
+    }
+
+    private static String getBankAccountTypeString(
+            Context context, @AccountType int bankAccountType) {
+        switch (bankAccountType) {
+            case AccountType.CHECKING:
+                return context.getResources().getString(R.string.bank_account_type_checking);
+            case AccountType.SAVINGS:
+                return context.getResources().getString(R.string.bank_account_type_savings);
+            case AccountType.CURRENT:
+                return context.getResources().getString(R.string.bank_account_type_current);
+            case AccountType.SALARY:
+                return context.getResources().getString(R.string.bank_account_type_salary);
+            case AccountType.TRANSACTING_ACCOUNT:
+                return context.getResources().getString(R.string.bank_account_type_transacting);
+            case AccountType.UNKNOWN:
+            default:
+                return "";
+        }
+    }
 }
diff --git a/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsProperties.java b/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsProperties.java
index b06bd42..e6d676b 100644
--- a/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsProperties.java
+++ b/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsProperties.java
@@ -25,18 +25,23 @@
         // The header at the top of the FacilitatedPayments bottom sheet.
         int HEADER = 0;
 
-        // A section containing the payment instrument data.
-        int PAYMENT_INSTRUMENT = 1;
+        // A section containing the bank account data.
+        int BANK_ACCOUNT = 1;
 
         // A footer section containing additional actions.
         int FOOTER = 2;
     }
 
     /** Properties for a payment instrument entry in the facilitated payments bottom sheet. */
-    static class PaymentInstrumentProperties {
-        static final PropertyKey[] NON_TRANSFORMING_KEYS = {};
+    static class BankAccountProperties {
+        static final ReadableObjectPropertyKey<String> BANK_NAME =
+                new ReadableObjectPropertyKey("bank_name");
+        static final ReadableObjectPropertyKey<String> BANK_ACCOUNT_SUMMARY =
+                new ReadableObjectPropertyKey("bank_account_summary");
 
-        private PaymentInstrumentProperties() {}
+        static final PropertyKey[] NON_TRANSFORMING_KEYS = {BANK_NAME, BANK_ACCOUNT_SUMMARY};
+
+        private BankAccountProperties() {}
     }
 
     /**
diff --git a/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsView.java b/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsView.java
index 475ee3a..3629ccc 100644
--- a/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsView.java
+++ b/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsView.java
@@ -80,7 +80,7 @@
 
     @Override
     protected Set<Integer> listedItemTypes() {
-        return Set.of(FacilitatedPaymentsPaymentMethodsProperties.ItemType.PAYMENT_INSTRUMENT);
+        return Set.of(FacilitatedPaymentsPaymentMethodsProperties.ItemType.BANK_ACCOUNT);
     }
 
     @Override
diff --git a/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsViewBridge.java b/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsViewBridge.java
index c854b1c3..479601f1 100644
--- a/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsViewBridge.java
+++ b/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsViewBridge.java
@@ -12,6 +12,10 @@
 import org.jni_zero.CalledByNative;
 import org.jni_zero.JNINamespace;
 
+import org.chromium.components.autofill.payments.AccountType;
+import org.chromium.components.autofill.payments.BankAccount;
+import org.chromium.components.autofill.payments.PaymentInstrument;
+import org.chromium.components.autofill.payments.PaymentRail;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider;
 import org.chromium.ui.base.WindowAndroid;
@@ -58,6 +62,34 @@
      */
     @CalledByNative
     public void requestShowContent() {
-        mComponent.showSheet();
+        // TODO(b/337180783): Pass bankAccounts from facilitated_payments_bottom_sheet_bridge.cc to
+        // Java file.
+        BankAccount bankAccountForTest1 =
+                new BankAccount.Builder()
+                        .setPaymentInstrument(
+                                new PaymentInstrument.Builder()
+                                        .setInstrumentId(100)
+                                        .setNickname("nickname1")
+                                        .setSupportedPaymentRails(new int[] {PaymentRail.PIX})
+                                        .build())
+                        .setBankName("bankName1")
+                        .setAccountNumberSuffix("1111")
+                        .setAccountType(AccountType.CHECKING)
+                        .build();
+        BankAccount bankAccountForTest2 =
+                new BankAccount.Builder()
+                        .setPaymentInstrument(
+                                new PaymentInstrument.Builder()
+                                        .setInstrumentId(200)
+                                        .setNickname("nickname2")
+                                        .setSupportedPaymentRails(new int[] {PaymentRail.PIX})
+                                        .build())
+                        .setBankName("bankName2")
+                        .setAccountNumberSuffix("2222")
+                        .setAccountType(AccountType.CHECKING)
+                        .build();
+
+        BankAccount[] bankAccounts = new BankAccount[] {bankAccountForTest1, bankAccountForTest2};
+        mComponent.showSheet(bankAccounts);
     }
 }
diff --git a/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsViewTest.java b/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsViewTest.java
index ef73faa..08cf2b4 100644
--- a/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsViewTest.java
+++ b/chrome/browser/facilitated_payments/ui/android/internal/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsViewTest.java
@@ -4,90 +4,172 @@
 
 package org.chromium.chrome.browser.facilitated_payments;
 
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.nullValue;
-import static org.junit.Assert.assertFalse;
+import static androidx.test.espresso.matcher.ViewMatchers.assertThat;
 
-import android.content.Context;
-import android.view.View;
+import static org.hamcrest.Matchers.is;
 
-import androidx.test.filters.SmallTest;
+import static org.chromium.chrome.browser.facilitated_payments.FacilitatedPaymentsPaymentMethodsProperties.ItemType.BANK_ACCOUNT;
+import static org.chromium.chrome.browser.facilitated_payments.FacilitatedPaymentsPaymentMethodsProperties.SHEET_ITEMS;
+import static org.chromium.chrome.browser.facilitated_payments.FacilitatedPaymentsPaymentMethodsProperties.VISIBLE;
+import static org.chromium.content_public.browser.test.util.TestThreadUtils.runOnUiThreadBlocking;
+
+import android.widget.TextView;
+
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.test.filters.MediumTest;
 
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
-import org.mockito.Mock;
+import org.junit.runner.RunWith;
 import org.mockito.MockitoAnnotations;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
-import org.robolectric.RuntimeEnvironment;
+import org.mockito.quality.Strictness;
 
-import org.chromium.chrome.R;
-import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
-import org.chromium.components.browser_ui.bottomsheet.ManagedBottomSheetController;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.autofill.payments.AccountType;
+import org.chromium.components.autofill.payments.BankAccount;
+import org.chromium.components.autofill.payments.PaymentInstrument;
+import org.chromium.components.autofill.payments.PaymentRail;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
+import org.chromium.components.browser_ui.bottomsheet.BottomSheetTestSupport;
+import org.chromium.ui.modelutil.MVCListAdapter.ListItem;
+import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
+import org.chromium.ui.modelutil.PropertyModel;
+import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 
-/** Unit test for {@link FacilitatedPaymentsPaymentMethodsView}. */
-@SmallTest
+/** Instrumentation tests for {@link FacilitatedPaymentsPaymentMethodsView}. */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public final class FacilitatedPaymentsPaymentMethodsViewTest {
-    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
+    private static final BankAccount BANK_ACCOUNT_1 =
+            new BankAccount.Builder()
+                    .setPaymentInstrument(
+                            new PaymentInstrument.Builder()
+                                    .setInstrumentId(100)
+                                    .setNickname("nickname1")
+                                    .setSupportedPaymentRails(new int[] {PaymentRail.PIX})
+                                    .build())
+                    .setBankName("bankName1")
+                    .setAccountNumberSuffix("1111")
+                    .setAccountType(AccountType.CHECKING)
+                    .build();
+    private static final BankAccount BANK_ACCOUNT_2 =
+            new BankAccount.Builder()
+                    .setPaymentInstrument(
+                            new PaymentInstrument.Builder()
+                                    .setInstrumentId(200)
+                                    .setNickname("nickname2")
+                                    .setSupportedPaymentRails(new int[] {PaymentRail.PIX})
+                                    .build())
+                    .setBankName("bankName2")
+                    .setAccountNumberSuffix("2222")
+                    .setAccountType(AccountType.SAVINGS)
+                    .build();
 
-    private Context mContext;
-    private FacilitatedPaymentsPaymentMethodsView mContent;
-    private View mView;
+    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
 
-    @Mock private ManagedBottomSheetController mBottomSheetController;
+    @Rule
+    public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+
+    private BottomSheetController mBottomSheetController;
+    private BottomSheetTestSupport mSheetTestSupport;
+    private FacilitatedPaymentsPaymentMethodsView mView;
+    private PropertyModel mModel;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.getApplication().getApplicationContext();
-        mView = new View(mContext);
-        mContent = new FacilitatedPaymentsPaymentMethodsView(mContext, mBottomSheetController);
+        mActivityTestRule.startMainActivityOnBlankPage();
+        mBottomSheetController =
+                mActivityTestRule
+                        .getActivity()
+                        .getRootUiCoordinatorForTesting()
+                        .getBottomSheetController();
+        mSheetTestSupport = new BottomSheetTestSupport(mBottomSheetController);
+        runOnUiThreadBlocking(
+                () -> {
+                    mModel = createFacilitatedPaymentsPaymentMethodsModel();
+                    mView =
+                            new FacilitatedPaymentsPaymentMethodsView(
+                                    mActivityTestRule.getActivity(), mBottomSheetController);
+                    PropertyModelChangeProcessor.create(
+                            mModel,
+                            mView,
+                            FacilitatedPaymentsPaymentMethodsViewBinder
+                                    ::bindFacilitatedPaymentsPaymentMethodsView);
+                });
     }
 
     @Test
-    public void testContentView() {
-        assertThat(mContent.getContentView(), equalTo(mView));
+    @MediumTest
+    public void testVisibilityChangedByModel() {
+        runOnUiThreadBlocking(
+                () -> {
+                    mModel.get(SHEET_ITEMS)
+                            .add(
+                                    new ListItem(
+                                            BANK_ACCOUNT, createBankAccountModel(BANK_ACCOUNT_1)));
+                });
+        runOnUiThreadBlocking(() -> mModel.set(VISIBLE, true));
+        BottomSheetTestSupport.waitForOpen(mBottomSheetController);
+        assertThat(mView.getContentView().isShown(), is(true));
     }
 
     @Test
-    public void testBottomSheetHasNoToolbar() {
-        assertThat(mContent.getToolbarView(), nullValue());
+    @MediumTest
+    public void testBankAccountShown() {
+        runOnUiThreadBlocking(
+                () -> {
+                    mModel.get(SHEET_ITEMS)
+                            .add(
+                                    new ListItem(
+                                            BANK_ACCOUNT, createBankAccountModel(BANK_ACCOUNT_1)));
+                    mModel.set(VISIBLE, true);
+                    mModel.get(SHEET_ITEMS)
+                            .add(
+                                    new ListItem(
+                                            BANK_ACCOUNT, createBankAccountModel(BANK_ACCOUNT_2)));
+                });
+
+        BottomSheetTestSupport.waitForOpen(mBottomSheetController);
+
+        assertThat(getBankAccounts().getChildCount(), is(2));
+
+        String expectedBankAccountSummary1 = String.format("Pix  •  %s ••••%s", "Checking", "1111");
+        assertThat(getBankAccountNameAt(0).getText(), is("bankName1"));
+        assertThat(getBankAccountSummaryAt(0).getText(), is(expectedBankAccountSummary1));
+
+        String expectedBankAccountSummary2 = String.format("Pix  •  %s ••••%s", "Savings", "2222");
+        assertThat(getBankAccountNameAt(1).getText(), is("bankName2"));
+        assertThat(getBankAccountSummaryAt(1).getText(), is(expectedBankAccountSummary2));
     }
 
-    @Test
-    public void testNoVerticalScrollOffset() {
-        assertThat(mContent.getVerticalScrollOffset(), equalTo(0));
+    private PropertyModel createFacilitatedPaymentsPaymentMethodsModel() {
+        return new PropertyModel.Builder(FacilitatedPaymentsPaymentMethodsProperties.ALL_KEYS)
+                .with(VISIBLE, false)
+                .with(SHEET_ITEMS, new ModelList())
+                .build();
     }
 
-    @Test
-    public void testBottomSheetPriority() {
-        assertThat(mContent.getPriority(), equalTo(BottomSheetContent.ContentPriority.HIGH));
+    private PropertyModel createBankAccountModel(BankAccount bankAccount) {
+        return FacilitatedPaymentsPaymentMethodsMediator.createBankAccountModel(
+                mActivityTestRule.getActivity(), bankAccount);
     }
 
-    @Test
-    public void testCannotSwipeToDismissBottomSheet() {
-        assertFalse(mContent.swipeToDismissEnabled());
+    private RecyclerView getBankAccounts() {
+        return mView.getContentView().findViewById(R.id.sheet_item_list);
     }
 
-    @Test
-    public void testBottomSheetAccessibilityContentDescription() {
-        assertThat(mContent.getSheetContentDescriptionStringId(), equalTo(R.string.ok));
+    private TextView getBankAccountNameAt(int index) {
+        return getBankAccounts().getChildAt(index).findViewById(R.id.bank_name);
     }
 
-    @Test
-    public void testBottomSheetHalfHeightAccessibilityContentDescription() {
-        assertThat(mContent.getSheetHalfHeightAccessibilityStringId(), equalTo(R.string.ok));
-    }
-
-    @Test
-    public void testBottomSheetFullHeightAccessibilityContentDescription() {
-        assertThat(mContent.getSheetFullHeightAccessibilityStringId(), equalTo(R.string.ok));
-    }
-
-    @Test
-    public void testBottomSheetClosedAccessibilityContentDescription() {
-        assertThat(mContent.getSheetClosedAccessibilityStringId(), equalTo(R.string.ok));
+    private TextView getBankAccountSummaryAt(int index) {
+        return getBankAccounts().getChildAt(index).findViewById(R.id.bank_account_summary);
     }
 }
diff --git a/chrome/browser/facilitated_payments/ui/android/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsComponent.java b/chrome/browser/facilitated_payments/ui/android/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsComponent.java
index 58f68442..c8295a79 100644
--- a/chrome/browser/facilitated_payments/ui/android/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsComponent.java
+++ b/chrome/browser/facilitated_payments/ui/android/java/src/org/chromium/chrome/browser/facilitated_payments/FacilitatedPaymentsPaymentMethodsComponent.java
@@ -6,6 +6,7 @@
 
 import android.content.Context;
 
+import org.chromium.components.autofill.payments.BankAccount;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 
 /**
@@ -19,5 +20,5 @@
     void initialize(Context context, BottomSheetController bottomSheetController);
 
     /** Displays a new bottom sheet. */
-    void showSheet();
+    void showSheet(BankAccount[] bankAccounts);
 }
diff --git a/chrome/browser/feed/android/java/res/drawable/header_title_section_tab_background.xml b/chrome/browser/feed/android/java/res/drawable/header_title_section_tab_background.xml
index 8254883..78304210d 100644
--- a/chrome/browser/feed/android/java/res/drawable/header_title_section_tab_background.xml
+++ b/chrome/browser/feed/android/java/res/drawable/header_title_section_tab_background.xml
@@ -11,7 +11,7 @@
     <org.chromium.components.browser_ui.widget.SurfaceColorDrawable
         android:shape="rectangle"
         app:surfaceElevation="@dimen/feed_header_section_tab_bg_elevation_enabled">
-      <corners android:radius="@dimen/feed_header_background_corner_radius"/>
+      <corners android:radius="@dimen/feed_header_background_corner_radius_polished"/>
     </org.chromium.components.browser_ui.widget.SurfaceColorDrawable>
   </item>
 </selector>
\ No newline at end of file
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderView.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderView.java
index f35fb62..ebb28d17 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderView.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderView.java
@@ -207,7 +207,9 @@
                 updateTabLayoutHeaderWidth(false);
                 mTabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
                 mTabLayout.setBackgroundResource(
-                        R.drawable.header_title_section_tab_background_polished);
+                        ChromeFeatureList.isEnabled(ChromeFeatureList.FEED_CONTAINMENT)
+                                ? R.drawable.header_title_section_tab_background
+                                : R.drawable.header_title_section_tab_background_polished);
             }
         }
 
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 6d0693c4..5dd7796 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2105,6 +2105,11 @@
     "expiry_milestone": 129
   },
   {
+    "name": "draw-key-native-edge-to-edge",
+    "owners": ["katzz@google.com", "twellington@chromium.org", "edge-to-edge@chromium.org"],
+    "expiry_milestone": 142
+  },
+  {
     "name": "draw-native-edge-to-edge",
     "owners": ["donnd@chromium.org", "twellington@chromium.org", "edge-to-edge@chromium.org"],
     "expiry_milestone": 125
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index c6568ab..a230c090 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -4094,6 +4094,11 @@
     "Enables the Android feature Edge-to-Edge to draw below the Nav Bar. "
     "Requires DrawCutoutEdgeToEdge to also be enabled.";
 
+const char kDrawKeyNativeEdgeToEdgeName[] = "DrawKeyNativeEdgeToEdge";
+const char kDrawKeyNativeEdgeToEdgeDescription[] =
+    "Enables the Android feature Edge-to-Edge and forces a draw ToEdge on "
+    "select native pages.";
+
 const char kDrawNativeEdgeToEdgeName[] = "DrawNativeEdgeToEdge";
 const char kDrawNativeEdgeToEdgeDescription[] =
     "Enables the Android feature Edge-to-Edge and forces a draw ToEdge on all "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 0c58c789..2a3944e 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2409,6 +2409,9 @@
 extern const char kDrawEdgeToEdgeName[];
 extern const char kDrawEdgeToEdgeDescription[];
 
+extern const char kDrawKeyNativeEdgeToEdgeName[];
+extern const char kDrawKeyNativeEdgeToEdgeDescription[];
+
 extern const char kDrawNativeEdgeToEdgeName[];
 extern const char kDrawNativeEdgeToEdgeDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 9767272..01a5a4c 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -213,6 +213,7 @@
     &kDragDropIntoOmnibox,
     &kDragDropTabTearing,
     &kDrawEdgeToEdge,
+    &kDrawKeyNativeEdgeToEdge,
     &kDrawNativeEdgeToEdge,
     &kDrawWebEdgeToEdge,
     &kDynamicTopChrome,
@@ -634,6 +635,10 @@
              "DrawEdgeToEdge",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kDrawKeyNativeEdgeToEdge,
+             "DrawKeyNativeEdgeToEdge",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 BASE_FEATURE(kDrawNativeEdgeToEdge,
              "DrawNativeEdgeToEdge",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index b65822f..aa55b90 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -82,6 +82,7 @@
 BASE_DECLARE_FEATURE(kDontPrefetchLibraries);
 BASE_DECLARE_FEATURE(kDownloadAutoResumptionThrottling);
 BASE_DECLARE_FEATURE(kDrawEdgeToEdge);
+BASE_DECLARE_FEATURE(kDrawKeyNativeEdgeToEdge);
 BASE_DECLARE_FEATURE(kDrawNativeEdgeToEdge);
 BASE_DECLARE_FEATURE(kDrawWebEdgeToEdge);
 BASE_DECLARE_FEATURE(kDragDropIntoOmnibox);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 658af07c..74c2b330 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -288,6 +288,7 @@
     public static final String DRAG_DROP_TAB_TEARING = "DragDropTabTearing";
     public static final String DRAW_CUTOUT_EDGE_TO_EDGE = "DrawCutoutEdgeToEdge";
     public static final String DRAW_EDGE_TO_EDGE = "DrawEdgeToEdge";
+    public static final String DRAW_KEY_NATIVE_EDGE_TO_EDGE = "DrawKeyNativeEdgeToEdge";
     public static final String DRAW_NATIVE_EDGE_TO_EDGE = "DrawNativeEdgeToEdge";
     public static final String DRAW_WEB_EDGE_TO_EDGE = "DrawWebEdgeToEdge";
     public static final String DYNAMIC_TOP_CHROME = "DynamicTopChrome";
@@ -573,6 +574,8 @@
     public static final CachedFlag sDownloadsMigrateToJobsAPI =
             newCachedFlag(DOWNLOADS_MIGRATE_TO_JOBS_API, false);
     public static final CachedFlag sDrawEdgeToEdge = newCachedFlag(DRAW_EDGE_TO_EDGE, false);
+    public static final CachedFlag sDrawKeyNativeEdgeToEdge =
+            newCachedFlag(DRAW_KEY_NATIVE_EDGE_TO_EDGE, false);
     public static final CachedFlag sDrawNativeEdgeToEdge =
             newCachedFlag(DRAW_NATIVE_EDGE_TO_EDGE, false);
     public static final CachedFlag sDrawWebEdgeToEdge = newCachedFlag(DRAW_WEB_EDGE_TO_EDGE, false);
@@ -709,6 +712,7 @@
                     sDragDropIntoOmnibox,
                     sDownloadsMigrateToJobsAPI,
                     sDrawEdgeToEdge,
+                    sDrawKeyNativeEdgeToEdge,
                     sDrawNativeEdgeToEdge,
                     sDrawWebEdgeToEdge,
                     sDynamicTopChrome,
diff --git a/chrome/browser/lens/core/mojom/lens.mojom b/chrome/browser/lens/core/mojom/lens.mojom
index 97c5590..d642c02 100644
--- a/chrome/browser/lens/core/mojom/lens.mojom
+++ b/chrome/browser/lens/core/mojom/lens.mojom
@@ -25,12 +25,16 @@
 
 // Browser-side handler for requests from WebUI page. (TypeScript -> C++)
 interface LensPageHandler {
-  // When either of these methods are called, the C++ coordinator will begin
-  // the tear-down flow. The difference between the two is used to record
-  // metrics about the method used.
+  // WebUI calls this when the user wants to dismiss the lens overlay using
+  // the close button.
   CloseRequestedByOverlayCloseButton();
+
+  // Like above, but when dismissed by clicking on the overlay background.
   CloseRequestedByOverlayBackgroundClick();
 
+  // Like above, but when dismissed by pressing the escape key.
+  CloseRequestedByOverlayEscapeKeyPress();
+
   // When this method is called, the C++ coordinator will add a blur to the
   // tab contents.
   AddBackgroundBlur();
@@ -53,8 +57,8 @@
   // They do not and will not be used to be indexed into anything in the
   // browser; when the user traverses history, the indices may be passed back to
   // the WebUI.
-  IssueTextSelectionRequest(string query, int32 selection_start_index,
-      int32 selection_end_index);
+  IssueTextSelectionRequest(
+      string query, int32 selection_start_index, int32 selection_end_index);
 
   // When called, the C++ coordinator closes the lens search bubble. When the
   // user selects text or thumbnail on the WebUI overlay, the search bubble
@@ -93,6 +97,10 @@
 // Browser-side handler for requests from Side PanelWebUI page.
 // (TypeScript -> C++)
 interface LensSidePanelPageHandler {
+  // When this method is called, the C++ coordinator will begin the tear-down
+  // flow.
+  CloseRequestedBySidePanelEscapeKeyPress();
+
   // Pops the most recent search query from the history stack to load in the
   // side panel.
   PopAndLoadQueryFromHistory();
diff --git a/chrome/browser/net/reporting_browsertest.cc b/chrome/browser/net/reporting_browsertest.cc
index 790aebff..21a4ac07 100644
--- a/chrome/browser/net/reporting_browsertest.cc
+++ b/chrome/browser/net/reporting_browsertest.cc
@@ -162,7 +162,7 @@
  public:
   ReportingBrowserTest() {
     scoped_feature_list_.InitAndEnableFeature(
-        net::features::kPartitionNelAndReportingByNetworkIsolationKey);
+        net::features::kPartitionConnectionsByNetworkIsolationKey);
   }
 
   ReportingBrowserTest(const ReportingBrowserTest&) = delete;
@@ -178,7 +178,7 @@
  public:
   NonIsolatedReportingBrowserTest() {
     scoped_feature_list_.InitAndDisableFeature(
-        net::features::kPartitionNelAndReportingByNetworkIsolationKey);
+        net::features::kPartitionConnectionsByNetworkIsolationKey);
   }
 
   NonIsolatedReportingBrowserTest(const NonIsolatedReportingBrowserTest&) =
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 5d6d8e3..193362b 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -2027,9 +2027,6 @@
   { key::kCORSNonWildcardRequestHeadersSupport,
     prefs::kCorsNonWildcardRequestHeadersSupport,
     base::Value::Type::BOOLEAN },
-  { key::kUserAgentClientHintsGREASEUpdateEnabled,
-    policy_prefs::kUserAgentClientHintsGREASEUpdateEnabled,
-    base::Value::Type::BOOLEAN},
   { key::kUserAgentReduction,
     prefs::kUserAgentReduction,
     base::Value::Type::INTEGER},
diff --git a/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_util.cc b/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_util.cc
index d252a2d..38d9c692 100644
--- a/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_util.cc
+++ b/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_util.cc
@@ -601,19 +601,15 @@
   return url.host() + first_level_path;
 }
 
-// Returns LcppStat from `data`.
-// If LcppMultipleKeyKeyStat is enabled, this function can modify `data`
-// to emplace new LcppStat. `data_updated` is true on the case and
-// the caller should update the stored data.
-// TODO(yoichio): Updating data in "Get" function sounds weird. It could be
-// nice if we could restructure the functions or rename them.
-LcppStat* GetLcppStatToUpdate(const LoadingPredictorConfig& config,
-                              const GURL& url,
-                              LcppData& data,
-                              bool& data_updated) {
-  if (!IsLcppMultipleKeyKeyStatEnabled()) {
-    return data.mutable_lcpp_stat();
-  }
+// Returns LcppStat from `data` for LcppMultipleKeyKeyStat.
+// This function can modify `data` to emplace new LcppStat. `data_updated` is
+// true on the case and the caller should update the stored data.
+// This can return nullptr based on the FrequencyStatData of `data`.
+LcppStat* TryToGetLcppStatForKeyStat(const LoadingPredictorConfig& config,
+                                     const GURL& url,
+                                     LcppData& data,
+                                     bool& data_updated) {
+  CHECK(IsLcppMultipleKeyKeyStatEnabled());
 
   const std::string first_level_path = GetFirstLevelPath(url);
   if (first_level_path.empty() ||
@@ -975,7 +971,9 @@
 
   bool data_updated = false;
   LcppStat* lcpp_stat =
-      GetLcppStatToUpdate(config_, url, lcpp_data, data_updated);
+      IsLcppMultipleKeyKeyStatEnabled()
+          ? TryToGetLcppStatForKeyStat(config_, url, lcpp_data, data_updated)
+          : lcpp_data.mutable_lcpp_stat();
   if (lcpp_stat) {
     if (!IsValidLcppStat(*lcpp_stat)) {
       lcpp_stat->Clear();
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index b62e659a..06bdd9d 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -96,6 +96,7 @@
 #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
 #include "chrome/browser/ui/exclusive_access/keyboard_lock_controller.h"
 #include "chrome/browser/ui/lens/lens_overlay_controller.h"
+#include "chrome/browser/ui/lens/lens_overlay_image_helper.h"
 #include "chrome/browser/ui/passwords/ui_utils.h"
 #include "chrome/browser/ui/qrcode_generator/qrcode_generator_bubble_controller.h"
 #include "chrome/browser/ui/send_tab_to_self/send_tab_to_self_bubble.h"
@@ -829,6 +830,8 @@
                                       kExitFullscreenMenuItem);
 DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(RenderViewContextMenu, kComposeMenuItem);
 DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(RenderViewContextMenu, kRegionSearchItem);
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(RenderViewContextMenu,
+                                      kSearchForImageItem);
 
 RenderViewContextMenu::RenderViewContextMenu(
     content::RenderFrameHost& render_frame_host,
@@ -2023,10 +2026,14 @@
     return;
   }
 
+  const int search_for_image_idc = GetSearchForImageIdc();
   menu_model_.AddItem(
-      GetSearchForImageIdc(),
+      search_for_image_idc,
       l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHLENSFORIMAGE,
                                  provider->short_name()));
+  const int command_index =
+      menu_model_.GetIndexOfCommandId(search_for_image_idc).value();
+  menu_model_.SetElementIdentifierAt(command_index, kSearchForImageItem);
 
   if (companion::IsNewBadgeEnabledForSearchMenuItem(GetBrowser())) {
     menu_model_.SetIsNewFeatureAt(menu_model_.GetItemCount() - 1, true);
@@ -4232,13 +4239,46 @@
   lens::RecordAmbientSearchQuery(
       lens::AmbientSearchEntryPoint::
           CONTEXT_MENU_SEARCH_IMAGE_WITH_GOOGLE_LENS);
-  core_tab_helper->SearchWithLens(
-      render_frame_host, params().src_url,
-      is_image_translate
-          ? lens::EntryPoint::
-                CHROME_TRANSLATE_IMAGE_WITH_GOOGLE_LENS_CONTEXT_MENU_ITEM
-          : lens::EntryPoint::CHROME_SEARCH_WITH_GOOGLE_LENS_CONTEXT_MENU_ITEM,
-      is_image_translate);
+
+  if (LensOverlayController::IsEnabled(GetProfile()) &&
+      lens::features::UseLensOverlayForImageSearch()) {
+    auto view_bounds = render_frame_host->GetView()->GetViewBounds();
+    mojo::AssociatedRemote<chrome::mojom::ChromeRenderFrame>
+        chrome_render_frame;
+    render_frame_host->GetRemoteAssociatedInterfaces()->GetInterface(
+        &chrome_render_frame);
+    // Bind the InterfacePtr into the callback so that it's kept alive until
+    // there's either a connection error or a response.
+    auto* frame = chrome_render_frame.get();
+
+    frame->RequestBoundsForContextNodeDiagnostic(
+        base::BindOnce(&RenderViewContextMenu::OpenLensOverlayWithBounds,
+                       weak_pointer_factory_.GetWeakPtr(),
+                       std::move(chrome_render_frame), view_bounds));
+  } else {
+    core_tab_helper->SearchWithLens(
+        render_frame_host, params().src_url,
+        is_image_translate
+            ? lens::EntryPoint::
+                  CHROME_TRANSLATE_IMAGE_WITH_GOOGLE_LENS_CONTEXT_MENU_ITEM
+            : lens::EntryPoint::
+                  CHROME_SEARCH_WITH_GOOGLE_LENS_CONTEXT_MENU_ITEM,
+        is_image_translate);
+  }
+}
+
+void RenderViewContextMenu::OpenLensOverlayWithBounds(
+    mojo::AssociatedRemote<chrome::mojom::ChromeRenderFrame>
+        chrome_render_frame,
+    const gfx::Rect& view_bounds,
+    const gfx::Rect& image_bounds) {
+  LensOverlayController* const controller =
+      LensOverlayController::GetController(source_web_contents_);
+  CHECK(controller);
+  controller->ShowUIWithPendingRegion(
+      LensOverlayController::InvocationSource::kContentAreaContextMenuPage,
+      lens::GetCenterRotatedBoxFromViewAndImageBounds(view_bounds,
+                                                      image_bounds));
 }
 
 void RenderViewContextMenu::ExecAddANote() {
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.h b/chrome/browser/renderer_context_menu/render_view_context_menu.h
index 6c59d4cca..2d1d3b1b 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.h
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.h
@@ -18,6 +18,7 @@
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/autofill/autofill_context_menu_manager.h"
+#include "chrome/common/chrome_render_frame.mojom.h"
 #include "components/compose/buildflags.h"
 #include "components/custom_handlers/protocol_handler_registry.h"
 #include "components/lens/buildflags.h"
@@ -112,6 +113,7 @@
   DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kExitFullscreenMenuItem);
   DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kComposeMenuItem);
   DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kRegionSearchItem);
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kSearchForImageItem);
 
   using ExecutePluginActionCallback =
       base::OnceCallback<void(content::RenderFrameHost*,
@@ -432,6 +434,14 @@
       supervised_user::FilteringBehaviorReason reason,
       bool uncertain);
 
+  // Opens the Lens overlay to search a region defined by the given bounds of
+  // the view and the image to be searched.
+  void OpenLensOverlayWithBounds(
+      mojo::AssociatedRemote<chrome::mojom::ChromeRenderFrame>
+          chrome_render_frame,
+      const gfx::Rect& view_bounds,
+      const gfx::Rect& image_bounds);
+
 #if BUILDFLAG(IS_CHROMEOS)
   // Shows the standalone clipboard history menu. `event_flags` describes the
   // event that caused the menu to show.
diff --git a/chrome/browser/resources/ash/settings/BUILD.gn b/chrome/browser/resources/ash/settings/BUILD.gn
index ea4085a..7117f00 100644
--- a/chrome/browser/resources/ash/settings/BUILD.gn
+++ b/chrome/browser/resources/ash/settings/BUILD.gn
@@ -367,6 +367,7 @@
     "common/route_origin_mixin.ts",
     "common/setting_id_param_util.ts",
     "common/types.ts",
+    "controls/v2/base_row_mixin.ts",
     "controls/v2/pref_control_mixin_internal.ts",
     "os_apps_page/app_management_page/privacy_hub_mixin.ts",
     "os_files_page/google_drive_browser_proxy.ts",
diff --git a/chrome/browser/resources/ash/settings/controls/v2/base_row_mixin.ts b/chrome/browser/resources/ash/settings/controls/v2/base_row_mixin.ts
new file mode 100644
index 0000000..51f90b2
--- /dev/null
+++ b/chrome/browser/resources/ash/settings/controls/v2/base_row_mixin.ts
@@ -0,0 +1,118 @@
+// 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
+ * BaseRowMixin is a mixin that provides the common properties and
+ * APIs shared by all settings row components. It is intended to reduce
+ * duplicated code among the row components.
+ */
+
+import {dedupingMixin, type PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import type {Constructor} from '../../common/types.js';
+
+export interface BaseRowMixinInterface {
+  label?: string;
+  sublabel?: string;
+  icon?: string;
+  learnMoreUrl?: string;
+  ariaLabel: string|null;
+  ariaDescription: string|null;
+  getAriaLabel(): string|null;
+  getAriaDescription(): string|null;
+}
+
+export const BaseRowMixin = dedupingMixin(
+    <T extends Constructor<PolymerElement>>(superClass: T): T&
+    Constructor<BaseRowMixinInterface> => {
+      class BaseRowMixinImpl extends superClass {
+        static get properties() {
+          return {
+            /**
+             * The user-visible label for the row.
+             */
+            label: String,
+
+            /**
+             * The user-visible sublabel for the row.
+             */
+            sublabel: String,
+
+            /**
+             * The leading icon for the row.
+             */
+            icon: String,
+
+            /**
+             * The URL that follows the `sublabel`. It usually opens a help
+             * center article to help user better understand the setting.
+             */
+            learnMoreUrl: {
+              type: String,
+              reflectToAttribute: true,
+            },
+
+            /**
+             * Used to manually define an a11y label for the associated control
+             * element of the row.
+             */
+            ariaLabel: {
+              type: String,
+              reflectToAttribute: true,
+            },
+
+            /**
+             * Used to manually define an a11y description for the associated
+             * control element of the row.
+             */
+            ariaDescription: {
+              type: String,
+              reflectToAttribute: true,
+            },
+          };
+        }
+
+        label?: string;
+        sublabel?: string;
+        icon?: string;
+        learnMoreUrl?: string;
+
+        /**
+         * Return an a11y label for the associated control element. `ariaLabel`
+         * takes precedence over `label`. If neither of them is defined, it
+         * returns null.
+         */
+        getAriaLabel(): string|null {
+          if (this.ariaLabel) {
+            return this.ariaLabel;
+          }
+
+          if (this.label) {
+            return this.label;
+          }
+
+          return null;
+        }
+
+        /**
+         * Return an a11y description for the associated control element.
+         * `ariaDescription` takes precedence over `sublabel`. If neither of
+         * them is defined, it returns null.
+         */
+        getAriaDescription(): string|null {
+          if (this.ariaDescription) {
+            return this.ariaDescription;
+          }
+
+          if (this.sublabel) {
+            return this.sublabel;
+          }
+
+          return null;
+        }
+      }
+
+      return BaseRowMixinImpl;
+    });
diff --git a/chrome/browser/resources/ash/settings/os_settings.ts b/chrome/browser/resources/ash/settings/os_settings.ts
index 74b5b46..897685d 100644
--- a/chrome/browser/resources/ash/settings/os_settings.ts
+++ b/chrome/browser/resources/ash/settings/os_settings.ts
@@ -138,6 +138,7 @@
 export {SettingsDropdownMenuElement} from './controls/settings_dropdown_menu.js';
 export {SettingsSliderElement} from './controls/settings_slider.js';
 export {SettingsToggleButtonElement} from './controls/settings_toggle_button.js';
+export {BaseRowMixin} from './controls/v2/base_row_mixin.js';
 export {PrefControlMixinInternal} from './controls/v2/pref_control_mixin_internal.js';
 export {SettingsDropdownV2Element} from './controls/v2/settings_dropdown_v2.js';
 export {SettingsSliderV2Element} from './controls/v2/settings_slider_v2.js';
diff --git a/chrome/browser/resources/chromeos/arc_graphics_tracing/OWNERS b/chrome/browser/resources/chromeos/arc_overview_tracing/OWNERS
similarity index 100%
rename from chrome/browser/resources/chromeos/arc_graphics_tracing/OWNERS
rename to chrome/browser/resources/chromeos/arc_overview_tracing/OWNERS
diff --git a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_overview_tracing.html b/chrome/browser/resources/chromeos/arc_overview_tracing/arc_overview_tracing.html
similarity index 100%
rename from chrome/browser/resources/chromeos/arc_graphics_tracing/arc_overview_tracing.html
rename to chrome/browser/resources/chromeos/arc_overview_tracing/arc_overview_tracing.html
diff --git a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_overview_tracing.js b/chrome/browser/resources/chromeos/arc_overview_tracing/arc_overview_tracing.js
similarity index 100%
rename from chrome/browser/resources/chromeos/arc_graphics_tracing/arc_overview_tracing.js
rename to chrome/browser/resources/chromeos/arc_overview_tracing/arc_overview_tracing.js
diff --git a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_overview_tracing_ui.js b/chrome/browser/resources/chromeos/arc_overview_tracing/arc_overview_tracing_ui.js
similarity index 100%
rename from chrome/browser/resources/chromeos/arc_graphics_tracing/arc_overview_tracing_ui.js
rename to chrome/browser/resources/chromeos/arc_overview_tracing/arc_overview_tracing_ui.js
diff --git a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_tracing.css b/chrome/browser/resources/chromeos/arc_overview_tracing/arc_tracing.css
similarity index 100%
rename from chrome/browser/resources/chromeos/arc_graphics_tracing/arc_tracing.css
rename to chrome/browser/resources/chromeos/arc_overview_tracing/arc_tracing.css
diff --git a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_tracing_ui.js b/chrome/browser/resources/chromeos/arc_overview_tracing/arc_tracing_ui.js
similarity index 100%
rename from chrome/browser/resources/chromeos/arc_graphics_tracing/arc_tracing_ui.js
rename to chrome/browser/resources/chromeos/arc_overview_tracing/arc_tracing_ui.js
diff --git a/chrome/browser/resources/discards/discards_main.html b/chrome/browser/resources/discards/discards_main.html
index 9ed843d25..84444eb 100644
--- a/chrome/browser/resources/discards/discards_main.html
+++ b/chrome/browser/resources/discards/discards_main.html
@@ -1,4 +1,3 @@
-
     <style include="cr-hidden-style">
       :host {
         display: flex;
@@ -7,12 +6,12 @@
         overflow: hidden;
       }
 
-      iron-pages {
+      cr-page-selector {
         flex: 1;
         overflow: hidden;
       }
 
-      iron-pages > * {
+      cr-page-selector > * {
         display: block;
         height: 100%;
         overflow: auto;
@@ -22,11 +21,10 @@
         overflow: hidden;
       }
     </style>
-    <iron-location path="{{path}}"></iron-location>
     <cr-tabs selected="{{selected}}" tab-names="[[tabs]]"></cr-tabs>
 
-    <iron-pages selected="[[selected]]">
+    <cr-page-selector selected="[[selected]]">
       <discards-tab></discards-tab>
       <database-tab></database-tab>
       <graph-tab></graph-tab>
-    </iron-pages>
+    </cr-page-selector>
diff --git a/chrome/browser/resources/discards/discards_main.ts b/chrome/browser/resources/discards/discards_main.ts
index c2fa051..18ce788 100644
--- a/chrome/browser/resources/discards/discards_main.ts
+++ b/chrome/browser/resources/discards/discards_main.ts
@@ -3,13 +3,13 @@
 // found in the LICENSE file.
 
 import 'chrome://resources/cr_elements/cr_hidden_style.css.js';
+import 'chrome://resources/cr_elements/cr_page_selector/cr_page_selector.js';
 import 'chrome://resources/cr_elements/cr_tabs/cr_tabs.js';
-import 'chrome://resources/polymer/v3_0/iron-location/iron-location.js';
-import 'chrome://resources/polymer/v3_0/iron-pages/iron-pages.js';
 import './database_tab.js';
 import './discards_tab.js';
 import './graph_tab.js';
 
+import {CrRouter} from 'chrome://resources/js/cr_router.js';
 import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 import {getTemplate} from './discards_main.html.js';
@@ -31,12 +31,6 @@
         observer: 'selectedChanged_',
       },
 
-      path: {
-        type: String,
-        value: '',
-        observer: 'pathChanged_',
-      },
-
       tabs: {
         type: Array,
         value: () => ['Discards', 'Database', 'Graph'],
@@ -45,16 +39,25 @@
   }
 
   selected: number;
-  path: string;
   tabs: string[];
 
+  override ready() {
+    super.ready();
+    const router = CrRouter.getInstance();
+    this.pathChanged_(router.getPath());
+    router.addEventListener(
+        'cr-router-path-changed',
+        (e: Event) => this.pathChanged_((e as CustomEvent<string>).detail));
+  }
+
   /** Updates the location hash on selection change. */
   private selectedChanged_(newValue: number, oldValue?: number) {
     if (oldValue !== undefined) {
       // The first tab is special-cased to the empty path.
       const defaultTab = this.tabs[0].toLowerCase();
       const tabName = this.tabs[newValue].toLowerCase();
-      this.path = '/' + (tabName === defaultTab ? '' : tabName);
+      CrRouter.getInstance().setPath(
+          '/' + (tabName === defaultTab ? '' : tabName));
     }
   }
 
@@ -68,7 +71,7 @@
   }
 
   /** Updates the selection property on path change. */
-  private pathChanged_(newValue: string, _oldValue?: string) {
+  private pathChanged_(newValue: string) {
     this.selected = this.selectedFromPath_(newValue.substr(1));
   }
 }
diff --git a/chrome/browser/resources/extensions/mv2_deprecation_panel.html b/chrome/browser/resources/extensions/mv2_deprecation_panel.html
index cab8b288..ee926c5 100644
--- a/chrome/browser/resources/extensions/mv2_deprecation_panel.html
+++ b/chrome/browser/resources/extensions/mv2_deprecation_panel.html
@@ -9,20 +9,6 @@
     padding: 12px 0px;
   }
 
-  .header-text {
-    padding-inline-start: 20px;
-  }
-
-  .header-text h3 {
-    margin: 5px 0 3px 0;
-    font-weight: 400;
-  }
-
-  .header-icon {
-    align-items: center;
-    fill: var(--review-panel-icon-color);
-  }
-
   .header-button {
     margin-inline-start: auto;
   }
@@ -52,9 +38,9 @@
 <div class="panel-background" id="panelContainer">
   <div class="header cr-row first">
     <iron-icon aria-hidden="true" icon="extensions-icons:my_extensions"
-        class="header-icon">
+        class="panel-header-icon">
     </iron-icon>
-    <div class="header-text">
+    <div class="panel-header-text">
       <h3 id="headingText">[[headerString_]]</h3>
       <div class="cr-secondary-text"
           inner-h-t-m-l="[[getSubtitleString_(subtitleString_)]]">
diff --git a/chrome/browser/resources/extensions/review_panel.html b/chrome/browser/resources/extensions/review_panel.html
index 2de2cb0..fdf22e1 100644
--- a/chrome/browser/resources/extensions/review_panel.html
+++ b/chrome/browser/resources/extensions/review_panel.html
@@ -15,11 +15,6 @@
     margin: 0 0 16px 5px;
   }
 
-  .header-with-icon h3 {
-    margin: 5px 0 3px 0;
-    font-weight: 400;
-  }
-
   cr-icon[icon='cr:check'] {
     padding-inline-start: 10px;
     fill: var(--google-green-700);
@@ -31,15 +26,6 @@
     }
   }
 
-  .text-container {
-    padding-inline-start: 20px;
-  }
-
-  .header-icon {
-    align-items: center;
-    fill: var(--panel-icon-color);
-  }
-
   .header-group-wrapper {
     flex: 1;
     margin-inline-start: 15px;
@@ -101,10 +87,6 @@
       margin-inline-end: auto;
       margin-top: 10px;
     }
-
-    .header-icon {
-      margin-top: 40px;
-    }
   }
   /* clean-css ignore:end */
 
@@ -120,9 +102,9 @@
       hidden$="[[!shouldShowUnsafeExtensions_]]">
     <div class="header-with-icon" id="reviewPanelContainer">
       <cr-icon aria-hidden="true" icon="extensions-icons:my_extensions"
-          class="header-icon">
+          class="panel-header-icon">
       </cr-icon>
-      <div class="text-container">
+      <div class="panel-header-text">
         <h3 id="headingText">[[headerString_]]</h3>
         <div
           class="cr-secondary-text"
diff --git a/chrome/browser/resources/extensions/shared_style.css b/chrome/browser/resources/extensions/shared_style.css
index 98d6af4..4ae22588 100644
--- a/chrome/browser/resources/extensions/shared_style.css
+++ b/chrome/browser/resources/extensions/shared_style.css
@@ -117,3 +117,25 @@
   padding: 12px 20px;
   container-type: inline-size;
 }
+
+.panel-header-text {
+  padding-inline-start: 20px;
+}
+
+.panel-header-text h3 {
+  margin: 5px 0 3px 0;
+  font-weight: 400;
+}
+
+.panel-header-icon {
+  align-items: center;
+  fill: var(--panel-icon-color);
+}
+
+/* clean-css ignore:start */
+@container (max-width:450px) {
+  .panel-header-icon {
+      margin-top: 40px;
+  }
+}
+/* clean-css ignore:end */
diff --git a/chrome/browser/resources/internals/user_education/user_education_internals.html b/chrome/browser/resources/internals/user_education/user_education_internals.html
index 0973422..68b7401 100644
--- a/chrome/browser/resources/internals/user_education/user_education_internals.html
+++ b/chrome/browser/resources/internals/user_education/user_education_internals.html
@@ -144,7 +144,6 @@
 <div id="container">
   <div id="left" hidden$="[[narrow_]]">
     <div role="navigation">
-      <iron-location hash="{{hash_}}"></iron-location>
       <h2>Navigation</h2>
       <cr-menu-selector id="menu" selectable="a" attr-for-selected="href"
           on-iron-activate="onSelectorActivate_" on-click="onLinkClick_"
diff --git a/chrome/browser/resources/internals/user_education/user_education_internals.ts b/chrome/browser/resources/internals/user_education/user_education_internals.ts
index ee9c644..2eb3d6b 100644
--- a/chrome/browser/resources/internals/user_education/user_education_internals.ts
+++ b/chrome/browser/resources/internals/user_education/user_education_internals.ts
@@ -14,7 +14,6 @@
 import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.js';
 import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar_search_field.js';
 import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
-import 'chrome://resources/polymer/v3_0/iron-location/iron-location.js';
 import './user_education_internals_card.js';
 
 import {ColorChangeUpdater} from 'chrome://resources/cr_components/color_change_listener/colors_css_updater.js';
diff --git a/chrome/browser/resources/lens/overlay/lens_overlay_app.html b/chrome/browser/resources/lens/overlay/lens_overlay_app.html
index 922c6517..711d5a0e 100644
--- a/chrome/browser/resources/lens/overlay/lens_overlay_app.html
+++ b/chrome/browser/resources/lens/overlay/lens_overlay_app.html
@@ -4,6 +4,10 @@
     width: 100%;
   }
 
+  .hidden {
+    display: none;
+  }
+
   #backgroundScrim {
     background-color: #151C264D;
     inset: 0;
@@ -46,11 +50,10 @@
     on-screenshot-rendered="onScreenshotRendered">
   <div id="backgroundScrim" on-click="onBackgroundScrimClicked"
       hidden$="[[!isImageRendered]]"></div>
-  <!-- Do not render selection overlay if data URI is empty. -->
-  <template is="dom-if" if="[[screenshotDataUri.length]]">
-    <lens-selection-overlay
-        screenshot-data-uri="[[screenshotDataUri]]"></lens-selection-overlay>
-  </template>
+  <lens-selection-overlay
+      screenshot-data-uri="[[screenshotDataUri]]"
+      class$="[[getSelectionOverlayClass(screenshotDataUri)]]">
+  </lens-selection-overlay>
   <initial-toast id="initialToast"></initial-toast>
   <div id="buttonContainer">
     <cr-icon-button id="feedbackButton" class="action-button"
diff --git a/chrome/browser/resources/lens/overlay/lens_overlay_app.ts b/chrome/browser/resources/lens/overlay/lens_overlay_app.ts
index f08075fc..05cb3ef 100644
--- a/chrome/browser/resources/lens/overlay/lens_overlay_app.ts
+++ b/chrome/browser/resources/lens/overlay/lens_overlay_app.ts
@@ -17,6 +17,14 @@
 import type {InitialToastElement} from './initial_toast.js';
 import {getTemplate} from './lens_overlay_app.html.js';
 
+// Closes overlay if escape button is pressed.
+function maybeCloseOverlay(event: KeyboardEvent) {
+  if (event.key === 'Escape') {
+    BrowserProxyImpl.getInstance()
+        .handler.closeRequestedByOverlayEscapeKeyPress();
+  }
+}
+
 export interface LensOverlayAppElement {
   $: {
     backgroundScrim: HTMLElement,
@@ -47,7 +55,7 @@
   }
 
   // The data URI of the screenshot passed from C++.
-  private screenshotDataUri: string;
+  private screenshotDataUri: string = '';
   // Whether the close button should be hidden.
   private closeButtonHidden: boolean = false;
   // Whether the image has finished rendering.
@@ -66,6 +74,7 @@
       callbackRouter.notifyResultsPanelOpened.addListener(
           this.onNotifyResultsPanelOpened.bind(this)),
     ];
+    window.addEventListener('keyup', maybeCloseOverlay);
   }
 
   override disconnectedCallback() {
@@ -73,6 +82,7 @@
     this.listenerIds.forEach(
         id => assert(this.browserProxy.callbackRouter.removeListener(id)));
     this.listenerIds = [];
+    window.removeEventListener('keyup', maybeCloseOverlay);
   }
 
   private onBackgroundScrimClicked() {
@@ -127,6 +137,13 @@
   private onScreenshotRendered() {
     this.isImageRendered = true;
   }
+  private getSelectionOverlayClass(screenshotDataUri: string): string {
+    if (!screenshotDataUri || !screenshotDataUri.length) {
+      return 'hidden';
+    } else {
+      return '';
+    }
+  }
 }
 
 declare global {
diff --git a/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.html b/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.html
index 2b7c774d..2b49d5c 100644
--- a/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.html
+++ b/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.html
@@ -48,14 +48,31 @@
     position: fixed;
     z-index: 2;  /* Searchbox should render in front of the results iframe. */
     /* TODO(jdonnelly): Specify these in a color mixer. */
-    --color-realbox-background: #ffffffff;
+    /* Colors used in the cr-searchbox results dropdown */
+    --color-realbox-answer-icon-background: #d3e3fdff;
+    --color-realbox-answer-icon-foreground: #041e49ff;
+    --color-realbox-results-action-chip-focus-outline: #0b57d0ff;
+    --color-realbox-results-action-chip-icon: #0b57d0ff;
+    --color-realbox-results-action-chip:#a8c7faff;
+    --color-realbox-results-background-hovered:#e9e9eaff;
+    --color-realbox-results-background: #ffffffff;
+    --color-realbox-results-button-hover: #202124ff;
+    --color-realbox-results-dim-selected: #5f6368ff;
+    --color-realbox-results-focus-indicator: #e9e9eaff;
+    --color-realbox-results-foreground-dimmed: #5f6368ff;
+    --color-realbox-results-foreground: #000000ff;
+    --color-realbox-results-icon-focused-outline: #1a73e8ff;
+    --color-realbox-results-icon-selected: #5f6368ff;
+    --color-realbox-results-icon: #5f6368ff;
+    --color-realbox-results-url-selected: #1967d2ff;
+    --color-realbox-results-url: #1967d2ff;
+    --color-realbox-search-icon-background: #5f6368ff;
+    /* Colors specific to the cr-searchbox input */
     --color-realbox-background-hovered: #ffffffff;
+    --color-realbox-background: #ffffffff;
     --color-realbox-border: #dadce0ff;
     --color-realbox-foreground: #202124ff;
-    --color-realbox-placeholder:#5f6368ff;
-    --color-realbox-results-background: #ffffffff;
-    --color-realbox-results-background-hovered:#e9e9eaff;
-    --color-realbox-results-focus-indicator: #e9e9eaff;
+    --color-realbox-placeholder: #5f6368ff;
     --color-realbox-shadow: #20212451;
   }
 
diff --git a/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.ts b/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.ts
index c0e5671..551d3db 100644
--- a/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.ts
+++ b/chrome/browser/resources/lens/overlay/side_panel/side_panel_app.ts
@@ -21,6 +21,14 @@
 const VIEWPORT_HEIGHT_KEY = 'bih';
 const VIEWPORT_WIDTH_KEY = 'biw';
 
+// Closes overlay if the escape key is pressed.
+function maybeCloseOverlay(event: KeyboardEvent) {
+  if (event.key === 'Escape') {
+    SidePanelBrowserProxyImpl.getInstance()
+        .handler.closeRequestedBySidePanelEscapeKeyPress();
+  }
+}
+
 export interface LensSidePanelAppElement {
   $: {
     results: HTMLIFrameElement,
@@ -89,6 +97,7 @@
       this.browserProxy.callbackRouter.setBackArrowVisible.addListener(
           this.setBackArrowVisible.bind(this)),
     ];
+    window.addEventListener('keyup', maybeCloseOverlay);
   }
 
   override disconnectedCallback() {
@@ -97,6 +106,7 @@
     this.listenerIds.forEach(
         id => assert(this.browserProxy.callbackRouter.removeListener(id)));
     this.listenerIds = [];
+    window.removeEventListener('keyup', maybeCloseOverlay);
   }
 
   private onBackArrowClick() {
diff --git a/chrome/browser/resources/omnibox_popup/app.html b/chrome/browser/resources/omnibox_popup/app.html
index 65612d3c..1fe0abb 100644
--- a/chrome/browser/resources/omnibox_popup/app.html
+++ b/chrome/browser/resources/omnibox_popup/app.html
@@ -1,25 +1,28 @@
 <style>
   :host {
-    --color-realbox-answer-icon-background: var(--color-omnibox-answer-icon-g-m3-background);
-    --color-realbox-answer-icon-foreground: var(--color-omnibox-answer-icon-g-m3-foreground);
-    --color-realbox-results-action-chip: var(--color-omnibox-results-button-border);
-    --color-realbox-results-action-chip-icon: var(--color-omnibox-results-button-icon);
-    --color-realbox-results-action-chip-focus-outline: var(--color-omnibox-results-button-icon-selected);
-    --color-realbox-results-background: var(--color-omnibox-results-background);
-    --color-realbox-results-background-hovered: var(--color-omnibox-results-background-hovered);
-    --color-realbox-results-dim-selected: var(--color-omnibox-result-text-dimmed-selected);
-    --color-realbox-results-focus-indicator: var(--color-omnibox-results-focus-indicator);
-    --color-realbox-results-foreground: var(--color-omnibox-text);
-    --color-realbox-results-foreground-dimmed: var(--color-omnibox-results-text-dimmed);
-    --color-realbox-results-icon: var(--color-omnibox-results-icon);
-    --color-realbox-results-icon-focused-outline: var(--color-omnibox-results-focus-indicator);
-    --color-realbox-results-icon-selected: var(--color-omnibox-results-icon-selected);
-    --color-realbox-results-url: var(--color-omnibox-results-url);
-    --color-realbox-results-url-selected: var(--color-omnibox-results-url-selected);
-    --color-realbox-search-icon-background: var(--color-omnibox-results-icon);
     --cr-realbox-min-width: 75%;
     --cr-realbox-width: 100%;
     font-size: 14.6px; /* closely resembles the omnibox input font size. */
+    /* Colors used in the cr-searchbox results dropdown */
+    --color-realbox-answer-icon-background: var(--color-omnibox-answer-icon-g-m3-background);
+    --color-realbox-answer-icon-foreground: var(--color-omnibox-answer-icon-g-m3-foreground);
+    --color-realbox-results-action-chip-focus-outline: var(--color-omnibox-results-button-icon-selected);
+    --color-realbox-results-action-chip-icon: var(--color-omnibox-results-button-icon);
+    --color-realbox-results-action-chip: var(--color-omnibox-results-button-border);
+    --color-realbox-results-background-hovered: var(--color-omnibox-results-background-hovered);
+    --color-realbox-results-background: var(--color-omnibox-results-background);
+    /* TODO(b/40251392): Replace hardcoded color below with a color token. */
+    --color-realbox-results-button-hover: #202124ff;
+    --color-realbox-results-dim-selected: var(--color-omnibox-result-text-dimmed-selected);
+    --color-realbox-results-focus-indicator: var(--color-omnibox-results-focus-indicator);
+    --color-realbox-results-foreground-dimmed: var(--color-omnibox-results-text-dimmed);
+    --color-realbox-results-foreground: var(--color-omnibox-text);
+    --color-realbox-results-icon-focused-outline: var(--color-omnibox-results-focus-indicator);
+    --color-realbox-results-icon-selected: var(--color-omnibox-results-icon-selected);
+    --color-realbox-results-icon: var(--color-omnibox-results-icon);
+    --color-realbox-results-url-selected: var(--color-omnibox-results-url-selected);
+    --color-realbox-results-url: var(--color-omnibox-results-url);
+    --color-realbox-search-icon-background: var(--color-omnibox-results-icon);
   }
 
   /**
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.ts b/chrome/browser/resources/settings/a11y_page/a11y_page.ts
index 3f7b097..9e18c4b 100644
--- a/chrome/browser/resources/settings/a11y_page/a11y_page.ts
+++ b/chrome/browser/resources/settings/a11y_page/a11y_page.ts
@@ -147,14 +147,9 @@
         type: Boolean,
         value() {
           let opensExternally = false;
-          // <if expr="is_macosx">
+          // <if expr="is_macosx or is_win">
           opensExternally = true;
           // </if>
-
-          // <if expr="is_win">
-          opensExternally = loadTimeData.getBoolean('isWindows10OrNewer');
-          // </if>
-
           return opensExternally;
         },
       },
diff --git a/chrome/browser/resources/settings/page_visibility.ts b/chrome/browser/resources/settings/page_visibility.ts
index b47ef20..c9b89e2 100644
--- a/chrome/browser/resources/settings/page_visibility.ts
+++ b/chrome/browser/resources/settings/page_visibility.ts
@@ -42,16 +42,13 @@
   searchPrediction: boolean;
 }
 
-/**
- * Dictionary defining page visibility.
- */
-export let pageVisibility: PageVisibility;
+function createPageVisibility(): PageVisibility|undefined {
+  if (!loadTimeData.getBoolean('isGuest')) {
+    return undefined;
+  }
 
-if (loadTimeData.getBoolean('isGuest')) {
-  // "if not chromeos" and "if chromeos" in two completely separate blocks
-  // to work around closure compiler.
   // <if expr="not is_chromeos">
-  pageVisibility = {
+  const pageVisibility = {
     a11y: false,
     advancedSettings: false,
     ai: false,
@@ -73,7 +70,7 @@
   };
   // </if>
   // <if expr="is_chromeos">
-  pageVisibility = {
+  const pageVisibility = {
     ai: false,
     autofill: false,
     people: false,
@@ -102,8 +99,16 @@
     performance: false,
   };
   // </if>
+
+  return pageVisibility;
 }
 
-export function setPageVisibilityForTesting(testVisibility: PageVisibility) {
+/**
+ * Dictionary defining page visibility.
+ */
+export let pageVisibility: PageVisibility|undefined = createPageVisibility();
+
+export function resetPageVisibilityForTesting(
+    testVisibility: PageVisibility|undefined = createPageVisibility()) {
   pageVisibility = testVisibility;
 }
diff --git a/chrome/browser/resources/settings/route.ts b/chrome/browser/resources/settings/route.ts
index c801b3c..b8937e3 100644
--- a/chrome/browser/resources/settings/route.ts
+++ b/chrome/browser/resources/settings/route.ts
@@ -269,12 +269,6 @@
     r.CAPTIONS = r.ACCESSIBILITY.createChild('/captions');
     // </if>
 
-    // <if expr="is_win">
-    if (!loadTimeData.getBoolean('isWindows10OrNewer')) {
-      r.CAPTIONS = r.ACCESSIBILITY.createChild('/captions');
-    }
-    // </if>
-
     // <if expr="not chromeos_ash">
     r.SYSTEM = r.ADVANCED.createSection(
         '/system', 'system', loadTimeData.getString('systemPageTitle'));
diff --git a/chrome/browser/resources/settings/settings.ts b/chrome/browser/resources/settings/settings.ts
index f0ae67b..31b3656 100644
--- a/chrome/browser/resources/settings/settings.ts
+++ b/chrome/browser/resources/settings/settings.ts
@@ -68,7 +68,7 @@
 export {EDIT_STARTUP_URL_EVENT, SettingsStartupUrlEntryElement} from './on_startup_page/startup_url_entry.js';
 export {SettingsStartupUrlsPageElement} from './on_startup_page/startup_urls_page.js';
 export {StartupUrlsPageBrowserProxy, StartupUrlsPageBrowserProxyImpl} from './on_startup_page/startup_urls_page_browser_proxy.js';
-export {pageVisibility, PrivacyPageVisibility, setPageVisibilityForTesting} from './page_visibility.js';
+export {pageVisibility, PrivacyPageVisibility, resetPageVisibilityForTesting} from './page_visibility.js';
 // <if expr="chromeos_ash">
 export {AccountManagerBrowserProxy, AccountManagerBrowserProxyImpl} from './people_page/account_manager_browser_proxy.js';
 // </if>
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.ts b/chrome/browser/resources/settings/settings_main/settings_main.ts
index 813168cb..9095caca 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.ts
+++ b/chrome/browser/resources/settings/settings_main/settings_main.ts
@@ -107,7 +107,7 @@
   private showNoResultsFound_: boolean;
   private showingSubpage_: boolean;
   toolbarSpinnerActive: boolean;
-  pageVisibility: PageVisibility;
+  pageVisibility?: PageVisibility;
 
   /**
    * Updates the hidden state of the about and settings pages based on the
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.ts b/chrome/browser/resources/settings/settings_menu/settings_menu.ts
index 0148e1f..f349e2a4 100644
--- a/chrome/browser/resources/settings/settings_menu/settings_menu.ts
+++ b/chrome/browser/resources/settings/settings_menu/settings_menu.ts
@@ -61,7 +61,7 @@
     };
   }
 
-  pageVisibility: PageVisibility;
+  pageVisibility?: PageVisibility;
   private showAdvancedFeaturesMainControl_: boolean;
   private routes_: SettingsRoutes;
 
diff --git a/chrome/browser/resources/side_panel/customize_chrome/customize_toolbar/toolbar.html b/chrome/browser/resources/side_panel/customize_chrome/customize_toolbar/toolbar.html
index 38d7a7eb..0352ef7 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/customize_toolbar/toolbar.html
+++ b/chrome/browser/resources/side_panel/customize_chrome/customize_toolbar/toolbar.html
@@ -7,12 +7,11 @@
 </div>
 <hr class="sp-cards-separator">
 <div class="sp-card">
-  <sp-heading hide-back-button>
-    <h3 slot="heading">Choose your toolbar icons</h3>
-  </sp-heading>
-  <h4 class="choose-icons-row">Tools and Actions</h4>
-  <div class="toggle-container choose-icons-row">
-    <h4 id="actionLabel" class="toggle-title"></h4>
-    <cr-toggle id="actionToggle" @change="${this.onActionToggle_}"></cr-toggle>
-  </div>
+  ${this.actions_.map((action) => html`
+    <div class="toggle-container choose-icons-row">
+      <h4 class="toggle-title">${action.displayName}</h4>
+      <cr-toggle @change="${this.getActionToggleHandler_(action.id)}"
+          ?checked="${action.pinned}"></cr-toggle>
+    </div>
+  `)}
 </div>
diff --git a/chrome/browser/resources/side_panel/customize_chrome/customize_toolbar/toolbar.ts b/chrome/browser/resources/side_panel/customize_chrome/customize_toolbar/toolbar.ts
index baca0af9..6fd811b 100644
--- a/chrome/browser/resources/side_panel/customize_chrome/customize_toolbar/toolbar.ts
+++ b/chrome/browser/resources/side_panel/customize_chrome/customize_toolbar/toolbar.ts
@@ -4,11 +4,10 @@
 
 import 'chrome://customize-chrome-side-panel.top-chrome/shared/sp_heading.js';
 
-import type {CrToggleElement} from '//resources/cr_elements/cr_toggle/cr_toggle.js';
 import type {SpHeadingElement} from 'chrome://customize-chrome-side-panel.top-chrome/shared/sp_heading.js';
 import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js';
 
-import type {CustomizeToolbarHandlerInterface} from '../customize_toolbar.mojom-webui.js';
+import type {Action, CustomizeToolbarHandlerInterface} from '../customize_toolbar.mojom-webui.js';
 
 import {CustomizeToolbarApiProxy} from './customize_toolbar_api_proxy.js';
 import {getCss} from './toolbar.css.js';
@@ -17,8 +16,6 @@
 export interface ToolbarElement {
   $: {
     heading: SpHeadingElement,
-    actionToggle: CrToggleElement,
-    actionLabel: HTMLHeadingElement,
   };
 }
 
@@ -35,22 +32,23 @@
     return getHtml.bind(this)();
   }
 
+  static override get properties() {
+    return {
+      actions_: {type: Array},
+    };
+  }
+
   private handler_: CustomizeToolbarHandlerInterface;
   private listenerIds_: number[] = [];
 
-  private actionId_: number = -1;
+  protected actions_: Action[] = [];
 
   constructor() {
     super();
     this.handler_ = CustomizeToolbarApiProxy.getInstance().handler;
 
     this.handler_.listActions().then(({actions}) => {
-      this.actionId_ = actions[0]!.id;
-      this.$.actionLabel.innerText = actions[0]!.displayName;
-
-      this.handler_.getActionPinned(this.actionId_).then(({pinned}) => {
-        this.$.actionToggle.checked = pinned;
-      });
+      this.actions_ = actions;
     });
   }
 
@@ -78,16 +76,19 @@
     this.fire('back-click');
   }
 
-  protected onActionToggle_(event: CustomEvent<boolean>) {
-    this.handler_.pinAction(this.actionId_, event.detail);
+  protected getActionToggleHandler_(actionId: number) {
+    return (event: CustomEvent<boolean>) =>
+               this.handler_.pinAction(actionId, event.detail);
   }
 
   private setActionPinned_(actionId: number, pinned: boolean) {
-    if (actionId !== this.actionId_) {
-      return;
-    }
+    this.actions_ = this.actions_.map((action) => {
+      if (action.id === actionId) {
+        action.pinned = pinned;
+      }
 
-    this.$.actionToggle.checked = pinned;
+      return action;
+    });
   }
 }
 
diff --git a/chrome/browser/resources/side_panel/read_anything/app.ts b/chrome/browser/resources/side_panel/read_anything/app.ts
index 1b86385..144efa2 100644
--- a/chrome/browser/resources/side_panel/read_anything/app.ts
+++ b/chrome/browser/resources/side_panel/read_anything/app.ts
@@ -1364,15 +1364,31 @@
   }
 
   // TODO: Should this be merged with highlightAndPlayMessage?
-  highlightAndPlayInterruptedMessage() {
+  highlightAndPlayInterruptedMessage(): boolean {
     // getCurrentText gets the AX Node IDs of text that should be spoken and
     // highlighted.
     const axNodeIds: number[] = chrome.readingMode.getCurrentText();
 
+    // If there aren't any valid ax node ids returned by getCurrentText,
+    // speech should stop.
+    if (axNodeIds.length === 0) {
+      return false;
+    }
+
     const utteranceText = this.extractTextOf(axNodeIds);
     // Return if the utterance is empty or null.
     if (!utteranceText) {
-      return false;
+      // TODO(b/332694565): This fallback should never be needed, but it is.
+      // Investigate root cause of Read Aloud / Reading Mode mismatch.
+      chrome.readingMode.movePositionToNextGranularity();
+      return this.highlightAndPlayInterruptedMessage();
+    }
+
+    // The TTS engine may not like attempts to speak whitespace, so move to the
+    // next utterance.
+    if (utteranceText.trim().length === 0) {
+      chrome.readingMode.movePositionToNextGranularity();
+      return this.highlightAndPlayInterruptedMessage();
     }
 
     if (this.wordBoundaryState.mode === WordBoundaryMode.BOUNDARY_DETECTED) {
@@ -1380,7 +1396,14 @@
           this.wordBoundaryState.speechUtteranceStartIndex;
       this.wordBoundaryState.previouslySpokenIndex = 0;
       this.wordBoundaryState.speechUtteranceStartIndex = substringIndex;
-      this.playText(utteranceText.substring(substringIndex));
+      const utteranceTextForWordBoundary =
+          utteranceText.substring(substringIndex);
+      // Don't use the word boundary if it's going to cause a TTS engine issue.
+      if (utteranceTextForWordBoundary.trim().length === 0) {
+        this.playText(utteranceText);
+      } else {
+        this.playText(utteranceText.substring(substringIndex));
+      }
     } else {
       this.playText(utteranceText);
     }
@@ -1415,6 +1438,13 @@
       return this.highlightAndPlayMessage();
     }
 
+    // The TTS engine may not like attempts to speak whitespace, so move to the
+    // next utterance.
+    if (utteranceText.trim().length === 0) {
+      chrome.readingMode.movePositionToNextGranularity();
+      return this.highlightAndPlayMessage();
+    }
+
     this.playText(utteranceText);
     if (this.wordBoundaryState.mode ===
             WordBoundaryMode.BOUNDARIES_NOT_SUPPORTED ||
@@ -1910,8 +1940,10 @@
   restoreSettingsFromPrefs() {
     if (this.isReadAloudEnabled_) {
       this.updateSpeechRate_(chrome.readingMode.speechRate);
-      this.selectPreferredVoice_();
+      // We need to restore enabled languages prior to selecting the preferred
+      // voice to ensure we have the right voices available.
       this.restoreEnabledLanguagesFromPref_();
+      this.selectPreferredVoice_();
     }
     this.updateLineSpacing_(chrome.readingMode.lineSpacing);
     this.updateLetterSpacing_(chrome.readingMode.letterSpacing);
@@ -1997,8 +2029,9 @@
 
     const selectedVoice = this.getVoices()
                               .filter(voice => voice.name === storedVoiceName);
-
-    this.selectedVoice = selectedVoice ? selectedVoice[0] : this.defaultVoice();
+    this.selectedVoice = selectedVoice && (selectedVoice.length > 0) ?
+        selectedVoice[0] :
+        this.defaultVoice();
   }
 
   private onLineSpacingChange_(event: CustomEvent<{data: number}>) {
diff --git a/chrome/browser/resources/side_panel/read_anything/language_menu.html b/chrome/browser/resources/side_panel/read_anything/language_menu.html
index 3ee9714..e951946 100644
--- a/chrome/browser/resources/side_panel/read_anything/language_menu.html
+++ b/chrome/browser/resources/side_panel/read_anything/language_menu.html
@@ -6,6 +6,7 @@
       margin-right: var(--sp-body-padding);
       height: fit-content;
       background: var(--color-side-panel-content-background);
+      --scroll-border-color: var(--color-side-panel-dialog-divider);
     }
 
     cr-icon {
diff --git a/chrome/browser/resources/side_panel/read_anything/voice_selection_menu.html b/chrome/browser/resources/side_panel/read_anything/voice_selection_menu.html
index 0d81735..51f27e05 100644
--- a/chrome/browser/resources/side_panel/read_anything/voice_selection_menu.html
+++ b/chrome/browser/resources/side_panel/read_anything/voice_selection_menu.html
@@ -61,7 +61,7 @@
     visibility: hidden;
   }
   .menu-divider {
-    border-top: 1px solid var(--cr-active-background-color);
+    border-top: 1px solid var(--color-side-panel-dialog-divider);
   }
   .language-menu-button {
     max-width: 100%;
diff --git a/chrome/browser/resources/webauthn/gpm_incognito.json b/chrome/browser/resources/webauthn/gpm_incognito.json
new file mode 100644
index 0000000..0285c888
--- /dev/null
+++ b/chrome/browser/resources/webauthn/gpm_incognito.json
@@ -0,0 +1 @@
+{"v":"5.6.6","ip":0,"op":1,"fr":60,"w":408,"h":100,"layers":[{"ind":13667,"nm":"surface67753","ao":0,"ip":0,"op":60,"st":0,"ty":4,"ks":{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[133.33,133.33]},"sk":{"k":0},"sa":{"k":0}},"shapes":[{"ty":"gr","hd":false,"nm":"surface67753","it":[{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0.83,0.83],[0,1.21],[-0.83,0.83],[-1.21,0],[-0.79,-0.64],[-0.23,-1],[-0.21,0.06],[-0.25,0],[-0.23,-0.06],[-0.23,-0.08],[-0.79,0.62],[-1.02,0],[-0.83,-0.83],[0,-1.23],[0.86,-0.86],[1.21,0],[0.77,0.61],[0.27,1],[0.25,0.08],[0.25,0],[0.21,-0.08],[0.21,-0.12],[0.77,-0.61],[1.02,0]],"o":[[-1.21,0],[-0.83,-0.86],[0,-1.23],[0.83,-0.83],[1.02,0],[0.79,0.62],[0.21,-0.08],[0.21,-0.06],[0.25,0],[0.23,0.06],[0.21,-1],[0.79,-0.64],[1.21,0],[0.86,0.83],[0,1.21],[-0.83,0.83],[-1.02,0],[-0.75,-0.61],[-0.21,-0.12],[-0.23,-0.08],[-0.25,0],[-0.21,0.08],[-0.27,1],[-0.77,0.61],[0,0]],"v":[[147.31,47.56],[144.25,46.31],[143,43.22],[144.25,40.12],[147.31,38.88],[150.03,39.84],[151.56,42.28],[152.19,42.06],[152.88,41.97],[153.59,42.06],[154.28,42.28],[155.78,39.84],[158.5,38.88],[161.56,40.12],[162.84,43.22],[161.56,46.31],[158.5,47.56],[155.81,46.66],[154.28,44.25],[153.59,43.94],[152.88,43.81],[152.19,43.94],[151.56,44.25],[150,46.66],[147.31,47.56]],"c":true}}},{"ty":"sh","ks":{"k":{"i":[[0,0],[-0.5,0.5],[0,0.71],[0.5,0.5],[0.71,0],[0.5,-0.5],[0,-0.73],[-0.5,-0.5],[-0.71,0]],"o":[[0.73,0],[0.5,-0.5],[0,-0.73],[-0.5,-0.5],[-0.73,0],[-0.5,0.5],[0,0.71],[0.5,0.5],[0,0]],"v":[[147.31,45.78],[149.16,45.03],[149.91,43.22],[149.16,41.38],[147.34,40.62],[145.5,41.38],[144.75,43.22],[145.5,45.03],[147.31,45.78]],"c":true}}},{"ty":"sh","ks":{"k":{"i":[[0,0],[-0.5,0.5],[0,0.71],[0.5,0.5],[0.71,0],[0.5,-0.5],[0,-0.73],[-0.5,-0.5],[-0.73,0]],"o":[[0.71,0],[0.5,-0.5],[0,-0.73],[-0.5,-0.5],[-0.73,0],[-0.5,0.5],[0,0.71],[0.5,0.5],[0,0]],"v":[[158.5,45.78],[160.31,45.03],[161.06,43.22],[160.31,41.38],[158.5,40.62],[156.66,41.38],[155.91,43.22],[156.66,45.03],[158.5,45.78]],"c":true}}},{"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0],[-0.29,0.14],[-0.36,-0.08],[0,0],[0,0],[-0.29,-0.17],[-0.12,-0.36],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0.12,-0.36],[0.29,-0.17],[0,0],[0,0],[0.33,-0.08],[0.31,0.14],[0,0],[0,0],[0,0],[0,0]],"v":[[141.59,37.28],[141.59,35.44],[145.5,35.44],[148.78,26.78],[149.41,26.03],[150.38,25.91],[152.94,26.62],[155.5,25.91],[156.44,26.03],[157.09,26.78],[160.38,35.44],[164.41,35.44],[164.41,37.28]],"c":true}}},{"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[148.28,35],[157.59,35],[155.25,28.44],[152.94,29.09],[150.62,28.44]],"c":true}}},{"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[152.94,35],[157.59,35],[148.28,35]],"c":true}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.89,0.89,0.89,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,3],[0,-3]],"o":[[0,3],[0,-3],[0,0]],"v":[[225.75,47.25],[221.25,47.25],[225.75,47.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,3],[0,-3]],"o":[[0,3],[0,-3],[0,0]],"v":[[213.75,47.25],[209.25,47.25],[213.75,47.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,3],[0,-3]],"o":[[0,3],[0,-3],[0,0]],"v":[[207.75,47.25],[203.25,47.25],[207.75,47.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,3],[0,-3]],"o":[[0,3],[0,-3],[0,0]],"v":[[201.75,47.25],[197.25,47.25],[201.75,47.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,3],[0,-3]],"o":[[0,3],[0,-3],[0,0]],"v":[[77.25,28.5],[72.75,28.5],[77.25,28.5]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,3],[0,-3]],"o":[[0,3],[0,-3],[0,0]],"v":[[101.25,28.5],[96.75,28.5],[101.25,28.5]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,3],[0,-3]],"o":[[0,3],[0,-3],[0,0]],"v":[[95.25,28.5],[90.75,28.5],[95.25,28.5]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,3],[0,-3]],"o":[[0,3],[0,-3],[0,0]],"v":[[89.25,28.5],[84.75,28.5],[89.25,28.5]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[246,26.25],[244.5,26.25],[246,26.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[243,26.25],[241.5,26.25],[243,26.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[231,26.25],[229.5,26.25],[231,26.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[58.5,44.25],[57,44.25],[58.5,44.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[58.5,47.25],[57,47.25],[58.5,47.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[55.5,47.25],[54,47.25],[55.5,47.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[52.5,47.25],[51,47.25],[52.5,47.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[61.5,47.25],[60,47.25],[61.5,47.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[49.5,47.25],[48,47.25],[49.5,47.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[67.5,44.25],[66,44.25],[67.5,44.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[70.5,47.25],[69,47.25],[70.5,47.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[64.5,44.25],[63,44.25],[64.5,44.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[219,60],[217.5,60],[219,60]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[219,63],[217.5,63],[219,63]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[216,63],[214.5,63],[216,63]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[213,63],[211.5,63],[213,63]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[222,63],[220.5,63],[222,63]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[210,63],[208.5,63],[210,63]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[61.5,44.25],[60,44.25],[61.5,44.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[67.5,47.25],[66,47.25],[67.5,47.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[228,60],[226.5,60],[228,60]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[64.5,47.25],[63,47.25],[64.5,47.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[231,63],[229.5,63],[231,63]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[225,60],[223.5,60],[225,60]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[222,60],[220.5,60],[222,60]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[228,63],[226.5,63],[228,63]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[225,63],[223.5,63],[225,63]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[240,26.25],[238.5,26.25],[240,26.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[237,26.25],[235.5,26.25],[237,26.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[234,26.25],[232.5,26.25],[234,26.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[100.5,63],[99,63],[100.5,63]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[115.5,63],[114,63],[115.5,63]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[112.5,63],[111,63],[112.5,63]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[109.5,63],[108,63],[109.5,63]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[106.5,63],[105,63],[106.5,63]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[103.5,63],[102,63],[103.5,63]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[258,23.25],[256.5,23.25],[258,23.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[255,23.25],[253.5,23.25],[255,23.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[252,23.25],[250.5,23.25],[252,23.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[243,23.25],[241.5,23.25],[243,23.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[89.25,11.25],[87.75,11.25],[89.25,11.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[240,23.25],[238.5,23.25],[240,23.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[101.25,11.25],[99.75,11.25],[101.25,11.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[98.25,11.25],[96.75,11.25],[98.25,11.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[83.25,11.25],[81.75,11.25],[83.25,11.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[95.25,11.25],[93.75,11.25],[95.25,11.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[92.25,11.25],[90.75,11.25],[92.25,11.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[249,23.25],[247.5,23.25],[249,23.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[246,23.25],[244.5,23.25],[246,23.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[121.5,60],[120,60],[121.5,60]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[204,10.5],[202.5,10.5],[204,10.5]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[201,10.5],[199.5,10.5],[201,10.5]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[210,10.5],[208.5,10.5],[210,10.5]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[207,10.5],[205.5,10.5],[207,10.5]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[118.5,60],[117,60],[118.5,60]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[112.5,60],[111,60],[112.5,60]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[109.5,60],[108,60],[109.5,60]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[115.5,60],[114,60],[115.5,60]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[110.25,8.25],[108.75,8.25],[110.25,8.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[101.25,8.25],[99.75,8.25],[101.25,8.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[98.25,8.25],[96.75,8.25],[98.25,8.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[107.25,8.25],[105.75,8.25],[107.25,8.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"gr","hd":false,"it":[{"ty":"sh","ks":{"k":{"i":[[0,0],[0,1],[0,-1]],"o":[[0,1],[0,-1],[0,0]],"v":[[104.25,8.25],[102.75,8.25],[104.25,8.25]],"c":false}}},{"ty":"fl","o":{"k":100},"c":{"k":[0.37,0.39,0.41,1]}},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]},{"ty":"tr","o":{"k":100},"r":{"k":0},"p":{"k":[0,0]},"a":{"k":[0,0]},"s":{"k":[100,100]},"sk":{"k":0},"sa":{"k":0},"hd":false}]}]}],"meta":{"g":"LF SVG to Lottie"},"assets":[]}
\ No newline at end of file
diff --git a/chrome/browser/resources/webui_gallery/app.ts b/chrome/browser/resources/webui_gallery/app.ts
index 3a3dc44..50986544 100644
--- a/chrome/browser/resources/webui_gallery/app.ts
+++ b/chrome/browser/resources/webui_gallery/app.ts
@@ -6,7 +6,6 @@
 import '//resources/cr_elements/cr_toggle/cr_toggle.js';
 import '//resources/cr_elements/cr_nav_menu_item_style.css.js';
 import '//resources/cr_elements/cr_shared_style.css.js';
-import '//resources/polymer/v3_0/iron-location/iron-location.js';
 
 import {ColorChangeUpdater, COLORS_CSS_SELECTOR} from '//resources/cr_components/color_change_listener/colors_css_updater.js';
 import type {CrMenuSelector} from '//resources/cr_elements/cr_menu_selector/cr_menu_selector.js';
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 6ca4ed42..09c0a8e 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -734,6 +734,11 @@
   ]
 
   if (is_win || is_linux || is_mac) {
+    sources += [
+      "shortcuts/desktop_shortcuts_utils.cc",
+      "shortcuts/desktop_shortcuts_utils.h",
+    ]
+
     deps += [ "//chrome/browser/shortcuts:shortcuts" ]
   }
 
@@ -3081,8 +3086,8 @@
       "webui/ash/app_install/app_install_page_handler.h",
       "webui/ash/app_install/app_install_ui.cc",
       "webui/ash/app_install/app_install_ui.h",
-      "webui/ash/arc_graphics_tracing/arc_graphics_tracing_ui.cc",
-      "webui/ash/arc_graphics_tracing/arc_graphics_tracing_ui.h",
+      "webui/ash/arc_overview_tracing/arc_overview_tracing_ui.cc",
+      "webui/ash/arc_overview_tracing/arc_overview_tracing_ui.h",
       "webui/ash/arc_power_control/arc_power_control_handler.cc",
       "webui/ash/arc_power_control/arc_power_control_handler.h",
       "webui/ash/arc_power_control/arc_power_control_ui.cc",
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinator.java
index 5025504c..217a16b 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinator.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabStripTransitionCoordinator.java
@@ -392,7 +392,11 @@
         // Update the min size for the control container. This is needed one-layout-before browser
         // controls start changing its height, as it assumed a fixed size control container during
         // transition. See b/324178484.
-        int maxHeight = calculateTabStripHeight() + mToolbarLayout.getMeasuredHeight();
+        View toolbarHairline = controlContainerView().findViewById(R.id.toolbar_hairline);
+        int maxHeight =
+                calculateTabStripHeight()
+                        + mToolbarLayout.getMeasuredHeight()
+                        + toolbarHairline.getMeasuredHeight();
         controlContainerView().setMinimumHeight(maxHeight);
 
         // When transition kicked off by the BrowserControlsManager, the toolbar capture can be
@@ -619,8 +623,13 @@
         mHandler.post(
                 mCallbackController.makeCancelable(
                         () -> {
+                            View toolbarHairline =
+                                    controlContainerView().findViewById(R.id.toolbar_hairline);
                             controlContainerView()
-                                    .setMinimumHeight(mToolbarLayout.getHeight() + mTabStripHeight);
+                                    .setMinimumHeight(
+                                            mToolbarLayout.getHeight()
+                                                    + mTabStripHeight
+                                                    + toolbarHairline.getHeight());
                             ViewUtils.requestLayout(
                                     controlContainerView(),
                                     "TabStripTransitionCoordinator.remeasureControlContainer");
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index 3b992709..f828da4 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -136,6 +136,10 @@
 #include "ui/ozone/public/ozone_platform.h"
 #endif
 
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
+#include "chrome/browser/ui/shortcuts/desktop_shortcuts_utils.h"
+#endif  // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
+
 using WebExposedIsolationLevel = content::WebExposedIsolationLevel;
 
 namespace chrome {
@@ -1589,8 +1593,19 @@
 
   bool can_create_web_app = web_app::CanCreateWebApp(browser_);
   command_updater_.UpdateCommandEnabled(IDC_INSTALL_PWA, can_create_web_app);
+
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
+  if (base::FeatureList::IsEnabled(features::kShortcutsNotApps)) {
+    command_updater_.UpdateCommandEnabled(
+        IDC_CREATE_SHORTCUT, shortcuts::CanCreateDesktopShortcut(browser_));
+  } else {
+    command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUT,
+                                          can_create_web_app);
+  }
+#else
   command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUT,
                                         can_create_web_app);
+#endif  // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
 
   command_updater_.UpdateCommandEnabled(IDC_SEND_TAB_TO_SELF,
                                         CanSendTabToSelf(browser_));
diff --git a/chrome/browser/ui/browser_command_controller_browsertest.cc b/chrome/browser/ui/browser_command_controller_browsertest.cc
index aace30a..bf4c204 100644
--- a/chrome/browser/ui/browser_command_controller_browsertest.cc
+++ b/chrome/browser/ui/browser_command_controller_browsertest.cc
@@ -54,6 +54,10 @@
 #include "ui/aura/window.h"
 #endif
 
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
+#include "chrome/common/chrome_features.h"
+#endif  // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
+
 namespace chrome {
 
 class BrowserCommandControllerBrowserTest : public InProcessBrowserTest {
@@ -435,4 +439,28 @@
   EXPECT_TRUE(chrome::ExecuteCommand(browser(), IDC_SHOW_TRANSLATE));
 }
 
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
+class CreateShortcutBrowserCommandControllerNavTest
+    : public BrowserCommandControllerBrowserTest {
+ public:
+  CreateShortcutBrowserCommandControllerNavTest() = default;
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_{
+      features::kShortcutsNotApps};
+};
+
+IN_PROC_BROWSER_TEST_F(CreateShortcutBrowserCommandControllerNavTest,
+                       ErrorUrlDisabled) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  // This returns a 404 server error, and cannot be unit-tested, since a valid
+  // request is not obtained for the navigation entry being committed in
+  // unit-tests.
+  GURL error_url(embedded_test_server()->GetURL("example.com", "/abcdef/"));
+  EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), error_url));
+  EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_CREATE_SHORTCUT));
+}
+
+#endif  // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
+
 }  // namespace chrome
diff --git a/chrome/browser/ui/browser_command_controller_unittest.cc b/chrome/browser/ui/browser_command_controller_unittest.cc
index 6bfe6001..5916dd7b 100644
--- a/chrome/browser/ui/browser_command_controller_unittest.cc
+++ b/chrome/browser/ui/browser_command_controller_unittest.cc
@@ -569,3 +569,61 @@
                                                    TabCloseTypes::CLOSE_NONE);
   EXPECT_FALSE(command_controller.IsCommandEnabled(IDC_BOOKMARK_ALL_TABS));
 }
+
+#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
+class CreateShortcutBrowserCommandControllerTest
+    : public BrowserCommandControllerTest {
+ public:
+  CreateShortcutBrowserCommandControllerTest() = default;
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_{
+      features::kShortcutsNotApps};
+};
+
+TEST_F(CreateShortcutBrowserCommandControllerTest, BrowserNoSiteNotEnabled) {
+  EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_CREATE_SHORTCUT));
+}
+
+TEST_F(CreateShortcutBrowserCommandControllerTest, DisabledForOTRProfile) {
+  // Set up a profile with an off the record profile.
+  std::unique_ptr<TestingProfile> profile1 = TestingProfile::Builder().Build();
+  Profile* incognito_profile =
+      profile1->GetPrimaryOTRProfile(/*create_if_needed=*/true);
+  EXPECT_EQ(incognito_profile->GetOriginalProfile(), profile1.get());
+
+  // Create a new browser based on the off the record profile.
+  Browser::CreateParams profile_params(incognito_profile, true);
+  std::unique_ptr<Browser> incognito_browser =
+      CreateBrowserWithTestWindowForParams(profile_params);
+
+  EXPECT_FALSE(
+      chrome::IsCommandEnabled(incognito_browser.get(), IDC_CREATE_SHORTCUT));
+}
+
+TEST_F(CreateShortcutBrowserCommandControllerTest, DisabledForGuestProfile) {
+  TestingProfile* test_profile = browser()->profile()->AsTestingProfile();
+  EXPECT_TRUE(test_profile);
+  test_profile->SetGuestSession(true);
+
+  EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_CREATE_SHORTCUT));
+}
+
+TEST_F(CreateShortcutBrowserCommandControllerTest, DisabledForSystemProfile) {
+  TestingProfile* test_profile = browser()->profile()->AsTestingProfile();
+  EXPECT_TRUE(test_profile);
+
+  EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_CREATE_SHORTCUT));
+}
+
+TEST_F(CreateShortcutBrowserCommandControllerTest, EnabledValidUrl) {
+  AddTab(browser(), GURL("https://example.com"));
+  EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_CREATE_SHORTCUT));
+}
+
+TEST_F(CreateShortcutBrowserCommandControllerTest, InvalidSchemeDisabled) {
+  AddTab(browser(), GURL("abc://apps"));
+  EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_CREATE_SHORTCUT));
+}
+
+#endif  // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN)
diff --git a/chrome/browser/ui/lens/lens_overlay_controller.cc b/chrome/browser/ui/lens/lens_overlay_controller.cc
index 9a9b41dc7..89c3864b 100644
--- a/chrome/browser/ui/lens/lens_overlay_controller.cc
+++ b/chrome/browser/ui/lens/lens_overlay_controller.cc
@@ -229,6 +229,13 @@
   return phys_mem_mb > lens::features::GetLensOverlayMinRamMb();
 }
 
+void LensOverlayController::ShowUIWithPendingRegion(
+    InvocationSource invocation_source,
+    lens::mojom::CenterRotatedBoxPtr region) {
+  pending_region_ = std::move(region);
+  ShowUI(invocation_source);
+}
+
 void LensOverlayController::ShowUI(InvocationSource invocation_source) {
   // If UI is already showing or in the process of showing, do nothing.
   if (state_ != State::kOff) {
@@ -383,6 +390,9 @@
         initialization_data_->current_screenshot_,
         initialization_data_->page_url_, initialization_data_->page_title_);
   }
+  if (pending_region_) {
+    IssueLensRequest(std::move(pending_region_));
+  }
 }
 
 void LensOverlayController::BindSidePanel(
@@ -797,6 +807,7 @@
   pending_text_query_.reset();
   pending_thumbnail_uri_.reset();
   thumbnail_uri_.clear();
+  pending_region_.reset();
 
   state_ = State::kOff;
 
@@ -812,6 +823,8 @@
 
 void LensOverlayController::InitializeOverlayUI(
     const OverlayInitializationData& init_data) {
+  // This should only contain LensPage mojo calls and should not affect
+  // `state_`.
   CHECK(page_);
   page_->ScreenshotDataUriReceived(init_data.current_screenshot_data_uri_);
   if (!init_data.objects_.empty()) {
@@ -820,6 +833,9 @@
   if (init_data.text_) {
     SendText(init_data.text_->Clone());
   }
+  if (pending_region_) {
+    page_->SetPostRegionSelection(pending_region_->Clone());
+  }
 }
 
 views::Widget::InitParams LensOverlayController::CreateWidgetInitParams() {
@@ -1040,6 +1056,14 @@
   CloseUIAsync(DismissalSource::kOverlayBackgroundClick);
 }
 
+void LensOverlayController::CloseRequestedByOverlayEscapeKeyPress() {
+  CloseUIAsync(DismissalSource::kEscapeKeyPress);
+}
+
+void LensOverlayController::CloseRequestedBySidePanelEscapeKeyPress() {
+  CloseUIAsync(DismissalSource::kEscapeKeyPress);
+}
+
 void LensOverlayController::FeedbackRequestedByOverlay() {
   Browser* tab_browser = chrome::FindBrowserWithTab(tab_->GetContents());
   if (!tab_browser) {
diff --git a/chrome/browser/ui/lens/lens_overlay_controller.h b/chrome/browser/ui/lens/lens_overlay_controller.h
index c7c41d2..25bc9d5 100644
--- a/chrome/browser/ui/lens/lens_overlay_controller.h
+++ b/chrome/browser/ui/lens/lens_overlay_controller.h
@@ -130,6 +130,10 @@
   };
   // LINT.ThenChange(//tools/metrics/histograms/metadata/others/enums.xml:LensOverlayInvocationSource)
 
+  // Sets a region to search after the overlay loads, then calls ShowUI().
+  void ShowUIWithPendingRegion(InvocationSource invocation_source,
+                               lens::mojom::CenterRotatedBoxPtr region);
+
   // This is entry point for showing the overlay UI. This has no effect if state
   // is not kOff. This has no effect if the tab is not in the foreground. If the
   // overlay is successfully invoked, then the value of `invocation_source` will
@@ -174,7 +178,10 @@
     // Encoding the screenshot failed.
     kErrorScreenshotEncodingFailed = 8,
 
-    kMaxValue = kErrorScreenshotEncodingFailed
+    // User pressed the escape key.
+    kEscapeKeyPress = 9,
+
+    kMaxValue = kEscapeKeyPress
   };
   // LINT.ThenChange(//tools/metrics/histograms/metadata/others/enums.xml:LensOverlayDismissalSource)
 
@@ -517,6 +524,7 @@
   void AddBackgroundBlur() override;
   void CloseRequestedByOverlayCloseButton() override;
   void CloseRequestedByOverlayBackgroundClick() override;
+  void CloseRequestedByOverlayEscapeKeyPress() override;
   void FeedbackRequestedByOverlay() override;
   // TODO: rename this to IssueRegionSearchRequest.
   void IssueLensRequest(lens::mojom::CenterRotatedBoxPtr region) override;
@@ -524,6 +532,8 @@
   void IssueTextSelectionRequest(const std::string& text_query,
                                  int selection_start_index,
                                  int selection_end_index) override;
+  // lens::mojom::LensSidePanelPageHandler overrides.
+  void CloseRequestedBySidePanelEscapeKeyPress() override;
 
   // Closes search bubble.
   void CloseSearchBubble() override;
@@ -595,6 +605,9 @@
   // side panel is not bound at the time of a region request.
   std::optional<std::string> pending_thumbnail_uri_ = std::nullopt;
 
+  // Pending region to search after the overlay loads.
+  lens::mojom::CenterRotatedBoxPtr pending_region_;
+
   // Thumbnail URI referencing the data defined by the user image selection on
   // the overlay. If the user hasn't made any selection or has made a text
   // selection this will contain an empty string. Returned by GetThumbnail().
diff --git a/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc b/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc
index f22eae7..c13fa0c 100644
--- a/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc
+++ b/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc
@@ -141,6 +141,11 @@
     lens::mojom::OverlayObject::New("unique_id", kTestGeometry->Clone());
 const lens::mojom::TextPtr kTestText =
     lens::mojom::Text::New(lens::mojom::TextLayout::New(), "es");
+const lens::mojom::CenterRotatedBoxPtr kTestRegion =
+    lens::mojom::CenterRotatedBox::New(
+        gfx::RectF(0.1, 0.1, 0.8, 0.8),
+        0.1,
+        lens::mojom::CenterRotatedBox_CoordinateType::kNormalized);
 
 class LensOverlayPageFake : public lens::mojom::LensPage {
  public:
@@ -712,6 +717,38 @@
   EXPECT_TRUE(fake_controller->fake_overlay_page_.did_notify_results_opened_);
 }
 
+IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
+                       ShowSidePanelWithPendingRegion) {
+  WaitForPaint();
+
+  // State should start in off.
+  auto* controller = browser()
+                         ->tab_strip_model()
+                         ->GetActiveTab()
+                         ->tab_features()
+                         ->lens_overlay_controller();
+  ASSERT_EQ(controller->state(), State::kOff);
+
+  // Showing UI should change the state to screenshot and eventually to overlay.
+  controller->ShowUIWithPendingRegion(InvocationSource::kAppMenu,
+                                      kTestRegion->Clone());
+  ASSERT_EQ(controller->state(), State::kScreenshot);
+  ASSERT_TRUE(base::test::RunUntil(
+      [&]() { return controller->state() == State::kOverlayAndResults; }));
+  auto* coordinator =
+      SidePanelUtil::GetSidePanelCoordinatorForBrowser(browser());
+  // Expect the Lens Overlay results panel to open.
+  ASSERT_TRUE(coordinator->IsSidePanelShowing());
+  EXPECT_EQ(coordinator->GetCurrentEntryId(),
+            SidePanelEntry::Id::kLensOverlayResults);
+
+  // Verify region was passed to WebUI.
+  auto* fake_controller = static_cast<LensOverlayControllerFake*>(controller);
+  ASSERT_TRUE(fake_controller);
+  EXPECT_EQ(kTestRegion,
+            fake_controller->fake_overlay_page_.post_region_selection_);
+}
+
 IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest, CloseSidePanel) {
   WaitForPaint();
 
diff --git a/chrome/browser/ui/lens/lens_overlay_controller_interactive_uitest.cc b/chrome/browser/ui/lens/lens_overlay_controller_interactive_uitest.cc
index 989bb31..c11a601 100644
--- a/chrome/browser/ui/lens/lens_overlay_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/lens/lens_overlay_controller_interactive_uitest.cc
@@ -29,6 +29,7 @@
 namespace {
 
 constexpr char kDocumentWithNamedElement[] = "/select.html";
+constexpr char kDocumentWithImage[] = "/test_visual.html";
 
 class LensOverlayControllerCUJTest : public InteractiveFeaturePromoTest {
  public:
@@ -99,6 +100,38 @@
         SelectMenuItem(RenderViewContextMenu::kRegionSearchItem));
   }
 
+  InteractiveTestApi::MultiStep OpenLensOverlayFromImage() {
+    DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kActiveTab);
+    const GURL url = embedded_test_server()->GetURL(kDocumentWithImage);
+
+    // In kDocumentWithImage.
+    const DeepQuery kPathToImg{
+        "img",
+    };
+
+    DEFINE_LOCAL_STATE_IDENTIFIER_VALUE(ui::test::PollingStateObserver<bool>,
+                                        kFirstPaintState);
+    return Steps(
+        InstrumentTab(kActiveTab), NavigateWebContents(kActiveTab, url),
+        EnsurePresent(kActiveTab, kPathToImg),
+        // TODO(https://crbug.com/331859922): This functionality should be built
+        // into test framework.
+        PollState(kFirstPaintState,
+                  [this]() {
+                    return browser()
+                        ->tab_strip_model()
+                        ->GetActiveTab()
+                        ->contents()
+                        ->CompletedFirstVisuallyNonEmptyPaint();
+                  }),
+        WaitForState(kFirstPaintState, true),
+        MoveMouseTo(kActiveTab, kPathToImg), ClickMouse(ui_controls::RIGHT),
+        WaitForShow(RenderViewContextMenu::kSearchForImageItem),
+        FlushEvents(),  // Required to fully render the menu before selection.
+
+        SelectMenuItem(RenderViewContextMenu::kSearchForImageItem));
+  }
+
  private:
   base::test::ScopedFeatureList feature_list_{lens::features::kLensOverlay};
 };
@@ -146,6 +179,45 @@
 // This tests the following CUJ:
 //  (1) User navigates to a website.
 //  (2) User opens lens overlay.
+//  (3) User presses the escape key to close lens overlay.
+// TOOD(b/340343342): Reenable on windows.
+#if BUILDFLAG(IS_WIN)
+#define MAYBE_EscapeKeyClose DISABLED_EscapeKeyClose
+#else
+#define MAYBE_EscapeKeyClose EscapeKeyClose
+#endif
+IN_PROC_BROWSER_TEST_F(LensOverlayControllerCUJTest, MAYBE_EscapeKeyClose) {
+  WaitForTemplateURLServiceToLoad();
+  DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kOverlayId);
+
+  const GURL url = embedded_test_server()->GetURL(kDocumentWithNamedElement);
+
+  // In kDocumentWithNamedElement.
+  const DeepQuery kPathToBody{
+      "body",
+  };
+
+  const ui::Accelerator escape_key(ui::VKEY_ESCAPE, ui::EF_NONE);
+
+  RunTestSequence(
+      OpenLensOverlay(),
+
+      // The overlay controller is an independent floating widget associated
+      // with a tab rather than a browser window, so by convention gets its own
+      // element context.
+      InAnyContext(Steps(InstrumentNonTabWebView(
+                             kOverlayId, LensOverlayController::kOverlayId),
+                         WaitForWebContentsReady(
+                             kOverlayId, GURL("chrome-untrusted://lens")))),
+      // Wait for the webview to finish loading to prevent re-entrancy.
+      InSameContext(Steps(FlushEvents(),
+                          SendAccelerator(kOverlayId, escape_key),
+                          WaitForHide(kOverlayId))));
+}
+
+// This tests the following CUJ:
+//  (1) User navigates to a website.
+//  (2) User opens lens overlay.
 //  (3) User drags to select a manual region on the overlay.
 //  (4) Side panel opens with results.
 IN_PROC_BROWSER_TEST_F(LensOverlayControllerCUJTest, SelectManualRegion) {
@@ -201,6 +273,46 @@
           EnsurePresent(kOverlaySidePanelWebViewId, kPathToResultsFrame))));
 }
 
+// This tests the following CUJ:
+//  (1) User navigates to a website.
+//  (2) User right-clicks an image and opens lens overlay.
+//  (3) Side panel opens with results.
+IN_PROC_BROWSER_TEST_F(LensOverlayControllerCUJTest, SearchForImage) {
+  WaitForTemplateURLServiceToLoad();
+  DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kOverlayId);
+  DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kOverlaySidePanelWebViewId);
+
+  const DeepQuery kPathToRegionSelection{
+      "lens-overlay-app",
+      "lens-selection-overlay",
+      "#regionSelectionLayer",
+  };
+  const DeepQuery kPathToResultsFrame{
+      "lens-side-panel-app",
+      "#results",
+  };
+
+  RunTestSequence(
+      OpenLensOverlayFromImage(),
+
+      // The overlay controller is an independent floating widget
+      // associated with a tab rather than a browser window, so by
+      // convention gets its own element context.
+      InAnyContext(Steps(InstrumentNonTabWebView(
+                             kOverlayId, LensOverlayController::kOverlayId),
+                         WaitForWebContentsReady(
+                             kOverlayId, GURL("chrome-untrusted://lens")))),
+
+      // The side panel should open with the results frame.
+      InAnyContext(Steps(
+          FlushEvents(),
+          InstrumentNonTabWebView(
+              kOverlaySidePanelWebViewId,
+              LensOverlayController::kOverlaySidePanelWebViewId),
+          FlushEvents(),
+          EnsurePresent(kOverlaySidePanelWebViewId, kPathToResultsFrame))));
+}
+
 class LensOverlayControllerPromoTest : public LensOverlayControllerCUJTest {
  public:
   LensOverlayControllerPromoTest()
diff --git a/chrome/browser/ui/lens/lens_overlay_image_helper.cc b/chrome/browser/ui/lens/lens_overlay_image_helper.cc
index afa06eb..557e89c 100644
--- a/chrome/browser/ui/lens/lens_overlay_image_helper.cc
+++ b/chrome/browser/ui/lens/lens_overlay_image_helper.cc
@@ -160,4 +160,40 @@
   return image_crop;
 }
 
+lens::mojom::CenterRotatedBoxPtr GetCenterRotatedBoxFromViewAndImageBounds(
+    const gfx::Rect& view_bounds,
+    const gfx::Rect& image_bounds) {
+  float left = static_cast<float>(image_bounds.x()) / view_bounds.width();
+  float right = static_cast<float>(image_bounds.x() + image_bounds.width()) /
+                view_bounds.width();
+  float top = static_cast<float>(image_bounds.y()) / view_bounds.height();
+  float bottom = static_cast<float>(image_bounds.y() + image_bounds.height()) /
+                 view_bounds.height();
+
+  // Clip to remain inside view bounds.
+  if (left < 0) {
+    left = 0;
+  }
+  if (right > 1) {
+    right = 1;
+  }
+  if (top < 0) {
+    top = 0;
+  }
+  if (bottom > 1) {
+    bottom = 1;
+  }
+
+  float width = right - left;
+  float height = bottom - top;
+  float x = (left + right) / 2;
+  float y = (top + bottom) / 2;
+
+  auto region = lens::mojom::CenterRotatedBox::New();
+  region->box = gfx::RectF(x, y, width, height);
+  region->coordinate_type =
+      lens::mojom::CenterRotatedBox_CoordinateType::kNormalized;
+  return region;
+}
+
 }  // namespace lens
diff --git a/chrome/browser/ui/lens/lens_overlay_image_helper.h b/chrome/browser/ui/lens/lens_overlay_image_helper.h
index 5053a1d..8b49ec63 100644
--- a/chrome/browser/ui/lens/lens_overlay_image_helper.h
+++ b/chrome/browser/ui/lens/lens_overlay_image_helper.h
@@ -33,6 +33,12 @@
 std::optional<lens::ImageCrop> DownscaleAndEncodeBitmapRegionIfNeeded(
     const SkBitmap& image,
     lens::mojom::CenterRotatedBoxPtr region);
+
+// Returns a normalized bounding box from the given view and image bounds,
+// clipping if the image bounds go outside the view bounds.
+lens::mojom::CenterRotatedBoxPtr GetCenterRotatedBoxFromViewAndImageBounds(
+    const gfx::Rect& view_bounds,
+    const gfx::Rect& image_bounds);
 }  // namespace lens
 
 #endif  // CHROME_BROWSER_UI_LENS_LENS_OVERLAY_IMAGE_HELPER_H_
diff --git a/chrome/browser/ui/lens/lens_overlay_image_helper_unittest.cc b/chrome/browser/ui/lens/lens_overlay_image_helper_unittest.cc
index 64d49da..2f805370 100644
--- a/chrome/browser/ui/lens/lens_overlay_image_helper_unittest.cc
+++ b/chrome/browser/ui/lens/lens_overlay_image_helper_unittest.cc
@@ -315,4 +315,35 @@
   ASSERT_EQ(expected_output, image_crop->image().image_content());
 }
 
+TEST_F(LensOverlayImageHelperTest, GetCenterRotatedBoxFromViewAndImageBounds) {
+  gfx::Rect view_bounds(10, 20, 200, 100);
+  gfx::Rect image_bounds(125, 25, 50, 50);
+
+  auto result =
+      GetCenterRotatedBoxFromViewAndImageBounds(view_bounds, image_bounds);
+
+  ASSERT_EQ(0.75, result->box.x());
+  ASSERT_EQ(0.5, result->box.y());
+  ASSERT_EQ(0.25, result->box.width());
+  ASSERT_EQ(0.5, result->box.height());
+  ASSERT_EQ(lens::mojom::CenterRotatedBox_CoordinateType::kNormalized,
+            result->coordinate_type);
+}
+
+TEST_F(LensOverlayImageHelperTest,
+       GetCenterRotatedBoxFromViewAndImageBoundsClipsWhenImageOutOfView) {
+  gfx::Rect view_bounds(10, 20, 200, 100);
+  gfx::Rect image_bounds(-50, 50, 150, 100);
+
+  auto result =
+      GetCenterRotatedBoxFromViewAndImageBounds(view_bounds, image_bounds);
+
+  ASSERT_EQ(0.25, result->box.x());
+  ASSERT_EQ(0.75, result->box.y());
+  ASSERT_EQ(0.5, result->box.width());
+  ASSERT_EQ(0.5, result->box.height());
+  ASSERT_EQ(lens::mojom::CenterRotatedBox_CoordinateType::kNormalized,
+            result->coordinate_type);
+}
+
 }  // namespace lens
diff --git a/chrome/browser/ui/quick_answers/ui/quick_answers_view.cc b/chrome/browser/ui/quick_answers/ui/quick_answers_view.cc
index c7f76991..5a56d94 100644
--- a/chrome/browser/ui/quick_answers/ui/quick_answers_view.cc
+++ b/chrome/browser/ui/quick_answers/ui/quick_answers_view.cc
@@ -88,10 +88,6 @@
 constexpr auto kResultTypeIconContainerInsets = gfx::Insets::TLBR(8, 12, 4, 8);
 constexpr auto kResultTypeIconCircleInsets = gfx::Insets::TLBR(4, 4, 4, 4);
 
-// Info icon.
-constexpr int kDogfoodIconSizeDip = 20;
-constexpr int kDogfoodIconBorderDip = 8;
-
 // Spacing between lines in the main view.
 constexpr int kLineSpacingDip = 4;
 constexpr int kDefaultLineHeightDip = 20;
@@ -109,10 +105,6 @@
 constexpr int kPhoneticsAudioButtonSizeDip = 14;
 constexpr int kPhoneticsAudioButtonBorderDip = 3;
 
-// ReportQueryView.
-constexpr int kReportQueryButtonMarginDip = 16;
-constexpr int kReportQueryViewFontSize = 12;
-
 // Expansion affordance indicator.
 constexpr int kExpansionIndicatorLabelFontSize = 12;
 constexpr int kExpansionIndicatorIconSizeDip = 12;
@@ -120,92 +112,16 @@
 constexpr int kExpansionIndicatorSizeDip = 72;
 constexpr auto kExpansionIndicatorViewInsets = gfx::Insets::TLBR(4, 8, 16, 12);
 
-gfx::Insets GetContentViewInsets() {
-  if (chromeos::features::IsQuickAnswersRichCardEnabled()) {
-    return kRichCardRedesignContentViewInsets;
-  }
-  return kContentViewInsets;
+gfx::Insets GetContentViewInsets(bool is_rich_answers_enabled) {
+  return is_rich_answers_enabled ? kRichCardRedesignContentViewInsets
+                                 : kContentViewInsets;
 }
 
-class ReportQueryView : public views::Button {
-  METADATA_HEADER(ReportQueryView, views::Button)
-
- public:
-  static constexpr size_t kMaximumHeight = kDogfoodIconBorderDip * 2;
-
-  explicit ReportQueryView(PressedCallback callback)
-      : Button(std::move(callback)) {
-    SetAccessibleName(l10n_util::GetStringUTF16(
-        IDS_QUICK_ANSWERS_VIEW_REPORT_QUERY_REPORT_LABEL));
-
-    SetBackground(views::CreateThemedSolidBackground(
-        kColorQuickAnswersReportQueryButtonBackground));
-
-    auto* layout = SetLayoutManager(std::make_unique<views::FlexLayout>());
-    layout->SetOrientation(views::LayoutOrientation::kHorizontal)
-        .SetMainAxisAlignment(views::LayoutAlignment::kStart);
-
-    dogfood_icon_ = AddChildView(std::make_unique<views::ImageView>());
-    dogfood_icon_->SetBorder(views::CreateEmptyBorder(kDogfoodIconBorderDip));
-
-    description_label_ = AddChildView(std::make_unique<Label>(
-        l10n_util::GetStringUTF16(
-            IDS_QUICK_ANSWERS_VIEW_REPORT_QUERY_INTERNAL_LABEL),
-        Label::CustomFont{gfx::FontList(
-            {quick_answers::kGoogleSansFont}, gfx::Font::ITALIC,
-            kReportQueryViewFontSize, gfx::Font::Weight::NORMAL)}));
-    description_label_->SetHorizontalAlignment(
-        gfx::HorizontalAlignment::ALIGN_LEFT);
-
-    report_label_ = AddChildView(std::make_unique<Label>(
-        l10n_util::GetStringUTF16(
-            IDS_QUICK_ANSWERS_VIEW_REPORT_QUERY_REPORT_LABEL),
-        Label::CustomFont{gfx::FontList(
-            {quick_answers::kGoogleSansFont}, gfx::Font::NORMAL,
-            kReportQueryViewFontSize, gfx::Font::Weight::MEDIUM)}));
-    report_label_->SetProperty(
-        views::kFlexBehaviorKey,
-        views::FlexSpecification(views::MinimumFlexSizeRule::kPreferred,
-                                 views::MaximumFlexSizeRule::kUnbounded)
-            .WithAlignment(views::LayoutAlignment::kEnd));
-    report_label_->SetProperty(
-        views::kMarginsKey,
-        gfx::Insets::TLBR(0, 0, 0, kReportQueryButtonMarginDip));
-  }
-
-  // Disallow copy and assign.
-  ReportQueryView(const ReportQueryView&) = delete;
-  ReportQueryView& operator=(const ReportQueryView&) = delete;
-
-  ~ReportQueryView() override = default;
-
-  // views::View:
-  void OnThemeChanged() override {
-    views::Button::OnThemeChanged();
-
-    dogfood_icon_->SetImage(ui::ImageModel::FromVectorIcon(
-        vector_icons::kDogfoodIcon,
-        kColorQuickAnswersReportQueryButtonForeground, kDogfoodIconSizeDip));
-    description_label_->SetEnabledColorId(
-        kColorQuickAnswersReportQueryButtonForeground);
-    report_label_->SetEnabledColorId(
-        kColorQuickAnswersReportQueryButtonForeground);
-  }
-
- private:
-  raw_ptr<views::ImageView> dogfood_icon_ = nullptr;
-  raw_ptr<views::Label> description_label_ = nullptr;
-  raw_ptr<views::Label> report_label_ = nullptr;
-};
-
-BEGIN_METADATA(ReportQueryView)
-END_METADATA
-
-// Maximum height QuickAnswersView can expand to.
-int MaximumViewHeight(bool is_internal) {
-  return kMainViewInsets.height() + GetContentViewInsets().height() +
-         kMaxRows * kDefaultLineHeightDip + (kMaxRows - 1) * kLineSpacingDip +
-         (is_internal ? ReportQueryView::kMaximumHeight : 0);
+// TODO(b/335701090): make this constexpr once rich answers enabled by default.
+int GetMaximumViewHeight(bool is_rich_answers_enabled) {
+  return kMainViewInsets.height() +
+         GetContentViewInsets(is_rich_answers_enabled).height() +
+         kMaxRows * kDefaultLineHeightDip + (kMaxRows - 1) * kLineSpacingDip;
 }
 
 // `MaybeASingleQuickAnswersTextLabel` returns a pointer of
@@ -266,6 +182,9 @@
       controller_(std::move(controller)),
       title_(title),
       is_internal_(is_internal),
+      is_rich_answers_enabled_(
+          chromeos::features::IsQuickAnswersRichCardEnabled()),
+      maximum_view_height_(GetMaximumViewHeight(is_rich_answers_enabled_)),
       focus_search_(std::make_unique<chromeos::editor_menu::FocusSearch>(
           this,
           base::BindRepeating(&QuickAnswersView::GetFocusableViews,
@@ -274,58 +193,45 @@
       views::CreateThemedSolidBackground(ui::kColorPrimaryBackground));
   SetUseDefaultFillLayout(true);
 
-  bool is_rich_answers_enabled =
-      chromeos::features::IsQuickAnswersRichCardEnabled();
-
   std::unique_ptr<views::FlexLayout> main_view_layout =
       std::make_unique<views::FlexLayout>();
   main_view_layout->SetOrientation(views::LayoutOrientation::kHorizontal)
       .SetInteriorMargin(kMainViewInsets);
 
-  QuickAnswersStageButton* main_view;
   views::View* content_view;
   views::ImageView* result_type_icon;
 
-  base_view_.SetView(AddChildView(
-      views::Builder<views::BoxLayoutView>()
-          .SetOrientation(views::LayoutOrientation::kVertical)
-          .SetCrossAxisAlignment(views::LayoutAlignment::kStretch)
+  main_view_.SetView(AddChildView(
+      views::Builder<QuickAnswersStageButton>()
+          .SetCallback(base::BindRepeating(
+              &QuickAnswersView::SendQuickAnswersQuery, base::Unretained(this)))
+          .SetAccessibleName(
+              l10n_util::GetStringUTF16(IDS_QUICK_ANSWERS_VIEW_A11Y_NAME_TEXT))
+          .SetLayoutManager(std::move(main_view_layout))
+          .AddChild(is_rich_answers_enabled_
+                        ? DefaultResultTypeIconBuilder(&result_type_icon)
+                        : GoogleIconBuilder())
           .AddChild(
-              views::Builder<QuickAnswersStageButton>()
-                  .SetCallback(base::BindRepeating(
-                      &QuickAnswersView::SendQuickAnswersQuery,
-                      base::Unretained(this)))
-                  .SetAccessibleName(l10n_util::GetStringUTF16(
-                      IDS_QUICK_ANSWERS_VIEW_A11Y_NAME_TEXT))
-                  .SetLayoutManager(std::move(main_view_layout))
-                  .CopyAddressTo(&main_view)
-                  .AddChild(
-                      is_rich_answers_enabled
-                          ? DefaultResultTypeIconBuilder(&result_type_icon)
-                          : GoogleIconBuilder())
-                  .AddChild(
-                      views::Builder<LoadingView>()
-                          .SetFirstLineText(base::UTF8ToUTF16(title_))
-                          .SetInteriorMargin(GetContentViewInsets())
-                          .SetProperty(
-                              views::kFlexBehaviorKey,
-                              views::FlexSpecification(
-                                  views::MinimumFlexSizeRule::kScaleToZero,
-                                  views::MaximumFlexSizeRule::kPreferred))
-                          .CopyAddressTo(&content_view)))
+              views::Builder<LoadingView>()
+                  .SetFirstLineText(base::UTF8ToUTF16(title_))
+                  .SetInteriorMargin(
+                      GetContentViewInsets(is_rich_answers_enabled_))
+                  .SetProperty(views::kFlexBehaviorKey,
+                               views::FlexSpecification(
+                                   views::MinimumFlexSizeRule::kScaleToZero,
+                                   views::MaximumFlexSizeRule::kPreferred))
+                  .CopyAddressTo(&content_view))
           .Build()));
 
-  CHECK(main_view);
-  main_view_.SetView(main_view);
   CHECK(content_view);
   content_view_.SetView(content_view);
 
-  if (is_rich_answers_enabled) {
+  if (is_rich_answers_enabled_) {
     CHECK(result_type_icon);
     result_type_icon_ = result_type_icon;
   }
 
-  if (!is_rich_answers_enabled) {
+  if (!is_rich_answers_enabled_) {
     // Add util buttons in the top-right corner.
     AddFrameButtons();
   }
@@ -407,7 +313,7 @@
   // in `ReadWriteCardsUiController`. We need to reserve space at
   // the top since the view might expand for two-line answers.
   // Note that the width will not be used in the calculation.
-  return gfx::Size(0, MaximumViewHeight(is_internal_));
+  return gfx::Size(0, maximum_view_height_);
 }
 
 void QuickAnswersView::UpdateBoundsForQuickAnswers() {
@@ -508,7 +414,7 @@
 bool QuickAnswersView::ShouldAddPhoneticsAudioButton(ResultType result_type,
                                                      GURL phonetics_audio,
                                                      bool tts_audio_enabled) {
-  if (chromeos::features::IsQuickAnswersRichCardEnabled()) {
+  if (is_rich_answers_enabled_) {
     return false;
   }
 
@@ -548,13 +454,13 @@
 
 int QuickAnswersView::GetLabelWidth(bool is_title) {
   int label_width = context_menu_bounds().width() - kMainViewInsets.width() -
-                    GetContentViewInsets().width() - kGoogleIconInsets.width() -
-                    kGoogleIconSizeDip;
+                    GetContentViewInsets(is_rich_answers_enabled_).width() -
+                    kGoogleIconInsets.width() - kGoogleIconSizeDip;
 
   // If the rich card feature flag is enabled, leave additional space
   // for the expansion affordance indicator.
   // This only applies to non-title text labels.
-  if (chromeos::features::IsQuickAnswersRichCardEnabled() && !is_title) {
+  if (is_rich_answers_enabled_ && !is_title) {
     return label_width - kExpansionIndicatorSizeDip;
   }
 
@@ -584,10 +490,6 @@
   bool pane_already_had_focus = HasFocusInside();
   ResetContentView();
 
-  if (report_query_view_) {
-    RemoveChildViewT(report_query_view_.view());
-  }
-
   // Update the icon representing the quick answers result type if it's shown.
   // In the case that the rich card feature is not enabled, this icon is null
   // and the google icon is being shown instead.
@@ -642,15 +544,7 @@
         l10n_util::GetStringUTF16(IDS_QUICK_ANSWERS_VIEW_A11Y_INFO_ALERT_TEXT));
   }
 
-  if (quick_answer.result_type == ResultType::kNoResult && is_internal_) {
-    CHECK(base_view_.view());
-    report_query_view_.SetView(base_view_.view()->AddChildView(
-        std::make_unique<ReportQueryView>(base::BindRepeating(
-            &QuickAnswersUiController::OnReportQueryButtonPressed,
-            controller_))));
-  }
-
-  if (chromeos::features::IsQuickAnswersRichCardEnabled() &&
+  if (is_rich_answers_enabled_ &&
       quick_answer.result_type != ResultType::kNoResult) {
     // Show the expansion affordance indicator if rich card view is available.
     auto* expansion_indicator_view =
@@ -700,9 +594,6 @@
   if (retry_label_ && retry_label_->GetVisible()) {
     focusable_views.push_back(retry_label_);
   }
-  if (report_query_view_ && report_query_view_.view()->GetVisible()) {
-    focusable_views.push_back(report_query_view_.view());
-  }
   return focusable_views;
 }
 
diff --git a/chrome/browser/ui/quick_answers/ui/quick_answers_view.h b/chrome/browser/ui/quick_answers/ui/quick_answers_view.h
index f7a5663..e0e910a 100644
--- a/chrome/browser/ui/quick_answers/ui/quick_answers_view.h
+++ b/chrome/browser/ui/quick_answers/ui/quick_answers_view.h
@@ -93,12 +93,13 @@
 
   base::WeakPtr<QuickAnswersUiController> controller_;
   std::string title_;
-  bool is_internal_ = false;
+  const bool is_internal_;
+  const bool is_rich_answers_enabled_;
+  const bool maximum_view_height_;
 
   views::ViewTracker base_view_;
   views::ViewTracker main_view_;
   views::ViewTracker content_view_;
-  views::ViewTracker report_query_view_;
   raw_ptr<views::Label> first_answer_label_ = nullptr;
   raw_ptr<views::LabelButton> retry_label_ = nullptr;
   raw_ptr<views::ImageButton> dogfood_feedback_button_ = nullptr;
diff --git a/chrome/browser/ui/shortcuts/OWNERS b/chrome/browser/ui/shortcuts/OWNERS
new file mode 100644
index 0000000..6a167de
--- /dev/null
+++ b/chrome/browser/ui/shortcuts/OWNERS
@@ -0,0 +1 @@
+file://chrome/browser/shortcuts/OWNERS
\ No newline at end of file
diff --git a/chrome/browser/ui/shortcuts/desktop_shortcuts_utils.cc b/chrome/browser/ui/shortcuts/desktop_shortcuts_utils.cc
new file mode 100644
index 0000000..d62479fd
--- /dev/null
+++ b/chrome/browser/ui/shortcuts/desktop_shortcuts_utils.cc
@@ -0,0 +1,50 @@
+// 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 "chrome/browser/ui/shortcuts/desktop_shortcuts_utils.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/page_type.h"
+#include "content/public/common/url_constants.h"
+
+namespace shortcuts {
+
+bool CanCreateDesktopShortcut(Browser* browser) {
+  Profile* profile = browser->profile();
+
+  // Do not allow for Guest or OTR profiles.
+  // System profiles have not been introduced here because they do not have a
+  // browser.
+  if (!profile || profile->IsGuestSession() || profile->IsOffTheRecord()) {
+    return false;
+  }
+
+  // Do not allow if the web_contents appear to be crashing.
+  content::WebContents* web_contents =
+      browser->tab_strip_model()->GetActiveWebContents();
+  if (!web_contents || web_contents->IsCrashed()) {
+    return false;
+  }
+
+  // Do not allow if the site_url is invalid or doesn't have a HTTP/HTTPS
+  // scheme.
+  const GURL site_url = web_contents->GetLastCommittedURL();
+  if (!site_url.is_valid() || !site_url.SchemeIsHTTPOrHTTPS()) {
+    return false;
+  }
+
+  // Do not allow for error pages (like network errors etc).
+  content::NavigationEntry* entry =
+      web_contents->GetController().GetLastCommittedEntry();
+  if (entry && entry->GetPageType() == content::PAGE_TYPE_ERROR) {
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace shortcuts
diff --git a/chrome/browser/ui/shortcuts/desktop_shortcuts_utils.h b/chrome/browser/ui/shortcuts/desktop_shortcuts_utils.h
new file mode 100644
index 0000000..17481a2
--- /dev/null
+++ b/chrome/browser/ui/shortcuts/desktop_shortcuts_utils.h
@@ -0,0 +1,18 @@
+// 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 CHROME_BROWSER_UI_SHORTCUTS_DESKTOP_SHORTCUTS_UTILS_H_
+#define CHROME_BROWSER_UI_SHORTCUTS_DESKTOP_SHORTCUTS_UTILS_H_
+
+class Browser;
+
+namespace shortcuts {
+
+// Returns whether a desktop shortcut can be created for the active web
+// contents.
+bool CanCreateDesktopShortcut(Browser* browser);
+
+}  // namespace shortcuts
+
+#endif  // CHROME_BROWSER_UI_SHORTCUTS_DESKTOP_SHORTCUTS_UTILS_H_
diff --git a/chrome/browser/ui/tabs/tab_group_deletion_dialog_controller.cc b/chrome/browser/ui/tabs/tab_group_deletion_dialog_controller.cc
index 066a504..1f72332 100644
--- a/chrome/browser/ui/tabs/tab_group_deletion_dialog_controller.cc
+++ b/chrome/browser/ui/tabs/tab_group_deletion_dialog_controller.cc
@@ -13,6 +13,8 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/browser_element_identifiers.h"
+#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.h"
+#include "chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_service_factory.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/prefs/pref_service.h"
@@ -25,36 +27,36 @@
 DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kDeletionDialogOkButtonId);
 
 namespace {
-
-// TODO(b/331254038) replace these hardcoded strings with IDS strings.
-
 // The text that shows on the checkbox.
 constexpr int kDontAskId = IDS_TAB_GROUP_DELETION_DIALOG_DONT_ASK;
 
+// Body text for all delete actions.
+constexpr int kDeleteBodySyncedId =
+    IDS_TAB_GROUP_DELETION_DIALOG_BODY_SYNCED_DELETE;
+constexpr int kDeleteBodyNotSyncedId =
+    IDS_TAB_GROUP_DELETION_DIALOG_BODY_NOT_SYNCED_DELETE;
+
 // For deletion, the text that shows on the dialog
 constexpr int kDeleteTitleId = IDS_TAB_GROUP_DELETION_DIALOG_TITLE_DELETE;
-constexpr int kDeleteBodyId = IDS_TAB_GROUP_DELETION_DIALOG_BODY_SYNCED_DELETE;
 constexpr int kDeleteOkTextId = IDS_TAB_GROUP_DELETION_DIALOG_OK_TEXT_DELETE;
 
 // For ungrouping, the text that shows on the dialog.
 constexpr int kUngroupTitleId = IDS_TAB_GROUP_DELETION_DIALOG_TITLE_UNGROUP;
-constexpr int kUngroupBodyId =
+constexpr int kUngroupSyncedBodyId =
     IDS_TAB_GROUP_DELETION_DIALOG_BODY_SYNCED_UNGROUP;
+constexpr int kUngroupNotSyncedBodyId =
+    IDS_TAB_GROUP_DELETION_DIALOG_BODY_NOT_SYNCED_UNGROUP;
 constexpr int kUngroupOkTextId = IDS_TAB_GROUP_DELETION_DIALOG_OK_TEXT_UNGROUP;
 
 // For closing the last tab, the text that shows on the dialog.
 constexpr int kCloseTabAndDeleteTitleId =
     IDS_TAB_GROUP_DELETION_DIALOG_TITLE_CLOSE_TAB_AND_DELETE;
-constexpr int kCloseTabAndDeleteBodyId =
-    IDS_TAB_GROUP_DELETION_DIALOG_BODY_SYNCED_DELETE;
 constexpr int kCloseTabAndDeleteOkTextId =
     IDS_TAB_GROUP_DELETION_DIALOG_OK_TEXT_DELETE;
 
 // For removing the last tab, the text that shows on the dialog.
 constexpr int kRemoveTabAndDeleteTitleId =
     IDS_TAB_GROUP_DELETION_DIALOG_TITLE_REMOVE_TAB_AND_DELETE;
-constexpr int kRemoveTabAndDeleteBodyId =
-    IDS_TAB_GROUP_DELETION_DIALOG_BODY_SYNCED_DELETE;
 constexpr int kRemoveTabAndDeleteOkTextId =
     IDS_TAB_GROUP_DELETION_DIALOG_OK_TEXT_DELETE;
 
@@ -65,27 +67,41 @@
 };
 
 // Returns the list of strings that are needed for a given dialog type.
-DialogText GetDialogText(DeletionDialogController::DialogType type) {
+DialogText GetDialogText(Profile* profile,
+                         DeletionDialogController::DialogType type) {
+  tab_groups::SavedTabGroupKeyedService* const saved_tab_group_service =
+      tab_groups::SavedTabGroupServiceFactory::GetForProfile(profile);
+  bool is_sync_enabled = saved_tab_group_service &&
+                         saved_tab_group_service->AreSavedTabGroupsSynced();
+
   switch (type) {
     case DeletionDialogController::DialogType::DeleteSingle: {
-      return DialogText{l10n_util::GetStringUTF16(kDeleteTitleId),
-                        l10n_util::GetStringUTF16(kDeleteBodyId),
-                        l10n_util::GetStringUTF16(kDeleteOkTextId)};
+      return DialogText{
+          l10n_util::GetStringUTF16(kDeleteTitleId),
+          l10n_util::GetStringUTF16(is_sync_enabled ? kDeleteBodySyncedId
+                                                    : kDeleteBodyNotSyncedId),
+          l10n_util::GetStringUTF16(kDeleteOkTextId)};
     }
     case DeletionDialogController::DialogType::UngroupSingle: {
-      return DialogText{l10n_util::GetStringUTF16(kUngroupTitleId),
-                        l10n_util::GetStringUTF16(kUngroupBodyId),
-                        l10n_util::GetStringUTF16(kUngroupOkTextId)};
+      return DialogText{
+          l10n_util::GetStringUTF16(kUngroupTitleId),
+          l10n_util::GetStringUTF16(is_sync_enabled ? kUngroupSyncedBodyId
+                                                    : kUngroupNotSyncedBodyId),
+          l10n_util::GetStringUTF16(kUngroupOkTextId)};
     }
     case DeletionDialogController::DialogType::RemoveTabAndDelete: {
-      return DialogText{l10n_util::GetStringUTF16(kRemoveTabAndDeleteTitleId),
-                        l10n_util::GetStringUTF16(kRemoveTabAndDeleteBodyId),
-                        l10n_util::GetStringUTF16(kRemoveTabAndDeleteOkTextId)};
+      return DialogText{
+          l10n_util::GetStringUTF16(kRemoveTabAndDeleteTitleId),
+          l10n_util::GetStringUTF16(is_sync_enabled ? kDeleteBodySyncedId
+                                                    : kDeleteBodyNotSyncedId),
+          l10n_util::GetStringUTF16(kRemoveTabAndDeleteOkTextId)};
     }
     case DeletionDialogController::DialogType::CloseTabAndDelete: {
-      return DialogText{l10n_util::GetStringUTF16(kCloseTabAndDeleteTitleId),
-                        l10n_util::GetStringUTF16(kCloseTabAndDeleteBodyId),
-                        l10n_util::GetStringUTF16(kCloseTabAndDeleteOkTextId)};
+      return DialogText{
+          l10n_util::GetStringUTF16(kCloseTabAndDeleteTitleId),
+          l10n_util::GetStringUTF16(is_sync_enabled ? kDeleteBodySyncedId
+                                                    : kDeleteBodyNotSyncedId),
+          l10n_util::GetStringUTF16(kCloseTabAndDeleteOkTextId)};
     }
   }
 }
@@ -210,7 +226,7 @@
 
 std::unique_ptr<ui::DialogModel> DeletionDialogController::BuildDialogModel(
     DialogType type) {
-  DialogText strings = GetDialogText(type);
+  DialogText strings = GetDialogText(browser_->profile(), type);
 
   return ui::DialogModel::Builder()
       .SetTitle(strings.title)
@@ -227,6 +243,11 @@
                        .SetLabel(strings.ok_text)
                        .SetEnabled(true)
                        .SetId(kDeletionDialogOkButtonId))
+      .SetCloseActionCallback(base::BindOnce(
+          [](DeletionDialogController* dialog_controller) {
+            dialog_controller->state_.reset();
+          },
+          base::Unretained(this)))
       .Build();
 }
 
diff --git a/chrome/browser/ui/views/commerce/product_specifications_button.cc b/chrome/browser/ui/views/commerce/product_specifications_button.cc
index c3cbde0b..2be9994f 100644
--- a/chrome/browser/ui/views/commerce/product_specifications_button.cc
+++ b/chrome/browser/ui/views/commerce/product_specifications_button.cc
@@ -18,6 +18,7 @@
 #include "ui/views/animation/ink_drop.h"
 #include "ui/views/controls/highlight_path_generator.h"
 #include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/flex_layout.h"
 #include "ui/views/mouse_watcher_view_host.h"
 #include "ui/views/view_class_properties.h"
 
@@ -105,6 +106,8 @@
 
   layout_manager->SetFlexForView(close_button_, 1);
 
+  SetLayoutManager(std::make_unique<views::FlexLayout>());
+
   UpdateColors();
 }
 
diff --git a/chrome/browser/ui/views/media_preview/media_view_controller_base_unittest.cc b/chrome/browser/ui/views/media_preview/media_view_controller_base_unittest.cc
index b85f50d..ac45fc57 100644
--- a/chrome/browser/ui/views/media_preview/media_view_controller_base_unittest.cc
+++ b/chrome/browser/ui/views/media_preview/media_view_controller_base_unittest.cc
@@ -116,14 +116,12 @@
     return controller_->GetNoDeviceLabelViewForTesting()->GetVisible();
   }
 
-  std::u16string GetComboboxAccessibleName() const {
+  const std::u16string& GetComboboxAccessibleName() const {
     return controller_->GetComboboxForTesting()->GetAccessibleName();
   }
-
   const std::u16string& GetDeviceNameLabel() const {
     return controller_->GetDeviceNameLabelViewForTesting()->GetText();
   }
-
   const std::u16string& GetNoDeviceLabel() const {
     return controller_->GetNoDeviceLabelViewForTesting()->GetText();
   }
diff --git a/chrome/browser/ui/views/supervised_user/parent_permission_dialog_view.cc b/chrome/browser/ui/views/supervised_user/parent_permission_dialog_view.cc
index 30cb457..59b2337 100644
--- a/chrome/browser/ui/views/supervised_user/parent_permission_dialog_view.cc
+++ b/chrome/browser/ui/views/supervised_user/parent_permission_dialog_view.cc
@@ -52,7 +52,6 @@
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/image/image_skia.h"
-#include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/border.h"
 #include "ui/views/bubble/bubble_frame_view.h"
 #include "ui/views/controls/button/radio_button.h"
@@ -80,11 +79,7 @@
 
  public:
   MaybeEmptyLabel(const std::string& text, const CustomFont& font)
-      : views::Label(base::UTF8ToUTF16(text), font) {
-    // Set the role to kAlert as this is required for
-    // sending accessibility notification alerts.
-    GetViewAccessibility().SetRole(ax::mojom::Role::kAlert);
-  }
+      : views::Label(base::UTF8ToUTF16(text), font) {}
 
   MaybeEmptyLabel& operator=(const MaybeEmptyLabel&) = delete;
   MaybeEmptyLabel(const MaybeEmptyLabel&) = delete;
@@ -98,6 +93,10 @@
     } else {
       node_data->SetNameExplicitlyEmpty();
     }
+
+    // Set the role to kAlert as this is required for
+    // sending accessibility notification alerts.
+    node_data->role = ax::mojom::Role::kAlert;
   }
 };
 
diff --git a/chrome/browser/ui/web_applications/web_app_link_capturing_browsertest.cc b/chrome/browser/ui/web_applications/web_app_link_capturing_browsertest.cc
index 11e38ec4..8b3255af 100644
--- a/chrome/browser/ui/web_applications/web_app_link_capturing_browsertest.cc
+++ b/chrome/browser/ui/web_applications/web_app_link_capturing_browsertest.cc
@@ -674,20 +674,20 @@
     : public WebAppLinkCapturingBrowserTest {
  public:
   WebAppTabStripLinkCapturingBrowserTest() {
-    // TODO(b/339747365): Enable kDesktopPWAsTabStripCustomizations in this test
-    // so it tests the released flag configuration.
     features_.InitWithFeatures(
         /*enabled_features=*/{blink::features::kDesktopPWAsTabStrip,
-                              features::kDesktopPWAsTabStripSettings},
-        /*disabled_features=*/{
-            blink::features::kDesktopPWAsTabStripCustomizations});
+                              blink::features::
+                                  kDesktopPWAsTabStripCustomizations},
+        /*disabled_features=*/{});
   }
 
   // Returns [app_id, in_scope_1, in_scope_2, scope]
   std::tuple<webapps::AppId, GURL, GURL, GURL> InstallTestTabbedApp() {
     const auto [app_id, in_scope_1, in_scope_2, scope] =
         WebAppLinkCapturingBrowserTest::InstallTestApp(
-            "/web_apps/tab_strip_customizations.html");
+            "/banners/"
+            "manifest_test_page.html?manifest=manifest_tabbed_display_override."
+            "json");
     return std::make_tuple(app_id, in_scope_1, in_scope_2, scope);
   }
 
diff --git a/chrome/browser/ui/webauthn/sheet_models.cc b/chrome/browser/ui/webauthn/sheet_models.cc
index 438803c..a0294304 100644
--- a/chrome/browser/ui/webauthn/sheet_models.cc
+++ b/chrome/browser/ui/webauthn/sheet_models.cc
@@ -2054,9 +2054,10 @@
         AuthenticatorRequestDialogModel* dialog_model)
     : AuthenticatorSheetModelBase(dialog_model,
                                   OtherMechanismButtonVisibility::kHidden) {
-  // TODO(enclave): Add the new incognito illustration to use instead.
-  lottie_illustrations_.emplace(IDR_WEBAUTHN_GPM_PASSKEY_LIGHT,
-                                IDR_WEBAUTHN_GPM_PASSKEY_DARK);
+  // Incognito always has a dark color scheme and so the two illustrations are
+  // the same.
+  lottie_illustrations_.emplace(IDR_WEBAUTHN_GPM_INCOGNITO,
+                                IDR_WEBAUTHN_GPM_INCOGNITO);
 }
 
 AuthenticatorGpmIncognitoCreateSheetModel::
diff --git a/chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_ui.h b/chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_ui.h
deleted file mode 100644
index 770fcd9..0000000
--- a/chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_ui.h
+++ /dev/null
@@ -1,39 +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 CHROME_BROWSER_UI_WEBUI_ASH_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_UI_H_
-#define CHROME_BROWSER_UI_WEBUI_ASH_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_UI_H_
-
-#include "content/public/browser/web_ui_controller.h"
-#include "content/public/browser/webui_config.h"
-
-namespace content {
-class WebUI;
-}
-
-namespace ash {
-
-class ArcGraphicsTracingUI;
-
-// WebUIConfig for chrome://arc-overview-tracing
-class ArcGraphicsTracingUIConfig
-    : public content::DefaultWebUIConfig<ArcGraphicsTracingUI> {
- public:
-  ArcGraphicsTracingUIConfig();
-
-  bool IsWebUIEnabled(content::BrowserContext* browser_context) override;
-};
-
-// WebUI controller for arc graphics/overview tracing.
-class ArcGraphicsTracingUI : public content::WebUIController {
- public:
-  explicit ArcGraphicsTracingUI(content::WebUI* web_ui);
-
-  ArcGraphicsTracingUI(const ArcGraphicsTracingUI&) = delete;
-  ArcGraphicsTracingUI& operator=(const ArcGraphicsTracingUI&) = delete;
-};
-
-}  // namespace ash
-
-#endif  // CHROME_BROWSER_UI_WEBUI_ASH_ARC_GRAPHICS_TRACING_ARC_GRAPHICS_TRACING_UI_H_
diff --git a/chrome/browser/ui/webui/ash/arc_graphics_tracing/OWNERS b/chrome/browser/ui/webui/ash/arc_overview_tracing/OWNERS
similarity index 100%
rename from chrome/browser/ui/webui/ash/arc_graphics_tracing/OWNERS
rename to chrome/browser/ui/webui/ash/arc_overview_tracing/OWNERS
diff --git a/chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_ui.cc b/chrome/browser/ui/webui/ash/arc_overview_tracing/arc_overview_tracing_ui.cc
similarity index 96%
rename from chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_ui.cc
rename to chrome/browser/ui/webui/ash/arc_overview_tracing/arc_overview_tracing_ui.cc
index bb8782a8a..bc583d6b 100644
--- a/chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_ui.cc
+++ b/chrome/browser/ui/webui/ash/arc_overview_tracing/arc_overview_tracing_ui.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_ui.h"
+#include "chrome/browser/ui/webui/ash/arc_overview_tracing/arc_overview_tracing_ui.h"
 
 #include <memory>
 #include <string>
@@ -216,17 +216,17 @@
 
 }  // anonymous namespace
 
-ArcGraphicsTracingUIConfig::ArcGraphicsTracingUIConfig()
+ArcOverviewTracingUIConfig::ArcOverviewTracingUIConfig()
     : DefaultWebUIConfig(content::kChromeUIScheme,
                          chrome::kChromeUIArcOverviewTracingHost) {}
 
-bool ArcGraphicsTracingUIConfig::IsWebUIEnabled(
+bool ArcOverviewTracingUIConfig::IsWebUIEnabled(
     content::BrowserContext* browser_context) {
   return arc::IsArcAllowedForProfile(
       Profile::FromBrowserContext(browser_context));
 }
 
-ArcGraphicsTracingUI::ArcGraphicsTracingUI(content::WebUI* web_ui)
+ArcOverviewTracingUI::ArcOverviewTracingUI(content::WebUI* web_ui)
     : WebUIController(web_ui) {
   web_ui->AddMessageHandler(std::make_unique<Handler>());
   CreateAndAddOverviewDataSource(Profile::FromWebUI(web_ui));
diff --git a/chrome/browser/ui/webui/ash/arc_overview_tracing/arc_overview_tracing_ui.h b/chrome/browser/ui/webui/ash/arc_overview_tracing/arc_overview_tracing_ui.h
new file mode 100644
index 0000000..9f32fd3
--- /dev/null
+++ b/chrome/browser/ui/webui/ash/arc_overview_tracing/arc_overview_tracing_ui.h
@@ -0,0 +1,39 @@
+// 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 CHROME_BROWSER_UI_WEBUI_ASH_ARC_OVERVIEW_TRACING_ARC_OVERVIEW_TRACING_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_ASH_ARC_OVERVIEW_TRACING_ARC_OVERVIEW_TRACING_UI_H_
+
+#include "content/public/browser/web_ui_controller.h"
+#include "content/public/browser/webui_config.h"
+
+namespace content {
+class WebUI;
+}
+
+namespace ash {
+
+class ArcOverviewTracingUI;
+
+// WebUIConfig for chrome://arc-overview-tracing
+class ArcOverviewTracingUIConfig
+    : public content::DefaultWebUIConfig<ArcOverviewTracingUI> {
+ public:
+  ArcOverviewTracingUIConfig();
+
+  bool IsWebUIEnabled(content::BrowserContext* browser_context) override;
+};
+
+// WebUI controller for arc graphics/overview tracing.
+class ArcOverviewTracingUI : public content::WebUIController {
+ public:
+  explicit ArcOverviewTracingUI(content::WebUI* web_ui);
+
+  ArcOverviewTracingUI(const ArcOverviewTracingUI&) = delete;
+  ArcOverviewTracingUI& operator=(const ArcOverviewTracingUI&) = delete;
+};
+
+}  // namespace ash
+
+#endif  // CHROME_BROWSER_UI_WEBUI_ASH_ARC_OVERVIEW_TRACING_ARC_OVERVIEW_TRACING_UI_H_
diff --git a/chrome/browser/ui/webui/ash/chrome_web_ui_configs_chromeos.cc b/chrome/browser/ui/webui/ash/chrome_web_ui_configs_chromeos.cc
index c932ad1..c0edaedd 100644
--- a/chrome/browser/ui/webui/ash/chrome_web_ui_configs_chromeos.cc
+++ b/chrome/browser/ui/webui/ash/chrome_web_ui_configs_chromeos.cc
@@ -58,7 +58,7 @@
 #include "chrome/browser/ui/webui/ash/account_manager/account_migration_welcome_ui.h"
 #include "chrome/browser/ui/webui/ash/add_supervision/add_supervision_ui.h"
 #include "chrome/browser/ui/webui/ash/app_install/app_install_ui.h"
-#include "chrome/browser/ui/webui/ash/arc_graphics_tracing/arc_graphics_tracing_ui.h"
+#include "chrome/browser/ui/webui/ash/arc_overview_tracing/arc_overview_tracing_ui.h"
 #include "chrome/browser/ui/webui/ash/arc_power_control/arc_power_control_ui.h"
 #include "chrome/browser/ui/webui/ash/assistant_optin/assistant_optin_ui.h"
 #include "chrome/browser/ui/webui/ash/audio/audio_ui.h"
@@ -216,7 +216,7 @@
   map.AddWebUIConfig(std::make_unique<AccountMigrationWelcomeUIConfig>());
   map.AddWebUIConfig(std::make_unique<AddSupervisionUIConfig>());
   map.AddWebUIConfig(std::make_unique<app_install::AppInstallDialogUIConfig>());
-  map.AddWebUIConfig(std::make_unique<ArcGraphicsTracingUIConfig>());
+  map.AddWebUIConfig(std::make_unique<ArcOverviewTracingUIConfig>());
   map.AddWebUIConfig(std::make_unique<ArcPowerControlUIConfig>());
   map.AddWebUIConfig(std::make_unique<AssistantOptInUIConfig>());
   map.AddWebUIConfig(std::make_unique<AudioUIConfig>());
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index 8fe7257..f5bbd0b2 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -287,10 +287,6 @@
   };
   html_source->AddLocalizedStrings(kLocalizedStrings);
 
-#if BUILDFLAG(IS_WIN)
-  html_source->AddBoolean("isWindows10OrNewer", true);
-#endif
-
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
   html_source->AddBoolean(
       "showFocusHighlightOption",
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar.mojom b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar.mojom
index 7a32bc6d..8a9be672 100644
--- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar.mojom
+++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar.mojom
@@ -5,9 +5,28 @@
 module side_panel.customize_chrome.mojom;
 
 // Unique identifiers for actions that can be pinned to the toolbar.
-// TODO(crbug.com/323964782): Add the other pinnable actions.
 enum ActionId {
+  kShowBookmarks,
+  kShowHistoryCluster,
+  kShowReadAnything,
+  kShowReadingList,
+  kShowSideSearch,
+  kHome,
+  kForward,
+  kNewIncognitoWindow,
+  kShowPasswordManager,
+  kShowPaymentMethods,
+  kShowAddresses,
+  kShowDownloads,
+  kClearBrowsingData,
   kPrint,
+  kShowTranslate,
+  kSendTabToSelf,
+  kQrCodeGenerator,
+  kRouteMedia,
+  kTaskManager,
+  kDevTools,
+  kShowChromeLabs,
 };
 
 // An action that can be pinned to the toolbar.
@@ -16,6 +35,8 @@
   ActionId id;
   // The name for the webui to display for this action.
   string display_name;
+  // Whether the action is currently pinned to the toolbar.
+  bool pinned;
   // TODO(crbug.com/323964782): Also include category.
   // TODO(crbug.com/323964874): Also include icon data.
 };
@@ -31,8 +52,6 @@
 interface CustomizeToolbarHandler {
   // Returns the list of all actions that can be pinned to the toolbar.
   ListActions() => (array<Action> actions);
-  // Returns true if the action with id `action_id` is pinned to the toolbar.
-  GetActionPinned(ActionId action_id) => (bool pinned);
   // Pins the action with id `action_id` to (or unpins it from) the toolbar.
   PinAction(ActionId action_id, bool pinned);
 };
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler.cc b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler.cc
index 738b238c..b60a721 100644
--- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler.cc
+++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler.cc
@@ -17,8 +17,49 @@
 std::optional<side_panel::customize_chrome::mojom::ActionId>
 MojoActionForChromeAction(actions::ActionId action_id) {
   switch (action_id) {
+    case kActionSidePanelShowBookmarks:
+      return side_panel::customize_chrome::mojom::ActionId::kShowBookmarks;
+    case kActionSidePanelShowHistoryCluster:
+      return side_panel::customize_chrome::mojom::ActionId::kShowHistoryCluster;
+    case kActionSidePanelShowReadAnything:
+      return side_panel::customize_chrome::mojom::ActionId::kShowReadAnything;
+    case kActionSidePanelShowReadingList:
+      return side_panel::customize_chrome::mojom::ActionId::kShowReadingList;
+    case kActionSidePanelShowSideSearch:
+      return side_panel::customize_chrome::mojom::ActionId::kShowSideSearch;
+    case kActionHome:
+      return side_panel::customize_chrome::mojom::ActionId::kHome;
+    case kActionForward:
+      return side_panel::customize_chrome::mojom::ActionId::kForward;
+    case kActionNewIncognitoWindow:
+      return side_panel::customize_chrome::mojom::ActionId::kNewIncognitoWindow;
+    case kActionShowPasswordManager:
+      return side_panel::customize_chrome::mojom::ActionId::
+          kShowPasswordManager;
+    case kActionShowPaymentMethods:
+      return side_panel::customize_chrome::mojom::ActionId::kShowPaymentMethods;
+    case kActionShowAddresses:
+      return side_panel::customize_chrome::mojom::ActionId::kShowAddresses;
+    case kActionShowDownloads:
+      return side_panel::customize_chrome::mojom::ActionId::kShowDownloads;
+    case kActionClearBrowsingData:
+      return side_panel::customize_chrome::mojom::ActionId::kClearBrowsingData;
     case kActionPrint:
       return side_panel::customize_chrome::mojom::ActionId::kPrint;
+    case kActionShowTranslate:
+      return side_panel::customize_chrome::mojom::ActionId::kShowTranslate;
+    case kActionSendTabToSelf:
+      return side_panel::customize_chrome::mojom::ActionId::kSendTabToSelf;
+    case kActionQrCodeGenerator:
+      return side_panel::customize_chrome::mojom::ActionId::kQrCodeGenerator;
+    case kActionRouteMedia:
+      return side_panel::customize_chrome::mojom::ActionId::kRouteMedia;
+    case kActionTaskManager:
+      return side_panel::customize_chrome::mojom::ActionId::kTaskManager;
+    case kActionDevTools:
+      return side_panel::customize_chrome::mojom::ActionId::kDevTools;
+    case kActionShowChromeLabs:
+      return side_panel::customize_chrome::mojom::ActionId::kShowChromeLabs;
     default:
       return std::nullopt;
   }
@@ -27,8 +68,48 @@
 std::optional<actions::ActionId> ChromeActionForMojoAction(
     side_panel::customize_chrome::mojom::ActionId action_id) {
   switch (action_id) {
+    case side_panel::customize_chrome::mojom::ActionId::kShowBookmarks:
+      return kActionSidePanelShowBookmarks;
+    case side_panel::customize_chrome::mojom::ActionId::kShowHistoryCluster:
+      return kActionSidePanelShowHistoryCluster;
+    case side_panel::customize_chrome::mojom::ActionId::kShowReadAnything:
+      return kActionSidePanelShowReadAnything;
+    case side_panel::customize_chrome::mojom::ActionId::kShowReadingList:
+      return kActionSidePanelShowReadingList;
+    case side_panel::customize_chrome::mojom::ActionId::kShowSideSearch:
+      return kActionSidePanelShowSideSearch;
+    case side_panel::customize_chrome::mojom::ActionId::kHome:
+      return kActionHome;
+    case side_panel::customize_chrome::mojom::ActionId::kForward:
+      return kActionForward;
+    case side_panel::customize_chrome::mojom::ActionId::kNewIncognitoWindow:
+      return kActionNewIncognitoWindow;
+    case side_panel::customize_chrome::mojom::ActionId::kShowPasswordManager:
+      return kActionShowPasswordManager;
+    case side_panel::customize_chrome::mojom::ActionId::kShowPaymentMethods:
+      return kActionShowPaymentMethods;
+    case side_panel::customize_chrome::mojom::ActionId::kShowAddresses:
+      return kActionShowAddresses;
+    case side_panel::customize_chrome::mojom::ActionId::kShowDownloads:
+      return kActionShowDownloads;
+    case side_panel::customize_chrome::mojom::ActionId::kClearBrowsingData:
+      return kActionClearBrowsingData;
     case side_panel::customize_chrome::mojom::ActionId::kPrint:
       return kActionPrint;
+    case side_panel::customize_chrome::mojom::ActionId::kShowTranslate:
+      return kActionShowTranslate;
+    case side_panel::customize_chrome::mojom::ActionId::kSendTabToSelf:
+      return kActionSendTabToSelf;
+    case side_panel::customize_chrome::mojom::ActionId::kQrCodeGenerator:
+      return kActionQrCodeGenerator;
+    case side_panel::customize_chrome::mojom::ActionId::kRouteMedia:
+      return kActionRouteMedia;
+    case side_panel::customize_chrome::mojom::ActionId::kTaskManager:
+      return kActionTaskManager;
+    case side_panel::customize_chrome::mojom::ActionId::kDevTools:
+      return kActionDevTools;
+    case side_panel::customize_chrome::mojom::ActionId::kShowChromeLabs:
+      return kActionShowChromeLabs;
     default:
       return std::nullopt;
   }
@@ -56,39 +137,53 @@
 void CustomizeToolbarHandler::ListActions(ListActionsCallback callback) {
   std::vector<side_panel::customize_chrome::mojom::ActionPtr> actions;
 
-  // TODO(crbug.com/323964782): Include the other pinnable actions - print is
-  // the only example for now.
-
-  const actions::ActionItem* const print_action_item =
-      actions::ActionManager::Get().FindAction(
-          kActionPrint,
-          BrowserActions::FromBrowser(browser())->root_action_item());
+  actions::ActionItem* const scope_action =
+      BrowserActions::FromBrowser(browser())->root_action_item();
+  const PinnedToolbarActionsModel* const pinned_model =
+      PinnedToolbarActionsModel::Get(profile_);
 
   // TODO(crbug.com/337938827): GetText() is wrong here; it returns "&Print..."
   // instead of "Print". We my need to introduce new strings instead of reusing
   // the action item text.
-  auto print_action = side_panel::customize_chrome::mojom::Action::New(
-      MojoActionForChromeAction(kActionPrint).value(),
-      base::UTF16ToUTF8(print_action_item->GetText()));
-  actions.push_back(std::move(print_action));
+  const auto add_action = [&actions, pinned_model,
+                           scope_action](actions::ActionId id) {
+    const actions::ActionItem* const action_item =
+        actions::ActionManager::Get().FindAction(id, scope_action);
+    CHECK(action_item) << "Action with id " << id << " not found.";
+    auto mojo_action = side_panel::customize_chrome::mojom::Action::New(
+        MojoActionForChromeAction(id).value(),
+        base::UTF16ToUTF8(action_item->GetText()), pinned_model->Contains(id));
+    actions.push_back(std::move(mojo_action));
+  };
+
+  // TODO(crbug.com/323961924): Enable the remaining actions as they are created
+  // in the action manager.
+  add_action(kActionSidePanelShowBookmarks);
+  add_action(kActionSidePanelShowHistoryCluster);
+  add_action(kActionSidePanelShowReadAnything);
+  add_action(kActionSidePanelShowReadingList);
+  // add_action(kActionSidePanelShowSideSearch);
+
+  // add_action(kActionHome);
+  // add_action(kActionForward);
+  add_action(kActionNewIncognitoWindow);
+  // add_action(kActionShowPasswordManager);
+  // add_action(kActionShowPaymentMethods);
+  // add_action(kActionShowAddresses);
+  // add_action(kActionShowDownloads);
+  add_action(kActionClearBrowsingData);
+  add_action(kActionPrint);
+  // add_action(kActionShowTranslate);
+  // add_action(kActionSendTabToSelf);
+  // add_action(kActionQrCodeGenerator);
+  // add_action(kActionRouteMedia);
+  add_action(kActionTaskManager);
+  add_action(kActionDevTools);
+  // add_action(kActionShowChromeLabs);
 
   std::move(callback).Run(std::move(actions));
 }
 
-void CustomizeToolbarHandler::GetActionPinned(
-    side_panel::customize_chrome::mojom::ActionId action_id,
-    GetActionPinnedCallback callback) {
-  const std::optional<actions::ActionId> chrome_action =
-      ChromeActionForMojoAction(action_id);
-  if (!chrome_action.has_value()) {
-    mojo::ReportBadMessage(
-        "GetActionPinned called with an unsupported action.");
-    return;
-  }
-  std::move(callback).Run(PinnedToolbarActionsModel::Get(profile_)->Contains(
-      chrome_action.value()));
-}
-
 void CustomizeToolbarHandler::PinAction(
     side_panel::customize_chrome::mojom::ActionId action_id,
     bool pin) {
diff --git a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler.h b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler.h
index f029ed6..955f5404 100644
--- a/chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler.h
+++ b/chrome/browser/ui/webui/side_panel/customize_chrome/customize_toolbar/customize_toolbar_handler.h
@@ -31,8 +31,6 @@
 
   // side_panel::customize_chrome::mojom::CustomizeToolbarHandler:
   void ListActions(ListActionsCallback callback) override;
-  void GetActionPinned(side_panel::customize_chrome::mojom::ActionId action_id,
-                       GetActionPinnedCallback callback) override;
   void PinAction(side_panel::customize_chrome::mojom::ActionId action_id,
                  bool pin) override;
 
diff --git a/chrome/browser/webauthn/DEPS b/chrome/browser/webauthn/DEPS
index 99277687d..6a406ec 100644
--- a/chrome/browser/webauthn/DEPS
+++ b/chrome/browser/webauthn/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+ash/shell.h",
   "+components/webauthn/android",
   "+components/externalauth/android",
   "+device/fido",
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.cc b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
index 8f447e1..58ddc15 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model.cc
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
@@ -249,25 +249,29 @@
                                       base::UTF8ToUTF16(*priority_phone_name));
   }
   int message;
-  bool enclave_enabled =
+  bool gpm_enabled =
+#if BUILDFLAG(IS_CHROMEOS)
+      base::FeatureList::IsEnabled(device::kChromeOsPasskeys) ||
+#endif
       base::FeatureList::IsEnabled(device::kWebAuthnEnclaveAuthenticator);
   switch (type) {
     case device::AuthenticatorType::kWinNative:
-      message = enclave_enabled ? IDS_WEBAUTHN_SOURCE_WINDOWS_HELLO_NEW
-                                : IDS_WEBAUTHN_SOURCE_WINDOWS_HELLO;
+      message = gpm_enabled ? IDS_WEBAUTHN_SOURCE_WINDOWS_HELLO_NEW
+                            : IDS_WEBAUTHN_SOURCE_WINDOWS_HELLO;
       break;
     case device::AuthenticatorType::kTouchID:
-      message = enclave_enabled ? IDS_WEBAUTHN_SOURCE_CHROME_PROFILE_NEW
-                                : IDS_WEBAUTHN_SOURCE_CHROME_PROFILE;
+      message = gpm_enabled ? IDS_WEBAUTHN_SOURCE_CHROME_PROFILE_NEW
+                            : IDS_WEBAUTHN_SOURCE_CHROME_PROFILE;
       break;
     case device::AuthenticatorType::kICloudKeychain:
       // TODO(crbug.com/40265798): Use IDS_WEBAUTHN_SOURCE_CUSTOM_VENDOR for
       // third party providers.
-      message = enclave_enabled ? IDS_WEBAUTHN_SOURCE_ICLOUD_KEYCHAIN_NEW
-                                : IDS_WEBAUTHN_SOURCE_ICLOUD_KEYCHAIN;
+      message = gpm_enabled ? IDS_WEBAUTHN_SOURCE_ICLOUD_KEYCHAIN_NEW
+                            : IDS_WEBAUTHN_SOURCE_ICLOUD_KEYCHAIN;
       break;
     case device::AuthenticatorType::kEnclave:
-      CHECK(enclave_enabled);
+    case device::AuthenticatorType::kChromeOSPasskeys:
+      CHECK(gpm_enabled);
       message = IDS_WEBAUTHN_SOURCE_GOOGLE_PASSWORD_MANAGER;
       break;
     default:
@@ -293,6 +297,8 @@
 // user ID.
 int SourcePriority(device::AuthenticatorType source) {
   switch (source) {
+    case device::AuthenticatorType::kChromeOSPasskeys:
+      return 5;
     case device::AuthenticatorType::kEnclave:
       return 4;
     case device::AuthenticatorType::kICloudKeychain:
@@ -2732,3 +2738,8 @@
   model_->priority_mechanism_index = IndexOfPriorityMechanism();
   StartConditionalMediationRequest();
 }
+
+void AuthenticatorRequestDialogController::OnChromeOSGPMRequestReady() {
+  HideDialogAndDispatchToPlatformAuthenticator(
+      device::AuthenticatorType::kChromeOSPasskeys);
+}
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.h b/chrome/browser/webauthn/authenticator_request_dialog_model.h
index ca31d88..70d5ba90 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model.h
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model.h
@@ -103,6 +103,9 @@
   /* Called when the enclave authenticator needs a reauth before it is */     \
   /* available for a request. */                                              \
   AUTHENTICATOR_REQUEST_EVENT_0(EnclaveNeedsReauth)                           \
+  /* Called when the ChromeOS authenticator is ready to handle a pending */   \
+  /* request. */                                                              \
+  AUTHENTICATOR_REQUEST_EVENT_0(OnChromeOSGPMRequestReady)                    \
   AUTHENTICATOR_REQUEST_EVENT_0(OnBioEnrollmentDone)                          \
   /* Called when the power state of the Bluetooth adapter has changed. */     \
   AUTHENTICATOR_REQUEST_EVENT_0(OnBluetoothPoweredStateChanged)               \
@@ -973,6 +976,8 @@
 
   void OnUserConfirmedPriorityMechanism() override;
 
+  void OnChromeOSGPMRequestReady() override;
+
   raw_ptr<Model> model_;
 
   // Identifier for the RenderFrameHost of the frame that initiated the current
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
index dc43d94..d603c34 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
@@ -110,6 +110,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS)
 #include "chrome/browser/webauthn/chromeos/passkey_dialog_controller.h"
+#include "chrome/browser/webauthn/chromeos/passkey_discovery.h"
 #include "chrome/browser/webauthn/chromeos/passkey_service.h"
 #include "chrome/browser/webauthn/chromeos/passkey_service_factory.h"
 #include "chromeos/components/webauthn/webauthn_request_registrar.h"
@@ -840,6 +841,18 @@
                                                    std::move(callback));
 }
 
+std::vector<std::unique_ptr<device::FidoDiscoveryBase>>
+ChromeAuthenticatorRequestDelegate::CreatePlatformDiscoveries() {
+  std::vector<std::unique_ptr<device::FidoDiscoveryBase>> discoveries;
+#if BUILDFLAG(IS_CHROMEOS)
+  if (base::FeatureList::IsEnabled(device::kChromeOsPasskeys)) {
+    discoveries.push_back(
+        std::make_unique<chromeos::PasskeyDiscovery>(GetRenderFrameHost()));
+  }
+#endif
+  return {};
+}
+
 void ChromeAuthenticatorRequestDelegate::ConfigureDiscoveries(
     const url::Origin& origin,
     const std::string& rp_id,
@@ -1304,9 +1317,13 @@
 void ChromeAuthenticatorRequestDelegate::ShowUI(
     device::FidoRequestHandlerBase::TransportAvailabilityInfo tai) {
   if (base::FeatureList::IsEnabled(syncer::kSyncWebauthnCredentials) &&
+      !IsVirtualEnvironmentEnabled() &&
       (can_use_synced_phone_passkeys_ ||
-       (enclave_controller_ && enclave_controller_->is_active())) &&
-      !IsVirtualEnvironmentEnabled()) {
+       (enclave_controller_ && enclave_controller_->is_active())
+#if BUILDFLAG(IS_CHROMEOS)
+       || chromeos_passkey_controller_
+#endif
+       )) {
     GetPhoneContactableGpmPasskeysForRpId(&tai.recognized_credentials);
   }
   FilterRecognizedCredentials(&tai);
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
index 4476673..3cee5d2 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
@@ -222,6 +222,8 @@
                                  credential_list) override;
   void SetUserEntityForMakeCredentialRequest(
       const device::PublicKeyCredentialUserEntity& user_entity) override;
+  std::vector<std::unique_ptr<device::FidoDiscoveryBase>>
+  CreatePlatformDiscoveries() override;
 
   // device::FidoRequestHandlerBase::Observer:
   void OnTransportAvailabilityEnumerated(
diff --git a/chrome/browser/webauthn/chromeos/passkey_authenticator.cc b/chrome/browser/webauthn/chromeos/passkey_authenticator.cc
new file mode 100644
index 0000000..ffdb70ef
--- /dev/null
+++ b/chrome/browser/webauthn/chromeos/passkey_authenticator.cc
@@ -0,0 +1,246 @@
+// 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 "chrome/browser/webauthn/chromeos/passkey_authenticator.h"
+
+#include "base/containers/span.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
+#include "base/functional/callback_helpers.h"
+#include "base/memory/weak_ptr.h"
+#include "base/no_destructor.h"
+#include "base/notimplemented.h"
+#include "base/task/sequenced_task_runner.h"
+#include "chrome/browser/webauthn/chromeos/passkey_in_session_auth.h"
+#include "chrome/browser/webauthn/chromeos/passkey_service.h"
+#include "components/device_event_log/device_event_log.h"
+#include "components/webauthn/core/browser/passkey_model.h"
+#include "components/webauthn/core/browser/passkey_model_utils.h"
+#include "content/public/browser/render_frame_host.h"
+#include "crypto/ec_private_key.h"
+#include "crypto/ec_signature_creator.h"
+#include "crypto/sha2.h"
+#include "device/fido/authenticator_get_assertion_response.h"
+#include "device/fido/authenticator_supported_options.h"
+#include "device/fido/ctap_get_assertion_request.h"
+#include "device/fido/ctap_make_credential_request.h"
+#include "device/fido/fido_authenticator.h"
+#include "device/fido/fido_constants.h"
+#include "device/fido/fido_transport_protocol.h"
+#include "device/fido/fido_types.h"
+#include "ui/aura/window.h"
+
+using device::AuthenticatorData;
+using device::AuthenticatorGetAssertionResponse;
+using device::AuthenticatorSupportedOptions;
+using device::AuthenticatorType;
+using device::CoseAlgorithmIdentifier;
+using device::CredentialType;
+using device::CtapDeviceResponseCode;
+using device::CtapGetAssertionOptions;
+using device::CtapGetAssertionRequest;
+using device::CtapMakeCredentialRequest;
+using device::FidoAuthenticator;
+using device::FidoRequestHandlerBase;
+using device::FidoTransportProtocol;
+using device::MakeCredentialOptions;
+using device::PublicKeyCredentialDescriptor;
+using device::PublicKeyCredentialUserEntity;
+
+namespace chromeos {
+namespace {
+
+AuthenticatorSupportedOptions PasskeyAuthenticatorOptions() {
+  AuthenticatorSupportedOptions options;
+  options.is_platform_device =
+      AuthenticatorSupportedOptions::PlatformDevice::kYes;
+  options.supports_resident_key = true;
+  options.user_verification_availability = AuthenticatorSupportedOptions::
+      UserVerificationAvailability::kSupportedAndConfigured;
+  return options;
+}
+
+// Returns the WebAuthn authenticator data for this authenticator. See
+// https://w3c.github.io/webauthn/#authenticator-data.
+AuthenticatorData MakeAuthenticatorDataForAssertion(std::string_view rp_id) {
+  using Flag = AuthenticatorData::Flag;
+  return AuthenticatorData(
+      crypto::SHA256Hash(base::as_byte_span(rp_id)),
+      {Flag::kTestOfUserPresence, Flag::kTestOfUserVerification,
+       Flag::kBackupEligible, Flag::kBackupState},
+      /*sign_counter=*/0u,
+      /*attested_credential_data=*/std::nullopt,
+      /*extensions=*/std::nullopt);
+}
+
+std::optional<std::vector<uint8_t>> GenerateEcSignature(
+    base::span<const uint8_t> pkcs8_ec_private_key,
+    base::span<const uint8_t> signed_over_data) {
+  auto ec_private_key =
+      crypto::ECPrivateKey::CreateFromPrivateKeyInfo(pkcs8_ec_private_key);
+  if (!ec_private_key) {
+    return std::nullopt;
+  }
+  auto signer = crypto::ECSignatureCreator::Create(ec_private_key.get());
+  std::vector<uint8_t> signature;
+  if (!signer->Sign(signed_over_data, &signature)) {
+    return std::nullopt;
+  }
+  return signature;
+}
+
+}  // namespace
+
+PasskeyAuthenticator::PasskeyAuthenticator(
+    content::RenderFrameHost* rfh,
+    PasskeyService* passkey_service,
+    webauthn::PasskeyModel* passkey_model)
+    : render_frame_host_id_(rfh->GetGlobalId()),
+      passkey_service_(passkey_service),
+      passkey_model_(passkey_model) {}
+
+PasskeyAuthenticator::~PasskeyAuthenticator() = default;
+
+AuthenticatorType PasskeyAuthenticator::GetType() const {
+  return AuthenticatorType::kChromeOSPasskeys;
+}
+
+std::string PasskeyAuthenticator::GetId() const {
+  return "ChromeOSPasskeysAuthenticator";
+}
+
+std::optional<base::span<const int32_t>> PasskeyAuthenticator::GetAlgorithms() {
+  constexpr std::array<int32_t, 1> kAlgorithms{
+      static_cast<int32_t>(CoseAlgorithmIdentifier::kEs256)};
+  return kAlgorithms;
+}
+
+const AuthenticatorSupportedOptions& PasskeyAuthenticator::Options() const {
+  static const base::NoDestructor<AuthenticatorSupportedOptions> options(
+      PasskeyAuthenticatorOptions());
+  return *options;
+}
+
+std::optional<FidoTransportProtocol>
+PasskeyAuthenticator::AuthenticatorTransport() const {
+  return FidoTransportProtocol::kInternal;
+}
+
+void PasskeyAuthenticator::GetTouch(base::OnceClosure callback) {}
+
+void PasskeyAuthenticator::InitializeAuthenticator(base::OnceClosure callback) {
+  std::move(callback).Run();
+}
+
+void PasskeyAuthenticator::MakeCredential(CtapMakeCredentialRequest request,
+                                          MakeCredentialOptions request_options,
+                                          MakeCredentialCallback callback) {}
+
+void PasskeyAuthenticator::GetAssertion(CtapGetAssertionRequest request,
+                                        CtapGetAssertionOptions options,
+                                        GetAssertionCallback callback) {
+  std::string rp_id = request.rp_id;
+  PasskeyInSessionAuthProvider::Get()->ShowPasskeyInSessionAuthDialog(
+      content::RenderFrameHost::FromID(render_frame_host_id_)
+          ->GetNativeView()
+          ->GetToplevelWindow(),
+      rp_id,
+      base::BindOnce(&PasskeyAuthenticator::FinishGetAssertion,
+                     weak_factory_.GetWeakPtr(), std::move(request),
+                     std::move(options), std::move(callback)));
+  return;
+}
+
+void PasskeyAuthenticator::FinishGetAssertion(CtapGetAssertionRequest request,
+                                              CtapGetAssertionOptions options,
+                                              GetAssertionCallback callback,
+                                              bool user_verification_success) {
+  if (!user_verification_success) {
+    std::move(callback).Run(CtapDeviceResponseCode::kCtap2ErrNoCredentials, {});
+    return;
+  }
+
+  CHECK_EQ(request.allow_list.size(), 1u);
+  const std::vector<uint8_t>& credential_id = request.allow_list.begin()->id;
+  const std::string credential_id_str = {credential_id.begin(),
+                                         credential_id.end()};
+
+  std::optional<sync_pb::WebauthnCredentialSpecifics> credential_specifics =
+      passkey_model_->GetPasskeyByCredentialId(request.rp_id,
+                                               credential_id_str);
+  if (!credential_specifics) {
+    FIDO_LOG(ERROR) << "Could not find a matching GPM credential.";
+    std::move(callback).Run(CtapDeviceResponseCode::kCtap2ErrNoCredentials, {});
+    return;
+  }
+
+  const std::optional<std::vector<uint8_t>> security_domain_secret =
+      passkey_service_->GetCachedSecurityDomainSecret();
+  if (!security_domain_secret) {
+    FIDO_LOG(ERROR) << "Security domain secret unavailable.";
+    std::move(callback).Run(CtapDeviceResponseCode::kCtap2ErrNoCredentials, {});
+    return;
+  }
+
+  // Decrypt the sealed data from `credential_specifics` into
+  // `credential_secrets`. Note that `DecryptWebauthnCredentialSpecificsData()`
+  // internally maps both the `encrypted` and `private_key` case of the
+  // `encrypted_data` oneof to `WebauthnCredentialSpecifics_Encrypted`. In the
+  // latter case, only the `private_key` field will be set.
+  sync_pb::WebauthnCredentialSpecifics_Encrypted unsealed_credential_secrets;
+  if (!webauthn::passkey_model_utils::DecryptWebauthnCredentialSpecificsData(
+          base::make_span(*security_domain_secret), *credential_specifics,
+          &unsealed_credential_secrets)) {
+    FIDO_LOG(ERROR) << "Decrypting WebauthnCredentialSpecifics failed.";
+    std::move(callback).Run(CtapDeviceResponseCode::kCtap2ErrNoCredentials, {});
+    return;
+  }
+
+  AuthenticatorData authenticator_data =
+      MakeAuthenticatorDataForAssertion(request.rp_id);
+  std::vector<uint8_t> signed_over_data(
+      authenticator_data.SerializeToByteArray());
+  signed_over_data.insert(signed_over_data.end(),
+                          request.client_data_hash.begin(),
+                          request.client_data_hash.end());
+  std::optional<std::vector<uint8_t>> assertion_signature = GenerateEcSignature(
+      base::as_byte_span(unsealed_credential_secrets.private_key()),
+      signed_over_data);
+  if (!assertion_signature) {
+    std::move(callback).Run(CtapDeviceResponseCode::kCtap2ErrNoCredentials, {});
+    return;
+  }
+
+  AuthenticatorGetAssertionResponse assertion_response(
+      std::move(authenticator_data), std::move(*assertion_signature),
+      /*transport_used=*/std::nullopt);
+  assertion_response.credential =
+      PublicKeyCredentialDescriptor(CredentialType::kPublicKey, credential_id);
+  assertion_response.user_entity = PublicKeyCredentialUserEntity(
+      std::vector<uint8_t>(credential_specifics->user_id().begin(),
+                           credential_specifics->user_id().end()));
+  std::vector<AuthenticatorGetAssertionResponse> responses;
+  responses.emplace_back(std::move(assertion_response));
+  std::move(callback).Run(CtapDeviceResponseCode::kSuccess,
+                          std::move(responses));
+}
+
+void PasskeyAuthenticator::GetPlatformCredentialInfoForRequest(
+    const CtapGetAssertionRequest& request,
+    const CtapGetAssertionOptions& options,
+    GetPlatformCredentialInfoForRequestCallback callback) {
+  std::move(callback).Run(
+      {},
+      FidoRequestHandlerBase::RecognizedCredential::kHasRecognizedCredential);
+}
+
+void PasskeyAuthenticator::Cancel() {
+  NOTIMPLEMENTED();
+}
+
+base::WeakPtr<FidoAuthenticator> PasskeyAuthenticator::GetWeakPtr() {
+  return weak_factory_.GetWeakPtr();
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/webauthn/chromeos/passkey_authenticator.h b/chrome/browser/webauthn/chromeos/passkey_authenticator.h
new file mode 100644
index 0000000..a053ef8
--- /dev/null
+++ b/chrome/browser/webauthn/chromeos/passkey_authenticator.h
@@ -0,0 +1,75 @@
+// 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 CHROME_BROWSER_WEBAUTHN_CHROMEOS_PASSKEY_AUTHENTICATOR_H_
+#define CHROME_BROWSER_WEBAUTHN_CHROMEOS_PASSKEY_AUTHENTICATOR_H_
+
+#include <string>
+
+#include "base/functional/callback_forward.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "content/public/browser/global_routing_id.h"
+#include "device/fido/fido_authenticator.h"
+
+namespace content {
+class RenderFrameHost;
+}
+
+namespace webauthn {
+class PasskeyModel;
+}
+
+namespace chromeos {
+
+class PasskeyService;
+
+class PasskeyAuthenticator : public device::FidoAuthenticator {
+ public:
+  // `rfh`, `passkey_service` and `rfh` must be non-null and outlive the
+  // PasskeyAuthenticator.
+  PasskeyAuthenticator(content::RenderFrameHost* rfh,
+                       PasskeyService* passkey_service,
+                       webauthn::PasskeyModel* model);
+  ~PasskeyAuthenticator() override;
+
+  // device::FidoAuthenticator:
+  void InitializeAuthenticator(base::OnceClosure callback) override;
+  std::optional<base::span<const int32_t>> GetAlgorithms() override;
+  void MakeCredential(device::CtapMakeCredentialRequest request,
+                      device::MakeCredentialOptions request_options,
+                      MakeCredentialCallback callback) override;
+  void GetAssertion(device::CtapGetAssertionRequest request,
+                    device::CtapGetAssertionOptions options,
+                    GetAssertionCallback callback) override;
+  void GetPlatformCredentialInfoForRequest(
+      const device::CtapGetAssertionRequest& request,
+      const device::CtapGetAssertionOptions& options,
+      GetPlatformCredentialInfoForRequestCallback callback) override;
+  void Cancel() override;
+  device::AuthenticatorType GetType() const override;
+  std::string GetId() const override;
+  const device::AuthenticatorSupportedOptions& Options() const override;
+  std::optional<device::FidoTransportProtocol> AuthenticatorTransport()
+      const override;
+  void GetTouch(base::OnceClosure callback) override;
+
+  base::WeakPtr<FidoAuthenticator> GetWeakPtr() override;
+
+ private:
+  const content::GlobalRenderFrameHostId render_frame_host_id_;
+  const raw_ptr<PasskeyService> passkey_service_;
+  const raw_ptr<webauthn::PasskeyModel> passkey_model_;
+
+  void FinishGetAssertion(device::CtapGetAssertionRequest request,
+                          device::CtapGetAssertionOptions options,
+                          GetAssertionCallback callback,
+                          bool user_verification_success);
+
+  base::WeakPtrFactory<PasskeyAuthenticator> weak_factory_{this};
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_WEBAUTHN_CHROMEOS_PASSKEY_AUTHENTICATOR_H_
diff --git a/chrome/browser/webauthn/chromeos/passkey_dialog_controller.cc b/chrome/browser/webauthn/chromeos/passkey_dialog_controller.cc
index 27cec94..9172c20 100644
--- a/chrome/browser/webauthn/chromeos/passkey_dialog_controller.cc
+++ b/chrome/browser/webauthn/chromeos/passkey_dialog_controller.cc
@@ -94,7 +94,6 @@
     std::vector<uint8_t> credential_id) {
   // FetchAccountState() should have completed before the UI was shown.
   CHECK(account_state_);
-
   switch (*account_state_) {
     case PasskeyService::AccountState::kError:
     case PasskeyService::AccountState::kEmpty:
@@ -123,7 +122,7 @@
 }
 
 void PasskeyDialogController::StartAuthenticatorRequest() {
-  // TODO: Dispatch request to the authenticator.
+  dialog_model_->OnChromeOSGPMRequestReady();
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/webauthn/chromeos/passkey_discovery.cc b/chrome/browser/webauthn/chromeos/passkey_discovery.cc
new file mode 100644
index 0000000..f7f716e0
--- /dev/null
+++ b/chrome/browser/webauthn/chromeos/passkey_discovery.cc
@@ -0,0 +1,44 @@
+// 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 "chrome/browser/webauthn/chromeos/passkey_discovery.h"
+
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/task/sequenced_task_runner.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/webauthn/chromeos/passkey_service_factory.h"
+#include "chrome/browser/webauthn/passkey_model_factory.h"
+#include "content/public/browser/render_frame_host.h"
+#include "device/fido/fido_authenticator.h"
+#include "device/fido/fido_transport_protocol.h"
+
+namespace chromeos {
+
+PasskeyDiscovery::PasskeyDiscovery(content::RenderFrameHost* rfh)
+    : FidoDiscoveryBase(device::FidoTransportProtocol::kInternal),
+      render_frame_host_id_(rfh->GetGlobalId()) {}
+
+PasskeyDiscovery::~PasskeyDiscovery() = default;
+
+void PasskeyDiscovery::Start() {
+  base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
+      FROM_HERE, base::BindOnce(&PasskeyDiscovery::StartDiscovery,
+                                weak_factory_.GetWeakPtr()));
+}
+
+void PasskeyDiscovery::StartDiscovery() {
+  auto* rfh = content::RenderFrameHost::FromID(render_frame_host_id_);
+  CHECK(rfh);
+  auto* profile = Profile::FromBrowserContext(rfh->GetBrowserContext());
+  auto authenticator = std::make_unique<PasskeyAuthenticator>(
+      rfh, PasskeyServiceFactory::GetForProfile(profile),
+      PasskeyModelFactory::GetForProfile(profile));
+  auto* ptr = authenticator.get();
+  authenticators_.emplace_back(std::move(authenticator));
+  observer()->DiscoveryStarted(this, /*success=*/true, {ptr});
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/webauthn/chromeos/passkey_discovery.h b/chrome/browser/webauthn/chromeos/passkey_discovery.h
new file mode 100644
index 0000000..970348c
--- /dev/null
+++ b/chrome/browser/webauthn/chromeos/passkey_discovery.h
@@ -0,0 +1,44 @@
+// 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 CHROME_BROWSER_WEBAUTHN_CHROMEOS_PASSKEY_DISCOVERY_H_
+#define CHROME_BROWSER_WEBAUTHN_CHROMEOS_PASSKEY_DISCOVERY_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/webauthn/chromeos/passkey_authenticator.h"
+#include "content/public/browser/global_routing_id.h"
+#include "device/fido/fido_discovery_base.h"
+
+namespace content {
+class RenderFrameHost;
+}
+
+namespace chromeos {
+
+class PasskeyAuthenticator;
+
+class PasskeyDiscovery : public device::FidoDiscoveryBase {
+ public:
+  explicit PasskeyDiscovery(content::RenderFrameHost* rfh);
+  ~PasskeyDiscovery() override;
+
+  void StartUI();
+
+  // device::FidoDiscoveryBase:
+  void Start() override;
+
+ private:
+  void StartDiscovery();
+
+  const content::GlobalRenderFrameHostId render_frame_host_id_;
+  std::vector<std::unique_ptr<PasskeyAuthenticator>> authenticators_;
+  base::WeakPtrFactory<PasskeyDiscovery> weak_factory_{this};
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_WEBAUTHN_CHROMEOS_PASSKEY_DISCOVERY_H_
diff --git a/chrome/browser/webauthn/chromeos/passkey_in_session_auth.cc b/chrome/browser/webauthn/chromeos/passkey_in_session_auth.cc
new file mode 100644
index 0000000..d787347
--- /dev/null
+++ b/chrome/browser/webauthn/chromeos/passkey_in_session_auth.cc
@@ -0,0 +1,104 @@
+// 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 "chrome/browser/webauthn/chromeos/passkey_in_session_auth.h"
+
+#include <string>
+
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
+#include "base/functional/callback_helpers.h"
+#include "base/logging.h"
+#include "base/notimplemented.h"
+#include "base/task/sequenced_task_runner.h"
+#include "components/device_event_log/device_event_log.h"
+#include "ui/aura/window.h"
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/public/cpp/in_session_auth_dialog_controller.h"
+#include "ash/public/cpp/webauthn_dialog_controller.h"
+#include "ash/shell.h"
+#include "chromeos/ash/components/osauth/public/common_types.h"
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+#include "chromeos/components/in_session_auth/mojom/in_session_auth.mojom.h"
+#include "chromeos/lacros/lacros_service.h"
+#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
+
+namespace chromeos {
+namespace {
+
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+void OnRequestToken(base::OnceCallback<void(bool)> callback,
+                    chromeos::auth::mojom::RequestTokenReplyPtr reply) {
+  std::move(callback).Run(/*success=*/!reply.is_null());
+}
+#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
+
+PasskeyInSessionAuthProvider* g_instance = nullptr;
+PasskeyInSessionAuthProvider* g_override = nullptr;
+
+class PasskeyInSessionAuthProviderImpl : public PasskeyInSessionAuthProvider {
+ public:
+  PasskeyInSessionAuthProviderImpl() = default;
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  void ShowPasskeyInSessionAuthDialog(
+      aura::Window* window,
+      const std::string& rp_id,
+      base::OnceCallback<void(bool)> result_callback) override {
+    ash::Shell::Get()->webauthn_dialog_controller()->ShowAuthenticationDialog(
+        window, rp_id, std::move(result_callback));
+  }
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+  void ShowPasskeyInSessionAuthDialog(
+      aura::Window* window,
+      const std::string& rp_id,
+      base::OnceCallback<void(bool)> result_callback) override {
+    auto* lacros_service = chromeos::LacrosService::Get();
+    if (!lacros_service->IsAvailable<chromeos::auth::mojom::InSessionAuth>() ||
+        lacros_service
+                ->GetInterfaceVersion<chromeos::auth::mojom::InSessionAuth>() <
+            static_cast<int>(chromeos::auth::mojom::InSessionAuth::
+                                 MethodMinVersions::kRequestTokenMinVersion)) {
+      FIDO_LOG(ERROR)
+          << "Failed to perform UV because InSessionAuth is not available";
+      std::move(result_callback).Run(false);
+      return;
+    }
+    // TODO(crbug.com/40187814): Implement a passkeys-specific in-session auth
+    // reason.
+    lacros_service->GetRemote<chromeos::auth::mojom::InSessionAuth>()
+        ->RequestToken(
+            chromeos::auth::mojom::Reason::kAccessPasswordManager, std::nullopt,
+            base::BindOnce(&OnRequestToken, std::move(result_callback)));
+  }
+#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
+};
+
+}  // namespace
+
+PasskeyInSessionAuthProvider::~PasskeyInSessionAuthProvider() = default;
+
+PasskeyInSessionAuthProvider* PasskeyInSessionAuthProvider::Get() {
+  if (g_override) {
+    return g_override;
+  }
+  if (!g_instance) {
+    g_instance = new PasskeyInSessionAuthProviderImpl();
+  }
+  return g_instance;
+}
+
+void PasskeyInSessionAuthProvider::SetInstanceForTesting(
+    PasskeyInSessionAuthProvider* test_override) {
+  CHECK(!g_override || !test_override)
+      << "Cannot override PasskeyInSessionAuthProvider twice.";
+  g_override = test_override;
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/webauthn/chromeos/passkey_in_session_auth.h b/chrome/browser/webauthn/chromeos/passkey_in_session_auth.h
new file mode 100644
index 0000000..039eb89
--- /dev/null
+++ b/chrome/browser/webauthn/chromeos/passkey_in_session_auth.h
@@ -0,0 +1,37 @@
+// 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 CHROME_BROWSER_WEBAUTHN_CHROMEOS_PASSKEY_IN_SESSION_AUTH_H_
+#define CHROME_BROWSER_WEBAUTHN_CHROMEOS_PASSKEY_IN_SESSION_AUTH_H_
+
+#include <string>
+
+#include "base/functional/callback_forward.h"
+
+namespace aura {
+class Window;
+}
+
+namespace chromeos {
+
+// PasskeyInSessionAuthProvider is responsible for showing the ChromeOS user
+// verification dialog when creating or asserting a passkey. It can be used from
+// Ash and Lacros.
+class PasskeyInSessionAuthProvider {
+ public:
+  static PasskeyInSessionAuthProvider* Get();
+  static void SetInstanceForTesting(
+      PasskeyInSessionAuthProvider* test_override);
+
+  virtual ~PasskeyInSessionAuthProvider();
+
+  virtual void ShowPasskeyInSessionAuthDialog(
+      aura::Window* window,
+      const std::string& rp_id,
+      base::OnceCallback<void(bool)> result_callback) = 0;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_WEBAUTHN_CHROMEOS_PASSKEY_IN_SESSION_AUTH_H_
diff --git a/chrome/browser/webauthn/chromeos/passkey_service.cc b/chrome/browser/webauthn/chromeos/passkey_service.cc
index 4db4c94..1f000c9 100644
--- a/chrome/browser/webauthn/chromeos/passkey_service.cc
+++ b/chrome/browser/webauthn/chromeos/passkey_service.cc
@@ -66,10 +66,18 @@
   MaybeFetchTrustedVaultKeys();
 }
 
+std::optional<std::vector<uint8_t>>
+PasskeyService::GetCachedSecurityDomainSecret() {
+  if (trusted_vault_keys_.empty()) {
+    return std::nullopt;
+  }
+  return trusted_vault_keys_.back();
+}
+
 void PasskeyService::UpdatePrimaryAccount() {
   CoreAccountInfo primary_account =
       identity_manager_->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin);
-  if (primary_account == primary_account_) {
+  if (primary_account.IsEmpty() || primary_account == primary_account_) {
     return;
   }
   primary_account_ = primary_account;
@@ -130,6 +138,8 @@
 
   if (pending_account_state_callbacks_.empty() ||
       download_account_state_request_) {
+    // No outstanding requests, or there is a download pending that will satisfy
+    // them.
     return;
   }
 
diff --git a/chrome/browser/webauthn/chromeos/passkey_service.h b/chrome/browser/webauthn/chromeos/passkey_service.h
index 3583a8d5..e9561b4 100644
--- a/chrome/browser/webauthn/chromeos/passkey_service.h
+++ b/chrome/browser/webauthn/chromeos/passkey_service.h
@@ -75,6 +75,11 @@
   // Determines the current `AccountState` for the current primary account.
   void FetchAccountState(AccountStateCallback callback);
 
+  // Returns the current security domain secret for the passkeys security domain
+  // if available locally. FetchAccountState() should be called to ensure the
+  // domain secret is available locally first.
+  std::optional<std::vector<uint8_t>> GetCachedSecurityDomainSecret();
+
  private:
   void UpdatePrimaryAccount();
   void MaybeFetchTrustedVaultKeys();
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index 9eedb824..d334e0c 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1715622766-5cb090821d5d16bde68a6bbd42cb8f45d7ae2227-6f0561e057c75258ac8117e57c522e67d9e20af8.profdata
+chrome-android32-main-1715644735-73fcb0819a8b6db969d12583ee03571994532f7c-7967106f59cbb413e347d9c054076ca515b0be2b.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index b6ba2b2..71d0785 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1715601385-1fd513ae21dcab09efc9ca050557f6b539be99ac-dc3597a14f378c1b6397ce86ac44ae90d3440f10.profdata
+chrome-android64-main-1715615885-e9b87cf3ecd1c33790ce4fd6639bbc583882a528-f04d604af99df4a19ecf107d691caf7f79804198.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 5518a71c..a7c5fda5 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1715630394-26b79fdefd6307362b180fbef8a9deda8bed8a3c-7e538fc99a79046208bfa1f5f97c9b49071199e5.profdata
+chrome-mac-arm-main-1715651842-4e4d55063246423ddb40964131a4b87aa78b70a5-df2a15d6120cdf013ec902b0e92a63217569d53a.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index 846d594..345ec40 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1715601385-171070fcc104542b9439c34d411a67443fa2f568-dc3597a14f378c1b6397ce86ac44ae90d3440f10.profdata
+chrome-win-arm64-main-1715644735-602295160645439e887257a489b5e86aa3abfbcb-7967106f59cbb413e347d9c054076ca515b0be2b.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index e78e5859..8e70508 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1715612211-5add684d131d8b2d2aa1e81bbec989b4db538837-4d9e27fa259eab864f3b87a5343cc75ba5c66e40.profdata
+chrome-win32-main-1715644735-8a983c56105ad936efb4f08f8d1979ae916c5edc-7967106f59cbb413e347d9c054076ca515b0be2b.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index c411e485..3a48ab4 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1715612211-b612959c3b1d8d9223490bfa1aad002a1d41f458-4d9e27fa259eab864f3b87a5343cc75ba5c66e40.profdata
+chrome-win64-main-1715644735-0f5bf6e802f1ce0a0ab96d8ff2a8e86c305a27fb-7967106f59cbb413e347d9c054076ca515b0be2b.profdata
diff --git a/chrome/common/chrome_render_frame.mojom b/chrome/common/chrome_render_frame.mojom
index 1c86d26..1a382d2 100644
--- a/chrome/common/chrome_render_frame.mojom
+++ b/chrome/common/chrome_render_frame.mojom
@@ -34,6 +34,14 @@
   // Requests the bitmap selected by the most recently opened context menu.
   RequestBitmapForContextNode() => (skia.mojom.BitmapN32? bitmap);
 
+  // Requests the bounds of the image selected by the most recently opened
+  // context menu. Note that the bounds originate from the DOM layer, and no
+  // guarantee is made about their correlation with the bounds of the image as
+  // displayed in the presentation layer. The returned bounds are also not
+  // guaranteed to correspond to the result of calling
+  // RequestBitmapForContextNode().
+  RequestBoundsForContextNodeDiagnostic() => (gfx.mojom.Rect bounds);
+
   // Requests an encoded image selected by the most recently opened context
   // menu. The encoding format is specified as a parameter. If no image is
   // selected or there's an error capturing the image, |image_data| will be
diff --git a/chrome/renderer/chrome_render_frame_observer.cc b/chrome/renderer/chrome_render_frame_observer.cc
index c7074ab..2eb9760f 100644
--- a/chrome/renderer/chrome_render_frame_observer.cc
+++ b/chrome/renderer/chrome_render_frame_observer.cc
@@ -509,6 +509,20 @@
   std::move(callback).Run(image);
 }
 
+void ChromeRenderFrameObserver::RequestBoundsForContextNodeDiagnostic(
+    RequestBoundsForContextNodeDiagnosticCallback callback) {
+  WebNode context_node = render_frame()->GetWebFrame()->ContextMenuImageNode();
+  gfx::Rect bounds;
+  if (context_node.IsNull() || !context_node.IsElementNode()) {
+    std::move(callback).Run(bounds);
+    return;
+  }
+
+  WebElement web_element = context_node.To<WebElement>();
+  bounds = web_element.BoundsInWidget();
+  std::move(callback).Run(bounds);
+}
+
 void ChromeRenderFrameObserver::RequestReloadImageForContextNode() {
   WebLocalFrame* frame = render_frame()->GetWebFrame();
   // TODO(dglazkov): This code is clearly in the wrong place. Need
diff --git a/chrome/renderer/chrome_render_frame_observer.h b/chrome/renderer/chrome_render_frame_observer.h
index 8a9172e0f..458d9946 100644
--- a/chrome/renderer/chrome_render_frame_observer.h
+++ b/chrome/renderer/chrome_render_frame_observer.h
@@ -101,6 +101,8 @@
       RequestImageForContextNodeCallback callback) override;
   void RequestBitmapForContextNode(
       RequestBitmapForContextNodeCallback callback) override;
+  void RequestBoundsForContextNodeDiagnostic(
+      RequestBoundsForContextNodeDiagnosticCallback callback) override;
   void RequestReloadImageForContextNode() override;
 #if BUILDFLAG(IS_ANDROID)
   void SetCCTClientHeader(const std::string& header) override;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 415c81d..b5512af 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -6930,8 +6930,8 @@
     "//components/country_codes",
     "//components/custom_handlers",
     "//components/custom_handlers:test_support",
+    "//components/data_sharing:test_support",
     "//components/data_sharing/internal",
-    "//components/data_sharing/internal:test_support",
     "//components/data_sharing/public",
     "//components/device_reauth",
     "//components/device_signals/core/browser",
diff --git a/chrome/test/data/arc_graphics_tracing/gem_objects b/chrome/test/data/arc_overview_tracing/gem_objects
similarity index 100%
rename from chrome/test/data/arc_graphics_tracing/gem_objects
rename to chrome/test/data/arc_overview_tracing/gem_objects
diff --git a/chrome/test/data/arc_graphics_tracing/gm_bad_no_view_buffers.json b/chrome/test/data/arc_overview_tracing/gm_bad_no_view_buffers.json
similarity index 100%
rename from chrome/test/data/arc_graphics_tracing/gm_bad_no_view_buffers.json
rename to chrome/test/data/arc_overview_tracing/gm_bad_no_view_buffers.json
diff --git a/chrome/test/data/arc_graphics_tracing/gm_bad_no_view_desc.json b/chrome/test/data/arc_overview_tracing/gm_bad_no_view_desc.json
similarity index 100%
rename from chrome/test/data/arc_graphics_tracing/gm_bad_no_view_desc.json
rename to chrome/test/data/arc_overview_tracing/gm_bad_no_view_desc.json
diff --git a/chrome/test/data/arc_graphics_tracing/gm_bad_wrong_timestamp.json b/chrome/test/data/arc_overview_tracing/gm_bad_wrong_timestamp.json
similarity index 100%
rename from chrome/test/data/arc_graphics_tracing/gm_bad_wrong_timestamp.json
rename to chrome/test/data/arc_overview_tracing/gm_bad_wrong_timestamp.json
diff --git a/chrome/test/data/arc_graphics_tracing/gm_good.json b/chrome/test/data/arc_overview_tracing/gm_good.json
similarity index 100%
rename from chrome/test/data/arc_graphics_tracing/gm_good.json
rename to chrome/test/data/arc_overview_tracing/gm_good.json
diff --git a/chrome/test/data/arc_graphics_tracing/proc_meminfo b/chrome/test/data/arc_overview_tracing/proc_meminfo
similarity index 100%
rename from chrome/test/data/arc_graphics_tracing/proc_meminfo
rename to chrome/test/data/arc_overview_tracing/proc_meminfo
diff --git a/chrome/test/data/arc_graphics_tracing/system_stat_collector b/chrome/test/data/arc_overview_tracing/system_stat_collector
similarity index 100%
rename from chrome/test/data/arc_graphics_tracing/system_stat_collector
rename to chrome/test/data/arc_overview_tracing/system_stat_collector
diff --git a/chrome/test/data/arc_graphics_tracing/temp1_input b/chrome/test/data/arc_overview_tracing/temp1_input
similarity index 100%
rename from chrome/test/data/arc_graphics_tracing/temp1_input
rename to chrome/test/data/arc_overview_tracing/temp1_input
diff --git a/chrome/test/data/arc_graphics_tracing/trace.dat.gz b/chrome/test/data/arc_overview_tracing/trace.dat.gz
similarity index 100%
rename from chrome/test/data/arc_graphics_tracing/trace.dat.gz
rename to chrome/test/data/arc_overview_tracing/trace.dat.gz
Binary files differ
diff --git a/chrome/test/data/arc_graphics_tracing/trace_async_events.json b/chrome/test/data/arc_overview_tracing/trace_async_events.json
similarity index 100%
rename from chrome/test/data/arc_graphics_tracing/trace_async_events.json
rename to chrome/test/data/arc_overview_tracing/trace_async_events.json
diff --git a/chrome/test/data/arc_graphics_tracing/trace_input.dat.gz b/chrome/test/data/arc_overview_tracing/trace_input.dat.gz
similarity index 100%
rename from chrome/test/data/arc_graphics_tracing/trace_input.dat.gz
rename to chrome/test/data/arc_overview_tracing/trace_input.dat.gz
Binary files differ
diff --git a/chrome/test/data/arc_graphics_tracing/trace_time.dat b/chrome/test/data/arc_overview_tracing/trace_time.dat
similarity index 100%
rename from chrome/test/data/arc_graphics_tracing/trace_time.dat
rename to chrome/test/data/arc_overview_tracing/trace_time.dat
diff --git a/chrome/test/data/arc_graphics_tracing/zram_stat b/chrome/test/data/arc_overview_tracing/zram_stat
similarity index 100%
rename from chrome/test/data/arc_graphics_tracing/zram_stat
rename to chrome/test/data/arc_overview_tracing/zram_stat
Binary files differ
diff --git a/chrome/test/data/banners/manifest_tabbed_display_override.json b/chrome/test/data/banners/manifest_tabbed_display_override.json
index e310d53..2fa9b152 100644
--- a/chrome/test/data/banners/manifest_tabbed_display_override.json
+++ b/chrome/test/data/banners/manifest_tabbed_display_override.json
@@ -9,8 +9,5 @@
   ],
   "start_url": "manifest_test_page.html",
   "display": "standalone",
-  "display_override": [ "tabbed" ],
-  "tab_strip": {
-    "new_tab_button": "auto"
-  }
+  "display_override": [ "tabbed" ]
 }
\ No newline at end of file
diff --git a/chrome/test/data/webui/chromeos/os_feedback_ui/share_data_page_test.ts b/chrome/test/data/webui/chromeos/os_feedback_ui/share_data_page_test.ts
index e37b8b4..c08f853 100644
--- a/chrome/test/data/webui/chromeos/os_feedback_ui/share_data_page_test.ts
+++ b/chrome/test/data/webui/chromeos/os_feedback_ui/share_data_page_test.ts
@@ -1181,6 +1181,16 @@
   });
 
   /**
+   * Test that WifiDebugLogs dialog contains a title.
+   */
+  test('titleForWifiDebugLogsDialog', async () => {
+    await initializePage();
+    assertEquals(
+        'Sharing Wi-Fi Debug Logs',
+        getElementContent('#wifiDebugLogsDialogTitle'));
+  });
+
+  /**
    * Test that clicking the "View more details" link will open the dialog and
    * set the focus on the close dialog icon button.
    */
diff --git a/chrome/test/data/webui/chromeos/settings/BUILD.gn b/chrome/test/data/webui/chromeos/settings/BUILD.gn
index ea8022f..37c5b81 100644
--- a/chrome/test/data/webui/chromeos/settings/BUILD.gn
+++ b/chrome/test/data/webui/chromeos/settings/BUILD.gn
@@ -62,6 +62,7 @@
     "controls/settings_slider_test.ts",
     "controls/settings_toggle_button_test.ts",
 
+    "controls/v2/base_row_mixin_test.ts",
     "controls/v2/pref_control_mixin_internal_test.ts",
     "controls/v2/settings_dropdown_v2_test.ts",
     "controls/v2/settings_toggle_v2_test.ts",
diff --git a/chrome/test/data/webui/chromeos/settings/controls/v2/base_row_mixin_test.ts b/chrome/test/data/webui/chromeos/settings/controls/v2/base_row_mixin_test.ts
new file mode 100644
index 0000000..34d8571
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/settings/controls/v2/base_row_mixin_test.ts
@@ -0,0 +1,106 @@
+// 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 {BaseRowMixin} from 'chrome://os-settings/os_settings.js';
+import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {assertEquals, assertNull} from 'chrome://webui-test/chai_assert.js';
+import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
+
+import {clearBody} from '../../utils.js';
+
+const TestRowElementBase = BaseRowMixin(PolymerElement);
+class TestRowElement extends TestRowElementBase {}
+customElements.define('test-row-element', TestRowElement);
+
+suite('SettingsBaseRowMixin', () => {
+  let testRowElement: TestRowElement;
+  const label = 'test label';
+  const sublabel = 'test sublabel';
+  const icon = 'test icon';
+  const learnMoreUrl = 'chrome://os-settings/test';
+  const ariaLabel = 'test aria label';
+  const ariaDescription = 'test aria description';
+
+  setup(async () => {
+    clearBody();
+    testRowElement =
+        document.createElement('test-row-element') as TestRowElement;
+    document.body.appendChild(testRowElement);
+    await flushTasks();
+  });
+
+  suite('fundamental properties', () => {
+    test('label is set correctly', () => {
+      testRowElement.label = label;
+      assertEquals(label, testRowElement.label);
+    });
+
+    test('sublabel is set correctly', () => {
+      testRowElement.sublabel = sublabel;
+      assertEquals(sublabel, testRowElement.sublabel);
+    });
+
+    test('icon is set correctly', () => {
+      testRowElement.icon = icon;
+      assertEquals(icon, testRowElement.icon);
+    });
+
+    test('learnMoreUrl is set correctly', () => {
+      testRowElement.learnMoreUrl = learnMoreUrl;
+      assertEquals(learnMoreUrl, testRowElement.learnMoreUrl);
+      assertEquals(learnMoreUrl, testRowElement.getAttribute('learn-more-url'));
+    });
+
+    test('ariaLabel is set correctly', () => {
+      testRowElement.ariaLabel = ariaLabel;
+      assertEquals(ariaLabel, testRowElement.ariaLabel);
+      assertEquals(ariaLabel, testRowElement.getAttribute('aria-label'));
+    });
+
+    test('ariaDescription is set correctly', () => {
+      testRowElement.ariaDescription = ariaDescription;
+      assertEquals(ariaDescription, testRowElement.ariaDescription);
+      assertEquals(
+          ariaDescription, testRowElement.getAttribute('aria-description'));
+    });
+  });
+
+  suite('getAriaLabel()', () => {
+    test('should return null if neither label nor ariaLabel is defined', () => {
+      assertNull(testRowElement.getAriaLabel());
+    });
+
+    test('ariaLabel takes precedence when defined', () => {
+      testRowElement.label = label;
+
+      // `getAriaLabel` returns the value of `label` when `ariaLabel` is not
+      // defined.
+      assertEquals(label, testRowElement.getAriaLabel());
+
+      testRowElement.ariaLabel = ariaLabel;
+      // 'ariaLabel' takes precedence over `label` when it's set.
+      assertEquals(ariaLabel, testRowElement.getAriaLabel());
+    });
+  });
+
+  suite('getAriaDescription()', () => {
+    test(
+        'should return null if neither sublabel nor ariaDescription is defined',
+        () => {
+          assertNull(testRowElement.getAriaDescription());
+        });
+
+    test('ariaDescription takes precedence when defined', () => {
+      testRowElement.sublabel = sublabel;
+
+      // `getAriaDescription` returns the value of `sublabel` when
+      // `ariaDescription` is not defined.
+      assertEquals(sublabel, testRowElement.getAriaDescription());
+
+      testRowElement.ariaDescription = ariaDescription;
+      // 'ariaLabel' takes precedence over `label` when it's set.
+      assertEquals(ariaDescription, testRowElement.getAriaDescription());
+    });
+  });
+});
diff --git a/chrome/test/data/webui/chromeos/settings/os_settings_browsertest.cc b/chrome/test/data/webui/chromeos/settings/os_settings_browsertest.cc
index 916e5453..1297010 100644
--- a/chrome/test/data/webui/chromeos/settings/os_settings_browsertest.cc
+++ b/chrome/test/data/webui/chromeos/settings/os_settings_browsertest.cc
@@ -698,6 +698,10 @@
   RunSettingsTest("controls/settings_toggle_button_test.js");
 }
 
+IN_PROC_BROWSER_TEST_P(OSSettingsRevampMochaTest, BaseRowMixin) {
+  RunSettingsTest("controls/v2/base_row_mixin_test.js");
+}
+
 IN_PROC_BROWSER_TEST_P(OSSettingsRevampMochaTest, PrefControlMixinInternal) {
   RunSettingsTest("controls/v2/pref_control_mixin_internal_test.js");
 }
diff --git a/chrome/test/data/webui/cr_components/certificate_manager_v2_test.ts b/chrome/test/data/webui/cr_components/certificate_manager_v2_test.ts
index 287bb27..a037c204 100644
--- a/chrome/test/data/webui/cr_components/certificate_manager_v2_test.ts
+++ b/chrome/test/data/webui/cr_components/certificate_manager_v2_test.ts
@@ -116,8 +116,9 @@
   let certManager: CertificateManagerV2Element;
   let testProxy: TestCertificateManagerProxy;
 
-  setup(() => {
+  setup(async () => {
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
+    await navigator.clipboard.writeText('');
     testProxy = new TestCertificateManagerProxy();
     CertificatesV2BrowserProxy.setInstance(testProxy);
   });
@@ -127,7 +128,7 @@
     document.body.appendChild(certManager);
   }
 
-  test('Copy hash', async () => {
+  test('Copy CRS hash', async () => {
     const certs: SummaryCertInfo[] = [
       {
         'sha256hashHex': 'deadbeef',
@@ -144,8 +145,10 @@
     const certEntries =
         certManager.$.crsCerts.querySelectorAll('certificate-entry-v2');
     assertEquals(1, certEntries.length, 'no certs found');
+    assertEquals('', await navigator.clipboard.readText());
     certEntries[0]!.$.copy.click();
     assertTrue(certManager.$.toast.open);
+    assertEquals('deadbeef', await navigator.clipboard.readText());
   });
 
   test('CRS list populated', async () => {
@@ -192,8 +195,8 @@
   test('platform client certs populated', async () => {
     const certs: SummaryCertInfo[] = [
       {
-        'sha256hashHex': 'deadbeef',
-        'displayName': 'cert1',
+        'sha256hashHex': 'deadbeef2',
+        'displayName': 'cert2',
       },
     ];
     testProxy.handler.setPlatformClientCerts(certs);
@@ -201,21 +204,28 @@
 
     await testProxy.handler.whenCalled('getPlatformClientCerts');
     await microtasksFinished();
+    assertFalse(certManager.$.toast.open);
 
     const parent_element =
         certManager.shadowRoot!.querySelector('#platform-client-certs');
     assertTrue(!!parent_element, 'parent element not found');
-    const matchEls = parent_element.querySelectorAll('.cert-row');
+    const matchEls = parent_element.querySelectorAll('certificate-entry-v2');
     assertEquals(1, matchEls.length, 'no certs displayed');
-    // TODO(crbug.com/40928765): test the displayed name/hash
+    assertEquals('cert2', matchEls[0]!.displayName);
+    assertEquals('deadbeef2', matchEls[0]!.sha256hashHex);
+
+    assertEquals('', await navigator.clipboard.readText());
+    matchEls[0]!.$.copy.click();
+    assertTrue(certManager.$.toast.open);
+    assertEquals('deadbeef2', await navigator.clipboard.readText());
   });
 
   test('provisioned client certs populated', async () => {
     // <if expr="is_win or is_macosx">
     const certs: SummaryCertInfo[] = [
       {
-        'sha256hashHex': 'deadbeef',
-        'displayName': 'cert1',
+        'sha256hashHex': 'deadbeef3',
+        'displayName': 'cert3',
       },
     ];
     testProxy.handler.setProvisionedClientCerts(certs);
@@ -226,15 +236,22 @@
     await testProxy.handler.whenCalled('getProvisionedClientCerts');
     // </if>
     await microtasksFinished();
+    assertFalse(certManager.$.toast.open);
 
     const parent_element =
         certManager.shadowRoot!.querySelector('#provisioned-client-certs');
 
     // <if expr="is_win or is_macosx">
     assertTrue(!!parent_element, 'parent element not found');
-    const matchEls = parent_element.querySelectorAll('.cert-row');
+    const matchEls = parent_element.querySelectorAll('certificate-entry-v2');
     assertEquals(1, matchEls.length, 'no certs displayed');
-    // TODO(crbug.com/40928765): test the displayed name/hash
+    assertEquals('cert3', matchEls[0]!.displayName);
+    assertEquals('deadbeef3', matchEls[0]!.sha256hashHex);
+
+    assertEquals('', await navigator.clipboard.readText());
+    matchEls[0]!.$.copy.click();
+    assertTrue(certManager.$.toast.open);
+    assertEquals('deadbeef3', await navigator.clipboard.readText());
     // </if>
 
     // <if expr="not (is_win or is_macosx)">
diff --git a/chrome/test/data/webui/extensions/mv2_deprecation_panel_test.ts b/chrome/test/data/webui/extensions/mv2_deprecation_panel_test.ts
index 0bdbf9ee..36b5322 100644
--- a/chrome/test/data/webui/extensions/mv2_deprecation_panel_test.ts
+++ b/chrome/test/data/webui/extensions/mv2_deprecation_panel_test.ts
@@ -36,8 +36,8 @@
   });
 
   test('header content is always visible', function() {
-    assertTrue(
-        isVisible(panelElement.shadowRoot!.querySelector('.header-text')));
+    assertTrue(isVisible(
+        panelElement.shadowRoot!.querySelector('.panel-header-text')));
     assertTrue(
         isVisible(panelElement.shadowRoot!.querySelector('.header-button')));
   });
diff --git a/chrome/test/data/webui/lens/BUILD.gn b/chrome/test/data/webui/lens/BUILD.gn
index 0c282d4..8429a28 100644
--- a/chrome/test/data/webui/lens/BUILD.gn
+++ b/chrome/test/data/webui/lens/BUILD.gn
@@ -9,6 +9,7 @@
   files = [
     "overlay/overlay_background_scrim_test.ts",
     "overlay/overlay_close_button_test.ts",
+    "overlay/overlay_escape_key_test.ts",
     "overlay/overlay_feedback_button_test.ts",
     "overlay/post_selection_renderer_test.ts",
     "overlay/overlay_screenshot_test.ts",
@@ -19,6 +20,7 @@
     "overlay/region_selection_test.ts",
     "side_panel/results_frame_test.ts",
     "side_panel/searchbox_back_button_test.ts",
+    "side_panel/side_panel_escape_key_test.ts",
     "side_panel/test_side_panel_browser_proxy.ts",
     "utils/object_utils.ts",
     "utils/selection_utils.ts",
diff --git a/chrome/test/data/webui/lens/lens_webui_browsertest.cc b/chrome/test/data/webui/lens/lens_webui_browsertest.cc
index fa3474e7..a973bbaa 100644
--- a/chrome/test/data/webui/lens/lens_webui_browsertest.cc
+++ b/chrome/test/data/webui/lens/lens_webui_browsertest.cc
@@ -118,6 +118,10 @@
   RunOverlayTest("lens/overlay/overlay_close_button_test.js", "mocha.run()");
 }
 
+IN_PROC_BROWSER_TEST_F(LensOverlayTest, OverlayEscapeKey) {
+  RunOverlayTest("lens/overlay/overlay_escape_key_test.js", "mocha.run()");
+}
+
 IN_PROC_BROWSER_TEST_F(LensOverlayTest, OverlayFeedbackButton) {
   RunOverlayTest("lens/overlay/overlay_feedback_button_test.js", "mocha.run()");
 }
@@ -156,4 +160,8 @@
                  "mocha.run()");
 }
 
+IN_PROC_BROWSER_TEST_F(LensSidePanelTest, SidePanelEscapeKey) {
+  RunOverlayTest("lens/side_panel/side_panel_escape_key_test.js",
+                 "mocha.run()");
+}
 }  // namespace
diff --git a/chrome/test/data/webui/lens/overlay/overlay_escape_key_test.ts b/chrome/test/data/webui/lens/overlay/overlay_escape_key_test.ts
new file mode 100644
index 0000000..947842bd
--- /dev/null
+++ b/chrome/test/data/webui/lens/overlay/overlay_escape_key_test.ts
@@ -0,0 +1,37 @@
+// 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 'chrome-untrusted://lens/lens_overlay_app.js';
+
+import {BrowserProxyImpl} from 'chrome-untrusted://lens/browser_proxy.js';
+import type {LensOverlayAppElement} from 'chrome-untrusted://lens/lens_overlay_app.js';
+import {waitBeforeNextRender} from 'chrome-untrusted://webui-test/polymer_test_util.js';
+
+import {TestLensOverlayBrowserProxy} from './test_overlay_browser_proxy.js';
+
+suite('OverlayEscapeKey', () => {
+  let testBrowserProxy: TestLensOverlayBrowserProxy;
+  let lensOverlayElement: LensOverlayAppElement;
+
+  setup(() => {
+    // Resetting the HTML needs to be the first thing we do in setup to
+    // guarantee that any singleton instances don't change while any UI is still
+    // attached to the DOM.
+    document.body.innerHTML = window.trustedTypes!.emptyHTML;
+
+    testBrowserProxy = new TestLensOverlayBrowserProxy();
+    BrowserProxyImpl.setInstance(testBrowserProxy);
+
+    lensOverlayElement = document.createElement('lens-overlay-app');
+    document.body.appendChild(lensOverlayElement);
+    return waitBeforeNextRender(lensOverlayElement);
+  });
+
+  test('EscapeKeyPressClosesOverlay', () => {
+    lensOverlayElement.dispatchEvent(
+        new KeyboardEvent('keyup', {bubbles: true, key: 'Escape'}));
+    return testBrowserProxy.handler.whenCalled(
+        'closeRequestedByOverlayEscapeKeyPress');
+  });
+});
diff --git a/chrome/test/data/webui/lens/overlay/overlay_screenshot_test.ts b/chrome/test/data/webui/lens/overlay/overlay_screenshot_test.ts
index 3173133..c994568a 100644
--- a/chrome/test/data/webui/lens/overlay/overlay_screenshot_test.ts
+++ b/chrome/test/data/webui/lens/overlay/overlay_screenshot_test.ts
@@ -7,8 +7,9 @@
 import type {BigBuffer} from '//resources/mojo/mojo/public/mojom/base/big_buffer.mojom-webui.js';
 import {BrowserProxyImpl} from 'chrome-untrusted://lens/browser_proxy.js';
 import type {LensOverlayAppElement} from 'chrome-untrusted://lens/lens_overlay_app.js';
-import {assertNull, assertTrue} from 'chrome-untrusted://webui-test/chai_assert.js';
+import {assertFalse, assertTrue} from 'chrome-untrusted://webui-test/chai_assert.js';
 import {waitAfterNextRender} from 'chrome-untrusted://webui-test/polymer_test_util.js';
+import {hasStyle} from 'chrome-untrusted://webui-test/test_util.js';
 
 import {TestLensOverlayBrowserProxy} from './test_overlay_browser_proxy.js';
 
@@ -36,15 +37,15 @@
     return waitAfterNextRender(lensOverlayElement);
   });
 
-  // Verify selection overlay is not present until screenshot data URI is
-  // received
+  // Verify selection overlay is hidden until screenshot data URI is received
   test('ShowSelectionOverlay', async () => {
     const appContainerBeforeScreenshot =
         lensOverlayElement.shadowRoot!.querySelector('.app-container');
     assertTrue(!!appContainerBeforeScreenshot);
     const selectionOverlayBeforeScreenshot =
         appContainerBeforeScreenshot.querySelector('lens-selection-overlay');
-    assertNull(selectionOverlayBeforeScreenshot);
+    assertTrue(!!selectionOverlayBeforeScreenshot);
+    assertTrue(hasStyle(selectionOverlayBeforeScreenshot, 'display', 'none'));
 
     const dataUriBytes = new TextEncoder().encode(SCREENSHOT_DATA_URI);
     // The following struct needs to be casted as BigBuffer in order to set
@@ -63,5 +64,6 @@
     const selectionOverlay =
         appContainer.querySelector('lens-selection-overlay');
     assertTrue(!!selectionOverlay);
+    assertFalse(hasStyle(selectionOverlayBeforeScreenshot, 'display', 'none'));
   });
 });
diff --git a/chrome/test/data/webui/lens/overlay/test_overlay_browser_proxy.ts b/chrome/test/data/webui/lens/overlay/test_overlay_browser_proxy.ts
index ab907f43..9fa810d1 100644
--- a/chrome/test/data/webui/lens/overlay/test_overlay_browser_proxy.ts
+++ b/chrome/test/data/webui/lens/overlay/test_overlay_browser_proxy.ts
@@ -18,6 +18,7 @@
     super([
       'closeRequestedByOverlayCloseButton',
       'closeRequestedByOverlayBackgroundClick',
+      'closeRequestedByOverlayEscapeKeyPress',
       'addBackgroundBlur',
       'closeSearchBubble',
       'feedbackRequestedByOverlay',
@@ -34,6 +35,10 @@
     this.methodCalled('closeRequestedByOverlayBackgroundClick');
   }
 
+  closeRequestedByOverlayEscapeKeyPress() {
+    this.methodCalled('closeRequestedByOverlayEscapeKeyPress');
+  }
+
   addBackgroundBlur() {
     this.methodCalled('addBackgroundBlur');
   }
diff --git a/chrome/test/data/webui/lens/side_panel/side_panel_escape_key_test.ts b/chrome/test/data/webui/lens/side_panel/side_panel_escape_key_test.ts
new file mode 100644
index 0000000..0c8958b9a
--- /dev/null
+++ b/chrome/test/data/webui/lens/side_panel/side_panel_escape_key_test.ts
@@ -0,0 +1,31 @@
+// 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 'chrome-untrusted://lens/side_panel/side_panel_app.js';
+
+import type {LensSidePanelAppElement} from 'chrome-untrusted://lens/side_panel/side_panel_app.js';
+import {SidePanelBrowserProxyImpl} from 'chrome-untrusted://lens/side_panel/side_panel_browser_proxy.js';
+
+import {TestLensSidePanelBrowserProxy} from './test_side_panel_browser_proxy.js';
+
+suite('SidePanelEscapeKey', () => {
+  let testBrowserProxy: TestLensSidePanelBrowserProxy;
+  let lensSidePanelElement: LensSidePanelAppElement;
+
+  setup(() => {
+    testBrowserProxy = new TestLensSidePanelBrowserProxy();
+    SidePanelBrowserProxyImpl.setInstance(testBrowserProxy);
+
+    document.body.innerHTML = window.trustedTypes!.emptyHTML;
+    lensSidePanelElement = document.createElement('lens-side-panel-app');
+    document.body.appendChild(lensSidePanelElement);
+  });
+
+  test('EscapeKeyPressClosesOverlay', () => {
+    lensSidePanelElement.dispatchEvent(
+        new KeyboardEvent('keyup', {bubbles: true, key: 'Escape'}));
+    return testBrowserProxy.handler.whenCalled(
+        'closeRequestedBySidePanelEscapeKeyPress');
+  });
+});
diff --git a/chrome/test/data/webui/lens/side_panel/test_side_panel_browser_proxy.ts b/chrome/test/data/webui/lens/side_panel/test_side_panel_browser_proxy.ts
index 1b594f9..b5a5cdd 100644
--- a/chrome/test/data/webui/lens/side_panel/test_side_panel_browser_proxy.ts
+++ b/chrome/test/data/webui/lens/side_panel/test_side_panel_browser_proxy.ts
@@ -14,10 +14,15 @@
     LensSidePanelPageHandlerInterface {
   constructor() {
     super([
+      'closeRequestedBySidePanelEscapeKeyPress',
       'popAndLoadQueryFromHistory',
     ]);
   }
 
+  closeRequestedBySidePanelEscapeKeyPress() {
+    this.methodCalled('closeRequestedBySidePanelEscapeKeyPress');
+  }
+
   popAndLoadQueryFromHistory() {
     this.methodCalled('popAndLoadQueryFromHistory');
   }
diff --git a/chrome/test/data/webui/settings/basic_page_test.ts b/chrome/test/data/webui/settings/basic_page_test.ts
index fb715e01..ff850d0 100644
--- a/chrome/test/data/webui/settings/basic_page_test.ts
+++ b/chrome/test/data/webui/settings/basic_page_test.ts
@@ -113,7 +113,7 @@
     }
 
     // Set the visibility of the pages under test to their default value.
-    page.pageVisibility = pageVisibility;
+    page.pageVisibility = pageVisibility || {};
     flush();
 
     // When enabled, SafetyHub replaces SafetyCheck by default.
@@ -469,7 +469,7 @@
 
   test('performanceSectionTitlesVisible', async function() {
     await createNewBasicPage();
-    page.pageVisibility = pageVisibility;
+    page.pageVisibility = pageVisibility || {};
     flush();
 
     assertEquals(
@@ -488,7 +488,7 @@
   test('performanceVisibilityTestFeaturesAvailable', async function() {
     await createNewBasicPage();
     // Set the visibility of the pages under test to their default value.
-    page.pageVisibility = pageVisibility;
+    page.pageVisibility = pageVisibility || {};
     flush();
 
     assertTrue(
@@ -520,7 +520,7 @@
 
   test('performanceVisibilityTestDeviceHasBattery', async function() {
     await createNewBasicPage();
-    page.pageVisibility = pageVisibility;
+    page.pageVisibility = pageVisibility || {};
     flush();
 
     await performanceBrowserProxy.whenCalled('getDeviceHasBattery');
@@ -567,7 +567,7 @@
     }
 
     // Set the visibility of the pages under test to their default value.
-    page.pageVisibility = pageVisibility;
+    page.pageVisibility = pageVisibility || {};
     flush();
 
     assertTrue(
@@ -589,7 +589,7 @@
     }
 
     // Set the visibility of the pages under test to their default value.
-    page.pageVisibility = pageVisibility;
+    page.pageVisibility = pageVisibility || {};
     flush();
 
     assertFalse(
diff --git a/chrome/test/data/webui/settings/people_page_test.ts b/chrome/test/data/webui/settings/people_page_test.ts
index 170260f7..90396e0 100644
--- a/chrome/test/data/webui/settings/people_page_test.ts
+++ b/chrome/test/data/webui/settings/people_page_test.ts
@@ -62,7 +62,7 @@
 
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
     peoplePage = document.createElement('settings-people-page');
-    peoplePage.pageVisibility = pageVisibility;
+    peoplePage.pageVisibility = pageVisibility || {};
     document.body.appendChild(peoplePage);
 
     await syncBrowserProxy.whenCalled('getSyncStatus');
@@ -114,7 +114,7 @@
 
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
     peoplePage = document.createElement('settings-people-page');
-    peoplePage.pageVisibility = pageVisibility;
+    peoplePage.pageVisibility = pageVisibility || {};
     document.body.appendChild(peoplePage);
   });
 
@@ -155,7 +155,7 @@
 
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
     peoplePage = document.createElement('settings-people-page');
-    peoplePage.pageVisibility = pageVisibility;
+    peoplePage.pageVisibility = pageVisibility || {};
     document.body.appendChild(peoplePage);
   });
 
@@ -505,7 +505,7 @@
 
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
     peoplePage = document.createElement('settings-people-page');
-    peoplePage.pageVisibility = pageVisibility;
+    peoplePage.pageVisibility = pageVisibility || {};
     document.body.appendChild(peoplePage);
 
     await syncBrowserProxy.whenCalled('getSyncStatus');
diff --git a/chrome/test/data/webui/settings/people_page_test_cros.ts b/chrome/test/data/webui/settings/people_page_test_cros.ts
index a056b6e..d8b7869 100644
--- a/chrome/test/data/webui/settings/people_page_test_cros.ts
+++ b/chrome/test/data/webui/settings/people_page_test_cros.ts
@@ -80,7 +80,7 @@
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
     peoplePage = document.createElement('settings-people-page');
     peoplePage.prefs = DEFAULT_PREFS;
-    peoplePage.pageVisibility = pageVisibility;
+    peoplePage.pageVisibility = pageVisibility || {};
     document.body.appendChild(peoplePage);
 
     await accountManagerBrowserProxy.whenCalled('getAccounts');
@@ -139,7 +139,7 @@
     document.body.innerHTML = window.trustedTypes!.emptyHTML;
     peoplePage = document.createElement('settings-people-page');
     peoplePage.prefs = DEFAULT_PREFS;
-    peoplePage.pageVisibility = pageVisibility;
+    peoplePage.pageVisibility = pageVisibility || {};
     document.body.appendChild(peoplePage);
 
     await syncBrowserProxy.whenCalled('getSyncStatus');
diff --git a/chrome/test/data/webui/settings/route_test.ts b/chrome/test/data/webui/settings/route_test.ts
index 0b30bf7..b5efbaa 100644
--- a/chrome/test/data/webui/settings/route_test.ts
+++ b/chrome/test/data/webui/settings/route_test.ts
@@ -4,7 +4,7 @@
 
 // clang-format off
 import type {SettingsRoutes} from 'chrome://settings/settings.js';
-import {resetRouterForTesting, buildRouter, loadTimeData, Route, Router, routes, setPageVisibilityForTesting} from 'chrome://settings/settings.js';
+import {resetRouterForTesting, buildRouter, loadTimeData, Route, Router, routes, resetPageVisibilityForTesting} from 'chrome://settings/settings.js';
 import {assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
 import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
 
@@ -274,7 +274,7 @@
   });
 
   test('pageVisibility affects route availability', function() {
-    setPageVisibilityForTesting({
+    resetPageVisibilityForTesting({
       appearance: false,
       autofill: false,
       defaultBrowser: false,
diff --git a/chrome/test/data/webui/side_panel/read_anything/prefs_test.ts b/chrome/test/data/webui/side_panel/read_anything/prefs_test.ts
index 3117553..f9a0dc73 100644
--- a/chrome/test/data/webui/side_panel/read_anything/prefs_test.ts
+++ b/chrome/test/data/webui/side_panel/read_anything/prefs_test.ts
@@ -121,6 +121,15 @@
         assertEquals(selectedVoice(), otherVoice);
       });
 
+      test('to a default voice if the stored voice is invalid', () => {
+        // @ts-ignore
+        chrome.readingMode.getStoredVoice = () => 'Matt';
+        // @ts-ignore
+        app.enabledLanguagesInPref = [langForDefaultVoice];
+        app.restoreSettingsFromPrefs();
+        assertEquals(selectedVoice(), defaultVoice);
+      });
+
       suite('when there is no stored voice for this language', () => {
         setup(() => {
           chrome.readingMode.getStoredVoice = () => '';
@@ -134,11 +143,15 @@
           test('to the current voice if there is one', () => {
             // @ts-ignore
             app.selectedVoice = otherVoice;
+            // @ts-ignore
+            app.enabledLanguagesInPref = [otherVoice.lang];
             app.restoreSettingsFromPrefs();
             assertEquals(selectedVoice(), otherVoice);
           });
 
           test('to the device default if there\'s no current voice', () => {
+            // @ts-ignore
+            app.enabledLanguagesInPref = [langForDefaultVoice, otherVoice.lang];
             app.restoreSettingsFromPrefs();
             assertEquals(selectedVoice(), defaultVoice);
           });
diff --git a/chrome/test/ppapi/ppapi_test.cc b/chrome/test/ppapi/ppapi_test.cc
index b0dd8c4..d202623 100644
--- a/chrome/test/ppapi/ppapi_test.cc
+++ b/chrome/test/ppapi/ppapi_test.cc
@@ -144,8 +144,7 @@
   // These are needed to test that the right NetworkAnonymizationKey is used.
   scoped_feature_list_.InitWithFeatures(
       // enabled_features
-      {net::features::kSplitHostCacheByNetworkIsolationKey,
-       net::features::kPartitionConnectionsByNetworkIsolationKey, kNaclAllow},
+      {net::features::kPartitionConnectionsByNetworkIsolationKey, kNaclAllow},
       // disabled_features
       {});
 }
diff --git a/chromeos/ash/components/fwupd/firmware_update_manager.cc b/chromeos/ash/components/fwupd/firmware_update_manager.cc
index 93caa4f2..eb7e2fcf 100644
--- a/chromeos/ash/components/fwupd/firmware_update_manager.cc
+++ b/chromeos/ash/components/fwupd/firmware_update_manager.cc
@@ -384,6 +384,46 @@
   return firmware_filename;
 }
 
+bool RefreshRemoteAllowed(FirmwareUpdateManager::Source source,
+                          bool refresh_remote_for_testing) {
+  FIRMWARE_LOG(DEBUG) << "RefreshRemoteAllowed()";
+  DCHECK(NetworkHandler::IsInitialized());
+  const bool is_metered = NetworkHandler::Get()
+                              ->network_state_handler()
+                              ->default_network_is_metered();
+  const bool connection_ok =
+      !is_metered || source == FirmwareUpdateManager::Source::kUI;
+  FIRMWARE_LOG(DEBUG) << "Connection metered: " << is_metered
+                      << ", Source: " << static_cast<int>(source)
+                      << ", Refresh Remote connection okay: " << connection_ok;
+  if (!connection_ok) {
+    return false;
+  }
+
+  // Always refresh the remote in tests for consistent results.
+  if (refresh_remote_for_testing) {
+    return true;
+  }
+  const base::FilePath local_firmware_path =
+      base::FilePath(kLocalFirmwareBasePath)
+          .Append(kLVFSRemoteId)
+          .Append(kLocalMetadataFileName);
+  base::File::Info info;
+  if (!GetMetadataFileInfo(local_firmware_path, &info)) {
+    // Allow RefreshRemote if file not found or info not found
+    return true;
+  }
+  base::TimeDelta age = base::Time::Now() - info.last_modified;
+  if (age >= base::Hours(0) && age <= base::Hours(24)) {
+    FIRMWARE_LOG(DEBUG) << "Local firmware file age < 24 hours, age: "
+                        << static_cast<int>(age.InHours());
+    return false;
+  }
+  FIRMWARE_LOG(DEBUG) << "Local firmware file age > 24 hours, age: "
+                      << static_cast<int>(age.InHours());
+  return true;
+}
+
 }  // namespace
 
 FirmwareUpdateManager::FirmwareUpdateManager()
@@ -451,46 +491,6 @@
   return critical_update_count;
 }
 
-bool FirmwareUpdateManager::RefreshRemoteAllowed(
-    FirmwareUpdateManager::Source source) {
-  FIRMWARE_LOG(DEBUG) << "RefreshRemoteAllowed()";
-  DCHECK(NetworkHandler::IsInitialized());
-  const bool is_metered = NetworkHandler::Get()
-                              ->network_state_handler()
-                              ->default_network_is_metered();
-  const bool connection_ok =
-      !is_metered || source == FirmwareUpdateManager::Source::kUI;
-  FIRMWARE_LOG(DEBUG) << "Connection metered: " << is_metered
-                      << ", Source: " << static_cast<int>(source)
-                      << ", Refresh Remote connection okay: " << connection_ok;
-  if (!connection_ok) {
-    return false;
-  }
-
-  // Always refresh the remote in tests for consistent results.
-  if (refresh_remote_for_testing_) {
-    return true;
-  }
-  const base::FilePath local_firmware_path =
-      base::FilePath(kLocalFirmwareBasePath)
-          .Append(kLVFSRemoteId)
-          .Append(kLocalMetadataFileName);
-  base::File::Info info;
-  if (!GetMetadataFileInfo(local_firmware_path, &info)) {
-    // Allow RefreshRemote if file not found or info not found
-    return true;
-  }
-  base::TimeDelta age = base::Time::Now() - info.last_modified;
-  if (age >= base::Hours(0) && age <= base::Hours(24)) {
-    FIRMWARE_LOG(DEBUG) << "Local firmware file age < 24 hours, age: "
-                        << static_cast<int>(age.InHours());
-    return false;
-  }
-  FIRMWARE_LOG(DEBUG) << "Local firmware file age > 24 hours, age: "
-                      << static_cast<int>(age.InHours());
-  return true;
-}
-
 const base::FilePath FirmwareUpdateManager::GetCacheDirPath() {
   base::FilePath root_dir;
   CHECK(base::PathService::Get(base::DIR_TEMP, &root_dir));
@@ -577,8 +577,8 @@
   is_fetching_updates_ = true;
   task_runner_->PostTaskAndReplyWithResult(
       FROM_HERE,
-      base::BindOnce(&FirmwareUpdateManager::RefreshRemoteAllowed,
-                     base::Unretained(this), source),
+      base::BindOnce(&RefreshRemoteAllowed, source,
+                     refresh_remote_for_testing_),
       base::BindOnce(&FirmwareUpdateManager::MaybeRefreshRemote,
                      weak_ptr_factory_.GetWeakPtr()));
 }
diff --git a/chromeos/ash/components/fwupd/firmware_update_manager.h b/chromeos/ash/components/fwupd/firmware_update_manager.h
index c677f8b..822fc3d 100644
--- a/chromeos/ash/components/fwupd/firmware_update_manager.h
+++ b/chromeos/ash/components/fwupd/firmware_update_manager.h
@@ -353,9 +353,6 @@
 
   int GetNumCriticalUpdates();
 
-  // Determines if RefreshRemote is necassary.
-  bool RefreshRemoteAllowed(FirmwareUpdateManager::Source source);
-
   // Gets /tmp directory path to store downloaded files.
   const base::FilePath GetCacheDirPath();
 
diff --git a/chromeos/ash/services/ime/user_data/japanese_dictionary.cc b/chromeos/ash/services/ime/user_data/japanese_dictionary.cc
index 3aafaac..29b12f1 100644
--- a/chromeos/ash/services/ime/user_data/japanese_dictionary.cc
+++ b/chromeos/ash/services/ime/user_data/japanese_dictionary.cc
@@ -12,61 +12,97 @@
 namespace {
 using chromeos_input::JapaneseDictionary;
 
-constexpr auto kPosTypes = base::MakeFixedFlatMap<JapaneseDictionary::PosType,
-                                                  mojom::JpPosType>({
-    {JapaneseDictionary::NO_POS, mojom::JpPosType::kNoPos},
-    {JapaneseDictionary::NOUN, mojom::JpPosType::kNoun},
-    {JapaneseDictionary::ABBREVIATION, mojom::JpPosType::kAbbreviation},
-    {JapaneseDictionary::SUGGESTION_ONLY, mojom::JpPosType::kSuggestionOnly},
-    {JapaneseDictionary::PROPER_NOUN, mojom::JpPosType::kProperNoun},
-    {JapaneseDictionary::PERSONAL_NAME, mojom::JpPosType::kPersonalName},
-    {JapaneseDictionary::FAMILY_NAME, mojom::JpPosType::kFamilyName},
-    {JapaneseDictionary::FIRST_NAME, mojom::JpPosType::kFirstName},
-    {JapaneseDictionary::ORGANIZATION_NAME,
-     mojom::JpPosType::kOrganizationName},
-    {JapaneseDictionary::PLACE_NAME, mojom::JpPosType::kPlaceName},
-    {JapaneseDictionary::SA_IRREGULAR_CONJUGATION_NOUN,
-     mojom::JpPosType::kSaIrregularConjugationNoun},
-    {JapaneseDictionary::ADJECTIVE_VERBAL_NOUN,
-     mojom::JpPosType::kAdjectiveVerbalNoun},
-    {JapaneseDictionary::NUMBER, mojom::JpPosType::kNumber},
-    {JapaneseDictionary::ALPHABET, mojom::JpPosType::kAlphabet},
-    {JapaneseDictionary::SYMBOL, mojom::JpPosType::kSymbol},
-    {JapaneseDictionary::EMOTICON, mojom::JpPosType::kEmoticon},
-    {JapaneseDictionary::ADVERB, mojom::JpPosType::kAdverb},
-    {JapaneseDictionary::PRENOUN_ADJECTIVAL,
-     mojom::JpPosType::kPrenounAdjectival},
-    {JapaneseDictionary::CONJUNCTION, mojom::JpPosType::kConjunction},
-    {JapaneseDictionary::INTERJECTION, mojom::JpPosType::kInterjection},
-    {JapaneseDictionary::PREFIX, mojom::JpPosType::kPrefix},
-    {JapaneseDictionary::COUNTER_SUFFIX, mojom::JpPosType::kCounterSuffix},
-    {JapaneseDictionary::GENERIC_SUFFIX, mojom::JpPosType::kGenericSuffix},
-    {JapaneseDictionary::PERSON_NAME_SUFFIX,
-     mojom::JpPosType::kPersonNameSuffix},
-    {JapaneseDictionary::PLACE_NAME_SUFFIX, mojom::JpPosType::kPlaceNameSuffix},
-    {JapaneseDictionary::WA_GROUP1_VERB, mojom::JpPosType::kWaGroup1Verb},
-    {JapaneseDictionary::KA_GROUP1_VERB, mojom::JpPosType::kKaGroup1Verb},
-    {JapaneseDictionary::SA_GROUP1_VERB, mojom::JpPosType::kSaGroup1Verb},
-    {JapaneseDictionary::TA_GROUP1_VERB, mojom::JpPosType::kTaGroup1Verb},
-    {JapaneseDictionary::NA_GROUP1_VERB, mojom::JpPosType::kNaGroup1Verb},
-    {JapaneseDictionary::MA_GROUP1_VERB, mojom::JpPosType::kMaGroup1Verb},
-    {JapaneseDictionary::RA_GROUP1_VERB, mojom::JpPosType::kRaGroup1Verb},
-    {JapaneseDictionary::GA_GROUP1_VERB, mojom::JpPosType::kGaGroup1Verb},
-    {JapaneseDictionary::BA_GROUP1_VERB, mojom::JpPosType::kBaGroup1Verb},
-    {JapaneseDictionary::HA_GROUP1_VERB, mojom::JpPosType::kHaGroup1Verb},
-    {JapaneseDictionary::GROUP2_VERB, mojom::JpPosType::kGroup2Verb},
-    {JapaneseDictionary::KURU_GROUP3_VERB, mojom::JpPosType::kKuruGroup3Verb},
-    {JapaneseDictionary::SURU_GROUP3_VERB, mojom::JpPosType::kSuruGroup3Verb},
-    {JapaneseDictionary::ZURU_GROUP3_VERB, mojom::JpPosType::kZuruGroup3Verb},
-    {JapaneseDictionary::RU_GROUP3_VERB, mojom::JpPosType::kRuGroup3Verb},
-    {JapaneseDictionary::ADJECTIVE, mojom::JpPosType::kAdjective},
-    {JapaneseDictionary::SENTENCE_ENDING_PARTICLE,
-     mojom::JpPosType::kSentenceEndingParticle},
-    {JapaneseDictionary::PUNCTUATION, mojom::JpPosType::kPunctuation},
-    {JapaneseDictionary::FREE_STANDING_WORD,
-     mojom::JpPosType::kFreeStandingWord},
-    {JapaneseDictionary::SUPPRESSION_WORD, mojom::JpPosType::kSuppressionWord},
-});
+struct PosTypePair {
+  JapaneseDictionary::PosType proto;
+  mojom::JpPosType mojom;
+};
+
+constexpr std::array<PosTypePair, 45> kPosTypes = {{
+    {.proto = JapaneseDictionary::NO_POS, .mojom = mojom::JpPosType::kNoPos},
+    {.proto = JapaneseDictionary::NOUN, .mojom = mojom::JpPosType::kNoun},
+    {.proto = JapaneseDictionary::ABBREVIATION,
+     .mojom = mojom::JpPosType::kAbbreviation},
+    {.proto = JapaneseDictionary::SUGGESTION_ONLY,
+     .mojom = mojom::JpPosType::kSuggestionOnly},
+    {.proto = JapaneseDictionary::PROPER_NOUN,
+     .mojom = mojom::JpPosType::kProperNoun},
+    {.proto = JapaneseDictionary::PERSONAL_NAME,
+     .mojom = mojom::JpPosType::kPersonalName},
+    {.proto = JapaneseDictionary::FAMILY_NAME,
+     .mojom = mojom::JpPosType::kFamilyName},
+    {.proto = JapaneseDictionary::FIRST_NAME,
+     .mojom = mojom::JpPosType::kFirstName},
+    {.proto = JapaneseDictionary::ORGANIZATION_NAME,
+     .mojom = mojom::JpPosType::kOrganizationName},
+    {.proto = JapaneseDictionary::PLACE_NAME,
+     .mojom = mojom::JpPosType::kPlaceName},
+    {.proto = JapaneseDictionary::SA_IRREGULAR_CONJUGATION_NOUN,
+     .mojom = mojom::JpPosType::kSaIrregularConjugationNoun},
+    {.proto = JapaneseDictionary::ADJECTIVE_VERBAL_NOUN,
+     .mojom = mojom::JpPosType::kAdjectiveVerbalNoun},
+    {.proto = JapaneseDictionary::NUMBER, .mojom = mojom::JpPosType::kNumber},
+    {.proto = JapaneseDictionary::ALPHABET,
+     .mojom = mojom::JpPosType::kAlphabet},
+    {.proto = JapaneseDictionary::SYMBOL, .mojom = mojom::JpPosType::kSymbol},
+    {.proto = JapaneseDictionary::EMOTICON,
+     .mojom = mojom::JpPosType::kEmoticon},
+    {.proto = JapaneseDictionary::ADVERB, .mojom = mojom::JpPosType::kAdverb},
+    {.proto = JapaneseDictionary::PRENOUN_ADJECTIVAL,
+     .mojom = mojom::JpPosType::kPrenounAdjectival},
+    {.proto = JapaneseDictionary::CONJUNCTION,
+     .mojom = mojom::JpPosType::kConjunction},
+    {.proto = JapaneseDictionary::INTERJECTION,
+     .mojom = mojom::JpPosType::kInterjection},
+    {.proto = JapaneseDictionary::PREFIX, .mojom = mojom::JpPosType::kPrefix},
+    {.proto = JapaneseDictionary::COUNTER_SUFFIX,
+     .mojom = mojom::JpPosType::kCounterSuffix},
+    {.proto = JapaneseDictionary::GENERIC_SUFFIX,
+     .mojom = mojom::JpPosType::kGenericSuffix},
+    {.proto = JapaneseDictionary::PERSON_NAME_SUFFIX,
+     .mojom = mojom::JpPosType::kPersonNameSuffix},
+    {.proto = JapaneseDictionary::PLACE_NAME_SUFFIX,
+     .mojom = mojom::JpPosType::kPlaceNameSuffix},
+    {.proto = JapaneseDictionary::WA_GROUP1_VERB,
+     .mojom = mojom::JpPosType::kWaGroup1Verb},
+    {.proto = JapaneseDictionary::KA_GROUP1_VERB,
+     .mojom = mojom::JpPosType::kKaGroup1Verb},
+    {.proto = JapaneseDictionary::SA_GROUP1_VERB,
+     .mojom = mojom::JpPosType::kSaGroup1Verb},
+    {.proto = JapaneseDictionary::TA_GROUP1_VERB,
+     .mojom = mojom::JpPosType::kTaGroup1Verb},
+    {.proto = JapaneseDictionary::NA_GROUP1_VERB,
+     .mojom = mojom::JpPosType::kNaGroup1Verb},
+    {.proto = JapaneseDictionary::MA_GROUP1_VERB,
+     .mojom = mojom::JpPosType::kMaGroup1Verb},
+    {.proto = JapaneseDictionary::RA_GROUP1_VERB,
+     .mojom = mojom::JpPosType::kRaGroup1Verb},
+    {.proto = JapaneseDictionary::GA_GROUP1_VERB,
+     .mojom = mojom::JpPosType::kGaGroup1Verb},
+    {.proto = JapaneseDictionary::BA_GROUP1_VERB,
+     .mojom = mojom::JpPosType::kBaGroup1Verb},
+    {.proto = JapaneseDictionary::HA_GROUP1_VERB,
+     .mojom = mojom::JpPosType::kHaGroup1Verb},
+    {.proto = JapaneseDictionary::GROUP2_VERB,
+     .mojom = mojom::JpPosType::kGroup2Verb},
+    {.proto = JapaneseDictionary::KURU_GROUP3_VERB,
+     .mojom = mojom::JpPosType::kKuruGroup3Verb},
+    {.proto = JapaneseDictionary::SURU_GROUP3_VERB,
+     .mojom = mojom::JpPosType::kSuruGroup3Verb},
+    {.proto = JapaneseDictionary::ZURU_GROUP3_VERB,
+     .mojom = mojom::JpPosType::kZuruGroup3Verb},
+    {.proto = JapaneseDictionary::RU_GROUP3_VERB,
+     .mojom = mojom::JpPosType::kRuGroup3Verb},
+    {.proto = JapaneseDictionary::ADJECTIVE,
+     .mojom = mojom::JpPosType::kAdjective},
+    {.proto = JapaneseDictionary::SENTENCE_ENDING_PARTICLE,
+     .mojom = mojom::JpPosType::kSentenceEndingParticle},
+    {.proto = JapaneseDictionary::PUNCTUATION,
+     .mojom = mojom::JpPosType::kPunctuation},
+    {.proto = JapaneseDictionary::FREE_STANDING_WORD,
+     .mojom = mojom::JpPosType::kFreeStandingWord},
+    {.proto = JapaneseDictionary::SUPPRESSION_WORD,
+     .mojom = mojom::JpPosType::kSuppressionWord},
+}};
 
 mojom::JapaneseDictionaryEntryPtr MakeEntry(
     chromeos_input::JapaneseDictionary::Entry proto) {
@@ -77,9 +113,14 @@
   entry->value = proto.value();
   entry->comment = proto.comment();
 
-  if (const auto& it = kPosTypes.find(proto.pos()); it != kPosTypes.end()) {
-    entry->pos = it->second;
+  const auto& it = std::find_if(
+      kPosTypes.begin(), kPosTypes.end(),
+      [&proto](const PosTypePair& val) { return val.proto == proto.pos(); });
+
+  if (it != kPosTypes.end()) {
+    entry->pos = it->mojom;
   }
+
   return entry;
 }
 
@@ -97,4 +138,23 @@
   return result;
 }
 
+chromeos_input::JapaneseDictionary::Entry MakeProtoJpDictEntry(
+    const mojom::JapaneseDictionaryEntry& mojom_entry) {
+  chromeos_input::JapaneseDictionary::Entry result;
+  result.set_key(mojom_entry.key);
+  result.set_value(mojom_entry.value);
+  result.set_comment(mojom_entry.comment);
+
+  const auto& it = std::find_if(kPosTypes.begin(), kPosTypes.end(),
+                                [&mojom_entry](const PosTypePair& val) {
+                                  return val.mojom == mojom_entry.pos;
+                                });
+
+  if (it != kPosTypes.end()) {
+    result.set_pos(it->proto);
+  }
+
+  return result;
+}
+
 }  // namespace ash::ime
diff --git a/chromeos/ash/services/ime/user_data/japanese_dictionary.h b/chromeos/ash/services/ime/user_data/japanese_dictionary.h
index f5c375f8..8171196 100644
--- a/chromeos/ash/services/ime/user_data/japanese_dictionary.h
+++ b/chromeos/ash/services/ime/user_data/japanese_dictionary.h
@@ -13,6 +13,9 @@
 mojom::JapaneseDictionaryPtr MakeMojomJapaneseDictionary(
     chromeos_input::JapaneseDictionary proto_response);
 
+chromeos_input::JapaneseDictionary::Entry MakeProtoJpDictEntry(
+    const mojom::JapaneseDictionaryEntry& mojom_entry);
+
 }  // namespace ash::ime
 
 #endif  // CHROMEOS_ASH_SERVICES_IME_USER_DATA_JAPANESE_DICTIONARY_H_
diff --git a/chromeos/ash/services/ime/user_data/japanese_dictionary_unittest.cc b/chromeos/ash/services/ime/user_data/japanese_dictionary_unittest.cc
index e2f721d3..b4c0cfc 100644
--- a/chromeos/ash/services/ime/user_data/japanese_dictionary_unittest.cc
+++ b/chromeos/ash/services/ime/user_data/japanese_dictionary_unittest.cc
@@ -342,5 +342,19 @@
   EXPECT_EQ(result, expected);
 }
 
+TEST(JapaneseDictionaryTest, MakeProtoJpDictEntry) {
+  JapaneseDictionary::Entry result =
+      MakeProtoJpDictEntry(*JapaneseDictionaryEntry::New(
+          /*key=*/"firstName", /*value=*/"value",
+          /*pos_type=*/JpPosType::kFirstName,
+          /*comment=*/"notes"));
+
+  EXPECT_EQ(result.key(), "firstName");
+  EXPECT_EQ(result.value(), "value");
+  EXPECT_EQ(result.pos(), JapaneseDictionary::FIRST_NAME);
+  EXPECT_EQ(result.comment(), "notes");
+}
+
 }  // namespace
 }  // namespace ash::ime
+                        
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index 84685e6..eafbe59 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -5680,6 +5680,9 @@
         <message name="IDS_FEEDBACK_TOOL_WIFI_DEBUG_LOGS_MESSAGE" translateable="false" desc="Message shown after user clicks on the Wifi debug logs hyperlink">
           Include proprietary debug data generated by the closed-source firmware of Wi-Fi chipsets. It may include information about the Wi-Fi chip (such as its MAC address), connected and surrounding Wi-Fi access points, and any other data going through the chipsets.&#10;&#10;This data can't be debugged by Google directly and is shared with the chipset vendors so that they can debug and fix any issues Googlers are experiencing. In case the issue needs to be shared with vendors, the data is kept in Buganizer until the bug is resolved.
         </message>
+        <message name="IDS_FEEDBACK_TOOL_WIFI_DEBUG_LOGS_TITLE" translateable="false" desc="Title on the dialog box for WiFi debug logs">
+            Sharing Wi-Fi Debug Logs
+        </message>
         <message name="IDS_FEEDBACK_TOOL_LINK_CROSS_DEVICE_DOGFOOD_FEEDBACK_INFO" translateable="false" desc="Checkbox for Google internal account to submit a Cross Device Feedback Report.">
           This is an issue between this Chromebook and another device. <ph name="BEGIN_LINK1">&lt;a id="linkCrossDeviceDogfoodFeedbackInfoLink"&gt;</ph>View more details<ph name="END_LINK1">&lt;/a&gt;</ph>.
         </message>
diff --git a/clank b/clank
index 23089ba..5581d13 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 23089ba269532c066446db34718544703ecf039e
+Subproject commit 5581d135e7c2a518da3872aa95fe0d94d259d1bf
diff --git a/components/browsing_data/content/browsing_data_helper.cc b/components/browsing_data/content/browsing_data_helper.cc
index ee0a31ac..7d9f794 100644
--- a/components/browsing_data/content/browsing_data_helper.cc
+++ b/components/browsing_data/content/browsing_data_helper.cc
@@ -40,7 +40,8 @@
   // this filter is used for is DURABLE_STORAGE, which also only uses
   // origin-scoped patterns. Such patterns can be directly translated to a GURL.
   GURL url(primary_pattern.ToString());
-  DCHECK(url.is_valid());
+  DCHECK(url.is_valid()) << "url: '" << url.possibly_invalid_spec() << "' "
+                         << "pattern: '" << primary_pattern.ToString() << "'";
   return predicate.Run(url);
 }
 
diff --git a/components/compose/core/browser/BUILD.gn b/components/compose/core/browser/BUILD.gn
index 5b91ca8..835bca0 100644
--- a/components/compose/core/browser/BUILD.gn
+++ b/components/compose/core/browser/BUILD.gn
@@ -36,6 +36,7 @@
     "//components/autofill/core/browser",
     "//components/autofill/core/common",
     "//components/keyed_service/core",
+    "//components/segmentation_platform/public:public",
     "//components/strings",
     "//services/metrics/public/cpp:metrics_cpp",
     "//services/metrics/public/cpp:ukm_builders",
diff --git a/components/compose/core/browser/DEPS b/components/compose/core/browser/DEPS
index ac9b8c7..2461633 100644
--- a/components/compose/core/browser/DEPS
+++ b/components/compose/core/browser/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+components/autofill/core",
+  "+components/segmentation_platform",
   "+components/strings/grit",
   "+components/ukm",
   "+services/metrics/public/cpp",
diff --git a/components/compose/core/browser/config.cc b/components/compose/core/browser/config.cc
index e4618dc..b984914 100644
--- a/components/compose/core/browser/config.cc
+++ b/components/compose/core/browser/config.cc
@@ -9,6 +9,7 @@
 #include "base/no_destructor.h"
 #include "base/types/cxx23_to_underlying.h"
 #include "components/compose/core/browser/compose_features.h"
+#include "components/segmentation_platform/public/features.h"
 
 namespace compose {
 
@@ -74,6 +75,9 @@
           "proactive_nudge_delay_milliseconds",
           proactive_nudge_delay.InMilliseconds()));
 
+  proactive_nudge_segmentation = base::FeatureList::IsEnabled(
+      segmentation_platform::features::kSegmentationPlatformComposePromotion);
+
   saved_state_timeout_milliseconds = base::GetFieldTrialParamByFeatureAsInt(
       features::kEnableComposeSavedStateNotification,
       "saved_state_timeout_milliseconds", saved_state_timeout_milliseconds);
diff --git a/components/compose/core/browser/config.h b/components/compose/core/browser/config.h
index 7ebdf0d..48f912e 100644
--- a/components/compose/core/browser/config.h
+++ b/components/compose/core/browser/config.h
@@ -67,6 +67,9 @@
   // hint decisions.
   bool proactive_nudge_bypass_optimization_guide = false;
 
+  // Uses segmentation platform to predict nudge utility.
+  bool proactive_nudge_segmentation = false;
+
   // How long to wait to show the proactive nudge.
   base::TimeDelta proactive_nudge_delay = base::Seconds(3);
 
diff --git a/components/constrained_window/constrained_window_views.cc b/components/constrained_window/constrained_window_views.cc
index a2ca2f5..d4fc620 100644
--- a/components/constrained_window/constrained_window_views.cc
+++ b/components/constrained_window/constrained_window_views.cc
@@ -98,12 +98,24 @@
   const char* const native_window_property_;
 };
 
-gfx::Rect GetModalDialogBounds(views::Widget* widget,
+void UpdateModalDialogPosition(views::Widget* widget,
                                web_modal::ModalDialogHost* dialog_host,
                                const gfx::Size& size) {
-  views::Widget* const host_widget =
+  // Do not forcibly update the dialog widget position if it is being dragged.
+  if (widget->HasCapture())
+    return;
+
+  views::Widget* host_widget =
       views::Widget::GetWidgetForNativeView(dialog_host->GetHostView());
-  CHECK(host_widget);
+
+  // If the host view is not backed by a Views::Widget, just update the widget
+  // size. This can happen on MacViews under the Cocoa browser where the window
+  // modal dialogs are displayed as sheets, and their position is managed by a
+  // ConstrainedWindowSheetController instance.
+  if (!host_widget) {
+    widget->SetSize(size);
+    return;
+  }
 
   gfx::Point position = dialog_host->GetDialogPosition(size);
   // Align the first row of pixels inside the border. This is the apparent top
@@ -147,30 +159,8 @@
     // Readjust the position of the dialog.
     dialog_bounds.set_origin(dialog_screen_bounds.origin());
   }
-  return dialog_bounds;
-}
 
-void UpdateModalDialogPosition(views::Widget* widget,
-                               web_modal::ModalDialogHost* dialog_host,
-                               const gfx::Size& size) {
-  // Do not forcibly update the dialog widget position if it is being dragged.
-  if (widget->HasCapture()) {
-    return;
-  }
-
-  views::Widget* const host_widget =
-      views::Widget::GetWidgetForNativeView(dialog_host->GetHostView());
-
-  // If the host view is not backed by a Views::Widget, just update the widget
-  // size. This can happen on MacViews under the Cocoa browser where the window
-  // modal dialogs are displayed as sheets, and their position is managed by a
-  // ConstrainedWindowSheetController instance.
-  if (!host_widget) {
-    widget->SetSize(size);
-    return;
-  }
-
-  widget->SetBounds(GetModalDialogBounds(widget, dialog_host, size));
+  widget->SetBounds(dialog_bounds);
 }
 
 }  // namespace
@@ -250,17 +240,9 @@
         << ", scheme=" << url.scheme_piece() << ", host=" << url.host_piece();
   }
 
-  web_modal::ModalDialogHost* dialog_host =
-      manager->delegate()->GetWebContentsModalDialogHost();
   views::Widget* widget = views::DialogDelegate::CreateDialogWidget(
-      dialog, nullptr, dialog_host->GetHostView());
-  dialog->set_desired_bounds_delegate(base::BindRepeating(
-      [](views::Widget* widget,
-         web_modal::ModalDialogHost* dialog_host) -> gfx::Rect {
-        return GetModalDialogBounds(
-            widget, dialog_host, widget->GetRootView()->GetPreferredSize({}));
-      },
-      widget, manager->delegate()->GetWebContentsModalDialogHost()));
+      dialog, nullptr,
+      manager->delegate()->GetWebContentsModalDialogHost()->GetHostView());
   widget->SetNativeWindowProperty(
       views::kWidgetIdentifierKey,
       const_cast<void*>(kConstrainedWindowWidgetIdentifier));
diff --git a/components/data_sharing/BUILD.gn b/components/data_sharing/BUILD.gn
index 25888443..2e28c21 100644
--- a/components/data_sharing/BUILD.gn
+++ b/components/data_sharing/BUILD.gn
@@ -17,3 +17,22 @@
 
   data = [ "components_unittests.filter" ]
 }
+
+source_set("test_support") {
+  testonly = true
+
+  sources = [
+    "test_support/mock_data_sharing_network_loader.cc",
+    "test_support/mock_data_sharing_network_loader.h",
+    "test_support/mock_data_sharing_service.cc",
+    "test_support/mock_data_sharing_service.h",
+  ]
+
+  public_deps = [
+    "//base",
+    "//components/data_sharing/public",
+    "//net/traffic_annotation",
+    "//testing/gmock",
+    "//url",
+  ]
+}
diff --git a/components/data_sharing/DEPS b/components/data_sharing/DEPS
index a82819d6..191e7d2 100644
--- a/components/data_sharing/DEPS
+++ b/components/data_sharing/DEPS
@@ -1,3 +1,6 @@
 include_rules = [
   "+components/keyed_service",
+  "+components/sync/model",
+  "+net/android",
+  "+net/traffic_annotation",
 ]
diff --git a/components/data_sharing/internal/BUILD.gn b/components/data_sharing/internal/BUILD.gn
index 2f3b58a..ee9159fa 100644
--- a/components/data_sharing/internal/BUILD.gn
+++ b/components/data_sharing/internal/BUILD.gn
@@ -90,7 +90,7 @@
 
   if (is_android) {
     deps += [
-      ":test_support",
+      "//components/data_sharing:test_support",
       "//url",
     ]
   }
@@ -146,27 +146,3 @@
     ]
   }
 }
-
-# TODO(b/339698854): Move these to public/test instead of internal.
-source_set("test_support") {
-  testonly = true
-
-  visibility = [
-    ":*",
-    "//chrome/test:*",
-  ]
-
-  sources = [
-    "mock_data_sharing_network_loader.cc",
-    "mock_data_sharing_network_loader.h",
-    "mock_data_sharing_service.cc",
-    "mock_data_sharing_service.h",
-  ]
-
-  public_deps = [
-    "//base",
-    "//components/data_sharing/public",
-    "//testing/gmock",
-    "//url",
-  ]
-}
diff --git a/components/data_sharing/internal/DEPS b/components/data_sharing/internal/DEPS
index cf7992e..60565ff 100644
--- a/components/data_sharing/internal/DEPS
+++ b/components/data_sharing/internal/DEPS
@@ -2,12 +2,9 @@
   "+components/endpoint_fetcher",
   "+components/signin/public/identity_manager",
   "+components/sync/base",
-  "+components/sync/model",
   "+components/sync/protocol",
   "+components/sync/test",
-  "+net/android",
   "+net/http",
-  "+net/traffic_annotation",
   "+services/network/public/cpp",
   "+services/network/test",
 ]
\ No newline at end of file
diff --git a/components/data_sharing/internal/android/data_sharing_network_loader_android_unittest.cc b/components/data_sharing/internal/android/data_sharing_network_loader_android_unittest.cc
index 65ca6bf..466371d 100644
--- a/components/data_sharing/internal/android/data_sharing_network_loader_android_unittest.cc
+++ b/components/data_sharing/internal/android/data_sharing_network_loader_android_unittest.cc
@@ -10,7 +10,7 @@
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_array.h"
-#include "components/data_sharing/internal/mock_data_sharing_network_loader.h"
+#include "components/data_sharing/test_support/mock_data_sharing_network_loader.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/android/gurl_android.h"
diff --git a/components/data_sharing/internal/data_sharing_service_impl.cc b/components/data_sharing/internal/data_sharing_service_impl.cc
index 7c767b1..e30ed6c 100644
--- a/components/data_sharing/internal/data_sharing_service_impl.cc
+++ b/components/data_sharing/internal/data_sharing_service_impl.cc
@@ -81,11 +81,13 @@
     signin::IdentityManager* identity_manager,
     syncer::OnceModelTypeStoreFactory model_type_store_factory,
     version_info::Channel channel,
-    std::unique_ptr<DataSharingSDKDelegate> sdk_delegate)
+    std::unique_ptr<DataSharingSDKDelegate> sdk_delegate,
+    std::unique_ptr<DataSharingUIDelegate> ui_delegate)
     : data_sharing_network_loader_(
           std::make_unique<DataSharingNetworkLoaderImpl>(url_loader_factory,
                                                          identity_manager)),
-      sdk_delegate_(std::move(sdk_delegate)) {
+      sdk_delegate_(std::move(sdk_delegate)),
+      ui_delegate_(std::move(ui_delegate)) {
   auto change_processor =
       std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
           syncer::COLLABORATION_GROUP,
@@ -477,7 +479,10 @@
 
 void DataSharingServiceImpl::HandleShareURLNavigationIntercepted(
     const GURL& url) {
-  NOTIMPLEMENTED();
+  if (!ui_delegate_) {
+    return;
+  }
+  ui_delegate_->HandleShareURLIntercepted(url);
 }
 
 }  // namespace data_sharing
diff --git a/components/data_sharing/internal/data_sharing_service_impl.h b/components/data_sharing/internal/data_sharing_service_impl.h
index 8f3c6de..29d0ae0 100644
--- a/components/data_sharing/internal/data_sharing_service_impl.h
+++ b/components/data_sharing/internal/data_sharing_service_impl.h
@@ -11,6 +11,7 @@
 #include "components/data_sharing/internal/collaboration_group_sync_bridge.h"
 #include "components/data_sharing/public/data_sharing_sdk_delegate.h"
 #include "components/data_sharing/public/data_sharing_service.h"
+#include "components/data_sharing/public/data_sharing_ui_delegate.h"
 #include "components/sync/model/model_type_controller_delegate.h"
 #include "components/sync/model/model_type_store.h"
 #include "components/sync/model/model_type_sync_bridge.h"
@@ -45,7 +46,8 @@
       signin::IdentityManager* identity_manager,
       syncer::OnceModelTypeStoreFactory model_type_store_factory,
       version_info::Channel channel,
-      std::unique_ptr<DataSharingSDKDelegate> sdk_delegate);
+      std::unique_ptr<DataSharingSDKDelegate> sdk_delegate,
+      std::unique_ptr<DataSharingUIDelegate> ui_delegate);
   ~DataSharingServiceImpl() override;
 
   // Disallow copy/assign.
@@ -132,6 +134,7 @@
       collaboration_group_sync_bridge_;
   // Nullable.
   std::unique_ptr<DataSharingSDKDelegate> sdk_delegate_;
+  std::unique_ptr<DataSharingUIDelegate> ui_delegate_;
 
   base::ObserverList<DataSharingService::Observer> observers_;
 
diff --git a/components/data_sharing/internal/data_sharing_service_impl_unittest.cc b/components/data_sharing/internal/data_sharing_service_impl_unittest.cc
index 73c4568..e8a249d 100644
--- a/components/data_sharing/internal/data_sharing_service_impl_unittest.cc
+++ b/components/data_sharing/internal/data_sharing_service_impl_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/version_info/channel.h"
 #include "components/data_sharing/public/data_sharing_sdk_delegate.h"
 #include "components/data_sharing/public/data_sharing_service.h"
+#include "components/data_sharing/public/data_sharing_ui_delegate.h"
 #include "components/data_sharing/public/protocol/data_sharing_sdk.pb.h"
 #include "components/signin/public/identity_manager/identity_test_environment.h"
 #include "components/sync/model/entity_change.h"
@@ -279,7 +280,8 @@
         std::move(test_url_loader_factory),
         identity_test_env_.identity_manager(),
         syncer::ModelTypeStoreTestUtil::FactoryForInMemoryStoreForTest(),
-        version_info::Channel::UNKNOWN, std::move(sdk_delegate));
+        version_info::Channel::UNKNOWN, std::move(sdk_delegate),
+        /*ui_delegate=*/nullptr);
   }
 
  protected:
diff --git a/components/data_sharing/public/BUILD.gn b/components/data_sharing/public/BUILD.gn
index 87f8a35..4d3df068 100644
--- a/components/data_sharing/public/BUILD.gn
+++ b/components/data_sharing/public/BUILD.gn
@@ -13,6 +13,7 @@
     "data_sharing_network_loader.h",
     "data_sharing_sdk_delegate.h",
     "data_sharing_service.h",
+    "data_sharing_ui_delegate.h",
     "features.cc",
     "features.h",
     "group_data.cc",
diff --git a/components/data_sharing/public/DEPS b/components/data_sharing/public/DEPS
deleted file mode 100644
index fe6ed5d..0000000
--- a/components/data_sharing/public/DEPS
+++ /dev/null
@@ -1,5 +0,0 @@
-include_rules = [
-  "+net/android",
-  "+net/traffic_annotation",
-  "+components/sync/model",
-]
\ No newline at end of file
diff --git a/components/data_sharing/public/android/java/src/org/chromium/components/data_sharing/DataSharingUIDelegate.java b/components/data_sharing/public/android/java/src/org/chromium/components/data_sharing/DataSharingUIDelegate.java
index 7ee4bf4..e50ce1e6 100644
--- a/components/data_sharing/public/android/java/src/org/chromium/components/data_sharing/DataSharingUIDelegate.java
+++ b/components/data_sharing/public/android/java/src/org/chromium/components/data_sharing/DataSharingUIDelegate.java
@@ -10,15 +10,20 @@
 
 import androidx.annotation.NonNull;
 
+import org.jni_zero.CalledByNative;
+import org.jni_zero.JNINamespace;
+
 import org.chromium.base.Callback;
 import org.chromium.base.UserData;
 import org.chromium.components.data_sharing.configs.AvatarConfig;
 import org.chromium.components.data_sharing.configs.GroupMemberConfig;
 import org.chromium.components.data_sharing.configs.MemberPickerConfig;
+import org.chromium.url.GURL;
 
 import java.util.List;
 
-/** An interface that shows sharing UI screens. */
+/** An interface that shows sharing UI screens. TODO(b/339685767): Remove UserData base class. */
+@JNINamespace("data_sharing")
 public interface DataSharingUIDelegate extends UserData {
 
     /** Interface for callback when members are picked. */
@@ -93,4 +98,12 @@
             String groupId,
             String tokenSecret,
             GroupMemberConfig config);
+
+    /**
+     * Handle the intercepted URL to show relevant data sharing group information.
+     *
+     * @param url The URL of the current share action.
+     */
+    @CalledByNative
+    public void handleShareURLIntercepted(GURL url);
 }
diff --git a/components/data_sharing/public/data_sharing_ui_delegate.h b/components/data_sharing/public/data_sharing_ui_delegate.h
new file mode 100644
index 0000000..7720d6e
--- /dev/null
+++ b/components/data_sharing/public/data_sharing_ui_delegate.h
@@ -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.
+
+#ifndef COMPONENTS_DATA_SHARING_PUBLIC_DATA_SHARING_UI_DELEGATE_H_
+#define COMPONENTS_DATA_SHARING_PUBLIC_DATA_SHARING_UI_DELEGATE_H_
+
+namespace data_sharing {
+
+// An interface for the data sharing service to communicate with UI elements.
+class DataSharingUIDelegate {
+ public:
+  DataSharingUIDelegate() = default;
+  virtual ~DataSharingUIDelegate() = default;
+
+  // Handle the intercepted URL to show relevant data sharing group information.
+  virtual void HandleShareURLIntercepted(const GURL& url) = 0;
+};
+
+}  // namespace data_sharing
+
+#endif  // COMPONENTS_DATA_SHARING_PUBLIC_DATA_SHARING_UI_DELEGATE_H_
diff --git a/components/data_sharing/internal/mock_data_sharing_network_loader.cc b/components/data_sharing/test_support/mock_data_sharing_network_loader.cc
similarity index 79%
rename from components/data_sharing/internal/mock_data_sharing_network_loader.cc
rename to components/data_sharing/test_support/mock_data_sharing_network_loader.cc
index 5c68a08..5d75815 100644
--- a/components/data_sharing/internal/mock_data_sharing_network_loader.cc
+++ b/components/data_sharing/test_support/mock_data_sharing_network_loader.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/data_sharing/internal/mock_data_sharing_network_loader.h"
+#include "components/data_sharing/test_support/mock_data_sharing_network_loader.h"
 
 namespace data_sharing {
 
diff --git a/components/data_sharing/internal/mock_data_sharing_network_loader.h b/components/data_sharing/test_support/mock_data_sharing_network_loader.h
similarity index 82%
rename from components/data_sharing/internal/mock_data_sharing_network_loader.h
rename to components/data_sharing/test_support/mock_data_sharing_network_loader.h
index 1a3863e4..7819c7e1 100644
--- a/components/data_sharing/internal/mock_data_sharing_network_loader.h
+++ b/components/data_sharing/test_support/mock_data_sharing_network_loader.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_DATA_SHARING_INTERNAL_MOCK_DATA_SHARING_NETWORK_LOADER_H_
-#define COMPONENTS_DATA_SHARING_INTERNAL_MOCK_DATA_SHARING_NETWORK_LOADER_H_
+#ifndef COMPONENTS_DATA_SHARING_TEST_SUPPORT_MOCK_DATA_SHARING_NETWORK_LOADER_H_
+#define COMPONENTS_DATA_SHARING_TEST_SUPPORT_MOCK_DATA_SHARING_NETWORK_LOADER_H_
 
 #include <string>
 #include <vector>
@@ -38,4 +38,4 @@
 
 }  // namespace data_sharing
 
-#endif  // COMPONENTS_DATA_SHARING_INTERNAL_MOCK_DATA_SHARING_NETWORK_LOADER_H_
+#endif  // COMPONENTS_DATA_SHARING_TEST_SUPPORT_MOCK_DATA_SHARING_NETWORK_LOADER_H_
diff --git a/components/data_sharing/internal/mock_data_sharing_service.cc b/components/data_sharing/test_support/mock_data_sharing_service.cc
similarity index 80%
rename from components/data_sharing/internal/mock_data_sharing_service.cc
rename to components/data_sharing/test_support/mock_data_sharing_service.cc
index d09c241..feee9d92 100644
--- a/components/data_sharing/internal/mock_data_sharing_service.cc
+++ b/components/data_sharing/test_support/mock_data_sharing_service.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/data_sharing/internal/mock_data_sharing_service.h"
+#include "components/data_sharing/test_support/mock_data_sharing_service.h"
 
 namespace data_sharing {
 
diff --git a/components/data_sharing/internal/mock_data_sharing_service.h b/components/data_sharing/test_support/mock_data_sharing_service.h
similarity index 90%
rename from components/data_sharing/internal/mock_data_sharing_service.h
rename to components/data_sharing/test_support/mock_data_sharing_service.h
index 72bce42..c8db7a6 100644
--- a/components/data_sharing/internal/mock_data_sharing_service.h
+++ b/components/data_sharing/test_support/mock_data_sharing_service.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_DATA_SHARING_INTERNAL_MOCK_DATA_SHARING_SERVICE_H_
-#define COMPONENTS_DATA_SHARING_INTERNAL_MOCK_DATA_SHARING_SERVICE_H_
+#ifndef COMPONENTS_DATA_SHARING_TEST_SUPPORT_MOCK_DATA_SHARING_SERVICE_H_
+#define COMPONENTS_DATA_SHARING_TEST_SUPPORT_MOCK_DATA_SHARING_SERVICE_H_
 
 #include "base/functional/callback_forward.h"
 #include "base/types/expected.h"
@@ -57,4 +57,4 @@
 
 }  // namespace data_sharing
 
-#endif  // COMPONENTS_DATA_SHARING_INTERNAL_MOCK_DATA_SHARING_SERVICE_H_
+#endif  // COMPONENTS_DATA_SHARING_TEST_SUPPORT_MOCK_DATA_SHARING_SERVICE_H_
diff --git a/components/facilitated_payments_strings.grdp b/components/facilitated_payments_strings.grdp
index cb26a26..c570b1c7 100644
--- a/components/facilitated_payments_strings.grdp
+++ b/components/facilitated_payments_strings.grdp
@@ -14,8 +14,9 @@
   <message name="IDS_SETTINGS_MANAGE_OTHER_FINANCIAL_ACCOUNTS_PIX" desc="Pix is an instant payment platform used in Brazil. This is the string added to the summary for the 'Manage other financial accounts' preference when user has accounts available to be used with the Pix platform." formatter_data="android_java" translateable="false">
     Pix
   </message>
+  <!--TODO(b/339939404): Fix typo and make PIX related strings to generic names shared between bottom sheet and settings page. -->
   <message name="IDS_SETTINGS_PIX_BANK_ACCOUNT_IDENTIFER" desc="Identifier for bank account that can be used for the Pix payment platform." formatter_data="android_java" translateable="false">
-    Pix  •  <ph name="BANK_ACCOUNT_TYPE">%1$s<ex>Checking</ex></ph> •• <ph name="ACCOUNT_NUMBER_SUFFIX">%2$s<ex>1234</ex></ph>
+    Pix  •  <ph name="BANK_ACCOUNT_TYPE">%1$s<ex>Checking</ex></ph> ••••<ph name="ACCOUNT_NUMBER_SUFFIX">%2$s<ex>1234</ex></ph>
   </message>
   <message name="IDS_BANK_ACCOUNT_TYPE_CHECKING" desc="A checking bank account is for users to transact their regular expenses. This is the string to describe a checking bank account." formatter_data="android_java">
     Checking
diff --git a/components/js_injection/browser/js_communication_host.cc b/components/js_injection/browser/js_communication_host.cc
index 14bd5b8..e59a79a 100644
--- a/components/js_injection/browser/js_communication_host.cc
+++ b/components/js_injection/browser/js_communication_host.cc
@@ -86,6 +86,37 @@
     const JsCommunicationHost::AddScriptResult&) = default;
 JsCommunicationHost::AddScriptResult::~AddScriptResult() = default;
 
+// Holds a set of JsToBrowserMessaging objects for a frame and allows notifying
+// the objects of renderer side messages.
+class JsCommunicationHost::JsToBrowserMessagingList
+    : public mojom::JsObjectsClient {
+ public:
+  JsToBrowserMessagingList(
+      std::map<std::u16string, std::unique_ptr<JsToBrowserMessaging>>
+          js_to_browser_messagings,
+      mojo::PendingAssociatedReceiver<mojom::JsObjectsClient> receiver)
+      : js_to_browser_messagings_(std::move(js_to_browser_messagings)),
+        receiver_(this, std::move(receiver)) {}
+
+  // mojom::JsObjectsClient:
+  void OnWindowObjectCleared() override {
+    for (auto& kv : js_to_browser_messagings_) {
+      // Send an empty remote here. The remote will be bound lazily when needed.
+      kv.second->SetBrowserToJsMessaging({});
+    }
+  }
+
+  const std::map<std::u16string, std::unique_ptr<JsToBrowserMessaging>>&
+  js_to_browser_messagings() const {
+    return js_to_browser_messagings_;
+  }
+
+ private:
+  const std::map<std::u16string, std::unique_ptr<JsToBrowserMessaging>>
+      js_to_browser_messagings_;
+  mojo::AssociatedReceiver<mojom::JsObjectsClient> receiver_;
+};
+
 JsCommunicationHost::JsCommunicationHost(content::WebContents* web_contents)
     : content::WebContentsObserver(web_contents) {}
 
@@ -239,8 +270,8 @@
   using LifecycleState = content::RenderFrameHost::LifecycleState;
   if (old_state == LifecycleState::kPrerendering &&
       new_state == LifecycleState::kActive) {
-    for (auto& js_to_browser_messaging_ptr : iter->second) {
-      js_to_browser_messaging_ptr->OnRenderFrameHostActivated();
+    for (auto& kv : iter->second->js_to_browser_messagings()) {
+      kv.second->OnRenderFrameHostActivated();
     }
   }
 }
@@ -266,6 +297,8 @@
       &configurator_remote);
   std::vector<mojom::JsObjectPtr> js_objects;
   js_objects.reserve(js_objects_.size());
+  std::map<std::u16string, std::unique_ptr<JsToBrowserMessaging>>
+      js_to_browser_messagings;
   for (const auto& js_object : js_objects_) {
     if (NavigationWebMessageSender::IsNavigationListener(js_object->name)) {
       // This is the special navigationListener object that is registered to
@@ -281,16 +314,23 @@
       continue;
     }
     mojo::PendingAssociatedRemote<mojom::JsToBrowserMessaging> pending_remote;
-    js_to_browser_messagings_[render_frame_host->GetGlobalId()].emplace_back(
+    mojo::PendingAssociatedReceiver<mojom::BrowserToJsMessagingFactory> factory;
+    js_to_browser_messagings[js_object->name] =
         std::make_unique<JsToBrowserMessaging>(
             render_frame_host,
             pending_remote.InitWithNewEndpointAndPassReceiver(),
-            js_object->factory.get(), js_object->allowed_origin_rules));
-    js_objects.push_back(mojom::JsObject::New(js_object->name,
-                                              std::move(pending_remote),
-                                              js_object->allowed_origin_rules));
+            factory.InitWithNewEndpointAndPassRemote(),
+            js_object->factory.get(), js_object->allowed_origin_rules);
+    js_objects.push_back(mojom::JsObject::New(
+        js_object->name, std::move(pending_remote), std::move(factory),
+        js_object->allowed_origin_rules));
   }
-  configurator_remote->SetJsObjects(std::move(js_objects));
+  mojo::PendingAssociatedRemote<mojom::JsObjectsClient> client;
+  js_to_browser_messagings_[render_frame_host->GetGlobalId()] =
+      std::make_unique<JsToBrowserMessagingList>(
+          std::move(js_to_browser_messagings),
+          client.InitWithNewEndpointAndPassReceiver());
+  configurator_remote->SetJsObjects(std::move(js_objects), std::move(client));
 }
 
 void JsCommunicationHost::PrimaryPageChanged(content::Page& page) {
diff --git a/components/js_injection/browser/js_communication_host.h b/components/js_injection/browser/js_communication_host.h
index 975757c..bd9dae6 100644
--- a/components/js_injection/browser/js_communication_host.h
+++ b/components/js_injection/browser/js_communication_host.h
@@ -23,7 +23,6 @@
 
 class OriginMatcher;
 struct JsObject;
-class JsToBrowserMessaging;
 class WebMessageHostFactory;
 
 struct DocumentStartJavaScript {
@@ -111,6 +110,7 @@
   void PrimaryPageChanged(content::Page& page) override;
 
  private:
+  class JsToBrowserMessagingList;
   void NotifyFrameForWebMessageListener(
       content::RenderFrameHost* render_frame_host);
   void NotifyFrameForAllDocumentStartJavaScripts(
@@ -126,7 +126,7 @@
   std::vector<DocumentStartJavaScript> scripts_;
   std::vector<std::unique_ptr<JsObject>> js_objects_;
   std::map<content::GlobalRenderFrameHostId,
-           std::vector<std::unique_ptr<JsToBrowserMessaging>>>
+           std::unique_ptr<JsToBrowserMessagingList>>
       js_to_browser_messagings_;
   bool has_navigation_listener_ = false;
 };
diff --git a/components/js_injection/browser/js_to_browser_messaging.cc b/components/js_injection/browser/js_to_browser_messaging.cc
index 4dc0562..ac3f983 100644
--- a/components/js_injection/browser/js_to_browser_messaging.cc
+++ b/components/js_injection/browser/js_to_browser_messaging.cc
@@ -69,34 +69,50 @@
 
 class JsToBrowserMessaging::ReplyProxyImpl : public WebMessageReplyProxy {
  public:
-  ReplyProxyImpl(content::RenderFrameHost* render_frame_host,
-                 mojo::PendingAssociatedRemote<mojom::BrowserToJsMessaging>
-                     java_to_js_messaging)
+  ReplyProxyImpl(
+      content::RenderFrameHost* render_frame_host,
+      mojo::PendingAssociatedRemote<mojom::BrowserToJsMessaging>
+          java_to_js_messaging,
+      mojo::SharedAssociatedRemote<mojom::BrowserToJsMessagingFactory> factory)
       : render_frame_host_(render_frame_host),
-        java_to_js_messaging_(std::move(java_to_js_messaging)) {}
+        java_to_js_messaging_(std::move(java_to_js_messaging)),
+        factory_(std::move(factory)) {}
   ReplyProxyImpl(const ReplyProxyImpl&) = delete;
   ReplyProxyImpl& operator=(const ReplyProxyImpl&) = delete;
   ~ReplyProxyImpl() override = default;
 
   // WebMessageReplyProxy:
   void PostWebMessage(blink::WebMessagePayload message) override {
+    EnsureBrowserToJsMessaging();
     java_to_js_messaging_->OnPostMessage(std::move(message));
   }
+
+  void EnsureBrowserToJsMessaging() {
+    if (!java_to_js_messaging_ && factory_) {
+      factory_->SendBrowserToJsMessaging(
+          java_to_js_messaging_.BindNewEndpointAndPassReceiver());
+    }
+  }
+
   content::Page& GetPage() override { return render_frame_host_->GetPage(); }
 
  private:
   raw_ptr<content::RenderFrameHost> render_frame_host_;
   mojo::AssociatedRemote<mojom::BrowserToJsMessaging> java_to_js_messaging_;
+  mojo::SharedAssociatedRemote<mojom::BrowserToJsMessagingFactory> factory_;
 };
 
 JsToBrowserMessaging::JsToBrowserMessaging(
     content::RenderFrameHost* render_frame_host,
     mojo::PendingAssociatedReceiver<mojom::JsToBrowserMessaging> receiver,
+    mojo::PendingAssociatedRemote<mojom::BrowserToJsMessagingFactory>
+        browser_to_js_factory,
     WebMessageHostFactory* factory,
     const OriginMatcher& origin_matcher)
     : render_frame_host_(render_frame_host),
       connection_factory_(factory),
-      origin_matcher_(origin_matcher) {
+      origin_matcher_(origin_matcher),
+      browser_to_js_factory_(std::move(browser_to_js_factory)) {
   receiver_.Bind(std::move(receiver));
 }
 
@@ -152,6 +168,7 @@
 
   // SetBrowserToJsMessaging must be called before this.
   DCHECK(reply_proxy_);
+  reply_proxy_->EnsureBrowserToJsMessaging();
 
   if (!host_) {
     const std::string top_level_origin_string =
@@ -207,7 +224,8 @@
   // more than once because of reusing of RenderFrame.
   host_.reset();
   reply_proxy_ = std::make_unique<ReplyProxyImpl>(
-      render_frame_host_, std::move(java_to_js_messaging));
+      render_frame_host_, std::move(java_to_js_messaging),
+      browser_to_js_factory_);
 }
 
 }  // namespace js_injection
diff --git a/components/js_injection/browser/js_to_browser_messaging.h b/components/js_injection/browser/js_to_browser_messaging.h
index 7cb23b4c..e9bfdfb 100644
--- a/components/js_injection/browser/js_to_browser_messaging.h
+++ b/components/js_injection/browser/js_to_browser_messaging.h
@@ -16,6 +16,7 @@
 #include "mojo/public/cpp/bindings/associated_remote.h"
 #include "mojo/public/cpp/bindings/pending_associated_receiver.h"
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
+#include "mojo/public/cpp/bindings/shared_associated_remote.h"
 #include "third_party/blink/public/common/messaging/message_port_descriptor.h"
 #include "third_party/blink/public/common/messaging/string_message_codec.h"
 
@@ -37,6 +38,8 @@
   JsToBrowserMessaging(
       content::RenderFrameHost* rfh,
       mojo::PendingAssociatedReceiver<mojom::JsToBrowserMessaging> receiver,
+      mojo::PendingAssociatedRemote<mojom::BrowserToJsMessagingFactory>
+          browser_to_js_factory,
       WebMessageHostFactory* factory,
       const OriginMatcher& origin_matcher);
 
@@ -64,6 +67,8 @@
   OriginMatcher origin_matcher_;
   mojo::AssociatedReceiver<mojom::JsToBrowserMessaging> receiver_{this};
   std::unique_ptr<WebMessageHost> host_;
+  mojo::SharedAssociatedRemote<mojom::BrowserToJsMessagingFactory>
+      browser_to_js_factory_;
 #if DCHECK_IS_ON()
   std::string top_level_origin_string_;
   std::string origin_string_;
diff --git a/components/js_injection/common/interfaces.mojom b/components/js_injection/common/interfaces.mojom
index 4b1d2cc..d20c8df3 100644
--- a/components/js_injection/common/interfaces.mojom
+++ b/components/js_injection/common/interfaces.mojom
@@ -10,13 +10,18 @@
 import "third_party/blink/public/mojom/messaging/message_port_descriptor.mojom";
 
 // JsObject struct represents a JavaScript object we will inject in the main
-// JavaScript world of a frame. |js_object_name| will be used as the name
-// of the JavaScript object. We will inject the object if the frame's origin
-// matches |origin_matcher|. |js_to_browser_messaging| will be used for that
-// JavaScript object to send message back to browser side.
+// JavaScript world of a frame. |js_object_name| will be used as the name of the
+// JavaScript object. We will inject the object if the frame's origin matches
+// |origin_matcher|. |js_to_browser_messaging| will be used for that JavaScript
+// object to send message back to browser side. |browser_to_js_factory| is used
+// when the kLazyBindJsInjection feature is enabled to request a
+// BrowserToJsMessaging pipe from the renderer when needed. If this is not set,
+// SetBrowserToJsMessaging() must be called from the renderer to pass the pipe.
 struct JsObject {
   mojo_base.mojom.String16 js_object_name;
   pending_associated_remote<JsToBrowserMessaging> js_to_browser_messaging;
+  pending_associated_receiver<BrowserToJsMessagingFactory>
+      browser_to_js_factory;
   js_injection.mojom.OriginMatcher origin_matcher;
 };
 
@@ -62,6 +67,19 @@
     pending_associated_remote<BrowserToJsMessaging> browser_to_js_messaging);
 };
 
+// Client interface to send batch messages related to JsObject.
+interface JsObjectsClient {
+  // Notifies the browser that the window object has been cleared for the frame.
+  OnWindowObjectCleared();
+};
+
+// Allows lazily binding the BrowserToJsMessaging pipe.
+interface BrowserToJsMessagingFactory {
+  // Sends a new BrowsertoJsMessaging pipe to the renderer.
+  SendBrowserToJsMessaging(
+    pending_associated_receiver<BrowserToJsMessaging> browser_to_js_messaging);
+};
+
 // For the browser to reply back to injected JavaScript object. Implemented by
 // the renderer.
 interface BrowserToJsMessaging {
@@ -73,7 +91,8 @@
 interface JsCommunication {
   // Called from browser, to tell renderer that if we need to inject
   // JavaScript objects to the frame based on the |js_objects| array.
-  SetJsObjects(array<js_injection.mojom.JsObject> js_objects);
+  SetJsObjects(array<js_injection.mojom.JsObject> js_objects,
+               pending_associated_remote<JsObjectsClient> client);
 
   // Called from browser, to add a script for a frame to run at document start
   // stage. The script will run only if the frame's origin matches any of the
diff --git a/components/js_injection/renderer/js_binding.cc b/components/js_injection/renderer/js_binding.cc
index d3a82c9..3d45b68 100644
--- a/components/js_injection/renderer/js_binding.cc
+++ b/components/js_injection/renderer/js_binding.cc
@@ -77,18 +77,26 @@
 base::WeakPtr<JsBinding> JsBinding::Install(
     content::RenderFrame* render_frame,
     const std::u16string& js_object_name,
-    base::WeakPtr<JsCommunication> js_communication) {
+    base::WeakPtr<JsCommunication> js_communication,
+    v8::Isolate* isolate,
+    v8::Local<v8::Context> context) {
   CHECK(!js_object_name.empty())
       << "JavaScript wrapper name shouldn't be empty";
 
-  blink::WebLocalFrame* web_frame = render_frame->GetWebFrame();
-  v8::Isolate* isolate = web_frame->GetAgentGroupScheduler()->Isolate();
-  v8::HandleScope handle_scope(isolate);
-  v8::Local<v8::Context> context = web_frame->MainWorldScriptContext();
-  if (context.IsEmpty())
-    return nullptr;
+  std::optional<v8::HandleScope> handle_scope;
+  std::optional<v8::Context::Scope> context_scope;
+  // The scopes may have already been setup outside this method.
+  if (!isolate) {
+    blink::WebLocalFrame* web_frame = render_frame->GetWebFrame();
+    isolate = web_frame->GetAgentGroupScheduler()->Isolate();
+    handle_scope.emplace(isolate);
+    context = web_frame->MainWorldScriptContext();
+    if (context.IsEmpty()) {
+      return nullptr;
+    }
 
-  v8::Context::Scope context_scope(context);
+    context_scope.emplace(context);
+  }
   // The call to CreateHandle() takes ownership of `js_binding` (but only on
   // success).
   JsBinding* js_binding =
@@ -115,12 +123,6 @@
     : render_frame_(render_frame),
       js_object_name_(js_object_name),
       js_communication_(js_communication) {
-  mojom::JsToBrowserMessaging* js_to_java_messaging =
-      js_communication_->GetJsToJavaMessage(js_object_name_);
-  if (js_to_java_messaging) {
-    js_to_java_messaging->SetBrowserToJsMessaging(
-        receiver_.BindNewEndpointAndPassRemote());
-  }
 }
 
 JsBinding::~JsBinding() = default;
@@ -196,6 +198,12 @@
   on_message_.Reset();
 }
 
+void JsBinding::Bind(
+    mojo::PendingAssociatedReceiver<mojom::BrowserToJsMessaging> receiver) {
+  receiver_.reset();
+  return receiver_.Bind(std::move(receiver));
+}
+
 gin::ObjectTemplateBuilder JsBinding::GetObjectTemplateBuilder(
     v8::Isolate* isolate) {
   return gin::Wrappable<JsBinding>::GetObjectTemplateBuilder(isolate)
diff --git a/components/js_injection/renderer/js_binding.h b/components/js_injection/renderer/js_binding.h
index c5fa257..ed5a0ee 100644
--- a/components/js_injection/renderer/js_binding.h
+++ b/components/js_injection/renderer/js_binding.h
@@ -16,6 +16,7 @@
 #include "mojo/public/cpp/bindings/associated_receiver.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
 #include "third_party/blink/public/common/messaging/string_message_codec.h"
+#include "v8/include/v8.h"
 
 namespace v8 {
 template <typename T>
@@ -44,13 +45,18 @@
   static base::WeakPtr<JsBinding> Install(
       content::RenderFrame* render_frame,
       const std::u16string& js_object_name,
-      base::WeakPtr<JsCommunication> js_communication);
+      base::WeakPtr<JsCommunication> js_communication,
+      v8::Isolate* isolate,
+      v8::Local<v8::Context> context);
 
   // mojom::BrowserToJsMessaging implementation.
   void OnPostMessage(blink::WebMessagePayload message) override;
 
   void ReleaseV8GlobalObjects();
 
+  void Bind(
+      mojo::PendingAssociatedReceiver<mojom::BrowserToJsMessaging> receiver);
+
  protected:
   ~JsBinding() override;
 
diff --git a/components/js_injection/renderer/js_communication.cc b/components/js_injection/renderer/js_communication.cc
index d049751e..b65c7b8 100644
--- a/components/js_injection/renderer/js_communication.cc
+++ b/components/js_injection/renderer/js_communication.cc
@@ -9,17 +9,60 @@
 #include "content/public/common/isolated_world_ids.h"
 #include "content/public/renderer/render_frame.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
+#include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/public/web/web_local_frame.h"
 #include "third_party/blink/public/web/web_script_source.h"
 #include "url/gurl.h"
 #include "url/origin.h"
+#include "v8/include/v8.h"
 
 namespace js_injection {
+namespace {
 
-struct JsCommunication::JsObjectInfo {
-  OriginMatcher origin_matcher;
-  mojo::AssociatedRemote<mojom::JsToBrowserMessaging> js_to_java_messaging;
+// If enabled will bind browser->js pipes lazily instead of when the window
+// object is cleared.
+BASE_FEATURE(kLazyBindJsInjection,
+             "LazyBindJsInjection",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+}  // namespace
+
+class JsCommunication::JsObjectInfo
+    : public mojom::BrowserToJsMessagingFactory {
+ public:
+  explicit JsObjectInfo(mojom::JsObjectPtr js_object)
+      : origin_matcher_(js_object->origin_matcher),
+        js_to_java_messaging_(std::move(js_object->js_to_browser_messaging)),
+        factory_receiver_(this, std::move(js_object->browser_to_js_factory)) {}
+
+  // mojom::BrowserToJsMessagingFactory:
+  void SendBrowserToJsMessaging(
+      mojo::PendingAssociatedReceiver<mojom::BrowserToJsMessaging>
+          browser_to_js_messaging) override {
+    if (!js_binding_) {
+      return;
+    }
+
+    js_binding_->Bind(std::move(browser_to_js_messaging));
+  }
+
+  void SetBinding(base::WeakPtr<JsBinding> js_binding) {
+    js_binding_ = std::move(js_binding);
+  }
+
+  const OriginMatcher& origin_matcher() const { return origin_matcher_; }
+
+  mojom::JsToBrowserMessaging* js_to_java_messaging() const {
+    return js_to_java_messaging_.get();
+  }
+
+ private:
+  OriginMatcher origin_matcher_;
+  mojo::AssociatedRemote<mojom::JsToBrowserMessaging> js_to_java_messaging_;
+  mojo::AssociatedReceiver<mojom::BrowserToJsMessagingFactory>
+      factory_receiver_;
+  base::WeakPtr<JsBinding> js_binding_;
 };
 
 struct JsCommunication::DocumentStartJavaScript {
@@ -39,18 +82,17 @@
 JsCommunication::~JsCommunication() = default;
 
 void JsCommunication::SetJsObjects(
-    std::vector<mojom::JsObjectPtr> js_object_ptrs) {
+    std::vector<mojom::JsObjectPtr> js_object_ptrs,
+    mojo::PendingAssociatedRemote<mojom::JsObjectsClient> client) {
   JsObjectMap js_objects;
-  for (const auto& js_object : js_object_ptrs) {
-    const auto& js_object_info_pair = js_objects.insert(
-        {js_object->js_object_name, std::make_unique<JsObjectInfo>()});
-    JsObjectInfo* js_object_info = js_object_info_pair.first->second.get();
-    js_object_info->origin_matcher = js_object->origin_matcher;
-    js_object_info->js_to_java_messaging =
-        mojo::AssociatedRemote<mojom::JsToBrowserMessaging>(
-            std::move(js_object->js_to_browser_messaging));
+  for (auto& js_object : js_object_ptrs) {
+    std::u16string name = js_object->js_object_name;
+    js_objects.insert(
+        {name, std::make_unique<JsObjectInfo>(std::move(js_object))});
   }
   js_objects_.swap(js_objects);
+  client_remote_.reset();
+  client_remote_.Bind(std::move(client));
 }
 
 void JsCommunication::AddDocumentStartScript(
@@ -81,20 +123,56 @@
   // so we can't delete it here).
   weak_ptr_factory_for_bindings_.InvalidateWeakPtrs();
 
+  // As an optimization, we may set up the v8 scopes here for all the JS
+  // binding installations.
+  v8::Isolate* isolate = nullptr;
+  v8::Local<v8::Context> context;
+  std::optional<v8::HandleScope> handle_scope;
+  std::optional<v8::Context::Scope> context_scope;
+  if (base::FeatureList::IsEnabled(kLazyBindJsInjection)) {
+    blink::WebLocalFrame* web_frame = render_frame()->GetWebFrame();
+    isolate = web_frame->GetAgentGroupScheduler()->Isolate();
+    handle_scope.emplace(isolate);
+    context = web_frame->MainWorldScriptContext();
+    if (context.IsEmpty()) {
+      return;
+    }
+
+    context_scope.emplace(context);
+  }
+
   url::Origin frame_origin =
       url::Origin(render_frame()->GetWebFrame()->GetSecurityOrigin());
   std::vector<base::WeakPtr<JsBinding>> js_bindings;
   js_bindings.reserve(js_objects_.size());
+
   for (const auto& js_object : js_objects_) {
-    if (!js_object.second->origin_matcher.Matches(frame_origin))
+    if (!js_object.second->origin_matcher().Matches(frame_origin)) {
+      js_object.second->SetBinding(nullptr);
       continue;
-    base::WeakPtr<JsBinding> js_binding =
-        JsBinding::Install(render_frame(), js_object.first,
-                           weak_ptr_factory_for_bindings_.GetWeakPtr());
-    if (js_binding)
+    }
+    base::WeakPtr<JsBinding> js_binding = JsBinding::Install(
+        render_frame(), js_object.first,
+        weak_ptr_factory_for_bindings_.GetWeakPtr(), isolate, context);
+    if (js_binding) {
+      if (base::FeatureList::IsEnabled(kLazyBindJsInjection)) {
+        js_object.second->SetBinding(js_binding);
+      } else {
+        mojom::JsToBrowserMessaging* js_to_java_messaging =
+            GetJsToJavaMessage(js_object.first);
+        if (js_to_java_messaging) {
+          mojo::PendingAssociatedRemote<mojom::BrowserToJsMessaging> remote;
+          js_binding->Bind(remote.InitWithNewEndpointAndPassReceiver());
+          js_to_java_messaging->SetBrowserToJsMessaging(std::move(remote));
+        }
+      }
       js_bindings.push_back(std::move(js_binding));
+    }
   }
   js_bindings_.swap(js_bindings);
+  if (client_remote_ && base::FeatureList::IsEnabled(kLazyBindJsInjection)) {
+    client_remote_->OnWindowObjectCleared();
+  }
 }
 
 void JsCommunication::WillReleaseScriptContext(v8::Local<v8::Context> context,
@@ -138,7 +216,7 @@
   auto iterator = js_objects_.find(js_object_name);
   if (iterator == js_objects_.end())
     return nullptr;
-  return iterator->second->js_to_java_messaging.get();
+  return iterator->second->js_to_java_messaging();
 }
 
 }  // namespace js_injection
diff --git a/components/js_injection/renderer/js_communication.h b/components/js_injection/renderer/js_communication.h
index f404d4d..165867ad 100644
--- a/components/js_injection/renderer/js_communication.h
+++ b/components/js_injection/renderer/js_communication.h
@@ -37,7 +37,9 @@
   ~JsCommunication() override;
 
   // mojom::JsCommunication implementation
-  void SetJsObjects(std::vector<mojom::JsObjectPtr> js_object_ptrs) override;
+  void SetJsObjects(
+      std::vector<mojom::JsObjectPtr> js_object_ptrs,
+      mojo::PendingAssociatedRemote<mojom::JsObjectsClient> client) override;
   void AddDocumentStartScript(
       mojom::DocumentStartJavaScriptPtr script_ptr) override;
   void RemoveDocumentStartScript(int32_t script_id) override;
@@ -54,7 +56,7 @@
       const std::u16string& js_object_name);
 
  private:
-  struct JsObjectInfo;
+  class JsObjectInfo;
   struct DocumentStartJavaScript;
 
   void BindPendingReceiver(
@@ -72,6 +74,7 @@
 
   // Associated with legacy IPC channel.
   mojo::AssociatedReceiver<mojom::JsCommunication> receiver_{this};
+  mojo::AssociatedRemote<mojom::JsObjectsClient> client_remote_;
 
   base::WeakPtrFactory<JsCommunication> weak_ptr_factory_for_bindings_{this};
 };
diff --git a/components/lens/lens_features.cc b/components/lens/lens_features.cc
index 9336e5a..3fb2799 100644
--- a/components/lens/lens_features.cc
+++ b/components/lens/lens_features.cc
@@ -86,6 +86,9 @@
 const base::FeatureParam<bool> kLensOverlayGoogleDseRequired{
     &kLensOverlay, "google-dse-required", true};
 
+const base::FeatureParam<bool> kUseLensOverlayForImageSearch{
+    &kLensOverlay, "use-for-image-search", true};
+
 constexpr base::FeatureParam<std::string> kLensOverlayEndpointUrl{
     &kLensOverlay, "endpoint-url",
     "https://lensfrontend-pa.googleapis.com/v1/crupload"};
@@ -328,4 +331,8 @@
   return kLensOverlayTapRegionWidth.Get();
 }
 
+bool UseLensOverlayForImageSearch() {
+  return kUseLensOverlayForImageSearch.Get();
+}
+
 }  // namespace lens::features
diff --git a/components/lens/lens_features.h b/components/lens/lens_features.h
index 00573e1cf2..960bcbd5 100644
--- a/components/lens/lens_features.h
+++ b/components/lens/lens_features.h
@@ -305,6 +305,12 @@
 // rather than drags.
 COMPONENT_EXPORT(LENS_FEATURES)
 extern int GetLensOverlayTapRegionWidth();
+
+// Returns whether to enable the image context menu extrypoint for Lens
+// Overlay.
+COMPONENT_EXPORT(LENS_FEATURES)
+extern bool UseLensOverlayForImageSearch();
+
 }  // namespace lens::features
 
 #endif  // COMPONENTS_LENS_LENS_FEATURES_H_
diff --git a/components/live_caption/views/caption_bubble.cc b/components/live_caption/views/caption_bubble.cc
index 42740fbfe..8a306abe 100644
--- a/components/live_caption/views/caption_bubble.cc
+++ b/components/live_caption/views/caption_bubble.cc
@@ -340,9 +340,6 @@
  public:
 #if defined(NEED_FOCUS_FOR_ACCESSIBILITY)
   CaptionBubbleLabel() {
-    SetAccessibleRole(ax::mojom::Role::kDocument);
-    SetAccessibleName(std::u16string(),
-                      ax::mojom::NameFrom::kAttributeExplicitlyEmpty);
     ax_mode_observer_ =
         std::make_unique<CaptionBubbleLabelAXModeObserver>(this);
     SetFocusBehaviorForAccessibility();
diff --git a/components/media_message_center/media_notification_view_impl_unittest.cc b/components/media_message_center/media_notification_view_impl_unittest.cc
index 6c48300..5dc0bf5 100644
--- a/components/media_message_center/media_notification_view_impl_unittest.cc
+++ b/components/media_message_center/media_notification_view_impl_unittest.cc
@@ -162,7 +162,9 @@
     return GetHeaderRow(view());
   }
 
-  std::u16string accessible_name() const { return view()->GetAccessibleName(); }
+  const std::u16string& accessible_name() const {
+    return view()->GetAccessibleName();
+  }
 
   views::View* button_row() const { return view()->button_row_; }
 
diff --git a/components/metrics/structured/BUILD.gn b/components/metrics/structured/BUILD.gn
index b088b0a5..e34f0c8 100644
--- a/components/metrics/structured/BUILD.gn
+++ b/components/metrics/structured/BUILD.gn
@@ -9,7 +9,7 @@
 
 # Structured metrics is subcomponent of UMA that gathers and reports structured
 # events with several attached metrics.
-static_library("structured") {
+source_set("structured") {
   sources = [
     "key_data_prefs_delegate.cc",
     "key_data_prefs_delegate.h",
@@ -55,7 +55,7 @@
 }
 
 if (is_chromeos_ash) {
-  static_library("external_metrics") {
+  source_set("external_metrics") {
     sources = [
       "external_metrics.cc",
       "external_metrics.h",
@@ -69,7 +69,10 @@
   }
 }
 
-static_library("events") {
+component("events") {
+  output_name = "metrics_structured"
+  defines = [ "IS_METRICS_STRUCTURED_IMPL" ]
+
   sources = [
     "enums.h",
     "event.cc",
@@ -77,7 +80,10 @@
     "structured_metrics_client.cc",
     "structured_metrics_client.h",
   ]
-  deps = [ "//base" ]
+  deps = [
+    "//base",
+    "//build:buildflag_header_h",
+  ]
 }
 
 proto_library("proto") {
@@ -96,7 +102,7 @@
   link_deps = [ "//third_party/metrics_proto" ]
 }
 
-# Sources used by all static libraries in this BUILD file.
+# Sources used by all source sets in this BUILD file.
 source_set("common") {
   sources = [
     "delegating_events_processor.cc",
@@ -123,7 +129,7 @@
   ]
 }
 
-static_library("structured_metrics_features") {
+source_set("structured_metrics_features") {
   sources = [
     "structured_metrics_features.cc",
     "structured_metrics_features.h",
@@ -161,9 +167,8 @@
 }
 
 # TODO(b/309122738): Generate the events by platform.
-static_library("structured_events") {
+source_set("structured_events") {
   sources = get_target_outputs(":gen_structured_events")
-
   public_deps = [
     ":events",
     "//components/metrics/structured/buildflags",
@@ -212,7 +217,7 @@
   }
 }
 
-static_library("structured_metrics_validator") {
+source_set("structured_metrics_validator") {
   sources = get_target_outputs(":gen_structured_metrics_validator") + [
               "event_validator.cc",
               "event_validator.h",
@@ -228,7 +233,7 @@
   ]
 }
 
-static_library("test_support") {
+source_set("test_support") {
   testonly = true
   sources = [
     "test/test_event_storage.cc",
@@ -240,6 +245,7 @@
     "test/test_structured_metrics_recorder.cc",
     "test/test_structured_metrics_recorder.h",
   ]
+
   deps = [
     ":structured",
     ":structured_metrics_validator",
diff --git a/components/metrics/structured/enums.h b/components/metrics/structured/enums.h
index 71aa4a9..621a3b0 100644
--- a/components/metrics/structured/enums.h
+++ b/components/metrics/structured/enums.h
@@ -5,8 +5,7 @@
 #ifndef COMPONENTS_METRICS_STRUCTURED_ENUMS_H_
 #define COMPONENTS_METRICS_STRUCTURED_ENUMS_H_
 
-namespace metrics {
-namespace structured {
+namespace metrics::structured {
 
 // Specifies the type of identifier attached to an event.
 enum class IdType {
@@ -25,7 +24,6 @@
   kPerDevice = 1,
 };
 
-}  // namespace structured
-}  // namespace metrics
+}  // namespace metrics::structured
 
 #endif  // COMPONENTS_METRICS_STRUCTURED_ENUMS_H_
diff --git a/components/metrics/structured/event.h b/components/metrics/structured/event.h
index ea904c53..bacd232 100644
--- a/components/metrics/structured/event.h
+++ b/components/metrics/structured/event.h
@@ -10,6 +10,7 @@
 #include <optional>
 #include <string>
 
+#include "base/component_export.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "components/metrics/structured/enums.h"
@@ -23,7 +24,7 @@
 // Event to be built and sent by StructuredMetrics clients. Builder
 // classes will be codegen'd from metrics definitions in structured.xml, but
 // clients may choose to use this class directly to build Events.
-class Event {
+class COMPONENT_EXPORT(METRICS_STRUCTURED) Event {
  public:
   // There should be a 1-1 mapping between MetricType and the mojom enums.
   //
@@ -40,7 +41,7 @@
   };
 
   // Holds the value and the type of the metric encoded.
-  struct MetricValue {
+  struct COMPONENT_EXPORT(METRICS_STRUCTURED) MetricValue {
     MetricValue() = default;
     MetricValue(MetricType type, base::Value value);
 
@@ -55,7 +56,7 @@
   };
 
   // Special metadata if event is a sequence project.
-  struct EventSequenceMetadata {
+  struct COMPONENT_EXPORT(METRICS_STRUCTURED) EventSequenceMetadata {
     explicit EventSequenceMetadata(int reset_counter);
     ~EventSequenceMetadata();
 
diff --git a/components/metrics/structured/structured_metrics_client.h b/components/metrics/structured/structured_metrics_client.h
index 0440c540..81905f3 100644
--- a/components/metrics/structured/structured_metrics_client.h
+++ b/components/metrics/structured/structured_metrics_client.h
@@ -5,9 +5,10 @@
 #ifndef COMPONENTS_METRICS_STRUCTURED_STRUCTURED_METRICS_CLIENT_H_
 #define COMPONENTS_METRICS_STRUCTURED_STRUCTURED_METRICS_CLIENT_H_
 
+#include "base/component_export.h"
 #include "base/memory/raw_ptr.h"
 #include "base/no_destructor.h"
-
+#include "build/buildflag.h"
 #include "components/metrics/structured/event.h"
 
 namespace metrics::structured {
@@ -16,7 +17,7 @@
 //
 // It allows a delegate to be set to control the recording logic as different
 // embedders have different requirements (ie ash vs lacros).
-class StructuredMetricsClient {
+class COMPONENT_EXPORT(METRICS_STRUCTURED) StructuredMetricsClient {
  public:
   class RecordingDelegate {
    public:
@@ -33,12 +34,23 @@
   StructuredMetricsClient& operator=(const StructuredMetricsClient& client) =
       delete;
 
+// Windows errors out with dllexport class cannot be applied to member of
+// dllexport class.
+#if BUILDFLAG(IS_WIN)
   // Provides access to global StructuredMetricsClient instance to record
   // metrics. This is typically used in the codegen.
   static StructuredMetricsClient* Get();
 
   // Records |event| using singleton from Get().
   static void Record(Event&& event);
+#else
+  // Provides access to global StructuredMetricsClient instance to record
+  // metrics. This is typically used in the codegen.
+  static COMPONENT_EXPORT(METRICS_STRUCTURED) StructuredMetricsClient* Get();
+
+  // Records |event| using singleton from Get().
+  static COMPONENT_EXPORT(METRICS_STRUCTURED) void Record(Event&& event);
+#endif  // BUILDFLAG(IS_WIN)
 
   // Sets the delegate for the client's recording logic. Should be called before
   // anything else. |this| does not take ownership of |delegate| and assumes
diff --git a/components/metrics/structured/structured_metrics_recorder_unittest.cc b/components/metrics/structured/structured_metrics_recorder_unittest.cc
index 24f2410..02309cc 100644
--- a/components/metrics/structured/structured_metrics_recorder_unittest.cc
+++ b/components/metrics/structured/structured_metrics_recorder_unittest.cc
@@ -111,12 +111,10 @@
   bool IsReadyToRecord() const override { return true; }
 };
 
-}  // namespace
-
-class TestStructuredMetricsRecorder : public StructuredMetricsRecorder {
+class TestSMRecorder : public StructuredMetricsRecorder {
  public:
-  TestStructuredMetricsRecorder(const base::FilePath& device_key_path,
-                                const base::FilePath& profile_key_path)
+  TestSMRecorder(const base::FilePath& device_key_path,
+                 const base::FilePath& profile_key_path)
       : StructuredMetricsRecorder(
             std::make_unique<TestKeyDataProvider>(device_key_path,
                                                   profile_key_path),
@@ -125,8 +123,6 @@
         static_cast<TestKeyDataProvider*>(key_data_provider());
   }
 
-  using StructuredMetricsRecorder::StructuredMetricsRecorder;
-
   void OnProfileAdded(const base::FilePath& profile_path) {
     test_key_data_provider_->OnProfileAdded(profile_path);
   }
@@ -135,6 +131,8 @@
   raw_ptr<TestKeyDataProvider> test_key_data_provider_;
 };
 
+}  // namespace
+
 class StructuredMetricsRecorderTest : public testing::Test {
  protected:
   void SetUp() override {
@@ -235,8 +233,8 @@
   // user logging in.
   void Init() {
     // Create the provider, normally done by the ChromeMetricsServiceClient.
-    recorder_ = std::make_unique<TestStructuredMetricsRecorder>(
-        device_key_path_, profile_key_path_);
+    recorder_ =
+        std::make_unique<TestSMRecorder>(device_key_path_, profile_key_path_);
     // Enable recording, normally done after the metrics service has checked
     // consent allows recording.
     recorder_->EnableRecording();
@@ -249,8 +247,8 @@
   // Enables recording without adding a profile.
   void InitWithoutLogin() {
     // Create the provider, normally done by the ChromeMetricsServiceClient.
-    recorder_ = std::make_unique<TestStructuredMetricsRecorder>(
-        device_key_path_, profile_key_path_);
+    recorder_ =
+        std::make_unique<TestSMRecorder>(device_key_path_, profile_key_path_);
     // Enable recording, normally done after the metrics service has checked
     // consent allows recording.
     recorder_->EnableRecording();
@@ -259,8 +257,8 @@
   // Sets up StructuredMetricsRecorder.
   void InitWithoutEnabling() {
     // Create the provider, normally done by the ChromeMetricsServiceClient.
-    recorder_ = std::make_unique<TestStructuredMetricsRecorder>(
-        device_key_path_, profile_key_path_);
+    recorder_ =
+        std::make_unique<TestSMRecorder>(device_key_path_, profile_key_path_);
   }
 
   bool is_initialized() { return recorder_->IsInitialized(); }
@@ -295,7 +293,7 @@
   }
 
  protected:
-  std::unique_ptr<TestStructuredMetricsRecorder> recorder_;
+  std::unique_ptr<TestSMRecorder> recorder_;
   // Feature list should be constructed before task environment.
   base::test::ScopedFeatureList scoped_feature_list_;
   base::test::TaskEnvironment task_environment_{
diff --git a/components/optimization_guide/core/tflite_op_resolver.cc b/components/optimization_guide/core/tflite_op_resolver.cc
index 0d481f45..11785cb6 100644
--- a/components/optimization_guide/core/tflite_op_resolver.cc
+++ b/components/optimization_guide/core/tflite_op_resolver.cc
@@ -390,7 +390,7 @@
   if (features::TFLiteXNNPACKDelegateEnabled()) {
     delegate_creators_.push_back([](TfLiteContext* context) {
       return tflite::MaybeCreateXNNPACKDelegate(
-          context, tflite::XNNPackQS8Options::disabled);
+          context, tflite::XNNPackQS8Options::default_value);
     });
   }
 #endif
diff --git a/components/viz/common/features.cc b/components/viz/common/features.cc
index 911c51c..9f3d837a 100644
--- a/components/viz/common/features.cc
+++ b/components/viz/common/features.cc
@@ -397,6 +397,13 @@
              "ColorConversionInRenderer",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Changes BeginFrame issue to use LastUsedBeginFrameArgs() instead of the
+// current set of BeginFrameArgs.
+// TODO(b/333940735): Should be removed if the issue isn't fixed.
+BASE_FEATURE(kUseLastBeginFrameArgs,
+             "UseLastBeginFrameArgs",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 bool IsDelegatedCompositingEnabled() {
   return base::FeatureList::IsEnabled(kDelegatedCompositing);
 }
diff --git a/components/viz/common/features.h b/components/viz/common/features.h
index a2f8628..3f953d2 100644
--- a/components/viz/common/features.h
+++ b/components/viz/common/features.h
@@ -96,6 +96,7 @@
 VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kSingleVideoFrameRateThrottling);
 VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kBatchMainThreadReleaseCallbacks);
 VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kColorConversionInRenderer);
+VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kUseLastBeginFrameArgs);
 
 VIZ_COMMON_EXPORT extern const char kDraw1Point12Ms[];
 VIZ_COMMON_EXPORT extern const char kDraw2Points6Ms[];
diff --git a/components/viz/common/frame_sinks/begin_frame_source.cc b/components/viz/common/frame_sinks/begin_frame_source.cc
index 71e5175a..4745f8a 100644
--- a/components/viz/common/frame_sinks/begin_frame_source.cc
+++ b/components/viz/common/frame_sinks/begin_frame_source.cc
@@ -23,6 +23,7 @@
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/traced_value.h"
 #include "base/tracing/protos/chrome_track_event.pbzero.h"
+#include "components/viz/common/features.h"
 #include "components/viz/common/frame_sinks/delay_based_time_source.h"
 
 namespace viz {
@@ -458,13 +459,19 @@
 void DelayBasedBeginFrameSource::IssueBeginFrameToObserver(
     BeginFrameObserver* obs,
     const BeginFrameArgs& args) {
+  BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs();
+
   // We should use |last_args| for margin calculation with
   // |obs->LastUsedBeginFrameArgs()| cached during last OnBeginFrame, as the
   // passed in |args| is updated if interval changes since last frame.
-  BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs();
+  auto args_for_margin =
+      base::FeatureList::IsEnabled(features::kUseLastBeginFrameArgs) ? last_args
+                                                                     : args;
+
   const base::TimeDelta double_tick_margin =
-      max_vrr_interval_.has_value() ? base::TimeDelta()
-                                    : last_args.interval / kDoubleTickDivisor;
+      max_vrr_interval_.has_value()
+          ? base::TimeDelta()
+          : args_for_margin.interval / kDoubleTickDivisor;
   if (!last_args.IsValid() ||
       (args.frame_time > last_args.frame_time + double_tick_margin)) {
     if (args.type == BeginFrameArgs::MISSED) {
diff --git a/content/browser/interest_group/auction_worklet_manager_unittest.cc b/content/browser/interest_group/auction_worklet_manager_unittest.cc
index e16cb141..9fa8cc9d 100644
--- a/content/browser/interest_group/auction_worklet_manager_unittest.cc
+++ b/content/browser/interest_group/auction_worklet_manager_unittest.cc
@@ -411,8 +411,8 @@
   }
 
   void ConnectDevToolsAgent(
-      mojo::PendingAssociatedReceiver<blink::mojom::DevToolsAgent> agent)
-      override {
+      mojo::PendingAssociatedReceiver<blink::mojom::DevToolsAgent> agent,
+      uint32_t thread_index) override {
     ADD_FAILURE()
         << "ConnectDevToolsAgent should not be called on MockSellerWorklet";
   }
diff --git a/content/browser/interest_group/debuggable_auction_worklet.cc b/content/browser/interest_group/debuggable_auction_worklet.cc
index 07016c1..29dddf2d 100644
--- a/content/browser/interest_group/debuggable_auction_worklet.cc
+++ b/content/browser/interest_group/debuggable_auction_worklet.cc
@@ -36,7 +36,7 @@
     (*bidder_worklet)->ConnectDevToolsAgent(std::move(agent));
   } else {
     absl::get<auction_worklet::mojom::SellerWorklet*>(worklet_)
-        ->ConnectDevToolsAgent(std::move(agent));
+        ->ConnectDevToolsAgent(std::move(agent), /*thread_index=*/0);
   }
 }
 
diff --git a/content/browser/interest_group/mock_auction_process_manager.cc b/content/browser/interest_group/mock_auction_process_manager.cc
index 71b0e53ca..73cc37b2 100644
--- a/content/browser/interest_group/mock_auction_process_manager.cc
+++ b/content/browser/interest_group/mock_auction_process_manager.cc
@@ -436,7 +436,8 @@
 }
 
 void MockSellerWorklet::ConnectDevToolsAgent(
-    mojo::PendingAssociatedReceiver<blink::mojom::DevToolsAgent> agent) {
+    mojo::PendingAssociatedReceiver<blink::mojom::DevToolsAgent> agent,
+    uint32_t thread_index) {
   ADD_FAILURE()
       << "ConnectDevToolsAgent should not be called on MockSellerWorklet";
 }
diff --git a/content/browser/interest_group/mock_auction_process_manager.h b/content/browser/interest_group/mock_auction_process_manager.h
index 2b14d023..cfe92e25 100644
--- a/content/browser/interest_group/mock_auction_process_manager.h
+++ b/content/browser/interest_group/mock_auction_process_manager.h
@@ -304,8 +304,8 @@
       uint64_t trace_id,
       ReportResultCallback report_result_callback) override;
   void ConnectDevToolsAgent(
-      mojo::PendingAssociatedReceiver<blink::mojom::DevToolsAgent> agent)
-      override;
+      mojo::PendingAssociatedReceiver<blink::mojom::DevToolsAgent> agent,
+      uint32_t thread_index) override;
 
   // Closes the receiver pipe with the provided reason.
   void ResetReceiverWithReason(const std::string& reason);
diff --git a/content/browser/web_package/signed_exchange_request_handler_browsertest.cc b/content/browser/web_package/signed_exchange_request_handler_browsertest.cc
index b60e74f..161c412 100644
--- a/content/browser/web_package/signed_exchange_request_handler_browsertest.cc
+++ b/content/browser/web_package/signed_exchange_request_handler_browsertest.cc
@@ -1440,13 +1440,8 @@
     : public SignedExchangeRequestHandlerBrowserTest {
  public:
   SignedExchangeReportingBrowserTest() {
-    feature_list_.InitWithFeatures(
-        // enabled_features
-        {net::features::kPartitionNelAndReportingByNetworkIsolationKey,
-         net::features::kPartitionConnectionsByNetworkIsolationKey,
-         net::features::kPartitionSSLSessionsByNetworkIsolationKey},
-        // disabled_features
-        {});
+    feature_list_.InitAndEnableFeature(
+        net::features::kPartitionConnectionsByNetworkIsolationKey);
   }
 
   ~SignedExchangeReportingBrowserTest() override = default;
diff --git a/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc b/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc
index 176d4340..4a9b45e 100644
--- a/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc
+++ b/content/browser/web_package/signed_exchange_subresource_prefetch_browsertest.cc
@@ -752,11 +752,7 @@
     enable_features.push_back(features::kSignedHTTPExchange);
     // Needed for reporting test. Doesn't significantly impact other tests.
     enable_features.push_back(
-        net::features::kPartitionNelAndReportingByNetworkIsolationKey);
-    enable_features.push_back(
         net::features::kPartitionConnectionsByNetworkIsolationKey);
-    enable_features.push_back(
-        net::features::kPartitionSSLSessionsByNetworkIsolationKey);
 
     feature_list_.InitWithFeatures(enable_features, disabled_features);
 
diff --git a/content/browser/webauth/authenticator_common_impl.cc b/content/browser/webauth/authenticator_common_impl.cc
index ddbef6c..a7b650a 100644
--- a/content/browser/webauth/authenticator_common_impl.cc
+++ b/content/browser/webauth/authenticator_common_impl.cc
@@ -660,9 +660,13 @@
           UsesDiscoverableCreds(*req_state_->make_credential_options),
           is_uvpaa_override_);
 
+  auto platform_discoveries =
+      discovery_factory()->IsTestOverride()
+          ? std::vector<std::unique_ptr<device::FidoDiscoveryBase>>()
+          : req_state_->request_delegate->CreatePlatformDiscoveries();
   req_state_->request_handler =
       std::make_unique<device::MakeCredentialRequestHandler>(
-          discovery_factory(), transports,
+          discovery_factory(), std::move(platform_discoveries), transports,
           *req_state_->ctap_make_credential_request,
           *req_state_->make_credential_options,
           base::BindOnce(&AuthenticatorCommonImpl::OnRegisterResponse,
@@ -715,8 +719,13 @@
           UsesDiscoverableCreds(*req_state_->ctap_get_assertion_request),
           is_uvpaa_override_);
 
+  auto platform_discoveries =
+      discovery_factory()->IsTestOverride()
+          ? std::vector<std::unique_ptr<device::FidoDiscoveryBase>>()
+          : req_state_->request_delegate->CreatePlatformDiscoveries();
   auto request_handler = std::make_unique<device::GetAssertionRequestHandler>(
-      discovery_factory(), transports, *req_state_->ctap_get_assertion_request,
+      discovery_factory(), std::move(platform_discoveries), transports,
+      *req_state_->ctap_get_assertion_request,
       *req_state_->ctap_get_assertion_options, allow_skipping_pin_touch,
       base::BindOnce(&AuthenticatorCommonImpl::OnSignResponse,
                      weak_factory_.GetWeakPtr()));
diff --git a/content/public/browser/authenticator_request_client_delegate.cc b/content/public/browser/authenticator_request_client_delegate.cc
index 94827692..57b58d8 100644
--- a/content/public/browser/authenticator_request_client_delegate.cc
+++ b/content/public/browser/authenticator_request_client_delegate.cc
@@ -205,6 +205,11 @@
 void AuthenticatorRequestClientDelegate::SetUserEntityForMakeCredentialRequest(
     const device::PublicKeyCredentialUserEntity&) {}
 
+std::vector<std::unique_ptr<device::FidoDiscoveryBase>>
+AuthenticatorRequestClientDelegate::CreatePlatformDiscoveries() {
+  return {};
+}
+
 void AuthenticatorRequestClientDelegate::OnTransportAvailabilityEnumerated(
     device::FidoRequestHandlerBase::TransportAvailabilityInfo data) {}
 
diff --git a/content/public/browser/authenticator_request_client_delegate.h b/content/public/browser/authenticator_request_client_delegate.h
index ec374212..09e1b3a 100644
--- a/content/public/browser/authenticator_request_client_delegate.h
+++ b/content/public/browser/authenticator_request_client_delegate.h
@@ -366,6 +366,12 @@
   virtual void SetUserEntityForMakeCredentialRequest(
       const device::PublicKeyCredentialUserEntity& user_entity);
 
+  // Returns a list of `FidoDiscoveryBase` instances that can instantiate an
+  // embedder-specific platform authenticator for handling WebAuthn requests.
+  // The discoveries' `transport()` must be `FidoTransportProtocol::kInternal`.
+  virtual std::vector<std::unique_ptr<device::FidoDiscoveryBase>>
+  CreatePlatformDiscoveries();
+
   // device::FidoRequestHandlerBase::Observer:
   void OnTransportAvailabilityEnumerated(
       device::FidoRequestHandlerBase::TransportAvailabilityInfo data) override;
diff --git a/content/services/auction_worklet/auction_worklet_service_impl.cc b/content/services/auction_worklet/auction_worklet_service_impl.cc
index d9933c5..39e52c07 100644
--- a/content/services/auction_worklet/auction_worklet_service_impl.cc
+++ b/content/services/auction_worklet/auction_worklet_service_impl.cc
@@ -224,13 +224,20 @@
     const url::Origin& top_window_origin,
     mojom::AuctionWorkletPermissionsPolicyStatePtr permissions_policy_state,
     std::optional<uint16_t> experiment_group_id) {
+  std::vector<mojo::PendingRemote<mojom::AuctionSharedStorageHost>>
+      shared_storage_hosts;
+  shared_storage_hosts.push_back(std::move(shared_storage_host_remote));
+
   auto seller_worklet = std::make_unique<SellerWorklet>(
-      auction_seller_v8_helper_holder_->V8Helper(),
-      std::move(shared_storage_host_remote), pause_for_debugger_on_start,
+      std::vector{auction_seller_v8_helper_holder_->V8Helper()},
+      std::move(shared_storage_hosts), pause_for_debugger_on_start,
       std::move(pending_url_loader_factory),
       std::move(auction_network_events_handler), decision_logic_url,
       trusted_scoring_signals_url, top_window_origin,
-      std::move(permissions_policy_state), experiment_group_id);
+      std::move(permissions_policy_state), experiment_group_id,
+      base::BindRepeating(
+          &AuctionWorkletServiceImpl::GetNextSellerWorkletThreadIndex,
+          base::Unretained(this)));
   auto* seller_worklet_ptr = seller_worklet.get();
 
   mojo::ReceiverId receiver_id = seller_worklets_.Add(
@@ -241,6 +248,10 @@
                      base::Unretained(this), receiver_id));
 }
 
+size_t AuctionWorkletServiceImpl::GetNextSellerWorkletThreadIndex() {
+  return 0;
+}
+
 void AuctionWorkletServiceImpl::DisconnectSellerWorklet(
     mojo::ReceiverId receiver_id,
     const std::string& reason) {
diff --git a/content/services/auction_worklet/auction_worklet_service_impl.h b/content/services/auction_worklet/auction_worklet_service_impl.h
index c38ed9f..794b3de 100644
--- a/content/services/auction_worklet/auction_worklet_service_impl.h
+++ b/content/services/auction_worklet/auction_worklet_service_impl.h
@@ -88,6 +88,10 @@
       mojom::AuctionWorkletPermissionsPolicyStatePtr permissions_policy_state,
       std::optional<uint16_t> experiment_group_id) override;
 
+  // Returns an index in the seller thread pool, where the corresponding V8
+  // thread will be used to execute the next task.
+  size_t GetNextSellerWorkletThreadIndex();
+
  private:
   class V8HelperHolder;
   enum class ProcessModel { kDedicated, kShared };
diff --git a/content/services/auction_worklet/public/mojom/seller_worklet.mojom b/content/services/auction_worklet/public/mojom/seller_worklet.mojom
index 6eb2dda..ea7cd337 100644
--- a/content/services/auction_worklet/public/mojom/seller_worklet.mojom
+++ b/content/services/auction_worklet/public/mojom/seller_worklet.mojom
@@ -387,7 +387,11 @@
            mojo_base.mojom.TimeDelta reporting_latency,
            array<string> error_msgs);
 
-  // Establishes a debugger connection to the worklet.
+  // Establishes a debugger connection to the worklet thread.
+  //
+  // Arguments:
+  // `thread_index` The index of the thread in the thread pool.
   ConnectDevToolsAgent(
-      pending_associated_receiver<blink.mojom.DevToolsAgent> agent);
+      pending_associated_receiver<blink.mojom.DevToolsAgent> agent,
+      uint32 thread_index);
 };
diff --git a/content/services/auction_worklet/seller_worklet.cc b/content/services/auction_worklet/seller_worklet.cc
index 9555ebb5..ae8bbf6 100644
--- a/content/services/auction_worklet/seller_worklet.cc
+++ b/content/services/auction_worklet/seller_worklet.cc
@@ -399,9 +399,9 @@
 }  // namespace
 
 SellerWorklet::SellerWorklet(
-    scoped_refptr<AuctionV8Helper> v8_helper,
-    mojo::PendingRemote<mojom::AuctionSharedStorageHost>
-        shared_storage_host_remote,
+    std::vector<scoped_refptr<AuctionV8Helper>> v8_helpers,
+    std::vector<mojo::PendingRemote<mojom::AuctionSharedStorageHost>>
+        shared_storage_hosts,
     bool pause_for_debugger_on_start,
     mojo::PendingRemote<network::mojom::URLLoaderFactory>
         pending_url_loader_factory,
@@ -411,22 +411,38 @@
     const std::optional<GURL>& trusted_scoring_signals_url,
     const url::Origin& top_window_origin,
     mojom::AuctionWorkletPermissionsPolicyStatePtr permissions_policy_state,
-    std::optional<uint16_t> experiment_group_id)
-    : v8_runner_(v8_helper->v8_runner()),
-      v8_helper_(std::move(v8_helper)),
-      debug_id_(
-          base::MakeRefCounted<AuctionV8Helper::DebugId>(v8_helper_.get())),
-      url_loader_factory_(std::move(pending_url_loader_factory)),
+    std::optional<uint16_t> experiment_group_id,
+    GetNextThreadIndexCallback get_next_thread_index_callback)
+    : url_loader_factory_(std::move(pending_url_loader_factory)),
       script_source_url_(decision_logic_url),
       trusted_scoring_signals_origin_(
           trusted_scoring_signals_url ? std::make_optional(url::Origin::Create(
                                             *trusted_scoring_signals_url))
                                       : std::nullopt),
-      v8_state_(nullptr, base::OnTaskRunnerDeleter(v8_runner_)),
       auction_network_events_handler_(
-          std::move(auction_network_events_handler)) {
+          std::move(auction_network_events_handler)),
+      get_next_thread_index_callback_(
+          std::move(get_next_thread_index_callback)) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_);
 
+  DCHECK(!v8_helpers.empty());
+  DCHECK_EQ(v8_helpers.size(), shared_storage_hosts.size());
+
+  for (size_t i = 0; i < v8_helpers.size(); ++i) {
+    v8_runners_.push_back(v8_helpers[i]->v8_runner());
+    v8_helpers_.push_back(std::move(v8_helpers[i]));
+    debug_ids_.push_back(
+        base::MakeRefCounted<AuctionV8Helper::DebugId>(v8_helpers_[i].get()));
+    v8_state_.push_back(std::unique_ptr<V8State, base::OnTaskRunnerDeleter>(
+        new V8State(v8_helpers_[i], debug_ids_[i],
+                    std::move(shared_storage_hosts[i]), decision_logic_url,
+                    trusted_scoring_signals_url,
+                    trusted_scoring_signals_origin_, top_window_origin,
+                    permissions_policy_state->Clone(), experiment_group_id,
+                    weak_ptr_factory_.GetWeakPtr()),
+        base::OnTaskRunnerDeleter(v8_runners_[i])));
+  }
+
   trusted_signals_request_manager_ =
       (trusted_scoring_signals_url
            ? std::make_unique<TrustedSignalsRequestManager>(
@@ -439,19 +455,11 @@
                  *trusted_scoring_signals_url,
                  /*experiment_group_id=*/experiment_group_id,
                  /*trusted_bidding_signals_slot_size_param=*/std::string(),
-                 v8_helper_.get())
+                 v8_helpers_[get_next_thread_index_callback_.Run()].get())
            : nullptr);
   trusted_signals_relation_ = ClassifyTrustedSignals(
       script_source_url_, trusted_scoring_signals_origin_);
 
-  v8_state_ = std::unique_ptr<V8State, base::OnTaskRunnerDeleter>(
-      new V8State(v8_helper_, debug_id_, std::move(shared_storage_host_remote),
-                  decision_logic_url, trusted_scoring_signals_url,
-                  trusted_scoring_signals_origin_, top_window_origin,
-                  std::move(permissions_policy_state), experiment_group_id,
-                  weak_ptr_factory_.GetWeakPtr()),
-      base::OnTaskRunnerDeleter(v8_runner_));
-
   paused_ = pause_for_debugger_on_start;
   if (!paused_) {
     Start();
@@ -460,11 +468,18 @@
 
 SellerWorklet::~SellerWorklet() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_);
-  debug_id_->AbortDebuggerPauses();
+
+  for (const auto& debug_id : debug_ids_) {
+    debug_id->AbortDebuggerPauses();
+  }
 }
 
-int SellerWorklet::context_group_id_for_testing() const {
-  return debug_id_->context_group_id();
+std::vector<int> SellerWorklet::context_group_ids_for_testing() const {
+  std::vector<int> results;
+  for (const auto& debug_id : debug_ids_) {
+    results.push_back(debug_id->context_group_id());
+  }
+  return results;
 }
 
 void SellerWorklet::ScoreAd(
@@ -706,12 +721,14 @@
 }
 
 void SellerWorklet::ConnectDevToolsAgent(
-    mojo::PendingAssociatedReceiver<blink::mojom::DevToolsAgent> agent) {
+    mojo::PendingAssociatedReceiver<blink::mojom::DevToolsAgent> agent,
+    uint32_t thread_index) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_);
-  v8_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&V8State::ConnectDevToolsAgent,
-                     base::Unretained(v8_state_.get()), std::move(agent)));
+
+  v8_runners_[thread_index]->PostTask(
+      FROM_HERE, base::BindOnce(&V8State::ConnectDevToolsAgent,
+                                base::Unretained(v8_state_[thread_index].get()),
+                                std::move(agent)));
 }
 
 SellerWorklet::ScoreAdTask::ScoreAdTask() = default;
@@ -1686,8 +1703,11 @@
     return;
   }
 
-  paused_ = false;
-  Start();
+  resumed_count_++;
+  if (resumed_count_ == v8_helpers_.size()) {
+    paused_ = false;
+    Start();
+  }
 }
 
 void SellerWorklet::Start() {
@@ -1706,11 +1726,12 @@
   base::UmaHistogramCounts100000(
       "Ads.InterestGroup.Net.RequestUrlSizeBytes.ScoringScriptJS",
       script_source_url_.spec().size());
+
   worklet_loader_ = std::make_unique<WorkletLoader>(
       url_loader_factory_.get(), /*auction_network_events_handler=*/
       CreateNewAuctionNetworkEventsHandlerRemote(
           auction_network_events_handler_),
-      script_source_url_, std::vector{v8_helper_}, std::vector{debug_id_},
+      script_source_url_, v8_helpers_, debug_ids_,
       std::move(on_got_cross_origin_signals_permissions),
       base::BindOnce(&SellerWorklet::OnDownloadComplete,
                      base::Unretained(this)));
@@ -1721,18 +1742,19 @@
     std::optional<std::string> error_msg) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(user_sequence_checker_);
 
-  DCHECK_EQ(worklet_scripts.size(), 1u);
-  WorkletLoader::Result worklet_script = std::move(worklet_scripts[0]);
+  DCHECK_EQ(worklet_scripts.size(), v8_helpers_.size());
 
+  // Use `worklet_scripts[0]` for metrics and for the failure check. All the
+  // results should be the same.
   base::UmaHistogramCounts10M(
       "Ads.InterestGroup.Net.ResponseSizeBytes.ScoringScriptJS",
-      worklet_script.original_size_bytes());
+      worklet_scripts[0].original_size_bytes());
   base::UmaHistogramTimes("Ads.InterestGroup.Net.DownloadTime.ScoringScriptJS",
-                          worklet_script.download_time());
+                          worklet_scripts[0].download_time());
   worklet_loader_.reset();
 
   // On failure, delete `this`, as it can't do anything without a loaded script.
-  bool success = worklet_script.success();
+  bool success = worklet_scripts[0].success();
   if (!success) {
     std::move(close_pipe_callback_)
         .Run(error_msg ? error_msg.value() : std::string());
@@ -1746,11 +1768,15 @@
 
   DCHECK_NE(trusted_signals_relation_,
             SignalsOriginRelation::kUnknownPermissionCrossOriginSignals);
-  v8_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&SellerWorklet::V8State::SetWorkletScript,
-                     base::Unretained(v8_state_.get()),
-                     std::move(worklet_script), trusted_signals_relation_));
+
+  for (size_t i = 0; i < v8_runners_.size(); ++i) {
+    v8_runners_[i]->PostTask(
+        FROM_HERE, base::BindOnce(&SellerWorklet::V8State::SetWorkletScript,
+                                  base::Unretained(v8_state_[i].get()),
+                                  std::move(worklet_scripts[i]),
+                                  trusted_signals_relation_));
+  }
+
   MaybeRecordCodeWait();
 
   for (auto score_ad_task = score_ad_tasks_.begin();
@@ -1969,10 +1995,12 @@
       base::BindOnce(&SellerWorklet::CleanUpScoreAdTaskOnUserThread,
                      weak_ptr_factory_.GetWeakPtr(), task));
 
+  int thread_index = get_next_thread_index_callback_.Run();
   task->task_id = cancelable_task_tracker_.PostTask(
-      v8_runner_.get(), FROM_HERE,
+      v8_runners_[thread_index].get(), FROM_HERE,
       base::BindOnce(
-          &SellerWorklet::V8State::ScoreAd, base::Unretained(v8_state_.get()),
+          &SellerWorklet::V8State::ScoreAd,
+          base::Unretained(v8_state_[thread_index].get()),
           task->ad_metadata_json, task->bid, std::move(task->bid_currency),
           std::move(task->auction_ad_config_non_shared_params),
           std::move(task->direct_from_seller_result_seller_signals),
@@ -1990,7 +2018,7 @@
           task->browser_signal_for_debugging_only_in_cooldown_or_lockout,
           std::move(task->seller_timeout), task->trace_id,
           base::ScopedClosureRunner(std::move(cleanup_score_ad_task)),
-          /*task_enqueued_time*/ base::TimeTicks::Now(),
+          /*task_enqueued_time=*/base::TimeTicks::Now(),
           base::BindOnce(&SellerWorklet::DeliverScoreAdCallbackOnUserThread,
                          weak_ptr_factory_.GetWeakPtr(), task)));
 }
@@ -2101,11 +2129,12 @@
       });
   TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("fledge", "post_v8_task", task->trace_id);
 
+  size_t thread_index = get_next_thread_index_callback_.Run();
   cancelable_task_tracker_.PostTask(
-      v8_runner_.get(), FROM_HERE,
+      v8_runners_[thread_index].get(), FROM_HERE,
       base::BindOnce(
           &SellerWorklet::V8State::ReportResult,
-          base::Unretained(v8_state_.get()),
+          base::Unretained(v8_state_[thread_index].get()),
           std::move(task->auction_ad_config_non_shared_params),
           std::move(task->direct_from_seller_result_seller_signals),
           std::move(task->direct_from_seller_seller_signals_header_ad_slot),
diff --git a/content/services/auction_worklet/seller_worklet.h b/content/services/auction_worklet/seller_worklet.h
index b507c30..43856ce 100644
--- a/content/services/auction_worklet/seller_worklet.h
+++ b/content/services/auction_worklet/seller_worklet.h
@@ -67,6 +67,8 @@
   using RealTimeReportingContributions =
       std::vector<auction_worklet::mojom::RealTimeReportingContributionPtr>;
 
+  using GetNextThreadIndexCallback = base::RepeatingCallback<size_t()>;
+
   // Classification of how trusted signals related to this worklet.
   // This is used for histograms, so entries should not be reordered or
   // otherwise renumbered.
@@ -86,9 +88,9 @@
 
   // Starts loading the worklet script on construction.
   SellerWorklet(
-      scoped_refptr<AuctionV8Helper> v8_helper,
-      mojo::PendingRemote<mojom::AuctionSharedStorageHost>
-          shared_storage_host_remote,
+      std::vector<scoped_refptr<AuctionV8Helper>> v8_helpers,
+      std::vector<mojo::PendingRemote<mojom::AuctionSharedStorageHost>>
+          shared_storage_hosts,
       bool pause_for_debugger_on_start,
       mojo::PendingRemote<network::mojom::URLLoaderFactory>
           pending_url_loader_factory,
@@ -98,7 +100,8 @@
       const std::optional<GURL>& trusted_scoring_signals_url,
       const url::Origin& top_window_origin,
       mojom::AuctionWorkletPermissionsPolicyStatePtr permissions_policy_state,
-      std::optional<uint16_t> experiment_group_id);
+      std::optional<uint16_t> experiment_group_id,
+      GetNextThreadIndexCallback next_thread_index_callback);
 
   explicit SellerWorklet(const SellerWorklet&) = delete;
   SellerWorklet& operator=(const SellerWorklet&) = delete;
@@ -114,7 +117,7 @@
     close_pipe_callback_ = std::move(close_pipe_callback);
   }
 
-  int context_group_id_for_testing() const;
+  std::vector<int> context_group_ids_for_testing() const;
 
   // mojom::SellerWorklet implementation:
   void ScoreAd(
@@ -168,8 +171,8 @@
       uint64_t trace_id,
       ReportResultCallback callback) override;
   void ConnectDevToolsAgent(
-      mojo::PendingAssociatedReceiver<blink::mojom::DevToolsAgent> agent)
-      override;
+      mojo::PendingAssociatedReceiver<blink::mojom::DevToolsAgent> agent,
+      uint32_t thread_index) override;
 
  private:
   // Contains all data needed for a ScoreAd() call. Destroyed only when its
@@ -564,9 +567,9 @@
   // Returns true if unpaused and the script has loaded.
   bool IsCodeReady() const;
 
-  scoped_refptr<base::SequencedTaskRunner> v8_runner_;
-  scoped_refptr<AuctionV8Helper> v8_helper_;
-  scoped_refptr<AuctionV8Helper::DebugId> debug_id_;
+  std::vector<scoped_refptr<base::SequencedTaskRunner>> v8_runners_;
+  std::vector<scoped_refptr<AuctionV8Helper>> v8_helpers_;
+  std::vector<scoped_refptr<AuctionV8Helper::DebugId>> debug_ids_;
 
   mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory_;
 
@@ -594,6 +597,8 @@
 
   bool paused_;
 
+  size_t resumed_count_ = 0;
+
   // Pending calls to the corresponding Javascript method. Only accessed on
   // main thread, but iterators to its elements are bound to callbacks passed
   // to the v8 thread, so it needs to be an std::lists rather than an
@@ -604,9 +609,9 @@
   // Deleted once load has completed.
   std::unique_ptr<WorkletLoader> worklet_loader_;
 
-  // Lives on `v8_runner_`. Since it's deleted there, tasks can be safely
+  // Lives on `v8_runners_`. Since it's deleted there, tasks can be safely
   // posted from main thread to it with an Unretained pointer.
-  std::unique_ptr<V8State, base::OnTaskRunnerDeleter> v8_state_;
+  std::vector<std::unique_ptr<V8State, base::OnTaskRunnerDeleter>> v8_state_;
 
   ClosePipeCallback close_pipe_callback_;
 
@@ -618,6 +623,8 @@
   mojo::Remote<auction_worklet::mojom::AuctionNetworkEventsHandler>
       auction_network_events_handler_;
 
+  GetNextThreadIndexCallback get_next_thread_index_callback_;
+
   SEQUENCE_CHECKER(user_sequence_checker_);
 
   // Used when posting callbacks back from V8State.
diff --git a/content/services/auction_worklet/seller_worklet_unittest.cc b/content/services/auction_worklet/seller_worklet_unittest.cc
index 7ae68891..33ca8eced 100644
--- a/content/services/auction_worklet/seller_worklet_unittest.cc
+++ b/content/services/auction_worklet/seller_worklet_unittest.cc
@@ -207,13 +207,18 @@
   ~SellerWorkletTest() override = default;
 
   void SetUp() override {
-    // v8_helper_ needs to be created here instead of the constructor, because
-    // this test fixture has a subclass that initializes a ScopedFeatureList in
-    // in their constructor, which needs to be done BEFORE other threads are
-    // started in multithreaded test environments so that no other threads use
-    // it when it's being initiated.
+    // The v8_helpers need to be created here instead of the constructor,
+    // because this test fixture has a subclass that initializes a
+    // ScopedFeatureList in in their constructor, which needs to be done BEFORE
+    // other threads are started in multithreaded test environments so that no
+    // other threads use it when it's being initiated.
     // https://source.chromium.org/chromium/chromium/src/+/main:base/test/scoped_feature_list.h;drc=60124005e97ae2716b0fb34187d82da6019b571f;l=37
-    v8_helper_ = AuctionV8Helper::Create(AuctionV8Helper::CreateTaskRunner());
+    while (v8_helpers_.size() < NumThreads()) {
+      v8_helpers_.push_back(
+          AuctionV8Helper::Create(AuctionV8Helper::CreateTaskRunner()));
+    }
+
+    shared_storage_hosts_.resize(NumThreads());
   }
 
   void TearDown() override {
@@ -222,7 +227,7 @@
     // that will result in UAFs. These lines are not necessary for any test to
     // pass. This needs to be done before a subclass resets ScopedFeatureList,
     // so no thread queries it while it's being modified.
-    v8_helper_.reset();
+    v8_helpers_.clear();
     task_environment_.RunUntilIdle();
 
     // In all tests where the SellerWorklet receiver is closed before the
@@ -230,6 +235,8 @@
     EXPECT_FALSE(disconnect_reason_);
   }
 
+  virtual size_t NumThreads() { return 1u; }
+
   // Sets default values for scoreAd() and report_result() arguments. No test
   // actually depends on these being anything but valid, but this does allow
   // tests to reset them to a consistent state.
@@ -743,13 +750,20 @@
           url_loader_factory.InitWithNewPipeAndPassReceiver());
     }
 
+    CHECK_EQ(v8_helpers_.size(), shared_storage_hosts_.size());
+
     mojo::Remote<mojom::SellerWorklet> seller_worklet;
     auto seller_worklet_impl = std::make_unique<SellerWorklet>(
-        v8_helper_, std::move(shared_storage_host_remote_),
+        v8_helpers_, std::move(shared_storage_hosts_),
         pause_for_debugger_on_start, std::move(url_loader_factory),
         auction_network_events_handler_.CreateRemote(), decision_logic_url_,
         trusted_scoring_signals_url_, top_window_origin_,
-        permissions_policy_state_.Clone(), experiment_group_id_);
+        permissions_policy_state_.Clone(), experiment_group_id_,
+        base::BindRepeating(&SellerWorkletTest::GetNextThreadIndex,
+                            base::Unretained(this)));
+
+    shared_storage_hosts_.resize(NumThreads());
+
     auto* seller_worklet_ptr = seller_worklet_impl.get();
     mojo::ReceiverId receiver_id =
         seller_worklets_.Add(std::move(seller_worklet_impl),
@@ -766,6 +780,12 @@
     return seller_worklet;
   }
 
+  // Use a round-robin scheduling. The state is shared across worklets in the
+  // same test case.
+  size_t GetNextThreadIndex() { return next_thread_index_++ % NumThreads(); }
+
+  scoped_refptr<AuctionV8Helper> v8_helper() { return v8_helpers_[0]; }
+
   // Waits for OnDisconnectWithReason() to be invoked, if it hasn't been
   // already, and returns the error string it was invoked with.
   std::string WaitForDisconnect() {
@@ -849,12 +869,15 @@
 
   network::TestURLLoaderFactory url_loader_factory_;
   network::TestURLLoaderFactory alternate_url_loader_factory_;
-  scoped_refptr<AuctionV8Helper> v8_helper_;
+
+  std::vector<scoped_refptr<AuctionV8Helper>> v8_helpers_;
 
   TestAuctionNetworkEventsHandler auction_network_events_handler_;
 
-  mojo::PendingRemote<mojom::AuctionSharedStorageHost>
-      shared_storage_host_remote_;
+  std::vector<mojo::PendingRemote<mojom::AuctionSharedStorageHost>>
+      shared_storage_hosts_;
+
+  size_t next_thread_index_ = 0;
 
   // Owns all created seller worklets - having a ReceiverSet allows them to have
   // a ClosePipeCallback which behaves just like the one in
@@ -862,6 +885,27 @@
   mojo::UniqueReceiverSet<mojom::SellerWorklet> seller_worklets_;
 };
 
+class SellerWorkletTwoThreadsTest : public SellerWorkletTest {
+ private:
+  size_t NumThreads() override { return 2u; }
+};
+
+class SellerWorkletMultiThreadingTest
+    : public SellerWorkletTest,
+      public testing::WithParamInterface<size_t> {
+ private:
+  size_t NumThreads() override { return GetParam(); }
+};
+
+INSTANTIATE_TEST_SUITE_P(All,
+                         SellerWorkletMultiThreadingTest,
+                         testing::Values(1, 2),
+                         [](const auto& info) {
+                           return base::StrCat({info.param == 2
+                                                    ? "TwoThreads"
+                                                    : "SingleThread"});
+                         });
+
 // Test the case the SellerWorklet pipe is closed before any of its methods are
 // invoked. Nothing should happen.
 TEST_F(SellerWorkletTest, PipeClosed) {
@@ -1588,14 +1632,14 @@
 // TODO(crbug.com/40266734): Remove this test when the field itself is
 // removed.
 TEST_F(SellerWorkletTest, ScoreAdRenderUrlDeprecationWarning) {
-  ScopedInspectorSupport inspector_support(v8_helper_.get());
+  ScopedInspectorSupport inspector_support(v8_helper().get());
   AddJavascriptResponse(
       &url_loader_factory_, decision_logic_url_,
       CreateScoreAdScript("browserSignals.renderUrl ? 1 : 0"));
   SellerWorklet* worklet_impl = nullptr;
   auto worklet =
       CreateWorklet(/*pause_for_debugger_on_start=*/false, &worklet_impl);
-  int id = worklet_impl->context_group_id_for_testing();
+  int id = worklet_impl->context_group_ids_for_testing()[0];
   TestChannel* channel =
       inspector_support.ConnectDebuggerSessionAndRuntimeEnable(id);
 
@@ -1617,14 +1661,14 @@
 //
 // TODO(crbug.com/40266734): Remove this test when renderUrl is removed.
 TEST_F(SellerWorkletTest, ScoreAdRenderUrlNoDeprecationWarning) {
-  ScopedInspectorSupport inspector_support(v8_helper_.get());
+  ScopedInspectorSupport inspector_support(v8_helper().get());
   AddJavascriptResponse(
       &url_loader_factory_, decision_logic_url_,
       CreateScoreAdScript("browserSignals.renderURL ? 1 : 0"));
   SellerWorklet* worklet_impl = nullptr;
   auto worklet =
       CreateWorklet(/*pause_for_debugger_on_start=*/false, &worklet_impl);
-  int id = worklet_impl->context_group_id_for_testing();
+  int id = worklet_impl->context_group_ids_for_testing()[0];
   TestChannel* channel =
       inspector_support.ConnectDebuggerSessionAndRuntimeEnable(id);
 
@@ -1719,7 +1763,7 @@
 // TODO(crbug.com/40266734): Remove this test when the fields are
 // removed.
 TEST_F(SellerWorkletTest, ScoreAdAuctionConfigUrlDeprecationWarning) {
-  ScopedInspectorSupport inspector_support(v8_helper_.get());
+  ScopedInspectorSupport inspector_support(v8_helper().get());
   decision_logic_url_ = GURL("https://url.test/");
   trusted_scoring_signals_url_ =
       GURL("https://url.test/trusted_scoring_signals");
@@ -1766,7 +1810,7 @@
   SellerWorklet* worklet_impl = nullptr;
   auto worklet =
       CreateWorklet(/*pause_for_debugger_on_start=*/false, &worklet_impl);
-  int id = worklet_impl->context_group_id_for_testing();
+  int id = worklet_impl->context_group_ids_for_testing()[0];
   TestChannel* channel =
       inspector_support.ConnectDebuggerSessionAndRuntimeEnable(id);
 
@@ -1829,7 +1873,7 @@
 // TODO(crbug.com/40266734): Remove this test when `decisionLogicUrl` and
 // `trustedScoringSignalsUrl` are removed.
 TEST_F(SellerWorkletTest, ScoreAdAuctionConfigUrlNoDeprecationWarning) {
-  ScopedInspectorSupport inspector_support(v8_helper_.get());
+  ScopedInspectorSupport inspector_support(v8_helper().get());
   decision_logic_url_ = GURL("https://url.test/");
   trusted_scoring_signals_url_ =
       GURL("https://url.test/trusted_scoring_signals");
@@ -1876,7 +1920,7 @@
   SellerWorklet* worklet_impl = nullptr;
   auto worklet =
       CreateWorklet(/*pause_for_debugger_on_start=*/false, &worklet_impl);
-  int id = worklet_impl->context_group_id_for_testing();
+  int id = worklet_impl->context_group_ids_for_testing()[0];
   TestChannel* channel =
       inspector_support.ConnectDebuggerSessionAndRuntimeEnable(id);
 
@@ -1898,7 +1942,7 @@
 // instead, the test advances the mock clock by
 // TrustedSignalsRequestManager::kAutoSendDelay, triggering each request to
 // automatically be sent.
-TEST_F(SellerWorkletTest, ScoreAdTrustedScoringSignals) {
+TEST_P(SellerWorkletMultiThreadingTest, ScoreAdTrustedScoringSignals) {
   // With no trusted scoring signals URL, `trustedScoringSignals` should be
   // null.
   trusted_scoring_signals_url_ = std::nullopt;
@@ -2092,7 +2136,7 @@
 
 // Test the case of a bunch of ScoreAd() calls in parallel, all started before
 // the worklet script has loaded.
-TEST_F(SellerWorkletTest, ScoreAdParallelBeforeLoadComplete) {
+TEST_P(SellerWorkletMultiThreadingTest, ScoreAdParallelBeforeLoadComplete) {
   auto seller_worklet = CreateWorklet(/*pause_for_debugger_on_start=*/false);
 
   const size_t kNumWorklets = 10;
@@ -2138,7 +2182,7 @@
 
 // Test the case of a bunch of ScoreAd() calls in parallel, all started after
 // the worklet script has loaded.
-TEST_F(SellerWorkletTest, ScoreAdParallelAfterLoadComplete) {
+TEST_P(SellerWorkletMultiThreadingTest, ScoreAdParallelAfterLoadComplete) {
   // Seller script that uses the last character of `renderURL` as the score.
   AddJavascriptResponse(
       &url_loader_factory_, decision_logic_url_,
@@ -2176,7 +2220,7 @@
 
 // Test the case of a bunch of ScoreAd() calls in parallel, all started before
 // the worklet script fails to load.
-TEST_F(SellerWorkletTest, ScoreAdParallelLoadFails) {
+TEST_P(SellerWorkletMultiThreadingTest, ScoreAdParallelLoadFails) {
   auto seller_worklet = CreateWorklet();
 
   for (size_t i = 0; i < 10; ++i) {
@@ -2202,7 +2246,8 @@
 // Test the case of a bunch of ScoreAd() calls in parallel, in the case trusted
 // scoring signals is non-null. In this case, call AllBidsGenerated() between
 // scoring each bid, which should result in requests being sent individually.
-TEST_F(SellerWorkletTest, ScoreAdParallelTrustedScoringSignalsNotBatched) {
+TEST_P(SellerWorkletMultiThreadingTest,
+       ScoreAdParallelTrustedScoringSignalsNotBatched) {
   base::Time start_time = base::Time::Now();
 
   // Seller script that gets the score from the `trustedScoringSignals` value of
@@ -2279,7 +2324,8 @@
 // 1) The worklet script load completes.
 // 2) ScoreAd() calls are made.
 // 3) The trusted bidding signals are loaded.
-TEST_F(SellerWorkletTest, ScoreAdParallelTrustedScoringSignalsBatched1) {
+TEST_P(SellerWorkletMultiThreadingTest,
+       ScoreAdParallelTrustedScoringSignalsBatched1) {
   // Seller script that gets the score from the `trustedScoringSignals` value of
   // the passed in `renderURL`.
   AddJavascriptResponse(
@@ -2351,7 +2397,8 @@
 // 1) ScoreAd() calls are made.
 // 2) The worklet script load completes.
 // 3) The trusted bidding signals are loaded.
-TEST_F(SellerWorkletTest, ScoreAdParallelTrustedScoringSignalsBatched2) {
+TEST_P(SellerWorkletMultiThreadingTest,
+       ScoreAdParallelTrustedScoringSignalsBatched2) {
   trusted_scoring_signals_url_ =
       GURL("https://url.test/trusted_scoring_signals");
   auto seller_worklet = CreateWorklet();
@@ -2426,7 +2473,8 @@
 // 1) ScoreAd() calls are made.
 // 2) The trusted bidding signals are loaded.
 // 3) The worklet script load completes.
-TEST_F(SellerWorkletTest, ScoreAdParallelTrustedScoringSignalsBatched3) {
+TEST_P(SellerWorkletMultiThreadingTest,
+       ScoreAdParallelTrustedScoringSignalsBatched3) {
   trusted_scoring_signals_url_ =
       GURL("https://url.test/trusted_scoring_signals");
   auto seller_worklet = CreateWorklet();
@@ -3052,13 +3100,13 @@
 // TODO(crbug.com/40266734): Remove this test when the field itself is
 // removed.
 TEST_F(SellerWorkletTest, ReportResultRenderUrlDeprecationWarning) {
-  ScopedInspectorSupport inspector_support(v8_helper_.get());
+  ScopedInspectorSupport inspector_support(v8_helper().get());
   AddJavascriptResponse(&url_loader_factory_, decision_logic_url_,
                         CreateReportToScript("browserSignals.renderUrl"));
   SellerWorklet* worklet_impl = nullptr;
   auto worklet =
       CreateWorklet(/*pause_for_debugger_on_start=*/false, &worklet_impl);
-  int id = worklet_impl->context_group_id_for_testing();
+  int id = worklet_impl->context_group_ids_for_testing()[0];
   TestChannel* channel =
       inspector_support.ConnectDebuggerSessionAndRuntimeEnable(id);
 
@@ -3088,13 +3136,13 @@
 //
 // TODO(crbug.com/40266734): Remove this test when renderUrl is removed.
 TEST_F(SellerWorkletTest, ReportResultRenderUrlNoDeprecationWarning) {
-  ScopedInspectorSupport inspector_support(v8_helper_.get());
+  ScopedInspectorSupport inspector_support(v8_helper().get());
   AddJavascriptResponse(&url_loader_factory_, decision_logic_url_,
                         CreateReportToScript("browserSignals.renderURL"));
   SellerWorklet* worklet_impl = nullptr;
   auto worklet =
       CreateWorklet(/*pause_for_debugger_on_start=*/false, &worklet_impl);
-  int id = worklet_impl->context_group_id_for_testing();
+  int id = worklet_impl->context_group_ids_for_testing()[0];
   TestChannel* channel =
       inspector_support.ConnectDebuggerSessionAndRuntimeEnable(id);
 
@@ -3493,7 +3541,7 @@
 // TODO(crbug.com/40266734): Remove this test when the fields are
 // removed.
 TEST_F(SellerWorkletTest, ReportResultAuctionConfigUrlDeprecationWarning) {
-  ScopedInspectorSupport inspector_support(v8_helper_.get());
+  ScopedInspectorSupport inspector_support(v8_helper().get());
   decision_logic_url_ = GURL("https://url.test/");
   trusted_scoring_signals_url_ =
       GURL("https://url.test/trusted_scoring_signals");
@@ -3531,7 +3579,7 @@
   SellerWorklet* worklet_impl = nullptr;
   auto worklet =
       CreateWorklet(/*pause_for_debugger_on_start=*/false, &worklet_impl);
-  int id = worklet_impl->context_group_id_for_testing();
+  int id = worklet_impl->context_group_ids_for_testing()[0];
   TestChannel* channel =
       inspector_support.ConnectDebuggerSessionAndRuntimeEnable(id);
 
@@ -3607,7 +3655,7 @@
 // TODO(crbug.com/40266734): Remove this test when `decisionLogicUrl` and
 // `trustedScoringSignalsUrl` are removed.
 TEST_F(SellerWorkletTest, ReportResultAuctionConfigUrlNoDeprecationWarning) {
-  ScopedInspectorSupport inspector_support(v8_helper_.get());
+  ScopedInspectorSupport inspector_support(v8_helper().get());
   decision_logic_url_ = GURL("https://url.test/");
   trusted_scoring_signals_url_ =
       GURL("https://url.test/trusted_scoring_signals");
@@ -3645,7 +3693,7 @@
   SellerWorklet* worklet_impl = nullptr;
   auto worklet =
       CreateWorklet(/*pause_for_debugger_on_start=*/false, &worklet_impl);
-  int id = worklet_impl->context_group_id_for_testing();
+  int id = worklet_impl->context_group_ids_for_testing()[0];
   TestChannel* channel =
       inspector_support.ConnectDebuggerSessionAndRuntimeEnable(id);
 
@@ -3811,7 +3859,7 @@
 
 // Subsequent runs of the same script should not affect each other. Same is true
 // for different scripts, but it follows from the single script case.
-TEST_F(SellerWorkletTest, ScriptIsolation) {
+TEST_P(SellerWorkletMultiThreadingTest, ScriptIsolation) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndDisableFeature(
       blink::features::kFledgeAlwaysReuseSellerContext);
@@ -4010,6 +4058,300 @@
   run_loop.Run();
 }
 
+TEST_F(
+    SellerWorkletTwoThreadsTest,
+    OneWorklet_ContextIsReusedInSameThreadIfFledgeAlwaysReuseSellerContextEnabled) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      blink::features::kFledgeAlwaysReuseSellerContext);
+  AddJavascriptResponse(&url_loader_factory_, decision_logic_url_,
+                        R"(
+        // Globally scoped variable.
+        if (!globalThis.var1)
+          globalThis.var1 = [1];
+        scoreAd = function() {
+          // Value only visible within this closure.
+          var var2 = [2];
+          return function() {
+            if (2 == ++globalThis.var1[0] && 3 == ++var2[0])
+              return 2;
+            return 1;
+          }
+        }();
+
+        reportResult = scoreAd;
+      )");
+
+  auto seller_worklet = CreateWorklet();
+
+  ASSERT_TRUE(seller_worklet);
+
+  // Context is reused within the same thread. Since we use a round-robin
+  // scheduling approach and the thread pool has a size of 2, it means the first
+  // two ScoreAds should have score=2 and the rest of them should have score=1.
+  std::vector<double> expected_scores = {2, 2, 1, 1, 1, 1};
+  for (int i = 0; i < 6; ++i) {
+    double expected_score = expected_scores[i];
+    base::RunLoop run_loop;
+    seller_worklet->ScoreAd(
+        ad_metadata_, bid_, bid_currency_, auction_ad_config_non_shared_params_,
+        direct_from_seller_seller_signals_,
+        direct_from_seller_seller_signals_header_ad_slot_,
+        direct_from_seller_auction_signals_,
+        direct_from_seller_auction_signals_header_ad_slot_,
+        browser_signals_other_seller_.Clone(), component_expect_bid_currency_,
+        browser_signal_interest_group_owner_, browser_signal_render_url_,
+        browser_signal_ad_components_, browser_signal_bidding_duration_msecs_,
+        browser_signal_render_size_,
+        browser_signal_for_debugging_only_in_cooldown_or_lockout_,
+        seller_timeout_,
+        /*trace_id=*/1,
+        TestScoreAdClient::Create(base::BindLambdaForTesting(
+            [&run_loop, &expected_score](
+                double score, mojom::RejectReason reject_reason,
+                mojom::ComponentAuctionModifiedBidParamsPtr
+                    component_auction_modified_bid_params,
+                std::optional<double> bid_in_seller_currency,
+                std::optional<uint32_t> scoring_signals_data_version,
+                const std::optional<GURL>& debug_loss_report_url,
+                const std::optional<GURL>& debug_win_report_url,
+                PrivateAggregationRequests pa_requests,
+                RealTimeReportingContributions real_time_contributions,
+                base::TimeDelta scoring_latency,
+                mojom::ScoreAdDependencyLatenciesPtr
+                    score_ad_dependency_latencies,
+                const std::vector<std::string>& errors) {
+              EXPECT_EQ(expected_score, score);
+              EXPECT_FALSE(scoring_signals_data_version.has_value());
+              EXPECT_TRUE(errors.empty());
+              run_loop.Quit();
+            })));
+    run_loop.Run();
+  }
+
+  // The Report worklet should still get a fresh context.
+  base::RunLoop run_loop;
+  seller_worklet->ReportResult(
+      auction_ad_config_non_shared_params_, direct_from_seller_seller_signals_,
+      direct_from_seller_seller_signals_header_ad_slot_,
+      direct_from_seller_auction_signals_,
+      direct_from_seller_auction_signals_header_ad_slot_,
+      browser_signals_other_seller_.Clone(),
+      browser_signal_interest_group_owner_,
+      browser_signal_buyer_and_seller_reporting_id_, browser_signal_render_url_,
+      bid_, bid_currency_, browser_signal_desireability_,
+      browser_signal_highest_scoring_other_bid_,
+      browser_signal_highest_scoring_other_bid_currency_,
+      browser_signals_component_auction_report_result_params_.Clone(),
+      browser_signal_data_version_,
+      /*trace_id=*/1,
+      base::BindLambdaForTesting(
+          [&run_loop](const std::optional<std::string>& signals_for_winner,
+                      const std::optional<GURL>& report_url,
+                      const base::flat_map<std::string, GURL>& ad_beacon_map,
+                      PrivateAggregationRequests pa_requests,
+                      base::TimeDelta reporting_latency,
+                      const std::vector<std::string>& errors) {
+            EXPECT_EQ("2", signals_for_winner);
+            EXPECT_TRUE(errors.empty());
+            run_loop.Quit();
+          }));
+  run_loop.Run();
+}
+
+TEST_F(
+    SellerWorkletTwoThreadsTest,
+    TwoWorklets_ContextIsReusedInSameThreadIfFledgeAlwaysReuseSellerContextEnabled) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      blink::features::kFledgeAlwaysReuseSellerContext);
+  AddJavascriptResponse(&url_loader_factory_, decision_logic_url_,
+                        R"(
+        // Globally scoped variable.
+        if (!globalThis.var1)
+          globalThis.var1 = [1];
+        scoreAd = function() {
+          // Value only visible within this closure.
+          var var2 = [2];
+          return function() {
+            if (2 == ++globalThis.var1[0] && 3 == ++var2[0])
+              return 2;
+            return 1;
+          }
+        }();
+
+        reportResult = scoreAd;
+      )");
+
+  auto seller_worklet1 = CreateWorklet();
+  auto seller_worklet2 = CreateWorklet();
+
+  // Context is reused within the same thread. Since we use a round-robin
+  // scheduling approach and the thread pool has a size of 2, it means the first
+  // two ScoreAds should have score=2 and the rest of them should have score=1.
+  //
+  // Together with the "OneWorklet_XXX" test variant above, this also shows that
+  // the round-robin scheduling state is not local to each SellerWorklet, but
+  // all worklets in the same test case will share the same state.
+  std::vector<double> expected_scores = {2, 2, 1, 1, 1, 1};
+  for (int i = 0; i < 6; ++i) {
+    auto* seller_worklet = (i % 2 == 0) ? &seller_worklet1 : &seller_worklet2;
+
+    double expected_score = expected_scores[i];
+    base::RunLoop run_loop;
+    (*seller_worklet)
+        ->ScoreAd(
+            ad_metadata_, bid_, bid_currency_,
+            auction_ad_config_non_shared_params_,
+            direct_from_seller_seller_signals_,
+            direct_from_seller_seller_signals_header_ad_slot_,
+            direct_from_seller_auction_signals_,
+            direct_from_seller_auction_signals_header_ad_slot_,
+            browser_signals_other_seller_.Clone(),
+            component_expect_bid_currency_,
+            browser_signal_interest_group_owner_, browser_signal_render_url_,
+            browser_signal_ad_components_,
+            browser_signal_bidding_duration_msecs_, browser_signal_render_size_,
+            browser_signal_for_debugging_only_in_cooldown_or_lockout_,
+            seller_timeout_,
+            /*trace_id=*/1,
+            TestScoreAdClient::Create(base::BindLambdaForTesting(
+                [&run_loop, &expected_score](
+                    double score, mojom::RejectReason reject_reason,
+                    mojom::ComponentAuctionModifiedBidParamsPtr
+                        component_auction_modified_bid_params,
+                    std::optional<double> bid_in_seller_currency,
+                    std::optional<uint32_t> scoring_signals_data_version,
+                    const std::optional<GURL>& debug_loss_report_url,
+                    const std::optional<GURL>& debug_win_report_url,
+                    PrivateAggregationRequests pa_requests,
+                    RealTimeReportingContributions real_time_contributions,
+                    base::TimeDelta scoring_latency,
+                    mojom::ScoreAdDependencyLatenciesPtr
+                        score_ad_dependency_latencies,
+                    const std::vector<std::string>& errors) {
+                  EXPECT_EQ(expected_score, score);
+                  EXPECT_FALSE(scoring_signals_data_version.has_value());
+                  EXPECT_TRUE(errors.empty());
+                  run_loop.Quit();
+                })));
+    run_loop.Run();
+  }
+
+  // The Report worklet should still get a fresh context.
+  for (auto* seller_worklet : {&seller_worklet1, &seller_worklet2}) {
+    base::RunLoop run_loop;
+    (*seller_worklet)
+        ->ReportResult(
+            auction_ad_config_non_shared_params_,
+            direct_from_seller_seller_signals_,
+            direct_from_seller_seller_signals_header_ad_slot_,
+            direct_from_seller_auction_signals_,
+            direct_from_seller_auction_signals_header_ad_slot_,
+            browser_signals_other_seller_.Clone(),
+            browser_signal_interest_group_owner_,
+            browser_signal_buyer_and_seller_reporting_id_,
+            browser_signal_render_url_, bid_, bid_currency_,
+            browser_signal_desireability_,
+            browser_signal_highest_scoring_other_bid_,
+            browser_signal_highest_scoring_other_bid_currency_,
+            browser_signals_component_auction_report_result_params_.Clone(),
+            browser_signal_data_version_,
+            /*trace_id=*/1,
+            base::BindLambdaForTesting(
+                [&run_loop](
+                    const std::optional<std::string>& signals_for_winner,
+                    const std::optional<GURL>& report_url,
+                    const base::flat_map<std::string, GURL>& ad_beacon_map,
+                    PrivateAggregationRequests pa_requests,
+                    base::TimeDelta reporting_latency,
+                    const std::vector<std::string>& errors) {
+                  EXPECT_EQ("2", signals_for_winner);
+                  EXPECT_TRUE(errors.empty());
+                  run_loop.Quit();
+                }));
+    run_loop.Run();
+  }
+}
+
+TEST_F(SellerWorkletTwoThreadsTest,
+       TrustedScoringSignalsTaskTriggersNextThreadIndexCallback) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      blink::features::kFledgeAlwaysReuseSellerContext);
+  AddJavascriptResponse(&url_loader_factory_, decision_logic_url_,
+                        R"(
+        // Globally scoped variable.
+        if (!globalThis.var1)
+          globalThis.var1 = [1];
+        scoreAd = function() {
+          // Value only visible within this closure.
+          var var2 = [2];
+          return function() {
+            if (2 == ++globalThis.var1[0] && 3 == ++var2[0])
+              return 2;
+            return 1;
+          }
+        }();
+
+        reportResult = scoreAd;
+      )");
+
+  auto seller_worklet = CreateWorklet();
+
+  ASSERT_TRUE(seller_worklet);
+
+  // Before the second ScoreAd (i == 1), create another worklet with non-empty
+  // `trusted_scoring_signals_url_`. The first and the third ScoreAd are
+  // expected to have a new context. This implies that creating a worklet with
+  // `trusted_scoring_signals_url_` will trigger the
+  // `GetNextThreadIndexCallback`.
+  std::vector<double> expected_scores = {2, 1, 2, 1, 1, 1};
+  for (int i = 0; i < 6; ++i) {
+    if (i == 1) {
+      trusted_scoring_signals_url_ = GURL("https://url.test/trustedsignals");
+      auto new_worklet = CreateWorklet();
+    }
+
+    double expected_score = expected_scores[i];
+    base::RunLoop run_loop;
+    seller_worklet->ScoreAd(
+        ad_metadata_, bid_, bid_currency_, auction_ad_config_non_shared_params_,
+        direct_from_seller_seller_signals_,
+        direct_from_seller_seller_signals_header_ad_slot_,
+        direct_from_seller_auction_signals_,
+        direct_from_seller_auction_signals_header_ad_slot_,
+        browser_signals_other_seller_.Clone(), component_expect_bid_currency_,
+        browser_signal_interest_group_owner_, browser_signal_render_url_,
+        browser_signal_ad_components_, browser_signal_bidding_duration_msecs_,
+        browser_signal_render_size_,
+        browser_signal_for_debugging_only_in_cooldown_or_lockout_,
+        seller_timeout_,
+        /*trace_id=*/1,
+        TestScoreAdClient::Create(base::BindLambdaForTesting(
+            [&run_loop, &expected_score](
+                double score, mojom::RejectReason reject_reason,
+                mojom::ComponentAuctionModifiedBidParamsPtr
+                    component_auction_modified_bid_params,
+                std::optional<double> bid_in_seller_currency,
+                std::optional<uint32_t> scoring_signals_data_version,
+                const std::optional<GURL>& debug_loss_report_url,
+                const std::optional<GURL>& debug_win_report_url,
+                PrivateAggregationRequests pa_requests,
+                RealTimeReportingContributions real_time_contributions,
+                base::TimeDelta scoring_latency,
+                mojom::ScoreAdDependencyLatenciesPtr
+                    score_ad_dependency_latencies,
+                const std::vector<std::string>& errors) {
+              EXPECT_EQ(expected_score, score);
+              EXPECT_FALSE(scoring_signals_data_version.has_value());
+              EXPECT_TRUE(errors.empty());
+              run_loop.Quit();
+            })));
+    run_loop.Run();
+  }
+}
+
 TEST_F(SellerWorkletTest, ContextReuseDoesNotCrashLazyFiller) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(
@@ -4076,7 +4418,7 @@
   auto seller_worklet = CreateWorklet();
   ASSERT_TRUE(seller_worklet);
 
-  base::WaitableEvent* event_handle = WedgeV8Thread(v8_helper_.get());
+  base::WaitableEvent* event_handle = WedgeV8Thread(v8_helper().get());
   seller_worklet->ScoreAd(
       ad_metadata_, bid_, bid_currency_, auction_ad_config_non_shared_params_,
       direct_from_seller_seller_signals_,
@@ -4107,7 +4449,7 @@
   // Need to call ScoreAd() calling ReportResult().
   RunScoreAdExpectingResultOnWorklet(seller_worklet.get(), 1);
 
-  base::WaitableEvent* event_handle = WedgeV8Thread(v8_helper_.get());
+  base::WaitableEvent* event_handle = WedgeV8Thread(v8_helper().get());
   seller_worklet->ReportResult(
       auction_ad_config_non_shared_params_, direct_from_seller_seller_signals_,
       direct_from_seller_seller_signals_header_ad_slot_,
@@ -4144,7 +4486,7 @@
   auto worklet =
       CreateWorklet(/*pause_for_debugger_on_start=*/true, &worklet_impl);
   // Grab the context ID to be able to resume.
-  int id = worklet_impl->context_group_id_for_testing();
+  int id = worklet_impl->context_group_ids_for_testing()[0];
 
   // Queue a ScoreAd() call, which should not happen immediately since loading
   // is paused.
@@ -4175,15 +4517,15 @@
   EXPECT_FALSE(run_loop.AnyQuitCalled());
 
   // Let the ScoreAd() call run.
-  v8_helper_->v8_runner()->PostTask(
+  v8_helper()->v8_runner()->PostTask(
       FROM_HERE, base::BindOnce([](scoped_refptr<AuctionV8Helper> v8_helper,
                                    int id) { v8_helper->Resume(id); },
-                                v8_helper_, id));
+                                v8_helper(), id));
 
   run_loop.RunUntilIdle();
 }
 
-TEST_F(SellerWorkletTest, PauseOnStartDelete) {
+TEST_P(SellerWorkletMultiThreadingTest, PauseOnStartDelete) {
   AddJavascriptResponse(&url_loader_factory_, decision_logic_url_,
                         CreateScoreAdScript("10"));
 
@@ -4199,23 +4541,23 @@
   task_environment_.RunUntilIdle();
 
   // Grab the context ID.
-  int id = worklet_impl->context_group_id_for_testing();
+  int id = worklet_impl->context_group_ids_for_testing()[0];
 
   // Delete the worklet.
   worklet.reset();
   task_environment_.RunUntilIdle();
 
   // Try to resume post-delete. Should not crash
-  v8_helper_->v8_runner()->PostTask(
+  v8_helper()->v8_runner()->PostTask(
       FROM_HERE, base::BindOnce([](scoped_refptr<AuctionV8Helper> v8_helper,
                                    int id) { v8_helper->Resume(id); },
-                                v8_helper_, id));
+                                v8_helper(), id));
 
   task_environment_.RunUntilIdle();
 }
 
 TEST_F(SellerWorkletTest, BasicV8Debug) {
-  ScopedInspectorSupport inspector_support(v8_helper_.get());
+  ScopedInspectorSupport inspector_support(v8_helper().get());
 
   // Helper for looking for scriptParsed events.
   auto is_script_parsed = [](const TestChannel::Event& event) -> bool {
@@ -4274,8 +4616,8 @@
       /*expected_signals_fetch_latency=*/std::nullopt,
       /*expected_code_ready_latency=*/std::nullopt, run_loop2.QuitClosure());
 
-  int id1 = worklet_impl1->context_group_id_for_testing();
-  int id2 = worklet_impl2->context_group_id_for_testing();
+  int id1 = worklet_impl1->context_group_ids_for_testing()[0];
+  int id2 = worklet_impl2->context_group_ids_for_testing()[0];
 
   TestChannel* channel1 = inspector_support.ConnectDebuggerSession(id1);
   TestChannel* channel2 = inspector_support.ConnectDebuggerSession(id2);
@@ -4341,14 +4683,115 @@
   EXPECT_TRUE(base::ranges::none_of(events2, is_script_parsed));
 }
 
+TEST_F(SellerWorkletTwoThreadsTest, BasicV8Debug) {
+  ScopedInspectorSupport inspector_support0(v8_helpers_[0].get());
+  ScopedInspectorSupport inspector_support1(v8_helpers_[1].get());
+
+  // Helper for looking for scriptParsed events.
+  auto is_script_parsed = [](const TestChannel::Event& event) -> bool {
+    if (event.type != TestChannel::Event::Type::Notification) {
+      return false;
+    }
+
+    const std::string* candidate_method =
+        event.value.GetDict().FindString("method");
+    return (candidate_method && *candidate_method == "Debugger.scriptParsed");
+  };
+
+  const GURL kUrl1 = GURL("http://example.test/first.js");
+
+  AddJavascriptResponse(&url_loader_factory_, kUrl1, CreateScoreAdScript("1"));
+
+  SellerWorklet* worklet_impl = nullptr;
+  decision_logic_url_ = kUrl1;
+  auto worklet = CreateWorklet(
+      /*pause_for_debugger_on_start=*/true, &worklet_impl);
+  base::RunLoop run_loop;
+  RunScoreAdOnWorkletAsync(
+      worklet.get(), /*expected_score=*/1,
+      /*expected_errors=*/{}, mojom::ComponentAuctionModifiedBidParamsPtr(),
+      /*expected_data_version=*/std::nullopt,
+      /*expected_debug_loss_report_url=*/std::nullopt,
+      /*expected_debug_win_report_url=*/std::nullopt,
+      /*expected_reject_reason=*/
+      mojom::RejectReason::kNotAvailable,
+      /*expected_pa_requests=*/{},
+      /*expected_real_time_contributions=*/{},
+      /*expected_bid_in_seller_currency=*/std::nullopt,
+      /*expected_score_ad_timeout=*/false,
+      /*expected_signals_fetch_latency=*/std::nullopt,
+      /*expected_code_ready_latency=*/std::nullopt, run_loop.QuitClosure());
+
+  std::vector<int> ids = worklet_impl->context_group_ids_for_testing();
+  ASSERT_EQ(ids.size(), 2u);
+
+  TestChannel* channel0 = inspector_support0.ConnectDebuggerSession(ids[0]);
+  TestChannel* channel1 = inspector_support1.ConnectDebuggerSession(ids[1]);
+
+  channel0->RunCommandAndWaitForResult(
+      1, "Runtime.enable", R"({"id":1,"method":"Runtime.enable","params":{}})");
+  channel0->RunCommandAndWaitForResult(
+      2, "Debugger.enable",
+      R"({"id":2,"method":"Debugger.enable","params":{}})");
+
+  channel1->RunCommandAndWaitForResult(
+      1, "Runtime.enable", R"({"id":1,"method":"Runtime.enable","params":{}})");
+  channel1->RunCommandAndWaitForResult(
+      2, "Debugger.enable",
+      R"({"id":2,"method":"Debugger.enable","params":{}})");
+
+  // Should not see scriptParsed before resume.
+  std::list<TestChannel::Event> events0 = channel0->TakeAllEvents();
+  EXPECT_TRUE(base::ranges::none_of(events0, is_script_parsed));
+  std::list<TestChannel::Event> events1 = channel1->TakeAllEvents();
+  EXPECT_TRUE(base::ranges::none_of(events1, is_script_parsed));
+
+  // Unpause execution for `channel0`. Expect that `run_loop` hasn't quit, as
+  // the worklet is waiting on both V8 threads to resume.
+  EXPECT_FALSE(run_loop.AnyQuitCalled());
+  channel0->RunCommandAndWaitForResult(
+      3, "Runtime.runIfWaitingForDebugger",
+      R"({"id":3,"method":"Runtime.runIfWaitingForDebugger","params":{}})");
+  task_environment_.RunUntilIdle();
+  EXPECT_FALSE(run_loop.AnyQuitCalled());
+
+  // Unpause execution for `channel1`. Expect that `run_loop` has quit.
+  channel1->RunCommandAndWaitForResult(
+      3, "Runtime.runIfWaitingForDebugger",
+      R"({"id":3,"method":"Runtime.runIfWaitingForDebugger","params":{}})");
+  task_environment_.RunUntilIdle();
+  EXPECT_TRUE(run_loop.AnyQuitCalled());
+
+  // `channel0` should have had a parsed notification for kUrl1, as the
+  // ScoreAd is executed on the corresponding thread.
+  events1 = channel1->TakeAllEvents();
+  EXPECT_TRUE(base::ranges::none_of(events1, is_script_parsed));
+
+  TestChannel::Event script_parsed0 =
+      channel0->WaitForMethodNotification("Debugger.scriptParsed");
+  const std::string* url =
+      script_parsed0.value.GetDict().FindStringByDottedPath("params.url");
+  ASSERT_TRUE(url);
+  EXPECT_EQ(kUrl1.spec(), *url);
+
+  worklet.reset();
+  task_environment_.RunUntilIdle();
+
+  // No other scriptParsed events should be on any channel.
+  events0 = channel0->TakeAllEvents();
+  events1 = channel1->TakeAllEvents();
+  EXPECT_TRUE(base::ranges::none_of(events0, is_script_parsed));
+  EXPECT_TRUE(base::ranges::none_of(events1, is_script_parsed));
+}
+
 TEST_F(SellerWorkletTest, ParseErrorV8Debug) {
-  ScopedInspectorSupport inspector_support(v8_helper_.get());
+  ScopedInspectorSupport inspector_support(v8_helper().get());
   AddJavascriptResponse(&url_loader_factory_, decision_logic_url_,
                         "Invalid Javascript");
   SellerWorklet* worklet_impl = nullptr;
   auto worklet =
       CreateWorklet(/*pause_for_debugger_on_start=*/true, &worklet_impl);
-  int id = worklet_impl->context_group_id_for_testing();
+  int id = worklet_impl->context_group_ids_for_testing()[0];
   TestChannel* channel = inspector_support.ConnectDebuggerSession(id);
 
   channel->RunCommandAndWaitForResult(
@@ -4372,6 +4815,59 @@
   EXPECT_EQ(decision_logic_url_.spec(), *error_url);
 }
 
+TEST_F(SellerWorkletTwoThreadsTest, ParseErrorV8Debug) {
+  ScopedInspectorSupport inspector_support0(v8_helpers_[0].get());
+  ScopedInspectorSupport inspector_support1(v8_helpers_[1].get());
+
+  AddJavascriptResponse(&url_loader_factory_, decision_logic_url_,
+                        "Invalid Javascript");
+  SellerWorklet* worklet_impl = nullptr;
+  auto worklet =
+      CreateWorklet(/*pause_for_debugger_on_start=*/true, &worklet_impl);
+
+  std::vector<int> ids = worklet_impl->context_group_ids_for_testing();
+  EXPECT_EQ(ids.size(), 2u);
+
+  TestChannel* channel0 = inspector_support0.ConnectDebuggerSession(ids[0]);
+  TestChannel* channel1 = inspector_support1.ConnectDebuggerSession(ids[1]);
+
+  channel0->RunCommandAndWaitForResult(
+      1, "Runtime.enable", R"({"id":1,"method":"Runtime.enable","params":{}})");
+  channel0->RunCommandAndWaitForResult(
+      2, "Debugger.enable",
+      R"({"id":2,"method":"Debugger.enable","params":{}})");
+
+  channel1->RunCommandAndWaitForResult(
+      1, "Runtime.enable", R"({"id":1,"method":"Runtime.enable","params":{}})");
+  channel1->RunCommandAndWaitForResult(
+      2, "Debugger.enable",
+      R"({"id":2,"method":"Debugger.enable","params":{}})");
+
+  // Unpause execution and wait for the pipe to be closed with an error.
+  channel0->RunCommandAndWaitForResult(
+      3, "Runtime.runIfWaitingForDebugger",
+      R"({"id":3,"method":"Runtime.runIfWaitingForDebugger","params":{}})");
+  channel1->RunCommandAndWaitForResult(
+      3, "Runtime.runIfWaitingForDebugger",
+      R"({"id":3,"method":"Runtime.runIfWaitingForDebugger","params":{}})");
+  EXPECT_FALSE(WaitForDisconnect().empty());
+
+  // Should have gotten a parse error notification for each channel.
+  TestChannel::Event parse_error0 =
+      channel0->WaitForMethodNotification("Debugger.scriptFailedToParse");
+  const std::string* error_url0 =
+      parse_error0.value.GetDict().FindStringByDottedPath("params.url");
+  ASSERT_TRUE(error_url0);
+  EXPECT_EQ(decision_logic_url_.spec(), *error_url0);
+
+  TestChannel::Event parse_error1 =
+      channel1->WaitForMethodNotification("Debugger.scriptFailedToParse");
+  const std::string* error_url1 =
+      parse_error1.value.GetDict().FindStringByDottedPath("params.url");
+  ASSERT_TRUE(error_url1);
+  EXPECT_EQ(decision_logic_url_.spec(), *error_url1);
+}
+
 TEST_F(SellerWorkletTest, BasicDevToolsDebug) {
   const char kScriptResult[] = "this.global_score ? this.global_score : 10";
 
@@ -4422,8 +4918,10 @@
       /*expected_code_ready_latency=*/std::nullopt, run_loop2.QuitClosure());
 
   mojo::AssociatedRemote<blink::mojom::DevToolsAgent> agent1, agent2;
-  worklet1->ConnectDevToolsAgent(agent1.BindNewEndpointAndPassReceiver());
-  worklet2->ConnectDevToolsAgent(agent2.BindNewEndpointAndPassReceiver());
+  worklet1->ConnectDevToolsAgent(agent1.BindNewEndpointAndPassReceiver(),
+                                 /*thread_index=*/0);
+  worklet2->ConnectDevToolsAgent(agent2.BindNewEndpointAndPassReceiver(),
+                                 /*thread_index=*/0);
 
   TestDevToolsAgentClient debug1(std::move(agent1), "123",
                                  /*use_binary_protocol=*/true);
@@ -4550,6 +5048,186 @@
   run_loop2.Run();
 }
 
+TEST_F(SellerWorkletTwoThreadsTest, BasicDevToolsDebug) {
+  const char kScriptResult[] = "this.global_score ? this.global_score : 10";
+
+  const char kUrl1[] = "http://example.test/first.js";
+
+  AddJavascriptResponse(&url_loader_factory_, GURL(kUrl1),
+                        CreateScoreAdScript(kScriptResult));
+
+  decision_logic_url_ = GURL(kUrl1);
+  auto worklet = CreateWorklet(/*pause_for_debugger_on_start=*/true);
+  base::RunLoop run_loop0;
+  RunScoreAdOnWorkletAsync(
+      worklet.get(), /*expected_score=*/100.5,
+      /*expected_errors=*/{}, mojom::ComponentAuctionModifiedBidParamsPtr(),
+      /*expected_data_version=*/std::nullopt,
+      /*expected_debug_loss_report_url=*/std::nullopt,
+      /*expected_debug_win_report_url=*/std::nullopt,
+      /*expected_reject_reason=*/
+      mojom::RejectReason::kNotAvailable,
+      /*expected_pa_requests=*/{},
+      /*expected_real_time_contributions=*/{},
+      /*expected_bid_in_seller_currency=*/std::nullopt,
+      /*expected_score_ad_timeout=*/false,
+      /*expected_signals_fetch_latency=*/std::nullopt,
+      /*expected_code_ready_latency=*/std::nullopt, run_loop0.QuitClosure());
+
+  base::RunLoop run_loop1;
+  RunScoreAdOnWorkletAsync(
+      worklet.get(), /*expected_score=*/100.6,
+      /*expected_errors=*/{}, mojom::ComponentAuctionModifiedBidParamsPtr(),
+      /*expected_data_version=*/std::nullopt,
+      /*expected_debug_loss_report_url=*/std::nullopt,
+      /*expected_debug_win_report_url=*/std::nullopt,
+      /*expected_reject_reason=*/
+      mojom::RejectReason::kNotAvailable,
+      /*expected_pa_requests=*/{},
+      /*expected_real_time_contributions=*/{},
+      /*expected_bid_in_seller_currency=*/std::nullopt,
+      /*expected_score_ad_timeout=*/false,
+      /*expected_signals_fetch_latency=*/std::nullopt,
+      /*expected_code_ready_latency=*/std::nullopt, run_loop1.QuitClosure());
+
+  mojo::AssociatedRemote<blink::mojom::DevToolsAgent> agent0, agent1;
+  worklet->ConnectDevToolsAgent(agent0.BindNewEndpointAndPassReceiver(),
+                                /*thread_index=*/0);
+  worklet->ConnectDevToolsAgent(agent1.BindNewEndpointAndPassReceiver(),
+                                /*thread_index=*/1);
+
+  TestDevToolsAgentClient debug0(std::move(agent0), "123",
+                                 /*use_binary_protocol=*/true);
+  TestDevToolsAgentClient debug1(std::move(agent1), "456",
+                                 /*use_binary_protocol=*/true);
+
+  debug0.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kMain, 1, "Runtime.enable",
+      R"({"id":1,"method":"Runtime.enable","params":{}})");
+  debug0.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kMain, 2, "Debugger.enable",
+      R"({"id":2,"method":"Debugger.enable","params":{}})");
+
+  debug1.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kMain, 1, "Runtime.enable",
+      R"({"id":1,"method":"Runtime.enable","params":{}})");
+  debug1.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kMain, 2, "Debugger.enable",
+      R"({"id":2,"method":"Debugger.enable","params":{}})");
+
+  const char kBreakpointTemplate[] = R"({
+        "id":3,
+        "method":"Debugger.setBreakpointByUrl",
+        "params": {
+          "lineNumber": 2,
+          "url": "%s",
+          "columnNumber": 0,
+          "condition": ""
+        }})";
+
+  debug0.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kMain, 3, "Debugger.setBreakpointByUrl",
+      base::StringPrintf(kBreakpointTemplate, kUrl1));
+  debug1.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kMain, 3, "Debugger.setBreakpointByUrl",
+      base::StringPrintf(kBreakpointTemplate, kUrl1));
+
+  // Now resume. We should see a scriptParsed event for `debug0` and `debug1`,
+  // as the two ScoreAds are executed on the corresponding thread respectively.
+  debug0.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kMain, 4,
+      "Runtime.runIfWaitingForDebugger",
+      R"({"id":4,"method":"Runtime.runIfWaitingForDebugger","params":{}})");
+  debug1.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kMain, 4,
+      "Runtime.runIfWaitingForDebugger",
+      R"({"id":4,"method":"Runtime.runIfWaitingForDebugger","params":{}})");
+
+  TestDevToolsAgentClient::Event script_parsed0 =
+      debug0.WaitForMethodNotification("Debugger.scriptParsed");
+  const std::string* url0 =
+      script_parsed0.value.GetDict().FindStringByDottedPath("params.url");
+  ASSERT_TRUE(url0);
+  EXPECT_EQ(*url0, kUrl1);
+
+  TestDevToolsAgentClient::Event script_parsed1 =
+      debug1.WaitForMethodNotification("Debugger.scriptParsed");
+  const std::string* url1 =
+      script_parsed1.value.GetDict().FindStringByDottedPath("params.url");
+  ASSERT_TRUE(url1);
+  EXPECT_EQ(*url1, kUrl1);
+
+  // The breakpoints will be hit.
+  TestDevToolsAgentClient::Event breakpoint_hit0 =
+      debug0.WaitForMethodNotification("Debugger.paused");
+  TestDevToolsAgentClient::Event breakpoint_hit1 =
+      debug1.WaitForMethodNotification("Debugger.paused");
+
+  base::Value::List* hit_breakpoints0 =
+      breakpoint_hit0.value.GetDict().FindDict("params")->FindList(
+          "hitBreakpoints");
+  ASSERT_TRUE(hit_breakpoints0);
+  ASSERT_EQ(1u, hit_breakpoints0->size());
+  ASSERT_TRUE((*hit_breakpoints0)[0].is_string());
+  EXPECT_EQ("1:2:0:http://example.test/first.js",
+            (*hit_breakpoints0)[0].GetString());
+  std::string* callframe_id0 = breakpoint_hit0.value.GetDict()
+                                   .FindDict("params")
+                                   ->FindList("callFrames")
+                                   ->front()
+                                   .GetDict()
+                                   .FindString("callFrameId");
+
+  base::Value::List* hit_breakpoints1 =
+      breakpoint_hit1.value.GetDict().FindDict("params")->FindList(
+          "hitBreakpoints");
+  ASSERT_TRUE(hit_breakpoints1);
+  ASSERT_EQ(1u, hit_breakpoints1->size());
+  ASSERT_TRUE((*hit_breakpoints1)[0].is_string());
+  EXPECT_EQ("1:2:0:http://example.test/first.js",
+            (*hit_breakpoints1)[0].GetString());
+  std::string* callframe_id1 = breakpoint_hit1.value.GetDict()
+                                   .FindDict("params")
+                                   ->FindList("callFrames")
+                                   ->front()
+                                   .GetDict()
+                                   .FindString("callFrameId");
+
+  // Override the score value.
+  const char kCommandTemplate[] = R"({
+    "id": 5,
+    "method": "Debugger.evaluateOnCallFrame",
+    "params": {
+      "callFrameId": "%s",
+      "expression": "global_score = %s"
+    }
+  })";
+
+  // Note that ScoreAds are processed in the opposite order they were queued.
+  // Thus `debug0` should correspond to the first `RunScoreAdOnWorkletAsync`
+  // call, and `debug1` should correspond to the second call.
+  debug0.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kIO, 5, "Debugger.evaluateOnCallFrame",
+      base::StringPrintf(kCommandTemplate, callframe_id0->c_str(), "100.6"));
+  debug1.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kIO, 5, "Debugger.evaluateOnCallFrame",
+      base::StringPrintf(kCommandTemplate, callframe_id1->c_str(), "100.5"));
+
+  // Let the thread associated with `debug0` resume.
+  EXPECT_FALSE(run_loop1.AnyQuitCalled());
+  debug0.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kIO, 6, "Debugger.resume",
+      R"({"id":6,"method":"Debugger.resume","params":{}})");
+  run_loop1.Run();
+
+  // Let the thread associated with `debug1` resume.
+  EXPECT_FALSE(run_loop0.AnyQuitCalled());
+  debug1.RunCommandAndWaitForResult(
+      TestDevToolsAgentClient::Channel::kIO, 6, "Debugger.resume",
+      R"({"id":6,"method":"Debugger.resume","params":{}})");
+  run_loop0.Run();
+}
+
 TEST_F(SellerWorkletTest, InstrumentationBreakpoints) {
   const char kUrl[] = "http://example.test/script.js";
 
@@ -4577,7 +5255,8 @@
       /*expected_code_ready_latency=*/std::nullopt, run_loop.QuitClosure());
 
   mojo::AssociatedRemote<blink::mojom::DevToolsAgent> agent;
-  worklet->ConnectDevToolsAgent(agent.BindNewEndpointAndPassReceiver());
+  worklet->ConnectDevToolsAgent(agent.BindNewEndpointAndPassReceiver(),
+                                /*thread_index=*/0);
 
   TestDevToolsAgentClient debug(std::move(agent), "123",
                                 /*use_binary_protocol=*/true);
@@ -4693,7 +5372,8 @@
   RunScoreAdOnWorkletExpectingCallbackNeverInvoked(worklet.get());
 
   mojo::AssociatedRemote<blink::mojom::DevToolsAgent> agent;
-  worklet->ConnectDevToolsAgent(agent.BindNewEndpointAndPassReceiver());
+  worklet->ConnectDevToolsAgent(agent.BindNewEndpointAndPassReceiver(),
+                                /*thread_index=*/0);
 
   TestDevToolsAgentClient debug(std::move(agent), "123",
                                 /*use_binary_protocol=*/true);
@@ -4757,7 +5437,7 @@
 
   // Now we no longer need it for parsing JS, wedge the V8 thread so we get a
   // chance to cancel the script *before* it actually tries running.
-  base::WaitableEvent* event_handle = WedgeV8Thread(v8_helper_.get());
+  base::WaitableEvent* event_handle = WedgeV8Thread(v8_helper().get());
 
   TestScoreAdClient client(TestScoreAdClient::ScoreAdNeverInvokedCallback());
   mojo::Receiver<mojom::ScoreAdClient> client_receiver(&client);
@@ -4790,13 +5470,13 @@
   seller_timeout_ = base::Days(360);
 
   // ReportResult timeout isn't configurable the way scoreAd is.
-  v8_helper_->v8_runner()->PostTask(
+  v8_helper()->v8_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(
           [](scoped_refptr<AuctionV8Helper> v8_helper) {
             v8_helper->set_script_timeout_for_testing(base::Days(360));
           },
-          v8_helper_));
+          v8_helper()));
 
   AddJavascriptResponse(&url_loader_factory_, decision_logic_url_,
                         "while(true) {}");
@@ -4806,7 +5486,7 @@
 
   // Now we no longer need it for parsing JS, wedge the V8 thread so we get a
   // chance to cancel the script *before* it actually tries running.
-  base::WaitableEvent* event_handle = WedgeV8Thread(v8_helper_.get());
+  base::WaitableEvent* event_handle = WedgeV8Thread(v8_helper().get());
 
   RunScoreAdOnWorkletExpectingCallbackNeverInvoked(seller_worklet.get());
   RunReportResultExpectingCallbackNeverInvoked(seller_worklet.get());
@@ -5037,7 +5717,7 @@
   {
     mojo::Receiver<auction_worklet::mojom::AuctionSharedStorageHost> receiver(
         &test_shared_storage_host);
-    shared_storage_host_remote_ = receiver.BindNewPipeAndPassRemote();
+    shared_storage_hosts_[0] = receiver.BindNewPipeAndPassRemote();
 
     RunScoreAdWithJavascriptExpectingResult(
         CreateScoreAdScript("5", /*extra_code=*/R"(
@@ -5087,7 +5767,7 @@
   }
 
   {
-    shared_storage_host_remote_ =
+    shared_storage_hosts_[0] =
         mojo::PendingRemote<mojom::AuctionSharedStorageHost>();
 
     // Set the shared-storage permissions policy to disallowed.
@@ -5124,7 +5804,7 @@
   {
     mojo::Receiver<auction_worklet::mojom::AuctionSharedStorageHost> receiver(
         &test_shared_storage_host);
-    shared_storage_host_remote_ = receiver.BindNewPipeAndPassRemote();
+    shared_storage_hosts_[0] = receiver.BindNewPipeAndPassRemote();
 
     RunReportResultCreatedScriptExpectingResult(
         R"(5)",
@@ -5172,7 +5852,7 @@
   }
 
   {
-    shared_storage_host_remote_ =
+    shared_storage_hosts_[0] =
         mojo::PendingRemote<mojom::AuctionSharedStorageHost>();
 
     // Set the shared-storage permissions policy to disallowed.
@@ -5200,6 +5880,54 @@
   }
 }
 
+class SellerWorkletTwoThreadsSharedStorageAPIEnabledTest
+    : public SellerWorkletSharedStorageAPIEnabledTest {
+ public:
+  size_t NumThreads() override { return 2u; }
+};
+
+TEST_F(SellerWorkletTwoThreadsSharedStorageAPIEnabledTest,
+       SharedStorageWriteInScoreAd) {
+  auction_worklet::TestAuctionSharedStorageHost test_shared_storage_host0;
+  auction_worklet::TestAuctionSharedStorageHost test_shared_storage_host1;
+
+  mojo::Receiver<auction_worklet::mojom::AuctionSharedStorageHost> receiver0(
+      &test_shared_storage_host0);
+  shared_storage_hosts_[0] = receiver0.BindNewPipeAndPassRemote();
+
+  mojo::Receiver<auction_worklet::mojom::AuctionSharedStorageHost> receiver1(
+      &test_shared_storage_host0);
+  shared_storage_hosts_[1] = receiver1.BindNewPipeAndPassRemote();
+
+  AddJavascriptResponse(
+      &url_loader_factory_, decision_logic_url_,
+      /*javascript=*/CreateScoreAdScript("5", /*extra_code=*/R"(
+        sharedStorage.set('a', 'b');
+      )"));
+
+  auto seller_worklet = CreateWorklet();
+
+  RunScoreAdExpectingResultOnWorklet(seller_worklet.get(), 5);
+
+  // Make sure the shared storage mojom methods are invoked as they use a
+  // dedicated pipe.
+  task_environment_.RunUntilIdle();
+
+  // Expect that only the shared storage host corresponding to the thread
+  // handling the ScoreAd has observed the requests.
+  EXPECT_TRUE(test_shared_storage_host1.observed_requests().empty());
+
+  using RequestType =
+      auction_worklet::TestAuctionSharedStorageHost::RequestType;
+  using Request = auction_worklet::TestAuctionSharedStorageHost::Request;
+
+  EXPECT_THAT(test_shared_storage_host0.observed_requests(),
+              testing::ElementsAre(Request{.type = RequestType::kSet,
+                                           .key = u"a",
+                                           .value = u"b",
+                                           .ignore_if_present = false}));
+}
+
 class SellerWorkletRealTimeTest : public SellerWorkletTest {
  public:
   SellerWorkletRealTimeTest()
@@ -5247,14 +5975,14 @@
   // that if the seller script with endless loop times out, we know that the
   // seller timeout overwrote the default script timeout and worked.
   const base::TimeDelta kScriptTimeout = base::Days(360);
-  v8_helper_->v8_runner()->PostTask(
+  v8_helper()->v8_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(
           [](scoped_refptr<AuctionV8Helper> v8_helper,
              const base::TimeDelta script_timeout) {
             v8_helper->set_script_timeout_for_testing(script_timeout);
           },
-          v8_helper_, kScriptTimeout));
+          v8_helper(), kScriptTimeout));
   // Make sure set_script_timeout_for_testing is called.
   task_environment_.RunUntilIdle();
 
@@ -5320,14 +6048,14 @@
   // that if the reportResult() script with endless loop times out, we know that
   // the reporting timeout overwrote the default script timeout and worked.
   const base::TimeDelta kScriptTimeout = base::Days(360);
-  v8_helper_->v8_runner()->PostTask(
+  v8_helper()->v8_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(
           [](scoped_refptr<AuctionV8Helper> v8_helper,
              const base::TimeDelta script_timeout) {
             v8_helper->set_script_timeout_for_testing(script_timeout);
           },
-          v8_helper_, kScriptTimeout));
+          v8_helper(), kScriptTimeout));
   // Make sure set_script_timeout_for_testing is called.
   task_environment_.RunUntilIdle();
 
diff --git a/crypto/user_verifying_key_win.cc b/crypto/user_verifying_key_win.cc
index 8726acba..1906b5a 100644
--- a/crypto/user_verifying_key_win.cc
+++ b/crypto/user_verifying_key_win.cc
@@ -15,7 +15,6 @@
 #include <functional>
 #include <utility>
 
-#include "base/base64.h"
 #include "base/functional/callback_helpers.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
@@ -23,6 +22,8 @@
 #include "base/memory/weak_ptr.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/atomic_flag.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/task/thread_pool.h"
@@ -53,6 +54,46 @@
 
 namespace {
 
+// Possible outcomes for WinRT API calls. These are recorded for signing
+// and key creation.
+// Do not delete or reorder entries, this must be kept in sync with the
+// corresponding metrics enum.
+enum class KeyCredentialCreateResult {
+  kSucceeded = 0,
+  kAPIReturnedError = 1,
+  kNoActivationFactory = 2,
+  kRequestCreateAsyncFailed = 3,
+  kPostAsyncHandlersFailed = 4,
+  kInvalidStatusReturned = 5,
+  kInvalidResultReturned = 6,
+  kInvalidCredentialReturned = 7,
+
+  kMaxValue = 7,
+};
+
+enum class KeyCredentialSignResult {
+  kSucceeded = 0,
+  kAPIReturnedError = 1,
+  kRequestSignAsyncFailed = 2,
+  kPostAsyncHandlersFailed = 3,
+  kIBufferCreationFailed = 4,
+  kInvalidStatusReturned = 5,
+  kInvalidResultReturned = 6,
+  kInvalidSignatureBufferReturned = 7,
+
+  kMaxValue = 7,
+};
+
+void RecordCreateAsyncResult(KeyCredentialCreateResult result) {
+  base::UmaHistogramEnumeration(
+      "WebAuthentication.Windows.KeyCredentialCreation", result);
+}
+
+void RecordSignAsyncResult(KeyCredentialSignResult result) {
+  base::UmaHistogramEnumeration("WebAuthentication.Windows.KeyCredentialSign",
+                                result);
+}
+
 // Due to a Windows bug (http://task.ms/49689617), the system UI for
 // KeyCredentialManager appears under all other windows, at least when invoked
 // from a Win32 app. Therefore this code polls the visible windows and
@@ -190,6 +231,7 @@
   if (FAILED(hr) || status != KeyCredentialStatus_Success) {
     LOG(ERROR) << FormatError(
         "Failed to obtain Status from IKeyCredentialOperationResult", hr);
+    RecordSignAsyncResult(KeyCredentialSignResult::kInvalidStatusReturned);
     std::move(callback).Run(std::nullopt);
     return;
   }
@@ -199,6 +241,7 @@
   if (FAILED(hr)) {
     LOG(ERROR) << FormatError(
         "Failed to obtain Result from IKeyCredentialOperationResult", hr);
+    RecordSignAsyncResult(KeyCredentialSignResult::kInvalidResultReturned);
     std::move(callback).Run(std::nullopt);
     return;
   }
@@ -210,9 +253,13 @@
   if (FAILED(hr)) {
     LOG(ERROR) << FormatError("Failed to obtain data from signature buffer",
                               hr);
+    RecordSignAsyncResult(
+        KeyCredentialSignResult::kInvalidSignatureBufferReturned);
     std::move(callback).Run(std::nullopt);
     return;
   }
+
+  RecordSignAsyncResult(KeyCredentialSignResult::kSucceeded);
   std::move(callback).Run(
       std::vector<uint8_t>(signature_data, signature_data + signature_length));
 }
@@ -223,6 +270,7 @@
     HRESULT hr) {
   foregrounder->Stop();
   LOG(ERROR) << FormatError("Failed to sign with user-verifying signature", hr);
+  RecordSignAsyncResult(KeyCredentialSignResult::kAPIReturnedError);
   std::move(callback).Run(std::nullopt);
 }
 
@@ -235,6 +283,7 @@
       base::win::CreateIBufferFromData(data.data(), data.size(), &signing_buf);
   if (FAILED(hr)) {
     LOG(ERROR) << FormatError("SignInternal: IBuffer creation failed", hr);
+    RecordSignAsyncResult(KeyCredentialSignResult::kIBufferCreationFailed);
     std::move(callback).Run(std::nullopt);
     return;
   }
@@ -244,6 +293,7 @@
   if (FAILED(hr)) {
     LOG(ERROR) << FormatError("SignInternal: Call to RequestSignAsync failed",
                               hr);
+    RecordSignAsyncResult(KeyCredentialSignResult::kRequestSignAsyncFailed);
     std::move(callback).Run(std::nullopt);
     return;
   }
@@ -259,6 +309,7 @@
   if (FAILED(hr)) {
     LOG(ERROR) << FormatError("SignInternal: Call to PostAsyncHandlers failed",
                               hr);
+    RecordSignAsyncResult(KeyCredentialSignResult::kPostAsyncHandlersFailed);
     std::move(std::get<2>(callback_splits)).Run(std::nullopt);
     return;
   }
@@ -326,11 +377,13 @@
   if (FAILED(hr)) {
     LOG(ERROR) << FormatError(
         "Failed to obtain Status from IKeyCredentialRetrievalResult", hr);
+    RecordCreateAsyncResult(KeyCredentialCreateResult::kInvalidStatusReturned);
     std::move(callback).Run(nullptr);
     return;
   } else if (status != KeyCredentialStatus_Success) {
     LOG(ERROR) << "IKeyCredentialRetrievalResult failed with status "
                << static_cast<uint32_t>(status);
+    RecordCreateAsyncResult(KeyCredentialCreateResult::kInvalidResultReturned);
     std::move(callback).Run(nullptr);
     return;
   }
@@ -340,9 +393,13 @@
   if (FAILED(hr)) {
     LOG(ERROR) << FormatError(
         "Failed to obtain KeyCredential from KeyCredentialRetrievalResult", hr);
+    RecordCreateAsyncResult(
+        KeyCredentialCreateResult::kInvalidCredentialReturned);
     std::move(callback).Run(nullptr);
     return;
   }
+
+  RecordCreateAsyncResult(KeyCredentialCreateResult::kSucceeded);
   auto key = std::make_unique<UserVerifyingSigningKeyWin>(
       std::move(key_name), std::move(credential));
   std::move(callback).Run(std::move(key));
@@ -357,6 +414,7 @@
   }
   LOG(ERROR) << FormatError("Failed to obtain user-verifying key from system",
                             hr);
+  RecordCreateAsyncResult(KeyCredentialCreateResult::kAPIReturnedError);
   std::move(callback).Run(nullptr);
 }
 
@@ -376,6 +434,7 @@
         "GenerateUserVerifyingSigningKeyInternal: Failed to obtain activation "
         "factory for KeyCredentialManager",
         hr);
+    RecordCreateAsyncResult(KeyCredentialCreateResult::kNoActivationFactory);
     std::move(callback).Run(nullptr);
     return;
   }
@@ -389,6 +448,8 @@
         "GenerateUserVerifyingSigningKeyInternal: Call to RequestCreateAsync "
         "failed",
         hr);
+    RecordCreateAsyncResult(
+        KeyCredentialCreateResult::kRequestCreateAsyncFailed);
     std::move(callback).Run(nullptr);
     return;
   }
@@ -407,6 +468,8 @@
         "GenerateUserVerifyingSigningKeyInternal: Call to PostAsyncHandlers "
         "failed",
         hr);
+    RecordCreateAsyncResult(
+        KeyCredentialCreateResult::kPostAsyncHandlersFailed);
     std::move(std::get<2>(callback_splits)).Run(nullptr);
     return;
   }
@@ -526,7 +589,7 @@
     std::vector<uint8_t> random(16);
     crypto::RandBytes(random);
     UserVerifyingKeyLabel key_label =
-        base::StrCat({"uvkey-", base::Base64Encode(random)});
+        base::StrCat({"uvkey-", base::HexEncode(random)});
 
     scoped_refptr<base::SequencedTaskRunner> task_runner =
         base::ThreadPool::CreateSequencedTaskRunner(
diff --git a/device/fido/fido_request_handler_base.cc b/device/fido/fido_request_handler_base.cc
index 4d6a704..4be0ebed9 100644
--- a/device/fido/fido_request_handler_base.cc
+++ b/device/fido/fido_request_handler_base.cc
@@ -119,13 +119,23 @@
 FidoRequestHandlerBase::FidoRequestHandlerBase(
     FidoDiscoveryFactory* fido_discovery_factory,
     const base::flat_set<FidoTransportProtocol>& available_transports)
+    : device::FidoRequestHandlerBase(fido_discovery_factory,
+                                     /*additional_discoveries=*/{},
+                                     available_transports) {}
+
+FidoRequestHandlerBase::FidoRequestHandlerBase(
+    FidoDiscoveryFactory* fido_discovery_factory,
+    std::vector<std::unique_ptr<FidoDiscoveryBase>> additional_discoveries,
+    const base::flat_set<FidoTransportProtocol>& available_transports)
     : FidoRequestHandlerBase() {
-  InitDiscoveries(fido_discovery_factory, available_transports,
+  InitDiscoveries(fido_discovery_factory, std::move(additional_discoveries),
+                  available_transports,
                   /*consider_enclave=*/true);
 }
 
 void FidoRequestHandlerBase::InitDiscoveries(
     FidoDiscoveryFactory* fido_discovery_factory,
+    std::vector<std::unique_ptr<FidoDiscoveryBase>> additional_discoveries,
     base::flat_set<FidoTransportProtocol> available_transports,
     bool consider_enclave) {
 #if BUILDFLAG(IS_WIN)
@@ -181,6 +191,18 @@
     }
   }
 
+  // `additional_discoveries` are injected by
+  // AuthenticatorRequestClientDelegate.
+  for (auto& discovery : additional_discoveries) {
+    // TODO: Make this work better for non-standard discoveries like Windows,
+    // which currently pretends to be `kInternal`.
+    if (!base::Contains(available_transports, discovery->transport())) {
+      continue;
+    }
+    discovery->set_observer(this);
+    discoveries_.emplace_back(std::move(discovery));
+  }
+
   if (consider_enclave) {
     std::optional<std::unique_ptr<FidoDiscoveryBase>> enclave_discovery =
         fido_discovery_factory->MaybeCreateEnclaveDiscovery();
diff --git a/device/fido/fido_request_handler_base.h b/device/fido/fido_request_handler_base.h
index 7d819c3..f81c3688 100644
--- a/device/fido/fido_request_handler_base.h
+++ b/device/fido/fido_request_handler_base.h
@@ -280,6 +280,11 @@
       FidoDiscoveryFactory* fido_discovery_factory,
       const base::flat_set<FidoTransportProtocol>& available_transports);
 
+  FidoRequestHandlerBase(
+      FidoDiscoveryFactory* fido_discovery_factory,
+      std::vector<std::unique_ptr<FidoDiscoveryBase>> additional_discoveries,
+      const base::flat_set<FidoTransportProtocol>& available_transports);
+
   FidoRequestHandlerBase(const FidoRequestHandlerBase&) = delete;
   FidoRequestHandlerBase& operator=(const FidoRequestHandlerBase&) = delete;
 
@@ -344,6 +349,7 @@
 
   void InitDiscoveries(
       FidoDiscoveryFactory* fido_discovery_factory,
+      std::vector<std::unique_ptr<FidoDiscoveryBase>> additional_discoveries,
       base::flat_set<FidoTransportProtocol> available_transports,
       bool consider_enclave);
 
diff --git a/device/fido/get_assertion_handler_unittest.cc b/device/fido/get_assertion_handler_unittest.cc
index 0136f59..72c58f9 100644
--- a/device/fido/get_assertion_handler_unittest.cc
+++ b/device/fido/get_assertion_handler_unittest.cc
@@ -122,8 +122,9 @@
     ForgeDiscoveries();
 
     auto handler = std::make_unique<GetAssertionRequestHandler>(
-        fake_discovery_factory_.get(), supported_transports_,
-        std::move(request), CtapGetAssertionOptions(),
+        fake_discovery_factory_.get(),
+        std::vector<std::unique_ptr<FidoDiscoveryBase>>(),
+        supported_transports_, std::move(request), CtapGetAssertionOptions(),
         /*allow_skipping_pin_touch=*/true, get_assertion_cb_.callback());
     return handler;
   }
@@ -899,6 +900,7 @@
   TestGetAssertionRequestCallback cb;
   auto request_handler = std::make_unique<GetAssertionRequestHandler>(
       &virtual_device_factory,
+      std::vector<std::unique_ptr<FidoDiscoveryBase>>(),
       base::flat_set<FidoTransportProtocol>(
           {FidoTransportProtocol::kUsbHumanInterfaceDevice}),
       std::move(request), CtapGetAssertionOptions(),
@@ -971,6 +973,7 @@
             test_data::kTestGetAssertionCredentialId))};
     auto handler = std::make_unique<GetAssertionRequestHandler>(
         &fido_discovery_factory,
+        std::vector<std::unique_ptr<FidoDiscoveryBase>>(),
         base::flat_set<FidoTransportProtocol>(
             {FidoTransportProtocol::kUsbHumanInterfaceDevice}),
         std::move(request), CtapGetAssertionOptions(),
diff --git a/device/fido/get_assertion_request_handler.cc b/device/fido/get_assertion_request_handler.cc
index dba202a0..b3505fb 100644
--- a/device/fido/get_assertion_request_handler.cc
+++ b/device/fido/get_assertion_request_handler.cc
@@ -360,6 +360,7 @@
 
 GetAssertionRequestHandler::GetAssertionRequestHandler(
     FidoDiscoveryFactory* fido_discovery_factory,
+    std::vector<std::unique_ptr<FidoDiscoveryBase>> additional_discoveries,
     const base::flat_set<FidoTransportProtocol>& supported_transports,
     CtapGetAssertionRequest request,
     CtapGetAssertionOptions options,
@@ -367,6 +368,7 @@
     CompletionCallback completion_callback)
     : FidoRequestHandlerBase(
           fido_discovery_factory,
+          std::move(additional_discoveries),
           base::STLSetIntersection<base::flat_set<FidoTransportProtocol>>(
               supported_transports,
               GetTransportsAllowedByRP(request))),
diff --git a/device/fido/get_assertion_request_handler.h b/device/fido/get_assertion_request_handler.h
index af5896c..3b3f8f7b 100644
--- a/device/fido/get_assertion_request_handler.h
+++ b/device/fido/get_assertion_request_handler.h
@@ -18,6 +18,7 @@
 #include "device/fido/ctap_get_assertion_request.h"
 #include "device/fido/discoverable_credential_metadata.h"
 #include "device/fido/fido_constants.h"
+#include "device/fido/fido_discovery_base.h"
 #include "device/fido/fido_request_handler_base.h"
 #include "device/fido/fido_transport_protocol.h"
 #include "device/fido/public_key_credential_descriptor.h"
@@ -67,6 +68,7 @@
 
   GetAssertionRequestHandler(
       FidoDiscoveryFactory* fido_discovery_factory,
+      std::vector<std::unique_ptr<FidoDiscoveryBase>> additional_discoveries,
       const base::flat_set<FidoTransportProtocol>& supported_transports,
       CtapGetAssertionRequest request_parameter,
       CtapGetAssertionOptions request_options,
diff --git a/device/fido/make_credential_handler_unittest.cc b/device/fido/make_credential_handler_unittest.cc
index 78fe4fa5..61aa353 100644
--- a/device/fido/make_credential_handler_unittest.cc
+++ b/device/fido/make_credential_handler_unittest.cc
@@ -95,8 +95,10 @@
     options.allow_skipping_pin_touch = true;
 
     auto handler = std::make_unique<MakeCredentialRequestHandler>(
-        fake_discovery_factory_.get(), supported_transports_,
-        std::move(request_parameter), std::move(options), cb_.callback());
+        fake_discovery_factory_.get(),
+        std::vector<std::unique_ptr<FidoDiscoveryBase>>(),
+        supported_transports_, std::move(request_parameter), std::move(options),
+        cb_.callback());
     if (pending_mock_platform_device_) {
       platform_discovery_->AddDevice(std::move(pending_mock_platform_device_));
       platform_discovery_->WaitForCallToStartAndSimulateSuccess();
diff --git a/device/fido/make_credential_request_handler.cc b/device/fido/make_credential_request_handler.cc
index 551b78e..e4974abd 100644
--- a/device/fido/make_credential_request_handler.cc
+++ b/device/fido/make_credential_request_handler.cc
@@ -383,6 +383,7 @@
 
 MakeCredentialRequestHandler::MakeCredentialRequestHandler(
     FidoDiscoveryFactory* fido_discovery_factory,
+    std::vector<std::unique_ptr<FidoDiscoveryBase>> additional_discoveries,
     const base::flat_set<FidoTransportProtocol>& supported_transports,
     CtapMakeCredentialRequest request,
     const MakeCredentialOptions& options,
@@ -425,7 +426,7 @@
 #endif
 
   InitDiscoveries(
-      fido_discovery_factory,
+      fido_discovery_factory, std::move(additional_discoveries),
       base::STLSetIntersection<base::flat_set<FidoTransportProtocol>>(
           supported_transports, allowed_transports),
       request.authenticator_attachment !=
diff --git a/device/fido/make_credential_request_handler.h b/device/fido/make_credential_request_handler.h
index 1ffcaefd..0d5875f 100644
--- a/device/fido/make_credential_request_handler.h
+++ b/device/fido/make_credential_request_handler.h
@@ -76,6 +76,7 @@
 
   MakeCredentialRequestHandler(
       FidoDiscoveryFactory* fido_discovery_factory,
+      std::vector<std::unique_ptr<FidoDiscoveryBase>> additional_discoveries,
       const base::flat_set<FidoTransportProtocol>& supported_transports,
       CtapMakeCredentialRequest request_parameter,
       const MakeCredentialOptions& options,
diff --git a/extensions/browser/api/dns/dns_apitest.cc b/extensions/browser/api/dns/dns_apitest.cc
index 346ddbf..2b760954 100644
--- a/extensions/browser/api/dns/dns_apitest.cc
+++ b/extensions/browser/api/dns/dns_apitest.cc
@@ -37,10 +37,10 @@
 class DnsApiTest : public ShellApiTest {
  public:
   DnsApiTest() {
-    // Enable kSplitHostCacheByNetworkIsolationKey so the test can verify that
-    // the correct NetworkAnonymizationKey was used for the DNS lookup.
+    // Enable kPartitionConnectionsByNetworkIsolationKey so the test can verify
+    // that the correct NetworkAnonymizationKey was used for the DNS lookup.
     scoped_feature_list_.InitAndEnableFeature(
-        net::features::kSplitHostCacheByNetworkIsolationKey);
+        net::features::kPartitionConnectionsByNetworkIsolationKey);
   }
 
  private:
diff --git a/extensions/browser/api/sockets_tcp/sockets_tcp_apitest.cc b/extensions/browser/api/sockets_tcp/sockets_tcp_apitest.cc
index 2cf22834..2bbc837a 100644
--- a/extensions/browser/api/sockets_tcp/sockets_tcp_apitest.cc
+++ b/extensions/browser/api/sockets_tcp/sockets_tcp_apitest.cc
@@ -39,10 +39,10 @@
 class SocketsTcpApiTest : public ShellApiTest {
  public:
   SocketsTcpApiTest() {
-    // Enable kSplitHostCacheByNetworkIsolationKey so the test can verify that
-    // the correct NetworkAnonymizationKey was used for the DNS lookup.
+    // Enable kPartitionConnectionsByNetworkIsolationKey so the test can verify
+    // that the correct NetworkAnonymizationKey was used for the DNS lookup.
     scoped_feature_list_.InitAndEnableFeature(
-        net::features::kSplitHostCacheByNetworkIsolationKey);
+        net::features::kPartitionConnectionsByNetworkIsolationKey);
 
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         switches::kUseMockCertVerifierForTesting);
diff --git a/gpu/config/gpu_control_list_format.txt b/gpu/config/gpu_control_list_format.txt
index 2068bd8f..6b1563061 100644
--- a/gpu/config/gpu_control_list_format.txt
+++ b/gpu/config/gpu_control_list_format.txt
@@ -80,7 +80,7 @@
 //     "apollolake", "skylake", "geminilake", "kabylake", "amberlake",
 //     "coffeelake", "whiskeylake", "cometlake", "cannonlake", "icelake",
 //     "elkhartlake", "jasperlake", "tigerlake", "rocketlake", "DG1",
-//     "alderlake", "alchemist", "raptorlake", "meteorlake".
+//     "alderlake", "alchemist", "raptorlake", "meteorlake", "lunarlake".
 // 30. "hardware_overlay" is either "supported" or "unsupported". Currently it
 //     only applies on Windows where hardware overlays may be supported on
 //     certain Intel GPUs. By default it's "dont_care" and there is no need to
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json
index eadbc134..e19b7ee 100644
--- a/gpu/config/gpu_driver_bug_list.json
+++ b/gpu/config/gpu_driver_bug_list.json
@@ -2308,7 +2308,8 @@
         "alderlake",
         "alchemist",
         "raptorlake",
-        "meteorlake"
+        "meteorlake",
+        "lunarlake"
       ],
       "features": [
         "force_rgb10a2_overlay_support"
@@ -2469,7 +2470,8 @@
         "alderlake",
         "alchemist",
         "raptorlake",
-        "meteorlake"
+        "meteorlake",
+        "lunarlake"
       ],
       "features": [
         "supports_two_yuv_hardware_overlays"
diff --git a/gpu/config/gpu_info.h b/gpu/config/gpu_info.h
index 98c2043b..3087a70b 100644
--- a/gpu/config/gpu_info.h
+++ b/gpu/config/gpu_info.h
@@ -81,8 +81,9 @@
   kAlchemist = 26,
   kRaptorlake = 27,
   kMeteorlake = 28,
+  kLunarlake = 29,
   // Please also update |gpu_series_map| in process_json.py.
-  kMaxValue = kMeteorlake,
+  kMaxValue = kLunarlake,
 };
 
 // Video profile.  This *must* match media::VideoCodecProfile.
diff --git a/gpu/config/gpu_util.cc b/gpu/config/gpu_util.cc
index bb91d3c..f05e22f 100644
--- a/gpu/config/gpu_util.cc
+++ b/gpu/config/gpu_util.cc
@@ -928,6 +928,8 @@
         return IntelGpuSeriesType::kRaptorlake;
       case 0x7d00:
         return IntelGpuSeriesType::kMeteorlake;
+      case 0x6400:
+        return IntelGpuSeriesType::kLunarlake;
       default:
         break;
     }
@@ -976,6 +978,8 @@
       case IntelGpuSeriesType::kRaptorlake:
       case IntelGpuSeriesType::kMeteorlake:
         return "12";
+      case IntelGpuSeriesType::kLunarlake:
+        return "13";
       default:
         break;
     }
diff --git a/gpu/config/process_json.py b/gpu/config/process_json.py
index cb41372..6eea6d3e 100755
--- a/gpu/config/process_json.py
+++ b/gpu/config/process_json.py
@@ -687,7 +687,8 @@
       'alderlake': 'kAlderlake',
       'alchemist': 'kAlchemist',
       'raptorlake': 'kRaptorlake',
-      'meteorlake': 'kMeteorlake'
+      'meteorlake': 'kMeteorlake',
+      'lunarlake': 'kLunarlake'
     }
     for series in intel_gpu_series_list:
       assert series in intel_gpu_series_map
diff --git a/headless/test/data/protocol/sanity/request-fullscreen-expected.txt b/headless/test/data/protocol/sanity/request-fullscreen-expected.txt
index 8bed9ba..8e7d2bc 100644
--- a/headless/test/data/protocol/sanity/request-fullscreen-expected.txt
+++ b/headless/test/data/protocol/sanity/request-fullscreen-expected.txt
@@ -1,2 +1,3 @@
 Tests element requestFullscreen.
-Entered fullscreen mode: fullscreen-div
\ No newline at end of file
+Seen page zoom and fullscreen element: fullscreen-div
+Seen page un-zoom
\ No newline at end of file
diff --git a/headless/test/data/protocol/sanity/request-fullscreen.js b/headless/test/data/protocol/sanity/request-fullscreen.js
index acaeb07f..c8a1806 100644
--- a/headless/test/data/protocol/sanity/request-fullscreen.js
+++ b/headless/test/data/protocol/sanity/request-fullscreen.js
@@ -8,44 +8,40 @@
         <div id="fullscreen-div">The element.</div>
       </body>
       <script>
-        function toggleFullscreen() {
+        function enterFullscreen() {
           const element = document.getElementById("fullscreen-div");
-          if (!document.fullscreenElement) {
+          return new Promise(resolve => {
+            element.addEventListener("fullscreenchange", () => {
+              if (document.fullscreenElement) {
+                resolve(document.fullscreenElement.id);
+              }
+            });
             element.requestFullscreen();
-          } else {
-            document.exitFullscreen();
           }
-        }
+        )}
 
-        function fullscreenchanged(event) {
-          if (document.fullscreenElement) {
-            console.log("Entered fullscreen mode: "
-                + document.fullscreenElement.id);
-          }
+        function exitFullscreen() {
+          document.exitFullscreen();
         }
-
-        document.getElementById("fullscreen-div")
-          .addEventListener("fullscreenchange", fullscreenchanged);
       </script>
       </html>
   `;
   const {session, dp} =
       await testRunner.startHTML(html, 'Tests element requestFullscreen.');
 
-  await dp.Runtime.enable();
-
-  dp.Runtime.onConsoleAPICalled(data => {
-    const text = data.params.args[0].value;
-    testRunner.log(text);
-  });
-
   await dp.Page.enable();
 
-  session.evaluateAsyncWithUserGesture('window.toggleFullscreen();');
-  await dp.Page.onceFrameResized();
+  const [entered_fullscreen] = await Promise.all([
+    session.evaluateAsyncWithUserGesture('window.enterFullscreen();'),
+    dp.Page.onceFrameResized()
+  ]);
 
-  session.evaluateAsyncWithUserGesture('window.toggleFullscreen();');
+  testRunner.log(
+      'Seen page zoom and fullscreen element: ' + entered_fullscreen);
+
+  session.evaluateAsyncWithUserGesture('window.exitFullscreen();');
   await dp.Page.onceFrameResized();
+  testRunner.log('Seen page un-zoom');
 
   testRunner.completeTest();
 })
diff --git a/headless/test/headless_protocol_browsertest.cc b/headless/test/headless_protocol_browsertest.cc
index 9ffc79f..4d923978 100644
--- a/headless/test/headless_protocol_browsertest.cc
+++ b/headless/test/headless_protocol_browsertest.cc
@@ -370,13 +370,7 @@
 HEADLESS_PROTOCOL_TEST(ScreencastBasics, "sanity/screencast-basics.js")
 HEADLESS_PROTOCOL_TEST(ScreencastViewport, "sanity/screencast-viewport.js")
 
-// https://crbug.com/339788212
-#if BUILDFLAG(IS_MAC)
-#define MAYBE_RequestFullscreen DISABLED_RequestFullscreen
-#else
-#define MAYBE_RequestFullscreen RequestFullscreen
-#endif
-HEADLESS_PROTOCOL_TEST(MAYBE_RequestFullscreen, "sanity/request-fullscreen.js")
+HEADLESS_PROTOCOL_TEST(RequestFullscreen, "sanity/request-fullscreen.js")
 
 class HeadlessProtocolBrowserTestWithProxy
     : public HeadlessProtocolBrowserTest {
diff --git a/infra/config/generated/testing/mixins.pyl b/infra/config/generated/testing/mixins.pyl
index 505a4a7..4040951 100644
--- a/infra/config/generated/testing/mixins.pyl
+++ b/infra/config/generated/testing/mixins.pyl
@@ -1435,6 +1435,13 @@
       },
     },
   },
+  'win11-any': {
+    'swarming': {
+      'dimensions': {
+        'os': 'Windows-11',
+      },
+    },
+  },
   'win11_qualcomm_adreno_690_stable': {
     'swarming': {
       'dimensions': {
diff --git a/infra/config/generated/testing/variants.pyl b/infra/config/generated/testing/variants.pyl
index 58c7b6a..7a01e9b 100644
--- a/infra/config/generated/testing/variants.pyl
+++ b/infra/config/generated/testing/variants.pyl
@@ -267,16 +267,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'identifier': 'Lacros version skew testing ash canary',
-    'description': 'Run with ash-chrome version 126.0.6476.0',
+    'description': 'Run with ash-chrome version 126.0.6477.0',
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6476.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6477.0/test_ash_chrome',
     ],
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v126.0.6476.0',
-          'revision': 'version:126.0.6476.0',
+          'location': 'lacros_version_skew_tests_v126.0.6477.0',
+          'revision': 'version:126.0.6477.0',
         },
       ],
     },
diff --git a/infra/config/targets/lacros-version-skew-variants.json b/infra/config/targets/lacros-version-skew-variants.json
index 03a25da..6c55313 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_v126.0.6476.0/test_ash_chrome"
+      "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6477.0/test_ash_chrome"
     ],
-    "description": "Run with ash-chrome version 126.0.6476.0",
+    "description": "Run with ash-chrome version 126.0.6477.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_v126.0.6476.0",
-          "revision": "version:126.0.6476.0"
+          "location": "lacros_version_skew_tests_v126.0.6477.0",
+          "revision": "version:126.0.6477.0"
         }
       ]
     }
diff --git a/infra/config/targets/mixins.star b/infra/config/targets/mixins.star
index b009a64..f6479b8 100644
--- a/infra/config/targets/mixins.star
+++ b/infra/config/targets/mixins.star
@@ -1842,6 +1842,15 @@
 )
 
 targets.mixin(
+    name = "win11-any",
+    swarming = targets.swarming(
+        dimensions = {
+            "os": "Windows-11",
+        },
+    ),
+)
+
+targets.mixin(
     name = "win-arm64",
     swarming = targets.swarming(
         dimensions = {
diff --git a/ios/chrome/browser/DEPS b/ios/chrome/browser/DEPS
index 4044455d..0654d61 100644
--- a/ios/chrome/browser/DEPS
+++ b/ios/chrome/browser/DEPS
@@ -65,6 +65,7 @@
   "+components/omnibox/common",
   "+components/open_from_clipboard",
   "+components/optimization_guide",
+  "+components/os_crypt/async/browser",
   "+components/password_manager/core/browser",
   "+components/password_manager/core/common",
   "+components/password_manager/ios",
diff --git a/ios/chrome/browser/application_context/model/BUILD.gn b/ios/chrome/browser/application_context/model/BUILD.gn
index ee5357a..4f6cf0f 100644
--- a/ios/chrome/browser/application_context/model/BUILD.gn
+++ b/ios/chrome/browser/application_context/model/BUILD.gn
@@ -19,6 +19,7 @@
     "//components/metrics_services_manager",
     "//components/net_log",
     "//components/network_time",
+    "//components/os_crypt/async/browser",
     "//components/prefs",
     "//components/sessions",
     "//components/translate/core/browser",
diff --git a/ios/chrome/browser/application_context/model/application_context_impl.h b/ios/chrome/browser/application_context/model/application_context_impl.h
index 79f6794..00899f2 100644
--- a/ios/chrome/browser/application_context/model/application_context_impl.h
+++ b/ios/chrome/browser/application_context/model/application_context_impl.h
@@ -85,6 +85,7 @@
   GetSegmentationOTRWebStateObserver() override;
   PushNotificationService* GetPushNotificationService() override;
   UpgradeCenter* GetUpgradeCenter() override;
+  os_crypt_async::OSCryptAsync* GetOSCryptAsync() override;
 
  private:
   // Represents the possible application states the app can be in.
@@ -158,6 +159,8 @@
 
   std::unique_ptr<PushNotificationService> push_notification_service_;
 
+  std::unique_ptr<os_crypt_async::OSCryptAsync> os_crypt_async_;
+
   __strong UpgradeCenter* upgrade_center_ = nil;
 };
 
diff --git a/ios/chrome/browser/application_context/model/application_context_impl.mm b/ios/chrome/browser/application_context/model/application_context_impl.mm
index 4472120..3d199fc 100644
--- a/ios/chrome/browser/application_context/model/application_context_impl.mm
+++ b/ios/chrome/browser/application_context/model/application_context_impl.mm
@@ -33,6 +33,7 @@
 #import "components/metrics_services_manager/metrics_services_manager.h"
 #import "components/net_log/net_export_file_writer.h"
 #import "components/network_time/network_time_tracker.h"
+#import "components/os_crypt/async/browser/os_crypt_async.h"
 #import "components/prefs/pref_registry_simple.h"
 #import "components/prefs/pref_service.h"
 #import "components/sessions/core/session_id_generator.h"
@@ -142,6 +143,14 @@
 }
 
 void ApplicationContextImpl::PostCreateThreads() {
+  // Delegate all encryption calls to OSCrypt.
+  os_crypt_async_ = std::make_unique<os_crypt_async::OSCryptAsync>(
+      std::vector<std::pair<os_crypt_async::OSCryptAsync::Precedence,
+                            std::unique_ptr<os_crypt_async::KeyProvider>>>());
+
+  // Trigger an instance grab on a background thread if necessary.
+  std::ignore = os_crypt_async_->GetInstance(base::DoNothing());
+
   web::GetIOThreadTaskRunner({})->PostTask(
       FROM_HERE, base::BindOnce(&IOSChromeIOThread::InitOnIO,
                                 base::Unretained(ios_chrome_io_thread_.get())));
@@ -524,6 +533,10 @@
   return upgrade_center_;
 }
 
+os_crypt_async::OSCryptAsync* ApplicationContextImpl::GetOSCryptAsync() {
+  return os_crypt_async_.get();
+}
+
 void ApplicationContextImpl::OnAppEnterState(AppState app_state) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!tearing_down_);
diff --git a/ios/chrome/browser/data_sharing/model/data_sharing_service_factory.mm b/ios/chrome/browser/data_sharing/model/data_sharing_service_factory.mm
index 4a2c539..9404693 100644
--- a/ios/chrome/browser/data_sharing/model/data_sharing_service_factory.mm
+++ b/ios/chrome/browser/data_sharing/model/data_sharing_service_factory.mm
@@ -47,7 +47,7 @@
       ModelTypeStoreServiceFactory::GetForBrowserState(chrome_browser_state)
           ->GetStoreFactory(),
       ::GetChannel(),
-      /*sdk_delegate=*/nullptr);
+      /*sdk_delegate=*/nullptr, /*ui_delegate=*/nullptr);
 }
 
 }  // namespace
diff --git a/ios/chrome/browser/shared/model/application_context/application_context.h b/ios/chrome/browser/shared/model/application_context/application_context.h
index e5a502b..f8aeeda 100644
--- a/ios/chrome/browser/shared/model/application_context/application_context.h
+++ b/ios/chrome/browser/shared/model/application_context/application_context.h
@@ -52,6 +52,10 @@
 class NetworkTimeTracker;
 }
 
+namespace os_crypt_async {
+class OSCryptAsync;
+}
+
 namespace segmentation_platform {
 class OTRWebStateObserver;
 }
@@ -182,6 +186,10 @@
   // notification to upgrade Chrome on iOS.
   virtual UpgradeCenter* GetUpgradeCenter() = 0;
 
+  // Returns the application's OSCryptAsync instance which can be used to create
+  // instances of Encryptor for data encryption.
+  virtual os_crypt_async::OSCryptAsync* GetOSCryptAsync() = 0;
+
  protected:
   // Sets the global ApplicationContext instance.
   static void SetApplicationContext(ApplicationContext* context);
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn
index 67230e1..762b892 100644
--- a/ios/chrome/test/BUILD.gn
+++ b/ios/chrome/test/BUILD.gn
@@ -68,6 +68,7 @@
     "//components/content_settings/core/browser",
     "//components/content_settings/core/common",
     "//components/network_time",
+    "//components/os_crypt/async/browser:test_support",
     "//components/prefs",
     "//components/prefs:test_support",
     "//components/safe_browsing/core/common",
diff --git a/ios/chrome/test/DEPS b/ios/chrome/test/DEPS
index 208e8bb..248f0aa 100644
--- a/ios/chrome/test/DEPS
+++ b/ios/chrome/test/DEPS
@@ -11,6 +11,7 @@
   "+components/language",
   "+components/metrics",
   "+components/network_time",
+  "+components/os_crypt/async",
   "+components/password_manager/core/common",
   "+components/prefs",
   "+components/signin/internal/identity_manager",
diff --git a/ios/chrome/test/testing_application_context.h b/ios/chrome/test/testing_application_context.h
index 5df05f88..6987c54 100644
--- a/ios/chrome/test/testing_application_context.h
+++ b/ios/chrome/test/testing_application_context.h
@@ -92,6 +92,7 @@
   GetSegmentationOTRWebStateObserver() override;
   PushNotificationService* GetPushNotificationService() override;
   UpgradeCenter* GetUpgradeCenter() override;
+  os_crypt_async::OSCryptAsync* GetOSCryptAsync() override;
 
  private:
   base::ThreadChecker thread_checker_;
@@ -118,6 +119,7 @@
   std::unique_ptr<PushNotificationService> push_notification_service_;
   raw_ptr<variations::VariationsService> variations_service_;
   __strong UpgradeCenter* upgrade_center_ = nil;
+  std::unique_ptr<os_crypt_async::OSCryptAsync> os_crypt_async_;
   raw_ptr<IOSChromeIOThread> ios_chrome_io_thread_;
 };
 
diff --git a/ios/chrome/test/testing_application_context.mm b/ios/chrome/test/testing_application_context.mm
index 7ba134c7..cbdfb54 100644
--- a/ios/chrome/test/testing_application_context.mm
+++ b/ios/chrome/test/testing_application_context.mm
@@ -11,6 +11,7 @@
 #import "base/time/default_clock.h"
 #import "base/time/default_tick_clock.h"
 #import "components/network_time/network_time_tracker.h"
+#import "components/os_crypt/async/browser/test_utils.h"
 #import "components/variations/service/variations_service.h"
 #import "ios/chrome/browser/browser_state/model/ios_chrome_io_thread.h"
 #import "ios/chrome/browser/policy/model/browser_policy_connector_ios.h"
@@ -288,3 +289,10 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   return upgrade_center_;
 }
+
+os_crypt_async::OSCryptAsync* TestingApplicationContext::GetOSCryptAsync() {
+  if (!os_crypt_async_) {
+    os_crypt_async_ = os_crypt_async::GetTestOSCryptAsyncForTesting();
+  }
+  return os_crypt_async_.get();
+}
diff --git a/ios/web/content/BUILD.gn b/ios/web/content/BUILD.gn
index 671d08f..56023242 100644
--- a/ios/web/content/BUILD.gn
+++ b/ios/web/content/BUILD.gn
@@ -27,6 +27,8 @@
     "navigation/content_navigation_item.mm",
     "navigation/content_navigation_manager.h",
     "navigation/content_navigation_manager.mm",
+    "ui/web_contents_view_delegate_impl.h",
+    "ui/web_contents_view_delegate_impl.mm",
     "web_state/content_web_state.h",
     "web_state/content_web_state.mm",
     "web_state/content_web_state_builder.h",
diff --git a/ios/web/content/init/DEPS b/ios/web/content/init/DEPS
index a3250d28..a002650 100644
--- a/ios/web/content/init/DEPS
+++ b/ios/web/content/init/DEPS
@@ -4,5 +4,6 @@
   "+content/public/common",
   "+content/public/renderer",
   "+components/embedder_support",
+  "+components/performance_manager/embedder",
   "+components/version_info",
 ]
diff --git a/ios/web/content/init/ios_content_browser_client.cc b/ios/web/content/init/ios_content_browser_client.cc
index 68f2980d..42fab05 100644
--- a/ios/web/content/init/ios_content_browser_client.cc
+++ b/ios/web/content/init/ios_content_browser_client.cc
@@ -5,12 +5,15 @@
 #include "ios/web/content/init/ios_content_browser_client.h"
 
 #import "components/embedder_support/user_agent_utils.h"
+#import "components/performance_manager/embedder/performance_manager_registry.h"
 #import "components/version_info/version_info.h"
 #import "content/public/browser/browser_context.h"
 #import "content/public/browser/devtools_manager_delegate.h"
+#import "content/public/browser/web_contents_view_delegate.h"
 #import "content/public/common/url_constants.h"
 #import "content/public/common/user_agent.h"
 #import "ios/web/content/init/ios_browser_main_parts.h"
+#import "ios/web/content/ui/web_contents_view_delegate_impl.h"
 
 namespace web {
 
@@ -81,6 +84,16 @@
   return metadata;
 }
 
+std::unique_ptr<content::WebContentsViewDelegate>
+IOSContentBrowserClient::GetWebContentsViewDelegate(
+    content::WebContents* web_contents) {
+  if (auto* registry =
+          performance_manager::PerformanceManagerRegistry::GetInstance()) {
+    registry->MaybeCreatePageNodeForWebContents(web_contents);
+  }
+  return CreateWebContentsViewDelegate(web_contents);
+}
+
 bool IOSContentBrowserClient::IsSharedStorageAllowed(
     content::BrowserContext* browser_context,
     content::RenderFrameHost* rfh,
diff --git a/ios/web/content/init/ios_content_browser_client.h b/ios/web/content/init/ios_content_browser_client.h
index 07d79cb..241ad9eb 100644
--- a/ios/web/content/init/ios_content_browser_client.h
+++ b/ios/web/content/init/ios_content_browser_client.h
@@ -26,6 +26,8 @@
   std::string GetUserAgentBasedOnPolicy(
       content::BrowserContext* context) override;
   blink::UserAgentMetadata GetUserAgentMetadata() override;
+  std::unique_ptr<content::WebContentsViewDelegate> GetWebContentsViewDelegate(
+      content::WebContents* web_contents) override;
   bool IsSharedStorageAllowed(
       content::BrowserContext* browser_context,
       content::RenderFrameHost* rfh,
diff --git a/ios/web/content/ui/web_contents_view_delegate_impl.h b/ios/web/content/ui/web_contents_view_delegate_impl.h
new file mode 100644
index 0000000..260c3d63
--- /dev/null
+++ b/ios/web/content/ui/web_contents_view_delegate_impl.h
@@ -0,0 +1,39 @@
+// 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 IOS_WEB_CONTENT_UI_WEB_CONTENTS_VIEW_DELEGATE_IMPL_H_
+#define IOS_WEB_CONTENT_UI_WEB_CONTENTS_VIEW_DELEGATE_IMPL_H_
+
+#import "base/memory/raw_ptr.h"
+#import "content/public/browser/web_contents_view_delegate.h"
+
+namespace content {
+class WebContents;
+class WebContentsViewDelegate;
+}  // namespace content
+
+class WebContentsViewDelegateImpl : public content::WebContentsViewDelegate {
+ public:
+  explicit WebContentsViewDelegateImpl(content::WebContents* web_contents);
+
+  WebContentsViewDelegateImpl(const WebContentsViewDelegateImpl&) = delete;
+  WebContentsViewDelegateImpl& operator=(const WebContentsViewDelegateImpl&) =
+      delete;
+
+  ~WebContentsViewDelegateImpl() override;
+
+  // WebContentsViewDelegate:
+  void ShowContextMenu(content::RenderFrameHost& render_frame_host,
+                       const content::ContextMenuParams& params) override;
+  void DismissContextMenu() override;
+
+ private:
+  // The WebContents that owns the view and this delegate transitively.
+  raw_ptr<content::WebContents> web_contents_;
+};
+
+std::unique_ptr<content::WebContentsViewDelegate> CreateWebContentsViewDelegate(
+    content::WebContents* web_contents);
+
+#endif  // IOS_WEB_CONTENT_UI_WEB_CONTENTS_VIEW_DELEGATE_IMPL_H_
diff --git a/ios/web/content/ui/web_contents_view_delegate_impl.mm b/ios/web/content/ui/web_contents_view_delegate_impl.mm
new file mode 100644
index 0000000..254aa52
--- /dev/null
+++ b/ios/web/content/ui/web_contents_view_delegate_impl.mm
@@ -0,0 +1,32 @@
+// 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 "ios/web/content/ui/web_contents_view_delegate_impl.h"
+
+#import <memory>
+
+#import "content/public/browser/context_menu_params.h"
+#import "content/public/browser/web_contents.h"
+#import "content/public/browser/web_contents_view_delegate.h"
+
+WebContentsViewDelegateImpl::WebContentsViewDelegateImpl(
+    content::WebContents* web_contents)
+    : web_contents_(web_contents) {}
+
+WebContentsViewDelegateImpl::~WebContentsViewDelegateImpl() {}
+
+void WebContentsViewDelegateImpl::ShowContextMenu(
+    content::RenderFrameHost& render_frame_host,
+    const content::ContextMenuParams& params) {
+  NOTIMPLEMENTED();
+}
+
+void WebContentsViewDelegateImpl::DismissContextMenu() {
+  NOTIMPLEMENTED();
+}
+
+std::unique_ptr<content::WebContentsViewDelegate> CreateWebContentsViewDelegate(
+    content::WebContents* web_contents) {
+  return std::make_unique<WebContentsViewDelegateImpl>(web_contents);
+}
diff --git a/ios/web/download/download_native_task_bridge.mm b/ios/web/download/download_native_task_bridge.mm
index 2cf9206..37365a6 100644
--- a/ios/web/download/download_native_task_bridge.mm
+++ b/ios/web/download/download_native_task_bridge.mm
@@ -130,6 +130,12 @@
     return;
   }
 
+  // TODO(crbug.com/339626229): Fix early return workaround.
+  CHECK(_startDownloadBlock, base::NotFatalUntil::M129);
+  if (!_startDownloadBlock) {
+    return;
+  }
+
   [self responseReceived:_response];
   [self startObservingDownloadProgress];
   _startDownloadBlock(_urlForDownload);
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn
index 3b95b807..2911828 100644
--- a/ios/web_view/BUILD.gn
+++ b/ios/web_view/BUILD.gn
@@ -325,6 +325,7 @@
   "//components/lookalikes/core",
   "//components/metrics:library_support",
   "//components/metrics/demographics",
+  "//components/os_crypt/async/browser",
   "//components/password_manager/core/browser",
   "//components/password_manager/core/browser/affiliation:affiliation_fetching",
   "//components/password_manager/core/browser/features:password_features",
diff --git a/ios/web_view/internal/DEPS b/ios/web_view/internal/DEPS
index 0949033..b5882d19 100644
--- a/ios/web_view/internal/DEPS
+++ b/ios/web_view/internal/DEPS
@@ -22,6 +22,7 @@
   "+components/metrics/demographics",
   "+components/metrics/library_support",
   "+components/net_log",
+  "+components/os_crypt/async/browser",
   "+components/password_manager/core",
   "+components/password_manager/ios",
   "+components/plus_addresses/webdata/plus_address_webdata_service.h",
diff --git a/ios/web_view/internal/app/application_context.h b/ios/web_view/internal/app/application_context.h
index 3e6ec94..696ef6a 100644
--- a/ios/web_view/internal/app/application_context.h
+++ b/ios/web_view/internal/app/application_context.h
@@ -34,6 +34,10 @@
 }
 }  // namespace network
 
+namespace os_crypt_async {
+class OSCryptAsync;
+}
+
 class PrefService;
 class SafeBrowsingService;
 
@@ -70,6 +74,9 @@
   // Gets the ComponentUpdateService.
   component_updater::ComponentUpdateService* GetComponentUpdateService();
 
+  // Gets the application specific OSCryptAsync instance.
+  os_crypt_async::OSCryptAsync* GetOSCryptAsync();
+
   // Creates state tied to application threads. It is expected this will be
   // called from web::WebMainParts::PreCreateThreads.
   void PreCreateThreads();
@@ -124,6 +131,8 @@
   std::unique_ptr<component_updater::ComponentUpdateService> component_updater_;
 
   scoped_refptr<SafeBrowsingService> safe_browsing_service_;
+
+  std::unique_ptr<os_crypt_async::OSCryptAsync> os_crypt_async_;
 };
 
 }  // namespace ios_web_view
diff --git a/ios/web_view/internal/app/application_context.mm b/ios/web_view/internal/app/application_context.mm
index dbd4762..76be3887 100644
--- a/ios/web_view/internal/app/application_context.mm
+++ b/ios/web_view/internal/app/application_context.mm
@@ -14,6 +14,7 @@
 #include "components/component_updater/timer_update_scheduler.h"
 #include "components/flags_ui/pref_service_flags_storage.h"
 #import "components/metrics/demographics/user_demographics.h"
+#import "components/os_crypt/async/browser/os_crypt_async.h"
 #include "components/prefs/json_pref_store.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
@@ -70,6 +71,14 @@
 }
 
 void ApplicationContext::PostCreateThreads() {
+  // Delegate all encryption calls to OSCrypt.
+  os_crypt_async_ = std::make_unique<os_crypt_async::OSCryptAsync>(
+      std::vector<std::pair<os_crypt_async::OSCryptAsync::Precedence,
+                            std::unique_ptr<os_crypt_async::KeyProvider>>>());
+
+  // Trigger an instance grab on a background thread if necessary.
+  std::ignore = os_crypt_async_->GetInstance(base::DoNothing());
+
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   web::GetIOThreadTaskRunner({})->PostTask(
       FROM_HERE, base::BindOnce(&WebViewIOThread::InitOnIO,
@@ -221,6 +230,10 @@
   return component_updater_.get();
 }
 
+os_crypt_async::OSCryptAsync* ApplicationContext::GetOSCryptAsync() {
+  return os_crypt_async_.get();
+}
+
 WebViewIOThread* ApplicationContext::GetWebViewIOThread() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(web_view_io_thread_.get());
diff --git a/media/video/gpu_memory_buffer_video_frame_pool.cc b/media/video/gpu_memory_buffer_video_frame_pool.cc
index 56a4601..893dfaa 100644
--- a/media/video/gpu_memory_buffer_video_frame_pool.cc
+++ b/media/video/gpu_memory_buffer_video_frame_pool.cc
@@ -55,6 +55,18 @@
 #endif
 
 namespace media {
+namespace {
+
+// Allow MappableSI to be used for GpuMemoryBufferVideoFramePool. Note that
+// enabling this flag does not necessarily enables MappableSI usage as it also
+// currently needs MultiPlanarSI support. MultiPlanarSI is now enabled by
+// default on ToT but the flag is still alive for 1 full release as a
+// kill-switch.
+BASE_FEATURE(kAlwaysUseMappableSIForGpuMemoryBufferVideoFramePool,
+             "AlwaysUseMappableSIForGpuMemoryBufferVideoFramePool",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
+}  // namespace
 
 // Implementation of a pool of GpuMemoryBuffers used to back VideoFrames.
 class GpuMemoryBufferVideoFramePool::PoolImpl
@@ -76,7 +88,10 @@
         gpu_factories_(gpu_factories),
         output_format_(GpuVideoAcceleratorFactories::OutputFormat::UNDEFINED),
         tick_clock_(base::DefaultTickClock::GetInstance()),
-        in_shutdown_(false) {
+        is_mappable_si_enabled_(
+            base::FeatureList::IsEnabled(
+                kAlwaysUseMappableSIForGpuMemoryBufferVideoFramePool) &&
+            IsMultiPlaneFormatForSoftwareVideoEnabled()) {
     DCHECK(media_task_runner_);
     DCHECK(worker_task_runner_);
 
@@ -84,6 +99,23 @@
     // GpuMemoryBufferVideoFramePool in a thread safe manner.
     static std::atomic_uint32_t id = 0;
     pool_id_ = ++id;
+
+    // Moving the common shared image usage here as a member. This can be moved
+    // back to local code where MappableSI is created after the GMB path is
+    // full removed.
+    si_usage_ = gpu::SHARED_IMAGE_USAGE_GLES2_READ |
+                gpu::SHARED_IMAGE_USAGE_RASTER_READ |
+                gpu::SHARED_IMAGE_USAGE_DISPLAY_READ |
+                gpu::SHARED_IMAGE_USAGE_SCANOUT;
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC)
+    // TODO(crbug.com/40194712): Always add the flag once the
+    // OzoneImageBacking is by default turned on.
+    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kEnableUnsafeWebGPU)) {
+      // This SharedImage may be used for zero-copy import into WebGPU.
+      si_usage_ |= gpu::SHARED_IMAGE_USAGE_WEBGPU_READ;
+    }
+#endif
   }
 
   PoolImpl(const PoolImpl&) = delete;
@@ -111,6 +143,8 @@
 
   void SetTickClockForTesting(const base::TickClock* tick_clock);
 
+  bool IsMappableSIEnabled() const;
+
  private:
   friend class base::RefCountedThreadSafe<
       GpuMemoryBufferVideoFramePool::PoolImpl>;
@@ -119,9 +153,16 @@
   // Resource to represent a plane.
   struct PlaneResource {
     gfx::Size size;
-    std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer;
     int32_t buffer_id = -1;
+    std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer;
     scoped_refptr<gpu::ClientSharedImage> shared_image;
+
+    // Currently when GpuMemoryBuffers are used to represent a resource plane,
+    // Map() and UnMap() happens in different methods and are not scoped in the
+    // same method. With MappableSI, keeping the |scoped_mapping| will allow to
+    // Map() and reset(UnMap()) it as needed to achieve same behavior.
+    std::unique_ptr<gpu::ClientSharedImage::ScopedMapping> scoped_mapping;
+
     // Tracks whether the SharedImage is created with GpuMemoryBuffer containing
     // multiplanar format and prefers external sampler.
     bool needs_external_sampler = false;
@@ -224,9 +265,9 @@
   // Get the resources needed for a frame out of the pool, or create them if
   // necessary.
   // This also drops the LRU resources that can't be reuse for this frame.
-  FrameResources* GetOrCreateFrameResources(
-      const gfx::Size& size,
-      gfx::BufferUsage usage);
+  FrameResources* GetOrCreateFrameResources(const gfx::Size& size,
+                                            gfx::BufferUsage usage,
+                                            const gfx::ColorSpace& color_space);
 
   // Calls the FrameReadyCB of the first entry in |frame_copy_requests_|, with
   // the provided |video_frame|, then deletes the entry from
@@ -275,6 +316,9 @@
   // GpuMemoryBuffer::GetId() and eventually GpuMemoryBuffer altogether when
   // MappableSI is enabled.
   uint32_t buffer_id_ = 0;
+
+  const bool is_mappable_si_enabled_;
+  uint32_t si_usage_ = 0;
 };
 
 namespace {
@@ -858,22 +902,35 @@
   for (const FrameResources* frame_resources : resources_pool_) {
     for (const PlaneResource& plane_resource :
          frame_resources->plane_resources) {
-      if (plane_resource.gpu_memory_buffer) {
+      if ((is_mappable_si_enabled_ && plane_resource.shared_image) ||
+          (!is_mappable_si_enabled_ && plane_resource.gpu_memory_buffer)) {
         std::string dump_name =
             base::StringPrintf("media/video_frame_memory_%d/buffer_%d",
                                pool_id_, plane_resource.buffer_id);
         base::trace_event::MemoryAllocatorDump* dump =
             pmd->CreateAllocatorDump(dump_name);
-        size_t buffer_size_in_bytes = gfx::BufferSizeForBufferFormat(
-            plane_resource.size, plane_resource.gpu_memory_buffer->GetFormat());
+
+        size_t buffer_size_in_bytes =
+            is_mappable_si_enabled_
+                ? plane_resource.shared_image->format().EstimatedSizeInBytes(
+                      plane_resource.size)
+                : gfx::BufferSizeForBufferFormat(
+                      plane_resource.size,
+                      plane_resource.gpu_memory_buffer->GetFormat());
+
         dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
                         base::trace_event::MemoryAllocatorDump::kUnitsBytes,
                         buffer_size_in_bytes);
         dump->AddScalar("free_size",
                         base::trace_event::MemoryAllocatorDump::kUnitsBytes,
                         frame_resources->is_used() ? 0 : buffer_size_in_bytes);
-        plane_resource.gpu_memory_buffer->OnMemoryDump(
-            pmd, dump->guid(), tracing_process_id, kImportance);
+        if (is_mappable_si_enabled_) {
+          plane_resource.shared_image->OnMemoryDump(pmd, dump->guid(),
+                                                    kImportance);
+        } else {
+          plane_resource.gpu_memory_buffer->OnMemoryDump(
+              pmd, dump->guid(), tracing_process_id, kImportance);
+        }
       }
     }
   }
@@ -895,13 +952,22 @@
     scoped_refptr<VideoFrame> video_frame,
     FrameResources* frame_resources) {
   if (!copy_failed) {
-    for (const auto& plane_resource : frame_resources->plane_resources) {
+    for (auto& plane_resource : frame_resources->plane_resources) {
       if (plane_resource.gpu_memory_buffer) {
+        // Additional checks for sanity and debug until MappableSI is launched.
+        CHECK(!is_mappable_si_enabled_);
         plane_resource.gpu_memory_buffer->Unmap();
 #if BUILDFLAG(IS_MAC)
         plane_resource.gpu_memory_buffer->SetColorSpace(
             video_frame->ColorSpace());
 #endif
+      } else if (plane_resource.scoped_mapping) {
+        CHECK(is_mappable_si_enabled_);
+        plane_resource.scoped_mapping.reset();
+#if BUILDFLAG(IS_MAC)
+        plane_resource.shared_image->SetColorSpaceOnNativeBuffer(
+            video_frame->ColorSpace());
+#endif
       }
     }
   }
@@ -929,7 +995,8 @@
             ? nullptr
             : GetOrCreateFrameResources(
                   CodedSize(request.video_frame.get(), output_format_),
-                  gfx::BufferUsage::SCANOUT_CPU_READ_WRITE);
+                  gfx::BufferUsage::SCANOUT_CPU_READ_WRITE,
+                  request.video_frame->ColorSpace());
     if (!frame_resources) {
       std::move(request.frame_ready_cb).Run(std::move(request.video_frame));
       frame_copy_requests_.pop_front();
@@ -965,13 +1032,32 @@
   }
 
   for (size_t i = 0; i < NumGpuMemoryBuffers(output_format_); ++i) {
-    gfx::GpuMemoryBuffer* buffer =
-        frame_resources->plane_resources[i].gpu_memory_buffer.get();
+    auto& plane_resource = frame_resources->plane_resources[i];
+    bool mapping_succeeded = false;
 
-    if (!buffer || !buffer->Map()) {
-      DLOG(ERROR) << "Could not get or Map() buffer";
-      for (size_t j = 0; j < i; ++j)
-        frame_resources->plane_resources[j].gpu_memory_buffer->Unmap();
+    // Shared image mapping (if enabled).
+    if (is_mappable_si_enabled_) {
+      mapping_succeeded = plane_resource.shared_image &&
+                          (plane_resource.scoped_mapping =
+                               plane_resource.shared_image->Map()) != nullptr;
+    } else {
+      // Check GPU memory buffer mapping.
+      mapping_succeeded = plane_resource.gpu_memory_buffer &&
+                          plane_resource.gpu_memory_buffer->Map();
+    }
+
+    // Error handling.
+    if (!mapping_succeeded) {
+      DLOG(ERROR) << "Could not get or map buffer.";
+
+      // Unmap previously mapped buffers.
+      for (size_t j = 0; j < i; ++j) {
+        if (is_mappable_si_enabled_) {
+          frame_resources->plane_resources[j].scoped_mapping.reset();
+        } else {
+          frame_resources->plane_resources[j].gpu_memory_buffer->Unmap();
+        }
+      }
       OnCopiesDone(/*copy_failed=*/true, std::move(video_frame),
                    frame_resources);
       return;
@@ -1033,14 +1119,23 @@
   base::ScopedClosureRunner done_runner(std::move(done));
   gfx::GpuMemoryBuffer* buffer =
       frame_resources->plane_resources[plane].gpu_memory_buffer.get();
+  auto* scoped_mapping =
+      frame_resources->plane_resources[plane].scoped_mapping.get();
+
+  // To handle plane 0 of the underlying buffer.
+  uint8_t* memory_ptr0 = static_cast<uint8_t*>(
+      scoped_mapping ? scoped_mapping->Memory(0) : buffer->memory(0));
+  size_t stride0 =
+      scoped_mapping ? scoped_mapping->Stride(0) : buffer->stride(0);
+
   switch (output_format) {
     case GpuVideoAcceleratorFactories::OutputFormat::I420: {
       const int bytes_per_row = VideoFrame::RowBytes(
           plane, VideoFormat(output_format), coded_size.width());
-      CopyRowsToI420Buffer(
-          row, rows_to_copy, bytes_per_row, video_frame->BitDepth(),
-          video_frame->visible_data(plane), video_frame->stride(plane),
-          static_cast<uint8_t*>(buffer->memory(0)), buffer->stride(0));
+      CopyRowsToI420Buffer(row, rows_to_copy, bytes_per_row,
+                           video_frame->BitDepth(),
+                           video_frame->visible_data(plane),
+                           video_frame->stride(plane), memory_ptr0, stride0);
       break;
     }
 
@@ -1064,21 +1159,26 @@
         const size_t plane_bytes_per_row =
             VideoFrame::RowBytes(src_plane, pixel_format, coded_size.width());
 
-        CopyRowsToI420Buffer(plane_row_start, plane_rows_to_copy,
-                             plane_bytes_per_row, video_frame->BitDepth(),
-                             video_frame->visible_data(src_plane),
-                             video_frame->stride(src_plane),
-                             static_cast<uint8_t*>(buffer->memory(dst_plane)),
-                             buffer->stride(dst_plane));
+        CopyRowsToI420Buffer(
+            plane_row_start, plane_rows_to_copy, plane_bytes_per_row,
+            video_frame->BitDepth(), video_frame->visible_data(src_plane),
+            video_frame->stride(src_plane),
+            static_cast<uint8_t*>(scoped_mapping
+                                      ? scoped_mapping->Memory(dst_plane)
+                                      : buffer->memory(dst_plane)),
+            scoped_mapping ? scoped_mapping->Stride(dst_plane)
+                           : buffer->stride(dst_plane));
       }
       break;
     }
 
     case GpuVideoAcceleratorFactories::OutputFormat::P010:
       CopyRowsToP010Buffer(
-          row, rows_to_copy, coded_size.width(), video_frame,
-          static_cast<uint8_t*>(buffer->memory(0)), buffer->stride(0),
-          static_cast<uint8_t*>(buffer->memory(1)), buffer->stride(1));
+          row, rows_to_copy, coded_size.width(), video_frame, memory_ptr0,
+          stride0,
+          static_cast<uint8_t*>(scoped_mapping ? scoped_mapping->Memory(1)
+                                               : buffer->memory(1)),
+          scoped_mapping ? scoped_mapping->Stride(1) : buffer->stride(1));
       break;
 
     case GpuVideoAcceleratorFactories::OutputFormat::NV12_SINGLE_GMB: {
@@ -1094,9 +1194,10 @@
                                VideoFormat(output_format), coded_size.width());
       CopyRowsToNV12Buffer(
           row, rows_to_copy_y, rows_to_copy_uv, bytes_per_row_y,
-          bytes_per_row_uv, video_frame,
-          static_cast<uint8_t*>(buffer->memory(0)), buffer->stride(0),
-          static_cast<uint8_t*>(buffer->memory(1)), buffer->stride(1));
+          bytes_per_row_uv, video_frame, memory_ptr0, stride0,
+          static_cast<uint8_t*>(scoped_mapping ? scoped_mapping->Memory(1)
+                                               : buffer->memory(1)),
+          scoped_mapping ? scoped_mapping->Stride(1) : buffer->stride(1));
       break;
     }
 
@@ -1113,11 +1214,15 @@
                                VideoFormat(output_format), coded_size.width());
       gfx::GpuMemoryBuffer* buffer2 =
           frame_resources->plane_resources[1].gpu_memory_buffer.get();
+      auto* scoped_mapping2 =
+          frame_resources->plane_resources[1].scoped_mapping.get();
+
       CopyRowsToNV12Buffer(
           row, rows_to_copy_y, rows_to_copy_uv, bytes_per_row_y,
-          bytes_per_row_uv, video_frame,
-          static_cast<uint8_t*>(buffer->memory(0)), buffer->stride(0),
-          static_cast<uint8_t*>(buffer2->memory(0)), buffer2->stride(0));
+          bytes_per_row_uv, video_frame, memory_ptr0, stride0,
+          static_cast<uint8_t*>(scoped_mapping2 ? scoped_mapping2->Memory(0)
+                                                : buffer2->memory(0)),
+          scoped_mapping2 ? scoped_mapping2->Stride(0) : buffer2->stride(0));
       break;
     }
 
@@ -1125,9 +1230,8 @@
     case GpuVideoAcceleratorFactories::OutputFormat::XB30: {
       const bool is_argb =
           output_format == GpuVideoAcceleratorFactories::OutputFormat::XR30;
-      CopyRowsToRGB10Buffer(
-          is_argb, row, rows_to_copy, coded_size.width(), video_frame,
-          static_cast<uint8_t*>(buffer->memory(0)), buffer->stride(0));
+      CopyRowsToRGB10Buffer(is_argb, row, rows_to_copy, coded_size.width(),
+                            video_frame, memory_ptr0, stride0);
       break;
     }
 
@@ -1135,9 +1239,8 @@
     case GpuVideoAcceleratorFactories::OutputFormat::BGRA: {
       const bool is_rgba =
           output_format == GpuVideoAcceleratorFactories::OutputFormat::RGBA;
-      CopyRowsToRGBABuffer(
-          is_rgba, row, rows_to_copy, coded_size.width(), video_frame,
-          static_cast<uint8_t*>(buffer->memory(0)), buffer->stride(0));
+      CopyRowsToRGBABuffer(is_rgba, row, rows_to_copy, coded_size.width(),
+                           video_frame, memory_ptr0, stride0);
       break;
     }
 
@@ -1213,13 +1316,20 @@
     PlaneResource& plane_resource = frame_resources->plane_resources[plane];
     gfx::GpuMemoryBuffer* gpu_memory_buffer =
         frame_resources->plane_resources[plane].gpu_memory_buffer.get();
-    // This method is only expected to be called when there is a GMB and copy to
-    // it didn't fail.
-    CHECK(gpu_memory_buffer);
+
+    // This method is only expected to be called when there is a GMB or
+    // MappableSI and copy to it after mapping didn't fail.
+    CHECK((is_mappable_si_enabled_ && plane_resource.shared_image) ||
+          (!is_mappable_si_enabled_ && gpu_memory_buffer));
+
+    auto handle =
+        is_mappable_si_enabled_
+            ? plane_resource.shared_image->CloneGpuMemoryBufferHandle()
+            : gpu_memory_buffer->CloneHandle();
+
     // Log software/hardware backed GpuMemoryBuffer's `output_format_` used to
     // create the shared image.
-    gfx::GpuMemoryBufferType buffer_type = gpu_memory_buffer->GetType();
-    if (buffer_type == gfx::GpuMemoryBufferType::SHARED_MEMORY_BUFFER) {
+    if (handle.type == gfx::GpuMemoryBufferType::SHARED_MEMORY_BUFFER) {
       UMA_HISTOGRAM_ENUMERATION("Media.GPU.OutputFormatSoftwareGmb",
                                 output_format_);
     } else {
@@ -1230,56 +1340,43 @@
 #if BUILDFLAG(IS_MAC)
     // Shared image uses iosurface as native resource which is compatible to
     // WebGPU always.
-    is_webgpu_compatible = media::IOSurfaceIsWebGPUCompatible(
-        gpu_memory_buffer->CloneHandle().io_surface.get());
+    is_webgpu_compatible =
+        media::IOSurfaceIsWebGPUCompatible(handle.io_surface.get());
 #endif
 
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
     is_webgpu_compatible =
-        gpu_memory_buffer->CloneHandle()
-            .native_pixmap_handle.supports_zero_copy_webgpu_import;
+        handle.native_pixmap_handle.supports_zero_copy_webgpu_import;
 #endif
 
     // Bind the texture and create or rebind the image. This image may be read
     // via the raster interface for import into canvas and/or 2-copy import into
     // WebGL as well as potentially being read via the GLES interface for 1-copy
     // import into WebGL.
-    if (!plane_resource.shared_image) {
-      uint32_t usage = gpu::SHARED_IMAGE_USAGE_GLES2_READ |
-                       gpu::SHARED_IMAGE_USAGE_RASTER_READ |
-                       gpu::SHARED_IMAGE_USAGE_DISPLAY_READ |
-                       gpu::SHARED_IMAGE_USAGE_SCANOUT;
-
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC)
-      // TODO(crbug.com/40194712): Always add the flag once the
-      // OzoneImageBacking is by default turned on.
-      if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-              switches::kEnableUnsafeWebGPU)) {
-        // This SharedImage may be used for zero-copy import into WebGPU.
-        usage |= gpu::SHARED_IMAGE_USAGE_WEBGPU_READ;
-      }
-#endif
-
+    // Note that when MappableSI is enabled via |is_mappable_si_enabled_|, we
+    // don't need to create a shared image here as we have already created a
+    // MappableSI instead of creating GpuMemoryBuffer in
+    // ::GetOrCreateFrameResource().
+    if (!is_mappable_si_enabled_ && !plane_resource.shared_image) {
       constexpr char kDebugLabel[] = "MediaGmbVideoFramePool";
-      scoped_refptr<gpu::ClientSharedImage> client_shared_image;
       if (IsMultiPlaneFormatForSoftwareVideoEnabled()) {
         viz::SharedImageFormat si_format =
             OutputFormatToSharedImageFormat(output_format_, plane);
-        if (gpu_memory_buffer->GetType() != gfx::SHARED_MEMORY_BUFFER) {
+        if (handle.type != gfx::GpuMemoryBufferType::SHARED_MEMORY_BUFFER) {
           if (SetPrefersExternalSampler(si_format)) {
             plane_resource.needs_external_sampler = true;
           }
         }
         plane_resource.shared_image =
             sii->CreateSharedImage({si_format, gpu_memory_buffer->GetSize(),
-                                    color_space, usage, kDebugLabel},
-                                   gpu_memory_buffer->CloneHandle());
+                                    color_space, si_usage_, kDebugLabel},
+                                   std::move(handle));
       } else {
         plane_resource.shared_image = sii->CreateSharedImage(
             gpu_memory_buffer, gpu_factories_->GpuMemoryBufferManager(),
             gfx::BufferPlane::DEFAULT,
-            {color_space, kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, usage,
-             kDebugLabel});
+            {color_space, kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
+             si_usage_, kDebugLabel});
       }
       CHECK(plane_resource.shared_image);
     } else {
@@ -1329,7 +1426,7 @@
     frame->set_shared_image_format_type(
         SharedImageFormatType::kSharedImageFormat);
     PlaneResource& resource = frame_resources->plane_resources[0];
-    if (resource.needs_external_sampler) {
+    if (resource.shared_image->format().PrefersExternalSampler()) {
       frame->set_shared_image_format_type(
           SharedImageFormatType::kSharedImageFormatExternalSampler);
     }
@@ -1414,12 +1511,17 @@
   tick_clock_ = tick_clock;
 }
 
+bool GpuMemoryBufferVideoFramePool::PoolImpl::IsMappableSIEnabled() const {
+  return is_mappable_si_enabled_;
+}
+
 // Tries to find the resources in the pool or create them.
 // Incompatible resources will be dropped.
 GpuMemoryBufferVideoFramePool::PoolImpl::FrameResources*
 GpuMemoryBufferVideoFramePool::PoolImpl::GetOrCreateFrameResources(
     const gfx::Size& size,
-    gfx::BufferUsage usage) {
+    gfx::BufferUsage usage,
+    const gfx::ColorSpace& color_space) {
   DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
 
   auto it = resources_pool_.begin();
@@ -1450,12 +1552,29 @@
         VideoFrame::Rows(i, VideoFormat(output_format_), size.height());
     plane_resource.size = gfx::Size(width, height);
 
-    const gfx::BufferFormat buffer_format =
-        GpuMemoryBufferFormat(output_format_, i);
-    plane_resource.gpu_memory_buffer = gpu_factories_->CreateGpuMemoryBuffer(
-        plane_resource.size, buffer_format, usage);
-    if (plane_resource.gpu_memory_buffer) {
-      plane_resource.buffer_id = ++buffer_id_;
+    if (is_mappable_si_enabled_) {
+      if (auto* sii = gpu_factories_->SharedImageInterface()) {
+        viz::SharedImageFormat si_format =
+            OutputFormatToSharedImageFormat(output_format_, i);
+
+        // This needs to be called before creating the mappable shared image
+        // here. |si_format| could be modified internally later based on the
+        // type of buffer (shared memory or native gpu buffer) backing the
+        // shared image. https://issues.chromium.org/339546249.
+        SetPrefersExternalSampler(si_format);
+
+        // Create a Mappable shared image.
+        plane_resource.shared_image = sii->CreateSharedImage(
+            {si_format, plane_resource.size, color_space, si_usage_,
+             "MediaGmbVideoFramePoolMappableSI"},
+            gpu::kNullSurfaceHandle, usage);
+      } else {
+        return nullptr;
+      }
+    } else {
+      auto buffer_format = GpuMemoryBufferFormat(output_format_, i);
+      plane_resource.gpu_memory_buffer = gpu_factories_->CreateGpuMemoryBuffer(
+          plane_resource.size, buffer_format, usage);
     }
   }
   return frame_resources;
@@ -1570,4 +1689,8 @@
   pool_impl_->SetTickClockForTesting(tick_clock);
 }
 
+bool GpuMemoryBufferVideoFramePool::IsMappableSIEnabledForTesting() const {
+  return pool_impl_->IsMappableSIEnabled();
+}
+
 }  // namespace media
diff --git a/media/video/gpu_memory_buffer_video_frame_pool.h b/media/video/gpu_memory_buffer_video_frame_pool.h
index 96896ace..9427066 100644
--- a/media/video/gpu_memory_buffer_video_frame_pool.h
+++ b/media/video/gpu_memory_buffer_video_frame_pool.h
@@ -68,6 +68,10 @@
   // of a multiplanar GpuMemoryBuffer. Exposed externally for testing.
   static bool MultiPlaneVideoSharedImagesEnabled();
 
+  // This is currently used to suppress some tests when MappableSI is
+  // enabled.
+  bool IsMappableSIEnabledForTesting() const;
+
  private:
   class PoolImpl;
   scoped_refptr<PoolImpl> pool_impl_;
diff --git a/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc b/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc
index 04ce9164..0886101 100644
--- a/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc
+++ b/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc
@@ -313,6 +313,9 @@
 }
 
 TEST_F(GpuMemoryBufferVideoFramePoolTest, CreateOneHardwareFrameWithOddSize) {
+  if (gpu_memory_buffer_pool_->IsMappableSIEnabledForTesting()) {
+    return;
+  }
   scoped_refptr<VideoFrame> software_frame =
       CreateTestYUVVideoFrameWithOddSize(9);
   scoped_refptr<VideoFrame> frame;
@@ -407,6 +410,9 @@
 
 TEST_F(GpuMemoryBufferVideoFramePoolTest,
        CreateOne10BppHardwareFrameWithOddSize) {
+  if (gpu_memory_buffer_pool_->IsMappableSIEnabledForTesting()) {
+    return;
+  }
   scoped_refptr<VideoFrame> software_frame =
       CreateTestYUVVideoFrameWithOddSize(17, 10);
   scoped_refptr<VideoFrame> frame;
@@ -550,6 +556,9 @@
 
 TEST_F(GpuMemoryBufferVideoFramePoolTest,
        CreateOneHardwareNV12FrameWithOddSize) {
+  if (gpu_memory_buffer_pool_->IsMappableSIEnabledForTesting()) {
+    return;
+  }
   scoped_refptr<VideoFrame> software_frame =
       CreateTestYUVVideoFrameWithOddSize(13);
   scoped_refptr<VideoFrame> frame;
@@ -593,6 +602,9 @@
 
 TEST_F(GpuMemoryBufferVideoFramePoolTest,
        CreateOneHardwareNV12Frame2WithOddSize) {
+  if (gpu_memory_buffer_pool_->IsMappableSIEnabledForTesting()) {
+    return;
+  }
   scoped_refptr<VideoFrame> software_frame =
       CreateTestYUVVideoFrameWithOddSize(5);
   scoped_refptr<VideoFrame> frame;
@@ -662,6 +674,9 @@
 
 TEST_F(GpuMemoryBufferVideoFramePoolTest,
        CreateOneHardwareFrameForNV12InputWithOddSize) {
+  if (gpu_memory_buffer_pool_->IsMappableSIEnabledForTesting()) {
+    return;
+  }
   scoped_refptr<VideoFrame> software_frame =
       CreateTestNV12VideoFrameWithOddSize(135);
   scoped_refptr<VideoFrame> frame;
@@ -717,6 +732,9 @@
 }
 
 TEST_F(GpuMemoryBufferVideoFramePoolTest, CreateOneHardwareXR30Frame) {
+  if (gpu_memory_buffer_pool_->IsMappableSIEnabledForTesting()) {
+    return;
+  }
   scoped_refptr<VideoFrame> software_frame = CreateTestYUVVideoFrame(10, 10);
   scoped_refptr<VideoFrame> frame;
   mock_gpu_factories_->SetVideoFrameOutputFormat(
@@ -740,6 +758,9 @@
 }
 
 TEST_F(GpuMemoryBufferVideoFramePoolTest, CreateOneHardwareP010Frame) {
+  if (gpu_memory_buffer_pool_->IsMappableSIEnabledForTesting()) {
+    return;
+  }
   scoped_refptr<VideoFrame> software_frame = CreateTestYUVVideoFrame(10, 10);
   scoped_refptr<VideoFrame> frame;
   mock_gpu_factories_->SetVideoFrameOutputFormat(
@@ -772,6 +793,9 @@
 
 TEST_F(GpuMemoryBufferVideoFramePoolTest,
        CreateOneHardwareP010FrameWithOddSize) {
+  if (gpu_memory_buffer_pool_->IsMappableSIEnabledForTesting()) {
+    return;
+  }
   scoped_refptr<VideoFrame> software_frame =
       CreateTestYUVVideoFrameWithOddSize(7, 10);
   scoped_refptr<VideoFrame> frame;
@@ -826,6 +850,9 @@
 }
 
 TEST_F(GpuMemoryBufferVideoFramePoolTest, CreateOneHardwareXR30FrameBT709) {
+  if (gpu_memory_buffer_pool_->IsMappableSIEnabledForTesting()) {
+    return;
+  }
   scoped_refptr<VideoFrame> software_frame = CreateTestYUVVideoFrame(10, 10);
   software_frame->set_color_space(gfx::ColorSpace::CreateREC709());
   scoped_refptr<VideoFrame> frame;
@@ -850,6 +877,9 @@
 }
 
 TEST_F(GpuMemoryBufferVideoFramePoolTest, CreateOneHardwareXR30FrameBT601) {
+  if (gpu_memory_buffer_pool_->IsMappableSIEnabledForTesting()) {
+    return;
+  }
   scoped_refptr<VideoFrame> software_frame = CreateTestYUVVideoFrame(10, 10);
   software_frame->set_color_space(gfx::ColorSpace::CreateREC601());
   scoped_refptr<VideoFrame> frame;
@@ -874,6 +904,9 @@
 }
 
 TEST_F(GpuMemoryBufferVideoFramePoolTest, CreateOneHardwareXB30Frame) {
+  if (gpu_memory_buffer_pool_->IsMappableSIEnabledForTesting()) {
+    return;
+  }
   scoped_refptr<VideoFrame> software_frame = CreateTestYUVVideoFrame(10, 10);
   scoped_refptr<VideoFrame> frame;
   mock_gpu_factories_->SetVideoFrameOutputFormat(
@@ -934,6 +967,9 @@
 // This test checks that in that case we don't crash and don't create the
 // textures.
 TEST_F(GpuMemoryBufferVideoFramePoolTest, CreateGpuMemoryBufferFail) {
+  if (gpu_memory_buffer_pool_->IsMappableSIEnabledForTesting()) {
+    return;
+  }
   scoped_refptr<VideoFrame> software_frame = CreateTestYUVVideoFrame(10);
   scoped_refptr<VideoFrame> frame;
   mock_gpu_factories_->SetFailToAllocateGpuMemoryBufferForTesting(true);
@@ -949,6 +985,9 @@
 
 TEST_F(GpuMemoryBufferVideoFramePoolTest,
        CreateGpuMemoryBufferFailAfterShutdown) {
+  if (gpu_memory_buffer_pool_->IsMappableSIEnabledForTesting()) {
+    return;
+  }
   scoped_refptr<VideoFrame> software_frame = CreateTestYUVVideoFrame(10);
   scoped_refptr<VideoFrame> frame;
   mock_gpu_factories_->SetFailToMapGpuMemoryBufferForTesting(true);
diff --git a/net/base/features.cc b/net/base/features.cc
index 3d473c6a..e048190 100644
--- a/net/base/features.cc
+++ b/net/base/features.cc
@@ -117,26 +117,10 @@
              "SplitCodeCacheByNetworkIsolationKey",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kSplitHostCacheByNetworkIsolationKey,
-             "SplitHostCacheByNetworkIsolationKey",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 BASE_FEATURE(kPartitionConnectionsByNetworkIsolationKey,
              "PartitionConnectionsByNetworkIsolationKey",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kPartitionHttpServerPropertiesByNetworkIsolationKey,
-             "PartitionHttpServerPropertiesByNetworkIsolationKey",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
-BASE_FEATURE(kPartitionSSLSessionsByNetworkIsolationKey,
-             "PartitionSSLSessionsByNetworkIsolationKey",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
-BASE_FEATURE(kPartitionNelAndReportingByNetworkIsolationKey,
-             "PartitionNelAndReportingByNetworkIsolationKey",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 BASE_FEATURE(kEnableCrossSiteFlagNetworkIsolationKey,
              "EnableCrossSiteFlagNetworkIsolationKey",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/net/base/features.h b/net/base/features.h
index 268022f..b9aa7d291 100644
--- a/net/base/features.h
+++ b/net/base/features.h
@@ -133,37 +133,10 @@
 // `net::HttpCache::IsSplitCacheEnabled()`.
 NET_EXPORT BASE_DECLARE_FEATURE(kSplitCodeCacheByNetworkIsolationKey);
 
-// Splits host cache entries by the DNS request's NetworkAnonymizationKey if one
-// is available. Also prevents merging live DNS lookups when there is a NAK
-// mismatch.
-NET_EXPORT BASE_DECLARE_FEATURE(kSplitHostCacheByNetworkIsolationKey);
-
-// Partitions connections based on the NetworkAnonymizationKey associated with a
-// request.
-NET_EXPORT BASE_DECLARE_FEATURE(kPartitionConnectionsByNetworkIsolationKey);
-
-// Partitions HttpServerProperties based on the NetworkAnonymizationKey
-// associated with a request.
-NET_EXPORT BASE_DECLARE_FEATURE(
-    kPartitionHttpServerPropertiesByNetworkIsolationKey);
-
-// Partitions TLS sessions and QUIC server configs based on the
+// Partitions connections and other network states based on the
 // NetworkAnonymizationKey associated with a request.
-//
-// This feature requires kPartitionConnectionsByNetworkIsolationKey to be
-// enabled to work.
-NET_EXPORT BASE_DECLARE_FEATURE(kPartitionSSLSessionsByNetworkIsolationKey);
-
-// Partitions Network Error Logging and Reporting API data by
-// NetworkAnonymizationKey. Also partitions all reports generated by other
-// consumers of the reporting API. Applies the NetworkAnonymizationKey to
-// reports uploads as well.
-//
-// When disabled, the main entry points of the reporting and NEL services ignore
-// NetworkAnonymizationKey parameters, and they're cleared while loading from
-// the cache, but internal objects can be created with them (e.g., endpoints),
-// for testing.
-NET_EXPORT BASE_DECLARE_FEATURE(kPartitionNelAndReportingByNetworkIsolationKey);
+// See https://github.com/MattMenke2/Explainer---Partition-Network-State.
+NET_EXPORT BASE_DECLARE_FEATURE(kPartitionConnectionsByNetworkIsolationKey);
 
 // Creates a <double key + is_cross_site> NetworkIsolationKey which is used
 // to partition the HTTP cache. This key will have the following properties:
diff --git a/net/base/network_anonymization_key.cc b/net/base/network_anonymization_key.cc
index e2627cf..93663c8 100644
--- a/net/base/network_anonymization_key.cc
+++ b/net/base/network_anonymization_key.cc
@@ -192,15 +192,7 @@
   g_partition_by_default_locked.store(true, std::memory_order_relaxed);
   return g_partition_by_default ||
          base::FeatureList::IsEnabled(
-             features::kSplitHostCacheByNetworkIsolationKey) ||
-         base::FeatureList::IsEnabled(
-             features::kPartitionConnectionsByNetworkIsolationKey) ||
-         base::FeatureList::IsEnabled(
-             features::kPartitionHttpServerPropertiesByNetworkIsolationKey) ||
-         base::FeatureList::IsEnabled(
-             features::kPartitionSSLSessionsByNetworkIsolationKey) ||
-         base::FeatureList::IsEnabled(
-             features::kPartitionNelAndReportingByNetworkIsolationKey);
+             features::kPartitionConnectionsByNetworkIsolationKey);
 }
 
 // static
@@ -208,15 +200,7 @@
   DCHECK(!g_partition_by_default_locked.load(std::memory_order_relaxed));
   // Only set the global if none of the relevant features are overridden.
   if (!base::FeatureList::GetInstance()->IsFeatureOverridden(
-          "SplitHostCacheByNetworkIsolationKey") &&
-      !base::FeatureList::GetInstance()->IsFeatureOverridden(
-          "PartitionConnectionsByNetworkIsolationKey") &&
-      !base::FeatureList::GetInstance()->IsFeatureOverridden(
-          "PartitionHttpServerPropertiesByNetworkIsolationKey") &&
-      !base::FeatureList::GetInstance()->IsFeatureOverridden(
-          "PartitionSSLSessionsByNetworkIsolationKey") &&
-      !base::FeatureList::GetInstance()->IsFeatureOverridden(
-          "PartitionNelAndReportingByNetworkIsolationKey")) {
+          "PartitionConnectionsByNetworkIsolationKey")) {
     g_partition_by_default = true;
   }
 }
diff --git a/net/base/network_anonymization_key.h b/net/base/network_anonymization_key.h
index d3b024f..a79a42e 100644
--- a/net/base/network_anonymization_key.h
+++ b/net/base/network_anonymization_key.h
@@ -170,15 +170,8 @@
       NetworkAnonymizationKey* out_network_anonymization_key);
 
   // Determine whether network state partitioning is enabled. This is true if
-  // any of the features
-  //
-  // * `SplitHostCacheByNetworkIsolationKey`
-  // * `PartitionConnectionsByNetworkIsolationKey`
-  // * `PartitionHttpServerPropertiesByNetworkIsolationKey`
-  // * `PartitionSSLSessionsByNetworkIsolationKey`
-  // * `PartitionNelAndReportingByNetworkIsolationKey`
-  //
-  // is enabled, or if `PartitionByDefault()` has been called.
+  // the `PartitionConnectionsByNetworkIsolationKey` feature is enabled, or if
+  // `PartitionByDefault()` has been called.
   static bool IsPartitioningEnabled();
 
   // Default partitioning to enabled, regardless of feature settings. This must
diff --git a/net/dns/context_host_resolver_unittest.cc b/net/dns/context_host_resolver_unittest.cc
index 61734c1..a01648a 100644
--- a/net/dns/context_host_resolver_unittest.cc
+++ b/net/dns/context_host_resolver_unittest.cc
@@ -706,7 +706,7 @@
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kSplitHostCacheByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   MockDnsClientRuleList rules;
   rules.emplace_back("example.com", dns_protocol::kTypeA, false /* secure */,
diff --git a/net/dns/host_resolver_manager_unittest.cc b/net/dns/host_resolver_manager_unittest.cc
index 38abfc28..4377a1a 100644
--- a/net/dns/host_resolver_manager_unittest.cc
+++ b/net/dns/host_resolver_manager_unittest.cc
@@ -3893,10 +3893,10 @@
     base::test::ScopedFeatureList feature_list;
     if (split_cache_by_network_anonymization_key) {
       feature_list.InitAndEnableFeature(
-          features::kSplitHostCacheByNetworkIsolationKey);
+          features::kPartitionConnectionsByNetworkIsolationKey);
     } else {
       feature_list.InitAndDisableFeature(
-          features::kSplitHostCacheByNetworkIsolationKey);
+          features::kPartitionConnectionsByNetworkIsolationKey);
     }
     proc_->AddRuleForAllFamilies("just.testing", kFirstDnsResult);
     proc_->SignalMultiple(1u);
@@ -4029,10 +4029,10 @@
     base::test::ScopedFeatureList feature_list;
     if (split_cache_by_network_anonymization_key) {
       feature_list.InitAndEnableFeature(
-          features::kSplitHostCacheByNetworkIsolationKey);
+          features::kPartitionConnectionsByNetworkIsolationKey);
     } else {
       feature_list.InitAndDisableFeature(
-          features::kSplitHostCacheByNetworkIsolationKey);
+          features::kPartitionConnectionsByNetworkIsolationKey);
     }
 
     // A request that uses kNetworkAnonymizationKey1 will return cache entry 1
@@ -4097,10 +4097,10 @@
     base::test::ScopedFeatureList feature_list;
     if (split_cache_by_network_anonymization_key) {
       feature_list.InitAndEnableFeature(
-          features::kSplitHostCacheByNetworkIsolationKey);
+          features::kPartitionConnectionsByNetworkIsolationKey);
     } else {
       feature_list.InitAndDisableFeature(
-          features::kSplitHostCacheByNetworkIsolationKey);
+          features::kPartitionConnectionsByNetworkIsolationKey);
     }
     proc_->AddRuleForAllFamilies("just.testing", kDnsResult);
 
@@ -7356,7 +7356,8 @@
 TEST_F(HostResolverManagerDnsTest, NotFoundTtl) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
-      /*enabled_features=*/{features::kSplitHostCacheByNetworkIsolationKey,
+      /*enabled_features=*/{features::
+                                kPartitionConnectionsByNetworkIsolationKey,
                             features::kUseHostResolverCache},
       /*disabled_features=*/{});
 
@@ -13631,7 +13632,8 @@
 TEST_F(HostResolverManagerDnsTest, SortFailure) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
-      /*enabled_features=*/{features::kSplitHostCacheByNetworkIsolationKey,
+      /*enabled_features=*/{features::
+                                kPartitionConnectionsByNetworkIsolationKey,
                             features::kUseHostResolverCache},
       /*disabled_features=*/{});
 
@@ -13694,7 +13696,8 @@
 TEST_F(HostResolverManagerDnsTest, PartialSortFailure) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
-      /*enabled_features=*/{features::kSplitHostCacheByNetworkIsolationKey,
+      /*enabled_features=*/{features::
+                                kPartitionConnectionsByNetworkIsolationKey,
                             features::kUseHostResolverCache},
       /*disabled_features=*/{});
 
@@ -13821,7 +13824,8 @@
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
       /*enabled_features=*/{features::kUseHostResolverCache,
-                            features::kSplitHostCacheByNetworkIsolationKey},
+                            features::
+                                kPartitionConnectionsByNetworkIsolationKey},
       /*disabled_features=*/{});
 
   ChangeDnsConfig(CreateValidDnsConfig());
@@ -13856,7 +13860,8 @@
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
       /*enabled_features=*/{features::kUseHostResolverCache,
-                            features::kSplitHostCacheByNetworkIsolationKey},
+                            features::
+                                kPartitionConnectionsByNetworkIsolationKey},
       /*disabled_features=*/{});
 
   constexpr std::string_view kHost = "host.test";
@@ -13914,7 +13919,8 @@
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
       /*enabled_features=*/{features::kUseHostResolverCache,
-                            features::kSplitHostCacheByNetworkIsolationKey},
+                            features::
+                                kPartitionConnectionsByNetworkIsolationKey},
       /*disabled_features=*/{});
 
   constexpr std::string_view kHost = "host.test";
@@ -13978,7 +13984,8 @@
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
       /*enabled_features=*/{features::kUseHostResolverCache,
-                            features::kSplitHostCacheByNetworkIsolationKey},
+                            features::
+                                kPartitionConnectionsByNetworkIsolationKey},
       /*disabled_features=*/{});
 
   constexpr std::string_view kHost = "host.test";
@@ -14033,7 +14040,8 @@
 TEST_F(HostResolverManagerDnsTest, NetworkErrorsNotSavedInHostCache) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
-      /*enabled_features=*/{features::kSplitHostCacheByNetworkIsolationKey},
+      /*enabled_features=*/{features::
+                                kPartitionConnectionsByNetworkIsolationKey},
       /*disabled_features=*/{features::kUseHostResolverCache});
 
   constexpr std::string_view kHost = "host.test";
@@ -14076,7 +14084,8 @@
 TEST_F(HostResolverManagerDnsTest, PartialNetworkErrorsNotSavedInHostCache) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
-      /*enabled_features=*/{features::kSplitHostCacheByNetworkIsolationKey},
+      /*enabled_features=*/{features::
+                                kPartitionConnectionsByNetworkIsolationKey},
       /*disabled_features=*/{features::kUseHostResolverCache});
 
   constexpr std::string_view kHost = "host.test";
@@ -14120,7 +14129,8 @@
 TEST_F(HostResolverManagerDnsTest, NetworkErrorsNotSavedInHostResolverCache) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
-      /*enabled_features=*/{features::kSplitHostCacheByNetworkIsolationKey,
+      /*enabled_features=*/{features::
+                                kPartitionConnectionsByNetworkIsolationKey,
                             features::kUseHostResolverCache},
       /*disabled_features=*/{});
 
@@ -14163,7 +14173,8 @@
        PartialNetworkErrorsNotSavedInHostResolverCache) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
-      /*enabled_features=*/{features::kSplitHostCacheByNetworkIsolationKey,
+      /*enabled_features=*/{features::
+                                kPartitionConnectionsByNetworkIsolationKey,
                             features::kUseHostResolverCache},
       /*disabled_features=*/{});
 
@@ -14223,7 +14234,8 @@
 TEST_F(HostResolverManagerDnsTest, MalformedResponsesNotSavedInHostCache) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
-      /*enabled_features=*/{features::kSplitHostCacheByNetworkIsolationKey},
+      /*enabled_features=*/{features::
+                                kPartitionConnectionsByNetworkIsolationKey},
       /*disabled_features=*/{features::kUseHostResolverCache});
 
   constexpr std::string_view kHost = "host.test";
@@ -14264,7 +14276,8 @@
        PartialMalformedResponsesNotSavedInHostCache) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
-      /*enabled_features=*/{features::kSplitHostCacheByNetworkIsolationKey},
+      /*enabled_features=*/{features::
+                                kPartitionConnectionsByNetworkIsolationKey},
       /*disabled_features=*/{features::kUseHostResolverCache});
 
   constexpr std::string_view kHost = "host.test";
@@ -14308,7 +14321,8 @@
        MalformedResponsesNotSavedInHostResolverCache) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
-      /*enabled_features=*/{features::kSplitHostCacheByNetworkIsolationKey,
+      /*enabled_features=*/{features::
+                                kPartitionConnectionsByNetworkIsolationKey,
                             features::kUseHostResolverCache},
       /*disabled_features=*/{});
 
@@ -14348,7 +14362,8 @@
        PartialMalformedResponsesNotSavedInHostResolverCache) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
-      /*enabled_features=*/{features::kSplitHostCacheByNetworkIsolationKey,
+      /*enabled_features=*/{features::
+                                kPartitionConnectionsByNetworkIsolationKey,
                             features::kUseHostResolverCache},
       /*disabled_features=*/{});
 
@@ -14407,7 +14422,8 @@
 TEST_F(HostResolverManagerDnsTest, HttpToHttpsUpgradeSavedInHostCache) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
-      /*enabled_features=*/{features::kSplitHostCacheByNetworkIsolationKey},
+      /*enabled_features=*/{features::
+                                kPartitionConnectionsByNetworkIsolationKey},
       /*disabled_features=*/{features::kUseHostResolverCache});
 
   constexpr std::string_view kHost = "host.test";
@@ -14466,7 +14482,8 @@
        HttpToHttpsUpgradeAfterAddressesSavedInHostResolverCache) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
-      /*enabled_features=*/{features::kSplitHostCacheByNetworkIsolationKey,
+      /*enabled_features=*/{features::
+                                kPartitionConnectionsByNetworkIsolationKey,
                             features::kUseHostResolverCache},
       /*disabled_features=*/{});
 
diff --git a/net/extras/sqlite/sqlite_persistent_reporting_and_nel_store_unittest.cc b/net/extras/sqlite/sqlite_persistent_reporting_and_nel_store_unittest.cc
index 9567da9..0018ac6 100644
--- a/net/extras/sqlite/sqlite_persistent_reporting_and_nel_store_unittest.cc
+++ b/net/extras/sqlite/sqlite_persistent_reporting_and_nel_store_unittest.cc
@@ -90,7 +90,7 @@
  public:
   SQLitePersistentReportingAndNelStoreTest() {
     feature_list_.InitAndEnableFeature(
-        features::kPartitionNelAndReportingByNetworkIsolationKey);
+        features::kPartitionConnectionsByNetworkIsolationKey);
   }
 
   void CreateStore() {
@@ -640,12 +640,12 @@
   event.Signal();
   RunUntilIdle();
 
-  // Close the database, disable kPartitionNelAndReportingByNetworkIsolationKey,
+  // Close the database, disable kPartitionConnectionsByNetworkIsolationKey,
   // and re-open it.
   DestroyStore();
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndDisableFeature(
-      features::kPartitionNelAndReportingByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
   CreateStore();
   std::vector<NetworkErrorLoggingService::NelPolicy> policies;
   LoadNelPolicies(&policies);
@@ -653,7 +653,7 @@
   // No entries should be restored.
   ASSERT_EQ(0u, policies.size());
 
-  // Now reload the store with kPartitionNelAndReportingByNetworkIsolationKey
+  // Now reload the store with kPartitionConnectionsByNetworkIsolationKey
   // enabled again.
   DestroyStore();
   feature_list.Reset();
@@ -1586,12 +1586,12 @@
   event.Signal();
   RunUntilIdle();
 
-  // Close the database, disable kPartitionNelAndReportingByNetworkIsolationKey,
+  // Close the database, disable kPartitionConnectionsByNetworkIsolationKey,
   // and re-open it.
   DestroyStore();
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndDisableFeature(
-      features::kPartitionNelAndReportingByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
   CreateStore();
 
   std::vector<ReportingEndpoint> endpoints;
@@ -1600,7 +1600,7 @@
   // No entries should be restored.
   ASSERT_EQ(0u, endpoints.size());
 
-  // Now reload the store with kPartitionNelAndReportingByNetworkIsolationKey
+  // Now reload the store with kPartitionConnectionsByNetworkIsolationKey
   // enabled again.
   DestroyStore();
   feature_list.Reset();
@@ -1645,12 +1645,12 @@
   event.Signal();
   RunUntilIdle();
 
-  // Close the database, disable kPartitionNelAndReportingByNetworkIsolationKey,
+  // Close the database, disable kPartitionConnectionsByNetworkIsolationKey,
   // and re-open it.
   DestroyStore();
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndDisableFeature(
-      features::kPartitionNelAndReportingByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
   CreateStore();
 
   std::vector<ReportingEndpoint> endpoints;
@@ -1659,7 +1659,7 @@
   LoadReportingClients(&endpoints, &groups);
   EXPECT_TRUE(groups.empty());
 
-  // Now reload the store with kPartitionNelAndReportingByNetworkIsolationKey
+  // Now reload the store with kPartitionConnectionsByNetworkIsolationKey
   // enabled again.
   DestroyStore();
   feature_list.Reset();
diff --git a/net/http/http_auth_handler_negotiate_unittest.cc b/net/http/http_auth_handler_negotiate_unittest.cc
index db77165a..a1e4be0f 100644
--- a/net/http/http_auth_handler_negotiate_unittest.cc
+++ b/net/http/http_auth_handler_negotiate_unittest.cc
@@ -59,7 +59,7 @@
  public:
   void SetUp() override {
     scoped_feature_list_.InitAndEnableFeature(
-        features::kSplitHostCacheByNetworkIsolationKey);
+        features::kPartitionConnectionsByNetworkIsolationKey);
     network_anoymization_key_ = NetworkAnonymizationKey::CreateTransient();
 #if BUILDFLAG(IS_WIN)
     auto auth_library =
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 21ef335..59737766f 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -16252,14 +16252,8 @@
 TEST_P(HttpNetworkTransactionTest,
        HonorAlternativeServiceHeaderWithNetworkAnonymizationKey) {
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
-       // Need to partition connections by NetworkAnonymizationKey for
-       // SpdySessionKeys to include NetworkAnonymizationKeys.
-       features::kPartitionConnectionsByNetworkIsolationKey},
-      // disabled_features
-      {});
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   session_deps_.http_server_properties =
@@ -23433,7 +23427,7 @@
  protected:
   HttpNetworkTransactionReportingTest() {
     std::vector<base::test::FeatureRef> required_features = {
-        features::kPartitionNelAndReportingByNetworkIsolationKey};
+        features::kPartitionConnectionsByNetworkIsolationKey};
     if (UseDocumentReporting()) {
       required_features.push_back(features::kDocumentReporting);
     }
@@ -25956,9 +25950,9 @@
   EXPECT_EQ(200, trans->GetResponseInfo()->headers->response_code());
 }
 
-// Test for kPartitionConnectionsByNetworkIsolationKey. Runs 3 requests in
-// sequence with two different NetworkAnonymizationKeys, the first and last have
-// the same key, the second a different one. Checks that the requests are
+// Test for partitioning connections by NetworkAnonymizationKey. Runs 3 requests
+// in sequence with two different NetworkAnonymizationKeys, the first and last
+// have the same key, the second a different one. Checks that the requests are
 // partitioned across sockets as expected.
 TEST_P(HttpNetworkTransactionTest, NetworkIsolation) {
   const SchemefulSite kSite1(GURL("http://origin1/"));
@@ -26483,10 +26477,8 @@
 // session cache is isolated.
 TEST_P(HttpNetworkTransactionTest, NetworkIsolationSSL) {
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      {features::kPartitionConnectionsByNetworkIsolationKey,
-       features::kPartitionSSLSessionsByNetworkIsolationKey},
-      {});
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   const SchemefulSite kSite1(GURL("http://origin1/"));
   const SchemefulSite kSite2(GURL("http://origin2/"));
@@ -26609,10 +26601,8 @@
 // session cache is isolated, for both origins and proxies.
 TEST_P(HttpNetworkTransactionTest, NetworkIsolationSSLProxy) {
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      {features::kPartitionConnectionsByNetworkIsolationKey,
-       features::kPartitionSSLSessionsByNetworkIsolationKey},
-      {});
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   session_deps_.proxy_resolution_service =
       ConfiguredProxyResolutionService::CreateFixedForTest(
diff --git a/net/http/http_server_properties_manager_unittest.cc b/net/http/http_server_properties_manager_unittest.cc
index c637a84..5a72e67 100644
--- a/net/http/http_server_properties_manager_unittest.cc
+++ b/net/http/http_server_properties_manager_unittest.cc
@@ -60,11 +60,11 @@
   switch (mode) {
     case NetworkAnonymizationKeyMode::kDisabled:
       feature_list->InitAndDisableFeature(
-          features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+          features::kPartitionConnectionsByNetworkIsolationKey);
       break;
     case NetworkAnonymizationKeyMode::kEnabled:
       feature_list->InitAndEnableFeature(
-          features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+          features::kPartitionConnectionsByNetworkIsolationKey);
       break;
   }
   return feature_list;
@@ -2109,8 +2109,7 @@
       std::unique_ptr<base::test::ScopedFeatureList> feature_list =
           SetNetworkAnonymizationKeyMode(save_network_anonymization_key_mode);
 
-      // This parameter is normally calculated by HttpServerProperties based on
-      // the kPartitionHttpServerPropertiesByNetworkIsolationKey feature, but
+      // This parameter is normally calculated by HttpServerProperties, but
       // this test doesn't use that class.
       bool use_network_anonymization_key =
           save_network_anonymization_key_mode !=
@@ -2203,7 +2202,7 @@
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   // Create and initialize an HttpServerProperties with no state.
   std::unique_ptr<MockPrefDelegate> pref_delegate =
@@ -2281,7 +2280,7 @@
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   // Create three alt service vectors of different lengths.
   base::Time expiration = base::Time::Now() + base::Days(1);
@@ -2645,7 +2644,7 @@
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   // Create and initialize an HttpServerProperties, must be done after
   // setting the feature.
@@ -2870,7 +2869,7 @@
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   // Create and initialize an HttpServerProperties with no state.
   std::unique_ptr<MockPrefDelegate> pref_delegate =
@@ -2973,7 +2972,7 @@
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   // Create and initialize an HttpServerProperties, must be done after
   // setting the feature.
@@ -3073,7 +3072,7 @@
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   // Create and initialize an HttpServerProperties with no state.
   std::unique_ptr<MockPrefDelegate> pref_delegate =
diff --git a/net/http/http_server_properties_unittest.cc b/net/http/http_server_properties_unittest.cc
index 77f51222..1fe24057 100644
--- a/net/http/http_server_properties_unittest.cc
+++ b/net/http/http_server_properties_unittest.cc
@@ -110,7 +110,7 @@
     std::unique_ptr<base::test::ScopedFeatureList> feature_list =
         std::make_unique<base::test::ScopedFeatureList>();
     feature_list->InitAndDisableFeature(
-        features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+        features::kPartitionConnectionsByNetworkIsolationKey);
     return feature_list;
   }
 
@@ -279,7 +279,7 @@
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   HttpServerProperties properties(nullptr /* pref_delegate */,
@@ -854,7 +854,7 @@
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   HttpServerProperties properties(nullptr /* pref_delegate */,
@@ -1432,7 +1432,7 @@
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   HttpServerProperties properties(nullptr /* pref_delegate */,
@@ -1566,7 +1566,7 @@
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   HttpServerProperties properties(nullptr /* pref_delegate */,
@@ -1701,7 +1701,7 @@
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   HttpServerProperties properties(nullptr /* pref_delegate */,
@@ -1837,7 +1837,7 @@
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   HttpServerProperties properties(nullptr /* pref_delegate */,
@@ -1948,7 +1948,7 @@
        CanonicalWithNetworkIsolationKey) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   HttpServerProperties properties(nullptr /* pref_delegate */,
@@ -2137,7 +2137,7 @@
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   HttpServerProperties properties(nullptr /* pref_delegate */,
@@ -2836,7 +2836,7 @@
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   HttpServerProperties properties(nullptr /* pref_delegate */,
@@ -2928,7 +2928,7 @@
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   HttpServerProperties properties(nullptr /* pref_delegate */,
diff --git a/net/http/http_stream_factory_job_controller_unittest.cc b/net/http/http_stream_factory_job_controller_unittest.cc
index f053d24..97edf47 100644
--- a/net/http/http_stream_factory_job_controller_unittest.cc
+++ b/net/http/http_stream_factory_job_controller_unittest.cc
@@ -3612,15 +3612,11 @@
        PreconnectMultipleStreamsToH2ServerWithNetworkIsolationKey) {
   base::test::ScopedFeatureList feature_list;
   // It's not strictly necessary to enable
-  // |kPartitionConnectionsByNetworkIsolationKey|, but the second phase of the
+  // `kPartitionConnectionsByNetworkIsolationKey`, but the second phase of the
   // test would only make 4 connections, reusing the first connection, without
   // it.
-  feature_list.InitWithFeatures(
-      {// enabled_features
-       features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
-       features::kPartitionConnectionsByNetworkIsolationKey},
-      // disabled_features
-      {});
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Need to re-create HttpServerProperties after enabling the field trial,
   // since it caches the field trial value on construction.
   session_deps_.http_server_properties =
@@ -4082,12 +4078,8 @@
 TEST_F(JobControllerLimitMultipleH2Requests,
        MultipleRequestsNetworkIsolationKey) {
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      {// enabled_features
-       features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
-       features::kPartitionConnectionsByNetworkIsolationKey},
-      // disabled_features
-      {});
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Need to re-create HttpServerProperties after enabling the field trial,
   // since it caches the field trial value on construction.
   session_deps_.http_server_properties =
diff --git a/net/http/http_stream_factory_unittest.cc b/net/http/http_stream_factory_unittest.cc
index fc862bbd1..ff41a546 100644
--- a/net/http/http_stream_factory_unittest.cc
+++ b/net/http/http_stream_factory_unittest.cc
@@ -1675,7 +1675,7 @@
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   url::SchemeHostPort scheme_host_port("http", "myproxy.org", 443);
   auto session_deps = std::make_unique<SpdySessionDependencies>(
diff --git a/net/network_error_logging/network_error_logging_service_unittest.cc b/net/network_error_logging/network_error_logging_service_unittest.cc
index 491f9b5b..57ac1e7 100644
--- a/net/network_error_logging/network_error_logging_service_unittest.cc
+++ b/net/network_error_logging/network_error_logging_service_unittest.cc
@@ -44,7 +44,7 @@
 
   NetworkErrorLoggingServiceTest() {
     feature_list_.InitAndEnableFeature(
-        features::kPartitionNelAndReportingByNetworkIsolationKey);
+        features::kPartitionConnectionsByNetworkIsolationKey);
 
     if (GetParam()) {
       store_ = std::make_unique<MockPersistentNelStore>();
@@ -418,7 +418,7 @@
 TEST_P(NetworkErrorLoggingServiceTest, NetworkAnonymizationKeyDisabled) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndDisableFeature(
-      features::kPartitionNelAndReportingByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   // Need to re-create the service, since it caches the feature value on
   // creation.
@@ -1456,7 +1456,7 @@
        SignedExchangeNetworkAnonymizationKeyDisabled) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndDisableFeature(
-      features::kPartitionNelAndReportingByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   // Need to re-create the service, since it caches the feature value on
   // creation.
diff --git a/net/nqe/network_quality_estimator_util_unittest.cc b/net/nqe/network_quality_estimator_util_unittest.cc
index ad13603..cd37551 100644
--- a/net/nqe/network_quality_estimator_util_unittest.cc
+++ b/net/nqe/network_quality_estimator_util_unittest.cc
@@ -143,7 +143,7 @@
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kSplitHostCacheByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   base::test::TaskEnvironment task_environment;
 
diff --git a/net/nqe/throughput_analyzer_unittest.cc b/net/nqe/throughput_analyzer_unittest.cc
index 125a6b90..5abf5d22 100644
--- a/net/nqe/throughput_analyzer_unittest.cc
+++ b/net/nqe/throughput_analyzer_unittest.cc
@@ -197,7 +197,7 @@
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kSplitHostCacheByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   for (bool use_network_isolation_key : {false, true}) {
     const base::TickClock* tick_clock = base::DefaultTickClock::GetInstance();
diff --git a/net/proxy_resolution/pac_file_fetcher_impl_unittest.cc b/net/proxy_resolution/pac_file_fetcher_impl_unittest.cc
index f0099c4f..5bda8bb0 100644
--- a/net/proxy_resolution/pac_file_fetcher_impl_unittest.cc
+++ b/net/proxy_resolution/pac_file_fetcher_impl_unittest.cc
@@ -240,12 +240,8 @@
 // the DNS cache.
 TEST_F(PacFileFetcherImplTest, IsolationInfo) {
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionConnectionsByNetworkIsolationKey,
-       features::kSplitHostCacheByNetworkIsolationKey},
-      // disabled_features
-      {});
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
   const char kHost[] = "foo.test";
 
   ASSERT_TRUE(test_server_.Start());
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index 21d4b4f..64fee2cc 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -2302,12 +2302,8 @@
     return;
   }
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
-       features::kPartitionConnectionsByNetworkIsolationKey},
-      // disabled_features
-      {});
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   http_server_properties_ = std::make_unique<HttpServerProperties>();
@@ -3173,12 +3169,8 @@
       NetworkAnonymizationKey::CreateSameSite(kSite2);
 
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
-       features::kPartitionConnectionsByNetworkIsolationKey},
-      // disabled_features
-      {});
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   http_server_properties_ = std::make_unique<HttpServerProperties>();
@@ -4288,12 +4280,8 @@
       NetworkAnonymizationKey::CreateSameSite(kSite2);
 
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
-       features::kPartitionConnectionsByNetworkIsolationKey},
-      // disabled_features
-      {});
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   http_server_properties_ = std::make_unique<HttpServerProperties>();
@@ -5140,12 +5128,8 @@
       NetworkAnonymizationKey::CreateSameSite(kSite2);
 
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
-       features::kPartitionConnectionsByNetworkIsolationKey},
-      // disabled_features
-      {});
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   http_server_properties_ = std::make_unique<HttpServerProperties>();
@@ -5459,12 +5443,8 @@
 TEST_P(QuicNetworkTransactionTest,
        FailedZeroRttBrokenAlternateProtocolWithNetworkIsolationKey) {
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
-       features::kPartitionConnectionsByNetworkIsolationKey},
-      // disabled_features
-      {});
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   http_server_properties_ = std::make_unique<HttpServerProperties>();
diff --git a/net/quic/quic_session_pool_test.cc b/net/quic/quic_session_pool_test.cc
index b4b7c67..2d8a775 100644
--- a/net/quic/quic_session_pool_test.cc
+++ b/net/quic/quic_session_pool_test.cc
@@ -1033,14 +1033,8 @@
       NetworkAnonymizationKey::CreateSameSite(kSite2);
 
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
-       // Need to partition connections by NetworkAnonymizationKey for
-       // QuicSessionAliasKey to include NetworkAnonymizationKeys.
-       features::kPartitionConnectionsByNetworkIsolationKey},
-      // disabled_features
-      {});
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   http_server_properties_ = std::make_unique<HttpServerProperties>();
@@ -1188,14 +1182,8 @@
       NetworkAnonymizationKey()};
 
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
-       // Need to partition connections by NetworkAnonymizationKey for
-       // QuicSessionAliasKey to include NetworkAnonymizationKeys.
-       features::kPartitionConnectionsByNetworkIsolationKey},
-      // disabled_features
-      {});
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   http_server_properties_ = std::make_unique<HttpServerProperties>();
@@ -11666,14 +11654,8 @@
 
 TEST_P(QuicSessionPoolTest, MaybeInitializeWithNetworkAnonymizationKey) {
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
-       // Need to partition connections by NetworkAnonymizationKey for
-       // QuicSessionAliasKey to include NetworkAnonymizationKeys.
-       features::kPartitionConnectionsByNetworkIsolationKey},
-      // disabled_features
-      {});
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   http_server_properties_ = std::make_unique<HttpServerProperties>();
@@ -11688,7 +11670,7 @@
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndDisableFeature(
-      features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   const SchemefulSite kSite1(GURL("https://foo.test/"));
   const auto kNetworkAnonymizationKey1 =
@@ -11739,14 +11721,8 @@
   const char kUserAgentId3[] = "another spoon";
 
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
-       // Need to partition connections by NetworkAnonymizationKey for
-       // QuicSessionAliasKey to include NetworkAnonymizationKeys.
-       features::kPartitionConnectionsByNetworkIsolationKey},
-      // disabled_features
-      {});
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   const SchemefulSite kSite1(GURL("https://foo.test/"));
   const auto kNetworkAnonymizationKey1 =
@@ -11827,14 +11803,8 @@
 // only one cache, so nothing is ever evicted.
 TEST_P(QuicSessionPoolTest, CryptoConfigCacheMRUWithNetworkAnonymizationKey) {
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
-       // Need to partition connections by NetworkAnonymizationKey for
-       // QuicSessionAliasKey to include NetworkAnonymizationKeys.
-       features::kPartitionConnectionsByNetworkIsolationKey},
-      // disabled_features
-      {});
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   const int kNumSessionsToMake = kMaxRecentCryptoConfigs + 5;
 
@@ -11902,14 +11872,8 @@
   const int kNumSessionsToMake = kMaxRecentCryptoConfigs + 5;
 
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
-       // Need to partition connections by NetworkAnonymizationKey for
-       // QuicSessionAliasKey to include NetworkAnonymizationKeys.
-       features::kPartitionConnectionsByNetworkIsolationKey},
-      // disabled_features
-      {});
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   http_server_properties_ = std::make_unique<HttpServerProperties>();
@@ -12950,12 +12914,8 @@
   const auto kNetworkAnonymizationKey =
       NetworkAnonymizationKey::CreateSameSite(kSite1);
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionConnectionsByNetworkIsolationKey,
-       features::kSplitHostCacheByNetworkIsolationKey},
-      // disabled_features
-      {});
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   Initialize();
   ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails();
diff --git a/net/reporting/reporting_cache_unittest.cc b/net/reporting/reporting_cache_unittest.cc
index e294c2e..c47663b 100644
--- a/net/reporting/reporting_cache_unittest.cc
+++ b/net/reporting/reporting_cache_unittest.cc
@@ -62,10 +62,10 @@
  protected:
   ReportingCacheTest() {
     // This is a private API of the reporting service, so no need to test the
-    // case kPartitionNelAndReportingByNetworkIsolationKey is disabled - the
+    // case kPartitionConnectionsByNetworkIsolationKey is disabled - the
     // feature is only applied at the entry points of the service.
     feature_list_.InitAndEnableFeature(
-        features::kPartitionNelAndReportingByNetworkIsolationKey);
+        features::kPartitionConnectionsByNetworkIsolationKey);
 
     ReportingPolicy policy;
     policy.max_report_count = 5;
diff --git a/net/reporting/reporting_delivery_agent_unittest.cc b/net/reporting/reporting_delivery_agent_unittest.cc
index 94f5ce8..62fff0c 100644
--- a/net/reporting/reporting_delivery_agent_unittest.cc
+++ b/net/reporting/reporting_delivery_agent_unittest.cc
@@ -40,10 +40,10 @@
  protected:
   ReportingDeliveryAgentTest() {
     // This is a private API of the reporting service, so no need to test the
-    // case kPartitionNelAndReportingByNetworkIsolationKey is disabled - the
+    // case kPartitionConnectionsByNetworkIsolationKey is disabled - the
     // feature is only applied at the entry points of the service.
     feature_list_.InitAndEnableFeature(
-        features::kPartitionNelAndReportingByNetworkIsolationKey);
+        features::kPartitionConnectionsByNetworkIsolationKey);
 
     ReportingPolicy policy;
     policy.endpoint_backoff_policy.num_errors_to_ignore = 0;
diff --git a/net/reporting/reporting_header_parser_unittest.cc b/net/reporting/reporting_header_parser_unittest.cc
index 3416d59..e678d31 100644
--- a/net/reporting/reporting_header_parser_unittest.cc
+++ b/net/reporting/reporting_header_parser_unittest.cc
@@ -112,10 +112,10 @@
  protected:
   ReportingHeaderParserTest() {
     // This is a private API of the reporting service, so no need to test the
-    // case kPartitionNelAndReportingByNetworkIsolationKey is disabled - the
+    // case kPartitionConnectionsByNetworkIsolationKey is disabled - the
     // feature is only applied at the entry points of the service.
     feature_list_.InitAndEnableFeature(
-        features::kPartitionNelAndReportingByNetworkIsolationKey);
+        features::kPartitionConnectionsByNetworkIsolationKey);
   }
 
   ReportingEndpointGroup MakeEndpointGroup(
@@ -1745,7 +1745,7 @@
     // Enable kDocumentReporting to support new StructuredHeader-based
     // Reporting-Endpoints header.
     feature_list_.InitWithFeatures(
-        {features::kPartitionNelAndReportingByNetworkIsolationKey,
+        {features::kPartitionConnectionsByNetworkIsolationKey,
          features::kDocumentReporting},
         {});
   }
diff --git a/net/reporting/reporting_service_unittest.cc b/net/reporting/reporting_service_unittest.cc
index 46cf10760..42479625d 100644
--- a/net/reporting/reporting_service_unittest.cc
+++ b/net/reporting/reporting_service_unittest.cc
@@ -71,7 +71,7 @@
 
   ReportingServiceTest() {
     feature_list_.InitAndEnableFeature(
-        features::kPartitionNelAndReportingByNetworkIsolationKey);
+        features::kPartitionConnectionsByNetworkIsolationKey);
     Init();
   }
 
@@ -160,7 +160,7 @@
 TEST_P(ReportingServiceTest, QueueReportNetworkIsolationKeyDisabled) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndDisableFeature(
-      features::kPartitionNelAndReportingByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   // Re-create the store, so it reads the new feature value.
   Init();
@@ -225,7 +225,7 @@
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures(
       {net::features::kDocumentReporting},
-      {features::kPartitionNelAndReportingByNetworkIsolationKey});
+      {features::kPartitionConnectionsByNetworkIsolationKey});
 
   // Re-create the store, so it reads the new feature value.
   Init();
@@ -403,7 +403,7 @@
 TEST_P(ReportingServiceTest, ProcessReportToHeaderNetworkIsolationKeyDisabled) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndDisableFeature(
-      features::kPartitionNelAndReportingByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   // Re-create the store, so it reads the new feature value.
   Init();
diff --git a/net/socket/client_socket_pool_unittest.cc b/net/socket/client_socket_pool_unittest.cc
index 7753aac..34d2d699 100644
--- a/net/socket/client_socket_pool_unittest.cc
+++ b/net/socket/client_socket_pool_unittest.cc
@@ -174,7 +174,7 @@
                 .ToString());
 }
 
-TEST(ClientSocketPool, PartitionConnectionsByNetworkIsolationKeyDisabled) {
+TEST(ClientSocketPool, SplitHostCacheByNetworkIsolationKeyDisabled) {
   const SchemefulSite kSiteFoo(GURL("https://foo.com"));
   const SchemefulSite kSiteBar(GURL("https://bar.com"));
   base::test::ScopedFeatureList feature_list;
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index 9226d30..0694ea62 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -3028,7 +3028,7 @@
        SessionResumptionNetworkIsolationKeyDisabled) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndDisableFeature(
-      features::kPartitionSSLSessionsByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   ASSERT_TRUE(
       StartEmbeddedTestServer(EmbeddedTestServer::CERT_OK, GetServerConfig()));
@@ -3084,7 +3084,7 @@
        SessionResumptionNetworkIsolationKeyEnabled) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      features::kPartitionSSLSessionsByNetworkIsolationKey);
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   const SchemefulSite kSiteA(GURL("https://a.test"));
   const SchemefulSite kSiteB(GURL("https://b.test"));
diff --git a/net/socket/transport_client_socket_pool_unittest.cc b/net/socket/transport_client_socket_pool_unittest.cc
index b32e633..f2a9db5 100644
--- a/net/socket/transport_client_socket_pool_unittest.cc
+++ b/net/socket/transport_client_socket_pool_unittest.cc
@@ -1813,12 +1813,8 @@
   const char kHost[] = "bar.test";
 
   base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionConnectionsByNetworkIsolationKey,
-       features::kSplitHostCacheByNetworkIsolationKey},
-      // disabled_features
-      {});
+  scoped_feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   session_deps_.host_resolver->set_ondemand_mode(true);
 
@@ -1850,12 +1846,8 @@
   const char kHost[] = "bar.test";
 
   base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionConnectionsByNetworkIsolationKey,
-       features::kSplitHostCacheByNetworkIsolationKey},
-      // disabled_features
-      {});
+  scoped_feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   session_deps_.host_resolver->set_ondemand_mode(true);
 
@@ -1897,12 +1889,8 @@
       "http://proxy.test", /*default_scheme=*/ProxyServer::SCHEME_HTTP);
 
   base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionConnectionsByNetworkIsolationKey,
-       features::kSplitHostCacheByNetworkIsolationKey},
-      // disabled_features
-      {});
+  scoped_feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   session_deps_.host_resolver->set_ondemand_mode(true);
 
@@ -1966,12 +1954,8 @@
       "https://proxy.test", /*default_scheme=*/ProxyServer::SCHEME_HTTP);
 
   base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionConnectionsByNetworkIsolationKey,
-       features::kSplitHostCacheByNetworkIsolationKey},
-      // disabled_features
-      {});
+  scoped_feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   session_deps_.host_resolver->set_ondemand_mode(true);
 
@@ -2036,12 +2020,8 @@
       "socks4://proxy.test", /*default_scheme=*/ProxyServer::SCHEME_HTTP);
 
   base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionConnectionsByNetworkIsolationKey,
-       features::kSplitHostCacheByNetworkIsolationKey},
-      // disabled_features
-      {});
+  scoped_feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   session_deps_.host_resolver->set_ondemand_mode(true);
 
@@ -2128,12 +2108,8 @@
       "socks5://proxy.test", /*default_scheme=*/ProxyServer::SCHEME_HTTP);
 
   base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionConnectionsByNetworkIsolationKey,
-       features::kSplitHostCacheByNetworkIsolationKey},
-      // disabled_features
-      {});
+  scoped_feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   session_deps_.host_resolver->set_ondemand_mode(true);
 
diff --git a/net/socket/websocket_transport_client_socket_pool_unittest.cc b/net/socket/websocket_transport_client_socket_pool_unittest.cc
index 560903e..e42d129 100644
--- a/net/socket/websocket_transport_client_socket_pool_unittest.cc
+++ b/net/socket/websocket_transport_client_socket_pool_unittest.cc
@@ -1258,12 +1258,8 @@
       NetworkAnonymizationKey::CreateSameSite(kSite);
 
   base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionConnectionsByNetworkIsolationKey,
-       features::kSplitHostCacheByNetworkIsolationKey},
-      // disabled_features
-      {});
+  scoped_feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   host_resolver_->set_ondemand_mode(true);
 
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index 35893817..11ec9b49 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -4412,14 +4412,10 @@
       kNetworkIsolationKey1, kNetworkIsolationKey2, NetworkIsolationKey()};
 
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
-       // Need to partition connections by NetworkAnonymizationKey for
-       // SpdySessionKeys to include NetworkAnonymizationKeys.
-       features::kPartitionConnectionsByNetworkIsolationKey},
-      // disabled_features
-      {});
+  // Need to partition connections by NetworkAnonymizationKey for
+  // SpdySessionKeys to include NetworkAnonymizationKeys.
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   // Do not force SPDY so that sockets can negotiate HTTP/1.1.
   NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
@@ -4631,14 +4627,10 @@
       kNetworkIsolationKey1, kNetworkIsolationKey2, NetworkIsolationKey()};
 
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
-       // Need to partition connections by NetworkAnonymizationKey for
-       // SpdySessionKeys to include NetworkAnonymizationKeys.
-       features::kPartitionConnectionsByNetworkIsolationKey},
-      // disabled_features
-      {});
+  // Need to partition connections by NetworkAnonymizationKey for
+  // SpdySessionKeys to include NetworkAnonymizationKeys.
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
 
   request_.method = "GET";
   auto session_deps = std::make_unique<SpdySessionDependencies>(
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc
index 1e18f4c..ccb8fea8 100644
--- a/net/spdy/spdy_session_unittest.cc
+++ b/net/spdy/spdy_session_unittest.cc
@@ -5867,14 +5867,11 @@
 TEST_F(AltSvcFrameTest,
        ProcessAltSvcFrameOnActiveStreamWithNetworkAnonymizationKey) {
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitWithFeatures(
-      // enabled_features
-      {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
-       // Need to partition connections by NetworkAnonymizationKey for
-       // SpdySessionKeys to include NetworkAnonymizationKeys.
-       features::kPartitionConnectionsByNetworkIsolationKey},
-      // disabled_features
-      {});
+  // Need to partition connections by NetworkAnonymizationKey for
+  // SpdySessionKeys to include NetworkAnonymizationKeys.
+  feature_list.InitAndEnableFeature(
+      features::kPartitionConnectionsByNetworkIsolationKey);
+
   // Since HttpServerProperties caches the feature value, have to create a new
   // one.
   session_deps_.http_server_properties =
diff --git a/net/ssl/ssl_config.h b/net/ssl/ssl_config.h
index 672b707..4492377 100644
--- a/net/ssl/ssl_config.h
+++ b/net/ssl/ssl_config.h
@@ -122,7 +122,7 @@
   // Keys which do not appear in |alpn_protos| are ignored.
   ApplicationSettings application_settings;
 
-  // If the PartitionSSLSessionsByNetworkIsolationKey feature is enabled, the
+  // If the PartitionConnectionsByNetworkIsolationKey feature is enabled, the
   // session cache is partitioned by this value.
   NetworkAnonymizationKey network_anonymization_key;
 
@@ -139,7 +139,7 @@
   // is moved into SSLClientContext. With client certificates are disabled, the
   // current session cache partitioning behavior will be needed to correctly
   // implement it. For now, it acts as an incomplete version of
-  // PartitionSSLSessionsByNetworkIsolationKey.
+  // PartitionConnectionsByNetworkIsolationKey.
   PrivacyMode privacy_mode = PRIVACY_MODE_DISABLED;
 
   // True if the post-handshake peeking of the transport should be skipped. This
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 5f0bc07..49d3352 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -13051,10 +13051,8 @@
 class PartitionConnectionsByNetworkAnonymizationKey : public URLRequestTest {
  public:
   PartitionConnectionsByNetworkAnonymizationKey() {
-    scoped_feature_list_.InitWithFeatures(
-        {net::features::kPartitionConnectionsByNetworkIsolationKey,
-         net::features::kPartitionSSLSessionsByNetworkIsolationKey},
-        {});
+    scoped_feature_list_.InitAndEnableFeature(
+        net::features::kPartitionConnectionsByNetworkIsolationKey);
   }
   const SchemefulSite kTestSiteA = SchemefulSite(GURL("http://a.test/"));
   const SchemefulSite kTestSiteB = SchemefulSite(GURL("http://b.test/"));
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index 1954502..7058961 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -1516,7 +1516,7 @@
 TEST_F(NetworkContextTest, P2PHostResolution) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      net::features::kSplitHostCacheByNetworkIsolationKey);
+      net::features::kPartitionConnectionsByNetworkIsolationKey);
 
   const char kHostname[] = "foo.test.";
   net::IPAddress ip_address;
diff --git a/services/network/p2p/socket_tcp_unittest.cc b/services/network/p2p/socket_tcp_unittest.cc
index 5da8e20c..93765ad0 100644
--- a/services/network/p2p/socket_tcp_unittest.cc
+++ b/services/network/p2p/socket_tcp_unittest.cc
@@ -531,7 +531,7 @@
 TEST(P2PSocketTcpWithPseudoTlsTest, Hostname) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
-      net::features::kSplitHostCacheByNetworkIsolationKey);
+      net::features::kPartitionConnectionsByNetworkIsolationKey);
 
   const char kHostname[] = "foo.test";
   base::test::TaskEnvironment task_environment(
diff --git a/services/network/proxy_resolving_client_socket_unittest.cc b/services/network/proxy_resolving_client_socket_unittest.cc
index f4d40498..eedb3c21 100644
--- a/services/network/proxy_resolving_client_socket_unittest.cc
+++ b/services/network/proxy_resolving_client_socket_unittest.cc
@@ -56,12 +56,8 @@
       public testing::WithParamInterface<bool> {
  protected:
   ProxyResolvingClientSocketTest() : use_tls_(GetParam()) {
-    feature_list_.InitWithFeatures(
-        // enabled_features
-        {net::features::kPartitionConnectionsByNetworkIsolationKey,
-         net::features::kSplitHostCacheByNetworkIsolationKey},
-        // disabled_features
-        {});
+    feature_list_.InitAndEnableFeature(
+        net::features::kPartitionConnectionsByNetworkIsolationKey);
   }
 
   ~ProxyResolvingClientSocketTest() override {}
diff --git a/services/network/resource_scheduler/resource_scheduler_unittest.cc b/services/network/resource_scheduler/resource_scheduler_unittest.cc
index aabc265..49744e37 100644
--- a/services/network/resource_scheduler/resource_scheduler_unittest.cc
+++ b/services/network/resource_scheduler/resource_scheduler_unittest.cc
@@ -132,7 +132,7 @@
   ResourceSchedulerTest() {
     base::test::ScopedFeatureList feature_list;
     feature_list.InitAndEnableFeature(
-        net::features::kPartitionHttpServerPropertiesByNetworkIsolationKey);
+        net::features::kPartitionConnectionsByNetworkIsolationKey);
     // This has to be done after initializing the feature list, since the value
     // of the feature is cached.
     auto context_builder = net::CreateTestURLRequestContextBuilder();
diff --git a/services/webnn/webnn_utils.cc b/services/webnn/webnn_utils.cc
index c6b57a9..85b6a23 100644
--- a/services/webnn/webnn_utils.cc
+++ b/services/webnn/webnn_utils.cc
@@ -143,9 +143,9 @@
 std::string OpKindToString(mojom::ArgMinMax::Kind kind) {
   switch (kind) {
     case mojom::ArgMinMax::Kind::kMin:
-      return "ArgMin";
+      return "argMin";
     case mojom::ArgMinMax::Kind::kMax:
-      return "ArgMax";
+      return "argMax";
   }
   NOTREACHED_NORETURN();
 }
@@ -217,25 +217,25 @@
 std::string OpKindToString(mojom::Reduce::Kind kind) {
   switch (kind) {
     case mojom::Reduce::Kind::kL1:
-      return "ReduceL1";
+      return "reduceL1";
     case mojom::Reduce::Kind::kL2:
-      return "ReduceL2";
+      return "reduceL2";
     case mojom::Reduce::Kind::kLogSum:
-      return "ReduceLogSum";
+      return "reduceLogSum";
     case mojom::Reduce::Kind::kLogSumExp:
-      return "ReduceLogSumExp";
+      return "reduceLogSumExp";
     case mojom::Reduce::Kind::kMax:
-      return "ReduceMax";
+      return "reduceMax";
     case mojom::Reduce::Kind::kMean:
-      return "ReduceMean";
+      return "reduceMean";
     case mojom::Reduce::Kind::kMin:
-      return "ReduceMin";
+      return "reduceMin";
     case mojom::Reduce::Kind::kProduct:
-      return "ReduceProduct";
+      return "reduceProduct";
     case mojom::Reduce::Kind::kSum:
-      return "ReduceSum";
+      return "reduceSum";
     case mojom::Reduce::Kind::kSumSquare:
-      return "ReduceSumSquare";
+      return "reduceSumSquare";
   }
 }
 
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 65d3dae..182a272 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -5487,9 +5487,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_v126.0.6476.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6477.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 126.0.6476.0",
+        "description": "Run with ash-chrome version 126.0.6477.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5499,8 +5499,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6476.0",
-              "revision": "version:126.0.6476.0"
+              "location": "lacros_version_skew_tests_v126.0.6477.0",
+              "revision": "version:126.0.6477.0"
             }
           ],
           "dimensions": {
@@ -5643,9 +5643,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_v126.0.6476.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6477.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 126.0.6476.0",
+        "description": "Run with ash-chrome version 126.0.6477.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5655,8 +5655,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6476.0",
-              "revision": "version:126.0.6476.0"
+              "location": "lacros_version_skew_tests_v126.0.6477.0",
+              "revision": "version:126.0.6477.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json
index 99eb8be..759e410a 100644
--- a/testing/buildbot/chromium.coverage.json
+++ b/testing/buildbot/chromium.coverage.json
@@ -19664,9 +19664,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_v126.0.6476.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6477.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 126.0.6476.0",
+        "description": "Run with ash-chrome version 126.0.6477.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -19676,8 +19676,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6476.0",
-              "revision": "version:126.0.6476.0"
+              "location": "lacros_version_skew_tests_v126.0.6477.0",
+              "revision": "version:126.0.6477.0"
             }
           ],
           "dimensions": {
@@ -19820,9 +19820,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_v126.0.6476.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6477.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 126.0.6476.0",
+        "description": "Run with ash-chrome version 126.0.6477.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -19832,8 +19832,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6476.0",
-              "revision": "version:126.0.6476.0"
+              "location": "lacros_version_skew_tests_v126.0.6477.0",
+              "revision": "version:126.0.6477.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 731a0cd..12ebdc6b 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -41840,9 +41840,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_v126.0.6476.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6477.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 126.0.6476.0",
+        "description": "Run with ash-chrome version 126.0.6477.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -41851,8 +41851,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6476.0",
-              "revision": "version:126.0.6476.0"
+              "location": "lacros_version_skew_tests_v126.0.6477.0",
+              "revision": "version:126.0.6477.0"
             }
           ],
           "dimensions": {
@@ -41990,9 +41990,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_v126.0.6476.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6477.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 126.0.6476.0",
+        "description": "Run with ash-chrome version 126.0.6477.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -42001,8 +42001,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6476.0",
-              "revision": "version:126.0.6476.0"
+              "location": "lacros_version_skew_tests_v126.0.6477.0",
+              "revision": "version:126.0.6477.0"
             }
           ],
           "dimensions": {
@@ -43339,9 +43339,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_v126.0.6476.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6477.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 126.0.6476.0",
+        "description": "Run with ash-chrome version 126.0.6477.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -43351,8 +43351,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6476.0",
-              "revision": "version:126.0.6476.0"
+              "location": "lacros_version_skew_tests_v126.0.6477.0",
+              "revision": "version:126.0.6477.0"
             }
           ],
           "dimensions": {
@@ -43495,9 +43495,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_v126.0.6476.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6477.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 126.0.6476.0",
+        "description": "Run with ash-chrome version 126.0.6477.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -43507,8 +43507,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6476.0",
-              "revision": "version:126.0.6476.0"
+              "location": "lacros_version_skew_tests_v126.0.6477.0",
+              "revision": "version:126.0.6477.0"
             }
           ],
           "dimensions": {
@@ -44820,9 +44820,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_v126.0.6476.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6477.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 126.0.6476.0",
+        "description": "Run with ash-chrome version 126.0.6477.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -44831,8 +44831,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6476.0",
-              "revision": "version:126.0.6476.0"
+              "location": "lacros_version_skew_tests_v126.0.6477.0",
+              "revision": "version:126.0.6477.0"
             }
           ],
           "dimensions": {
@@ -44970,9 +44970,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_v126.0.6476.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6477.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 126.0.6476.0",
+        "description": "Run with ash-chrome version 126.0.6477.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -44981,8 +44981,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6476.0",
-              "revision": "version:126.0.6476.0"
+              "location": "lacros_version_skew_tests_v126.0.6477.0",
+              "revision": "version:126.0.6477.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index c3b95a7..d6fa8d2 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -15763,12 +15763,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_v126.0.6476.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6477.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 126.0.6476.0",
+        "description": "Run with ash-chrome version 126.0.6477.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -15778,8 +15778,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6476.0",
-              "revision": "version:126.0.6476.0"
+              "location": "lacros_version_skew_tests_v126.0.6477.0",
+              "revision": "version:126.0.6477.0"
             }
           ],
           "dimensions": {
@@ -15939,12 +15939,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_v126.0.6476.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6477.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 126.0.6476.0",
+        "description": "Run with ash-chrome version 126.0.6477.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -15954,8 +15954,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v126.0.6476.0",
-              "revision": "version:126.0.6476.0"
+              "location": "lacros_version_skew_tests_v126.0.6477.0",
+              "revision": "version:126.0.6477.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.updater.json b/testing/buildbot/chromium.updater.json
index 51de853..5bc23847 100644
--- a/testing/buildbot/chromium.updater.json
+++ b/testing/buildbot/chromium.updater.json
@@ -673,7 +673,7 @@
           "dimensions": {
             "cpu": "x86-64",
             "integrity": "high",
-            "os": "Windows-11-22000",
+            "os": "Windows-11",
             "pool": "chromium.win.uac"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
@@ -689,7 +689,7 @@
         "swarming": {
           "dimensions": {
             "cpu": "x86-64",
-            "os": "Windows-11-22000",
+            "os": "Windows-11",
             "pool": "chromium.win.uac"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
diff --git a/testing/buildbot/mixins.pyl b/testing/buildbot/mixins.pyl
index 505a4a7..4040951 100644
--- a/testing/buildbot/mixins.pyl
+++ b/testing/buildbot/mixins.pyl
@@ -1435,6 +1435,13 @@
       },
     },
   },
+  'win11-any': {
+    'swarming': {
+      'dimensions': {
+        'os': 'Windows-11',
+      },
+    },
+  },
   'win11_qualcomm_adreno_690_stable': {
     'swarming': {
       'dimensions': {
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 58c7b6a..7a01e9b 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -267,16 +267,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'identifier': 'Lacros version skew testing ash canary',
-    'description': 'Run with ash-chrome version 126.0.6476.0',
+    'description': 'Run with ash-chrome version 126.0.6477.0',
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6476.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v126.0.6477.0/test_ash_chrome',
     ],
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v126.0.6476.0',
-          'revision': 'version:126.0.6476.0',
+          'location': 'lacros_version_skew_tests_v126.0.6477.0',
+          'revision': 'version:126.0.6477.0',
         },
       ],
     },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index d8ab767..18d1c81 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -5789,7 +5789,7 @@
       },
       'win11-updater-tester-dbg-uac': {
         'mixins': [
-          'win11',
+          'win11-any',
           'x86-64',
         ],
         'test_suites': {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 706c614a..152019bf 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -4681,6 +4681,25 @@
             ]
         }
     ],
+    "ConditionalImageResize": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "ConditionalImageResize"
+                    ]
+                }
+            ]
+        }
+    ],
     "ConditionallySkipGpuChannelFlush": [
         {
             "platforms": [
@@ -6822,6 +6841,86 @@
             ]
         }
     ],
+    "DownloadWarningSurvey": [
+        {
+            "platforms": [
+                "chromeos",
+                "chromeos_lacros",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "DownloadBubbleBypass_20240513",
+                    "params": {
+                        "en_site_id": "ikozJtokP0ugnJ3q1cK0SbwHjMKE",
+                        "probability": "1.0",
+                        "survey_type": "0"
+                    },
+                    "enable_features": [
+                        "DownloadWarningSurvey"
+                    ]
+                },
+                {
+                    "name": "DownloadBubbleHeed_20240513",
+                    "params": {
+                        "en_site_id": "jhF4CtEp50ugnJ3q1cK0UZhzeE9d",
+                        "probability": "1.0",
+                        "survey_type": "1"
+                    },
+                    "enable_features": [
+                        "DownloadWarningSurvey"
+                    ]
+                },
+                {
+                    "name": "DownloadBubbleIgnore_20240513",
+                    "params": {
+                        "en_site_id": "QGZEf3nUW0ugnJ3q1cK0PoGTrYqX",
+                        "ignore_delay_seconds": "300",
+                        "probability": "0.5",
+                        "survey_type": "2"
+                    },
+                    "enable_features": [
+                        "DownloadWarningSurvey"
+                    ]
+                },
+                {
+                    "name": "DownloadsPageBypass_20240513",
+                    "params": {
+                        "en_site_id": "B4TxfW2d50ugnJ3q1cK0SrBjxPp9",
+                        "probability": "1.0",
+                        "survey_type": "3"
+                    },
+                    "enable_features": [
+                        "DownloadWarningSurvey"
+                    ]
+                },
+                {
+                    "name": "DownloadsPageHeed_20240513",
+                    "params": {
+                        "en_site_id": "P1UCDjb5L0ugnJ3q1cK0S1YhAs9h",
+                        "probability": "1.0",
+                        "survey_type": "4"
+                    },
+                    "enable_features": [
+                        "DownloadWarningSurvey"
+                    ]
+                },
+                {
+                    "name": "DownloadsPageIgnore_20240513",
+                    "params": {
+                        "en_site_id": "ToBgFcctL0ugnJ3q1cK0UoPbrdFt",
+                        "probability": "0.5",
+                        "survey_type": "5"
+                    },
+                    "enable_features": [
+                        "DownloadWarningSurvey"
+                    ]
+                }
+            ]
+        }
+    ],
     "DownloadsMigrateToJobsAPI": [
         {
             "platforms": [
@@ -11073,6 +11172,21 @@
             ]
         }
     ],
+    "LazyBindJsInjection": [
+        {
+            "platforms": [
+                "android_webview"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "LazyBindJsInjection"
+                    ]
+                }
+            ]
+        }
+    ],
     "LeakSkiaEventTracerAtExit": [
         {
             "platforms": [
@@ -14072,11 +14186,7 @@
                     "name": "enabled_triple_nik_cross_site_flag_nak_rollout",
                     "enable_features": [
                         "PartitionConnectionsByNetworkIsolationKey",
-                        "PartitionDomainReliabilityByNetworkIsolationKey",
-                        "PartitionHttpServerPropertiesByNetworkIsolationKey",
-                        "PartitionNelAndReportingByNetworkIsolationKey",
-                        "PartitionSSLSessionsByNetworkIsolationKey",
-                        "SplitHostCacheByNetworkIsolationKey"
+                        "PartitionDomainReliabilityByNetworkIsolationKey"
                     ],
                     "disable_features": []
                 }
diff --git a/third_party/angle b/third_party/angle
index 3b470cf..df2e7bd 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit 3b470cf502e9846e0c355a826cd844a4cf46fda0
+Subproject commit df2e7bd7c99e27868947f887355ad11979f6d492
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
index cc88e375..5b5010e 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -462,13 +462,28 @@
     return false;
   }
 
-  // Native <img> create extra child nodes to hold alt text, which are not
-  // allowed as children. Note: images can have image map children, but these
-  // are moved from the <map> descendants and are not descendants of the image.
-  // See AXNodeObject::AddImageMapChildren().
-  if (node->IsInUserAgentShadowRoot() &&
-      IsA<HTMLImageElement>(node->OwnerShadowHost())) {
-    return false;
+  if (node->IsInUserAgentShadowRoot()) {
+    // Native <img> create extra child nodes to hold alt text, which are not
+    // allowed as children. Note: images can have image map children, but these
+    // are moved from the <map> descendants and are not descendants of the
+    // image. See AXNodeObject::AddImageMapChildren().
+    if (IsA<HTMLImageElement>(node->OwnerShadowHost())) {
+      return false;
+    }
+    // aria-hidden subtrees can safely be pruned when it's in a UA shadow root.
+    // Make an exception for file input, which needs to gather its name from
+    // aria-hidden contents.
+    if (const Element* element = DynamicTo<Element>(node)) {
+      if (element->FastGetAttribute(html_names::kAriaHiddenAttr) == "true") {
+        if (auto* input =
+                DynamicTo<HTMLInputElement>(element->OwnerShadowHost())) {
+          if (input->FormControlType() == FormControlType::kInputFile) {
+            return true;
+          }
+        }
+        return false;
+      }
+    }
   }
 
   // All other non-slot user agent shadow nodes are relevant.
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 54e3161..1032fc8 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -7383,3 +7383,6 @@
 crbug.com/333739617 fast/peerconnection/RTCEncodedVideoFrameMetadata-timestamp.html [ Failure Pass Timeout ]
 crbug.com/333395248 [ Mac ] virtual/keepalive-in-browser-migration/external/wpt/fetch/api/response/response-clone.any.serviceworker.html [ Failure Pass ]
 crbug.com/329784394 external/wpt/html/browsers/browsing-the-web/history-traversal/persisted-user-state-restoration/scroll-restoration-fragment-scrolling-samedoc.html [ Failure Pass ]
+
+# Gardener 2024-05-13
+crbug.com/339835801 [ Win ] fast/forms/select-popup/popup-menu-appearance-tall.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/external/wpt/client-hints/resources/2x3-svg-scaled-by-sec-ch-width.py b/third_party/blink/web_tests/external/wpt/client-hints/resources/2x3-svg-scaled-by-sec-ch-width.py
deleted file mode 100644
index d53574c3..0000000
--- a/third_party/blink/web_tests/external/wpt/client-hints/resources/2x3-svg-scaled-by-sec-ch-width.py
+++ /dev/null
@@ -1,22 +0,0 @@
-def main(request, response):
-    """
-    Simple handler that responds with an SVG image with width `2 * sec-ch-width`
-    and height `3 * sec-ch-width`, or 1x1 if sec-ch-width is not present.
-    """
-
-    width = 1
-    height = 1
-
-    if b"sec-ch-width" in request.headers:
-      sec_ch_width = request.headers.get(b"sec-ch-width").decode()
-      width = 2 * int(sec_ch_width)
-      height = 3 * int(sec_ch_width)
-
-    response.headers.set(b"Content-Type", b"image/svg+xml")
-    response.content = str.encode(f"""<svg
-        xmlns="http://www.w3.org/2000/svg"
-        xmlns:xlink="http://www.w3.org/1999/xlink"
-        width="{width}"
-        height="{height}">
-      <rect width="100%" height="100%" fill="green" />
-    </svg>""")
diff --git a/third_party/blink/web_tests/external/wpt/client-hints/sec-ch-width.https.html b/third_party/blink/web_tests/external/wpt/client-hints/sec-ch-width.https.html
deleted file mode 100644
index f44fa3b..0000000
--- a/third_party/blink/web_tests/external/wpt/client-hints/sec-ch-width.https.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<meta http-equiv="Delegate-CH" content="Sec-CH-Width">
-<title>Tests Sec-CH-Width</title>
-<link rel="help" href="https://wicg.github.io/responsive-image-client-hints/#sec-ch-width">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<img src="resources/2x3-svg-scaled-by-sec-ch-width.py" width="50" height="50">
-
-<script>
-  promise_test(async (test) => {
-    const testImage = document.getElementsByTagName('img')[0];
-    await new Promise(resolve => testImage.onload = resolve);
-    assert_equals(testImage.naturalWidth, 100);
-    assert_equals(testImage.naturalHeight, 150);
-  }, 'Sec-CH-Width should be set');
-</script>
diff --git a/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/arg_min_max.https.any.worker_gpu-expected.txt b/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/arg_min_max.https.any.worker_gpu-expected.txt
index 8fab6bf..e038dd2 100644
--- a/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/arg_min_max.https.any.worker_gpu-expected.txt
+++ b/third_party/blink/web_tests/platform/mac-mac14-arm64/virtual/webnn-service-with-gpu/external/wpt/webnn/conformance_tests/arg_min_max.https.any.worker_gpu-expected.txt
@@ -1,84 +1,84 @@
 This is a testharness.js-based test.
 [FAIL] argMin float32 1D constant tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMin"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMin"
 [FAIL] argMin float32 1D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMin"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMin"
 [FAIL] argMin float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMin"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMin"
 [FAIL] argMin float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMin"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMin"
 [FAIL] argMin float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMin"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMin"
 [FAIL] argMin float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMin"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMin"
 [FAIL] argMin float32 4D tensor options.axes=[2]
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMin"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMin"
 [FAIL] argMin float32 4D tensor options.axes=[]
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMin"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMin"
 [FAIL] argMin float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMin"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMin"
 [FAIL] argMin float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMin"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMin"
 [FAIL] argMin float32 4D tensor options.selectLastIndex=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMin"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMin"
 [FAIL] argMin float32 4D tensor options.selectLastIndex=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMin"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMin"
 [FAIL] argMin float32 4D tensor options.axes=[0, 2] options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMin"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMin"
 [FAIL] argMin float32 4D tensor options.axes=[3, 0, 1] options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMin"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMin"
 [FAIL] argMin float32 4D tensor options.axes=[0, 2] options.selectLastIndex=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMin"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMin"
 [FAIL] argMin float32 4D tensor options.axes=[0, 2] options.selectLastIndex=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMin"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMin"
 [FAIL] argMin float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMin"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMin"
 [FAIL] argMin float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMin"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMin"
 [FAIL] argMin float32 4D tensor all options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMin"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMin"
 [FAIL] argMin float32 0D scalar options.axes=[]
   promise_test: Unhandled rejection with value: object "DataError: Failed to execute 'argMin' on 'MLGraphBuilder': The rank of input must be larger than or equal to 1."
 [FAIL] argMin float32 0D scalar options.axes=[] no effect by both keepDimensions and selectLastIndex being true
   promise_test: Unhandled rejection with value: object "DataError: Failed to execute 'argMin' on 'MLGraphBuilder': The rank of input must be larger than or equal to 1."
 [FAIL] argMax float32 1D constant tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMax"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMax"
 [FAIL] argMax float32 1D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMax"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMax"
 [FAIL] argMax float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMax"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMax"
 [FAIL] argMax float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMax"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMax"
 [FAIL] argMax float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMax"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMax"
 [FAIL] argMax float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMax"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMax"
 [FAIL] argMax float32 4D tensor options.axes=[2]
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMax"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMax"
 [FAIL] argMax float32 4D tensor options.axes=[]
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMax"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMax"
 [FAIL] argMax float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMax"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMax"
 [FAIL] argMax float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMax"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMax"
 [FAIL] argMax float32 4D tensor options.selectLastIndex=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMax"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMax"
 [FAIL] argMax float32 4D tensor options.selectLastIndex=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMax"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMax"
 [FAIL] argMax float32 4D tensor options.axes=[0, 2] options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMax"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMax"
 [FAIL] argMax float32 4D tensor options.axes=[3, 0, 1] options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMax"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMax"
 [FAIL] argMax float32 4D tensor options.axes=[0, 2] options.selectLastIndex=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMax"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMax"
 [FAIL] argMax float32 4D tensor options.axes=[0, 2] options.selectLastIndex=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMax"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMax"
 [FAIL] argMax float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMax"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMax"
 [FAIL] argMax float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMax"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMax"
 [FAIL] argMax float32 4D tensor all options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator ArgMax"
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': Unsupported operator argMax"
 [FAIL] argMax float32 0D scalar options.axes=[]
   promise_test: Unhandled rejection with value: object "DataError: Failed to execute 'argMax' on 'MLGraphBuilder': The rank of input must be larger than or equal to 1."
 [FAIL] argMax float32 0D scalar options.axes=[] no effect by both keepDimensions and selectLastIndex being true
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/arg_min_max.https.any.worker_cpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/arg_min_max.https.any.worker_cpu-expected.txt
index 8115ba7c..a4f24c88 100644
--- a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/arg_min_max.https.any.worker_cpu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/arg_min_max.https.any.worker_cpu-expected.txt
@@ -1,72 +1,72 @@
 This is a testharness.js-based test.
 [FAIL] argMin float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.axes=[]
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.selectLastIndex=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.selectLastIndex=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.axes=[0, 2] options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.axes=[3, 0, 1] options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.axes=[0, 2] options.selectLastIndex=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.axes=[0, 2] options.selectLastIndex=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor all options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 0D scalar options.axes=[]
   promise_test: Unhandled rejection with value: object "DataError: Failed to execute 'argMin' on 'MLGraphBuilder': The rank of input must be larger than or equal to 1."
 [FAIL] argMin float32 0D scalar options.axes=[] no effect by both keepDimensions and selectLastIndex being true
   promise_test: Unhandled rejection with value: object "DataError: Failed to execute 'argMin' on 'MLGraphBuilder': The rank of input must be larger than or equal to 1."
 [FAIL] argMax float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.axes=[]
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.selectLastIndex=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.selectLastIndex=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.axes=[0, 2] options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.axes=[3, 0, 1] options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.axes=[0, 2] options.selectLastIndex=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.axes=[0, 2] options.selectLastIndex=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor all options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 0D scalar options.axes=[]
   promise_test: Unhandled rejection with value: object "DataError: Failed to execute 'argMax' on 'MLGraphBuilder': The rank of input must be larger than or equal to 1."
 [FAIL] argMax float32 0D scalar options.axes=[] no effect by both keepDimensions and selectLastIndex being true
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/arg_min_max.https.any_cpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/arg_min_max.https.any_cpu-expected.txt
index 8115ba7c..a4f24c88 100644
--- a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/arg_min_max.https.any_cpu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/arg_min_max.https.any_cpu-expected.txt
@@ -1,72 +1,72 @@
 This is a testharness.js-based test.
 [FAIL] argMin float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.axes=[]
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.selectLastIndex=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.selectLastIndex=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.axes=[0, 2] options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.axes=[3, 0, 1] options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.axes=[0, 2] options.selectLastIndex=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.axes=[0, 2] options.selectLastIndex=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 4D tensor all options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMin: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMin: Only supports scalar axis."
 [FAIL] argMin float32 0D scalar options.axes=[]
   promise_test: Unhandled rejection with value: object "DataError: Failed to execute 'argMin' on 'MLGraphBuilder': The rank of input must be larger than or equal to 1."
 [FAIL] argMin float32 0D scalar options.axes=[] no effect by both keepDimensions and selectLastIndex being true
   promise_test: Unhandled rejection with value: object "DataError: Failed to execute 'argMin' on 'MLGraphBuilder': The rank of input must be larger than or equal to 1."
 [FAIL] argMax float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.axes=[]
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.selectLastIndex=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.selectLastIndex=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.axes=[0, 2] options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.axes=[3, 0, 1] options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.axes=[0, 2] options.selectLastIndex=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.axes=[0, 2] options.selectLastIndex=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor options.axes=[3, 0, 1] options.selectLastIndex=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 4D tensor all options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ArgMax: Only supports scalar axis."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': argMax: Only supports scalar axis."
 [FAIL] argMax float32 0D scalar options.axes=[]
   promise_test: Unhandled rejection with value: object "DataError: Failed to execute 'argMax' on 'MLGraphBuilder': The rank of input must be larger than or equal to 1."
 [FAIL] argMax float32 0D scalar options.axes=[] no effect by both keepDimensions and selectLastIndex being true
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reduction.https.any.worker_cpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reduction.https.any.worker_cpu-expected.txt
index 34a3fbca..07c00356 100644
--- a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reduction.https.any.worker_cpu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reduction.https.any.worker_cpu-expected.txt
@@ -1,170 +1,170 @@
 This is a testharness.js-based test.
 Found 83 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] reduceL1 float32 1D constant tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 1D tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 1D tensor all negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 1D tensor all positive integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 1D tensor all negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL2 float32 1D constant tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 1D tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 1D tensor all negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 1D tensor all positive integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 1D tensor all negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceLogSum float32 1D constant tensor all non-negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 1D tensor all non-negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 1D tensor all non-negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSumExp float32 1D constant tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 1D tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 1D tensor all negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 1D tensor all positive integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 1D tensor all negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceSumSquare float32 1D constant tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 1D tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 1D tensor all negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 1D tensor all positive integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 1D tensor all negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reduction.https.any_cpu-expected.txt b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reduction.https.any_cpu-expected.txt
index 34a3fbca..07c00356 100644
--- a/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reduction.https.any_cpu-expected.txt
+++ b/third_party/blink/web_tests/virtual/webnn-service-on-cpu/external/wpt/webnn/conformance_tests/reduction.https.any_cpu-expected.txt
@@ -1,170 +1,170 @@
 This is a testharness.js-based test.
 Found 83 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] reduceL1 float32 1D constant tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 1D tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 1D tensor all negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 1D tensor all positive integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 1D tensor all negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL1 float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL1 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL1 is not implemented."
 [FAIL] reduceL2 float32 1D constant tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 1D tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 1D tensor all negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 1D tensor all positive integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 1D tensor all negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceL2 float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceL2 is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceL2 is not implemented."
 [FAIL] reduceLogSum float32 1D constant tensor all non-negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 1D tensor all non-negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 1D tensor all non-negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSum float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSum is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSum is not implemented."
 [FAIL] reduceLogSumExp float32 1D constant tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 1D tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 1D tensor all negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 1D tensor all positive integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 1D tensor all negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceLogSumExp float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceLogSumExp is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceLogSumExp is not implemented."
 [FAIL] reduceSumSquare float32 1D constant tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 1D tensor all positive default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 1D tensor all negative default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 1D tensor all positive integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 1D tensor all negative integers default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 2D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 3D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 4D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 5D tensor default options
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 3D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 4D tensor options.axes
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 3D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 3D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 4D tensor options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 4D tensor options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 4D tensor options.axes with options.keepDimensions=false
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 [FAIL] reduceSumSquare float32 4D tensor options.axes with options.keepDimensions=true
-  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': ReduceSumSquare is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Failed to execute 'build' on 'MLGraphBuilder': reduceSumSquare is not implemented."
 Harness: the test ran to completion.
 
diff --git a/third_party/chromium-variations b/third_party/chromium-variations
index 1545704..ac4104d8 160000
--- a/third_party/chromium-variations
+++ b/third_party/chromium-variations
@@ -1 +1 @@
-Subproject commit 1545704ff52cfb5119f3693c9a9e971594e9cb43
+Subproject commit ac4104d893a647c86da29a4b3a2a7ba5dd393380
diff --git a/third_party/closure_compiler/externs/tts.js b/third_party/closure_compiler/externs/tts.js
index a8fa4a2..16cbfa5 100644
--- a/third_party/closure_compiler/externs/tts.js
+++ b/third_party/closure_compiler/externs/tts.js
@@ -230,8 +230,8 @@
 chrome.tts.onEvent;
 
 /**
- * Called when the list of voices that would be returned by getVoices has
- * changed.
+ * Called when the list of $(ref:tts.TtsVoice) that would be returned by
+ * getVoices has changed.
  * @type {!ChromeEvent}
  * @see https://developer.chrome.com/extensions/tts#event-onVoicesChanged
  */
diff --git a/third_party/depot_tools b/third_party/depot_tools
index 28ece72a..af58dae 160000
--- a/third_party/depot_tools
+++ b/third_party/depot_tools
@@ -1 +1 @@
-Subproject commit 28ece72a5d752a5e36e62124979b18530e610f6b
+Subproject commit af58dae320bbe5b28ff312cca870ecbdb6751763
diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium
index 842f2d6..d59c0f94 100644
--- a/third_party/freetype/README.chromium
+++ b/third_party/freetype/README.chromium
@@ -1,7 +1,7 @@
 Name: FreeType
 URL: http://www.freetype.org/
-Version: VER-2-13-2-139-ga46424228
-Revision: a46424228f0998a72c715f32e18dca8a7a764c1f
+Version: VER-2-13-2-145-g68399b424
+Revision: 68399b4244d85a1acc18ce669176b531b2eb7e32
 CPEPrefix: cpe:/a:freetype:freetype:2.13.2
 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent
          JPEG Group) licenses"
diff --git a/third_party/freetype/src b/third_party/freetype/src
index a464242..68399b4 160000
--- a/third_party/freetype/src
+++ b/third_party/freetype/src
@@ -1 +1 @@
-Subproject commit a46424228f0998a72c715f32e18dca8a7a764c1f
+Subproject commit 68399b4244d85a1acc18ce669176b531b2eb7e32
diff --git a/third_party/polymer/v3_0/BUILD.gn b/third_party/polymer/v3_0/BUILD.gn
index b3360d5..bbf2c65 100644
--- a/third_party/polymer/v3_0/BUILD.gn
+++ b/third_party/polymer/v3_0/BUILD.gn
@@ -14,15 +14,12 @@
 js_files = [
   "iron-a11y-keys-behavior/iron-a11y-keys-behavior.js",
   "iron-a11y-keys/iron-a11y-keys.js",
-  "iron-behaviors/iron-control-state.js",
   "iron-collapse/iron-collapse.js",
   "iron-fit-behavior/iron-fit-behavior.js",
   "iron-flex-layout/iron-flex-layout-classes.js",
   "iron-icon/iron-icon.js",
   "iron-iconset-svg/iron-iconset-svg.js",
   "iron-list/iron-list.js",
-  "iron-location/iron-location.js",
-  "iron-location/iron-query-params.js",
   "iron-media-query/iron-media-query.js",
   "iron-meta/iron-meta.js",
   "iron-pages/iron-pages.js",
@@ -45,8 +42,11 @@
 if (is_chromeos_ash) {
   js_files += [
     "iron-a11y-announcer/iron-a11y-announcer.js",
+    "iron-behaviors/iron-control-state.js",
     "iron-dropdown/iron-dropdown.js",
     "iron-dropdown/iron-dropdown-scroll-manager.js",
+    "iron-location/iron-location.js",
+    "iron-location/iron-query-params.js",
     "iron-overlay-behavior/iron-focusables-helper.js",
     "iron-overlay-behavior/iron-overlay-backdrop.js",
     "iron-overlay-behavior/iron-overlay-behavior.js",
@@ -210,15 +210,13 @@
   definitions = [
     "components-chromium/iron-a11y-keys-behavior/iron-a11y-keys-behavior.d.ts",
     "components-chromium/iron-a11y-keys/iron-a11y-keys.d.ts",
-    "components-chromium/iron-behaviors/iron-control-state.d.ts",
     "components-chromium/iron-collapse/iron-collapse.d.ts",
+    "components-chromium/iron-behaviors/iron-control-state.d.ts",
     "components-chromium/iron-fit-behavior/iron-fit-behavior.d.ts",
     "components-chromium/iron-flex-layout/iron-flex-layout-classes.d.ts",
     "components-chromium/iron-icon/iron-icon.d.ts",
     "components-chromium/iron-iconset-svg/iron-iconset-svg.d.ts",
     "components-chromium/iron-list/iron-list.d.ts",
-    "components-chromium/iron-location/iron-location.d.ts",
-    "components-chromium/iron-location/iron-query-params.d.ts",
     "components-chromium/iron-media-query/iron-media-query.d.ts",
     "components-chromium/iron-meta/iron-meta.d.ts",
     "components-chromium/iron-pages/iron-pages.d.ts",
@@ -290,6 +288,8 @@
       "components-chromium/iron-a11y-announcer/iron-a11y-announcer.d.ts",
       "components-chromium/iron-dropdown/iron-dropdown.d.ts",
       "components-chromium/iron-dropdown/iron-dropdown-scroll-manager.d.ts",
+      "components-chromium/iron-location/iron-location.d.ts",
+      "components-chromium/iron-location/iron-query-params.d.ts",
       "components-chromium/iron-overlay-behavior/iron-focusables-helper.d.ts",
       "components-chromium/iron-overlay-behavior/iron-overlay-backdrop.d.ts",
       "components-chromium/iron-overlay-behavior/iron-overlay-behavior.d.ts",
diff --git a/third_party/ruy/BUILD.gn b/third_party/ruy/BUILD.gn
index 5ac4003..c8ed599 100644
--- a/third_party/ruy/BUILD.gn
+++ b/third_party/ruy/BUILD.gn
@@ -806,6 +806,7 @@
     ":ruy_mul_params",
     ":ruy_path",
     ":ruy_platform",
+    ":ruy_profiler_instrumentation",
     ":ruy_size_util",
     ":ruy_trace",
   ]
diff --git a/third_party/skia b/third_party/skia
index b4162f6..93912d5 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit b4162f6c282524637f0c1fc751809fe68597c02c
+Subproject commit 93912d50850d3f783e2e4dc51bda5667e798dddb
diff --git a/third_party/tflite/BUILD.gn b/third_party/tflite/BUILD.gn
index 1c28626..a80f824 100644
--- a/third_party/tflite/BUILD.gn
+++ b/third_party/tflite/BUILD.gn
@@ -80,7 +80,12 @@
   ]
 
   if (build_tflite_with_xnnpack) {
-    defines += [ "TFLITE_BUILD_WITH_XNNPACK_DELEGATE" ]
+    defines += [
+      "TFLITE_BUILD_WITH_XNNPACK_DELEGATE",
+      "XNNPACK_DELEGATE_ENABLE_QS8",
+      "XNNPACK_DELEGATE_ENABLE_QU8",
+      "XNNPACK_DELEGATE_USE_LATEST_OPS",
+    ]
   } else {
     defines += [ "TFLITE_WITHOUT_XNNPACK" ]
   }
@@ -192,7 +197,10 @@
 
   public_configs = [ ":tflite_config" ]
 
-  visibility = [ "//third_party/mediapipe/*" ]
+  visibility = [
+    ":tflite_benchmark",
+    "//third_party/mediapipe/*",
+  ]
 
   conditional_deps = [ ":tflite" ]
 }
@@ -799,3 +807,49 @@
   # these switches).
   public_deps_for_standalone = [ "//third_party/neon_2_sse" ]
 }
+
+executable("tflite_benchmark") {
+  sources = [
+    "src/tensorflow/lite/tools/benchmark/benchmark_main.cc",
+    "src/tensorflow/lite/tools/benchmark/benchmark_model.cc",
+    "src/tensorflow/lite/tools/benchmark/benchmark_model.h",
+    "src/tensorflow/lite/tools/benchmark/benchmark_tflite_model.cc",
+    "src/tensorflow/lite/tools/benchmark/benchmark_tflite_model.h",
+    "src/tensorflow/lite/tools/benchmark/benchmark_utils.cc",
+    "src/tensorflow/lite/tools/benchmark/benchmark_utils.h",
+    "src/tensorflow/lite/tools/benchmark/profiling_listener.cc",
+    "src/tensorflow/lite/tools/benchmark/profiling_listener.h",
+    "src/tensorflow/lite/tools/command_line_flags.cc",
+    "src/tensorflow/lite/tools/command_line_flags.h",
+    "src/tensorflow/lite/tools/delegates/delegate_provider.cc",
+    "src/tensorflow/lite/tools/delegates/delegate_provider.h",
+    "src/tensorflow/lite/tools/model_loader.cc",
+    "src/tensorflow/lite/tools/model_loader.h",
+    "src/tensorflow/lite/tools/tool_params.cc",
+    "src/tensorflow/lite/tools/tool_params.h",
+    "src/tensorflow/lite/tools/utils.cc",
+    "src/tensorflow/lite/tools/utils.h",
+  ]
+  deps = [
+    ":tflite",
+    ":tflite_builtin_op_resolver",
+    "//third_party/abseil-cpp:absl",
+    "//third_party/ruy",
+  ]
+
+  public_configs = [ ":tflite_config" ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//third_party/eigen3:eigen_includes",
+    ":tflite_flags",
+  ]
+
+  if (is_clang) {
+    cflags_cc = [
+      "-Wno-ignored-qualifiers",
+      "-Wno-defaulted-function-deleted",
+    ]
+  }
+}
diff --git a/third_party/vulkan-deps b/third_party/vulkan-deps
index f1dcf23..e2486aa9 160000
--- a/third_party/vulkan-deps
+++ b/third_party/vulkan-deps
@@ -1 +1 @@
-Subproject commit f1dcf238ad742f936794809f28b0ad0511b6585b
+Subproject commit e2486aa9a1f0cb28dfa714232dcd1d0d5ec5dca4
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 88797bf..df81c87 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -20447,6 +20447,7 @@
   <int value="-350558651" label="EnableWebHidInWebView:disabled"/>
   <int value="-350336634"
       label="ExperimentalAccessibilityDictationExtension:enabled"/>
+  <int value="-349924568" label="DrawKeyNativeEdgeToEdge:enabled"/>
   <int value="-349505266" label="ShimlessRMADisableDarkMode:enabled"/>
   <int value="-349437334" label="UseDdljsonApi:disabled"/>
   <int value="-349380607" label="AndroidNightMode:disabled"/>
@@ -22525,6 +22526,7 @@
   <int value="560369327" label="LauncherImageSearch:disabled"/>
   <int value="560953355"
       label="ExtractRelatedSearchesFromPrefetchedZPSResponse:disabled"/>
+  <int value="561162418" label="DrawKeyNativeEdgeToEdge:disabled"/>
   <int value="561374433" label="SCTAuditing:disabled"/>
   <int value="561951500" label="GlobalMediaControlsCastStartStop:enabled"/>
   <int value="562111126" label="SidePanelBorder:enabled"/>
diff --git a/tools/metrics/histograms/metadata/apps/histograms.xml b/tools/metrics/histograms/metadata/apps/histograms.xml
index b41c799e..aa0d744 100644
--- a/tools/metrics/histograms/metadata/apps/histograms.xml
+++ b/tools/metrics/histograms/metadata/apps/histograms.xml
@@ -1776,7 +1776,7 @@
     different category.
   </summary>
   <token key="AppListPage">
-    <variant name="AppCollectionsPage" summary=""/>
+    <variant name="AppsCollectionsPage" summary=""/>
     <variant name="AppsPage" summary=""/>
   </token>
   <token key="ExperimentalArm">
@@ -1799,7 +1799,7 @@
     entity that the apps belongs to (Default apps or Third-Party apps).
   </summary>
   <token key="AppListPage">
-    <variant name="AppCollectionsPage" summary=""/>
+    <variant name="AppsCollectionsPage" summary=""/>
     <variant name="AppsPage" summary=""/>
   </token>
   <token key="ExperimentalArm">
@@ -1825,7 +1825,7 @@
     if it were visible when the apps grid view is not scrolled.
   </summary>
   <token key="AppListPage">
-    <variant name="AppCollectionsPage" summary="Apps Collections page"/>
+    <variant name="AppsCollectionsPage" summary="Apps Collections page"/>
     <variant name="AppsPage" summary="Apps page"/>
   </token>
   <token key="ExperimentalArm">
@@ -1852,7 +1852,7 @@
     bucket records a particular default app.
   </summary>
   <token key="AppListPage">
-    <variant name="AppCollectionsPage" summary="Apps Collections page"/>
+    <variant name="AppsCollectionsPage" summary="Apps Collections page"/>
     <variant name="AppsPage" summary="Apps page"/>
   </token>
   <token key="ExperimentalArm">
diff --git a/tools/metrics/histograms/metadata/input/histograms.xml b/tools/metrics/histograms/metadata/input/histograms.xml
index 95669b6..b197b35 100644
--- a/tools/metrics/histograms/metadata/input/histograms.xml
+++ b/tools/metrics/histograms/metadata/input/histograms.xml
@@ -1529,6 +1529,17 @@
   </summary>
 </histogram>
 
+<histogram
+    name="InputMethod.PhysicalKeyboard.Japanese.OnFocusMigratedToSystemPk"
+    enum="Boolean" expires_after="2025-05-01">
+  <owner>jhtin@chromium.org</owner>
+  <owner>essential-inputs-team@google.com</owner>
+  <summary>
+    Logs whether user is using SystemPK (if true) or legacy extension (if false)
+    mozc when any input is focused on.
+  </summary>
+</histogram>
+
 <histogram name="InputMethod.PhysicalKeyboard.Japanese.StartupAction"
     enum="JapaneseStartupAction" expires_after="2024-11-01">
   <owner>jhtin@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/others/enums.xml b/tools/metrics/histograms/metadata/others/enums.xml
index 653102c..f30379a 100644
--- a/tools/metrics/histograms/metadata/others/enums.xml
+++ b/tools/metrics/histograms/metadata/others/enums.xml
@@ -53,6 +53,7 @@
   <int value="6" label="Tab backgrounded while screenshotting"/>
   <int value="7" label="Error: Screenshot creation failed"/>
   <int value="8" label="Error: Screenshot encoding failed"/>
+  <int value="9" label="Escape key press"/>
 </enum>
 
 <!-- LINT.ThenChange(//chrome/browser/ui/lens/lens_overlay_controller.h:DismissalSource) -->
diff --git a/tools/metrics/histograms/metadata/webauthn/enums.xml b/tools/metrics/histograms/metadata/webauthn/enums.xml
index 3f238da4..5bd84642 100644
--- a/tools/metrics/histograms/metadata/webauthn/enums.xml
+++ b/tools/metrics/histograms/metadata/webauthn/enums.xml
@@ -276,6 +276,17 @@
   <int value="3" label="Polling cancelled before finding window"/>
 </enum>
 
+<enum name="WindowsKeyCredentialCreateResult">
+  <int value="0" label="Operation succeeded"/>
+  <int value="1" label="System operation returned an error"/>
+  <int value="2" label="ActivationFactory Not Available"/>
+  <int value="3" label="RequestCreateAsync Call Failed"/>
+  <int value="4" label="PostAsyncHandlers Call Failed"/>
+  <int value="5" label="Invalid status returned"/>
+  <int value="6" label="Invalid result returned"/>
+  <int value="7" label="Invalid credential returned"/>
+</enum>
+
 <enum name="WindowsKeyCredentialManagerSupportResults">
   <int value="0" label="KeyCredentialManager Available"/>
   <int value="1" label="KeyCredentialManager Not Available"/>
@@ -285,6 +296,17 @@
   <int value="5" label="Async Operation Failed"/>
 </enum>
 
+<enum name="WindowsKeyCredentialSignResult">
+  <int value="0" label="Operation succeeded"/>
+  <int value="1" label="System operation returned an error"/>
+  <int value="2" label="RequestSignAsync call failed"/>
+  <int value="3" label="PostAsyncHandlers call failed"/>
+  <int value="4" label="IBuffer creation failed"/>
+  <int value="5" label="Invalid status returned"/>
+  <int value="6" label="Invalid result returned"/>
+  <int value="7" label="Invalid signature buffer returned"/>
+</enum>
+
 </enums>
 
 </histogram-configuration>
diff --git a/tools/metrics/histograms/metadata/webauthn/histograms.xml b/tools/metrics/histograms/metadata/webauthn/histograms.xml
index 4ed72f3..bd3cba59 100644
--- a/tools/metrics/histograms/metadata/webauthn/histograms.xml
+++ b/tools/metrics/histograms/metadata/webauthn/histograms.xml
@@ -299,6 +299,18 @@
   </summary>
 </histogram>
 
+<histogram name="WebAuthentication.Windows.KeyCredentialCreation"
+    enum="WindowsKeyCredentialCreateResult" expires_after="2024-12-31">
+  <owner>kenrb@chromium.org</owner>
+  <owner>chrome-webauthn@google.com</owner>
+  <summary>
+    Records the result of the KeyCredentialManager.RequestCreateAsync method in
+    the Windows Runtime API. It is recorded when that method is called, which
+    currently only happens following a device registration with the GPM passkey
+    enclave service.
+  </summary>
+</histogram>
+
 <histogram name="WebAuthentication.Windows.KeyCredentialManagerSupported"
     enum="WindowsKeyCredentialManagerSupportResults" expires_after="2024-12-31">
   <owner>kenrb@chromium.org</owner>
@@ -310,6 +322,18 @@
   </summary>
 </histogram>
 
+<histogram name="WebAuthentication.Windows.KeyCredentialSign"
+    enum="WindowsKeyCredentialSignResult" expires_after="2024-12-31">
+  <owner>kenrb@chromium.org</owner>
+  <owner>chrome-webauthn@google.com</owner>
+  <summary>
+    Records the result of the KeyCredential.RequestSignAsync method in the
+    Windows Runtime API. It is recorded when that method is called, which
+    currently only happens when signing a UV passkey request for the GPM passkey
+    enclave service.
+  </summary>
+</histogram>
+
 </histograms>
 
 </histogram-configuration>
diff --git a/tools/metrics/structured/sync/structured_chromiumos.xml b/tools/metrics/structured/sync/structured_chromiumos.xml
index b000ce1..aa39745 100644
--- a/tools/metrics/structured/sync/structured_chromiumos.xml
+++ b/tools/metrics/structured/sync/structured_chromiumos.xml
@@ -1680,6 +1680,175 @@
   </event>
 </project>
 
+<project name="UsbQuality">
+  <owner>jthies@google.com</owner>
+  <owner>chromeos-usb@google.com</owner>
+  <id>per-project</id>
+  <summary>
+    Project to measure USB device connectivity quality be recording USB data bus
+    and power delivery quality indicators when devices are added or removed.
+  </summary>
+
+  <event name="UsbBusConnect">
+  <summary>
+    USB quality metric recorded on device enumeration.
+  </summary>
+    <metric name="BootId" type="hmac-string">
+      <summary>
+        Random ID generated at boot time to detect reboots.
+      </summary>
+    </metric>
+    <metric name="ConnectionId" type="hmac-string">
+      <summary>
+        Unique device connection ID based on boot information, busnum and
+        devnum.
+      </summary>
+    </metric>
+    <metric name="VendorId" type="int">
+      <summary>
+        Vendor ID, obfuscated for unpopular devices.
+      </summary>
+    </metric>
+    <metric name="ProductId" type="int">
+      <summary>
+        Product ID, obfuscated for unpopular devices.
+      </summary>
+    </metric>
+    <metric name="LockScreen" type="int">
+      <summary>
+        Bool noting whether the lock screen is show. This impacts USBGuard
+        behavior.
+      </summary>
+    </metric>
+    <metric name="Speed" type="int">
+      <summary>
+        USB device speed, based on UMA metric with fallback speeds.
+      </summary>
+    </metric>
+    <metric name="DeviceClass" type="int">
+      <summary>
+        The device's USB class.
+      </summary>
+    </metric>
+    <metric name="InterfaceClass" type="int-array" max="20">
+      <summary>
+        USB class for each of the device's interfaces.
+      </summary>
+    </metric>
+    <metric name="InterfaceSubClass" type="int-array" max="20">
+      <summary>
+       USB subclass for each of the device's interfaces.
+      </summary>
+    </metric>
+    <metric name="InterfaceProtocol" type="int-array" max="20">
+      <summary>
+        Protocol for each of the device's interfaces.
+      </summary>
+    </metric>
+    <metric name="InterfaceDriver" type="int-array" max="20">
+      <summary>
+        Drivers bound to each of the device's interfaces.
+      </summary>
+    </metric>
+    <metric name="Endpoint" type="int-array" max="20">
+      <summary>
+        List of endpoints used by the devices interfaces.
+      </summary>
+    </metric>
+  </event>
+
+  <event name="UsbBusDisconnect">
+  <summary>
+    USB quality metric recorded on device disconnection.
+  </summary>
+    <metric name="BootId" type="hmac-string">
+      <summary>
+        Random ID generated at boot time to detect reboots.
+      </summary>
+    </metric>
+    <metric name="ConnectionId" type="hmac-string">
+      <summary>
+        Unique device connection ID based on boot information, busnum and
+        devnum.
+      </summary>
+    </metric>
+    <metric name="VendorId" type="int">
+      <summary>
+        Vendor ID, obfuscated for unpopular devices.
+      </summary>
+    </metric>
+    <metric name="ProductId" type="int">
+      <summary>
+        Product ID, obfuscated for unpopular devices.
+      </summary>
+    </metric>
+    <metric name="DeviceError" type="int-array" max="10">
+      <summary>
+        List of USB errors in dmesg attributable to the device at when it is
+        disconnected.
+      </summary>
+    </metric>
+  </event>
+
+  <event name="UsbPdConnect">
+  <summary>
+    USB quality metric recorded on shortly after USB PD device registration.
+  </summary>
+    <metric name="BootId" type="hmac-string">
+      <summary>
+        Random ID generated at boot time to detect reboots.
+      </summary>
+    </metric>
+    <metric name="Usb2ConnectionId" type="hmac-string">
+      <summary>
+        Unique device connection ID based on boot information, busnum and
+        devnum if the USB PD device includes an internal USB 2.0 device.
+      </summary>
+    </metric>
+    <metric name="Usb3ConnectionId" type="hmac-string">
+      <summary>
+        Unique device connection ID based on boot information, busnum and
+        devnum if the USB PD device includes an internal USB 3.2 device.
+      </summary>
+    </metric>
+    <metric name="VendorId" type="int">
+      <summary>
+        Vendor ID, obfuscated for unpopular devices.
+      </summary>
+    </metric>
+    <metric name="ProductId" type="int">
+      <summary>
+        Product ID, obfuscated for unpopular devices.
+      </summary>
+    </metric>
+    <metric name="PartnerType" type="int">
+      <summary>
+        Partner category derived from USB PD identity and mode support.
+      </summary>
+    </metric>
+    <metric name="CableType" type="int">
+      <summary>
+        Cable category derived from USB PD identity and mode support.
+      </summary>
+    </metric>
+    <metric name="MaxChargingRate" type="int">
+      <summary>
+        Wattage of highest available PDO.
+      </summary>
+    </metric>
+    <metric name="RealizedChargingRate" type="int">
+      <summary>
+        Wattage the port is sinking if applicable.
+      </summary>
+    </metric>
+    <metric name="ModeEntryResult" type="int">
+      <summary>
+        Enum specifying the attempted mode entered and a pass/fail result.
+      </summary>
+    </metric>
+  </event>
+</project>
+
 <project name="UsbError">
   <owner>jthies@google.com</owner>
   <owner>chromeos-usb@google.com</owner>
diff --git a/ui/gl/gl_angle_util_win.cc b/ui/gl/gl_angle_util_win.cc
index d06ec3d..18e6b7f 100644
--- a/ui/gl/gl_angle_util_win.cc
+++ b/ui/gl/gl_angle_util_win.cc
@@ -13,17 +13,15 @@
 #include "ui/gl/gl_surface_egl.h"
 
 namespace gl {
-
-void* QueryDeviceObjectFromANGLE(int object_type) {
+namespace {
+void* QueryDeviceObjectFromANGLE(EGLDisplay egl_display, int object_type) {
   TRACE_EVENT0("gpu", "QueryDeviceObjectFromANGLE");
-
-  EGLDisplay egl_display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
   if (egl_display == EGL_NO_DISPLAY) {
     DVLOG(1) << "Failed to retrieve EGLDisplay";
     return nullptr;
   }
 
-  if (!gl::g_driver_egl.client_ext.b_EGL_EXT_device_query) {
+  if (!g_driver_egl.client_ext.b_EGL_EXT_device_query) {
     DVLOG(1) << "EGL_EXT_device_query not supported";
     return nullptr;
   }
@@ -48,18 +46,29 @@
 
   return reinterpret_cast<void*>(device);
 }
+}  // namespace
 
 Microsoft::WRL::ComPtr<ID3D11Device> QueryD3D11DeviceObjectFromANGLE() {
+  auto* display = GLSurfaceEGL::GetGLDisplayEGL();
+  if (!display || (display->GetDisplayType() != ANGLE_D3D11 &&
+                   display->GetDisplayType() != ANGLE_D3D11_NULL &&
+                   display->GetDisplayType() != ANGLE_D3D11on12)) {
+    return nullptr;
+  }
   Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device;
-  d3d11_device = reinterpret_cast<ID3D11Device*>(
-      QueryDeviceObjectFromANGLE(EGL_D3D11_DEVICE_ANGLE));
+  d3d11_device = reinterpret_cast<ID3D11Device*>(QueryDeviceObjectFromANGLE(
+      display->GetDisplay(), EGL_D3D11_DEVICE_ANGLE));
   return d3d11_device;
 }
 
 Microsoft::WRL::ComPtr<IDirect3DDevice9> QueryD3D9DeviceObjectFromANGLE() {
+  auto* display = GLSurfaceEGL::GetGLDisplayEGL();
+  if (!display || display->GetDisplayType() != ANGLE_D3D9) {
+    return nullptr;
+  }
   Microsoft::WRL::ComPtr<IDirect3DDevice9> d3d9_device;
   d3d9_device = reinterpret_cast<IDirect3DDevice9*>(
-      QueryDeviceObjectFromANGLE(EGL_D3D9_DEVICE_ANGLE));
+      QueryDeviceObjectFromANGLE(display->GetDisplay(), EGL_D3D9_DEVICE_ANGLE));
   return d3d9_device;
 }
 
diff --git a/ui/views/accessibility/view_accessibility.cc b/ui/views/accessibility/view_accessibility.cc
index 36b5b849..2d524f0 100644
--- a/ui/views/accessibility/view_accessibility.cc
+++ b/ui/views/accessibility/view_accessibility.cc
@@ -35,6 +35,7 @@
     // These roles all have special meaning and shouldn't ever be
     // set on a View.
     case ax::mojom::Role::kDesktop:
+    case ax::mojom::Role::kDocument:  // Used for ARIA role="document".
     case ax::mojom::Role::kIframe:
     case ax::mojom::Role::kIframePresentational:
     case ax::mojom::Role::kPdfRoot:
@@ -44,18 +45,6 @@
     case ax::mojom::Role::kUnknown:
       return false;
 
-    // The role kDocument should not be allowed on Views, but it needs to be
-    // allowed temporarily for the CaptionBubbleLabel view. This is because the
-    // CaptionBubbleLabel is designed to be interacted with by a braille display
-    // in virtual buffer mode. In order to activate the virtual buffer in NVDA,
-    // we set the role to kDocument and the readonly restriction.
-    //
-    // TODO(crbug.com/339479333): Investigate this further to either add a
-    // views-specific role that maps to the document role on the various
-    // platform APIs, or remove this comment and update the allowed usage of the
-    // kDocument role.
-    case ax::mojom::Role::kDocument:  // Used for ARIA role="document".
-      return true;
     default:
       return true;
   }
@@ -194,18 +183,6 @@
     return;
   }
 
-  // The role and the name needs to be set on the data member passed to
-  // View::GetAccessibleNodeData in case the view changes either or both.
-  //
-  // TODO(accessibility): This won't be necessary once all Views initialize
-  // their role and name in Views::GetAccessibleNodeData, and that function
-  // is only called once to initialize the cached data.
-  data->role = data_.role;
-  data->SetNameFrom(GetCachedNameFrom());
-  if (!GetCachedName().empty()) {
-    data->SetName(GetCachedName());
-  }
-
   view_->GetAccessibleNodeData(data);
 
   // TODO(accessibility): This next check should be added to SetRole.
@@ -364,7 +341,7 @@
     if (name_from.has_value()) {
       SetName(name.value(), name_from.value());
     } else {
-      SetName(name.value());
+      SetName(name.value(), ax::mojom::NameFrom::kAttribute);
     }
   }
 
@@ -460,14 +437,16 @@
   SetRole(role);
 }
 
-void ViewAccessibility::SetName(std::u16string name,
+void ViewAccessibility::SetName(const std::string& name,
                                 ax::mojom::NameFrom name_from) {
-  // Allow subclasses to adjust the name.
-  view_->AdjustAccessibleName(name, name_from);
-
+  DCHECK_NE(name_from, ax::mojom::NameFrom::kNone);
   // Ensure we have a current `name_from` value. For instance, the name might
   // still be an empty string, but a view is now indicating that this is by
   // design by setting `NameFrom::kAttributeExplicitlyEmpty`.
+  DCHECK_EQ(name.empty(),
+            name_from == ax::mojom::NameFrom::kAttributeExplicitlyEmpty)
+      << "If the name is being removed to improve the user experience, "
+         "|name_from| should be set to |kAttributeExplicitlyEmpty|.";
   data_.SetNameFrom(name_from);
 
   if (name == GetCachedName()) {
@@ -492,22 +471,23 @@
     data_.SetName(name);
   }
 
-  view_->OnAccessibleNameChanged(name);
   NotifyEvent(ax::mojom::Event::kTextChanged, true);
 }
 
-void ViewAccessibility::SetName(const std::string& name,
+void ViewAccessibility::SetName(const std::u16string& name,
                                 ax::mojom::NameFrom name_from) {
-  std::u16string string_name = base::UTF8ToUTF16(name);
+  std::string string_name = base::UTF16ToUTF8(name);
   SetName(string_name, name_from);
 }
 
 void ViewAccessibility::SetName(const std::string& name) {
-  SetName(name, GetCachedNameFrom());
+  SetName(name, static_cast<ax::mojom::NameFrom>(data_.GetIntAttribute(
+                    ax::mojom::IntAttribute::kNameFrom)));
 }
 
 void ViewAccessibility::SetName(const std::u16string& name) {
-  SetName(name, GetCachedNameFrom());
+  SetName(name, static_cast<ax::mojom::NameFrom>(data_.GetIntAttribute(
+                    ax::mojom::IntAttribute::kNameFrom)));
 }
 
 void ViewAccessibility::SetName(View& naming_view) {
@@ -528,7 +508,8 @@
     DCHECK(!name.empty());
     SetName(name, ax::mojom::NameFrom::kRelatedElement);
   } else {
-    std::u16string name = naming_view.GetViewAccessibility().GetCachedName();
+    const std::string& name =
+        naming_view.GetViewAccessibility().GetCachedName();
     DCHECK(!name.empty());
     SetName(name, ax::mojom::NameFrom::kRelatedElement);
   }
@@ -538,8 +519,8 @@
       {naming_view.GetViewAccessibility().GetUniqueId().Get()});
 }
 
-std::u16string ViewAccessibility::GetCachedName() const {
-  return data_.GetString16Attribute(ax::mojom::StringAttribute::kName);
+const std::string& ViewAccessibility::GetCachedName() const {
+  return data_.GetStringAttribute(ax::mojom::StringAttribute::kName);
 }
 
 ax::mojom::NameFrom ViewAccessibility::GetCachedNameFrom() const {
@@ -632,7 +613,8 @@
 void ViewAccessibility::SetDescription(View& describing_view) {
   DCHECK_NE(view_, &describing_view);
 
-  std::u16string name = describing_view.GetViewAccessibility().GetCachedName();
+  const std::string& name =
+      describing_view.GetViewAccessibility().GetCachedName();
   if (name.empty()) {
     // TODO(javiercon): This is a temporary workaround for the scenarios where
     // the name is set via View::SetAccessibleName, which means that
diff --git a/ui/views/accessibility/view_accessibility.h b/ui/views/accessibility/view_accessibility.h
index d48587e..40cd6617 100644
--- a/ui/views/accessibility/view_accessibility.h
+++ b/ui/views/accessibility/view_accessibility.h
@@ -180,7 +180,7 @@
   // follow the established pattern and be named GetName()
   // TODO(accessibility): Rename to GetName once the ViewsAX project is
   // completed and we don't have ViewAXPlatformNodeDelegate anymore.
-  std::u16string GetCachedName() const;
+  const std::string& GetCachedName() const;
 
   // Returns the source type of the accessible name.
   //
@@ -212,10 +212,10 @@
   // * kTitle: Name from a title attribute or element (HTML or SVG).
   // * kValue: Name from a value attribute (e.g. button).
   // * kPopoverAttribute: Name from a tooltip-style popover.
-  void SetName(std::u16string name, ax::mojom::NameFrom name_from);
   void SetName(const std::string& name, ax::mojom::NameFrom name_from);
-  void SetName(const std::u16string& name);
+  void SetName(const std::u16string& name, ax::mojom::NameFrom name_from);
   void SetName(const std::string& name);
+  void SetName(const std::u16string& name);
 
   // Sets the accessible name of this view to that of `naming_view`. Often
   // `naming_view` is a `views::Label`, but any view with an accessible name
@@ -411,8 +411,6 @@
   AccessibilityEventsCallback accessibility_events_callback_;
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(ViewTest, PauseAccessibilityEvents);
-
   // Prune/Unprune all descendant views from the accessibility tree. We prune
   // for two reasons: 1) The view has been explicitly marked as a leaf node, 2)
   // The view is focusable and lacks focusable descendants (e.g. a button with a
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc b/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
index f169707..1cd13d8 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
+++ b/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
@@ -471,6 +471,21 @@
   EXPECT_EQ(button_accessibility()->GetDescriptionFrom(),
             ax::mojom::DescriptionFrom::kNone);
 
+  // Setting the name to the empty string without explicitly setting the
+  // source to reflect that should trigger a DCHECK in SetName.
+  EXPECT_DCHECK_DEATH_WITH(
+      button_accessibility()->SetName("", ax::mojom::NameFrom::kAttribute),
+      "Check failed: name.empty\\(\\) == name_from == "
+      "ax::mojom::NameFrom::kAttributeExplicitlyEmpty");
+
+  // Setting the name to a non-empty string with a NameFrom of
+  // kAttributeExplicitlyEmpty should trigger a DCHECK in SetName.
+  EXPECT_DCHECK_DEATH_WITH(
+      button_accessibility()->SetName(
+          "foo", ax::mojom::NameFrom::kAttributeExplicitlyEmpty),
+      "Check failed: name.empty\\(\\) == name_from == "
+      "ax::mojom::NameFrom::kAttributeExplicitlyEmpty");
+
   button_accessibility()->SetName(
       "", ax::mojom::NameFrom::kAttributeExplicitlyEmpty);
   EXPECT_EQ(button_accessibility()->GetName(), "");
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.cc b/ui/views/bubble/bubble_dialog_delegate_view.cc
index b71aa33..ba9a0e39 100644
--- a/ui/views/bubble/bubble_dialog_delegate_view.cc
+++ b/ui/views/bubble/bubble_dialog_delegate_view.cc
@@ -455,9 +455,6 @@
   set_footnote_margins(
       layout_provider->GetInsetsMetric(INSETS_DIALOG_FOOTNOTE));
 
-  set_desired_bounds_delegate(base::BindRepeating(
-      &BubbleDialogDelegate::GetDesiredBubbleBounds, base::Unretained(this)));
-
   RegisterWidgetInitializedCallback(base::BindOnce(
       [](BubbleDialogDelegate* bubble_delegate) {
         bubble_delegate->theme_observer_ =
@@ -955,7 +952,7 @@
   return ax::mojom::Role::kAlertDialog;
 }
 
-gfx::Rect BubbleDialogDelegate::GetDesiredBubbleBounds() {
+gfx::Rect BubbleDialogDelegate::GetDesiredWidgetBounds() {
   CHECK(use_custom_frame())
       << "GetBubbleBounds() for native frame dialogs is not supported.";
 
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.h b/ui/views/bubble/bubble_dialog_delegate_view.h
index 0262f11..dbc98f9 100644
--- a/ui/views/bubble/bubble_dialog_delegate_view.h
+++ b/ui/views/bubble/bubble_dialog_delegate_view.h
@@ -58,6 +58,9 @@
   ClientView* CreateClientView(Widget* widget) override;
   ax::mojom::Role GetAccessibleWindowRole() final;
 
+  // WidgetDelegate:
+  gfx::Rect GetDesiredWidgetBounds() final;
+
   // Create and initialize the bubble Widget with proper bounds.
   static Widget* CreateBubble(
       std::unique_ptr<BubbleDialogDelegate> bubble_delegate);
@@ -452,8 +455,6 @@
 
   void SetAnchoredDialogKey();
 
-  gfx::Rect GetDesiredBubbleBounds();
-
   gfx::Insets title_margins_;
   gfx::Insets footnote_margins_;
   BubbleBorder::Arrow arrow_ = BubbleBorder::NONE;
diff --git a/ui/views/controls/label.cc b/ui/views/controls/label.cc
index 2c773355..5fc895a 100644
--- a/ui/views/controls/label.cc
+++ b/ui/views/controls/label.cc
@@ -115,12 +115,7 @@
   ClearDisplayText();
 
   if (GetAccessibleName().empty() || GetAccessibleName() == current_text) {
-    if (new_text.empty()) {
-      SetAccessibleName(new_text,
-                        ax::mojom::NameFrom::kAttributeExplicitlyEmpty);
-    } else {
-      SetAccessibleName(new_text);
-    }
+    SetAccessibleName(new_text);
   }
 
   OnPropertyChanged(&full_text_ + kLabelText,
diff --git a/ui/views/view.cc b/ui/views/view.cc
index 30c39729..86a3c4a70 100644
--- a/ui/views/view.cc
+++ b/ui/views/view.cc
@@ -237,6 +237,8 @@
     SetProperty(kViewStackTraceKey,
                 std::make_unique<base::debug::StackTrace>());
   }
+
+  ax_node_data_ = std::make_unique<ui::AXNodeData>();
 }
 
 View::~View() {
@@ -2078,6 +2080,19 @@
   return *view_accessibility_;
 }
 
+void View::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+  // `ViewAccessibility::GetAccessibleNodeData` populates the id and classname
+  // values prior to asking the View for its data. We don't want to stomp on
+  // those values.
+  ax_node_data_->id = node_data->id;
+  ax_node_data_->AddStringAttribute(
+      ax::mojom::StringAttribute::kClassName,
+      node_data->GetStringAttribute(ax::mojom::StringAttribute::kClassName));
+
+  // Copy everything set by the property setters.
+  *node_data = *ax_node_data_;
+}
+
 void View::SetAccessibilityProperties(
     std::optional<ax::mojom::Role> role,
     std::optional<std::u16string> name,
@@ -2085,39 +2100,138 @@
     std::optional<std::u16string> role_description,
     std::optional<ax::mojom::NameFrom> name_from,
     std::optional<ax::mojom::DescriptionFrom> description_from) {
-  GetViewAccessibility().SetProperties(
-      role, name, description, role_description, name_from, description_from);
+  // TODO(accessibility): Remove this attribute once we migrate the
+  // SetAccessibilityProperties function to ViewAccessibility.
+  base::AutoReset<bool> initializing(&pause_accessibility_events_, true);
+  if (role.has_value()) {
+    if (role_description.has_value()) {
+      SetAccessibleRole(role.value(), role_description.value());
+    } else {
+      SetAccessibleRole(role.value());
+    }
+  }
+
+  // Defining the NameFrom value without specifying the name doesn't make much
+  // sense. The only exception might be if the NameFrom is setting the name to
+  // explicitly empty. In order to prevent surprising/confusing behavior, we
+  // only use the NameFrom value if we have an explicit name. As a result, any
+  // caller setting the name to explicitly empty must set the name to an empty
+  // string.
+  if (name.has_value()) {
+    if (name_from.has_value()) {
+      SetAccessibleName(name.value(), name_from.value());
+    } else {
+      SetAccessibleName(name.value());
+    }
+  }
+
+  // See the comment above regarding the NameFrom value.
+  if (description.has_value()) {
+    if (description_from.has_value()) {
+      GetViewAccessibility().SetDescription(description.value(),
+                                            description_from.value());
+    } else {
+      GetViewAccessibility().SetDescription(description.value());
+    }
+  }
 }
 
 void View::SetAccessibleName(const std::u16string& name) {
-  SetAccessibleName(name, GetViewAccessibility().GetCachedNameFrom());
+  SetAccessibleName(
+      name, static_cast<ax::mojom::NameFrom>(ax_node_data_->GetIntAttribute(
+                ax::mojom::IntAttribute::kNameFrom)));
 }
 
 void View::SetAccessibleName(std::u16string name,
                              ax::mojom::NameFrom name_from) {
-  GetViewAccessibility().SetName(name, name_from);
+  // Allow subclasses to adjust the name.
+  AdjustAccessibleName(name, name_from);
+
+  // Ensure we have a current `name_from` value. For instance, the name might
+  // still be an empty string, but a view is now indicating that this is by
+  // design by setting `NameFrom::kAttributeExplicitlyEmpty`.
+  ax_node_data_->SetNameFrom(name_from);
+
+  if (name == accessible_name_) {
+    return;
+  }
+
+  if (name.empty()) {
+    ax_node_data_->RemoveStringAttribute(ax::mojom::StringAttribute::kName);
+  } else if (ax_node_data_->role != ax::mojom::Role::kUnknown &&
+             ax_node_data_->role != ax::mojom::Role::kNone) {
+    // TODO(accessibility): This is to temporarily work around the DCHECK
+    // in `AXNodeData` that wants to have a role to calculate a name-from.
+    // If we don't have a role yet, don't add it to the data until we do.
+    // See `SetAccessibleRole` where we check for and handle this condition.
+    // Also note that the `SetAccessibilityProperties` function allows view
+    // authors to set the role and name at once, if all views use it, we can
+    // remove this workaround.
+    ax_node_data_->SetName(name);
+  }
+
+  accessible_name_ = name;
+  OnPropertyChanged(&accessible_name_, kPropertyEffectsNone);
+  OnAccessibleNameChanged(name);
+  NotifyAccessibilityEvent(ax::mojom::Event::kTextChanged, true);
 }
 
 void View::SetAccessibleName(View* naming_view) {
   DCHECK(naming_view);
-  GetViewAccessibility().SetName(*naming_view);
+  DCHECK_NE(this, naming_view);
+
+  const std::u16string& name = naming_view->GetAccessibleName();
+  DCHECK(!name.empty());
+
+  SetAccessibleName(name, ax::mojom::NameFrom::kRelatedElement);
+  ax_node_data_->AddIntListAttribute(
+      ax::mojom::IntListAttribute::kLabelledbyIds,
+      {naming_view->GetViewAccessibility().GetUniqueId().Get()});
 }
 
-std::u16string View::GetAccessibleName() const {
-  return GetViewAccessibility().GetCachedName();
+const std::u16string& View::GetAccessibleName() const {
+  return accessible_name_;
 }
 
 void View::SetAccessibleRole(const ax::mojom::Role role) {
-  GetViewAccessibility().SetRole(role);
+  if (role == accessible_role_) {
+    return;
+  }
+
+  ax_node_data_->role = role;
+  if (role != ax::mojom::Role::kUnknown && role != ax::mojom::Role::kNone) {
+    if (ax_node_data_->GetStringAttribute(ax::mojom::StringAttribute::kName)
+            .empty() &&
+        !accessible_name_.empty()) {
+      // TODO(accessibility): This is to temporarily work around the DCHECK
+      // that wants to have a role to calculate a name-from. If we have a
+      // name in our properties but not in our `AXNodeData`, the name was
+      // set prior to the role. Now that we have a valid role, we can set
+      // the name. See `SetAccessibleName` for where we delayed setting it.
+      ax_node_data_->SetName(accessible_name_);
+    }
+  }
+
+  accessible_role_ = role;
+  OnPropertyChanged(&accessible_role_, kPropertyEffectsNone);
 }
 
 void View::SetAccessibleRole(const ax::mojom::Role role,
                              const std::u16string& role_description) {
-  GetViewAccessibility().SetRole(role, role_description);
+  if (!role_description.empty()) {
+    ax_node_data_->AddStringAttribute(
+        ax::mojom::StringAttribute::kRoleDescription,
+        base::UTF16ToUTF8(role_description));
+  } else {
+    ax_node_data_->RemoveStringAttribute(
+        ax::mojom::StringAttribute::kRoleDescription);
+  }
+
+  SetAccessibleRole(role);
 }
 
 ax::mojom::Role View::GetAccessibleRole() const {
-  return GetViewAccessibility().GetCachedRole();
+  return accessible_role_;
 }
 
 void View::SetAccessibleDescription(const std::u16string& description) {
@@ -2186,6 +2300,16 @@
 
 void View::NotifyAccessibilityEvent(ax::mojom::Event event_type,
                                     bool send_native_event) {
+  // TODO(accessibility): Remove this condition once we migrate the
+  // SetAccessibilityProperties function to ViewAccessibility.
+  //
+  // If `pause_accessibility_events_` is true, it means we are initializing
+  // property values. In this specific case, we do not want to notify platform
+  // assistive technologies that a property has changed.
+  if (pause_accessibility_events_) {
+    return;
+  }
+
   GetViewAccessibility().NotifyEvent(event_type, send_native_event);
 }
 
diff --git a/ui/views/view.h b/ui/views/view.h
index 4024ec97..e21731a 100644
--- a/ui/views/view.h
+++ b/ui/views/view.h
@@ -1497,7 +1497,7 @@
   // Get the object managing the accessibility interface for this View.
   ViewAccessibility& GetViewAccessibility() const;
 
-  // Modifies `node_data` to reflect the current accessible state of this view.
+  // Modifies |node_data| to reflect the current accessible state of this view.
   // It accomplishes this by keeping the data up-to-date in response to the use
   // of the accessible-property setters.
   // NOTE: View authors should use the available property setters rather than
@@ -1507,10 +1507,8 @@
   // parent class. This ensures that if an owning view customizes an accessible
   // property, such as the name, role, or description, that customization is
   // included in your view's `AXNodeData`.
-  virtual void GetAccessibleNodeData(ui::AXNodeData* node_data) {}
+  virtual void GetAccessibleNodeData(ui::AXNodeData* node_data);
 
-  // DEPRECATED: Use `ViewAccessibility::SetName` instead.
-  //
   // Sets/gets the accessible name.
   // The value of the accessible name is a localized, end-user-consumable string
   // which may be derived from visible information (e.g. the text on a button)
@@ -1519,13 +1517,8 @@
   // reader when that object gains focus and is critical to understanding the
   // purpose of that object non-visually.
   void SetAccessibleName(const std::u16string& name);
+  const std::u16string& GetAccessibleName() const;
 
-  // This function is deprecated. Use `ViewAccessibility::GetCachedName`
-  // instead.
-  std::u16string GetAccessibleName() const;
-
-  // DEPRECATED: Use `ViewAccessibility::SetName` instead.
-  //
   // Sets the accessible name to the specified string and source type.
   // To indicate that this view should never have an accessible name, e.g. to
   // prevent screen readers from speaking redundant information, set the type to
@@ -1535,8 +1528,6 @@
   // especially for views which are focusable or otherwise interactive.
   void SetAccessibleName(std::u16string name, ax::mojom::NameFrom name_from);
 
-  // DEPRECATED: Use `ViewAccessibility::SetName` instead.
-  //
   // Sets the accessible name of this view to that of `naming_view`. Often
   // `naming_view` is a `views::Label`, but any view with an accessible name
   // will work.
@@ -1628,16 +1619,6 @@
   void RemoveObserver(ViewObserver* observer);
   bool HasObserver(const ViewObserver* observer) const;
 
-  // Called when the accessible name of the View changed.
-  virtual void OnAccessibleNameChanged(const std::u16string& new_name) {}
-
-  // Called by `SetAccessibleName` to allow subclasses to adjust the new name.
-  // Potential use cases include setting the accessible name to the tooltip
-  // text when the new name is empty and prepending/appending additional text
-  // to the new name.
-  virtual void AdjustAccessibleName(std::u16string& new_name,
-                                    ax::mojom::NameFrom& name_from) {}
-
   // View Controller Interfaces -----------------------------------------------
   // These functions provide a common interface for view controllers to interact
   // with views.
@@ -1699,6 +1680,16 @@
       std::optional<ax::mojom::DescriptionFrom> description_from =
           std::nullopt);
 
+  // Called when the accessible name of the View changed.
+  virtual void OnAccessibleNameChanged(const std::u16string& new_name) {}
+
+  // Called by `SetAccessibleName` to allow subclasses to adjust the new name.
+  // Potential use cases include setting the accessible name to the tooltip
+  // text when the new name is empty and prepending/appending additional text
+  // to the new name.
+  virtual void AdjustAccessibleName(std::u16string& new_name,
+                                    ax::mojom::NameFrom& name_from) {}
+
   // Size and disposition ------------------------------------------------------
 
   // Calculates the preferred size for the View given `available_size`.
@@ -1950,6 +1941,7 @@
   FRIEND_TEST_ALL_PREFIXES(ViewTest, PaintWithMovedViewUsesCache);
   FRIEND_TEST_ALL_PREFIXES(ViewTest, PaintWithMovedViewUsesCacheInRTL);
   FRIEND_TEST_ALL_PREFIXES(ViewTest, PaintWithUnknownInvalidation);
+  FRIEND_TEST_ALL_PREFIXES(ViewTest, PauseAccessibilityEvents);
 
   // Painting  -----------------------------------------------------------------
 
@@ -2493,11 +2485,28 @@
   // Manages the accessibility interface for this View.
   mutable std::unique_ptr<ViewAccessibility> view_accessibility_;
 
+  // Updated by the accessibility property setters and returned by
+  // `GetAccessibleNodeData`.
+  std::unique_ptr<ui::AXNodeData> ax_node_data_;
+
+  // TODO(accessibility): Remove this attribute once we migrate the
+  // SetAccessibilityProperties function to ViewAccessibility.
+  //
+  // Used by `SetAccessibilityProperties` and to prevent accessibility
+  // property-change events from being fired during initialization of this view.
+  bool pause_accessibility_events_ = false;
+
   // Keeps track of whether accessibility checks for this View have run yet.
   // They run once inside ::OnPaint() to keep overhead low. The idea is that if
   // a View is ready to paint it should also be set up to be accessible.
   bool has_run_accessibility_paint_checks_ = false;
 
+  // Accessible properties whose values are set by views using the accessible
+  // property setters, and used to populate the `AXNodeData` associated with
+  // this view and provided by `View::GetAccessibleNodeData`.
+  std::u16string accessible_name_;
+  ax::mojom::Role accessible_role_ = ax::mojom::Role::kUnknown;
+
   // Observers -----------------------------------------------------------------
 
   base::ObserverList<ViewObserver>::Unchecked observers_;
diff --git a/ui/views/view_unittest.cc b/ui/views/view_unittest.cc
index ffa8b55..ac177a5b 100644
--- a/ui/views/view_unittest.cc
+++ b/ui/views/view_unittest.cc
@@ -518,29 +518,29 @@
 TEST_F(ViewTest, PauseAccessibilityEvents) {
   TestView v;
   v.SetAccessibleRole(ax::mojom::Role::kStaticText);
-  EXPECT_EQ(v.GetViewAccessibility().pause_accessibility_events_, false);
+  EXPECT_EQ(v.pause_accessibility_events_, false);
 
   // Setting the accessible name when `pause_accessibility_events_` is false
   // should result in an event being fired.
   v.last_a11y_event_ = ax::mojom::Event::kNone;
   v.SetAccessibleName(u"Name");
   EXPECT_EQ(v.last_a11y_event_, ax::mojom::Event::kTextChanged);
-  EXPECT_EQ(v.GetViewAccessibility().pause_accessibility_events_, false);
+  EXPECT_EQ(v.pause_accessibility_events_, false);
 
   // Setting the accessible name when `pause_accessibility_events_` is true
   // should result in no event being fired.
   v.last_a11y_event_ = ax::mojom::Event::kNone;
-  v.GetViewAccessibility().pause_accessibility_events_ = true;
+  v.pause_accessibility_events_ = true;
   v.SetAccessibleName(u"New Name");
   EXPECT_EQ(v.last_a11y_event_, ax::mojom::Event::kNone);
-  EXPECT_EQ(v.GetViewAccessibility().pause_accessibility_events_, true);
+  EXPECT_EQ(v.pause_accessibility_events_, true);
 
   // A11yTestView views are constructed using `SetAccessibilityProperties`. By
   // default, `pause_accessibility_events_` is false. It is temporarily set to
   // true and then reset at the end of initialization.
   A11yTestView ax_v(ax::mojom::Role::kButton, u"Name", u"Description");
   EXPECT_EQ(ax_v.last_a11y_event_, ax::mojom::Event::kNone);
-  EXPECT_EQ(ax_v.GetViewAccessibility().pause_accessibility_events_, false);
+  EXPECT_EQ(ax_v.pause_accessibility_events_, false);
 }
 
 TEST_F(ViewTest, SetAccessibilityPropertiesRoleNameDescription) {
@@ -851,6 +851,78 @@
             ax::mojom::NameFrom::kAttributeExplicitlyEmpty);
 }
 
+TEST_F(ViewTest, SetAccessibleNameToStringRoleNotInitiallySet) {
+  TestView v;
+  ui::AXNodeData data = ui::AXNodeData();
+  v.GetViewAccessibility().GetAccessibleNodeData(&data);
+  EXPECT_EQ(v.GetAccessibleName(), u"");
+  EXPECT_EQ(data.GetString16Attribute(ax::mojom::StringAttribute::kName), u"");
+
+  v.last_a11y_event_ = ax::mojom::Event::kNone;
+  data = ui::AXNodeData();
+
+  // Setting the name prior to setting the role violates an expectation of
+  // `AXNodeData::SetName`. `View::SetAccessibleName` handles that case by
+  // setting the property but not adding it to `ax_node_data_` until a role
+  // has been set.
+  v.SetAccessibleName(u"Name");
+  v.GetViewAccessibility().GetAccessibleNodeData(&data);
+  EXPECT_EQ(v.GetAccessibleName(), u"Name");
+  EXPECT_EQ(data.GetString16Attribute(ax::mojom::StringAttribute::kName), u"");
+  EXPECT_EQ(v.last_a11y_event_, ax::mojom::Event::kTextChanged);
+
+  v.last_a11y_event_ = ax::mojom::Event::kNone;
+  data = ui::AXNodeData();
+
+  // Setting the role to a valid role should add the previously-set name to
+  // ax_node_data_. Note there is currently no role-changed accessibility event.
+  v.SetAccessibleRole(ax::mojom::Role::kButton);
+  v.GetViewAccessibility().GetAccessibleNodeData(&data);
+  EXPECT_EQ(v.GetAccessibleName(), u"Name");
+  EXPECT_EQ(data.GetString16Attribute(ax::mojom::StringAttribute::kName),
+            u"Name");
+  EXPECT_EQ(v.last_a11y_event_, ax::mojom::Event::kNone);
+
+  v.last_a11y_event_ = ax::mojom::Event::kNone;
+  data = ui::AXNodeData();
+}
+
+TEST_F(ViewTest, SetAccessibleNameToLabelRoleNotInitiallySet) {
+  TestView label;
+  label.SetAccessibleName(u"Label's Name");
+
+  TestView v;
+  ui::AXNodeData data = ui::AXNodeData();
+  v.GetViewAccessibility().GetAccessibleNodeData(&data);
+  EXPECT_EQ(v.GetAccessibleName(), u"");
+  EXPECT_EQ(data.GetString16Attribute(ax::mojom::StringAttribute::kName), u"");
+
+  v.last_a11y_event_ = ax::mojom::Event::kNone;
+  data = ui::AXNodeData();
+
+  // Setting the name prior to setting the role violates an expectation of
+  // `AXNodeData::SetName`. `View::SetAccessibleName` handles that case by
+  // setting the property but not adding it to `ax_node_data_` until a role
+  // has been set.
+  v.SetAccessibleName(&label);
+  v.GetViewAccessibility().GetAccessibleNodeData(&data);
+  EXPECT_EQ(v.GetAccessibleName(), u"Label's Name");
+  EXPECT_EQ(data.GetString16Attribute(ax::mojom::StringAttribute::kName), u"");
+  EXPECT_EQ(v.last_a11y_event_, ax::mojom::Event::kTextChanged);
+
+  v.last_a11y_event_ = ax::mojom::Event::kNone;
+  data = ui::AXNodeData();
+
+  // Setting the role to a valid role should add the previously-set name to
+  // ax_node_data_. Note there is currently no role-changed accessibility event.
+  v.SetAccessibleRole(ax::mojom::Role::kButton);
+  v.GetViewAccessibility().GetAccessibleNodeData(&data);
+  EXPECT_EQ(v.GetAccessibleName(), u"Label's Name");
+  EXPECT_EQ(data.GetString16Attribute(ax::mojom::StringAttribute::kName),
+            u"Label's Name");
+  EXPECT_EQ(v.last_a11y_event_, ax::mojom::Event::kNone);
+}
+
 TEST_F(ViewTest, SetAccessibleDescriptionToString) {
   TestView v;
   ui::AXNodeData data = ui::AXNodeData();
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
index 389e718..0490b0f8 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -486,7 +486,7 @@
 }
 
 bool DesktopWindowTreeHostPlatform::IsVisible() const {
-  return platform_window()->IsVisible();
+  return platform_window() && platform_window()->IsVisible();
 }
 
 void DesktopWindowTreeHostPlatform::SetSize(const gfx::Size& size) {
diff --git a/ui/views/widget/widget_delegate.cc b/ui/views/widget/widget_delegate.cc
index 7d7f1c9..d9273f4 100644
--- a/ui/views/widget/widget_delegate.cc
+++ b/ui/views/widget/widget_delegate.cc
@@ -514,10 +514,6 @@
 gfx::Rect WidgetDelegate::GetDesiredWidgetBounds() {
   DCHECK(GetWidget());
 
-  if (has_desired_bounds_delegate()) {
-    return params_.desired_bounds_delegate.Run();
-  }
-
   return gfx::Rect(GetWidget()->GetWindowBoundsInScreen().origin(),
                    GetWidget()->GetContentsView()->GetPreferredSize({}));
 }
diff --git a/ui/views/widget/widget_delegate.h b/ui/views/widget/widget_delegate.h
index d1f6be37..c1a408b62 100644
--- a/ui/views/widget/widget_delegate.h
+++ b/ui/views/widget/widget_delegate.h
@@ -87,13 +87,6 @@
     // this WidgetDelegate is used to initialize a Widget.
     std::optional<View*> initially_focused_view;
 
-    // This is used by modal dialogs to override and constrain desired bounds
-    // calculations.
-    // TODO(pbos): Consider if we could express bounds constraints in views and
-    // keep them in sync rather than constrained_window owning the calculation
-    // here. Considering this wasn't very expedient at the time.
-    base::RepeatingCallback<gfx::Rect()> desired_bounds_delegate;
-
     // The widget's internal name, used to identify it in window-state
     // restoration (if this widget participates in that) and in debugging
     // contexts. Never displayed to the user, and not translated.
@@ -347,7 +340,7 @@
   // Called when the widget wants to resize itself.
   // Default origin is the widget origin.
   // Default size is the ContentsView's PreferredSize.
-  gfx::Rect GetDesiredWidgetBounds();
+  virtual gfx::Rect GetDesiredWidgetBounds();
 
   // Setters for data parameters of the WidgetDelegate. If you use these
   // setters, there is no need to override the corresponding virtual getters.
@@ -422,14 +415,6 @@
   void set_internal_name(std::string name) { params_.internal_name = name; }
   std::string internal_name() const { return params_.internal_name; }
 
-  bool has_desired_bounds_delegate() const {
-    return static_cast<bool>(params_.desired_bounds_delegate);
-  }
-  void set_desired_bounds_delegate(
-      base::RepeatingCallback<gfx::Rect()> desired_bounds_delegate) {
-    params_.desired_bounds_delegate = std::move(desired_bounds_delegate);
-  }
-
  private:
   // We're using a vector of OnceClosures instead of a OnceCallbackList because
   // most of the clients of WidgetDelegate don't have a convenient place to
diff --git a/ui/webui/resources/cr_components/certificate_manager/certificate_manager_v2.html b/ui/webui/resources/cr_components/certificate_manager/certificate_manager_v2.html
index bc28812..3adeca1 100644
--- a/ui/webui/resources/cr_components/certificate_manager/certificate_manager_v2.html
+++ b/ui/webui/resources/cr_components/certificate_manager/certificate_manager_v2.html
@@ -28,9 +28,10 @@
       <div id="provisioned-client-certs">
         From your administrator
         <template is="dom-repeat" items="[[provisionedClientCerts_]]">
-          <div class="cr-row cr-padded-text cert-row">
-            [[item.displayName]] - [[item.sha256hashHex]]
-          </div>
+          <certificate-entry-v2 display-name="[[item.displayName]]"
+              sha256hash-hex="[[item.sha256hashHex]]"
+              on-hash-copied="onHashCopied_">
+          </certificate-entry-v2>
         </template>
       </div>
     </if>
@@ -38,9 +39,10 @@
     <div id="platform-client-certs">
       Client certificates from platform
       <template is="dom-repeat" items="[[platformClientCerts_]]">
-        <div class="cr-row cr-padded-text cert-row">
-          [[item.displayName]] - [[item.sha256hashHex]]
-        </div>
+        <certificate-entry-v2 display-name="[[item.displayName]]"
+            sha256hash-hex="[[item.sha256hashHex]]"
+            on-hash-copied="onHashCopied_">
+        </certificate-entry-v2>
       </template>
     </div>
   </div>
@@ -62,7 +64,7 @@
       <template is="dom-repeat" items="[[crsCertificates_]]">
         <certificate-entry-v2 display-name="[[item.displayName]]"
             sha256hash-hex="[[item.sha256hashHex]]"
-            on-hash-copied="onValueCopied_">
+            on-hash-copied="onHashCopied_">
         </certificate-entry-v2>
       </template>
     </cr-collapse>
diff --git a/ui/webui/resources/cr_components/certificate_manager/certificate_manager_v2.ts b/ui/webui/resources/cr_components/certificate_manager/certificate_manager_v2.ts
index 83a9ea8..7e13446 100644
--- a/ui/webui/resources/cr_components/certificate_manager/certificate_manager_v2.ts
+++ b/ui/webui/resources/cr_components/certificate_manager/certificate_manager_v2.ts
@@ -94,7 +94,7 @@
     // </if>
   }
 
-  private onValueCopied_() {
+  private onHashCopied_() {
     // TODO(crbug.com/40928765): Support localization.
     this.toastMessage_ = 'Hash copied to clipboard';
     this.$.toast.show();
diff --git a/ui/webui/resources/cr_components/searchbox/realbox_icon.html b/ui/webui/resources/cr_components/searchbox/realbox_icon.html
index a3efbc8..e360c96 100644
--- a/ui/webui/resources/cr_components/searchbox/realbox_icon.html
+++ b/ui/webui/resources/cr_components/searchbox/realbox_icon.html
@@ -30,7 +30,7 @@
 
   /* Entities may feature a dominant color background until image loads. */
   :host-context(cr-realbox-match[has-image]):host(:not([is-weather-answer])) #container {
-    background-color: var(--cr-realbox-icon-container-bg-color,
+    background-color: var(--color-realbox-results-icon-container-background,
         var(--container-bg-color));
   }
 
diff --git a/ui/webui/resources/cr_components/searchbox/realbox_match.html b/ui/webui/resources/cr_components/searchbox/realbox_match.html
index 464f569e..b347e7a4 100644
--- a/ui/webui/resources/cr_components/searchbox/realbox_match.html
+++ b/ui/webui/resources/cr_components/searchbox/realbox_match.html
@@ -238,7 +238,7 @@
     --cr-realbox-icon-border-radius: 12px;
     /* Disable placeholder dominant color as the images are large and the
      * placeholder color looks like a flash of unstyled content. */
-    --cr-realbox-icon-container-bg-color: transparent;
+    --color-realbox-results-icon-container-background: transparent;
     height: 90px;
     margin-block-end: 8px;
     width: 90px;