diff --git a/DEPS b/DEPS
index 8745b59..ae79a0a 100644
--- a/DEPS
+++ b/DEPS
@@ -295,7 +295,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'src_internal_revision': '9fd28e7faf34a6ae2ee795d2aebafe88abe80407',
+  'src_internal_revision': 'fc8270585d35ff4b1d05c06fbc75fa5fb7d8d63e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
@@ -303,11 +303,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '32b330ac8c50d47938a879343e450bd8bd8cd2e0',
+  'v8_revision': '41aacdda71ed37cbaf84d7c138a0be8297d2fb85',
   # 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': '5d63c8d5a09ec399a2603f87fd8c1775abbe7c56',
+  'angle_revision': 'ce156f3bc3547d7467a4b9db047b13c54e47cffd',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -331,7 +331,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling googletest
   # and whatever else without interference from each other.
-  'googletest_revision': 'fd15f51d57f983c5f3f609bb39fd77f6dbdc391a',
+  'googletest_revision': '1aeec48a1dda87f179d76b5f4f30db91c9ab7239',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling lighttpd
   # and whatever else without interference from each other.
@@ -371,11 +371,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '1d50003d814d326a3e1f000d456b3eede5ab8fd5',
+  'catapult_revision': '3936da5884d45fc16ecbd3d939c4709fe3ebbd3e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling CrossBench
   # and whatever else without interference from each other.
-  'crossbench_revision': 'e5f52e392ef8fae9e4fd83e2d6af366999f28776',
+  'crossbench_revision': 'f153de5d266c992e05a5f00db9b1f75440076f32',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -391,7 +391,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '1ad5f0be793810c0b09958a976bda35724a20c6d',
+  'devtools_frontend_revision': '3a4bfd655bb875cee25ff21160dce79479f9f4fb',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -415,11 +415,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '8f0deff0d2fa43ec948531a7ae69ee02dd6485c1',
+  'dawn_revision': '31cf85d685b9ba4f3596ac21d484051f3196e43a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'quiche_revision': '9194c7eec5a1e6ac9034a8ee7fd18804fb9a7125',
+  'quiche_revision': '611b64ffd0f17e96d31ff1d3e52ff1df0c9219f8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ink
   # and whatever else without interference from each other.
@@ -495,7 +495,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'libcxxabi_revision':    '3a31ad538c40ba0eb41fbfd3ec583cdef340cf72',
+  'libcxxabi_revision':    'e44c3c4560f1742744ef3f9fb4217a5f26ebca1b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -1521,7 +1521,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    'bce0ee19815b3b46f811a323eafa5a89ea508d34',
+    '495257e25198d1739ddaddd2f1c63e98e0d107e5',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1680,7 +1680,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'TCDGGp_3Gr2F56oMV8V8aL77QPbyhx9NEn1l-uaJjcYC',
+          'version': 'oyu2fpTO_0piy3yAZIpJzeyhXuJMSn6-8DaEjlgvmwEC',
       },
     ],
     'condition': 'checkout_android and non_git_source',
@@ -1751,7 +1751,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_build_tools/error_prone',
-               'version': 'OFmDaNXqS5PTb5YKd4fCb0Y4cK4ImQXeZISzw9p1ILcC',
+               'version': 'RiplT9oTSE0lQHviAF6FMk5P9863t0-WHcl2te12hi0C',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -1773,7 +1773,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_build_tools/lint',
-               'version': 'elV-KSOeiX0hBeuw8Swk8wWiXT8Ns35MNwiOp6SLR4QC',
+               'version': 'Otd2S_y5ozK3q8Q7eMr1NqNH38ESBnUYT4I842UsU0UC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -1784,7 +1784,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_build_tools/manifest_merger',
-               'version': 'VcONzD64-9oyADpPb46XY3qQ0bWCJVaFIKA2dNziAY4C',
+               'version': 'UrgRDTQRxa2KqkIGo6gwYOY7uf56hYmH-QAjov2N9NMC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -2000,7 +2000,7 @@
     Var('chromium_git') + '/external/github.com/google/cpu_features.git' + '@' + '936b9ab5515dead115606559502e3864958f7f6e',
 
   'src/third_party/cpuinfo/src':
-    Var('chromium_git') + '/external/github.com/pytorch/cpuinfo.git' + '@' + '6c9eb84ba310f237cea13c478be50102e1128e9b',
+    Var('chromium_git') + '/external/github.com/pytorch/cpuinfo.git' + '@' + 'd7427551d6531037da216d20cd36feb19ed4905f',
 
   'src/third_party/crc32c/src':
     Var('chromium_git') + '/external/github.com/google/crc32c.git' + '@' + 'd3d60ac6e0f16780bcfcc825385e1d338801a558',
@@ -2028,7 +2028,7 @@
     Var('chromium_git') + '/external/github.com/jk-jeon/dragonbox.git' + '@' + '6c7c925b571d54486b9ffae8d9d18a822801cbda',
 
   'src/third_party/eigen3/src':
-    Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + '21e89b930c6af56dbdaeea2a91d8b9d6fd2c208a',
+    Var('chromium_git') + '/external/gitlab.com/libeigen/eigen.git' + '@' + 'd0b490ee091629068e0c11953419eb089f9e6bb2',
 
   'src/third_party/emoji-metadata/src': {
     'url': Var('chromium_git') + '/external/github.com/googlefonts/emoji-metadata' + '@' + '045f146fca682a836e01cd265171312bfb300e06',
@@ -2267,7 +2267,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/kotlin_stdlib',
-              'version': 'Mc9HaD_2yySsh6UsClUG1vyaXh_UKNCiwjHdrCuTp1kC',
+              'version': '8XeqF76rn8_JTQhKeVQl7VP6j626lwcLXU8ASXeiyAkC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -2564,7 +2564,7 @@
     Var('pdfium_git') + '/pdfium.git' + '@' +  Var('pdfium_revision'),
 
   'src/third_party/perfetto':
-    Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + 'fbed4ffaccc0e754779134993ae8212091582aa9',
+    Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + 'e93a2c7998dee72ddcacff7cf54d001051205ce4',
 
   'src/base/tracing/test/data': {
     'bucket': 'perfetto',
@@ -2782,7 +2782,7 @@
     Var('chromium_git') + '/external/github.com/google/ruy.git' + '@' + '83fd40d730feb0804fafbc2d8814bcc19a17b2e5',
 
   'src/third_party/search_engines_data/resources':
-    Var('chromium_git') + '/external/search_engines_data.git' + '@' + 'b07b9e19ca1e2ee2bfeef7e45fc91faaa12c78ed',
+    Var('chromium_git') + '/external/search_engines_data.git' + '@' + '09fd22f3a4fb77ab03b7734e0c03ff7d7f97ef88',
 
   'src/third_party/search_engines_data/resources_internal': {
     'url': Var('chrome_git') + '/external/search_engines_data_internal.git' + '@' + 'cc57055d268edc933691dccb2139d0ced064a6c2',
@@ -2870,7 +2870,7 @@
     Var('chromium_git') + '/external/github.com/GoogleChromeLabs/text-fragments-polyfill.git' + '@' + 'c036420683f672d685e27415de0a5f5e85bdc23f',
 
   'src/third_party/tflite/src':
-    Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + '60fb9c76b41f0e4d6cfdd6b1bd2fabe443455306',
+    Var('chromium_git') + '/external/github.com/tensorflow/tensorflow.git' + '@' + '75530866a843d37eb98dfc75c2eb152634335949',
 
   'src/third_party/turbine/cipd': {
       'packages': [
@@ -2883,7 +2883,7 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@636bbcfcf2bc3bd8f1d1408bf631ccfa5a359e6a',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@222889ea039509b86fa6dd90fcb6acf47e79cdb9',
   'src/third_party/glslang/src': '{chromium_git}/external/github.com/KhronosGroup/glslang@05cfcc1613c28c1274036f53616d66324f7cd383',
   'src/third_party/spirv-cross/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Cross@b8fcf307f1f347089e3c46eb4451d27f32ebc8d3',
   'src/third_party/spirv-headers/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Headers@50daff941d88609b4d2ad076eae558e727f8e5cd',
@@ -2892,7 +2892,7 @@
   'src/third_party/vulkan-loader/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Loader@63b05d2b087952662623de7eddd44f2e57d71a1e',
   'src/third_party/vulkan-tools/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@fbe722654b7173da961398cf78bd4a62d1839b65',
   'src/third_party/vulkan-utility-libraries/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Utility-Libraries@e48ae20a7938b01aee62806bfcdafe8a0883b1e4',
-  'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@24d7e9058718bb4f183a44c0fcf479cd886a03bd',
+  'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@6d6e6ec8e51cd219498359cbc48e4762d1a80616',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '56300b29fbfcc693ee6609ddad3fdd5b7a449a21',
@@ -2931,7 +2931,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'c01b768bce4a143e152c1870b6ba99ea6267d2b0',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '605c2fec81e2227d91a019bb0d8dc6eb7554af44',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'cb3be1a0c7f808d1cae46d4ca14a966777193e2e',
 
   'src/third_party/webpagereplay':
     Var('chromium_git') + '/webpagereplay.git' + '@' + Var('webpagereplay_revision'),
@@ -2961,7 +2961,7 @@
   },
 
   'src/third_party/xnnpack/src':
-    Var('chromium_git') + '/external/github.com/google/XNNPACK.git' + '@' + '888719e9a4b11251d03ad2d6526da7f2e2b57308',
+    Var('chromium_git') + '/external/github.com/google/XNNPACK.git' + '@' + 'a0a1bd4b3de97b356d7b106bf7fd3def6ad2103f',
 
   'src/third_party/libei/cipd': {
 
@@ -3114,7 +3114,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 'e89COprilVD-C-RooQvJX-mlgTkRV9BARTNaJIvXfd0C',
+        'version': 'OHihXqKySLaEnCtvfWU4zP6H9JUPTScqKRlEXN-_7SwC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -4723,7 +4723,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        '27a3b55cbe85ff91ece1b77557c87338d6a96984',
+        '9359be07f1fa746ee3d0332c9292639e6c5effcf',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/ProfileExtraHeadersTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/ProfileExtraHeadersTest.java
index 0f3e30e..254aab4c 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/ProfileExtraHeadersTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/ProfileExtraHeadersTest.java
@@ -4,6 +4,8 @@
 
 package org.chromium.android_webview.test;
 
+import android.webkit.WebSettings;
+
 import androidx.annotation.NonNull;
 import androidx.test.filters.LargeTest;
 import androidx.test.filters.MediumTest;
@@ -568,10 +570,22 @@
     @Feature({"AndroidWebView"})
     @Test
     public void willAttachHeaderOnCrossOriginResourceRequests() throws Exception {
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> mAwContents.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE));
+        AwActivityTestRule.enableJavaScriptOnUiThread(mAwContents);
+        TestWebMessageListener listener = addTestWebMessageListener();
         String mainContentTemplate =
                 """
             <!DOCTYPE html>
-            <html><body><img src="%s"></body></html>
+            <html>
+            <script>
+            function onImageLoaded() {
+              testListener.postMessage("loaded");
+            }
+            </script>
+            <!-- onerror because we are returning an invalid result from the test server. -->
+            <body><img onerror="onImageLoaded()" src="%s">
+            </body></html>
             """;
         try (TestWebServer server = TestWebServer.start();
                 TestWebServer corsServer = TestWebServer.startAdditional()) {
@@ -585,8 +599,9 @@
             String mainContent = String.format(mainContentTemplate, corsUrl);
             String mainUrl = server.setResponse("/index.html", mainContent, null);
 
-            mActivityTestRule.loadUrlSync(
-                    mAwContents, mContentsClient.getOnPageFinishedHelper(), mainUrl);
+            mActivityTestRule.loadUrlAsync(mAwContents, mainUrl);
+            listener.waitForOnPostMessage();
+
             HTTPRequest lastRequest = server.getLastRequest("/index.html");
             Assert.assertEquals("", lastRequest.headerValue("X-ApplicationHeader"));
 
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc
index 9517ace..1fa7d7a 100644
--- a/ash/wm/overview/overview_grid.cc
+++ b/ash/wm/overview/overview_grid.cc
@@ -1055,7 +1055,7 @@
   auto iter = std::ranges::find(base::Reversed(item_list_), overview_item,
                                 &std::unique_ptr<OverviewItemBase>::get);
   CHECK(iter != item_list_.rend());
-
+  CHECK_EQ(iter->get(), overview_item);
   UpdateNumSavedDeskUnsupportedWindows(overview_item->GetWindows(),
                                        /*increment=*/false);
 
@@ -1063,6 +1063,10 @@
   // iterating through the `item_list_`.
   std::unique_ptr<OverviewItemBase> tmp = std::move(*iter);
   item_list_.erase(std::next(iter).base());
+
+  if (!item_destroying) {
+    tmp->Shutdown();
+  }
   tmp.reset();
 
   if (overview_session_)
@@ -3094,6 +3098,7 @@
   // determine each item's scale.
   for (size_t i = 0u; i < item_count; ++i) {
     const auto& item = item_list_[i];
+    CHECK(item.get());
     if (ShouldExcludeItemFromGridLayout(item.get(), ignored_items)) {
       continue;
     }
@@ -3474,6 +3479,7 @@
 
   auto drop_target = std::make_unique<OverviewDropTarget>(this);
   drop_target_ = drop_target.get();
+  CHECK(drop_target);
   item_list_.insert(item_list_.begin() + position, std::move(drop_target));
 
   base::flat_set<OverviewItemBase*> ignored_items;
diff --git a/ash/wm/overview/overview_group_item.cc b/ash/wm/overview/overview_group_item.cc
index 8de6c426..c80b80c 100644
--- a/ash/wm/overview/overview_group_item.cc
+++ b/ash/wm/overview/overview_group_item.cc
@@ -17,6 +17,7 @@
 #include "ash/wm/overview/overview_item_view.h"
 #include "ash/wm/overview/overview_session.h"
 #include "ash/wm/overview/overview_utils.h"
+#include "ash/wm/overview/overview_window_drag_controller.h"
 #include "ash/wm/snap_group/snap_group.h"
 #include "ash/wm/snap_group/snap_group_controller.h"
 #include "ash/wm/splitview/layout_divider_controller.h"
@@ -468,6 +469,11 @@
   for (const auto& overview_item : overview_items_) {
     overview_item->Shutdown();
   }
+  if (IsDragItem() && overview_grid_->drop_target()) {
+    auto* drag_controller = overview_session_->window_drag_controller();
+    CHECK(drag_controller);
+    drag_controller->ResetGesture();
+  }
 }
 
 void OverviewGroupItem::AnimateAndCloseItem(bool up) {
diff --git a/ash/wm/overview/overview_test_util.cc b/ash/wm/overview/overview_test_util.cc
index 7b70c32..b70a8dd 100644
--- a/ash/wm/overview/overview_test_util.cc
+++ b/ash/wm/overview/overview_test_util.cc
@@ -107,8 +107,10 @@
                      bool drop) {
   DCHECK(item);
 
-  const gfx::Point item_center =
+  gfx::Point item_center =
       gfx::ToRoundedPoint(item->target_bounds().CenterPoint());
+  // Move slightly to right bottom as the center may have a gap for dividier.
+  item_center.Offset(10, 10);
   event_generator->set_current_screen_location(item_center);
   if (by_touch_gestures) {
     event_generator->PressTouch();
diff --git a/ash/wm/snap_group/snap_group_metrics.h b/ash/wm/snap_group/snap_group_metrics.h
index 233a53b..c22fe3b 100644
--- a/ash/wm/snap_group/snap_group_metrics.h
+++ b/ash/wm/snap_group/snap_group_metrics.h
@@ -73,7 +73,8 @@
   kSelectWindowInSnapGroupInPartialOverview,
   kCoral,
   kToggleSnapGroupAccelerator,
-  kMaxValue = kToggleSnapGroupAccelerator,
+  kMoveToAnotherDisplay,
+  kMaxValue = kMoveToAnotherDisplay,
 };
 
 // Records the partial overview metrics for `item`. Should only be called while
diff --git a/ash/wm/snap_group/snap_group_unittest.cc b/ash/wm/snap_group/snap_group_unittest.cc
index 11702fb..c307f87b 100644
--- a/ash/wm/snap_group/snap_group_unittest.cc
+++ b/ash/wm/snap_group/snap_group_unittest.cc
@@ -6193,6 +6193,38 @@
   EXPECT_EQ(1u, overview_grid->item_list().size());
 }
 
+// Make sure that ungrouping while dragging snapgroup in overview will not
+// crash.
+TEST_F(SnapGroupOverviewTest, UngroupDuringDragInOverview) {
+  // Set the min width so that the windows don't fit after zooming in using
+  // keyboard shortcut.
+  std::unique_ptr<aura::Window> w1(CreateAppWindow());
+  std::unique_ptr<aura::Window> w2(CreateAppWindow());
+  ASSERT_FALSE(IsInOverviewSession());
+  SnapTwoTestWindows(w1.get(), w2.get(), /*horizontal=*/true,
+                     GetEventGenerator());
+  auto* snap_group_controller = SnapGroupController::Get();
+  EXPECT_TRUE(snap_group_controller->AreWindowsInSnapGroup(w1.get(), w2.get()));
+
+  ToggleOverview();
+  ASSERT_TRUE(IsInOverviewSession());
+
+  OverviewItemBase* overview_group_item = GetOverviewItemForWindow(w1.get());
+  ASSERT_TRUE(overview_group_item);
+
+  DragItemToPoint(overview_group_item, gfx::Point(200, 100),
+                  GetEventGenerator(),
+                  /*by_touch_gestures=*/false, /*drop=*/false);
+
+  ASSERT_TRUE(overview_group_item->IsDragItem());
+  ASSERT_TRUE(IsInOverviewSession());
+
+  // Restore the window during the drag. This should not cause a crash.
+  ::wm::Restore(w1.get());
+  EXPECT_TRUE(IsInOverviewSession());
+  EXPECT_NE(overview_group_item, GetOverviewItemForWindow(w1.get()));
+}
+
 // -----------------------------------------------------------------------------
 // SnapGroupDesksTest:
 using SnapGroupDesksTest = SnapGroupTest;
@@ -9419,22 +9451,22 @@
   // update the work area insets to trigger it.
   display_manager->UpdateWorkAreaOfDisplay(display_ids[0], gfx::Insets(5));
 
-  // Disconnect the secondary display and verify that `snap_group` will be moved
-  // to the primary display.
+  // Disconnect the secondary display and verify that `snap_group` is removed
+  // but windows are moved to the primary display.
   std::vector<display::ManagedDisplayInfo> display_info_list;
   display_info_list.push_back(display_manager->GetDisplayInfo(display_ids[0]));
   display_manager->OnNativeDisplaysChanged(display_info_list);
   EXPECT_EQ(1u, display_manager->GetNumDisplays());
-  EXPECT_TRUE(SnapGroupController::Get()->GetSnapGroupForGivenWindow(w1.get()));
-  VerifySnapGroupOnDisplay(snap_group, display_ids[0]);
-
-  // Reconnect the secondary display and verify that `snap_group` will be moved
-  // back to the secondary display.
-  display_info_list.insert(display_info_list.begin(),
-                           display_manager->GetDisplayInfo(display_ids[1]));
-  display_manager->OnNativeDisplaysChanged(display_info_list);
-  EXPECT_EQ(2u, display_manager->GetNumDisplays());
-  VerifySnapGroupOnDisplay(snap_group, display_ids[1]);
+  EXPECT_FALSE(
+      SnapGroupController::Get()->GetSnapGroupForGivenWindow(w1.get()));
+  EXPECT_FALSE(
+      SnapGroupController::Get()->GetSnapGroupForGivenWindow(w2.get()));
+  EXPECT_EQ(
+      display_ids[0],
+      display::Screen::GetScreen()->GetDisplayNearestWindow(w1.get()).id());
+  EXPECT_EQ(
+      display_ids[0],
+      display::Screen::GetScreen()->GetDisplayNearestWindow(w2.get()).id());
 }
 
 // Tests to verify that when a window is dragged out of a snap group and onto
@@ -9489,101 +9521,32 @@
   auto* snap_group_divider = SnapGroupController::Get()
                                  ->GetSnapGroupForGivenWindow(w1.get())
                                  ->snap_group_divider();
-  const int64_t primary_id =
-      display::Screen::GetScreen()->GetPrimaryDisplay().id();
+  const int64_t primary_id = GetPrimaryDisplay().id();
   display::Screen* screen = display::Screen::GetScreen();
   ASSERT_EQ(primary_id, screen->GetDisplayNearestWindow(w1.get()).id());
   ASSERT_EQ(primary_id, screen->GetDisplayNearestWindow(w2.get()).id());
 
   // Activate `w1`, then press Search+Alt+M to move it to display 2.
   wm::ActivateWindow(w1.get());
-  PressAndReleaseKey(ui::VKEY_M, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN);
-  const int64_t secondary_id =
-      display::test::DisplayManagerTestApi(display_manager())
-          .GetSecondaryDisplay()
-          .id();
-  ASSERT_EQ(secondary_id, screen->GetDisplayNearestWindow(w1.get()).id());
-  EXPECT_EQ(secondary_id, screen->GetDisplayNearestWindow(w2.get()).id());
-  aura::Window* divider_window = snap_group_divider->GetDividerWindow();
-  EXPECT_EQ(secondary_id, screen->GetDisplayNearestWindow(divider_window).id());
-
-  auto* desk_container = desks_util::GetActiveDeskContainerForRoot(
-      Shell::Get()->GetRootWindowForDisplayId(secondary_id));
 
   MruWindowTracker* mru_window_tracker = Shell::Get()->mru_window_tracker();
   aura::Window* mru_window = window_util::GetTopMostWindow(
       mru_window_tracker->BuildMruWindowList(DesksMruType::kActiveDesk));
-
-  // `w1` will be the mru window. With the window stacking fixed by
-  // `window_util::FixWindowStackingAccordingToGlobalMru()`, the `w2` that gets
-  // moved after will be stacked above `w1`.
   EXPECT_EQ(mru_window, w1.get());
-  EXPECT_THAT(desk_container->children(),
-              ElementsAre(w2.get(), w1.get(), divider_window));
 
-  UnionBoundsEqualToWorkAreaBounds(w1.get(), w2.get(), snap_group_divider);
-}
+  PressAndReleaseKey(ui::VKEY_M, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN);
 
-// Tests that moving an `OverviewGroupItem` between displays correctly
-// relocates the group item and its windows without crashing, while maintaining
-// divider widget invisibility during the overview session.
-TEST_F(SnapGroupMultiDisplayTest, MoveSnapGroupBetweenDisplaysInOverview) {
-  UpdateDisplay("800x700,801+0-800x700,1602+0-800x700");
-  display::DisplayManager* display_manager = Shell::Get()->display_manager();
-  const auto& displays = display_manager->active_display_list();
-  ASSERT_EQ(3U, displays.size());
+  const int64_t secondary_id = GetSecondaryDisplay().id();
+  ASSERT_EQ(secondary_id, screen->GetDisplayNearestWindow(w1.get()).id());
 
-  const gfx::Point point_in_display2(900, 100);
-  EXPECT_FALSE(displays[0].bounds().Contains(point_in_display2));
-  EXPECT_TRUE(displays[1].bounds().Contains(point_in_display2));
-  EXPECT_FALSE(displays[2].bounds().Contains(point_in_display2));
+  // Ungrouped window will stay in the primary.
+  EXPECT_EQ(primary_id, screen->GetDisplayNearestWindow(w2.get()).id());
+  EXPECT_FALSE(snap_group_divider->GetDividerWindow());
 
-  const gfx::Point point_in_display3(1700, 200);
-  EXPECT_FALSE(displays[0].bounds().Contains(point_in_display3));
-  EXPECT_FALSE(displays[1].bounds().Contains(point_in_display3));
-  EXPECT_TRUE(displays[2].bounds().Contains(point_in_display3));
-
-  std::unique_ptr<aura::Window> w1(CreateAppWindow());
-  std::unique_ptr<aura::Window> w2(CreateAppWindow());
-  auto* event_generator = GetEventGenerator();
-  SnapTwoTestWindows(w1.get(), w2.get(), /*horizontal=*/true, event_generator);
-  auto* divider = GetTopmostSnapGroupDivider();
-  ASSERT_TRUE(divider);
-  auto* divider_widget = divider->divider_widget();
-  ASSERT_TRUE(divider_widget);
-  ASSERT_TRUE(divider_widget->IsVisible());
-
-  struct {
-    gfx::Point drop_location;
-    int display_index;
-  } kTestCases[]{
-      {point_in_display2, 1}, {point_in_display3, 2}, {gfx::Point(0, 0), 0}};
-
-  OverviewController* overview_controller = OverviewController::Get();
-  for (const auto test_case : kTestCases) {
-    SCOPED_TRACE("\nDrop location: " + test_case.drop_location.ToString() +
-                 ";\n" + "Destination display index: " +
-                 base::NumberToString(test_case.display_index) + ".");
-    overview_controller->StartOverview(OverviewStartAction::kOverviewButton);
-    EXPECT_FALSE(divider_widget->IsVisible());
-
-    auto* overview_group_item = GetOverviewItemForWindow(w1.get());
-    DragGroupItemToPoint(overview_group_item, test_case.drop_location,
-                         event_generator,
-                         /*by_touch_gestures=*/false, /*drop=*/true);
-    EXPECT_FALSE(divider_widget->IsVisible());
-
-    display::Screen* screen = display::Screen::GetScreen();
-    EXPECT_EQ(displays[test_case.display_index].id(),
-              screen->GetDisplayNearestWindow(w1.get()).id());
-    EXPECT_EQ(displays[test_case.display_index].id(),
-              screen->GetDisplayNearestWindow(w2.get()).id());
-
-    SendKeyUntilOverviewItemIsFocused(ui::VKEY_TAB, GetEventGenerator());
-    event_generator->PressKey(ui::VKEY_RETURN, /*flags=*/0);
-
-    EXPECT_TRUE(divider_widget->IsVisible());
-  }
+  // `w1` and 'w2'  will be on different displays, and will not share the same
+  // same parent.
+  EXPECT_FALSE(window_util::GetTopMostWindow(
+      mru_window_tracker->BuildMruWindowList(DesksMruType::kActiveDesk)));
 }
 
 // Verifies that when an `OverviewGroupItem` is dragged between displays in
@@ -9596,6 +9559,7 @@
   const auto& displays = display_manager->active_display_list();
   ASSERT_EQ(2U, displays.size());
 
+  const gfx::Point point_in_display1(400, 100);
   const gfx::Point point_in_display2(1000, 100);
   EXPECT_FALSE(displays[0].bounds().Contains(point_in_display2));
   EXPECT_TRUE(displays[1].bounds().Contains(point_in_display2));
@@ -9614,12 +9578,12 @@
   ToggleOverview();
   ASSERT_TRUE(IsInOverviewSession());
 
-  // Move Snap Group to display #2.
   OverviewGroupItem* group_item =
       static_cast<OverviewGroupItem*>(GetOverviewItemForWindow(w1.get()));
+
+  // Move Snap Group to display #2.
   DragGroupItemToPoint(group_item, point_in_display2, event_generator,
                        /*by_touch_gestures=*/false, /*drop=*/false);
-
   // Verify that the item widget and window are mirrored for the individual
   // items.
   for (const auto& item : group_item->overview_items_for_testing()) {
@@ -9627,12 +9591,16 @@
     EXPECT_TRUE(item->window_mirror_for_dragging_for_testing());
   }
 
+  // Move Snap Group back to display #1.
+  event_generator->MoveMouseTo(point_in_display1);
   event_generator->ReleaseLeftButton();
 
-  // Verify that the windows are moved to the destination display properly.
+  EXPECT_TRUE(
+      SnapGroupController::Get()->AreWindowsInSnapGroup(w1.get(), w2.get()));
+
   display::Screen* screen = display::Screen::GetScreen();
-  EXPECT_EQ(displays[1].id(), screen->GetDisplayNearestWindow(w1.get()).id());
-  EXPECT_EQ(displays[1].id(), screen->GetDisplayNearestWindow(w2.get()).id());
+  EXPECT_EQ(displays[0].id(), screen->GetDisplayNearestWindow(w1.get()).id());
+  EXPECT_EQ(displays[0].id(), screen->GetDisplayNearestWindow(w2.get()).id());
 }
 
 // Tests that when moving snap group to another display with snap group, the
@@ -9687,10 +9655,15 @@
 
   // Verify that the windows are moved to the destination display properly.
   display::Screen* screen = display::Screen::GetScreen();
-  EXPECT_EQ(displays[0].id(), screen->GetDisplayNearestWindow(w3.get()).id());
-  EXPECT_EQ(displays[0].id(), screen->GetDisplayNearestWindow(w4.get()).id());
+  EXPECT_FALSE(
+      SnapGroupController::Get()->AreWindowsInSnapGroup(w1.get(), w2.get()));
   EXPECT_EQ(displays[1].id(), screen->GetDisplayNearestWindow(w1.get()).id());
-  EXPECT_EQ(displays[1].id(), screen->GetDisplayNearestWindow(w2.get()).id());
+  EXPECT_EQ(displays[0].id(), screen->GetDisplayNearestWindow(w2.get()).id());
+
+  EXPECT_FALSE(
+      SnapGroupController::Get()->AreWindowsInSnapGroup(w3.get(), w4.get()));
+  EXPECT_EQ(displays[0].id(), screen->GetDisplayNearestWindow(w3.get()).id());
+  EXPECT_EQ(displays[1].id(), screen->GetDisplayNearestWindow(w4.get()).id());
 }
 
 // Tests that dragging an `OverviewGroupItem` to a different desk in another
@@ -9744,18 +9717,16 @@
   waiter.Wait();
   ASSERT_FALSE(IsInOverviewSession());
 
+  EXPECT_FALSE(GetTopmostSnapGroupDivider());
   display::Screen* screen = display::Screen::GetScreen();
   EXPECT_EQ(displays[1].id(), screen->GetDisplayNearestWindow(w1.get()).id());
-  EXPECT_EQ(displays[1].id(), screen->GetDisplayNearestWindow(w2.get()).id());
+  // The snapgroup will be removed and w2 should stay on display 1.
+  EXPECT_EQ(displays[0].id(), screen->GetDisplayNearestWindow(w2.get()).id());
   EXPECT_TRUE(desks_util::IsActiveDeskContainer(w1->parent()));
+
   EXPECT_TRUE(desks_util::IsActiveDeskContainer(w2->parent()));
   EXPECT_TRUE(w1->IsVisible());
   EXPECT_TRUE(w2->IsVisible());
-  UnionBoundsEqualToWorkAreaBounds(w1.get(), w2.get(),
-                                   GetTopmostSnapGroupDivider());
-  VerifySnapGroupOnDisplay(
-      snap_group_controller->GetSnapGroupForGivenWindow(w1.get()),
-      displays[1].id());
 }
 
 // Tests if a `SnapGroup` is created on the external display, desk change with
@@ -9839,7 +9810,9 @@
   display_manager->SetMirrorMode(display::MirrorMode::kNormal, std::nullopt);
   ASSERT_EQ(1U, displays.size());
   VerifySnapGroupOnDisplay(group1, primary_id);
-  VerifySnapGroupOnDisplay(group2, primary_id);
+  // Snapgroup #2 will be unsnapped.
+  EXPECT_FALSE(
+      SnapGroupController::Get()->AreWindowsInSnapGroup(w3.get(), w4.get()));
 
   // Exit mirrored mode.
   display_manager->SetMirrorMode(display::MirrorMode::kOff, std::nullopt);
@@ -9849,8 +9822,8 @@
   // we just verify the group bounds are visible and on-screen.
   UnionBoundsEqualToWorkAreaBounds(w1.get(), w2.get(),
                                    group1->snap_group_divider());
-  UnionBoundsEqualToWorkAreaBounds(w3.get(), w4.get(),
-                                   group2->snap_group_divider());
+  EXPECT_FALSE(
+      SnapGroupController::Get()->AreWindowsInSnapGroup(w3.get(), w4.get()));
 }
 
 // Tests that toggling mirror mode with a Snap Group on external display doesn't
@@ -9880,13 +9853,16 @@
   // Enable mirror mode and there should be no crash.
   display_manager->SetMirrorMode(display::MirrorMode::kNormal, std::nullopt);
   ASSERT_EQ(1U, displays.size());
-  VerifySnapGroupOnDisplay(snap_group, displays[0].id());
+  // Snapgroup will be unsnapped.
+  EXPECT_FALSE(
+      SnapGroupController::Get()->AreWindowsInSnapGroup(w1.get(), w2.get()));
   base::RunLoop().RunUntilIdle();
 
   // Disable mirror mode and there should be no crash.
   display_manager->SetMirrorMode(display::MirrorMode::kOff, std::nullopt);
   ASSERT_EQ(2U, displays.size());
-  VerifySnapGroupOnDisplay(snap_group, displays[1].id());
+  EXPECT_FALSE(
+      SnapGroupController::Get()->AreWindowsInSnapGroup(w1.get(), w2.get()));
   base::RunLoop().RunUntilIdle();
 }
 
@@ -9976,8 +9952,8 @@
   ASSERT_EQ(WindowTreeHostManager::GetPrimaryDisplayId(), secondary_id);
   UnionBoundsEqualToWorkAreaBounds(w1.get(), w2.get(),
                                    group1->snap_group_divider());
-  UnionBoundsEqualToWorkAreaBounds(w3.get(), w4.get(),
-                                   group2->snap_group_divider());
+  EXPECT_FALSE(
+      SnapGroupController::Get()->AreWindowsInSnapGroup(w3.get(), w4.get()));
 
   // Reconnect primary display.
   display_info_list.push_back(primary_info);
@@ -9986,8 +9962,8 @@
   ASSERT_EQ(WindowTreeHostManager::GetPrimaryDisplayId(), primary_id);
   UnionBoundsEqualToWorkAreaBounds(w1.get(), w2.get(),
                                    group1->snap_group_divider());
-  UnionBoundsEqualToWorkAreaBounds(w3.get(), w4.get(),
-                                   group2->snap_group_divider());
+  EXPECT_FALSE(
+      SnapGroupController::Get()->AreWindowsInSnapGroup(w3.get(), w4.get()));
 }
 
 // Tests no overlap in the divider and window bounds after disconnecting and
diff --git a/ash/wm/window_positioning_utils.cc b/ash/wm/window_positioning_utils.cc
index 413dd8f..7003d8d1d 100644
--- a/ash/wm/window_positioning_utils.cc
+++ b/ash/wm/window_positioning_utils.cc
@@ -13,6 +13,7 @@
 #include "ash/screen_util.h"
 #include "ash/shell.h"
 #include "ash/wm/pip/pip_controller.h"
+#include "ash/wm/snap_group/snap_group_controller.h"
 #include "ash/wm/system_modal_container_layout_manager.h"
 #include "ash/wm/window_properties.h"
 #include "ash/wm/window_restore/window_restore_controller.h"
@@ -269,6 +270,12 @@
     }
 
     if (dst_container && window->parent() != dst_container) {
+      if (auto* snap_group =
+              SnapGroupController::Get()->GetSnapGroupForGivenWindow(window)) {
+        SnapGroupController::Get()->RemoveSnapGroup(
+            snap_group, SnapGroupExitPoint::kDragWindowOut);
+      }
+
       aura::Window* focused = window_util::GetFocusedWindow();
       aura::Window* active = window_util::GetActiveWindow();
 
diff --git a/ash/wm/window_util.cc b/ash/wm/window_util.cc
index e5bdd15..c8546bd 100644
--- a/ash/wm/window_util.cc
+++ b/ash/wm/window_util.cc
@@ -322,6 +322,13 @@
     NOTREACHED();
   }
 
+  // If snapped , breake it.
+  if (auto* snap_group =
+          SnapGroupController::Get()->GetSnapGroupForGivenWindow(window)) {
+    SnapGroupController::Get()->RemoveSnapGroup(
+        snap_group, SnapGroupExitPoint::kMoveToAnotherDisplay);
+  }
+
   WindowState* window_state = WindowState::Get(window);
   if (window_state->allow_set_bounds_direct()) {
     display::Display display;
diff --git a/base/android/orderfile/orderfile_instrumentation.cc b/base/android/orderfile/orderfile_instrumentation.cc
index 0c4969d..5b30a89 100644
--- a/base/android/orderfile/orderfile_instrumentation.cc
+++ b/base/android/orderfile/orderfile_instrumentation.cc
@@ -33,6 +33,7 @@
 #if BUILDFLAG(DEVTOOLS_INSTRUMENTATION_DUMPING)
 #include <sstream>
 
+#include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
 #include "base/trace_event/memory_dump_manager.h"   // no-presubmit-check
 #include "base/trace_event/memory_dump_provider.h"  // no-presubmit-check
diff --git a/base/callback_list.h b/base/callback_list.h
index 35dff35c..6fe1a02 100644
--- a/base/callback_list.h
+++ b/base/callback_list.h
@@ -254,7 +254,7 @@
     // that were executed above have all been removed regardless of whether
     // they're counted in |erased_callbacks_|.
     if (removal_callback_ &&
-        (erased_callbacks || is_instantiation<OnceCallback, CallbackType>)) {
+        (erased_callbacks || is_instantiation<CallbackType, OnceCallback>)) {
       removal_callback_.Run();  // May delete |this|!
     }
   }
diff --git a/base/containers/auto_spanification_helper.h b/base/containers/auto_spanification_helper.h
index 4d0f62f..007156b 100644
--- a/base/containers/auto_spanification_helper.h
+++ b/base/containers/auto_spanification_helper.h
@@ -7,6 +7,22 @@
 
 #include "base/numerics/checked_math.h"
 
+namespace base {
+
+// SpanificationSizeofForStdArray was introduced temporarily in order to help
+// the auto spanification tool (//tools/clang/spanify), and not meant to be
+// used widely.
+//
+// Note that it's *not* guaranteed by the C++ standard that
+//     sizeof(arr) == arr.size() * sizeof(arr[0])
+// and it's possible that std::array has additional data and/or padding.
+template <typename Element, size_t N>
+constexpr size_t SpanificationSizeofForStdArray(const std::array<Element, N>&) {
+  return sizeof(Element) * N;
+}
+
+}  // namespace base
+
 namespace base::spanification_internal {
 
 // ToPointer is a helper function that converts either of a `T&` or a `T*` to a
diff --git a/base/containers/auto_spanification_helper_unittest.cc b/base/containers/auto_spanification_helper_unittest.cc
index 701b6ec..22675f2 100644
--- a/base/containers/auto_spanification_helper_unittest.cc
+++ b/base/containers/auto_spanification_helper_unittest.cc
@@ -15,6 +15,14 @@
 
 namespace {
 
+TEST(AutoSpanificationHelperTest, SpanificationSizeofForStdArray) {
+  std::array<char, 7> char_array;
+  EXPECT_EQ(SpanificationSizeofForStdArray(char_array), 7);
+
+  std::array<uint16_t, 3> uint16_array;
+  EXPECT_EQ(SpanificationSizeofForStdArray(uint16_array), sizeof(uint16_t) * 3);
+}
+
 // Minimized mock of SkBitmap class defined in
 // //third_party/skia/include/core/SkBitmap.h
 class SkBitmap {
diff --git a/base/feature_list.h b/base/feature_list.h
index fe4d3df..ada5231 100644
--- a/base/feature_list.h
+++ b/base/feature_list.h
@@ -22,11 +22,14 @@
 #include "base/dcheck_is_on.h"
 #include "base/feature_list_buildflags.h"
 #include "base/gtest_prod_util.h"
-#include "base/logging.h"
 #include "base/memory/raw_ptr.h"
 #include "base/synchronization/lock.h"
 #include "build/build_config.h"
 
+#if BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX)
+#include "base/logging.h"
+#endif
+
 namespace base {
 
 class FieldTrial;
diff --git a/base/functional/bind_internal.h b/base/functional/bind_internal.h
index c52b963..eb2eec8 100644
--- a/base/functional/bind_internal.h
+++ b/base/functional/bind_internal.h
@@ -454,7 +454,7 @@
 
 // Implements `DropTypeListItem`.
 template <size_t n, typename List>
-  requires is_instantiation<TypeList, List>
+  requires is_instantiation<List, TypeList>
 struct DropTypeListItemImpl {
   using Type = List;
 };
@@ -470,7 +470,7 @@
 
 // Implements `TakeTypeListItem`.
 template <size_t n, typename List, typename... Accum>
-  requires is_instantiation<TypeList, List>
+  requires is_instantiation<List, TypeList>
 struct TakeTypeListItemImpl {
   using Type = TypeList<Accum...>;
 };
@@ -1680,7 +1680,7 @@
 struct BindHelper {
  private:
   static constexpr bool kIsOnce =
-      is_instantiation<OnceCallback, CallbackT<void()>>;
+      is_instantiation<CallbackT<void()>, OnceCallback>;
 
   template <typename Traits, bool v = IsComplete<Traits>>
   struct TraitsAreInstantiable {
@@ -1694,7 +1694,7 @@
   };
 
   template <typename Functor,
-            bool v = !is_instantiation<OnceCallback, std::decay_t<Functor>> ||
+            bool v = !is_instantiation<std::decay_t<Functor>, OnceCallback> ||
                      (kIsOnce && std::is_rvalue_reference_v<Functor&&> &&
                       !std::is_const_v<std::remove_reference_t<Functor>>)>
   struct OnceCallbackFunctorIsValid {
@@ -1717,7 +1717,7 @@
       // Can't use a defaulted template param since it can't come after `Args`.
       constexpr bool v =
           !kIsOnce ||
-          (... && !is_instantiation<PassedWrapper, std::decay_t<Args>>);
+          (... && !is_instantiation<std::decay_t<Args>, PassedWrapper>);
       static_assert(
           v,
           "Use std::move() instead of base::Passed() with base::BindOnce().");
@@ -1728,8 +1728,8 @@
   template <
       typename Functor,
       bool v =
-          !is_instantiation<FunctionRef, std::remove_cvref_t<Functor>> &&
-          !is_instantiation<absl::FunctionRef, std::remove_cvref_t<Functor>>>
+          !is_instantiation<std::remove_cvref_t<Functor>, FunctionRef> &&
+          !is_instantiation<std::remove_cvref_t<Functor>, absl::FunctionRef>>
   struct NotFunctionRef {
     static constexpr bool value = [] {
       static_assert(
@@ -1852,7 +1852,7 @@
   // `OnceCallback` passed to `OnceCallback`, or `RepeatingCallback` passed to
   // `RepeatingCallback`.
   template <typename T>
-    requires is_instantiation<CallbackT, T>
+    requires is_instantiation<T, CallbackT>
   static T BindImpl(T callback) {
     // Guard against null pointers accidentally ending up in posted tasks,
     // causing hard-to-debug crashes.
@@ -1863,7 +1863,7 @@
   // `RepeatingCallback` passed to `OnceCallback`. The opposite direction is
   // intentionally not supported.
   template <typename Signature>
-    requires is_instantiation<CallbackT, OnceCallback<Signature>>
+    requires is_instantiation<OnceCallback<Signature>, CallbackT>
   static OnceCallback<Signature> BindImpl(
       RepeatingCallback<Signature> callback) {
     return BindImpl(OnceCallback<Signature>(callback));
@@ -1914,7 +1914,7 @@
 //   BindOnce(&S::f, weak_s).Run();  // `S::f()` is not called.
 // ```
 template <typename T>
-struct IsWeakReceiver : std::bool_constant<is_instantiation<WeakPtr, T>> {};
+struct IsWeakReceiver : std::bool_constant<is_instantiation<T, WeakPtr>> {};
 
 template <typename T>
 struct IsWeakReceiver<std::reference_wrapper<T>> : IsWeakReceiver<T> {};
@@ -1943,9 +1943,9 @@
 template <typename T>
   requires internal::kIsUnretainedWrapper<internal::UnretainedWrapper, T> ||
            internal::kIsUnretainedWrapper<internal::UnretainedRefWrapper, T> ||
-           is_instantiation<internal::RetainedRefWrapper, T> ||
-           is_instantiation<internal::OwnedWrapper, T> ||
-           is_instantiation<internal::OwnedRefWrapper, T>
+           is_instantiation<T, internal::RetainedRefWrapper> ||
+           is_instantiation<T, internal::OwnedWrapper> ||
+           is_instantiation<T, internal::OwnedRefWrapper>
 struct BindUnwrapTraits<T> {
   static decltype(auto) Unwrap(const T& o) { return o.get(); }
 };
@@ -1998,8 +1998,8 @@
 
 // Specialization for a nested `Bind()`.
 template <typename Functor, typename... BoundArgs>
-  requires is_instantiation<OnceCallback, Functor> ||
-           is_instantiation<RepeatingCallback, Functor>
+  requires is_instantiation<Functor, OnceCallback> ||
+           is_instantiation<Functor, RepeatingCallback>
 struct CallbackCancellationTraits<Functor, std::tuple<BoundArgs...>> {
   static constexpr bool is_cancellable = true;
 
diff --git a/base/functional/function_ref.h b/base/functional/function_ref.h
index 9ee9363..520d94db 100644
--- a/base/functional/function_ref.h
+++ b/base/functional/function_ref.h
@@ -90,10 +90,10 @@
              // we could teach our trampoline to deal with this, but this may be
              // the sign of an object lifetime bug, and again it's not clear
              // that this isn't just a mistake on the part of the user.
-             (!is_instantiation<FunctionRef, std::decay_t<Functor>>) &&
+             (!is_instantiation<std::decay_t<Functor>, FunctionRef>) &&
              // For the same reason as the second case above, prevent
              // construction from `absl::FunctionRef`.
-             (!is_instantiation<absl::FunctionRef, std::decay_t<Functor>>)
+             (!is_instantiation<std::decay_t<Functor>, absl::FunctionRef>)
   // NOLINTNEXTLINE(google-explicit-constructor)
   FunctionRef(const Functor& functor LIFETIME_BOUND)
       : wrapped_func_ref_(functor) {}
diff --git a/base/strings/string_tokenizer.h b/base/strings/string_tokenizer.h
index b37c80c..3e6b20d 100644
--- a/base/strings/string_tokenizer.h
+++ b/base/strings/string_tokenizer.h
@@ -210,7 +210,7 @@
   const_iterator token_end() const { return token_end_; }
   str token() const { return str(token_begin_, token_end_); }
   std::basic_string_view<char_type> token_piece() const {
-    return MakeBasicStringPiece<char_type>(token_begin_, token_end_);
+    return std::basic_string_view(token_begin_, token_end_);
   }
 
  private:
diff --git a/base/strings/string_util.h b/base/strings/string_util.h
index a5917d3..1525d0fd 100644
--- a/base/strings/string_util.h
+++ b/base/strings/string_util.h
@@ -108,31 +108,6 @@
 // This function is intended to be called from base::vswprintf.
 BASE_EXPORT bool IsWprintfFormatPortable(const wchar_t* format);
 
-// Simplified implementation of C++20's std::basic_string_view(It, End).
-// Reference: https://wg21.link/string.view.cons
-template <typename CharT, typename Iter>
-constexpr std::basic_string_view<CharT> MakeBasicStringPiece(Iter begin,
-                                                             Iter end) {
-  DCHECK_GE(end - begin, 0);
-  return {base::to_address(begin), static_cast<size_t>(end - begin)};
-}
-
-// Explicit instantiations of MakeBasicStringPiece.
-template <typename Iter>
-constexpr std::string_view MakeStringPiece(Iter begin, Iter end) {
-  return MakeBasicStringPiece<char>(begin, end);
-}
-
-template <typename Iter>
-constexpr std::u16string_view MakeStringPiece16(Iter begin, Iter end) {
-  return MakeBasicStringPiece<char16_t>(begin, end);
-}
-
-template <typename Iter>
-constexpr std::wstring_view MakeWStringView(Iter begin, Iter end) {
-  return MakeBasicStringPiece<wchar_t>(begin, end);
-}
-
 // ASCII-specific tolower.  The standard library's tolower is locale sensitive,
 // so we don't want to use it here.
 template <typename CharT>
diff --git a/base/strings/string_util_unittest.cc b/base/strings/string_util_unittest.cc
index e994ee8..2bfa190 100644
--- a/base/strings/string_util_unittest.cc
+++ b/base/strings/string_util_unittest.cc
@@ -1606,47 +1606,6 @@
   }
 }
 
-TEST(StringUtilTest, MakeBasicStringPieceTest) {
-  constexpr char kFoo[] = "Foo";
-  static_assert(MakeStringPiece(kFoo, kFoo + 3) == kFoo, "");
-  static_assert(MakeStringPiece(kFoo, kFoo + 3).data() == kFoo, "");
-  static_assert(MakeStringPiece(kFoo, kFoo + 3).size() == 3, "");
-  static_assert(MakeStringPiece(kFoo + 3, kFoo + 3).empty(), "");
-  static_assert(MakeStringPiece(kFoo + 4, kFoo + 4).empty(), "");
-
-  std::string foo = kFoo;
-  EXPECT_EQ(MakeStringPiece(foo.begin(), foo.end()), foo);
-  EXPECT_EQ(MakeStringPiece(foo.begin(), foo.end()).data(), foo.data());
-  EXPECT_EQ(MakeStringPiece(foo.begin(), foo.end()).size(), foo.size());
-  EXPECT_TRUE(MakeStringPiece(foo.end(), foo.end()).empty());
-
-  constexpr char16_t kBar[] = u"Bar";
-  static_assert(MakeStringPiece16(kBar, kBar + 3) == kBar, "");
-  static_assert(MakeStringPiece16(kBar, kBar + 3).data() == kBar, "");
-  static_assert(MakeStringPiece16(kBar, kBar + 3).size() == 3, "");
-  static_assert(MakeStringPiece16(kBar + 3, kBar + 3).empty(), "");
-  static_assert(MakeStringPiece16(kBar + 4, kBar + 4).empty(), "");
-
-  std::u16string bar = kBar;
-  EXPECT_EQ(MakeStringPiece16(bar.begin(), bar.end()), bar);
-  EXPECT_EQ(MakeStringPiece16(bar.begin(), bar.end()).data(), bar.data());
-  EXPECT_EQ(MakeStringPiece16(bar.begin(), bar.end()).size(), bar.size());
-  EXPECT_TRUE(MakeStringPiece16(bar.end(), bar.end()).empty());
-
-  constexpr wchar_t kBaz[] = L"Baz";
-  static_assert(MakeWStringView(kBaz, kBaz + 3) == kBaz, "");
-  static_assert(MakeWStringView(kBaz, kBaz + 3).data() == kBaz, "");
-  static_assert(MakeWStringView(kBaz, kBaz + 3).size() == 3, "");
-  static_assert(MakeWStringView(kBaz + 3, kBaz + 3).empty(), "");
-  static_assert(MakeWStringView(kBaz + 4, kBaz + 4).empty(), "");
-
-  std::wstring baz = kBaz;
-  EXPECT_EQ(MakeWStringView(baz.begin(), baz.end()), baz);
-  EXPECT_EQ(MakeWStringView(baz.begin(), baz.end()).data(), baz.data());
-  EXPECT_EQ(MakeWStringView(baz.begin(), baz.end()).size(), baz.size());
-  EXPECT_TRUE(MakeWStringView(baz.end(), baz.end()).empty());
-}
-
 TEST(StringUtilTest, RemoveChars) {
   const char kRemoveChars[] = "-/+*";
   std::string input = "A-+bc/d!*";
diff --git a/base/task/thread_pool/thread_pool_instance.h b/base/task/thread_pool/thread_pool_instance.h
index b50530b1..7a43a0d 100644
--- a/base/task/thread_pool/thread_pool_instance.h
+++ b/base/task/thread_pool/thread_pool_instance.h
@@ -5,16 +5,12 @@
 #ifndef BASE_TASK_THREAD_POOL_THREAD_POOL_INSTANCE_H_
 #define BASE_TASK_THREAD_POOL_THREAD_POOL_INSTANCE_H_
 
+#include <cstddef>
 #include <memory>
 #include <string_view>
 
 #include "base/base_export.h"
 #include "base/functional/callback.h"
-#include "base/gtest_prod_util.h"
-#include "base/task/sequenced_task_runner.h"
-#include "base/task/single_thread_task_runner.h"
-#include "base/task/single_thread_task_runner_thread_mode.h"
-#include "base/task/task_runner.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 
diff --git a/base/test/rectify_callback_internal.h b/base/test/rectify_callback_internal.h
index 6ac3c8e6..7c6a402 100644
--- a/base/test/rectify_callback_internal.h
+++ b/base/test/rectify_callback_internal.h
@@ -33,7 +33,7 @@
   template <typename Actual>
   static CallbackType<R(IgnoredArgs..., PartialArgs...)> Rectify(
       Actual&& callback) {
-    if constexpr (is_instantiation<OnceCallback, CallbackType<void()>>) {
+    if constexpr (is_instantiation<CallbackType<void()>, OnceCallback>) {
       return BindOnce(
           [](OnceCallback<R(PartialArgs...)> callback, IgnoredArgs...,
              PartialArgs... args) {
diff --git a/base/tracing/stdlib/chrome/scroll_jank/scroll_jank_v3.sql b/base/tracing/stdlib/chrome/scroll_jank/scroll_jank_v3.sql
index 813fc92..9cfb1dbd8 100644
--- a/base/tracing/stdlib/chrome/scroll_jank/scroll_jank_v3.sql
+++ b/base/tracing/stdlib/chrome/scroll_jank/scroll_jank_v3.sql
@@ -473,36 +473,3 @@
 FROM frames
 LEFT JOIN janky_frames
   ON frames.scroll_id = janky_frames.scroll_id;
-
--- Scroll jank causes per scroll.
-CREATE PERFETTO VIEW chrome_causes_per_scroll (
-  -- The ID of the scroll.
-  scroll_id LONG,
-  -- The maximum time a frame was delayed after the presentation of the previous
-  -- frame.
-  max_delay_since_last_frame DOUBLE,
-  -- The expected vsync interval.
-  vsync_interval DOUBLE,
-  -- A proto amalgamation of each scroll jank cause including cause name, sub
-  -- cause and the duration of the delay since the previous frame was presented.
-  scroll_jank_causes BYTES
-) AS
-SELECT
-  scroll_id,
-  max(1.0 * delay_since_last_frame / vsync_interval) AS max_delay_since_last_frame,
-  -- MAX does not matter, since `vsync_interval` is the computed as the
-  -- same value for a single trace.
-  max(vsync_interval) AS vsync_interval,
-  repeatedfield(
-    chromescrolljankv3_scroll_scrolljankcause(
-      'cause',
-      cause_of_jank,
-      'sub_cause',
-      sub_cause_of_jank,
-      'delay_since_last_frame',
-      1.0 * delay_since_last_frame / vsync_interval
-    )
-  ) AS scroll_jank_causes
-FROM chrome_janky_frames
-GROUP BY
-  scroll_id;
diff --git a/base/types/expected_macros.h b/base/types/expected_macros.h
index 5b065ca..1d46b5b 100644
--- a/base/types/expected_macros.h
+++ b/base/types/expected_macros.h
@@ -359,7 +359,7 @@
   {                                                                           \
     static_assert(                                                            \
         base::internal::IsExpected<decltype(expected)> ||                     \
-            base::is_instantiation<std::optional, decltype(expected)>,        \
+            base::is_instantiation<decltype(expected), std::optional>,        \
         #name                                                                 \
         " should only be used with base::expected<> or std::optional<>");     \
   }                                                                           \
diff --git a/base/types/is_instantiation.h b/base/types/is_instantiation.h
index 036d9d1..f8c200d 100644
--- a/base/types/is_instantiation.h
+++ b/base/types/is_instantiation.h
@@ -15,11 +15,11 @@
 //
 // This is false by default. We specialize it to true below for pairs of
 // arguments that satisfy the condition.
-template <template <typename...> class C, typename T>
+template <typename T, template <typename...> class C>
 inline constexpr bool is_instantiation_v = false;
 
 template <template <typename...> class C, typename... Ts>
-inline constexpr bool is_instantiation_v<C, C<Ts...>> = true;
+inline constexpr bool is_instantiation_v<C<Ts...>, C> = true;
 
 }  // namespace internal
 
@@ -28,8 +28,8 @@
 //
 // Note that there is no allowance for reference or const/volatile qualifiers;
 // if these are a concern you probably want to feed through `std::decay_t<T>`.
-template <template <typename...> class C, typename T>
-concept is_instantiation = internal::is_instantiation_v<C, T>;
+template <typename T, template <typename...> class C>
+concept is_instantiation = internal::is_instantiation_v<T, C>;
 
 }  // namespace base
 
diff --git a/base/types/is_instantiation_unittest.cc b/base/types/is_instantiation_unittest.cc
index 286a9e4..ddbf8bb 100644
--- a/base/types/is_instantiation_unittest.cc
+++ b/base/types/is_instantiation_unittest.cc
@@ -18,17 +18,17 @@
 template <typename T1>
 class SingleArg;
 
-static_assert(is_instantiation<SingleArg, SingleArg<int>>);
-static_assert(is_instantiation<SingleArg, SingleArg<char>>);
-static_assert(is_instantiation<SingleArg, SingleArg<std::string>>);
-static_assert(is_instantiation<SingleArg, SingleArg<std::vector<int>>>);
+static_assert(is_instantiation<SingleArg<int>, SingleArg>);
+static_assert(is_instantiation<SingleArg<char>, SingleArg>);
+static_assert(is_instantiation<SingleArg<std::string>, SingleArg>);
+static_assert(is_instantiation<SingleArg<std::vector<int>>, SingleArg>);
 
-static_assert(!is_instantiation<SingleArg, int>);
-static_assert(!is_instantiation<SingleArg, char>);
-static_assert(!is_instantiation<SingleArg, std::vector<int>>);
-static_assert(!is_instantiation<SingleArg, std::vector<SingleArg<int>>>);
+static_assert(!is_instantiation<int, SingleArg>);
+static_assert(!is_instantiation<char, SingleArg>);
+static_assert(!is_instantiation<std::vector<int>, SingleArg>);
+static_assert(!is_instantiation<std::vector<SingleArg<int>>, SingleArg>);
 
-static_assert(!is_instantiation<std::vector, SingleArg<int>>);
+static_assert(!is_instantiation<SingleArg<int>, std::vector>);
 
 /////////////////////////////
 // Variadic template
@@ -37,22 +37,22 @@
 template <typename...>
 class Variadic;
 
-static_assert(is_instantiation<Variadic, Variadic<>>);
-static_assert(is_instantiation<Variadic, Variadic<int>>);
-static_assert(is_instantiation<Variadic, Variadic<int, char>>);
-static_assert(is_instantiation<Variadic, Variadic<int, char, Variadic<>>>);
+static_assert(is_instantiation<Variadic<>, Variadic>);
+static_assert(is_instantiation<Variadic<int>, Variadic>);
+static_assert(is_instantiation<Variadic<int, char>, Variadic>);
+static_assert(is_instantiation<Variadic<int, char, Variadic<>>, Variadic>);
 
-static_assert(!is_instantiation<Variadic, SingleArg<int>>);
-static_assert(!is_instantiation<SingleArg, Variadic<>>);
-static_assert(!is_instantiation<SingleArg, Variadic<int>>);
+static_assert(!is_instantiation<SingleArg<int>, Variadic>);
+static_assert(!is_instantiation<Variadic<>, SingleArg>);
+static_assert(!is_instantiation<Variadic<int>, SingleArg>);
 
 /////////////////////////////
 // Real types
 /////////////////////////////
 
-static_assert(is_instantiation<std::vector, std::vector<bool>>);
-static_assert(is_instantiation<std::vector, std::vector<int>>);
-static_assert(is_instantiation<std::map, std::map<int, char>>);
+static_assert(is_instantiation<std::vector<bool>, std::vector>);
+static_assert(is_instantiation<std::vector<int>, std::vector>);
+static_assert(is_instantiation<std::map<int, char>, std::map>);
 
 }  // namespace
 }  // namespace base
diff --git a/base/types/optional_util.h b/base/types/optional_util.h
index 45ecac4..baa3bcd 100644
--- a/base/types/optional_util.h
+++ b/base/types/optional_util.h
@@ -21,11 +21,11 @@
 
 template <typename Opt>
 concept IsOptional =
-    base::is_instantiation<std::optional, std::remove_cvref_t<Opt>>;
+    base::is_instantiation<std::remove_cvref_t<Opt>, std::optional>;
 
 template <typename Exp>
 concept IsExpected =
-    base::is_instantiation<base::expected, std::remove_cvref_t<Exp>>;
+    base::is_instantiation<std::remove_cvref_t<Exp>, base::expected>;
 
 template <typename Opt>
   requires(IsOptional<Opt>)
diff --git a/cc/layers/heads_up_display_layer_impl.cc b/cc/layers/heads_up_display_layer_impl.cc
index 76179044..72c6d3a6 100644
--- a/cc/layers/heads_up_display_layer_impl.cc
+++ b/cc/layers/heads_up_display_layer_impl.cc
@@ -208,6 +208,10 @@
   // Update state that will be drawn.
   UpdateHudContents();
 
+  // Note the layer properties changed, to force the layer to update changes to
+  // Viz/Display.
+  NoteLayerPropertyChanged();
+
   viz::RasterContextProvider* raster_context_provider = nullptr;
   std::optional<viz::RasterContextProvider::ScopedRasterContextLock> lock;
   if (draw_mode == DRAW_MODE_HARDWARE) {
@@ -449,6 +453,22 @@
   layout_shift_rects_.clear();
 }
 
+void HeadsUpDisplayLayerImpl::GetContentsResourceId(
+    viz::ResourceId* resource_id,
+    gfx::Size* resource_size,
+    gfx::SizeF* resource_uv_size) const {
+  if (in_flight_resource_ && in_flight_resource_.backing()) {
+    *resource_id = in_flight_resource_.resource_id_for_export();
+    *resource_size = in_flight_resource_.size();
+    // HUD layers use the full texture.
+    *resource_uv_size = gfx::SizeF(1.f, 1.f);
+  } else {
+    *resource_id = viz::kInvalidResourceId;
+    *resource_size = gfx::Size();
+    *resource_uv_size = gfx::SizeF();
+  }
+}
+
 void HeadsUpDisplayLayerImpl::PushPropertiesTo(LayerImpl* layer) {
   LayerImpl::PushPropertiesTo(layer);
 
diff --git a/cc/layers/heads_up_display_layer_impl.h b/cc/layers/heads_up_display_layer_impl.h
index 3429d0a..24367850 100644
--- a/cc/layers/heads_up_display_layer_impl.h
+++ b/cc/layers/heads_up_display_layer_impl.h
@@ -81,6 +81,10 @@
   // This evicts hud quad appended during render pass preparation.
   void EvictHudQuad(const viz::CompositorRenderPassList& list);
 
+  void GetContentsResourceId(viz::ResourceId* resource_id,
+                             gfx::Size* resource_size,
+                             gfx::SizeF* resource_uv_size) const override;
+
   // LayerImpl overrides.
   void PushPropertiesTo(LayerImpl* layer) override;
 
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index d963f85..103ddeab 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -2929,7 +2929,6 @@
   std::set<Tile*> unique_tiles;
   bool reached_prepaint = false;
   int non_ideal_tile_count = 0u;
-  int low_res_tile_count = 0u;
   int high_res_tile_count = 0u;
   int high_res_now_tiles = 0u;
   std::unique_ptr<TilingSetRasterQueueAll> queue =
@@ -2955,7 +2954,6 @@
     }
 
     non_ideal_tile_count += priority.resolution == NON_IDEAL_RESOLUTION;
-    low_res_tile_count += priority.resolution == LOW_RESOLUTION;
     high_res_tile_count += priority.resolution == HIGH_RESOLUTION;
 
     unique_tiles.insert(prioritized_tile.tile());
@@ -2964,13 +2962,12 @@
 
   EXPECT_TRUE(reached_prepaint);
   EXPECT_EQ(0, non_ideal_tile_count);
-  EXPECT_EQ(0, low_res_tile_count);
 
   // With layer size being 1000x1000 and default tile size 256x256, we expect to
   // see 4 now tiles out of 16 total high res tiles.
   EXPECT_EQ(16, high_res_tile_count);
   EXPECT_EQ(4, high_res_now_tiles);
-  EXPECT_EQ(low_res_tile_count + high_res_tile_count + non_ideal_tile_count,
+  EXPECT_EQ(high_res_tile_count + non_ideal_tile_count,
             static_cast<int>(unique_tiles.size()));
 
   std::unique_ptr<TilingSetRasterQueueRequired> required_queue =
@@ -4131,47 +4128,35 @@
   ASSERT_TRUE(active_layer()->CanHaveTilings());
   active_layer()->SetContentsScaleForTesting(scale);
   active_layer()->tilings()->RemoveAllTilings();
-  float low_res_factor = 0.25f;
-  active_layer()
-      ->AddTiling(gfx::AxisTransform2d(low_res_factor, gfx::Vector2dF()))
-      ->set_resolution(LOW_RESOLUTION);
   active_layer()
       ->AddTiling(gfx::AxisTransform2d(scale, gfx::Vector2dF()))
       ->set_resolution(HIGH_RESOLUTION);
 
-  ASSERT_EQ(2u, active_layer()->num_tilings());
+  ASSERT_EQ(1u, active_layer()->num_tilings());
 
   host_impl()->AdvanceToNextFrame(base::Milliseconds(1));
   // UpdateDrawProperties with the occluding layer.
   UpdateDrawProperties(host_impl()->active_tree());
 
-  ASSERT_EQ(2u, active_layer()->num_tilings());
+  ASSERT_EQ(1u, active_layer()->num_tilings());
 
   int occluded_tile_count = 0;
-  for (size_t i = 0; i < active_layer()->num_tilings(); ++i) {
-    PictureLayerTiling* tiling = active_layer()->tilings()->tiling_at(i);
-    auto prioritized_tiles =
-        tiling->UpdateAndGetAllPrioritizedTilesForTesting();
-    std::vector<Tile*> tiles = tiling->AllTilesForTesting();
+  PictureLayerTiling* tiling = active_layer()->tilings()->tiling_at(0);
+  auto prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting();
+  std::vector<Tile*> tiles = tiling->AllTilesForTesting();
 
-    occluded_tile_count = 0;
-    for (size_t j = 0; j < tiles.size(); ++j) {
-      if (prioritized_tiles[tiles[j]].is_occluded()) {
-        gfx::Rect scaled_content_rect = ScaleToEnclosingRect(
-            tiles[j]->content_rect(), 1.f / tiles[j]->contents_scale_key());
-        EXPECT_GE(scaled_content_rect.x(), occluding_layer_position.x());
-        occluded_tile_count++;
-      }
-    }
-
-    if (i == 0) {
-      EXPECT_EQ(scale, tiling->contents_scale_key());
-      EXPECT_EQ(occluded_tile_count, expected_occluded_count);
-    } else {
-      ASSERT_EQ(1u, i);
-      EXPECT_EQ(occluded_tile_count, 2);
+  occluded_tile_count = 0;
+  for (size_t i = 0; i < tiles.size(); ++i) {
+    if (prioritized_tiles[tiles[i]].is_occluded()) {
+      gfx::Rect scaled_content_rect = ScaleToEnclosingRect(
+          tiles[i]->content_rect(), 1.f / tiles[i]->contents_scale_key());
+      EXPECT_GE(scaled_content_rect.x(), occluding_layer_position.x());
+      occluded_tile_count++;
     }
   }
+
+  EXPECT_EQ(scale, tiling->contents_scale_key());
+  EXPECT_EQ(occluded_tile_count, expected_occluded_count);
 }
 
 TEST_F(OcclusionTrackingPictureLayerImplTest, OcclusionForScale0_3) {
@@ -4254,11 +4239,6 @@
       // All tiles are unoccluded, because the pending tree has no occlusion.
       EXPECT_FALSE(prioritized_tiles[tile].is_occluded());
 
-      if (tiling->resolution() == LOW_RESOLUTION) {
-        EXPECT_FALSE(active_layer()->GetPendingOrActiveTwinTiling(tiling));
-        continue;
-      }
-
       Tile* twin_tile =
           active_layer()->GetPendingOrActiveTwinTiling(tiling)->TileAt(
               iter.i(), iter.j());
diff --git a/cc/mojo_embedder/viz_layer_context.cc b/cc/mojo_embedder/viz_layer_context.cc
index 5550e0ea..434089b 100644
--- a/cc/mojo_embedder/viz_layer_context.cc
+++ b/cc/mojo_embedder/viz_layer_context.cc
@@ -22,6 +22,7 @@
 #include "cc/animation/animation_timeline.h"
 #include "cc/animation/keyframe_effect.h"
 #include "cc/animation/keyframe_model.h"
+#include "cc/layers/heads_up_display_layer_impl.h"
 #include "cc/layers/layer_impl.h"
 #include "cc/layers/mirror_layer_impl.h"
 #include "cc/layers/nine_patch_thumb_scrollbar_layer_impl.h"
@@ -614,6 +615,38 @@
   }
 }
 
+// Serializes HUD-specific data into a TextureLayerExtra mojom object.
+// HUD layers are treated as Texture layers by Viz.
+void SerializeHudLayerExtra(HeadsUpDisplayLayerImpl& layer,
+                            viz::mojom::TextureLayerExtraPtr& extra,
+                            viz::ClientResourceProvider& resource_provider,
+                            viz::RasterContextProvider& context_provider) {
+  // HUD layers are typically drawn onto a transparent background and then
+  // composited. They don't have a specific background color to blend with.
+  extra->blend_background_color = false;
+  // HUD content (text, graphs) often has alpha.
+  extra->force_texture_to_opaque = false;
+
+  viz::ResourceId resource_id = viz::kInvalidResourceId;
+  gfx::Size resource_size_in_pixels;
+  gfx::SizeF resource_uv_size;
+  layer.GetContentsResourceId(&resource_id, &resource_size_in_pixels,
+                              &resource_uv_size);
+
+  if (resource_id != viz::kInvalidResourceId) {
+    std::vector<viz::ResourceId> ids = {resource_id};
+    std::vector<viz::TransferableResource> resources;
+    resource_provider.PrepareSendToParent(ids, &resources, &context_provider);
+    CHECK_EQ(resources.size(), 1u);
+    extra->transferable_resource = resources[0];
+    extra->uv_top_left = gfx::PointF();
+    extra->uv_bottom_right =
+        gfx::PointF(resource_uv_size.width(), resource_uv_size.height());
+  } else {
+    extra->transferable_resource = viz::TransferableResource();
+  }
+}
+
 void SerializeMirrorLayerExtra(MirrorLayerImpl& layer,
                                viz::mojom::MirrorLayerExtraPtr& extra) {
   extra->mirrored_layer_id = layer.mirrored_layer_id();
@@ -776,6 +809,17 @@
     wire.rare_properties = std::move(rare_properties);
   }
   switch (layer.GetLayerType()) {
+    case mojom::LayerType::kHeadsUpDisplay: {
+      // For Viz, this should look like a Texture layer.
+      wire.type = mojom::LayerType::kTexture;
+      auto texture_layer_extra = viz::mojom::TextureLayerExtra::New();
+      SerializeHudLayerExtra(static_cast<HeadsUpDisplayLayerImpl&>(layer),
+                             texture_layer_extra, resource_provider,
+                             context_provider);
+      wire.layer_extra = viz::mojom::LayerExtra::NewTextureLayerExtra(
+          std::move(texture_layer_extra));
+      break;
+    }
     case mojom::LayerType::kMirror: {
       auto mirror_layer_extra = viz::mojom::MirrorLayerExtra::New();
       SerializeMirrorLayerExtra(static_cast<MirrorLayerImpl&>(layer),
diff --git a/chrome/VERSION b/chrome/VERSION
index bf7bcef..8a864ae 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=139
 MINOR=0
-BUILD=7236
+BUILD=7237
 PATCH=0
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutPTTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutPTTest.java
index 9f4bbb81..aa9ad10 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutPTTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherLayoutPTTest.java
@@ -88,6 +88,7 @@
     ChromeFeatureList.GRID_TAB_SWITCHER_UPDATE,
     ChromeFeatureList.ANDROID_THEME_MODULE
 })
+@DisableIf.Build(sdk_equals = Build.VERSION_CODES.BAKLAVA, message = "crbug.com/424223727")
 public class TabSwitcherLayoutPTTest {
     private static final String TEST_URL = "/chrome/test/data/android/google.html";
 
@@ -563,7 +564,6 @@
 
     @Test
     @MediumTest
-    @DisableIf.Build(sdk_equals = Build.VERSION_CODES.BAKLAVA, message = "crbug.com/424223727")
     public void testTabGroupCreation_rejectInvalidTitle() {
         WebPageStation firstPage = mCtaTestRule.startOnBlankPage();
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/vcn/AutofillVcnEnrollBottomSheetCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/vcn/AutofillVcnEnrollBottomSheetCoordinator.java
index 40801fe..9f3f7e3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/vcn/AutofillVcnEnrollBottomSheetCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/vcn/AutofillVcnEnrollBottomSheetCoordinator.java
@@ -8,6 +8,7 @@
 import android.view.View;
 
 import org.chromium.base.supplier.ObservableSupplier;
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.autofill.AutofillImageFetcherFactory;
 import org.chromium.chrome.browser.autofill.AutofillUiUtils;
 import org.chromium.chrome.browser.autofill.vcn.AutofillVcnEnrollBottomSheetProperties.IssuerIcon;
@@ -20,6 +21,7 @@
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 
 /** Coordinator controller for the virtual card number (VCN) enrollment bottom sheet. */
+@NullMarked
 /*package*/ class AutofillVcnEnrollBottomSheetCoordinator {
     /** Callbacks from the VCN enrollment bottom sheet. */
     interface Delegate {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browsing_data/OtherFormsOfHistoryDialogFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/browsing_data/OtherFormsOfHistoryDialogFragment.java
index 4f39f376..ad4ea34 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browsing_data/OtherFormsOfHistoryDialogFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browsing_data/OtherFormsOfHistoryDialogFragment.java
@@ -17,6 +17,8 @@
 import androidx.fragment.app.DialogFragment;
 import androidx.fragment.app.FragmentActivity;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
@@ -27,6 +29,7 @@
 import org.chromium.ui.text.SpanApplier;
 
 /** Informs the user about the existence of other forms of browsing history. */
+@NullMarked
 public class OtherFormsOfHistoryDialogFragment extends DialogFragment
         implements DialogInterface.OnClickListener {
     private static final String TAG = "OtherFormsOfHistoryDialogFragment";
@@ -40,7 +43,7 @@
     }
 
     @Override
-    public Dialog onCreateDialog(Bundle savedInstanceState) {
+    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
         super.onCreateDialog(savedInstanceState);
         LayoutInflater inflater = getActivity().getLayoutInflater();
         View view = inflater.inflate(R.layout.other_forms_of_history_dialog, null);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java
index 154b6db7..bbf3676 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java
@@ -632,7 +632,7 @@
      * @return                  A {@link SceneLayer} that represents the content for this
      *                          {@link Layout}.
      */
-    public final SceneLayer getUpdatedSceneLayer(
+    public final @Nullable SceneLayer getUpdatedSceneLayer(
             RectF viewport,
             RectF visibleViewport,
             TabContentManager tabContentManager,
@@ -668,7 +668,7 @@
      *
      * @return The scene layer for this {@link Layout}.
      */
-    protected abstract SceneLayer getSceneLayer();
+    protected abstract @Nullable SceneLayer getSceneLayer();
 
     /**
      * Update {@link SceneLayer} instance this layout holds. Any class inheriting {@link Layout}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/SceneChangeObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/SceneChangeObserver.java
index a3f4aca..5da3108 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/SceneChangeObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/SceneChangeObserver.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.compositor.layouts;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.layouts.LayoutStateProvider.LayoutStateObserver;
 
 /**
@@ -12,6 +13,7 @@
  * DEPRECATED, please use {@link LayoutStateObserver} instead.
  */
 @Deprecated
+@NullMarked
 public interface SceneChangeObserver {
     /**
      * Called when the active {@link Layout} changes.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/ToolbarSwipeLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/ToolbarSwipeLayout.java
index 5f2c145..8666289 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/ToolbarSwipeLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/ToolbarSwipeLayout.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.compositor.layouts;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
@@ -19,6 +21,8 @@
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
 import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab;
@@ -54,6 +58,7 @@
 import java.util.List;
 
 /** Layout defining the animation and positioning of the tabs during the edge swipe effect. */
+@NullMarked
 public class ToolbarSwipeLayout extends Layout {
     private static final boolean ANONYMIZE_NON_FOCUSED_TAB = true;
 
@@ -69,16 +74,16 @@
     // This is the max contribution from fling in screen size percentage.
     private static final float FLING_MAX_CONTRIBUTION = 0.5f;
 
-    private LayoutTab mLeftTab;
-    private LayoutTab mRightTab;
-    private LayoutTab mFromTab; // Set to either mLeftTab or mRightTab.
-    private LayoutTab mToTab; // Set to mLeftTab or mRightTab or null if it is not determined.
+    private @Nullable LayoutTab mLeftTab;
+    private @Nullable LayoutTab mRightTab;
+    private @Nullable LayoutTab mFromTab; // Set to either mLeftTab or mRightTab.
+    private @Nullable LayoutTab mToTab; // Set to mLeftTab or mRightTab or null if undetermined.
 
-    private TopToolbarOverlayCoordinator mLeftToolbarOverlay;
-    private TopToolbarOverlayCoordinator mRightToolbarOverlay;
+    private @Nullable TopToolbarOverlayCoordinator mLeftToolbarOverlay;
+    private @Nullable TopToolbarOverlayCoordinator mRightToolbarOverlay;
 
-    private final ObservableSupplierImpl<Tab> mLeftTabSupplier;
-    private final ObservableSupplierImpl<Tab> mRightTabSupplier;
+    private final ObservableSupplierImpl<@Nullable Tab> mLeftTabSupplier;
+    private final ObservableSupplierImpl<@Nullable Tab> mRightTabSupplier;
 
     private final ViewGroup mContentContainer;
 
@@ -95,7 +100,7 @@
     private final float mCommitDistanceFromEdge;
 
     private final BlackHoleEventFilter mBlackHoleEventFilter;
-    private ToolbarSwipeSceneLayer mSceneLayer;
+    private @Nullable ToolbarSwipeSceneLayer mSceneLayer;
 
     private final BrowserControlsStateProvider mBrowserControlsStateProvider;
 
@@ -206,6 +211,7 @@
         // Native pages already had thumbnails captured in `show()` so repeat work can be bypassed
         // by hiding the tab early. This also fixes a blank NTP from being captured after Feed
         // memory optimizations.
+        assumeNonNull(mTabModelSelector);
         Tab currentTab = mTabModelSelector.getCurrentTab();
         if (currentTab != null && currentTab.isNativePage()) {
             // Use type CHANGED_TABS here as it triggers side-effects in observers that we want to
@@ -225,7 +231,10 @@
         mNextTabId = Tab.INVALID_TAB_ID;
         if (mTabModelSelector == null) return;
         Tab tab = mTabModelSelector.getCurrentTab();
-        if (tab != null && tab.isNativePage()) mTabContentManager.cacheTabThumbnail(tab);
+        if (tab != null && tab.isNativePage()) {
+            assumeNonNull(mTabContentManager);
+            mTabContentManager.cacheTabThumbnail(tab);
+        }
 
         TabModel model = mTabModelSelector.getCurrentModel();
         if (model == null) return;
@@ -242,7 +251,7 @@
             // TODO(crbug.com/40233431): Move this piece logic to use a LayoutStateObserver instead
             // - let the caller of the LayoutManager#switchToTab observe the LayoutState and close
             // the ntp tab in the #doneShowing event.
-            Tab lastTab = mTabModelSelector.getTabById(mFromTabId);
+            Tab lastTab = assumeNonNull(mTabModelSelector.getTabById(mFromTabId));
             if (UrlUtilities.isNtpUrl(lastTab.getUrl())
                     && !lastTab.canGoBack()
                     && !lastTab.canGoForward()) {
@@ -307,15 +316,16 @@
         mLeftTabSupplier.set(null);
         mRightTabSupplier.set(null);
 
+        assumeNonNull(mTabModelSelector);
         TabModel model = mTabModelSelector.getCurrentModel();
         if (0 <= leftIndex && leftIndex < model.getCount()) {
-            leftTabId = model.getTabAt(leftIndex).getId();
+            leftTabId = model.getTabAtChecked(leftIndex).getId();
             mLeftTab = createLayoutTab(leftTabId, model.isIncognito());
             prepareLayoutTabForSwipe(mLeftTab, leftIndex != fromIndex);
             mLeftTabSupplier.set(model.getTabAt(leftIndex));
         }
         if (0 <= rightIndex && rightIndex < model.getCount()) {
-            rightTabId = model.getTabAt(rightIndex).getId();
+            rightTabId = model.getTabAtChecked(rightIndex).getId();
             mRightTab = createLayoutTab(rightTabId, model.isIncognito());
             prepareLayoutTabForSwipe(mRightTab, rightIndex != fromIndex);
             mRightTabSupplier.set(model.getTabAt(rightIndex));
@@ -571,7 +581,7 @@
     }
 
     @Override
-    protected SceneLayer getSceneLayer() {
+    protected @Nullable SceneLayer getSceneLayer() {
         return mSceneLayer;
     }
 
@@ -615,6 +625,7 @@
      * @param fromTabId The id of the previous tab which will be switched out.
      */
     public void switchToTab(int toTabId, int fromTabId) {
+        assumeNonNull(mTabModelSelector);
         int fromTabIndex =
                 TabModelUtils.getTabIndexById(mTabModelSelector.getCurrentModel(), fromTabId);
         int toTabIndex =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/CompositorButton.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/CompositorButton.java
index f64690f..698e35fa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/CompositorButton.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/CompositorButton.java
@@ -65,7 +65,7 @@
     private boolean mIsHovered;
     private String mAccessibilityDescriptionIncognito = "";
 
-    private final TooltipHandler mTooltipHandler;
+    private final @Nullable TooltipHandler mTooltipHandler;
 
     // @StripLayoutView the button was embedded in. Null if it's not a child view.
     @Nullable private final StripLayoutView mParentView;
@@ -88,7 +88,7 @@
             StripLayoutView parentView,
             float width,
             float height,
-            TooltipHandler tooltipHandler,
+            @Nullable TooltipHandler tooltipHandler,
             StripLayoutViewOnClickHandler clickHandler,
             StripLayoutViewOnKeyboardFocusHandler keyboardFocusHandler,
             float clickSlopDp) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/TintedCompositorButton.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/TintedCompositorButton.java
index 3f1e550..ea54b98 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/TintedCompositorButton.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/components/TintedCompositorButton.java
@@ -12,6 +12,7 @@
 import androidx.appcompat.content.res.AppCompatResources;
 
 import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutView;
 
 /** Class for a CompositorButton that uses tint instead of multiple drawable resources. */
@@ -40,7 +41,7 @@
             StripLayoutView parentView,
             float width,
             float height,
-            TooltipHandler tooltipHandler,
+            @Nullable TooltipHandler tooltipHandler,
             StripLayoutViewOnClickHandler clickHandler,
             StripLayoutViewOnKeyboardFocusHandler keyboardFocusHandler,
             @DrawableRes int resource,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java
index f820733..c2e3ebb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java
@@ -16,12 +16,13 @@
 
 import androidx.annotation.ColorInt;
 import androidx.annotation.DrawableRes;
-import androidx.annotation.Nullable;
 import androidx.annotation.StringRes;
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.ObserverList;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.compositor.layouts.LayoutRenderHost;
 import org.chromium.chrome.browser.compositor.layouts.LayoutUpdateHost;
@@ -46,6 +47,7 @@
  * {@link StripLayoutTab} is used to keep track of the strip position and rendering information for
  * a particular tab so it can draw itself onto the GL canvas.
  */
+@NullMarked
 public class StripLayoutTab extends StripLayoutView {
     /** An observer interface for StripLayoutTab. */
     public interface Observer {
@@ -164,7 +166,7 @@
     private boolean mShowingCloseButton = true;
 
     // Content Animations
-    private CompositorAnimator mButtonOpacityAnimation;
+    private @Nullable CompositorAnimator mButtonOpacityAnimation;
 
     private float mLoadingSpinnerRotationDegrees;
 
@@ -641,7 +643,11 @@
     }
 
     @Override
-    public void setTouchTargetInsets(Float left, Float top, Float right, Float bottom) {
+    public void setTouchTargetInsets(
+            @Nullable Float left,
+            @Nullable Float top,
+            @Nullable Float right,
+            @Nullable Float bottom) {
         super.setTouchTargetInsets(left, top, right, bottom);
         // The vertical insets of the close button should match that of the parent tab.
         mCloseButton.setTouchTargetInsets(null, top, null, bottom);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutView.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutView.java
index 996a59d..b0a4684 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutView.java
@@ -14,6 +14,7 @@
 
 import org.chromium.base.MathUtils;
 import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.layouts.components.VirtualView;
 import org.chromium.components.browser_ui.styles.ChromeColors;
 
@@ -415,7 +416,11 @@
      * @param right Right inset to apply to touch target.
      * @param bottom Bottom inset to apply to touch target.
      */
-    public void setTouchTargetInsets(Float left, Float top, Float right, Float bottom) {
+    public void setTouchTargetInsets(
+            @Nullable Float left,
+            @Nullable Float top,
+            @Nullable Float right,
+            @Nullable Float bottom) {
         if (left != null) mTouchTargetInsetLeft = left;
         if (right != null) mTouchTargetInsetRight = right;
         if (top != null) mTouchTargetInsetTop = top;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java
index d2e96710..4ab737c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.compositor.scene_layer;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.RectF;
@@ -11,6 +13,8 @@
 import org.jni_zero.JNINamespace;
 import org.jni_zero.NativeMethods;
 
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
 import org.chromium.chrome.browser.compositor.layouts.Layout;
@@ -28,9 +32,10 @@
  * TODO(changwan): change layouts to share one instance of this.
  */
 @JNINamespace("android")
+@NullMarked
 public class TabListSceneLayer extends SceneLayer {
     private long mNativePtr;
-    private TabModelSelector mTabModelSelector;
+    private @Nullable TabModelSelector mTabModelSelector;
     private boolean mIsInitialized;
 
     public void setTabModelSelector(TabModelSelector tabModelSelector) {
@@ -81,7 +86,6 @@
         final int tabListBgColor = getTabListBackgroundColor(context);
 
         LayoutTab[] tabs = layout.getLayoutTabsToRender();
-        int tabsCount = tabs != null ? tabs.length : 0;
 
         if (!mIsInitialized) {
             init(tabContentManager, resourceManager);
@@ -119,7 +123,9 @@
         int contentOffset = browserControls != null ? browserControls.getContentOffset() : 0;
         final int urlBarBackgroundId = R.drawable.modern_location_bar;
 
+        int tabsCount = tabs != null ? tabs.length : 0;
         for (int i = 0; i < tabsCount; i++) {
+            assumeNonNull(tabs);
             LayoutTab t = tabs[i];
             final float decoration = t.getDecorationAlpha();
             boolean useIncognitoColors = t.isIncognito();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ToolbarSwipeSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ToolbarSwipeSceneLayer.java
index d27ae48..faa244e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ToolbarSwipeSceneLayer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ToolbarSwipeSceneLayer.java
@@ -10,6 +10,7 @@
 import org.jni_zero.NativeMethods;
 
 import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab;
 import org.chromium.chrome.browser.layouts.scene_layer.SceneLayer;
 import org.chromium.chrome.browser.tab.Tab;
@@ -27,7 +28,7 @@
         ToolbarSwipeSceneLayerJni.get().setTabContentManager(mNativePtr, this, tabContentManager);
     }
 
-    public void update(LayoutTab tab, boolean isLeftTab, int backgroundColor) {
+    public void update(@Nullable LayoutTab tab, boolean isLeftTab, int backgroundColor) {
         final float dpToPx = mContext.getResources().getDisplayMetrics().density;
 
         ToolbarSwipeSceneLayerJni.get()
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelper.java
index a19303c3..ed7464c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelper.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.customtabs;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.content.Intent;
@@ -11,9 +13,8 @@
 import android.os.Build;
 import android.text.TextUtils;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.browserservices.intents.WebappExtras;
@@ -37,6 +38,7 @@
  *
  * <p>The task description is what is shown in Android's Overview/Recents screen for each entry.
  */
+@NullMarked
 public class CustomTabTaskDescriptionHelper implements NativeInitObserver, DestroyObserver {
     private final Activity mActivity;
     private final CustomTabActivityTabProvider mTabProvider;
@@ -44,18 +46,18 @@
     private final BrowserServicesIntentDataProvider mIntentDataProvider;
     private final TopUiThemeColorProvider mTopUiThemeColorProvider;
 
-    @Nullable private CustomTabTaskDescriptionIconGenerator mIconGenerator;
-    @Nullable private FaviconHelper mFaviconHelper;
+    private @Nullable CustomTabTaskDescriptionIconGenerator mIconGenerator;
+    private @Nullable FaviconHelper mFaviconHelper;
 
-    @Nullable private CustomTabTabObserver mTabObserver;
-    @Nullable private CustomTabTabObserver mIconTabObserver;
+    private @Nullable CustomTabTabObserver mTabObserver;
+    private @Nullable CustomTabTabObserver mIconTabObserver;
 
     private int mDefaultThemeColor;
-    @Nullable private String mForceTitle;
-    @Nullable private Bitmap mForceIcon;
+    private @Nullable String mForceTitle;
+    private @Nullable Bitmap mForceIcon;
     private boolean mUseClientIcon;
 
-    @Nullable private Bitmap mLargestFavicon;
+    private @Nullable Bitmap mLargestFavicon;
 
     public CustomTabTaskDescriptionHelper(
             Activity activity,
@@ -136,12 +138,12 @@
                     }
 
                     @Override
-                    public void onAttachedToInitialTab(@NonNull Tab tab) {
+                    public void onAttachedToInitialTab(Tab tab) {
                         onActiveTabChanged();
                     }
 
                     @Override
-                    public void onObservingDifferentTab(@NonNull Tab tab) {
+                    public void onObservingDifferentTab(Tab tab) {
                         onActiveTabChanged();
                     }
                 };
@@ -212,7 +214,7 @@
     }
 
     /** Computes the title for the task description. */
-    private String computeTitle() {
+    private @Nullable String computeTitle() {
         if (!TextUtils.isEmpty(mForceTitle)) return mForceTitle;
 
         Tab currentTab = mTabProvider.getTab();
@@ -227,7 +229,7 @@
     }
 
     /** Computes the icon for the task description. */
-    private Bitmap computeIcon() {
+    private @Nullable Bitmap computeIcon() {
         if (mUseClientIcon) return null;
 
         if (mForceIcon != null) return mForceIcon;
@@ -237,6 +239,7 @@
 
         Bitmap bitmap = null;
         if (!currentTab.isIncognito()) {
+            assumeNonNull(mIconGenerator);
             bitmap = mIconGenerator.getBitmap(currentTab.getUrl(), mLargestFavicon);
         }
         return bitmap;
@@ -254,6 +257,7 @@
         if (currentTab == null) return;
 
         final GURL currentUrl = currentTab.getUrl();
+        assumeNonNull(mFaviconHelper);
         mFaviconHelper.getLocalFaviconImageForURL(
                 currentTab.getProfile(),
                 currentTab.getUrl(),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionIconGenerator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionIconGenerator.java
index 6e11a6b..d53a96f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionIconGenerator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionIconGenerator.java
@@ -48,7 +48,7 @@
      * @param largestFavicon The largest favicon available at the page URL.
      * @return The icon to use in the recent tasks list.
      */
-    public @Nullable Bitmap getBitmap(GURL pageUrl, Bitmap largestFavicon) {
+    public @Nullable Bitmap getBitmap(GURL pageUrl, @Nullable Bitmap largestFavicon) {
         if (largestFavicon != null
                 && largestFavicon.getWidth() >= mMinSizePx
                 && largestFavicon.getHeight() >= mMinSizePx) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java
index 1073c39..5dc9c97 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationController.java
@@ -147,17 +147,16 @@
 
                 @Override
                 public void onAllTabsClosed() {
-                    mBackPressStateSupplier.set(shouldInterceptBackPress());
-                    finish(mIsHandlingUserNavigation ? USER_NAVIGATION : OTHER);
+                    boolean shouldInterceptBackPress = shouldInterceptBackPress();
+                    mBackPressStateSupplier.set(shouldInterceptBackPress);
+
+                    if (shouldInterceptBackPress) {
+                        finish(mIsHandlingUserNavigation ? USER_NAVIGATION : OTHER);
+                    }
                 }
 
                 private boolean shouldInterceptBackPress() {
-                    // If this is the first tab created or when all other tabs are closed, we want
-                    // the OS to handle the back event then notify the registered observer that the
-                    // back event has happened.
-                    if (supportsPredictiveBackGesture()
-                            && mTabController.onlyOneTabRemaining()
-                            && !mIntentDataProvider.isPartialCustomTab()) {
+                    if (shouldDeferToOs()) {
                         return false;
                     }
                     return mTabProvider.getTab() != null
@@ -193,7 +192,8 @@
         ChromeBrowserInitializer.getInstance()
                 .runNowOrAfterFullBrowserStarted(
                         () -> {
-                            mBackPressStateSupplier.set(mTabProvider.getTab() != null);
+                            mBackPressStateSupplier.set(
+                                    mTabProvider.getTab() != null && !shouldDeferToOs());
                         });
     }
 
@@ -517,6 +517,21 @@
         assert false : assertMsg;
     }
 
+    private boolean shouldDeferToOs() {
+        // If this is the first tab created or when all other tabs are closed, we want
+        // the OS to handle the back event. This allows the predictive back gesture to
+        // show the "back to home" animation. The registered observer will be notified
+        // that the back event has been handled by the OS.
+        // Additionally, we verify that an initial tab has been set and the tab count is either one
+        // or zero if it is a tab that is being initially set before updating the tab count.
+        // This behavior is not applicable to partial custom tabs.
+        return supportsPredictiveBackGesture()
+                && (mTabProvider.getInitialTabCreationMode() != TabCreationMode.NONE
+                        && (mTabController.onlyOneTabRemaining()
+                                || mTabController.getTabCount() == 0))
+                && !mIntentDataProvider.isPartialCustomTab();
+    }
+
     public BrowserServicesIntentDataProvider getIntentDataProviderForTesting() {
         return mIntentDataProvider;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
index 816fdb64..d81e87922 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabController.java
@@ -200,8 +200,18 @@
     }
 
     /**
-     * Checks if the current tab contains unload events and if so it opens the dialog
-     * to ask the user before closing the tab.
+     * Returns the number of tabs in the current model.
+     *
+     * @return The number of tabs.
+     */
+    public int getTabCount() {
+        TabModel model = mTabFactory.getTabModelSelector().getCurrentModel();
+        return model.getCount();
+    }
+
+    /**
+     * Checks if the current tab contains unload events and if so it opens the dialog to ask the
+     * user before closing the tab.
      *
      * @return Whether we ran the unload events or not.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/EngagementSignalsInitialScrollObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/EngagementSignalsInitialScrollObserver.java
index 8c06427..4c80b4e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/EngagementSignalsInitialScrollObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/EngagementSignalsInitialScrollObserver.java
@@ -4,9 +4,8 @@
 
 package org.chromium.chrome.browser.customtabs.content;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.cc.mojom.RootScrollOffsetUpdateFrequency;
 import org.chromium.chrome.browser.customtabs.content.TabObserverRegistrar.CustomTabTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
@@ -22,12 +21,13 @@
  * Class that observes the Custom Tab for an initial scroll down gesture before
  * {@link RealtimeEngagementSignalObserver} is created.
  */
+@NullMarked
 public class EngagementSignalsInitialScrollObserver extends CustomTabTabObserver {
     private final TabObserverRegistrar mTabObserverRegistrar;
 
-    private WebContents mWebContents;
-    private GestureStateListener mGestureStateListener;
-    private WebContentsObserver mWebContentsObserver;
+    private @Nullable WebContents mWebContents;
+    private @Nullable GestureStateListener mGestureStateListener;
+    private @Nullable WebContentsObserver mWebContentsObserver;
     private boolean mHadScrollDown;
 
     public EngagementSignalsInitialScrollObserver(TabObserverRegistrar tabObserverRegistrar) {
@@ -42,12 +42,12 @@
 
     // extends CustomTabTabObserver
     @Override
-    protected void onAttachedToInitialTab(@NonNull Tab tab) {
+    protected void onAttachedToInitialTab(Tab tab) {
         startTrackingScrolls(tab);
     }
 
     @Override
-    protected void onObservingDifferentTab(@NonNull Tab tab) {
+    protected void onObservingDifferentTab(Tab tab) {
         cleanUpListeners();
         startTrackingScrolls(tab);
     }
@@ -130,8 +130,9 @@
                 };
 
         GestureListenerManager gestureListenerManager =
-                GestureListenerManager.fromWebContents(mWebContents);
-        if (!gestureListenerManager.hasListener(mGestureStateListener)) {
+                mWebContents != null ? GestureListenerManager.fromWebContents(mWebContents) : null;
+        if (gestureListenerManager != null
+                && !gestureListenerManager.hasListener(mGestureStateListener)) {
             gestureListenerManager.addListener(
                     mGestureStateListener, RootScrollOffsetUpdateFrequency.NONE);
         }
@@ -140,9 +141,10 @@
     private void cleanUpListeners() {
         mHadScrollDown = false;
         if (mWebContents != null) {
-            if (mGestureStateListener != null) {
-                GestureListenerManager.fromWebContents(mWebContents)
-                        .removeListener(mGestureStateListener);
+            GestureListenerManager gestureListenerManager =
+                    GestureListenerManager.fromWebContents(mWebContents);
+            if (gestureListenerManager != null && mGestureStateListener != null) {
+                gestureListenerManager.removeListener(mGestureStateListener);
             }
             if (mWebContentsObserver != null) {
                 mWebContentsObserver.observe(null);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrar.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrar.java
index 736f132f..7f071a10 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrar.java
@@ -122,7 +122,8 @@
         }
     }
 
-    public void unregisterActivityTabObserver(CustomTabTabObserver observer) {
+    public void unregisterActivityTabObserver(@Nullable CustomTabTabObserver observer) {
+        if (observer == null) return;
         mActivityTabObservers.removeObserver(observer);
         Tab activeTab = mTabProvider.getTab();
         if (activeTab != null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ChromeFeedbackCollector.java b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ChromeFeedbackCollector.java
index d1094e7..6a54011 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ChromeFeedbackCollector.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ChromeFeedbackCollector.java
@@ -6,10 +6,11 @@
 
 import android.app.Activity;
 
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.Callback;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.night_mode.AutoDarkFeedbackSource;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.url.GURL;
@@ -21,6 +22,7 @@
  * Used for gathering a variety of feedback from various components in Chrome and bundling it into
  * a set of Key - Value pairs used to submit feedback requests.
  */
+@NullMarked
 public class ChromeFeedbackCollector extends FeedbackCollector<ChromeFeedbackCollector.InitParams>
         implements Runnable {
     /** Initialization Parameters of the Chrome overload of FeedbackCollector<T>. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feedback/FeedFeedbackCollector.java b/chrome/android/java/src/org/chromium/chrome/browser/feedback/FeedFeedbackCollector.java
index 8d8bb250..1d2cfd6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/feedback/FeedFeedbackCollector.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/feedback/FeedFeedbackCollector.java
@@ -6,10 +6,11 @@
 
 import android.app.Activity;
 
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.Callback;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.profiles.Profile;
 
 import java.util.ArrayList;
@@ -20,6 +21,7 @@
  * Used for gathering feedback from the feed in Chrome and bundling it into a set of Key - Value
  * pairs used to submit feedback requests.
  */
+@NullMarked
 public class FeedFeedbackCollector extends FeedbackCollector<FeedFeedbackCollector.InitParams>
         implements Runnable {
     /** Initialization parameters needed by the Feed overload of FeedbackCollector<T>. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoDescriptionView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoDescriptionView.java
index f162cb0c..d776cf36 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoDescriptionView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoDescriptionView.java
@@ -22,11 +22,13 @@
 import android.widget.TextView;
 
 import androidx.annotation.IdRes;
-import androidx.annotation.NonNull;
 import androidx.annotation.StringRes;
 import androidx.appcompat.widget.SwitchCompat;
 
 import org.chromium.base.Callback;
+import org.chromium.build.annotations.EnsuresNonNullIf;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.settings.SettingsNavigationFactory;
@@ -43,6 +45,7 @@
 import org.chromium.ui.widget.TextViewWithClickableSpans;
 
 /** The view to describle incognito mode. */
+@NullMarked
 public class IncognitoDescriptionView extends LinearLayout {
     private int mWidthDp;
     private int mHeightDp;
@@ -53,11 +56,11 @@
     private LinearLayout mBulletpointsContainer;
     private TextViewWithClickableSpans mLearnMore;
     private TextView[] mParagraphs;
-    private ViewGroup mCookieControlsCard;
-    private SwitchCompat mCookieControlsToggle;
-    private ImageView mCookieControlsManagedIcon;
-    private TextView mCookieControlsTitle;
-    private TextView mCookieControlsSubtitle;
+    private @Nullable ViewGroup mCookieControlsCard;
+    private @Nullable SwitchCompat mCookieControlsToggle;
+    private @Nullable ImageView mCookieControlsManagedIcon;
+    private @Nullable TextView mCookieControlsTitle;
+    private @Nullable TextView mCookieControlsSubtitle;
 
     private static final int BULLETPOINTS_HORIZONTAL_SPACING_DP = 40;
     private static final int BULLETPOINTS_MARGIN_BOTTOM_DP = 12;
@@ -203,7 +206,6 @@
         view.setText(spannedText);
     }
 
-    @NonNull
     static SpannableString getSpannedBulletText(Context context, @StringRes int content) {
         String text = context.getString(content);
         // Some translations don't have a line break between list entries.
@@ -516,12 +518,21 @@
     }
 
     /** Finds the 3PC controls and returns true if they exist. */
+    @EnsuresNonNullIf({
+        "mCookieControlsToggle",
+        "mCookieControlsManagedIcon",
+        "mCookieControlsTitle",
+        "mCookieControlsSubtitle"
+    })
     private boolean findCookieControlElements() {
         mCookieControlsToggle = findViewById(R.id.cookie_controls_card_toggle);
         if (mCookieControlsToggle == null) return false;
         mCookieControlsManagedIcon = findViewById(R.id.cookie_controls_card_managed_icon);
         mCookieControlsTitle = findViewById(R.id.cookie_controls_card_title);
         mCookieControlsSubtitle = findViewById(R.id.cookie_controls_card_subtitle);
+        assert mCookieControlsManagedIcon != null
+                && mCookieControlsTitle != null
+                && mCookieControlsSubtitle != null;
         return true;
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sharing/SharingNotificationUtil.java b/chrome/android/java/src/org/chromium/chrome/browser/sharing/SharingNotificationUtil.java
index 4d43643..4aba1369 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sharing/SharingNotificationUtil.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sharing/SharingNotificationUtil.java
@@ -50,10 +50,10 @@
             @SystemNotificationType int type,
             String group,
             int id,
-            PendingIntentProvider contentIntent,
-            PendingIntentProvider deleteIntent,
-            PendingIntentProvider confirmIntent,
-            PendingIntentProvider cancelIntent,
+            @Nullable PendingIntentProvider contentIntent,
+            @Nullable PendingIntentProvider deleteIntent,
+            @Nullable PendingIntentProvider confirmIntent,
+            @Nullable PendingIntentProvider cancelIntent,
             String contentTitle,
             String contentText,
             @DrawableRes int smallIconId,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java
index 8f607c6..e1d5a64 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java
@@ -20,6 +20,8 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.IntentUtils;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.device.DeviceConditions;
 import org.chromium.chrome.browser.notifications.NotificationConstants;
@@ -28,6 +30,7 @@
 import org.chromium.components.browser_ui.notifications.PendingIntentProvider;
 
 /** Manages ClickToCall related notifications for Android. */
+@NullMarked
 public class ClickToCallMessageHandler {
     private static final String EXTRA_PHONE_NUMBER = "ClickToCallMessageHandler.EXTRA_PHONE_NUMBER";
 
@@ -36,7 +39,7 @@
      *
      * @param phoneNumber The phone number to show in the dialer.
      */
-    private static void openDialer(String phoneNumber) {
+    private static void openDialer(@Nullable String phoneNumber) {
         try {
             ContextUtils.getApplicationContext().startActivity(getDialIntent(phoneNumber));
             ClickToCallUma.recordDialerPresent(true);
@@ -121,7 +124,7 @@
                 /* startsActivity= */ true);
     }
 
-    private static Intent getDialIntent(String phoneNumber) {
+    private static Intent getDialIntent(@Nullable String phoneNumber) {
         Intent dialIntent =
                 TextUtils.isEmpty(phoneNumber)
                         ? new Intent(Intent.ACTION_DIAL)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sharing/sms_fetcher/SmsFetcherMessageHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/sharing/sms_fetcher/SmsFetcherMessageHandler.java
index 73e73c9..3782e6a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sharing/sms_fetcher/SmsFetcherMessageHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sharing/sms_fetcher/SmsFetcherMessageHandler.java
@@ -10,8 +10,6 @@
 import android.content.Intent;
 import android.content.res.Resources;
 
-import androidx.annotation.Nullable;
-
 import org.jni_zero.CalledByNative;
 import org.jni_zero.JniType;
 import org.jni_zero.NativeMethods;
@@ -19,6 +17,8 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.device.DeviceConditions;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -28,20 +28,22 @@
 import org.chromium.components.browser_ui.notifications.PendingIntentProvider;
 
 /** Handles Sms Fetcher messages and notifications for Android. */
+@NullMarked
 public class SmsFetcherMessageHandler {
     private static final String NOTIFICATION_ACTION_CONFIRM = "sms_fetcher_notification.confirm";
     private static final String NOTIFICATION_ACTION_CANCEL = "sms_fetcher_notification.cancel";
     private static final String TAG = "SmsMessageHandler";
     private static final boolean DEBUG = false;
     private static long sSmsFetcherMessageHandlerAndroid;
-    private static String sTopOrigin;
-    private static String sEmbeddedOrigin;
+    private static @Nullable String sTopOrigin;
+    private static @Nullable String sEmbeddedOrigin;
 
     /** Handles the interaction of an incoming notification when an expected SMS arrives. */
     public static final class NotificationReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
+            assert action != null;
             boolean nativeIsDestroyed = sSmsFetcherMessageHandlerAndroid == 0;
             RecordHistogram.recordBooleanHistogram(
                     "Sharing.SmsFetcherTapWithChromeDestroyed", nativeIsDestroyed);
@@ -79,7 +81,10 @@
      * @param clientName The client name where the remote request comes from
      */
     private static String getNotificationTitle(
-            String oneTimeCode, String topOrigin, String embeddedOrigin, String clientName) {
+            String oneTimeCode,
+            String topOrigin,
+            @Nullable String embeddedOrigin,
+            String clientName) {
         Resources resources = ContextUtils.getApplicationContext().getResources();
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.WEB_OTP_CROSS_DEVICE_SIMPLE_STRING)) {
             if (embeddedOrigin == null) {
@@ -106,7 +111,7 @@
      * @param clientName The client name where the remote request comes from
      */
     private static String getNotificationText(
-            String topOrigin, String embeddedOrigin, String clientName) {
+            String topOrigin, @Nullable String embeddedOrigin, String clientName) {
         Resources resources = ContextUtils.getApplicationContext().getResources();
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.WEB_OTP_CROSS_DEVICE_SIMPLE_STRING)) {
             if (embeddedOrigin == null) return clientName;
@@ -193,12 +198,12 @@
     interface Natives {
         void onConfirm(
                 long nativeSmsFetchRequestHandler,
-                @JniType("std::u16string") String topOrigin,
-                String embeddedOrigin);
+                @JniType("std::u16string") @Nullable String topOrigin,
+                @Nullable String embeddedOrigin);
 
         void onDismiss(
                 long nativeSmsFetchRequestHandler,
-                @JniType("std::u16string") String topOrigin,
-                String embeddedOrigin);
+                @JniType("std::u16string") @Nullable String topOrigin,
+                @Nullable String embeddedOrigin);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/ChildAccountStatusSupplier.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/ChildAccountStatusSupplier.java
index 6044778b..6839755 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/ChildAccountStatusSupplier.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/ChildAccountStatusSupplier.java
@@ -6,12 +6,12 @@
 
 import android.os.SystemClock;
 
-import androidx.annotation.Nullable;
-
 import org.chromium.base.Callback;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.base.supplier.OneshotSupplierImpl;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.components.signin.AccountManagerFacade;
 import org.chromium.components.signin.AccountUtils;
 
@@ -25,12 +25,13 @@
  * optimisation creates a potential conflict if there are no app restrictions on a supervised
  * device. However, this should never happen on real devices.
  */
+@NullMarked
 public class ChildAccountStatusSupplier implements OneshotSupplier<Boolean> {
     private final OneshotSupplierImpl<Boolean> mValue = new OneshotSupplierImpl<>();
     private final long mChildAccountStatusStartTime;
 
-    private Boolean mHasRestriction;
-    private Boolean mChildAccountStatusFromAccountManagerFacade;
+    private @Nullable Boolean mHasRestriction;
+    private @Nullable Boolean mChildAccountStatusFromAccountManagerFacade;
 
     /**
      * Creates ChildAccountStatusSupplier and starts fetching the child account status.
@@ -57,12 +58,13 @@
     }
 
     @Override
-    public Boolean onAvailable(Callback<Boolean> callback) {
+    public @Nullable Boolean onAvailable(Callback<Boolean> callback) {
         return mValue.onAvailable(callback);
     }
 
     @Override
-    public Boolean get() {
+    @SuppressWarnings("NullAway") // https://github.com/uber/NullAway/issues/1209
+    public @Nullable Boolean get() {
         return mValue.get();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/PolicyLoadListener.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/PolicyLoadListener.java
index a780836c..1120f96 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/PolicyLoadListener.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/PolicyLoadListener.java
@@ -4,13 +4,13 @@
 
 package org.chromium.chrome.browser.signin;
 
-import androidx.annotation.Nullable;
-
 import org.chromium.base.Callback;
 import org.chromium.base.CallbackController;
 import org.chromium.base.Log;
 import org.chromium.base.supplier.OneshotSupplier;
 import org.chromium.base.supplier.OneshotSupplierImpl;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.components.policy.PolicyService;
 import org.chromium.components.policy.PolicyService.Observer;
 
@@ -28,6 +28,7 @@
  * <p>- Supplies [True] if policy service is initialized and policy might be applied; - Supplies
  * [False] if no app restriction is found, thus no polices will be found on device.
  */
+@NullMarked
 public class PolicyLoadListener implements OneshotSupplier<Boolean> {
     private static final String TAG = "PolicyLoadListener";
 
@@ -35,7 +36,7 @@
     private final OneshotSupplierImpl<Boolean> mMightHavePoliciesSupplier;
     private final OneshotSupplier<PolicyService> mPolicyServiceSupplier;
 
-    private PolicyService.Observer mPolicyServiceObserver;
+    private PolicyService.@Nullable Observer mPolicyServiceObserver;
 
     /**
      * Whether app restriction is found on the device. This can be null when this information is not
@@ -73,12 +74,13 @@
     }
 
     @Override
-    public Boolean onAvailable(Callback<Boolean> callback) {
+    public @Nullable Boolean onAvailable(Callback<Boolean> callback) {
         return mMightHavePoliciesSupplier.onAvailable(mCallbackController.makeCancelable(callback));
     }
 
     @Override
-    public Boolean get() {
+    @SuppressWarnings("NullAway") // https://github.com/uber/NullAway/issues/1209
+    public @Nullable Boolean get() {
         return mMightHavePoliciesSupplier.get();
     }
 
@@ -130,6 +132,7 @@
                                     TAG,
                                     "#onPolicyServiceInitialized() "
                                             + policyService.isInitializationComplete());
+                            assert mPolicyServiceObserver != null;
                             policyService.removeObserver(mPolicyServiceObserver);
                             mPolicyServiceObserver = null;
                             setSupplierIfDecidable();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java
index e0dc815..2a4833942e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java
@@ -4,10 +4,10 @@
 
 package org.chromium.chrome.browser.signin;
 
+import static org.chromium.build.NullUtil.assumeNonNull;
+
 import androidx.annotation.IntDef;
 import androidx.annotation.MainThread;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
 import org.jni_zero.CalledByNative;
@@ -24,6 +24,8 @@
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.task.PostTask;
 import org.chromium.base.task.TaskTraits;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.bookmarks.BookmarkModel;
 import org.chromium.chrome.browser.browsing_data.BrowsingDataBridge;
 import org.chromium.chrome.browser.browsing_data.BrowsingDataType;
@@ -74,6 +76,7 @@
  *
  * <p>See chrome/browser/android/signin/signin_manager_android.h for more details.
  */
+@NullMarked
 class SigninManagerImpl implements IdentityManager.Observer, SigninManager, AccountsChangeObserver {
     private static final String TAG = "SigninManager";
 
@@ -187,8 +190,7 @@
             return;
         }
 
-        @Nullable
-        CoreAccountInfo primaryAccountInfo =
+        @Nullable CoreAccountInfo primaryAccountInfo =
                 mIdentityManager.getPrimaryAccountInfo(ConsentLevel.SIGNIN);
         if (primaryAccountInfo == null) {
             seedThenReloadAllAccountsFromSystem(null);
@@ -323,7 +325,9 @@
     @Override
     public void turnOnSyncForTesting(
             CoreAccountInfo coreAccountInfo, @SigninAccessPoint int accessPoint) {
-        assert mIdentityManager.getPrimaryAccountInfo(ConsentLevel.SIGNIN).equals(coreAccountInfo)
+        CoreAccountInfo primaryAccountInfo =
+                mIdentityManager.getPrimaryAccountInfo(ConsentLevel.SIGNIN);
+        assert primaryAccountInfo != null && primaryAccountInfo.equals(coreAccountInfo)
                 : "Must be signed-in to turn on sync ";
         @PrimaryAccountError
         int primaryAccountError =
@@ -377,7 +381,7 @@
         if (!mAccountManagerFacade.getAccounts().isFulfilled()) {
             throw new IllegalStateException("Account information should be available on signin");
         }
-        if (mSignInState.mCoreAccountInfo == null) {
+        if (mSignInState == null || mSignInState.mCoreAccountInfo == null) {
             throw new IllegalStateException(
                     "The account should be on the device before it can be set as primary.");
         }
@@ -529,7 +533,7 @@
     @Override
     public void signOut(
             @SignoutReason int signoutSource,
-            SignOutCallback signOutCallback,
+            @Nullable SignOutCallback signOutCallback,
             boolean forceWipeUserData) {
         // Only one signOut at a time!
         assert mSignOutState == null;
@@ -556,7 +560,7 @@
      * Returns the management domain if the signed in account is managed, otherwise returns null.
      */
     @Override
-    public String getManagementDomain() {
+    public @Nullable String getManagementDomain() {
         return SigninManagerImplJni.get().getManagementDomain(mNativeSigninManagerAndroid);
     }
 
@@ -643,7 +647,7 @@
 
     @Override
     public void isAccountManaged(
-            @NonNull CoreAccountInfo account, final Callback<Boolean> callback) {
+            @Nullable CoreAccountInfo account, final Callback<Boolean> callback) {
         if (account == null) throw new IllegalArgumentException("Account shouldn't be null!");
 
         if (SigninFeatureMap.isEnabled(
@@ -783,6 +787,7 @@
     }
 
     private void disableSyncAndWipeData(final Runnable wipeDataCallback) {
+        assumeNonNull(mSignOutState);
         Log.i(
                 TAG,
                 "Native signout complete, wiping data (user callback: %s)",
@@ -815,7 +820,7 @@
     private static class SignInState {
         private final @SigninAccessPoint Integer mAccessPoint;
         private final CoreAccountInfo mCoreAccountInfo;
-        final SignInCallback mCallback;
+        final @Nullable SignInCallback mCallback;
 
         /**
          * State for the sign-in flow that doesn't enable sync.
@@ -902,8 +907,7 @@
                 CoreAccountInfo account,
                 Callback<Boolean> callback);
 
-        @Nullable
-        String getManagementDomain(long nativeSigninManagerAndroid);
+        @Nullable String getManagementDomain(long nativeSigninManagerAndroid);
 
         void wipeProfileData(
                 long nativeSigninManagerAndroid,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/StatusIndicatorViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/StatusIndicatorViewBinder.java
index e16cbd6..507f61f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/StatusIndicatorViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/StatusIndicatorViewBinder.java
@@ -9,12 +9,14 @@
 import android.view.View;
 import android.widget.TextView;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.R;
 import org.chromium.components.browser_ui.widget.ViewResourceFrameLayout;
 import org.chromium.components.browser_ui.widget.text.TextViewWithCompoundDrawables;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 
+@NullMarked
 class StatusIndicatorViewBinder {
     /**
      * A wrapper class that holds a {@link ViewResourceFrameLayout} and a composited layer to be
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/mostvisited/MostVisitedSites.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/mostvisited/MostVisitedSites.java
index baf2def..0f03c44f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/mostvisited/MostVisitedSites.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/mostvisited/MostVisitedSites.java
@@ -18,12 +18,19 @@
 public interface MostVisitedSites extends CustomLinkOperations {
     /** An interface for handling events in {@link MostVisitedSites}. */
     interface Observer {
-        /** This is called when the list of most visited URLs is initially available or updated. */
-        void onSiteSuggestionsAvailable(List<SiteSuggestion> siteSuggestions);
+        /**
+         * This is called when the list of most visited URLs is initially available or updated.
+         *
+         * @param isUserTriggered Whether the event is triggered by direct user action. This is
+         *     useful for deciding whether tile update should be eager or deferred.
+         * @param siteSuggestions The list of suggested most visited URLs, with more information.
+         */
+        void onSiteSuggestionsAvailable(
+                boolean isUserTriggered, List<SiteSuggestion> siteSuggestions);
 
         /**
-         * This is called when a previously uncached icon has been fetched.
-         * Parameters guaranteed to be non-null.
+         * This is called when a previously uncached icon has been fetched. Parameters guaranteed to
+         * be non-null.
          *
          * @param siteUrl URL of site with newly-cached icon.
          */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/mostvisited/MostVisitedSitesBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/mostvisited/MostVisitedSitesBridge.java
index ce5d62c..37662ed 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/mostvisited/MostVisitedSitesBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/mostvisited/MostVisitedSitesBridge.java
@@ -170,10 +170,11 @@
      * Parameters guaranteed to be non-null.
      */
     @CalledByNative
-    private void onURLsAvailable(@JniType("std::vector") List<SiteSuggestion> suggestions) {
+    private void onURLsAvailable(
+            boolean isUserTriggered, @JniType("std::vector") List<SiteSuggestion> suggestions) {
         // Don't notify observer if we've already been destroyed.
         if (mNativeMostVisitedSitesBridge != 0 && mWrappedObserver != null) {
-            mWrappedObserver.onSiteSuggestionsAvailable(suggestions);
+            mWrappedObserver.onSiteSuggestionsAvailable(isUserTriggered, suggestions);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/Tile.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/Tile.java
index 674da3a..e69d0dc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/Tile.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/Tile.java
@@ -7,14 +7,15 @@
 import android.content.res.ColorStateList;
 import android.graphics.drawable.Drawable;
 
-import androidx.annotation.Nullable;
-
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.browser.suggestions.OfflinableSuggestion;
 import org.chromium.chrome.browser.suggestions.SiteSuggestion;
 import org.chromium.components.favicon.IconType;
 import org.chromium.url.GURL;
 
 /** Holds the details to populate a site suggestion tile. */
+@NullMarked
 public class Tile implements OfflinableSuggestion {
     private final SiteSuggestion mSiteData;
 
@@ -24,11 +25,11 @@
 
     private @IconType int mIconType = IconType.INVALID;
 
-    @Nullable private Drawable mIcon;
+    private @Nullable Drawable mIcon;
 
-    @Nullable private ColorStateList mIconTint;
+    private @Nullable ColorStateList mIconTint;
 
-    @Nullable private Long mOfflinePageOfflineId;
+    private @Nullable Long mOfflinePageOfflineId;
 
     /**
      * @param suggestion The site data we want to populate the tile with.
@@ -53,9 +54,8 @@
         mOfflinePageOfflineId = offlineId;
     }
 
-    @Nullable
     @Override
-    public Long getOfflinePageOfflineId() {
+    public @Nullable Long getOfflinePageOfflineId() {
         return mOfflinePageOfflineId;
     }
 
@@ -145,7 +145,7 @@
         mIconTint = iconTint;
     }
 
-    public ColorStateList getIconTint() {
+    public @Nullable ColorStateList getIconTint() {
         return mIconTint;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroup.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroup.java
index 647685b..7117e7e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroup.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroup.java
@@ -36,40 +36,16 @@
 public class TileGroup implements MostVisitedSites.Observer {
 
     /**
-     * onSiteSuggestionsAvailable() is asynchronously called from two sources:
+     * This class marshals data involving deferred updates or actions involving suggestion tiles.
      *
-     * <p>1. Backend updates, e.g., triggered by changes from other NTP.
-     *
-     * <p>2. Tile UI updates originating from the current NTP, involving API calls to {@link
-     * Delegate} or {@link CustomTileModificationDelegate}.
-     *
-     * <p>For (2), we'd like to pass data from pre-API calls to onSiteSuggestionsAvailable() and
-     * direct downstream flow (e.g., to call loadTiles()). One way to do this is to pass to the API
-     * and then received by onSiteSuggestionsAvailable() -- but the current code does not do this.
-     *
-     * <p>Instead, the "trans-API" data are stored as fields. This is simple but somewhat sloppy.
-     * This class marshalls these trans-API fields in one place. This also simplifies access from
-     * {@link Delegate} or {@link CustomTileModificationDelegate}.
+     * <p>Suggestions data changes can be caused by (1) the current NTP, or (2) another NTP. This
+     * leads to {@link onSiteSuggestionsAvailable()} call with suggestions passed. Render
+     * suggestions we'd call {@link loadTiles()}. This call may be deferred as an optimization to
+     * avoid useless rendering (e.g., when an NTP is not visible).
      */
     public static class PendingChanges {
-        /** Most recently received tile data that has not been displayed yet. */
-        public @Nullable List<SiteSuggestion> tiles;
-
-        /**
-         * URL of the most recently removed tile. Used to identify when a tile removal is confirmed
-         * by the tile backend.
-         */
-        public @Nullable GURL removalUrl;
-
-        /**
-         * URL of the most recently added tile. Used to identify when a given tile's insertion is
-         * confirmed by the tile backend. This is relevant when a previously existing tile is
-         * removed, then the user undoes the action and wants that tile back.
-         */
-        public @Nullable GURL insertionUrl;
-
-        /** Flag to indicate that Custom Tiles are being changed. */
-        public boolean customTilesIndicator;
+        /** Most recently received tile data pending displayed (eager or deferred). */
+        public @Nullable List<SiteSuggestion> siteSuggestions;
 
         /** List of tasks to run after tiles are reloaded and re-rendered. */
         public final LinkedList<Runnable> taskToRunAfterTileReload = new LinkedList<>();
@@ -80,9 +56,6 @@
      */
     public interface Delegate extends CustomLinkOperations {
 
-        /** Setter to pass object to provide feedback to onSiteSuggestionsAvailable(). */
-        void setPendingChanges(PendingChanges pendingChanges);
-
         /**
          * @param tile The tile corresponding to the most visited item to remove.
          */
@@ -417,7 +390,6 @@
         mUiDelegate.addDestructionObserver(mOfflineModelObserver);
         mCustomTileModificationDelegate = new CustomTileModificationDelegateImpl();
 
-        mTileGroupDelegate.setPendingChanges(mPendingChanges);
         mPrerenderDelay =
                 ChromeFeatureList.getFieldTrialParamByFeatureAsInt(
                         ChromeFeatureList.NEW_TAB_PAGE_ANDROID_TRIGGER_FOR_PRERENDER2,
@@ -426,45 +398,13 @@
     }
 
     @Override
-    public void onSiteSuggestionsAvailable(List<SiteSuggestion> siteSuggestions) {
-        // Only transforms the incoming tiles and stores them in a buffer for when we decide to
-        // refresh the tiles in the UI.
-
-        boolean removalCompleted = mPendingChanges.removalUrl != null;
-        boolean insertionCompleted = mPendingChanges.insertionUrl == null;
-        boolean forceUpdate = false;
-
-        mPendingChanges.tiles = new ArrayList<>();
-        for (SiteSuggestion suggestion : siteSuggestions) {
-            mPendingChanges.tiles.add(suggestion);
-
-            // Only tiles in the personal section can be modified.
-            if (suggestion.sectionType != TileSectionType.PERSONALIZED) continue;
-            if (suggestion.url.equals(mPendingChanges.removalUrl)) removalCompleted = false;
-            if (suggestion.url.equals(mPendingChanges.insertionUrl)) insertionCompleted = true;
-        }
-
-        boolean expectedChangeCompleted = false;
-        if (mPendingChanges.removalUrl != null && removalCompleted) {
-            mPendingChanges.removalUrl = null;
-            expectedChangeCompleted = true;
-        }
-        if (mPendingChanges.insertionUrl != null && insertionCompleted) {
-            mPendingChanges.insertionUrl = null;
-            expectedChangeCompleted = true;
-        }
-        if (mPendingChanges.customTilesIndicator) {
-            mPendingChanges.customTilesIndicator = false;
-            expectedChangeCompleted = true;
-            forceUpdate = true;
-        }
-
-        if (!mHasReceivedData || !mUiDelegate.isVisible() || expectedChangeCompleted) {
-            loadTiles(forceUpdate);
-            for (Runnable task : mPendingChanges.taskToRunAfterTileReload) {
-                task.run();
-            }
-            mPendingChanges.taskToRunAfterTileReload.clear();
+    public void onSiteSuggestionsAvailable(
+            boolean isUserTriggered, List<SiteSuggestion> siteSuggestions) {
+        // Store incoming suggestions for later usage by loadTiles(). This may happen eagerly below
+        // if conditions are met, or deferred to onSwitchToForeground().
+        mPendingChanges.siteSuggestions = new ArrayList<>(siteSuggestions);
+        if (!mHasReceivedData || !mUiDelegate.isVisible() || isUserTriggered) {
+            loadTiles(); // Eager update.
         }
     }
 
@@ -520,7 +460,9 @@
      */
     public void onSwitchToForeground(boolean trackLoadTask) {
         if (trackLoadTask) addTask(TileTask.FETCH_DATA);
-        if (mPendingChanges.tiles != null) loadTiles(/* forceUpdate= */ false);
+        if (mPendingChanges.siteSuggestions != null) {
+            loadTiles(); // Deferred update.
+        }
         if (trackLoadTask) removeTask(TileTask.FETCH_DATA);
     }
 
@@ -528,66 +470,43 @@
         return mTileSetupDelegate;
     }
 
-    /**
-     * Loads tile data from {@link #mPendingChanges.tiles} and clears it afterwards.
-     *
-     * @param forceUpdate Flag to force an update even if tile composition remains the same. A
-     *     particular use case is Custom Tile reordering, which keeps the set of suggestions the
-     *     same but still requires update.
-     */
-    private void loadTiles(boolean forceUpdate) {
-        assert mPendingChanges.tiles != null;
+    /** Loads tile data from {@link #mPendingChanges.siteSuggestions} and clears it afterwards. */
+    private void loadTiles() {
+        assert mPendingChanges.siteSuggestions != null;
 
         boolean isInitialLoad = !mHasReceivedData;
         mHasReceivedData = true;
 
-        boolean dataChanged = forceUpdate || isInitialLoad;
-        List<Tile> personalisedTiles = mTileSections.get(TileSectionType.PERSONALIZED);
-        int oldPersonalisedTilesCount = personalisedTiles == null ? 0 : personalisedTiles.size();
+        List<Tile> oldPersonalizedTiles = mTileSections.get(TileSectionType.PERSONALIZED);
 
-        SparseArray<List<Tile>> newSites = createEmptyTileData();
-        for (int i = 0; i < mPendingChanges.tiles.size(); ++i) {
-            SiteSuggestion suggestion = mPendingChanges.tiles.get(i);
-            if (findTile(suggestion) == null) {
-                // Don't reuse the Tile found, since index might change.
-                dataChanged = true;
+        mTileSections = createTileData(mPendingChanges.siteSuggestions);
+        mPendingChanges.siteSuggestions = null;
+
+        List<Tile> newPersonalizedTiles = mTileSections.get(TileSectionType.PERSONALIZED);
+
+        boolean dataChanged =
+                isInitialLoad || !tileListAreEqual(oldPersonalizedTiles, newPersonalizedTiles);
+
+        if (dataChanged) {
+            mCustomTileCountIsUnderLimit =
+                    TileUtils.customTileCountIsUnderLimit(newPersonalizedTiles);
+
+            mOfflineModelObserver.updateAllSuggestionsOfflineAvailability();
+
+            if (isInitialLoad || oldPersonalizedTiles.size() != newPersonalizedTiles.size()) {
+                mObserver.onTileCountChanged();
             }
 
-            List<Tile> sectionTiles = newSites.get(suggestion.sectionType);
-            if (sectionTiles == null) {
-                sectionTiles = new ArrayList<>();
-                newSites.append(suggestion.sectionType, sectionTiles);
-            }
+            if (isLoadTracked()) addTask(TileTask.SCHEDULE_ICON_FETCH);
+            mObserver.onTileDataChanged();
 
-            // Duplicate should not exist but they may. See https://crbug.com/703628
-            if (findTileByUrl(suggestion.url, sectionTiles) != null) continue;
-
-            sectionTiles.add(new Tile(suggestion, i));
+            if (isInitialLoad) removeTask(TileTask.FETCH_DATA);
         }
 
-        mTileSections = newSites;
-        mPendingChanges.tiles = null;
-
-        // TODO(dgn): change these events, maybe introduce new ones or just change semantics? This
-        // will depend on the UI to be implemented and the desired refresh behaviour.
-        List<Tile> personalizedTiles = mTileSections.get(TileSectionType.PERSONALIZED);
-        int numberOfPersonalizedTiles = personalizedTiles == null ? 0 : personalizedTiles.size();
-        boolean countChanged =
-                isInitialLoad || numberOfPersonalizedTiles != oldPersonalisedTilesCount;
-        dataChanged = dataChanged || countChanged;
-
-        if (!dataChanged) return;
-
-        mCustomTileCountIsUnderLimit = TileUtils.customTileCountIsUnderLimit(personalizedTiles);
-
-        mOfflineModelObserver.updateAllSuggestionsOfflineAvailability();
-
-        if (countChanged) mObserver.onTileCountChanged();
-
-        if (isLoadTracked()) addTask(TileTask.SCHEDULE_ICON_FETCH);
-        mObserver.onTileDataChanged();
-
-        if (isInitialLoad) removeTask(TileTask.FETCH_DATA);
+        for (Runnable task : mPendingChanges.taskToRunAfterTileReload) {
+            task.run();
+        }
+        mPendingChanges.taskToRunAfterTileReload.clear();
     }
 
     protected @Nullable Tile findTile(SiteSuggestion suggestion) {
@@ -603,7 +522,7 @@
      * @param tiles The section to search in, represented by the contained list of tiles.
      * @return A tile matching the provided URL and section, or {@code null} if none is found.
      */
-    private Tile findTileByUrl(GURL url, @Nullable List<Tile> tiles) {
+    private static Tile findTileByUrl(GURL url, @Nullable List<Tile> tiles) {
         if (tiles == null) return null;
         for (Tile tile : tiles) {
             if (tile.getUrl().equals(url)) return tile;
@@ -689,6 +608,42 @@
         return newTileData;
     }
 
+    private static SparseArray<List<Tile>> createTileData(List<SiteSuggestion> suggestions) {
+        SparseArray<List<Tile>> newTileData = createEmptyTileData();
+        for (int i = 0; i < suggestions.size(); ++i) {
+            SiteSuggestion suggestion = suggestions.get(i);
+
+            List<Tile> sectionTiles = newTileData.get(suggestion.sectionType);
+            if (sectionTiles == null) {
+                sectionTiles = new ArrayList<>();
+                newTileData.append(suggestion.sectionType, sectionTiles);
+            }
+
+            // Duplicate should not exist but they may. See https://crbug.com/703628
+            if (findTileByUrl(suggestion.url, sectionTiles) != null) continue;
+
+            sectionTiles.add(new Tile(suggestion, i));
+        }
+
+        return newTileData;
+    }
+
+    private boolean tileListAreEqual(
+            @Nullable List<Tile> tileList1, @Nullable List<Tile> tileList2) {
+        if (tileList1 == null) return tileList2 == null || tileList2.isEmpty();
+        if (tileList2 == null) return tileList1.isEmpty();
+        int n = tileList1.size();
+        if (tileList2.size() != n) return false;
+        for (int i = 0; i < n; ++i) {
+            Tile tile1 = tileList1.get(i);
+            Tile tile2 = tileList2.get(i);
+            if (!tile1.getData().equals(tile2.getData())) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     /** Called before this instance is abandoned to the garbage collector. */
     public void destroy() {
         // The mOfflineModelObserver which implements SuggestionsOfflineModelObserver adds itself
@@ -771,13 +726,11 @@
             }
 
             // On success, onSiteSuggestionsAvailable() triggers.
-            mPendingChanges.customTilesIndicator = true;
             Runnable onSuccessCallback = () -> handleCustomTileAdd(url);
             mPendingChanges.taskToRunAfterTileReload.add(onSuccessCallback);
             boolean success = mTileGroupDelegate.addCustomLink(name, url, pos);
             if (!success) {
                 mPendingChanges.taskToRunAfterTileReload.removeLastOccurrence(onSuccessCallback);
-                mPendingChanges.customTilesIndicator = false;
             }
             return success;
         }
@@ -790,21 +743,17 @@
             }
 
             // On success, onSiteSuggestionsAvailable() triggers.
-            mPendingChanges.customTilesIndicator = true;
             Runnable onSuccessCallback = () -> handleCustomTileAdd(url);
             mPendingChanges.taskToRunAfterTileReload.add(onSuccessCallback);
             boolean success = mTileGroupDelegate.assignCustomLink(keyUrl, name, url);
             if (!success) {
                 mPendingChanges.taskToRunAfterTileReload.removeLastOccurrence(onSuccessCallback);
-                mPendingChanges.customTilesIndicator = false;
             }
             return success;
         }
 
         private void deleteCustomLinkAndUpdateOnSuccess(Tile tile) {
             // On success, onSiteSuggestionsAvailable() triggers.
-            mPendingChanges.customTilesIndicator = true;
-
             if (mTileGroupDelegate.deleteCustomLink(tile.getUrl())) {
                 mTileGroupDelegate.showTileUnpinSnackbar(
                         () -> {
@@ -812,18 +761,11 @@
                             addCustomLinkAndUpdateOnSuccess(
                                     tile.getTitle(), tile.getUrl(), tile.getIndex());
                         });
-            } else {
-                mPendingChanges.customTilesIndicator = false;
             }
         }
 
         private boolean reorderCustomLinkAndUpdateOnSuccess(GURL url, int newPos) {
-            mPendingChanges.customTilesIndicator = true;
-            boolean success = mTileGroupDelegate.reorderCustomLink(url, newPos);
-            if (!success) {
-                mPendingChanges.customTilesIndicator = false;
-            }
-            return success;
+            return mTileGroupDelegate.reorderCustomLink(url, newPos);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroupDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroupDelegateImpl.java
index 122e40b..374e9cb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroupDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/tile/TileGroupDelegateImpl.java
@@ -7,7 +7,6 @@
 import android.content.Context;
 
 import org.chromium.base.metrics.RecordUserAction;
-import org.chromium.build.annotations.Initializer;
 import org.chromium.build.annotations.Nullable;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -17,7 +16,6 @@
 import org.chromium.chrome.browser.suggestions.SuggestionsDependencyFactory;
 import org.chromium.chrome.browser.suggestions.SuggestionsNavigationDelegate;
 import org.chromium.chrome.browser.suggestions.mostvisited.MostVisitedSites;
-import org.chromium.chrome.browser.suggestions.tile.TileGroup.PendingChanges;
 import org.chromium.chrome.browser.suggestions.tile.tile_edit_dialog.CustomTileEditCoordinator;
 import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
@@ -53,7 +51,6 @@
     private final MostVisitedSites mMostVisitedSites;
 
     private @Nullable ModalDialogManager mModalDialogManager;
-    private @Nullable PendingChanges mPendingChanges;
 
     private boolean mIsDestroyed;
     private SnackbarController mTileRemovedSnackbarController;
@@ -107,23 +104,11 @@
         return mMostVisitedSites.reorderCustomLink(keyUrl, newPos);
     }
 
-    // TileGroup.Delegate implementation.
-    @Override
-    @Initializer
-    public void setPendingChanges(PendingChanges pendingChanges) {
-        mPendingChanges = pendingChanges;
-    }
-
     @Override
     public void removeMostVisitedItem(Tile item) {
         assert !mIsDestroyed;
 
         GURL url = item.getUrl();
-        // Handle change detection. This only tracks the most recent removal, and not all removals.
-        // But if the removal is committed, this is good enough for change detection.
-        if (mPendingChanges != null) {
-            mPendingChanges.removalUrl = url;
-        }
         mMostVisitedSites.addBlocklistedUrl(url);
         showTileRemovedSnackbar(url);
     }
@@ -259,9 +244,6 @@
                         public void onAction(Object actionData) {
                             if (mIsDestroyed) return;
                             GURL url = (GURL) actionData;
-                            if (mPendingChanges != null) {
-                                mPendingChanges.insertionUrl = url;
-                            }
                             mMostVisitedSites.removeBlocklistedUrl(url);
                         }
                     };
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/PerformancePTTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/PerformancePTTest.java
index bc19e71..25c44d2 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/PerformancePTTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/PerformancePTTest.java
@@ -5,19 +5,24 @@
 package org.chromium.chrome.browser.compositor;
 
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.when;
 
 import androidx.test.filters.MediumTest;
 
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.transit.TransitAsserts;
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisableIf;
-import org.chromium.base.test.util.Restriction;
+import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.tab.TabStateBrowserControlsVisibilityDelegate;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
@@ -25,8 +30,7 @@
 import org.chromium.chrome.test.transit.ChromeTransitTestRules;
 import org.chromium.chrome.test.transit.page.WebPageStation;
 import org.chromium.chrome.test.transit.testhtmls.TopBottomLinksPageStation;
-import org.chromium.ui.base.DeviceFormFactor;
-import org.chromium.ui.test.util.DeviceRestriction;
+import org.chromium.components.feature_engagement.Tracker;
 
 @RunWith(ChromeJUnit4ClassRunner.class)
 @Batch(Batch.PER_CLASS)
@@ -35,6 +39,21 @@
     public AutoResetCtaTransitTestRule mCtaTestRule =
             ChromeTransitTestRules.autoResetCtaActivityRule();
 
+    @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    @Mock private Tracker mTracker;
+
+    @Before
+    public void setUp() {
+        // Disable IPH. We want the browser controls to scroll off the screen.
+        // An IPH anchored to the toolbar will prevent the browser controls
+        // from being scrolled. Sometimes an IPH appears at the location we
+        // inject the touch event, which also prevents the controls from being
+        // scrolled.
+        when(mTracker.shouldTriggerHelpUi(anyString())).thenReturn(false);
+        TrackerFactory.setTrackerForTests(mTracker);
+    }
+
     private static class TestFrameRequestObserver
             implements CompositorViewHolder.FrameRequestObserver {
         private int mFrameCount;
@@ -52,11 +71,7 @@
     @Test
     @MediumTest
     @CommandLineFlags.Add({ChromeSwitches.DISABLE_MINIMUM_SHOW_DURATION})
-    @DisableIf.Device(DeviceFormFactor.ONLY_TABLET) // Disable on tablet (crbug.com/420861061)
-    @Restriction(
-            DeviceRestriction
-                    .RESTRICTION_TYPE_NON_AUTO) // Disable on automotive (crbug.com/420881807)
-    public void zeroCompositorFramesWhileScrollingBrowserControls() {
+    public void zeroCompositorFramesWhileScrollingBrowserControls() throws Exception {
         ThreadUtils.runOnUiThreadBlocking(
                 () -> {
                     TabStateBrowserControlsVisibilityDelegate.disablePageLoadDelayForTests();
@@ -71,6 +86,10 @@
                 mCtaTestRule.getActivity().getCompositorViewHolderForTesting();
         TestFrameRequestObserver frameObserver = new TestFrameRequestObserver();
 
+        // Some delayed tasks that are posted in response to page load result in additional frames.
+        // Give them time to run before we start counting.
+        Thread.sleep(200);
+
         ThreadUtils.runOnUiThreadBlocking(
                 () -> {
                     compositorViewHolder.addFrameRequestObserver(frameObserver);
@@ -83,8 +102,9 @@
         bottomFacility = topFacility.scrollToBottom();
         topFacility = bottomFacility.scrollToTop();
 
-        // Sometimes, we get one browser frame from scrolling the webpage for the first time, but
-        // we shouldn't get any more frames afterwards.
+        // TODO(https://crbug.com/423953849): We usually get one browser frame from scrolling the
+        // webpage the first time after BottomControlsStacker is initialized, but we shouldn't get
+        // any more frames afterwards.
         int expectedAtMost = 1;
         int actual = frameObserver.getFrameCount();
         assertTrue(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxPTTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxPTTest.java
index ddbdcf56..5a9c2bc 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxPTTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxPTTest.java
@@ -36,6 +36,7 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 @Batch(Batch.PER_CLASS)
+@DisableIf.Build(sdk_equals = Build.VERSION_CODES.BAKLAVA, message = "crbug.com/424223725")
 public class OmniboxPTTest {
     @Rule
     public ReusedCtaTransitTestRule<WebPageStation> mCtaTestRule =
@@ -70,7 +71,6 @@
 
     @LargeTest
     @Test
-    @DisableIf.Build(sdk_equals = Build.VERSION_CODES.BAKLAVA, message = "crbug.com/424223725")
     public void testOpenTypeDelete_fromNtp() {
         WebPageStation blankPage = mCtaTestRule.start();
         RegularNewTabPageStation ntp = blankPage.openNewTabFast();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGroupUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGroupUnitTest.java
index 35036ff..3a417e90 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGroupUnitTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGroupUnitTest.java
@@ -122,7 +122,7 @@
     @SmallTest
     @DisabledTest(message = "https://crbug.com/1292469")
     public void testInitialiseWithTileList() {
-        mMostVisitedSites.setTileSuggestions(URLS);
+        mMostVisitedSites.setTileSuggestionsPassive(URLS);
 
         TileGroup tileGroup =
                 new TileGroup(
@@ -178,7 +178,7 @@
         TileGroup tileGroup = initialiseTileGroup(URLS);
 
         // Notify the same thing. No changes so|mTileGroupObserver| should not be notified.
-        mMostVisitedSites.setTileSuggestions(URLS);
+        mMostVisitedSites.setTileSuggestionsPassive(URLS);
 
         verifyNoMoreInteractions(mTileGroupObserver);
         verifyNoMoreInteractions(mTileGroupDelegate);
@@ -190,11 +190,11 @@
     @SmallTest
     @DisabledTest(message = "https://crbug.com/1336867")
     public void testReceiveNewTilesWithoutChanges_TrackLoad() {
-        TileGroup tileGroup = initialiseTileGroup(/* deferLoad: */ true, URLS);
+        TileGroup tileGroup = initialiseTileGroup(/* deferLoad= */ true, URLS);
 
         // Notify the same thing. No changes so|mTileGroupObserver| should not be notified.
-        mMostVisitedSites.setTileSuggestions(URLS);
-        tileGroup.onSwitchToForeground(/* trackLoadTask: */ true);
+        mMostVisitedSites.setTileSuggestionsPassive(URLS);
+        tileGroup.onSwitchToForeground(/* trackLoadTask= */ true);
 
         verifyNoMoreInteractions(mTileGroupObserver);
         verifyNoMoreInteractions(mTileGroupDelegate);
@@ -209,7 +209,7 @@
 
         // Notify the about different URLs, but the same number. #onTileCountChanged() should not be
         // called.
-        mMostVisitedSites.setTileSuggestions("http://foo.com", "http://bar.com");
+        mMostVisitedSites.setTileSuggestionsPassive("http://foo.com", "http://bar.com");
 
         verify(mTileGroupObserver, never()).onTileCountChanged(); // Tile count is still 2.
         verify(mTileGroupObserver).onTileDataChanged(); // Data DID change.
@@ -224,12 +224,12 @@
     @SmallTest
     // If this flakes again, refer to https://crbug.com/1330627, https://crbug.com/1293208.
     public void testReceiveNewTilesWithDataChanges_TrackLoad() {
-        TileGroup tileGroup = initialiseTileGroup(/* deferLoad: */ true, URLS);
+        TileGroup tileGroup = initialiseTileGroup(/* deferLoad= */ true, URLS);
 
         // Notify the about different URLs, but the same number. #onTileCountChanged() should not be
         // called.
-        mMostVisitedSites.setTileSuggestions("http://foo.com", "http://bar.com");
-        tileGroup.onSwitchToForeground(/* trackLoadTask: */ true);
+        mMostVisitedSites.setTileSuggestionsPassive("http://foo.com", "http://bar.com");
+        tileGroup.onSwitchToForeground(/* trackLoadTask= */ true);
 
         verify(mTileGroupObserver).onTileDataChanged(); // Now data DID change.
         verify(mTileGroupObserver, never()).onTileCountChanged(); // Tile count is still 2.
@@ -271,7 +271,7 @@
                         mOfflinePageBridge);
         tileGroup.startObserving(MAX_TILES_TO_FETCH);
 
-        mMostVisitedSites.setTileSuggestions(URLS);
+        mMostVisitedSites.setTileSuggestionsPassive(URLS);
 
         // Because it's the first load, we accept the incoming tiles and refresh the view.
         verify(mTileGroupObserver).onTileDataChanged();
@@ -294,10 +294,10 @@
                         mOfflinePageBridge);
         tileGroup.startObserving(MAX_TILES_TO_FETCH);
 
-        mMostVisitedSites.setTileSuggestions(URLS);
+        mMostVisitedSites.setTileSuggestionsPassive(URLS);
         reset(mTileGroupObserver);
 
-        mMostVisitedSites.setTileSuggestions(URLS[0]);
+        mMostVisitedSites.setTileSuggestionsPassive(URLS[0]);
 
         // Even though the data changed, the notification should not happen because we want to not
         // show changes to UI elements currently visible
@@ -315,7 +315,7 @@
     public void testTileLoadingWhenVisibleBlocked_2() {
         TileGroup tileGroup = initialiseTileGroup(true, URLS);
 
-        mMostVisitedSites.setTileSuggestions(URLS[0]);
+        mMostVisitedSites.setTileSuggestionsPassive(URLS[0]);
 
         // Even though the data changed, the notification should not happen because we want to not
         // show changes to UI elements currently visible
@@ -362,7 +362,7 @@
         MostVisitedTilesLayout layout = setupView();
 
         // Initialise the internal list of tiles
-        mMostVisitedSites.setTileSuggestions(URLS);
+        mMostVisitedSites.setTileSuggestionsPassive(URLS);
 
         // Render them to the layout.
         refreshData(tileGroup, layout);
@@ -404,7 +404,7 @@
         MostVisitedTilesLayout layout = setupView();
 
         // Initialise the internal list of tiles
-        mMostVisitedSites.setTileSuggestions(URLS[0], URLS[1], URLS[0]);
+        mMostVisitedSites.setTileSuggestionsPassive(URLS[0], URLS[1], URLS[0]);
 
         // Render them to the layout. The duplicated URL should not trigger an exception.
         refreshData(tileGroup, layout);
@@ -443,7 +443,7 @@
                         mTileGroupObserver,
                         mOfflinePageBridge);
         tileGroup.startObserving(MAX_TILES_TO_FETCH);
-        mMostVisitedSites.setTileSuggestions(URLS);
+        mMostVisitedSites.setTileSuggestionsPassive(URLS);
 
         // Initialise the layout with views whose URLs don't match the ones of the new tiles.
         MostVisitedTilesLayout layout = setupView();
@@ -473,7 +473,7 @@
     @UiThreadTest
     @SmallTest
     public void testRenderTileViewRecycling() {
-        mMostVisitedSites.setTileSuggestions(URLS);
+        mMostVisitedSites.setTileSuggestionsPassive(URLS);
         List<SiteSuggestion> sites = mMostVisitedSites.getCurrentSites();
         TileGroup tileGroup =
                 new TileGroup(
@@ -552,7 +552,7 @@
         reset(mTileGroupObserver, mTileGroupDelegate);
 
         // Notify for a second set.
-        mMostVisitedSites.setTileSuggestions(URLS);
+        mMostVisitedSites.setTileSuggestionsPassive(URLS);
         refreshData(tileGroup);
         mImageFetcher.fulfillLargeIconRequests();
 
@@ -567,13 +567,13 @@
     @SmallTest
     @DisabledTest(message = "https://crbug.com/1330627, https://crbug.com/1293208")
     public void testIconLoading_AsyncNoTrack() {
-        TileGroup tileGroup = initialiseTileGroup(/* deferLoad: */ true);
+        TileGroup tileGroup = initialiseTileGroup(/* deferLoad= */ true);
         mImageFetcher.fulfillLargeIconRequests();
         reset(mTileGroupObserver, mTileGroupDelegate);
 
         // Notify for a second set.
-        mMostVisitedSites.setTileSuggestions(URLS);
-        tileGroup.onSwitchToForeground(/* trackLoadTask: */ false);
+        mMostVisitedSites.setTileSuggestionsPassive(URLS);
+        tileGroup.onSwitchToForeground(/* trackLoadTask= */ false);
         refreshData(tileGroup);
         mImageFetcher.fulfillLargeIconRequests();
 
@@ -588,13 +588,13 @@
     @SmallTest
     @DisabledTest(message = "https://crbug.com/1330627, https://crbug.com/1293208")
     public void testIconLoading_AsyncTrack() {
-        TileGroup tileGroup = initialiseTileGroup(/* deferLoad: */ true);
+        TileGroup tileGroup = initialiseTileGroup(/* deferLoad= */ true);
         mImageFetcher.fulfillLargeIconRequests();
         reset(mTileGroupObserver, mTileGroupDelegate);
 
         // Notify for a second set.
-        mMostVisitedSites.setTileSuggestions(URLS);
-        tileGroup.onSwitchToForeground(/* trackLoadTask: */ true);
+        mMostVisitedSites.setTileSuggestionsPassive(URLS);
+        tileGroup.onSwitchToForeground(/* trackLoadTask= */ true);
         refreshData(tileGroup);
         mImageFetcher.fulfillLargeIconRequests();
 
@@ -636,7 +636,11 @@
         when(mSuggestionsUiDelegate.getImageFetcher()).thenReturn(mImageFetcher);
         when(mSuggestionsUiDelegate.isVisible()).thenReturn(deferLoad);
 
-        mMostVisitedSites.setTileSuggestions(urls);
+        if (deferLoad) {
+            mMostVisitedSites.setTileSuggestionsPassive(urls);
+        } else {
+            mMostVisitedSites.setTileSuggestions(urls);
+        }
 
         TileGroup tileGroup =
                 new TileGroup(
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationControllerTest.java
index fc5bdcc..7c1994a 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityNavigationControllerTest.java
@@ -302,14 +302,55 @@
     public void observerDefaultsToOS_WhenOnlyOneTabRemains() {
         CustomTabActivityNavigationController.enablePredictiveBackGestureForTesting();
         when(mTabController.onlyOneTabRemaining()).thenReturn(false);
+        when(mTabController.getTabCount()).thenReturn(2);
         when(mTabController.dispatchBeforeUnloadIfNeeded()).thenReturn(false);
         mNavigationController.getTabObserverForTesting().onTabSwapped(env.prepareTab());
-        assertTrue(mNavigationController.getHandleBackPressChangedSupplier().get());
+        // With multiple tabs, predictive back enabled, and initial tab mode set (default),
+        // Chrome should handle the back press.
+        mNavigationController.getTabObserverForTesting().onTabSwapped(env.prepareTab());
+        Assert.assertTrue(
+                "Chrome should handle back press when multiple tabs are present.",
+                mNavigationController.getHandleBackPressChangedSupplier().get());
+
+        // Now, simulate only one tab remaining.
+        mNavigationController.navigateOnBack(FinishReason.HANDLED_BY_OS);
+        when(mTabController.onlyOneTabRemaining()).thenReturn(true);
+        // When only one tab remains, and predictive back conditions are met,
+        // the OS should handle the back press (supplier should be false).
+        mNavigationController.getTabObserverForTesting().onTabSwapped(env.prepareTab());
+        Assert.assertFalse(
+                "OS should handle back press when only one tab remains.",
+                mNavigationController.getHandleBackPressChangedSupplier().get());
+    }
+
+    @Test
+    public void observerDefaultsToOS_WhenInitialTabCountNotReflected() {
+        CustomTabActivityNavigationController.enablePredictiveBackGestureForTesting();
+        when(mTabController.onlyOneTabRemaining()).thenReturn(false);
+        when(mTabController.getTabCount()).thenReturn(0);
+        when(mTabController.dispatchBeforeUnloadIfNeeded()).thenReturn(false);
+        mNavigationController.getTabObserverForTesting().onTabSwapped(env.prepareTab());
+        Assert.assertFalse(mNavigationController.getHandleBackPressChangedSupplier().get());
 
         mNavigationController.navigateOnBack(FinishReason.HANDLED_BY_OS);
         when(mTabController.onlyOneTabRemaining()).thenReturn(true);
+        mNavigationController
+                .getTabObserverForTesting()
+                .onInitialTabCreated(env.prepareTab(), TabCreationMode.EARLY);
+        Assert.assertFalse(mNavigationController.getHandleBackPressChangedSupplier().get());
+    }
+
+    @Test
+    public void doesNotFinish_WhenOnAllTabsClosedDefersToOS() {
+        CustomTabActivityNavigationController.enablePredictiveBackGestureForTesting();
+        when(mTabController.onlyOneTabRemaining()).thenReturn(true);
+        when(mTabController.dispatchBeforeUnloadIfNeeded()).thenReturn(false);
         mNavigationController.getTabObserverForTesting().onTabSwapped(env.prepareTab());
         Assert.assertFalse(mNavigationController.getHandleBackPressChangedSupplier().get());
+
+        mNavigationController.getTabObserverForTesting().onAllTabsClosed();
+        Assert.assertFalse(mNavigationController.getHandleBackPressChangedSupplier().get());
+        verify(mFinishHandler, never()).onFinish(anyInt(), anyBoolean());
     }
 
     @Test
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerUnitTest.java
index c2530c2..0dad71f 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/content/CustomTabActivityTabControllerUnitTest.java
@@ -388,4 +388,22 @@
         mTabController.finishNativeInitialization();
         assertEquals(tab, env.tabProvider.getTab());
     }
+
+    @Test
+    public void getTabCount_noTabs() {
+        when(env.tabModel.getCount()).thenReturn(0);
+        assertEquals(0, mTabController.getTabCount());
+    }
+
+    @Test
+    public void getTabCount_oneTab() {
+        when(env.tabModel.getCount()).thenReturn(1);
+        assertEquals(1, mTabController.getTabCount());
+    }
+
+    @Test
+    public void getTabCount_multipleTabs() {
+        when(env.tabModel.getCount()).thenReturn(5);
+        assertEquals(5, mTabController.getTabCount());
+    }
 }
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 633c127..896d554 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-139.0.7230.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-139.0.7234.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/os_settings_search_tag_strings.grdp b/chrome/app/os_settings_search_tag_strings.grdp
index fc6056f2..0bd2cb69 100644
--- a/chrome/app/os_settings_search_tag_strings.grdp
+++ b/chrome/app/os_settings_search_tag_strings.grdp
@@ -906,6 +906,9 @@
   <message name="IDS_OS_SETTINGS_TAG_MAGIC_BOOST_LOBSTER" desc="Text for search result item which, when clicked, navigates the user to Create Image settings, with an option to turn functionality on.">
     Create Image
   </message>
+  <message name="IDS_OS_SETTINGS_TAG_SUGGESTED_ACTIONS" desc="Text for search result item which, when clicked, navigates the user to Suggested actions when searching your screen settings, with an option to turn functionality on.">
+    Suggested actions when searching your screen
+  </message>
 
   <!-- Apps section. -->
   <message name="IDS_OS_SETTINGS_TAG_APPS" desc="Text for search result item which, when clicked, navigates the user to apps settings.">
diff --git a/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_SUGGESTED_ACTIONS.png.sha1 b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_SUGGESTED_ACTIONS.png.sha1
new file mode 100644
index 0000000..01399c2
--- /dev/null
+++ b/chrome/app/os_settings_search_tag_strings_grdp/IDS_OS_SETTINGS_TAG_SUGGESTED_ACTIONS.png.sha1
@@ -0,0 +1 @@
+28010407e6986961af87c31c269e67ce1cabb93e
\ No newline at end of file
diff --git a/chrome/app/password_manager_ui_strings.grdp b/chrome/app/password_manager_ui_strings.grdp
index a55701bb..482e0f6 100644
--- a/chrome/app/password_manager_ui_strings.grdp
+++ b/chrome/app/password_manager_ui_strings.grdp
@@ -1010,7 +1010,19 @@
   <message name="IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_BUBBLE_DETAILS" desc="Detailed explanation in the credential leak dialog. This dialog is displayed only when the password change flow is available.">
     Chrome can update your account for this site with a strong password. You won't need to remember the password because it's saved for you in Google Password Manager for <ph name="EMAIL">$2<ex>user@gmail.com</ex></ph>. More about <ph name="PASSWORD_CHANGE">$1<ex>password change</ex></ph>.
   </message>
-   <message name ="IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_PRIVACY_NOTICE" desc="The second paragraph that introduces the automated password change feature and informs the user about information that gets shared with Google to offer the feature. * “password pages and related info”: The feature analyses a site’s password page and other information in order to provide the service. This data might be seen by people who work for Google. Depending on the nature of the site’s password page, this could reveal information about the user that they might now want broadly shared. * “though your password is encrypted” is intended to reassure the user. While info about their experience may be seen by people who work for Google, their password can’t be seen by anyone.">
+  <message name ="IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_DIALOG_TITLE" desc="The title of a dialog that interrupts the user as they're browsing. * “your” is an important keyword to suggest this message personally affects the user. * “public” does two things: 1) it provides distance between “Chrome” and “data breach”, because we don’t want users to associate the breach with Chrome (Chrome didn’t have a data leak, 2) and related, it might reassure the user to know that Chrome is using public information to establish these lists of compromised passwords">
+    Your password was found in a public data breach
+  </message>
+  <message name ="IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_DIALOG_DETAILS" desc="The first paragraph after the title. This paragraph explains what the feature offers. * “can” is important to convey that this is an optional feature. Google Password Manager has the ability to help. * “update your account” refers to the site or app the user is trying to access. For example, the user’s amazon.com password might have been found in a data breach. Google Password Manager can update the way the user gets into their amazon.com account. * “save it in [username@gmail.com]...”: This informs the user where their data gets saved. This is an identifier for their Google Account.">
+    Google Password Manager can update your account with a strong password and save it in <ph name="EMAIL">$1<ex>user@gmail.com</ex></ph>. <ph name="PASSWORD_CHANGE">$2<ex>More about automated password change</ex></ph>
+  </message>
+  <message name ="IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_DIALOG_LINK_WITHOUT_PRIVACY_NOTICE" desc="Link to a help-center article that explain the password change feature in more details.">
+    More about this feature and your privacy
+  </message>
+  <message name ="IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_DIALOG_LINK_WITH_PRIVACY_NOTICE" desc="Link to a help-center article that explains the feature in more detail. * “automated password change”: We were careful to choose “automated” and not “automatic” because we don’t want to give the user the impression that this will happen without their knowledge. There is an ‘automated’ process that the user initiates, but the process isn’t ‘automatic’ in the sense that it might be happening behind the scenes without the user’s knowledge">
+    More about automated password change
+  </message>
+  <message name ="IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_PRIVACY_NOTICE" desc="The second paragraph that introduces the automated password change feature and informs the user about information that gets shared with Google to offer the feature. * “password pages and related info”: The feature analyses a site’s password page and other information in order to provide the service. This data might be seen by people who work for Google. Depending on the nature of the site’s password page, this could reveal information about the user that they might now want broadly shared. * “though your password is encrypted” is intended to reassure the user. While info about their experience may be seen by people who work for Google, their password can’t be seen by anyone.">
     Humans review password pages and related info to improve this feature, though your password is encrypted and never seen by anyone.
   </message>
   <message name="IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_SETTINGS_LINK" desc="The text of the link displayed on password change bubble, which redirects user to the settings page with more information about the feature.">
diff --git a/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_DIALOG_DETAILS.png.sha1 b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_DIALOG_DETAILS.png.sha1
new file mode 100644
index 0000000..914eb8bf
--- /dev/null
+++ b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_DIALOG_DETAILS.png.sha1
@@ -0,0 +1 @@
+145b41ab72632bef16ada91654783d0d1cdc4051
\ No newline at end of file
diff --git a/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_DIALOG_LINK_WITHOUT_PRIVACY_NOTICE.png.sha1 b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_DIALOG_LINK_WITHOUT_PRIVACY_NOTICE.png.sha1
new file mode 100644
index 0000000..914eb8bf
--- /dev/null
+++ b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_DIALOG_LINK_WITHOUT_PRIVACY_NOTICE.png.sha1
@@ -0,0 +1 @@
+145b41ab72632bef16ada91654783d0d1cdc4051
\ No newline at end of file
diff --git a/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_DIALOG_LINK_WITH_PRIVACY_NOTICE.png.sha1 b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_DIALOG_LINK_WITH_PRIVACY_NOTICE.png.sha1
new file mode 100644
index 0000000..c588a04
--- /dev/null
+++ b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_DIALOG_LINK_WITH_PRIVACY_NOTICE.png.sha1
@@ -0,0 +1 @@
+450971db957ea9d7ea5fbe8e25259f2f5b789986
\ No newline at end of file
diff --git a/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_DIALOG_TITLE.png.sha1 b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_DIALOG_TITLE.png.sha1
new file mode 100644
index 0000000..914eb8bf
--- /dev/null
+++ b/chrome/app/password_manager_ui_strings_grdp/IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_DIALOG_TITLE.png.sha1
@@ -0,0 +1 @@
+145b41ab72632bef16ada91654783d0d1cdc4051
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index f2699fd..2cd42d2 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -7786,6 +7786,15 @@
         "//services/accessibility:buildflags",
         "//services/accessibility/public/mojom",
         "//ui/events/ozone/layout:layout",
+
+        # TODO(crbug.com/40227502): Currently EnterpriseDeviceAttributes
+        # internally uses profile manager. We should get rid of it.
+        "//chrome/browser/extensions/api/enterprise_device_attributes",
+      ]
+      allow_circular_includes_from += [
+        # TODO(crbug.com/40227502): Currently EnterpriseDeviceAttributes
+        # internally uses profile manager. We should get rid of it.
+        "//chrome/browser/extensions/api/enterprise_device_attributes",
       ]
     }
   }
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index a88fc32..a7b35cb 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1254,10 +1254,15 @@
 };
 
 const FeatureEntry::FeatureParam kPageActionsMigrationParams[] = {
-    {"lens_overlay", "true"},       {"translate", "true"},
-    {"memory_saver", "true"},       {"price_insights", "true"},
-    {"offer_notification", "true"}, {"intent_picker", "true"},
-    {"file_system_access", "true"}, {"zoom", "true"},
+    {"autofill_address", "true"},
+    {"lens_overlay", "true"},
+    {"translate", "true"},
+    {"memory_saver", "true"},
+    {"price_insights", "true"},
+    {"offer_notification", "true"},
+    {"intent_picker", "true"},
+    {"file_system_access", "true"},
+    {"zoom", "true"},
 };
 const FeatureEntry::FeatureVariation kPageActionsMigrationVariations[] = {
     {"with all migrated page actions enabled", kPageActionsMigrationParams,
diff --git a/chrome/browser/android/examples/inline_autofill_service/src/java/org/chromium/example/autofill_service/fill_service/helpers/ResponseHelper.java b/chrome/browser/android/examples/inline_autofill_service/src/java/org/chromium/example/autofill_service/fill_service/helpers/ResponseHelper.java
index 9c83a1a..fabd04bc 100644
--- a/chrome/browser/android/examples/inline_autofill_service/src/java/org/chromium/example/autofill_service/fill_service/helpers/ResponseHelper.java
+++ b/chrome/browser/android/examples/inline_autofill_service/src/java/org/chromium/example/autofill_service/fill_service/helpers/ResponseHelper.java
@@ -87,7 +87,8 @@
                 hint.contains("password") ? "password for #" + (index + 1) : value;
         Presentations.Builder presentationsBuilder =
                 new Presentations.Builder()
-                        .setDialogPresentation(newDatasetPresentation(displayValue));
+                        .setDialogPresentation(newDatasetPresentation(displayValue))
+                        .setMenuPresentation(newDatasetPresentation(displayValue));
         if (mInlineHelper.hasInlineRequest()) {
             presentationsBuilder.setInlinePresentation(
                     mInlineHelper.createInlineDataset(displayValue, index));
diff --git a/chrome/browser/android/ntp/most_visited_sites_bridge.cc b/chrome/browser/android/ntp/most_visited_sites_bridge.cc
index afd72b9..275b205 100644
--- a/chrome/browser/android/ntp/most_visited_sites_bridge.cc
+++ b/chrome/browser/android/ntp/most_visited_sites_bridge.cc
@@ -136,6 +136,7 @@
   JavaObserver& operator=(const JavaObserver&) = delete;
 
   void OnURLsAvailable(
+      bool is_user_triggered,
       const std::map<SectionType, NTPTilesVector>& sections) override;
 
   void OnIconMadeAvailable(const GURL& site_url) override;
@@ -150,6 +151,7 @@
     : observer_(env, obj) {}
 
 void MostVisitedSitesBridge::JavaObserver::OnURLsAvailable(
+    bool is_user_triggered,
     const std::map<SectionType, NTPTilesVector>& sections) {
   JNIEnv* env = AttachCurrentThread();
   std::vector<jni_zero::ScopedJavaLocalRef<jobject>> suggestions;
@@ -162,7 +164,8 @@
           static_cast<int32_t>(tile.source), section_type));
     }
   }
-  Java_MostVisitedSitesBridge_onURLsAvailable(env, observer_, suggestions);
+  Java_MostVisitedSitesBridge_onURLsAvailable(env, observer_, is_user_triggered,
+                                              suggestions);
 }
 
 void MostVisitedSitesBridge::JavaObserver::OnIconMadeAvailable(
diff --git a/chrome/browser/android/preferences/autofill/autofill_payment_methods_delegate.cc b/chrome/browser/android/preferences/autofill/autofill_payment_methods_delegate.cc
index a466387..5462e67 100644
--- a/chrome/browser/android/preferences/autofill/autofill_payment_methods_delegate.cc
+++ b/chrome/browser/android/preferences/autofill/autofill_payment_methods_delegate.cc
@@ -87,11 +87,10 @@
       personal_data_manager_->payments_data_manager()
           .GetCreditCardByInstrumentId(instrument_id);
   virtual_card_enrollment_manager_->InitVirtualCardEnroll(
-      *credit_card, VirtualCardEnrollmentSource::kSettingsPage,
+      *credit_card, VirtualCardEnrollmentSource::kSettingsPage, std::nullopt,
+      profile_->GetPrefs(), base::BindOnce(&risk_util::LoadRiskDataHelper),
       base::BindOnce(&RunVirtualCardEnrollmentFieldsLoadedCallback,
-                     ScopedJavaGlobalRef<jobject>(jcallback)),
-      std::nullopt, profile_->GetPrefs(),
-      base::BindOnce(&risk_util::LoadRiskDataHelper));
+                     ScopedJavaGlobalRef<jobject>(jcallback)));
 }
 
 void AutofillPaymentMethodsDelegate::EnrollOfferedVirtualCard(
diff --git a/chrome/browser/ash/crosapi/BUILD.gn b/chrome/browser/ash/crosapi/BUILD.gn
index 754d736..aa679a29 100644
--- a/chrome/browser/ash/crosapi/BUILD.gn
+++ b/chrome/browser/ash/crosapi/BUILD.gn
@@ -23,8 +23,6 @@
     "crosapi_manager.h",
     "crosapi_util.cc",
     "crosapi_util.h",
-    "device_attributes_ash.cc",
-    "device_attributes_ash.h",
     "document_scan_ash.cc",
     "document_scan_ash.h",
     "document_scan_ash_type_converters.cc",
@@ -53,8 +51,6 @@
     "parent_access_ash.h",
     "primary_profile_creation_waiter.cc",
     "primary_profile_creation_waiter.h",
-    "structured_metrics_service_ash.cc",
-    "structured_metrics_service_ash.h",
     "vpn_service_ash.cc",
     "vpn_service_ash.h",
   ]
@@ -218,7 +214,6 @@
     "//components/language/core/browser",
     "//components/live_caption:utils",
     "//components/metrics",
-    "//components/metrics/structured",
     "//components/metrics_services_manager:metrics_services_manager",
     "//components/payments/core:error_strings",
     "//components/policy/core/common:common_constants",
@@ -349,7 +344,6 @@
   sources = [
     "cert_provisioning_ash_unittest.cc",
     "crosapi_util_unittest.cc",
-    "device_attributes_ash_unittest.cc",
     "document_scan_ash_type_converters_unittest.cc",
     "document_scan_ash_unittest.cc",
     "keystore_service_ash_unittest.cc",
diff --git a/chrome/browser/ash/crosapi/crosapi_ash.cc b/chrome/browser/ash/crosapi/crosapi_ash.cc
index 2d7c153..d4892fd6 100644
--- a/chrome/browser/ash/crosapi/crosapi_ash.cc
+++ b/chrome/browser/ash/crosapi/crosapi_ash.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/ash/crosapi/cert_provisioning_ash.h"
-#include "chrome/browser/ash/crosapi/device_attributes_ash.h"
 #include "chrome/browser/ash/crosapi/document_scan_ash.h"
 #include "chrome/browser/ash/crosapi/file_system_access_cloud_identifier_provider_ash.h"
 #include "chrome/browser/ash/crosapi/file_system_provider_service_ash.h"
@@ -26,7 +25,6 @@
 #include "chrome/browser/ash/crosapi/multi_capture_service_ash.h"
 #include "chrome/browser/ash/crosapi/networking_attributes_ash.h"
 #include "chrome/browser/ash/crosapi/parent_access_ash.h"
-#include "chrome/browser/ash/crosapi/structured_metrics_service_ash.h"
 #include "chrome/browser/ash/crosapi/vpn_service_ash.h"
 #include "chrome/browser/ash/login/quick_unlock/quick_unlock_factory.h"
 #include "chrome/browser/ash/printing/print_preview/print_preview_webcontents_adapter_ash.h"
@@ -96,7 +94,6 @@
 
 CrosapiAsh::CrosapiAsh()
     : cert_provisioning_ash_(std::make_unique<CertProvisioningAsh>()),
-      device_attributes_ash_(std::make_unique<DeviceAttributesAsh>()),
       diagnostics_service_ash_(std::make_unique<ash::DiagnosticsServiceAsh>()),
       document_scan_ash_(std::make_unique<DocumentScanAsh>()),
       file_system_access_cloud_identifier_provider_ash_(
@@ -119,8 +116,6 @@
       probe_service_ash_(std::make_unique<ash::ProbeServiceAsh>()),
       print_preview_webcontents_adapter_ash_(
           std::make_unique<ash::printing::PrintPreviewWebcontentsAdapterAsh>()),
-      structured_metrics_service_ash_(
-          std::make_unique<StructuredMetricsServiceAsh>()),
       video_conference_manager_ash_(
           std::make_unique<ash::VideoConferenceManagerAsh>()),
       vpn_service_ash_(std::make_unique<VpnServiceAsh>()) {
@@ -171,11 +166,6 @@
   ash::BindCrosDisplayConfigController(std::move(receiver));
 }
 
-void CrosapiAsh::BindDeviceAttributes(
-    mojo::PendingReceiver<mojom::DeviceAttributes> receiver) {
-  device_attributes_ash_->BindReceiver(std::move(receiver));
-}
-
 void CrosapiAsh::BindDiagnosticsService(
     mojo::PendingReceiver<mojom::DiagnosticsService> receiver) {
   diagnostics_service_ash_->BindReceiver(std::move(receiver));
@@ -298,11 +288,6 @@
       std::move(remote));
 }
 
-void CrosapiAsh::BindStructuredMetricsService(
-    mojo::PendingReceiver<crosapi::mojom::StructuredMetricsService> receiver) {
-  structured_metrics_service_ash_->BindReceiver(std::move(receiver));
-}
-
 void CrosapiAsh::BindTelemetryDiagnosticRoutinesService(
     mojo::PendingReceiver<mojom::TelemetryDiagnosticRoutinesService> receiver) {
   telemetry_diagnostic_routine_service_ash_->BindReceiver(std::move(receiver));
diff --git a/chrome/browser/ash/crosapi/crosapi_ash.h b/chrome/browser/ash/crosapi/crosapi_ash.h
index 94f103e6..a4ee6fc9b 100644
--- a/chrome/browser/ash/crosapi/crosapi_ash.h
+++ b/chrome/browser/ash/crosapi/crosapi_ash.h
@@ -44,7 +44,6 @@
 namespace crosapi {
 
 class CertProvisioningAsh;
-class DeviceAttributesAsh;
 class DocumentScanAsh;
 class FileSystemAccessCloudIdentifierProviderAsh;
 class FileSystemProviderServiceAsh;
@@ -55,7 +54,6 @@
 class MultiCaptureServiceAsh;
 class NetworkingAttributesAsh;
 class ParentAccessAsh;
-class StructuredMetricsServiceAsh;
 class VpnServiceAsh;
 
 // Implementation of Crosapi in Ash. It provides a set of APIs that
@@ -83,8 +81,6 @@
   void BindCrosDisplayConfigController(
       mojo::PendingReceiver<mojom::CrosDisplayConfigController> receiver)
       override;
-  void BindDeviceAttributes(
-      mojo::PendingReceiver<mojom::DeviceAttributes> receiver) override;
   void BindDiagnosticsService(
       mojo::PendingReceiver<mojom::DiagnosticsService> receiver) override;
   void BindDocumentScan(
@@ -131,9 +127,6 @@
   void BindSensorHalClient(
       mojo::PendingRemote<chromeos::sensors::mojom::SensorHalClient> remote)
       override;
-  void BindStructuredMetricsService(
-      ::mojo::PendingReceiver<::crosapi::mojom::StructuredMetricsService>
-          receiver) override;
   void BindTelemetryDiagnosticRoutinesService(
       mojo::PendingReceiver<mojom::TelemetryDiagnosticRoutinesService> receiver)
       override;
@@ -157,10 +150,6 @@
     return cert_provisioning_ash_.get();
   }
 
-  DeviceAttributesAsh* device_attributes_ash() {
-    return device_attributes_ash_.get();
-  }
-
   DocumentScanAsh* document_scan_ash() { return document_scan_ash_.get(); }
 
   FileSystemAccessCloudIdentifierProviderAsh*
@@ -199,10 +188,6 @@
 
   ash::ProbeServiceAsh* probe_service_ash() { return probe_service_ash_.get(); }
 
-  StructuredMetricsServiceAsh* structured_metrics_service_ash() {
-    return structured_metrics_service_ash_.get();
-  }
-
   ash::VideoConferenceManagerAsh* video_conference_manager_ash() {
     return video_conference_manager_ash_.get();
   }
@@ -214,7 +199,6 @@
   void OnDisconnected();
 
   std::unique_ptr<CertProvisioningAsh> cert_provisioning_ash_;
-  std::unique_ptr<DeviceAttributesAsh> device_attributes_ash_;
   std::unique_ptr<ash::DiagnosticsServiceAsh> diagnostics_service_ash_;
   std::unique_ptr<DocumentScanAsh> document_scan_ash_;
   std::unique_ptr<FileSystemAccessCloudIdentifierProviderAsh>
@@ -236,7 +220,6 @@
   std::unique_ptr<ash::ProbeServiceAsh> probe_service_ash_;
   std::unique_ptr<ash::printing::PrintPreviewWebcontentsAdapterAsh>
       print_preview_webcontents_adapter_ash_;
-  std::unique_ptr<StructuredMetricsServiceAsh> structured_metrics_service_ash_;
   std::unique_ptr<ash::VideoConferenceManagerAsh> video_conference_manager_ash_;
   std::unique_ptr<VpnServiceAsh> vpn_service_ash_;
 
diff --git a/chrome/browser/ash/crosapi/device_attributes_ash.cc b/chrome/browser/ash/crosapi/device_attributes_ash.cc
deleted file mode 100644
index cf1057b..0000000
--- a/chrome/browser/ash/crosapi/device_attributes_ash.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/crosapi/device_attributes_ash.h"
-
-#include <optional>
-#include <string>
-#include <utility>
-
-#include "base/functional/bind.h"
-#include "chrome/browser/apps/app_service/metrics/app_platform_metrics_utils.h"
-#include "chrome/browser/ash/crosapi/crosapi_util.h"
-#include "chrome/browser/ash/policy/core/device_attributes.h"
-#include "chrome/browser/ash/policy/core/device_attributes_fake.h"
-#include "chrome/browser/ash/policy/core/device_attributes_impl.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chromeos/crosapi/mojom/device_attributes.mojom.h"
-
-namespace crosapi {
-
-namespace {
-
-const char kAccessDenied[] = "Access denied.";
-
-void GetAttribute(
-    base::OnceCallback<void(mojom::DeviceAttributesStringResultPtr)> callback,
-    const std::string& attr_value) {
-  Profile* profile =
-      g_browser_process->profile_manager()->GetPrimaryUserProfile();
-  if (!browser_util::IsSigninProfileOrBelongsToAffiliatedUser(profile)) {
-    std::move(callback).Run(
-        mojom::DeviceAttributesStringResult::NewErrorMessage(kAccessDenied));
-    return;
-  }
-
-  std::move(callback).Run(
-      mojom::DeviceAttributesStringResult::NewContents(attr_value));
-}
-
-}  // namespace
-
-DeviceAttributesAsh::DeviceAttributesAsh()
-    : attributes_(std::make_unique<policy::DeviceAttributesImpl>()) {}
-
-DeviceAttributesAsh::~DeviceAttributesAsh() = default;
-
-void DeviceAttributesAsh::BindReceiver(
-    mojo::PendingReceiver<mojom::DeviceAttributes> receiver) {
-  receivers_.Add(this, std::move(receiver));
-}
-
-void DeviceAttributesAsh::GetDirectoryDeviceId(
-    GetDirectoryDeviceIdCallback callback) {
-  GetAttribute(std::move(callback), attributes_->GetDirectoryApiID());
-}
-
-void DeviceAttributesAsh::GetDeviceSerialNumber(
-    GetDeviceSerialNumberCallback callback) {
-  GetAttribute(std::move(callback), attributes_->GetDeviceSerialNumber());
-}
-
-void DeviceAttributesAsh::GetDeviceAssetId(GetDeviceAssetIdCallback callback) {
-  GetAttribute(std::move(callback), attributes_->GetDeviceAssetID());
-}
-
-void DeviceAttributesAsh::GetDeviceAnnotatedLocation(
-    GetDeviceAnnotatedLocationCallback callback) {
-  GetAttribute(std::move(callback), attributes_->GetDeviceAnnotatedLocation());
-}
-
-void DeviceAttributesAsh::GetDeviceHostname(
-    GetDeviceHostnameCallback callback) {
-  GetAttribute(std::move(callback),
-               attributes_->GetDeviceHostname().value_or(""));
-}
-
-void DeviceAttributesAsh::GetDeviceTypeForMetrics(
-    GetDeviceTypeForMetricsCallback callback) {
-  std::move(callback).Run(apps::GetUserTypeByDeviceTypeMetrics());
-}
-
-void DeviceAttributesAsh::SetDeviceAttributesForTesting(
-    std::unique_ptr<policy::FakeDeviceAttributes> attributes) {
-  attributes_ = std::move(attributes);
-}
-
-}  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/device_attributes_ash.h b/chrome/browser/ash/crosapi/device_attributes_ash.h
deleted file mode 100644
index 8a082fd3..0000000
--- a/chrome/browser/ash/crosapi/device_attributes_ash.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ASH_CROSAPI_DEVICE_ATTRIBUTES_ASH_H_
-#define CHROME_BROWSER_ASH_CROSAPI_DEVICE_ATTRIBUTES_ASH_H_
-
-#include "chrome/browser/ash/policy/core/device_attributes.h"
-#include "chromeos/crosapi/mojom/device_attributes.mojom.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
-
-namespace policy {
-class FakeDeviceAttributes;
-}
-
-namespace crosapi {
-
-// The ash-chrome implementation of the DeviceAttributes crosapi interface.
-// This class must only be used from the main thread.
-class DeviceAttributesAsh : public mojom::DeviceAttributes {
- public:
-  DeviceAttributesAsh();
-  DeviceAttributesAsh(const DeviceAttributesAsh&) = delete;
-  DeviceAttributesAsh& operator=(const DeviceAttributesAsh&) = delete;
-  ~DeviceAttributesAsh() override;
-
-  void BindReceiver(mojo::PendingReceiver<mojom::DeviceAttributes> receiver);
-
-  // crosapi::mojom::DeviceAttributes:
-  void GetDirectoryDeviceId(GetDirectoryDeviceIdCallback callback) override;
-  void GetDeviceSerialNumber(GetDeviceSerialNumberCallback callback) override;
-  void GetDeviceAssetId(GetDeviceAssetIdCallback callback) override;
-  void GetDeviceAnnotatedLocation(
-      GetDeviceAnnotatedLocationCallback callback) override;
-  void GetDeviceHostname(GetDeviceHostnameCallback callback) override;
-  void GetDeviceTypeForMetrics(
-      GetDeviceTypeForMetricsCallback callback) override;
-
-  void SetDeviceAttributesForTesting(
-      std::unique_ptr<policy::FakeDeviceAttributes> attributes);
-
- private:
-  using StringResult = mojom::DeviceAttributesStringResult;
-
-  // This class supports any number of connections.
-  mojo::ReceiverSet<mojom::DeviceAttributes> receivers_;
-
-  std::unique_ptr<policy::DeviceAttributes> attributes_;
-};
-
-}  // namespace crosapi
-
-#endif  // CHROME_BROWSER_ASH_CROSAPI_DEVICE_ATTRIBUTES_ASH_H_
diff --git a/chrome/browser/ash/crosapi/device_attributes_ash_unittest.cc b/chrome/browser/ash/crosapi/device_attributes_ash_unittest.cc
deleted file mode 100644
index 8bb6824..0000000
--- a/chrome/browser/ash/crosapi/device_attributes_ash_unittest.cc
+++ /dev/null
@@ -1,221 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ash/crosapi/device_attributes_ash.h"
-
-#include "base/test/test_future.h"
-#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
-#include "chrome/browser/ash/policy/core/device_attributes_fake.h"
-#include "chrome/browser/ash/profiles/profile_helper.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/common/chrome_constants.h"
-#include "chrome/test/base/scoped_testing_local_state.h"
-#include "chrome/test/base/testing_browser_process.h"
-#include "chrome/test/base/testing_profile.h"
-#include "chrome/test/base/testing_profile_manager.h"
-#include "chromeos/ash/components/browser_context_helper/browser_context_helper.h"
-#include "chromeos/crosapi/mojom/device_attributes.mojom.h"
-#include "components/account_id/account_id.h"
-#include "components/user_manager/scoped_user_manager.h"
-#include "components/user_manager/test_helper.h"
-#include "content/public/test/browser_task_environment.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-const char kErrorUserNotAffiliated[] = "Access denied.";
-
-constexpr char kFakeAnnotatedLocation[] = "fake annotated location";
-constexpr char kFakeAssetId[] = "fake asset ID";
-constexpr char kFakeSerialNumber[] = "fake serial number";
-constexpr char kFakeDirectoryApiId[] = "fake directory API ID";
-constexpr char kFakeHostname[] = "fake-hostname";
-
-enum class TestProfileChoice {
-  kSigninProfile,
-  kNonAffiliatedProfile,
-  kAffiliatedProfile
-};
-
-std::string ParamToString(
-    const testing::TestParamInfo<TestProfileChoice>& info) {
-  switch (info.param) {
-    case TestProfileChoice::kSigninProfile:
-      return "SigninProfile";
-    case TestProfileChoice::kNonAffiliatedProfile:
-      return "NonAffiliatedUser";
-    case TestProfileChoice::kAffiliatedProfile:
-      return "AffiliatedUser";
-  }
-}
-
-}  // namespace
-
-namespace crosapi {
-
-class DeviceAttributesAshTest
-    : public testing::TestWithParam<TestProfileChoice> {
- public:
-  DeviceAttributesAshTest() = default;
-  ~DeviceAttributesAshTest() override = default;
-
-  void SetUp() override {
-    fake_user_manager_.Reset(std::make_unique<ash::FakeChromeUserManager>());
-
-    // Set up fake device attributes.
-    device_attributes_ = std::make_unique<policy::FakeDeviceAttributes>();
-    device_attributes_->SetFakeDirectoryApiId(kFakeDirectoryApiId);
-    device_attributes_->SetFakeDeviceSerialNumber(kFakeSerialNumber);
-    device_attributes_->SetFakeDeviceAssetId(kFakeAssetId);
-    device_attributes_->SetFakeDeviceAnnotatedLocation(kFakeAnnotatedLocation);
-    device_attributes_->SetFakeDeviceHostname(kFakeHostname);
-
-    device_attributes_ash_ = std::make_unique<DeviceAttributesAsh>();
-    device_attributes_ash_->SetDeviceAttributesForTesting(
-        std::move(device_attributes_));
-    device_attributes_ash_->BindReceiver(
-        device_attributes_remote_.BindNewPipeAndPassReceiver());
-
-    profile_manager_ = std::make_unique<TestingProfileManager>(
-        TestingBrowserProcess::GetGlobal());
-    ASSERT_TRUE(profile_manager_->SetUp());
-    profile_ = profile_manager_->CreateTestingProfile(
-        TestingProfile::kDefaultProfileUserName);
-
-    switch (GetParam()) {
-      case TestProfileChoice::kSigninProfile:
-        TestingProfile* signin_profile;
-        signin_profile = static_cast<TestingProfile*>(
-            ash::ProfileHelper::GetSigninProfile());
-        EXPECT_TRUE(ProfileManager::GetPrimaryUserProfile()->IsSameOrParent(
-            signin_profile));
-        ASSERT_EQ(signin_profile, ProfileManager::GetPrimaryUserProfile());
-        break;
-      case TestProfileChoice::kNonAffiliatedProfile:
-        AddUser(/*is_affiliated=*/false);
-        break;
-      case TestProfileChoice::kAffiliatedProfile:
-        AddUser(/*is_affiliated=*/true);
-        break;
-    }
-  }
-
-  void TearDown() override { device_attributes_ash_.reset(); }
-
-  void AddUser(bool is_affiliated = true) {
-    AccountId account_id =
-        AccountId::FromUserEmail(TestingProfile::kDefaultProfileUserName);
-    fake_user_manager_->AddUserWithAffiliation(account_id, is_affiliated);
-    fake_user_manager_->UserLoggedIn(
-        account_id, user_manager::TestHelper::GetFakeUsernameHash(account_id));
-    fake_user_manager_->SimulateUserProfileLoad(account_id);
-  }
-
-  bool IsSigninProfileOrBelongsToAffiliatedUser() {
-    switch (GetParam()) {
-      case TestProfileChoice::kSigninProfile:
-      case TestProfileChoice::kAffiliatedProfile:
-        return true;
-      case TestProfileChoice::kNonAffiliatedProfile:
-        return false;
-    }
-  }
-
- protected:
-  content::BrowserTaskEnvironment task_environment_;
-
-  user_manager::TypedScopedUserManager<ash::FakeChromeUserManager>
-      fake_user_manager_;
-  std::unique_ptr<TestingProfileManager> profile_manager_;
-  raw_ptr<TestingProfile> profile_;
-
-  std::unique_ptr<policy::FakeDeviceAttributes> device_attributes_;
-  mojo::Remote<mojom::DeviceAttributes> device_attributes_remote_;
-  std::unique_ptr<DeviceAttributesAsh> device_attributes_ash_;
-};
-
-TEST_P(DeviceAttributesAshTest, GetDirectoryDeviceId) {
-  base::test::TestFuture<mojom::DeviceAttributesStringResultPtr> future;
-
-  device_attributes_remote_->GetDirectoryDeviceId(future.GetCallback());
-
-  mojom::DeviceAttributesStringResultPtr result = future.Take();
-  const bool expect_contents = IsSigninProfileOrBelongsToAffiliatedUser();
-  ASSERT_EQ(expect_contents, result->is_contents());
-  if (expect_contents) {
-    ASSERT_EQ(kFakeDirectoryApiId, result->get_contents());
-  } else {
-    ASSERT_EQ(kErrorUserNotAffiliated, result->get_error_message());
-  }
-}
-
-TEST_P(DeviceAttributesAshTest, GetDeviceSerialNumber) {
-  base::test::TestFuture<mojom::DeviceAttributesStringResultPtr> future;
-
-  device_attributes_remote_->GetDeviceSerialNumber(future.GetCallback());
-
-  mojom::DeviceAttributesStringResultPtr result = future.Take();
-  const bool expect_contents = IsSigninProfileOrBelongsToAffiliatedUser();
-  ASSERT_EQ(expect_contents, result->is_contents());
-  if (expect_contents) {
-    ASSERT_EQ(kFakeSerialNumber, result->get_contents());
-  } else {
-    ASSERT_EQ(kErrorUserNotAffiliated, result->get_error_message());
-  }
-}
-
-TEST_P(DeviceAttributesAshTest, GetDeviceAssetId) {
-  base::test::TestFuture<mojom::DeviceAttributesStringResultPtr> future;
-
-  device_attributes_remote_->GetDeviceAssetId(future.GetCallback());
-
-  mojom::DeviceAttributesStringResultPtr result = future.Take();
-  const bool expect_contents = IsSigninProfileOrBelongsToAffiliatedUser();
-  ASSERT_EQ(expect_contents, result->is_contents());
-  if (expect_contents) {
-    ASSERT_EQ(kFakeAssetId, result->get_contents());
-  } else {
-    ASSERT_EQ(kErrorUserNotAffiliated, result->get_error_message());
-  }
-}
-
-TEST_P(DeviceAttributesAshTest, GetDeviceAnnotatedLocation) {
-  base::test::TestFuture<mojom::DeviceAttributesStringResultPtr> future;
-
-  device_attributes_remote_->GetDeviceAnnotatedLocation(future.GetCallback());
-
-  mojom::DeviceAttributesStringResultPtr result = future.Take();
-  const bool expect_contents = IsSigninProfileOrBelongsToAffiliatedUser();
-  ASSERT_EQ(expect_contents, result->is_contents());
-  if (expect_contents) {
-    ASSERT_EQ(kFakeAnnotatedLocation, result->get_contents());
-  } else {
-    ASSERT_EQ(kErrorUserNotAffiliated, result->get_error_message());
-  }
-}
-
-TEST_P(DeviceAttributesAshTest, GetDeviceHostname) {
-  base::test::TestFuture<mojom::DeviceAttributesStringResultPtr> future;
-
-  device_attributes_remote_->GetDeviceHostname(future.GetCallback());
-
-  mojom::DeviceAttributesStringResultPtr result = future.Take();
-  const bool expect_contents = IsSigninProfileOrBelongsToAffiliatedUser();
-  ASSERT_EQ(expect_contents, result->is_contents());
-  if (expect_contents) {
-    ASSERT_EQ(kFakeHostname, result->get_contents());
-  } else {
-    ASSERT_EQ(kErrorUserNotAffiliated, result->get_error_message());
-  }
-}
-
-INSTANTIATE_TEST_SUITE_P(
-    All,
-    DeviceAttributesAshTest,
-    ::testing::Values(TestProfileChoice::kSigninProfile,
-                      TestProfileChoice::kAffiliatedProfile,
-                      TestProfileChoice::kNonAffiliatedProfile),
-    &ParamToString);
-
-}  // namespace crosapi
diff --git a/chrome/browser/ash/login/demo_mode/demo_login_controller_unittest.cc b/chrome/browser/ash/login/demo_mode/demo_login_controller_unittest.cc
index 7f9bee8..7baf9cf4 100644
--- a/chrome/browser/ash/login/demo_mode/demo_login_controller_unittest.cc
+++ b/chrome/browser/ash/login/demo_mode/demo_login_controller_unittest.cc
@@ -781,16 +781,6 @@
   }
 
   void TearDown() override {
-    // `BrowserPolicyConnectorAsh` is constructed in
-    // `TestingBrowserProcess::browser_policy_connector()`,
-    // which is called in the ctor of `DemoLoginController` The memory will be
-    // allocated in the scope of `DemoLoginController`.
-    //  `TestingBrowserProcess::ShutdownBrowserPolicyConnector` will get called
-    //  at the end of test, after destructing `DemoLoginController`. Release the
-    //  memory of `BrowserPolicyConnectorAsh` before destructing
-    //  `DemoLoginController` to avoid dangling pointer.
-    TestingBrowserProcess::GetGlobal()->ShutdownBrowserPolicyConnector();
-
     demo_login_controller_.reset();
     DeviceSettingsService::Shutdown();
     DBusThreadManager::Shutdown();
@@ -799,9 +789,13 @@
   void MockConfigureAutoLogin() { is_auto_login_trigger_ = true; }
 
   base::test::ScopedFeatureList features_;
+
+  // InstallAttributes is created before ThreadPool and destroyed after
+  // ThreadPool.
+  ScopedStubInstallAttributes test_install_attributes_;
+
   content::BrowserTaskEnvironment task_environment_{
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
-  ScopedStubInstallAttributes test_install_attributes_;
   std::unique_ptr<DemoLoginController> demo_login_controller_;
   bool is_auto_login_trigger_ = false;
   base::UserActionTester user_action_tester_;
diff --git a/chrome/browser/ash/policy/scheduled_task_handler/test/device_scheduled_reboot_handler_unittest.cc b/chrome/browser/ash/policy/scheduled_task_handler/test/device_scheduled_reboot_handler_unittest.cc
index be12fe5..08080fc7 100644
--- a/chrome/browser/ash/policy/scheduled_task_handler/test/device_scheduled_reboot_handler_unittest.cc
+++ b/chrome/browser/ash/policy/scheduled_task_handler/test/device_scheduled_reboot_handler_unittest.cc
@@ -64,10 +64,6 @@
   DeviceScheduledRebootHandlerForTest& operator=(
       const DeviceScheduledRebootHandlerForTest&) = delete;
 
-  ~DeviceScheduledRebootHandlerForTest() override {
-    TestingBrowserProcess::GetGlobal()->ShutdownBrowserPolicyConnector();
-  }
-
   int GetRebootTimerExpirations() const { return reboot_timer_expirations_; }
   int GetPolicyChangesProcessedCount() const {
     return policy_changes_processed_;
diff --git a/chrome/browser/ash/policy/scheduled_task_handler/test/device_scheduled_update_checker_unittest.cc b/chrome/browser/ash/policy/scheduled_task_handler/test/device_scheduled_update_checker_unittest.cc
index 3734ebb..da6a48a 100644
--- a/chrome/browser/ash/policy/scheduled_task_handler/test/device_scheduled_update_checker_unittest.cc
+++ b/chrome/browser/ash/policy/scheduled_task_handler/test/device_scheduled_update_checker_unittest.cc
@@ -85,10 +85,6 @@
   DeviceScheduledUpdateCheckerForTest& operator=(
       const DeviceScheduledUpdateCheckerForTest&) = delete;
 
-  ~DeviceScheduledUpdateCheckerForTest() override {
-    TestingBrowserProcess::GetGlobal()->ShutdownBrowserPolicyConnector();
-  }
-
   int GetUpdateCheckTimerExpirations() const {
     return update_check_timer_expirations_;
   }
diff --git a/chrome/browser/ash/smb_client/smbfs_share.cc b/chrome/browser/ash/smb_client/smbfs_share.cc
index 62b86cd..38332dd1 100644
--- a/chrome/browser/ash/smb_client/smbfs_share.cc
+++ b/chrome/browser/ash/smb_client/smbfs_share.cc
@@ -16,7 +16,7 @@
 #include "chrome/browser/ash/smb_client/smb_service_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/ash/smb_shares/smb_credentials_dialog.h"
-#include "crypto/sha2.h"
+#include "crypto/hash.h"
 #include "storage/browser/file_system/external_mount_points.h"
 
 namespace ash::smb_client {
@@ -311,9 +311,8 @@
 }
 
 std::string SmbFsShare::GenerateStableMountId() const {
-  std::string hash_input = GenerateStableMountIdInput();
-  return base::ToLowerASCII(base::HexEncode(
-      crypto::SHA256HashString(hash_input).c_str(), crypto::kSHA256Length));
+  const auto input = GenerateStableMountIdInput();
+  return base::ToLowerASCII(base::HexEncode(crypto::hash::Sha256(input)));
 }
 
 std::string SmbFsShare::GenerateStableMountIdInput() const {
diff --git a/chrome/browser/auxiliary_search/auxiliary_search_top_site_provider_bridge.cc b/chrome/browser/auxiliary_search/auxiliary_search_top_site_provider_bridge.cc
index 91d9bb5..f25ce945 100644
--- a/chrome/browser/auxiliary_search/auxiliary_search_top_site_provider_bridge.cc
+++ b/chrome/browser/auxiliary_search/auxiliary_search_top_site_provider_bridge.cc
@@ -69,6 +69,7 @@
 }
 
 void AuxiliarySearchTopSiteProviderBridge::OnURLsAvailable(
+    bool is_user_triggered,
     const std::map<ntp_tiles::SectionType, ntp_tiles::NTPTilesVector>&
         sections) {
   CHECK(most_visited_sites_);
diff --git a/chrome/browser/auxiliary_search/auxiliary_search_top_site_provider_bridge.h b/chrome/browser/auxiliary_search/auxiliary_search_top_site_provider_bridge.h
index 071c78a..fc38a2d 100644
--- a/chrome/browser/auxiliary_search/auxiliary_search_top_site_provider_bridge.h
+++ b/chrome/browser/auxiliary_search/auxiliary_search_top_site_provider_bridge.h
@@ -47,6 +47,7 @@
 
   // ntp_tiles::MostVisitedSites::Observer implementation.
   void OnURLsAvailable(
+      bool is_user_triggered,
       const std::map<ntp_tiles::SectionType, ntp_tiles::NTPTilesVector>&
           sections) override;
   void OnIconMadeAvailable(const GURL& site_url) override;
diff --git a/chrome/browser/bookmarks/android/BUILD.gn b/chrome/browser/bookmarks/android/BUILD.gn
index aafe27e..fa85404 100644
--- a/chrome/browser/bookmarks/android/BUILD.gn
+++ b/chrome/browser/bookmarks/android/BUILD.gn
@@ -224,6 +224,7 @@
     "//chrome/browser/bookmarks/android/junit/src/org/chromium/chrome/browser/bookmarks/FakeBookmarkModel.java",
     "//chrome/browser/bookmarks/android/junit/src/org/chromium/chrome/browser/bookmarks/SharedBookmarkModelMocks.java",
     "javatests/src/org/chromium/chrome/browser/bookmarks/AccountBookmarkTest.java",
+    "javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkBatchUploadCardRenderTest.java",
     "javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkBridgeTest.java",
     "javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerRenderTest.java",
     "javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkOpenerTest.java",
diff --git a/chrome/browser/bookmarks/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkBatchUploadCardRenderTest.java b/chrome/browser/bookmarks/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkBatchUploadCardRenderTest.java
new file mode 100644
index 0000000..3d5dbd6
--- /dev/null
+++ b/chrome/browser/bookmarks/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkBatchUploadCardRenderTest.java
@@ -0,0 +1,172 @@
+// Copyright 2025 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.bookmarks;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+
+import static org.chromium.base.ThreadUtils.runOnUiThreadBlocking;
+
+import android.app.Activity;
+import android.view.View;
+
+import androidx.test.espresso.contrib.RecyclerViewActions;
+import androidx.test.filters.LargeTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DoNotBatch;
+import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.Features.EnableFeatures;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.browser.profiles.ProfileManager;
+import org.chromium.chrome.browser.sync.SyncTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.R;
+import org.chromium.chrome.test.transit.AutoResetCtaTransitTestRule;
+import org.chromium.chrome.test.transit.ChromeTransitTestRules;
+import org.chromium.chrome.test.util.BookmarkTestRule;
+import org.chromium.chrome.test.util.BookmarkTestUtil;
+import org.chromium.chrome.test.util.ChromeRenderTestRule;
+import org.chromium.chrome.test.util.browser.sync.SyncTestUtil;
+import org.chromium.ui.test.util.ViewUtils;
+import org.chromium.url.GURL;
+
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+@DoNotBatch(reason = "SyncTestRule doesn't support batching.")
+@EnableFeatures({ChromeFeatureList.UNO_PHASE_2_FOLLOW_UP})
+public class BookmarkBatchUploadCardRenderTest {
+    private static final int RENDER_TEST_REVISION = 1;
+
+    @Rule public final SyncTestRule mSyncTestRule = new SyncTestRule();
+    @Rule public final BookmarkTestRule mBookmarkTestRule = new BookmarkTestRule();
+
+    @Rule
+    public final AutoResetCtaTransitTestRule mActivityTestRule =
+            ChromeTransitTestRules.fastAutoResetCtaActivityRule();
+
+    @Rule
+    public final ChromeRenderTestRule mRenderTestRule =
+            ChromeRenderTestRule.Builder.withPublicCorpus()
+                    .setRevision(RENDER_TEST_REVISION)
+                    .setBugComponent(ChromeRenderTestRule.Component.SERVICES_SYNC)
+                    .build();
+
+    private BookmarkModel mBookmarkModel;
+
+    @Before
+    public void setUp() throws Exception {
+        runOnUiThreadBlocking(
+                () -> {
+                    mBookmarkModel =
+                            BookmarkModel.getForProfile(ProfileManager.getLastUsedRegularProfile());
+                    mBookmarkModel.loadEmptyPartnerBookmarkShimForTesting();
+                });
+        BookmarkTestUtil.waitForBookmarkModelLoaded();
+    }
+
+    @Test
+    @LargeTest
+    @Feature({"Sync", "RenderTest"})
+    public void testBookmarkBatchUploadEntryDescriptionBookmark() throws Exception {
+        runOnUiThreadBlocking(
+                () ->
+                        // Add local bookmark.
+                        mBookmarkModel.addBookmark(
+                                mBookmarkModel.getMobileFolderId(),
+                                0,
+                                "bookmark",
+                                new GURL("https://test.com")));
+
+        mSyncTestRule.setUpAccountAndSignInForTesting();
+        SyncTestUtil.waitForSyncTransportActive();
+
+        mBookmarkTestRule.showBookmarkManager(mSyncTestRule.getActivity());
+        onView(withId(R.id.selectable_list_recycler_view))
+                .perform(RecyclerViewActions.scrollToLastPosition());
+        ViewUtils.waitForVisibleView(withId(R.id.signin_settings_card));
+        View view =
+                runOnUiThreadBlocking(
+                        () -> {
+                            return getBookmarkHostActivity()
+                                    .findViewById(R.id.signin_settings_card);
+                        });
+        mRenderTestRule.render(view, "batch_upload_entry_description_bookmark");
+    }
+
+    @Test
+    @LargeTest
+    @Feature({"Sync", "RenderTest"})
+    public void testBookmarkBatchUploadEntryDescriptionOther() throws Exception {
+        runOnUiThreadBlocking(
+                () -> // Add local reading list entry.
+                mBookmarkModel.addToDefaultReadingList(
+                                "reading list entry", new GURL("https://test.com")));
+
+        mSyncTestRule.setUpAccountAndSignInForTesting();
+        SyncTestUtil.waitForSyncTransportActive();
+
+        mBookmarkTestRule.showBookmarkManager(mSyncTestRule.getActivity());
+        onView(withId(R.id.selectable_list_recycler_view))
+                .perform(RecyclerViewActions.scrollToLastPosition());
+        ViewUtils.waitForVisibleView(withId(R.id.signin_settings_card));
+        View view =
+                runOnUiThreadBlocking(
+                        () -> {
+                            return getBookmarkHostActivity()
+                                    .findViewById(R.id.signin_settings_card);
+                        });
+        mRenderTestRule.render(view, "batch_upload_entry_description_other");
+    }
+
+    @Test
+    @LargeTest
+    @Feature({"Sync", "RenderTest"})
+    public void testBookmarkBatchUploadEntryDescriptionBookmarkAndOther() throws Exception {
+        runOnUiThreadBlocking(
+                () -> {
+                    // Add local bookmark.
+                    mBookmarkModel.addBookmark(
+                            mBookmarkModel.getMobileFolderId(),
+                            0,
+                            "bookmark",
+                            new GURL("https://test.com"));
+                    // Add local reading list entry.
+                    mBookmarkModel.addToDefaultReadingList(
+                            "reading list entry", new GURL("https://test.com"));
+                });
+
+        mSyncTestRule.setUpAccountAndSignInForTesting();
+        SyncTestUtil.waitForSyncTransportActive();
+
+        mBookmarkTestRule.showBookmarkManager(mSyncTestRule.getActivity());
+        onView(withId(R.id.selectable_list_recycler_view))
+                .perform(RecyclerViewActions.scrollToLastPosition());
+        ViewUtils.waitForVisibleView(withId(R.id.signin_settings_card));
+        View view =
+                runOnUiThreadBlocking(
+                        () -> {
+                            return getBookmarkHostActivity()
+                                    .findViewById(R.id.signin_settings_card);
+                        });
+        mRenderTestRule.render(view, "batch_upload_entry_description_bookmark_and_other");
+    }
+
+    // Get the activity that hosts the bookmark UI - on phones, this is a BookmarkActivity, on
+    // tablets this is a native page.
+    private Activity getBookmarkHostActivity() {
+        if (mActivityTestRule.getActivity().isTablet()) {
+            return mActivityTestRule.getActivity();
+        } else {
+            return mBookmarkTestRule.getBookmarkActivity();
+        }
+    }
+}
diff --git a/chrome/browser/bookmarks/bookmark_merged_surface_service_unittest.cc b/chrome/browser/bookmarks/bookmark_merged_surface_service_unittest.cc
index 5f730f1..ff5c291 100644
--- a/chrome/browser/bookmarks/bookmark_merged_surface_service_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_merged_surface_service_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/functional/bind.h"
 #include "base/scoped_observation.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_ostream_operators.h"
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/values.h"
diff --git a/chrome/browser/bookmarks/permanent_folder_ordering_tracker_unittest.cc b/chrome/browser/bookmarks/permanent_folder_ordering_tracker_unittest.cc
index ee25f4c..d6144e9 100644
--- a/chrome/browser/bookmarks/permanent_folder_ordering_tracker_unittest.cc
+++ b/chrome/browser/bookmarks/permanent_folder_ordering_tracker_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <cstddef>
 
+#include "base/strings/utf_ostream_operators.h"
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/bookmarks/bookmark_test_helpers.h"
 #include "components/bookmarks/browser/bookmark_model.h"
diff --git a/chrome/browser/enterprise/connectors/device_trust/signals/decorators/ash/ash_signals_decorator.cc b/chrome/browser/enterprise/connectors/device_trust/signals/decorators/ash/ash_signals_decorator.cc
index 03c2185a..90ab794 100644
--- a/chrome/browser/enterprise/connectors/device_trust/signals/decorators/ash/ash_signals_decorator.cc
+++ b/chrome/browser/enterprise/connectors/device_trust/signals/decorators/ash/ash_signals_decorator.cc
@@ -8,10 +8,7 @@
 #include "base/check.h"
 #include "base/time/time.h"
 #include "base/values.h"
-#include "chrome/browser/ash/crosapi/crosapi_ash.h"
-#include "chrome/browser/ash/crosapi/crosapi_manager.h"
 #include "chrome/browser/ash/crosapi/crosapi_util.h"
-#include "chrome/browser/ash/crosapi/networking_attributes_ash.h"
 #include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
 #include "chrome/browser/ash/policy/core/device_attributes_impl.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
@@ -20,6 +17,7 @@
 #include "chrome/browser/enterprise/connectors/device_trust/signals/decorators/common/signals_decorator.h"
 #include "chrome/browser/enterprise/connectors/device_trust/signals/decorators/common/signals_utils.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "chromeos/ash/components/network/device_state.h"
 #include "chromeos/ash/components/network/network_handler.h"
 #include "chromeos/ash/components/network/network_state_handler.h"
@@ -64,6 +62,26 @@
   network_state_handler->GetDeviceList(list);
 }
 
+std::optional<std::string> GetMacAddress(Profile* profile) {
+  if (!crosapi::browser_util::IsSigninProfileOrBelongsToAffiliatedUser(
+          profile)) {
+    return std::nullopt;
+  }
+
+  ash::NetworkStateHandler* network_state_handler =
+      ash::NetworkHandler::Get()->network_state_handler();
+  const ash::NetworkState* network = network_state_handler->DefaultNetwork();
+  if (!network) {
+    return std::nullopt;
+  }
+  const ash::DeviceState* device =
+      network_state_handler->GetDeviceState(network->device_path());
+  if (!device) {
+    return std::nullopt;
+  }
+  return ash::network_util::FormattedMacAddress(device->mac_address());
+}
+
 }  // namespace
 
 AshSignalsDecorator::AshSignalsDecorator(
@@ -120,48 +138,14 @@
   signals.Set(device_signals::names::kImei, std::move(imei_list));
   signals.Set(device_signals::names::kMeid, std::move(meid_list));
 
-  if (!crosapi::CrosapiManager::Get() ||
-      !crosapi::CrosapiManager::Get()->crosapi_ash() ||
-      !crosapi::CrosapiManager::Get()
-           ->crosapi_ash()
-           ->networking_attributes_ash()) {
-    LogSignalsCollectionLatency(kLatencyHistogramVariant, start_time);
-
-    std::move(done_closure).Run();
-    return;
-  }
-
-  auto callback =
-      base::BindOnce(&AshSignalsDecorator::OnNetworkInfoRetrieved,
-                     weak_ptr_factory_.GetWeakPtr(), std::ref(signals),
-                     start_time, std::move(done_closure));
-
-  crosapi::CrosapiManager::Get()
-      ->crosapi_ash()
-      ->networking_attributes_ash()
-      ->GetNetworkDetails(std::move(callback));
-}
-
-void AshSignalsDecorator::OnNetworkInfoRetrieved(
-    base::Value::Dict& signals,
-    base::TimeTicks start_time,
-    base::OnceClosure done_closure,
-    crosapi::mojom::GetNetworkDetailsResultPtr result) {
   std::vector<std::string> mac_addresses;
-  using Result = crosapi::mojom::GetNetworkDetailsResult;
-  switch (result->which()) {
-    case Result::Tag::kErrorMessage:
-      break;
-    case Result::Tag::kNetworkDetails:
-      std::optional<std::string> mac_address =
-          result->get_network_details()->mac_address;
-
-      // `get_network_details()->mac_address` returns a std::string. On other
-      // platforms (Windows, Linux and Mac) there can be multiple mac
-      // addresses.
-      if (mac_address) {
-        mac_addresses.push_back(mac_address.value());
-      }
+  std::optional<std::string> mac_address = GetMacAddress(
+      g_browser_process->profile_manager()->GetPrimaryUserProfile());
+  // `get_network_details()->mac_address` returns a std::string. On other
+  // platforms (Windows, Linux and Mac) there can be multiple mac
+  // addresses.
+  if (mac_address) {
+    mac_addresses.push_back(mac_address.value());
   }
 
   // The mac addresses signal must always have a value, which can be an empty
@@ -169,7 +153,6 @@
   signals.Set(device_signals::names::kMacAddresses, ToListValue(mac_addresses));
 
   LogSignalsCollectionLatency(kLatencyHistogramVariant, start_time);
-
   std::move(done_closure).Run();
 }
 
diff --git a/chrome/browser/enterprise/connectors/device_trust/signals/decorators/ash/ash_signals_decorator.h b/chrome/browser/enterprise/connectors/device_trust/signals/decorators/ash/ash_signals_decorator.h
index 11a2a04..93133cb 100644
--- a/chrome/browser/enterprise/connectors/device_trust/signals/decorators/ash/ash_signals_decorator.h
+++ b/chrome/browser/enterprise/connectors/device_trust/signals/decorators/ash/ash_signals_decorator.h
@@ -9,7 +9,6 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/policy/core/device_attributes.h"
 #include "chrome/browser/enterprise/connectors/device_trust/signals/decorators/common/signals_decorator.h"
-#include "chromeos/crosapi/mojom/networking_attributes.mojom.h"
 
 #include "base/values.h"
 
@@ -34,12 +33,6 @@
                 base::OnceClosure done_closure) override;
 
  private:
-  void OnNetworkInfoRetrieved(
-      base::Value::Dict& signals,
-      base::TimeTicks start_time,
-      base::OnceClosure done_closure,
-      crosapi::mojom::GetNetworkDetailsResultPtr result);
-
   const raw_ptr<policy::BrowserPolicyConnectorAsh> browser_policy_connector_;
   raw_ptr<Profile> profile_;
 
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 5b4e5a08..9bbfd65 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -286,6 +286,12 @@
     "extension_service.h",
     "extension_special_storage_policy.cc",
     "extension_special_storage_policy.h",
+    "extension_sync_data.cc",
+    "extension_sync_data.h",
+    "extension_sync_service.cc",
+    "extension_sync_service.h",
+    "extension_sync_service_factory.cc",
+    "extension_sync_service_factory.h",
     "extension_sync_util.cc",
     "extension_sync_util.h",
     "extension_tab_util.cc",
@@ -356,6 +362,8 @@
     "install_verifier_factory.h",
     "installed_loader.cc",
     "installed_loader.h",
+    "launch_util.cc",
+    "launch_util.h",
     "load_error_reporter.cc",
     "load_error_reporter.h",
     "managed_installation_mode.h",
@@ -407,6 +415,8 @@
     "standard_management_policy_provider.h",
     "startup_helper.cc",
     "startup_helper.h",
+    "sync_bundle.cc",
+    "sync_bundle.h",
     "system_display/display_info_provider.h",
     "tab_helper.cc",
     "tab_helper.h",
@@ -752,12 +762,6 @@
       "extension_gcm_app_handler.h",
       "extension_menu_icon_loader.cc",
       "extension_menu_icon_loader.h",
-      "extension_sync_data.cc",
-      "extension_sync_data.h",
-      "extension_sync_service.cc",
-      "extension_sync_service.h",
-      "extension_sync_service_factory.cc",
-      "extension_sync_service_factory.h",
       "extension_uninstall_dialog.cc",
       "extension_uninstall_dialog.h",
       "extension_view_host_web_modal_handler.cc",
@@ -766,8 +770,6 @@
       "external_install_error_desktop.h",
       "file_handlers/file_handling_launch_utils.cc",
       "file_handlers/file_handling_launch_utils.h",
-      "launch_util.cc",
-      "launch_util.h",
       "menu_icon_loader.h",
       "menu_manager.cc",
       "menu_manager.h",
@@ -775,8 +777,6 @@
       "menu_manager_factory.h",
       "navigation_extension_enabler.cc",
       "navigation_extension_enabler.h",
-      "sync_bundle.cc",
-      "sync_bundle.h",
       "theme_installed_infobar_delegate.cc",
       "theme_installed_infobar_delegate.h",
       "warning_badge_service.cc",
@@ -1561,6 +1561,8 @@
     "scoped_database_manager_for_test.h",
     "scoped_test_mv2_enabler.cc",
     "scoped_test_mv2_enabler.h",
+    "signin_test_util.cc",
+    "signin_test_util.h",
     "test_blocklist.cc",
     "test_blocklist.h",
     "test_extension_system.cc",
@@ -1577,6 +1579,7 @@
     "//components/safe_browsing/core/browser/db:database_manager",
     "//components/services/unzip:in_process",
     "//components/services/unzip/content",
+    "//components/signin/public/identity_manager:test_support",
     "//components/value_store:test_support",
     "//extensions:test_support",
     "//services/data_decoder/public/cpp:test_support",
@@ -1597,8 +1600,6 @@
       "menu_manager_test_observer.h",
       "mock_crx_installer.cc",
       "mock_crx_installer.h",
-      "signin_test_util.cc",
-      "signin_test_util.h",
       "test_blocklist_state_fetcher.cc",
       "test_blocklist_state_fetcher.h",
       "test_extension_service.cc",
@@ -1617,7 +1618,6 @@
       "//components/crx_file",
       "//components/safe_browsing/core/browser/db:v4_test_util",
       "//components/sessions",
-      "//components/signin/public/identity_manager:test_support",
       "//content/public/browser",
       "//content/test:test_support",
       "//extensions:test_support",
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc b/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc
index b8accd9..00b7d5b 100644
--- a/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc
+++ b/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc
@@ -702,16 +702,11 @@
     return RespondNow(Error(kErrorDataUnavailable));
   }
 
-  auto* virtual_card_enrollment_manager =
-      autofill_client()
-          ->GetPaymentsAutofillClient()
-          ->GetVirtualCardEnrollmentManager();
-  CHECK(virtual_card_enrollment_manager);
-  virtual_card_enrollment_manager->InitVirtualCardEnroll(
-      *card, autofill::VirtualCardEnrollmentSource::kSettingsPage,
-      base::BindOnce(
-          &autofill::VirtualCardEnrollmentManager::ShowVirtualCardEnrollBubble,
-          virtual_card_enrollment_manager->GetWeakPtr()));
+  autofill_client()
+      ->GetPaymentsAutofillClient()
+      ->GetVirtualCardEnrollmentManager()
+      ->InitVirtualCardEnroll(
+          *card, autofill::VirtualCardEnrollmentSource::kSettingsPage);
   return RespondNow(NoArguments());
 }
 
diff --git a/chrome/browser/extensions/api/enterprise_device_attributes/BUILD.gn b/chrome/browser/extensions/api/enterprise_device_attributes/BUILD.gn
index 8385f6e..0337ee24 100644
--- a/chrome/browser/extensions/api/enterprise_device_attributes/BUILD.gn
+++ b/chrome/browser/extensions/api/enterprise_device_attributes/BUILD.gn
@@ -16,14 +16,16 @@
 
   configs += [ "//build/config/compiler:wexit_time_destructors" ]
 
-  public_deps = [
-    "//chromeos/crosapi/mojom",
-    "//extensions/browser",
-  ]
+  public_deps = [ "//extensions/browser" ]
 
   deps = [
     "//base",
-    "//chrome/browser/ash/crosapi",
+    "//chrome/browser:browser_process",
+    "//chrome/browser:browser_public_dependencies",
+    "//chrome/browser/ash/policy/core",
+    "//chrome/browser/profiles",
     "//chrome/browser/profiles:profile",
+    "//chromeos/ash/components/browser_context_helper",
+    "//components/user_manager",
   ]
 }
diff --git a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api.cc b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api.cc
index 80c28df..a075a01 100644
--- a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api.cc
+++ b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api.cc
@@ -7,94 +7,96 @@
 #include <utility>
 
 #include "base/functional/bind.h"
-#include "chrome/browser/ash/crosapi/crosapi_ash.h"
-#include "chrome/browser/ash/crosapi/crosapi_manager.h"
-#include "chrome/browser/ash/crosapi/device_attributes_ash.h"
+#include "chrome/browser/ash/policy/core/device_attributes_impl.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chromeos/ash/components/browser_context_helper/browser_context_helper.h"
+#include "chromeos/ash/components/browser_context_helper/browser_context_types.h"
+#include "components/user_manager/user.h"
 
 namespace {
 
-crosapi::mojom::DeviceAttributes* GetDeviceAttributesApi() {
-  return crosapi::CrosapiManager::Get()->crosapi_ash()->device_attributes_ash();
+bool IsAccessAllowed() {
+  // TODO(crbug.com/354842935): this check looks incorrect, because APIs are
+  // running under a certain profile, while this looks at primary user profile.
+  // Also GetPrimaryUserProfile has known issue (crbug.com/40227502).
+  // We should respect the Profile which can be taken by
+  // `Profile::FromBrowserContext(ExtensionFunction::browser_context())`.
+  Profile* profile =
+      g_browser_process->profile_manager()->GetPrimaryUserProfile();
+  if (ash::IsSigninBrowserContext(profile)) {
+    return true;
+  }
+  if (profile->IsOffTheRecord()) {
+    return false;
+  }
+
+  const user_manager::User* user =
+      ash::BrowserContextHelper::Get()->GetUserByBrowserContext(profile);
+  if (!user) {
+    return false;
+  }
+  return user->IsAffiliated();
 }
 
 }  // namespace
 
 namespace extensions {
 
-void EnterpriseDeviceAttributesBase::OnCrosapiResult(
-    crosapi::mojom::DeviceAttributesStringResultPtr result) {
-  using Result = crosapi::mojom::DeviceAttributesStringResult;
-  switch (result->which()) {
-    case Result::Tag::kErrorMessage:
-      // We intentionally drop the error message here because the extension API
-      // is expected to return "" on validation error.
-      Respond(WithArguments(""));
-      return;
-    case Result::Tag::kContents:
-      Respond(WithArguments(result->get_contents()));
-      return;
-  }
+EnterpriseDeviceAttributesBase::EnterpriseDeviceAttributesBase()
+    : device_attributes_(std::make_unique<policy::DeviceAttributesImpl>()) {}
+
+EnterpriseDeviceAttributesBase::~EnterpriseDeviceAttributesBase() = default;
+
+template <std::invocable F>
+  requires std::convertible_to<std::invoke_result_t<F>, std::string>
+ExtensionFunction::ResponseAction
+EnterpriseDeviceAttributesBase::RespondWithCheck(F&& f) {
+  return RespondNow(WithArguments(
+      IsAccessAllowed()
+          ? f()
+          :
+          // We intentionally drop the error message here because the
+          // extension API is expected to return "" on validation error.
+          std::string()));
+}
+
+void EnterpriseDeviceAttributesBase::SetDeviceAttributes(
+    base::PassKey<EnterpriseDeviceAttributesApiAshTest>,
+    std::unique_ptr<policy::DeviceAttributes> device_attributes) {
+  device_attributes_ = std::move(device_attributes);
 }
 
 ExtensionFunction::ResponseAction
 EnterpriseDeviceAttributesGetDirectoryDeviceIdFunction::Run() {
-  // We don't need Unretained() or WeakPtr because ExtensionFunction is
-  // ref-counted.
-  auto cb = base::BindOnce(
-      &EnterpriseDeviceAttributesGetDirectoryDeviceIdFunction::OnCrosapiResult,
-      this);
-
-  GetDeviceAttributesApi()->GetDirectoryDeviceId(std::move(cb));
-  return did_respond() ? AlreadyResponded() : RespondLater();
+  return RespondWithCheck(
+      [this]() { return device_attributes().GetDirectoryApiID(); });
 }
 
 ExtensionFunction::ResponseAction
 EnterpriseDeviceAttributesGetDeviceSerialNumberFunction::Run() {
-  // We don't need Unretained() or WeakPtr because ExtensionFunction is
-  // ref-counted.
-  auto cb = base::BindOnce(
-      &EnterpriseDeviceAttributesGetDeviceSerialNumberFunction::OnCrosapiResult,
-      this);
-
-  GetDeviceAttributesApi()->GetDeviceSerialNumber(std::move(cb));
-  return did_respond() ? AlreadyResponded() : RespondLater();
+  return RespondWithCheck(
+      [this]() { return device_attributes().GetDeviceSerialNumber(); });
 }
 
 ExtensionFunction::ResponseAction
 EnterpriseDeviceAttributesGetDeviceAssetIdFunction::Run() {
-  // We don't need Unretained() or WeakPtr because ExtensionFunction is
-  // ref-counted.
-  auto cb = base::BindOnce(
-      &EnterpriseDeviceAttributesGetDeviceAssetIdFunction::OnCrosapiResult,
-      this);
-
-  GetDeviceAttributesApi()->GetDeviceAssetId(std::move(cb));
-  return did_respond() ? AlreadyResponded() : RespondLater();
+  return RespondWithCheck(
+      [this]() { return device_attributes().GetDeviceAssetID(); });
 }
 
 ExtensionFunction::ResponseAction
 EnterpriseDeviceAttributesGetDeviceAnnotatedLocationFunction::Run() {
-  // We don't need Unretained() or WeakPtr because ExtensionFunction is
-  // ref-counted.
-  auto cb = base::BindOnce(
-      &EnterpriseDeviceAttributesGetDeviceAnnotatedLocationFunction::
-          OnCrosapiResult,
-      this);
-
-  GetDeviceAttributesApi()->GetDeviceAnnotatedLocation(std::move(cb));
-  return did_respond() ? AlreadyResponded() : RespondLater();
+  return RespondWithCheck(
+      [this]() { return device_attributes().GetDeviceAnnotatedLocation(); });
 }
 
 ExtensionFunction::ResponseAction
 EnterpriseDeviceAttributesGetDeviceHostnameFunction::Run() {
-  // We don't need Unretained() or WeakPtr because ExtensionFunction is
-  // ref-counted.
-  auto cb = base::BindOnce(
-      &EnterpriseDeviceAttributesGetDeviceHostnameFunction::OnCrosapiResult,
-      this);
-
-  GetDeviceAttributesApi()->GetDeviceHostname(std::move(cb));
-  return did_respond() ? AlreadyResponded() : RespondLater();
+  return RespondWithCheck([this]() {
+    return device_attributes().GetDeviceHostname().value_or(std::string());
+  });
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api.h b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api.h
index cc3183d9..94e92188 100644
--- a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api.h
+++ b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api.h
@@ -8,20 +8,49 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_ENTERPRISE_DEVICE_ATTRIBUTES_ENTERPRISE_DEVICE_ATTRIBUTES_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_ENTERPRISE_DEVICE_ATTRIBUTES_ENTERPRISE_DEVICE_ATTRIBUTES_API_H_
 
-#include "chromeos/crosapi/mojom/device_attributes.mojom-forward.h"
+#include <concepts>
+#include <memory>
+#include <type_traits>
+
+#include "base/types/pass_key.h"
 #include "extensions/browser/extension_function.h"
 #include "extensions/browser/extension_function_histogram_value.h"
 
+namespace policy {
+class DeviceAttributes;
+}  // namespace policy
+
 namespace extensions {
 
+class EnterpriseDeviceAttributesApiAshTest;
+
 // The implementation requires forwarding to ash via crosapi. This subclass is
 // used to reduce redundant code.
 class EnterpriseDeviceAttributesBase : public ExtensionFunction {
- protected:
-  ~EnterpriseDeviceAttributesBase() override = default;
+ public:
+  // Injects DeviceAttributes for testing.
+  void SetDeviceAttributes(
+      base::PassKey<EnterpriseDeviceAttributesApiAshTest>,
+      std::unique_ptr<policy::DeviceAttributes> device_attributes);
 
-  // Called asynchronously when crosapi returns the result.
-  void OnCrosapiResult(crosapi::mojom::DeviceAttributesStringResultPtr result);
+ protected:
+  EnterpriseDeviceAttributesBase();
+  ~EnterpriseDeviceAttributesBase() override;
+
+  // Checks whether it is allowed to respond with a valid value, and if it is
+  // responds the value returned from `f()`, which is called synchronously.
+  // Otherwise, responds with an empty string as an error.
+  // We cannot use RespondWithValidation/PreRunValidation, because it'll cause
+  // to return Error on error, while enterprise.deviceAttributes functions
+  // expect to return an empty string as an error.
+  template <std::invocable F>
+    requires std::convertible_to<std::invoke_result_t<F>, std::string>
+  ResponseAction RespondWithCheck(F&& f);
+
+  policy::DeviceAttributes& device_attributes() { return *device_attributes_; }
+
+ private:
+  std::unique_ptr<policy::DeviceAttributes> device_attributes_;
 };
 
 class EnterpriseDeviceAttributesGetDirectoryDeviceIdFunction
diff --git a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api_ash_unittest.cc b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api_ash_unittest.cc
index 0e37acd..42f0c338 100644
--- a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api_ash_unittest.cc
+++ b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api_ash_unittest.cc
@@ -7,9 +7,6 @@
 #include "base/files/file_path.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/values.h"
-#include "chrome/browser/ash/crosapi/crosapi_ash.h"
-#include "chrome/browser/ash/crosapi/crosapi_manager.h"
-#include "chrome/browser/ash/crosapi/device_attributes_ash.h"
 #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/ash/policy/core/device_attributes_fake.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
@@ -90,23 +87,10 @@
         break;
     }
 
-    // Set up fake device attributes.
-    device_attributes_ = std::make_unique<policy::FakeDeviceAttributes>();
-    device_attributes_->SetFakeDirectoryApiId(kFakeDirectoryApiId);
-    device_attributes_->SetFakeDeviceSerialNumber(kFakeSerialNumber);
-    device_attributes_->SetFakeDeviceAssetId(kFakeAssetId);
-    device_attributes_->SetFakeDeviceAnnotatedLocation(kFakeAnnotatedLocation);
-    device_attributes_->SetFakeDeviceHostname(kFakeHostname);
-
     ash::LoginState::Initialize();
-    manager_ = std::make_unique<crosapi::CrosapiManager>();
-    manager_->crosapi_ash()
-        ->device_attributes_ash()
-        ->SetDeviceAttributesForTesting(std::move(device_attributes_));
   }
 
   void TearDown() override {
-    manager_.reset();
     ash::DeviceSettingsTestBase::TearDown();
     ash::LoginState::Shutdown();
   }
@@ -129,18 +113,28 @@
     }
   }
 
+  void SetDeviceAttributes(EnterpriseDeviceAttributesBase* function) {
+    auto device_attributes = std::make_unique<policy::FakeDeviceAttributes>();
+    device_attributes->SetFakeDirectoryApiId(kFakeDirectoryApiId);
+    device_attributes->SetFakeDeviceSerialNumber(kFakeSerialNumber);
+    device_attributes->SetFakeDeviceAssetId(kFakeAssetId);
+    device_attributes->SetFakeDeviceAnnotatedLocation(kFakeAnnotatedLocation);
+    device_attributes->SetFakeDeviceHostname(kFakeHostname);
+
+    function->SetDeviceAttributes({}, std::move(device_attributes));
+  }
+
  protected:
   user_manager::TypedScopedUserManager<ash::FakeChromeUserManager>
       user_manager_{std::make_unique<ash::FakeChromeUserManager>()};
   TestingProfileManager profile_manager_;
   raw_ptr<TestingProfile> testing_profile_;
-  std::unique_ptr<crosapi::CrosapiManager> manager_;
-  std::unique_ptr<policy::FakeDeviceAttributes> device_attributes_;
 };
 
 TEST_P(EnterpriseDeviceAttributesApiAshTest, GetDirectoryDeviceIdFunction) {
   auto function = base::MakeRefCounted<
       EnterpriseDeviceAttributesGetDirectoryDeviceIdFunction>();
+  SetDeviceAttributes(function.get());
 
   std::optional<base::Value> result =
       api_test_utils::RunFunctionAndReturnSingleResult(
@@ -154,6 +148,7 @@
 TEST_P(EnterpriseDeviceAttributesApiAshTest, GetDeviceSerialNumberFunction) {
   auto function = base::MakeRefCounted<
       EnterpriseDeviceAttributesGetDeviceSerialNumberFunction>();
+  SetDeviceAttributes(function.get());
 
   std::optional<base::Value> result =
       api_test_utils::RunFunctionAndReturnSingleResult(
@@ -166,6 +161,7 @@
 TEST_P(EnterpriseDeviceAttributesApiAshTest, GetDeviceAssetIdFunction) {
   auto function = base::MakeRefCounted<
       EnterpriseDeviceAttributesGetDeviceAssetIdFunction>();
+  SetDeviceAttributes(function.get());
 
   std::optional<base::Value> result =
       api_test_utils::RunFunctionAndReturnSingleResult(
@@ -179,6 +175,7 @@
        GetDeviceAnnotatedLocationFunction) {
   auto function = base::MakeRefCounted<
       EnterpriseDeviceAttributesGetDeviceAnnotatedLocationFunction>();
+  SetDeviceAttributes(function.get());
 
   std::optional<base::Value> result =
       api_test_utils::RunFunctionAndReturnSingleResult(
@@ -192,6 +189,7 @@
 TEST_P(EnterpriseDeviceAttributesApiAshTest, GetDeviceHostnameFunction) {
   auto function = base::MakeRefCounted<
       EnterpriseDeviceAttributesGetDeviceHostnameFunction>();
+  SetDeviceAttributes(function.get());
 
   std::optional<base::Value> result =
       api_test_utils::RunFunctionAndReturnSingleResult(
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc
index 87b5187d..11d76f6 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -37,6 +37,7 @@
 #include "base/task/single_thread_task_runner.h"
 #include "base/task/thread_pool.h"
 #include "base/types/expected.h"
+#include "base/types/expected_macros.h"
 #include "base/types/optional_util.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
@@ -72,9 +73,12 @@
 #include "chrome/browser/ui/tabs/tab_strip_user_gesture_details.h"
 #include "chrome/browser/ui/tabs/tab_utils.h"
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
+#include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
 #include "chrome/browser/ui/window_sizer/window_sizer.h"
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
 #include "chrome/browser/web_applications/web_app_helpers.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
+#include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/common/extensions/api/tabs.h"
 #include "chrome/common/extensions/api/windows.h"
 #include "chrome/common/extensions/extension_constants.h"
@@ -829,11 +833,14 @@
   Browser::CreateParams create_params(window_type, window_profile,
                                       user_gesture());
   if (isolated_web_app_url_info.has_value()) {
+    // For Isolated Web Apps, the actual navigating-to URL will be the app's
+    // start_url to prevent deep-linking attacks, while the original URL will be
+    // accessible via window.launchQueue; for this reason the browser is marked
+    // trusted.
     create_params = Browser::CreateParams::CreateForApp(
         web_app::GenerateApplicationNameFromAppId(
             isolated_web_app_url_info->app_id()),
-        /*trusted_source=*/false, window_bounds, window_profile,
-        user_gesture());
+        /*trusted_source=*/true, window_bounds, window_profile, user_gesture());
   } else if (extension_id.empty()) {
     create_params.initial_bounds = window_bounds;
   } else {
@@ -858,7 +865,8 @@
     return RespondNow(Error(ExtensionTabUtil::kBrowserWindowNotAllowed));
   }
 
-  for (const GURL& url : urls) {
+  auto create_nav_params =
+      [&](const GURL& url) -> base::expected<NavigateParams, std::string> {
     NavigateParams navigate_params(new_window, url, ui::PAGE_TRANSITION_LINK);
     navigate_params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
     // Ensure that these navigations will not get 'captured' into PWA windows,
@@ -876,8 +884,12 @@
     if (set_self_as_opener) {
       if (is_from_service_worker()) {
         // TODO(crbug.com/40636155): Add test for this.
-        return RespondNow(
-            Error("Cannot specify setSelfAsOpener Service Worker extension."));
+        return base::unexpected(
+            "Cannot specify setSelfAsOpener Service Worker extension.");
+      }
+      if (isolated_web_app_url_info) {
+        return base::unexpected(
+            "Cannot specify setSelfAsOpener for isolated-app:// URLs.");
       }
       // TODO(crbug.com/40636155): Add tests for checking opener SiteInstance
       // behavior from a SW based extension's extension frame (e.g. from popup).
@@ -890,7 +902,41 @@
           render_frame_host()->GetSiteInstance();
     }
 
-    Navigate(&navigate_params);
+    return navigate_params;
+  };
+
+  if (!isolated_web_app_url_info) {
+    for (const GURL& url : urls) {
+      ASSIGN_OR_RETURN(
+          NavigateParams navigate_params, create_nav_params(url),
+          [&](const std::string& error) { return RespondNow(Error(error)); });
+      Navigate(&navigate_params);
+    }
+  } else {
+    CHECK_EQ(urls.size(), 1U);
+    const GURL& original_url = urls[0];
+
+    const webapps::AppId& iwa_id = isolated_web_app_url_info->app_id();
+    web_app::WebAppRegistrar& registrar =
+        web_app::WebAppProvider::GetForWebApps(window_profile)
+            ->registrar_unsafe();
+
+    // TODO(crbug.com/424128443): create an dummy tab in the browser so that the
+    // returned window's tab count is always equal to 1 -- this will limit the
+    // extension's ability to figure out which IWAs are installed without the
+    // `tabs` permission.
+    if (registrar.IsIsolated(iwa_id)) {
+      ASSIGN_OR_RETURN(
+          NavigateParams navigate_params,
+          create_nav_params(registrar.GetAppStartUrl(iwa_id)),
+          [&](const std::string& error) { return RespondNow(Error(error)); });
+      base::WeakPtr<content::NavigationHandle> handle =
+          Navigate(&navigate_params);
+      CHECK(handle);
+      web_app::EnqueueLaunchParams(
+          handle->GetWebContents(), iwa_id, original_url,
+          /*wait_for_navigation_to_complete=*/true, handle->NavigationStart());
+    }
   }
 
   const TabModel* tab = nullptr;
diff --git a/chrome/browser/extensions/api/tabs/tabs_test.cc b/chrome/browser/extensions/api/tabs/tabs_test.cc
index c6602bff..74dc4204 100644
--- a/chrome/browser/extensions/api/tabs/tabs_test.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_test.cc
@@ -237,10 +237,11 @@
 
   // Basic window details.
   gfx::Rect bounds;
-  if (browser()->window()->IsMinimized())
+  if (browser()->window()->IsMinimized()) {
     bounds = browser()->window()->GetRestoredBounds();
-  else
+  } else {
     bounds = browser()->window()->GetBounds();
+  }
 
   function = base::MakeRefCounted<WindowsGetFunction>();
   function->set_extension(extension.get());
@@ -691,8 +692,9 @@
 
 IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, QueryCurrentWindowTabs) {
   const size_t kExtraWindows = 3;
-  for (size_t i = 0; i < kExtraWindows; ++i)
+  for (size_t i = 0; i < kExtraWindows; ++i) {
     CreateBrowser(browser()->profile());
+  }
 
   GURL url(url::kAboutBlankURL);
   ASSERT_TRUE(AddTabAtIndex(0, url, ui::PAGE_TRANSITION_LINK));
@@ -858,8 +860,9 @@
 
   // Get the display bounds so we can test whether the window intersects.
   gfx::Rect displays;
-  for (const auto& display : display::Screen::GetScreen()->GetAllDisplays())
+  for (const auto& display : display::Screen::GetScreen()->GetAllDisplays()) {
     displays.Union(display.bounds());
+  }
 
   int window_id = ExtensionTabUtil::GetWindowId(browser());
   gfx::Rect window_bounds = browser()->window()->GetBounds();
@@ -1074,8 +1077,9 @@
 IN_PROC_BROWSER_TEST_F(ExtensionWindowCreateTest, ValidateCreateWindowBounds) {
   // Get the display bounds so we can test whether the window intersects.
   gfx::Rect displays;
-  for (const auto& display : display::Screen::GetScreen()->GetAllDisplays())
+  for (const auto& display : display::Screen::GetScreen()->GetAllDisplays()) {
     displays.Union(display.bounds());
+  }
 
   static const char kArgsCreateFunction[] =
       "[{\"left\": %d, \"top\": %d, \"width\": %d, \"height\": %d }]";
@@ -1240,7 +1244,20 @@
     ASSERT_EQ(BrowserList::GetInstance()->size(), 1ul);
     Browser* iwa_browser = *BrowserList::GetInstance()->begin();
     ASSERT_EQ(iwa_browser->tab_strip_model()->count(), 1);
-    EXPECT_EQ(iwa_browser->tab_strip_model()->GetWebContentsAt(0)->GetURL(),
+
+    auto* web_contents = iwa_browser->tab_strip_model()->GetActiveWebContents();
+    content::WaitForLoadStop(web_contents);
+    EXPECT_EQ(web_contents->GetURL(), url_info.origin().GetURL());
+
+    static constexpr std::string_view kLaunchQueueScript = R"(
+      new Promise(async (resolve) => {
+        window.launchQueue.setConsumer(launchParams => {
+          resolve(launchParams.targetURL);
+        });
+      });
+    )";
+
+    EXPECT_EQ(content::EvalJs(web_contents, kLaunchQueueScript),
               url_info.origin().GetURL().Resolve("/index.html"));
   } else {
     EXPECT_FALSE(result);
@@ -2014,8 +2031,7 @@
                                              double* default_zoom_factor);
 
   // Runs chrome.tabs.setZoom(), expecting an error.
-  std::string RunSetZoomExpectError(int tab_id,
-                                    double zoom_factor);
+  std::string RunSetZoomExpectError(int tab_id, double zoom_factor);
 
   // Runs chrome.tabs.setZoomSettings(), expecting an error.
   std::string RunSetZoomSettingsExpectError(int tab_id,
@@ -2056,12 +2072,14 @@
           get_zoom_function.get(), base::StringPrintf("[%u]", tab_id),
           browser()->profile());
 
-  if (!get_zoom_result)
+  if (!get_zoom_result) {
     return testing::AssertionFailure() << "no result";
+  }
 
   std::optional<double> maybe_value = get_zoom_result->GetIfDouble();
-  if (!maybe_value.has_value())
+  if (!maybe_value.has_value()) {
     return testing::AssertionFailure() << "result was not a double";
+  }
 
   *zoom_factor = maybe_value.value();
   return testing::AssertionSuccess();
@@ -2103,8 +2121,9 @@
           get_zoom_settings_function.get(), base::StringPrintf("[%u]", tab_id),
           browser()->profile());
 
-  if (!get_zoom_settings_result)
+  if (!get_zoom_settings_result) {
     return testing::AssertionFailure() << "no result";
+  }
 
   base::Value::Dict get_zoom_settings_dict =
       utils::ToDict(std::move(get_zoom_settings_result));
@@ -2177,7 +2196,7 @@
   ui_test_utils::NavigateToURLWithDisposition(
       browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
-  return  browser()->tab_strip_model()->GetActiveWebContents();
+  return browser()->tab_strip_model()->GetActiveWebContents();
 }
 
 namespace {
@@ -2388,8 +2407,7 @@
   std::string error =
       RunSetZoomSettingsExpectError(tab_id, "manual", "per-origin");
   EXPECT_TRUE(base::MatchPattern(error, keys::kPerOriginOnlyInAutomaticError));
-  error =
-      RunSetZoomSettingsExpectError(tab_id, "disabled", "per-origin");
+  error = RunSetZoomSettingsExpectError(tab_id, "disabled", "per-origin");
   EXPECT_TRUE(base::MatchPattern(error, keys::kPerOriginOnlyInAutomaticError));
 }
 
diff --git a/chrome/browser/extensions/chrome_extension_system.cc b/chrome/browser/extensions/chrome_extension_system.cc
index f9a3e23..8f8861b 100644
--- a/chrome/browser/extensions/chrome_extension_system.cc
+++ b/chrome/browser/extensions/chrome_extension_system.cc
@@ -27,6 +27,7 @@
 #include "chrome/browser/extensions/extension_garbage_collector.h"
 #include "chrome/browser/extensions/extension_management.h"
 #include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_sync_service.h"
 #include "chrome/browser/extensions/install_verifier.h"
 #include "chrome/browser/extensions/load_error_reporter.h"
 #include "chrome/browser/extensions/shared_module_service.h"
@@ -63,7 +64,6 @@
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
 #include "chrome/browser/extensions/chrome_app_sorting.h"
-#include "chrome/browser/extensions/extension_sync_service.h"
 #else
 #include "chrome/browser/extensions/chrome_extension_registrar_delegate.h"
 #include "extensions/browser/null_app_sorting.h"
@@ -289,10 +289,8 @@
 
   extension_service_->Init();
 
-#if BUILDFLAG(ENABLE_EXTENSIONS)
   // Make sure ExtensionSyncService is created.
   ExtensionSyncService::Get(profile_);
-#endif
 
   // Make the chrome://extension-icon/ resource available.
   content::URLDataSource::Add(profile_,
diff --git a/chrome/browser/extensions/extension_sync_data.h b/chrome/browser/extensions/extension_sync_data.h
index 9c29d320..6d58e504 100644
--- a/chrome/browser/extensions/extension_sync_data.h
+++ b/chrome/browser/extensions/extension_sync_data.h
@@ -13,9 +13,12 @@
 #include "base/version.h"
 #include "components/sync/model/string_ordinal.h"
 #include "components/sync/model/sync_change.h"
+#include "extensions/buildflags/buildflags.h"
 #include "extensions/common/constants.h"
 #include "url/gurl.h"
 
+static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE));
+
 namespace syncer {
 class SyncData;
 }
diff --git a/chrome/browser/extensions/extension_sync_data_unittest.cc b/chrome/browser/extensions/extension_sync_data_unittest.cc
index 7e8ada3..b870ba9e 100644
--- a/chrome/browser/extensions/extension_sync_data_unittest.cc
+++ b/chrome/browser/extensions/extension_sync_data_unittest.cc
@@ -13,11 +13,14 @@
 #include "components/sync/protocol/entity_specifics.pb.h"
 #include "components/sync/protocol/extension_specifics.pb.h"
 #include "extensions/browser/disable_reason.h"
+#include "extensions/buildflags/buildflags.h"
 #include "extensions/common/extension.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
+static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE));
+
 namespace extensions {
 
 namespace {
diff --git a/chrome/browser/extensions/extension_sync_service.cc b/chrome/browser/extensions/extension_sync_service.cc
index aea955bc..01e31ca8 100644
--- a/chrome/browser/extensions/extension_sync_service.cc
+++ b/chrome/browser/extensions/extension_sync_service.cc
@@ -25,7 +25,6 @@
 #include "chrome/browser/extensions/permissions/permissions_updater.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/glue/sync_start_util.h"
-#include "chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/sync_helper.h"
 #include "components/sync/model/sync_change.h"
@@ -43,6 +42,10 @@
 #include "extensions/common/permissions/permission_message_provider.h"
 #include "extensions/common/permissions/permissions_data.h"
 
+#if !BUILDFLAG(IS_ANDROID)
+#include "chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.h"
+#endif
+
 using extensions::AccountExtensionTracker;
 using extensions::AppSorting;
 using extensions::Extension;
@@ -771,6 +774,10 @@
 
 bool ExtensionSyncService::IsMigratingPreinstalledWebApp(
     const extensions::ExtensionId& extension_id) {
+#if BUILDFLAG(IS_ANDROID)
+  // Android does not support Chrome Apps.
+  return false;
+#else
   if (!migrating_default_chrome_app_ids_cache_) {
     std::vector<web_app::PreinstalledWebAppMigration> migrations =
         web_app::GetPreinstalledWebAppMigrations(*profile_);
@@ -785,4 +792,5 @@
   }
 
   return migrating_default_chrome_app_ids_cache_->contains(extension_id);
+#endif  // BUILDFLAG(IS_ANDROID)
 }
diff --git a/chrome/browser/extensions/extension_sync_service.h b/chrome/browser/extensions/extension_sync_service.h
index bf13216..1200441 100644
--- a/chrome/browser/extensions/extension_sync_service.h
+++ b/chrome/browser/extensions/extension_sync_service.h
@@ -26,6 +26,9 @@
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_registry_observer.h"
 #include "extensions/browser/extension_system.h"
+#include "extensions/buildflags/buildflags.h"
+
+static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE));
 
 class Profile;
 
@@ -176,10 +179,13 @@
   // asynchronously via MergeDataAndStartSyncing as soon as possible.
   SyncableService::StartSyncFlare flare_;
 
+#if !BUILDFLAG(IS_ANDROID)
   // Caches the set of Chrome app IDs undergoing migration to web apps because
   // it is expensive to generate every time (multiple SkBitmap copies).
+  // Android does not support Chrome apps.
   std::optional<base::flat_set<std::string>>
       migrating_default_chrome_app_ids_cache_;
+#endif  // !BUILDFLAG(IS_ANDROID)
 
   base::WeakPtrFactory<ExtensionSyncService> weak_ptr_factory_{this};
 };
diff --git a/chrome/browser/extensions/extension_sync_service_unittest.cc b/chrome/browser/extensions/extension_sync_service_unittest.cc
index befa1aa..d0e16419 100644
--- a/chrome/browser/extensions/extension_sync_service_unittest.cc
+++ b/chrome/browser/extensions/extension_sync_service_unittest.cc
@@ -32,9 +32,6 @@
 #include "chrome/browser/extensions/updater/extension_updater.h"
 #include "chrome/browser/profiles/profile_key.h"
 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
-#include "chrome/browser/themes/test/theme_service_changed_waiter.h"
-#include "chrome/browser/themes/theme_service.h"
-#include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/extensions/extension_test_util.h"
 #include "chrome/common/extensions/sync_helper.h"
@@ -60,12 +57,21 @@
 #include "extensions/browser/extension_util.h"
 #include "extensions/browser/management_policy.h"
 #include "extensions/browser/pending_extension_manager.h"
+#include "extensions/buildflags/buildflags.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/extension_urls.h"
 #include "extensions/common/manifest_url_handlers.h"
 #include "extensions/common/mojom/manifest.mojom-shared.h"
 #include "extensions/common/permissions/permission_set.h"
 
+#if !BUILDFLAG(IS_ANDROID)
+#include "chrome/browser/themes/test/theme_service_changed_waiter.h"
+#include "chrome/browser/themes/theme_service.h"
+#include "chrome/browser/themes/theme_service_factory.h"
+#endif
+
+static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE));
+
 using extensions::AccountExtensionTracker;
 using extensions::AppSorting;
 using extensions::ComponentLoader;
@@ -873,6 +879,8 @@
       ExtensionPrefs::Get(profile())->IsExternalExtensionUninstalled(kGoodCrx));
 }
 
+#if !BUILDFLAG(IS_ANDROID)
+// Disabled on Android since Android does not support Chrome Apps.
 TEST_F(ExtensionSyncServiceTest, GetSyncAppDataUserSettings) {
   InitializeEmptyExtensionService();
   const Extension* app =
@@ -929,6 +937,7 @@
 // ExtensionService, so this test probably needs a new home. Unfortunately, it
 // relies pretty heavily on things like InitializeExtension[Sync]Service() and
 // PackAndInstallCRX(). When we clean up a bit more, this should move out.
+// Disabled on Android since Android does not support Chrome Apps.
 TEST_F(ExtensionSyncServiceTest, GetSyncAppDataUserSettingsOnExtensionMoved) {
   InitializeEmptyExtensionService();
   const size_t kAppCount = 3;
@@ -973,6 +982,7 @@
     EXPECT_TRUE(app_launch_ordinals[0].LessThan(app_launch_ordinals[2]));
   }
 }
+#endif  // !BUILDFLAG(IS_ANDROID)
 
 TEST_F(ExtensionSyncServiceTest, GetSyncDataList) {
   InitializeEmptyExtensionService();
@@ -1856,6 +1866,8 @@
   }
 }
 
+#if !BUILDFLAG(IS_ANDROID)
+// Disabled on Android since Android does not support themes.
 // Regression test for crbug.com/558299
 TEST_F(ExtensionSyncServiceTest, DontSyncThemes) {
   InitializeEmptyExtensionService();
@@ -1884,6 +1896,7 @@
   waiter.WaitForThemeChanged();
   EXPECT_TRUE(processor->changes().empty());
 }
+#endif  // !BUILDFLAG(IS_ANDROID)
 
 // Tests sync behavior in the case of an item that starts out as an app and gets
 // updated to become an extension.
diff --git a/chrome/browser/extensions/extension_util.cc b/chrome/browser/extensions/extension_util.cc
index bc12f4f..b4b06269 100644
--- a/chrome/browser/extensions/extension_util.cc
+++ b/chrome/browser/extensions/extension_util.cc
@@ -13,6 +13,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
+#include "chrome/browser/extensions/extension_sync_service.h"
 #include "chrome/browser/extensions/permissions/permissions_updater.h"
 #include "chrome/browser/extensions/shared_module_service.h"
 #include "chrome/browser/profiles/profile.h"
@@ -51,7 +52,6 @@
 
 #if !BUILDFLAG(IS_ANDROID)
 #include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_sync_service.h"
 #include "chrome/browser/ui/browser.h"
 #endif
 
@@ -229,13 +229,10 @@
 
   // Reloading the extension invalidates the |extension| pointer.
   extension = registry->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
-  // TODO(crbug.com/356905053): Enable extensions sync on desktop android.
-#if !BUILDFLAG(IS_ANDROID)
   if (extension) {
     Profile* profile = Profile::FromBrowserContext(context);
     ExtensionSyncService::Get(profile)->SyncExtensionChangeIfNeeded(*extension);
   }
-#endif
 }
 
 void SetAllowFileAccess(const std::string& extension_id,
diff --git a/chrome/browser/extensions/keyed_services/chrome_browser_context_keyed_service_factories.cc b/chrome/browser/extensions/keyed_services/chrome_browser_context_keyed_service_factories.cc
index d540c47..805c38e 100644
--- a/chrome/browser/extensions/keyed_services/chrome_browser_context_keyed_service_factories.cc
+++ b/chrome/browser/extensions/keyed_services/chrome_browser_context_keyed_service_factories.cc
@@ -6,6 +6,7 @@
 
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
+#include "chrome/browser/extensions/account_extension_tracker.h"
 #include "chrome/browser/extensions/activity_log/activity_log.h"
 #include "chrome/browser/extensions/blocklist_factory.h"
 #include "chrome/browser/extensions/chrome_extension_cookies_factory.h"
@@ -18,6 +19,7 @@
 #include "chrome/browser/extensions/extension_allowlist_factory.h"
 #include "chrome/browser/extensions/extension_garbage_collector_factory.h"
 #include "chrome/browser/extensions/extension_management.h"
+#include "chrome/browser/extensions/extension_sync_service_factory.h"
 #include "chrome/browser/extensions/extension_web_ui_override_registrar.h"
 #include "chrome/browser/extensions/external_install_manager_factory.h"
 #include "chrome/browser/extensions/external_provider_manager_factory.h"
@@ -30,11 +32,9 @@
 #include "chrome/browser/extensions/updater/extension_updater_factory.h"
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
-#include "chrome/browser/extensions/account_extension_tracker.h"
 #include "chrome/browser/extensions/chrome_app_icon_service_factory.h"
 #include "chrome/browser/extensions/extension_error_controller_factory.h"
 #include "chrome/browser/extensions/extension_gcm_app_handler.h"
-#include "chrome/browser/extensions/extension_sync_service_factory.h"
 #include "chrome/browser/extensions/extension_web_ui_override_registrar.h"
 #include "chrome/browser/extensions/menu_manager_factory.h"
 #include "chrome/browser/extensions/permissions/permissions_updater.h"
@@ -54,6 +54,8 @@
   TRACE_EVENT("browser",
               "chrome_extensions::"
               "EnsureChromeBrowserContextKeyedServiceFactoriesBuilt");
+  ExtensionSyncServiceFactory::GetInstance();
+  extensions::AccountExtensionTracker::GetFactory();
   extensions::ActivityLog::GetFactoryInstance();
   extensions::BlocklistFactory::GetInstance();
   extensions::ChromeExtensionCookiesFactory::GetInstance();
@@ -78,8 +80,6 @@
   extensions::SharedModuleServiceFactory::GetInstance();
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
-  ExtensionSyncServiceFactory::GetInstance();
-  extensions::AccountExtensionTracker::GetFactory();
   extensions::ChromeAppIconServiceFactory::GetInstance();
   extensions::ExtensionErrorControllerFactory::GetInstance();
   extensions::ExtensionGCMAppHandler::GetFactoryInstance();
diff --git a/chrome/browser/extensions/keyed_services/chrome_browser_context_keyed_service_factories.h b/chrome/browser/extensions/keyed_services/chrome_browser_context_keyed_service_factories.h
index c77ce3b..12c3f18 100644
--- a/chrome/browser/extensions/keyed_services/chrome_browser_context_keyed_service_factories.h
+++ b/chrome/browser/extensions/keyed_services/chrome_browser_context_keyed_service_factories.h
@@ -5,6 +5,10 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_KEYED_SERVICES_CHROME_BROWSER_CONTEXT_KEYED_SERVICE_FACTORIES_H_
 #define CHROME_BROWSER_EXTENSIONS_KEYED_SERVICES_CHROME_BROWSER_CONTEXT_KEYED_SERVICE_FACTORIES_H_
 
+#include "extensions/buildflags/buildflags.h"
+
+static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE));
+
 namespace chrome_extensions {
 
 // Ensures the existence of any BrowserContextKeyedServiceFactory provided by
diff --git a/chrome/browser/extensions/launch_util.h b/chrome/browser/extensions/launch_util.h
index 752dbec..c758010 100644
--- a/chrome/browser/extensions/launch_util.h
+++ b/chrome/browser/extensions/launch_util.h
@@ -8,8 +8,11 @@
 #include <string>
 
 #include "components/services/app_service/public/cpp/app_launch_util.h"
+#include "extensions/buildflags/buildflags.h"
 #include "extensions/common/constants.h"
 
+static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE));
+
 namespace content {
 class BrowserContext;
 }
diff --git a/chrome/browser/extensions/signin_test_util.h b/chrome/browser/extensions/signin_test_util.h
index ac6ec347..ca808584 100644
--- a/chrome/browser/extensions/signin_test_util.h
+++ b/chrome/browser/extensions/signin_test_util.h
@@ -8,6 +8,10 @@
 #include <optional>
 #include <string>
 
+#include "extensions/buildflags/buildflags.h"
+
+static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE));
+
 class Profile;
 struct AccountInfo;
 
diff --git a/chrome/browser/extensions/sync_bundle.h b/chrome/browser/extensions/sync_bundle.h
index 0e4bd12..24fd1c4 100644
--- a/chrome/browser/extensions/sync_bundle.h
+++ b/chrome/browser/extensions/sync_bundle.h
@@ -12,8 +12,11 @@
 #include "components/sync/model/sync_change.h"
 #include "components/sync/model/sync_change_processor.h"
 #include "components/sync/model/sync_data.h"
+#include "extensions/buildflags/buildflags.h"
 #include "extensions/common/extension_id.h"
 
+static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE));
+
 namespace extensions {
 
 class ExtensionSyncData;
diff --git a/chrome/browser/glic/glic_enabling.h b/chrome/browser/glic/glic_enabling.h
index 77fc205..1732150 100644
--- a/chrome/browser/glic/glic_enabling.h
+++ b/chrome/browser/glic/glic_enabling.h
@@ -166,19 +166,6 @@
     glic_user_status_fetcher_->SetGlicUserStatusUrlForTest(test_url);
   }
 
-  void SetUserStatusFetchOverrideForTest(
-      GlicUserStatusFetcher::FetchOverrideCallback fetch_override) {
-    glic_user_status_fetcher_->SetFetchOverrideForTest(
-        std::move(fetch_override));
-  }
-
-  // Updates the user status when information suggests that it might have
-  // changed recently. This is internally debounced to avoid excessive
-  // requests, for signals that might be received multiple times.
-  void UpdateUserStatusWithDebouncing() {
-    glic_user_status_fetcher_->UpdateUserStatusWithDebouncing();
-  }
-
   // This is called anytime IsAllowed() might return a different value.
   using EnableChangedCallback = base::RepeatingClosure;
   base::CallbackListSubscription RegisterAllowedChanged(
diff --git a/chrome/browser/glic/glic_user_status_fetcher.cc b/chrome/browser/glic/glic_user_status_fetcher.cc
index d474932..2090f895 100644
--- a/chrome/browser/glic/glic_user_status_fetcher.cc
+++ b/chrome/browser/glic/glic_user_status_fetcher.cc
@@ -191,8 +191,6 @@
 }
 
 void GlicUserStatusFetcher::UpdateUserStatus() {
-  last_update_start_time_ = base::Time::Now();
-
   if (refresh_status_timer_.IsRunning()) {
     refresh_status_timer_.Stop();
   }
@@ -205,55 +203,16 @@
 
   // only send user status request when primary account exists and refresh
   // token is available.
-  if (!identity_manager->HasPrimaryAccountWithRefreshToken(
+  if (identity_manager->HasPrimaryAccountWithRefreshToken(
           signin::ConsentLevel::kSignin)) {
+    // Only send the RPC for enterprise account.
+    if (!IsEnterpriseAccount()) {
+      return;
+    }
+    FetchNow();
+  } else {
     is_user_status_waiting_for_refresh_token_ = true;
-    return;
   }
-
-  // Only send the RPC for enterprise account.
-  if (!IsEnterpriseAccount()) {
-    return;
-  }
-
-  // Cancel any ongoing fetch. This will do nothing if the request is already
-  // finished.
-  CancelUserStatusUpdateIfNeeded();
-
-  // schedule next run regardless.
-  ScheduleUserStatusUpdate(features::kGlicUserStatusRequestDelay.Get());
-
-  auto gaia_id_hash = GetGaiaIdHashForPrimaryAccount(profile_);
-  if (!gaia_id_hash.has_value()) {
-    return;
-  }
-
-  auto callback = base::BindOnce(&GlicUserStatusFetcher::ProcessResponse,
-                                 weak_ptr_factory_.GetWeakPtr(),
-                                 gaia_id_hash.value().ToBase64());
-
-  if (fetch_override_for_test_) {
-    fetch_override_for_test_.Run(std::move(callback));
-    return;
-  }
-
-  request_sender_ = std::make_unique<google_apis::RequestSender>(
-      std::make_unique<google_apis::AuthService>(
-          identity_manager,
-          identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSignin),
-          profile_->GetURLLoaderFactory(),
-          std::vector<std::string>{oauth2_scope_}),
-      profile_->GetURLLoaderFactory(),
-      base::ThreadPool::CreateSequencedTaskRunner(
-          {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
-           base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})
-          .get(),
-      /*custom_user_agent=*/std::string(), kTrafficAnnotation);
-
-  auto request = std::make_unique<GlicUserStatusRequest>(
-      request_sender_.get(), endpoint_, std::move(callback));
-  cancel_closure_ =
-      request_sender_->StartRequestWithAuthRetry(std::move(request));
 }
 
 void GlicUserStatusFetcher::ScheduleUserStatusUpdate(
@@ -292,34 +251,56 @@
   return signin::GaiaIdHash::FromGaiaId(primary_account.gaia);
 }
 
+void GlicUserStatusFetcher::FetchNow() {
+  // Cancel any ongoing fetch. This will do nothing if the request is already
+  // finished.
+  CancelUserStatusUpdateIfNeeded();
+
+  // schedule next run regardless.
+  ScheduleUserStatusUpdate(features::kGlicUserStatusRequestDelay.Get());
+
+  auto account_info = GetGaiaIdHashForPrimaryAccount(profile_);
+
+  if (!account_info.has_value()) {
+    return;
+  }
+
+  std::vector<std::string> scopes;
+  scopes.push_back(oauth2_scope_);
+
+  signin::IdentityManager* identity_manager =
+      IdentityManagerFactory::GetForProfile(profile_);
+
+  request_sender_ = std::make_unique<google_apis::RequestSender>(
+      std::make_unique<google_apis::AuthService>(
+          identity_manager,
+          identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSignin),
+          profile_->GetURLLoaderFactory(),
+          std::vector<std::string>{oauth2_scope_}),
+      profile_->GetURLLoaderFactory(),
+      base::ThreadPool::CreateSequencedTaskRunner(
+          {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
+           base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})
+          .get(),
+      /*custom_user_agent=*/std::string(), kTrafficAnnotation);
+
+  auto request = std::make_unique<GlicUserStatusRequest>(
+      request_sender_.get(), endpoint_,
+      base::BindOnce(&GlicUserStatusFetcher::ProcessResponse,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     account_info.value().ToBase64()));
+  cancel_closure_ =
+      request_sender_->StartRequestWithAuthRetry(std::move(request));
+}
+
 void GlicUserStatusFetcher::CancelUserStatusUpdateIfNeeded() {
   if (cancel_closure_) {
     std::move(cancel_closure_).Run();
   }
 }
 
-void GlicUserStatusFetcher::UpdateUserStatusWithDebouncing() {
-  // If it has been less than the debounce interval since the last update,
-  // don't update the user status immediately but schedule it to run after
-  // the debounce interval (unless it already was scheduled to run by that
-  // time). This limits the rate at which certain kinds of potentially frequent
-  // events can cause requests to be sent, while still making the update
-  // immediate most of the time.
-  const base::TimeDelta debounce_interval =
-      features::kGlicUserStatusDebounceInterval.Get();
-  const base::Time now = base::Time::Now();
-
-  if (now >= last_update_start_time_ + debounce_interval) {
-    UpdateUserStatus();
-  } else if (!refresh_status_timer_.IsRunning() ||
-             refresh_status_timer_.desired_run_time() >
-                 now + debounce_interval) {
-    ScheduleUserStatusUpdate(debounce_interval);
-  }
-}
-
 void GlicUserStatusFetcher::ProcessResponse(const std::string& account_id_hash,
-                                            const CachedUserStatus& user_status) {
+                                            CachedUserStatus user_status) {
   // We don't overwrite the previous GlicUserStatus when UserStatusCode is
   // SERVER_UNAVAILABLE.
   if (user_status.user_status_code != UserStatusCode::SERVER_UNAVAILABLE) {
diff --git a/chrome/browser/glic/glic_user_status_fetcher.h b/chrome/browser/glic/glic_user_status_fetcher.h
index 8f1bd59..010d7ae 100644
--- a/chrome/browser/glic/glic_user_status_fetcher.h
+++ b/chrome/browser/glic/glic_user_status_fetcher.h
@@ -58,9 +58,6 @@
 // clock adjustment if any.
 class GlicUserStatusFetcher {
  public:
-  using FetchOverrideCallback = base::RepeatingCallback<void(
-      base::OnceCallback<void(const CachedUserStatus&)>)>;
-
   explicit GlicUserStatusFetcher(Profile* profile,
                                  base::RepeatingClosure callback);
   ~GlicUserStatusFetcher();
@@ -75,15 +72,7 @@
   void ScheduleUserStatusUpdate(base::TimeDelta time_to_next_update);
   void CancelUserStatusUpdateIfNeeded();
 
-  // Updates the user status when information suggests that it might have
-  // changed recently. This is internally debounced to avoid excessive
-  // requests, for signals that might be received multiple times.
-  void UpdateUserStatusWithDebouncing();
-
   void SetGlicUserStatusUrlForTest(GURL test_url) { endpoint_ = test_url; }
-  void SetFetchOverrideForTest(FetchOverrideCallback fetch_override) {
-    fetch_override_for_test_ = std::move(fetch_override);
-  }
 
  private:
   static std::optional<signin::GaiaIdHash> GetGaiaIdHashForPrimaryAccount(
@@ -91,22 +80,20 @@
 
   void CreateRequestSender();
 
+  void FetchNow();
+
   void ProcessResponse(const std::string& account_id_hash,
-                       const CachedUserStatus& user_status);
+                       CachedUserStatus user_status);
 
   bool is_user_status_waiting_for_refresh_token_ = false;
   raw_ptr<Profile> profile_;
   const base::RepeatingClosure callback_;
   GURL endpoint_;
   std::string oauth2_scope_;
-  base::Time last_update_start_time_;
   base::WallClockTimer refresh_status_timer_;
   std::unique_ptr<google_apis::RequestSender> request_sender_;
   base::OnceClosure cancel_closure_;
 
-  // When set, replaces the actual fetch with a callback.
-  FetchOverrideCallback fetch_override_for_test_;
-
   base::WeakPtrFactory<GlicUserStatusFetcher> weak_ptr_factory_{this};
 };
 
diff --git a/chrome/browser/glic/glic_user_status_request.cc b/chrome/browser/glic/glic_user_status_request.cc
index a7fe83e0..83bd6c08 100644
--- a/chrome/browser/glic/glic_user_status_request.cc
+++ b/chrome/browser/glic/glic_user_status_request.cc
@@ -35,7 +35,7 @@
 GlicUserStatusRequest::GlicUserStatusRequest(
     google_apis::RequestSender* sender,
     GURL url,
-    base::OnceCallback<void(const CachedUserStatus&)> process_response_callback)
+    base::OnceCallback<void(CachedUserStatus)> process_response_callback)
     : UrlFetchRequestBase(sender,
                           google_apis::ProgressCallback(),
                           google_apis::ProgressCallback()),
diff --git a/chrome/browser/glic/glic_user_status_request.h b/chrome/browser/glic/glic_user_status_request.h
index 197519a..a7cc3e333 100644
--- a/chrome/browser/glic/glic_user_status_request.h
+++ b/chrome/browser/glic/glic_user_status_request.h
@@ -18,7 +18,8 @@
   explicit GlicUserStatusRequest(
       google_apis::RequestSender* sender,
       GURL url,
-      base::OnceCallback<void(const CachedUserStatus&)> process_response_callback);
+
+      base::OnceCallback<void(CachedUserStatus)> process_response_callback);
   GlicUserStatusRequest(const GlicUserStatusRequest&) = delete;
   GlicUserStatusRequest& operator=(const GlicUserStatusRequest&) = delete;
   ~GlicUserStatusRequest() override;
@@ -45,7 +46,7 @@
       std::string_view response_body);
 
   GURL url_;
-  base::OnceCallback<void(const CachedUserStatus&)> process_response_callback_;
+  base::OnceCallback<void(CachedUserStatus)> process_response_callback_;
 };
 
 }  // namespace glic
diff --git a/chrome/browser/glic/host/glic.mojom b/chrome/browser/glic/host/glic.mojom
index a5abf82a..37ee1f6 100644
--- a/chrome/browser/glic/host/glic.mojom
+++ b/chrome/browser/glic/host/glic.mojom
@@ -7,12 +7,12 @@
 import "components/content_settings/core/common/content_settings_types.mojom";
 import "components/optimization_guide/content/mojom/ai_page_content_metadata.mojom";
 import "mojo/public/mojom/base/proto_wrapper.mojom";
-import "mojo/public/mojom/base/time.mojom";
 import "mojo/public/mojom/base/version.mojom";
 import "skia/public/mojom/bitmap.mojom";
 import "ui/gfx/geometry/mojom/geometry.mojom";
 import "url/mojom/origin.mojom";
 import "url/mojom/url.mojom";
+import "mojo/public/mojom/base/time.mojom";
 
 // The ready state of the profile.
 enum ProfileReadyState {
@@ -28,7 +28,6 @@
 interface Page {
   // Called before the page is shown.
   IntentToShow();
-
   // Called any time the ready state of the profile changes.
   // `ready_state` = `GlicEnabling::GetProfileReadyState()`.
   SetProfileReadyState(ProfileReadyState ready_state);
@@ -37,8 +36,8 @@
 // Factory for PageHandler used in chrome://glic.
 interface PageHandlerFactory {
   // Creates the PageHandler for chrome://glic.
-  CreatePageHandler(
-      pending_receiver<PageHandler> receiver, pending_remote<Page> page);
+  CreatePageHandler(pending_receiver<PageHandler> receiver,
+      pending_remote<Page> page);
 };
 
 // It is used in the Glic.PanelWebUiState.FinishState histogram.
@@ -74,7 +73,6 @@
   // Web view is displayed, but it is an error page.
   kGuestError = 11,
 };
-
 // LINT.ThenChange(//tools/metrics/histograms/metadata/glic/enums.xml:WebUiState)
 
 // The result of `PrepareForClient()`.
@@ -133,7 +131,6 @@
   // Failed to start a new task.
   [MinVersion=1] kFailedToStartTask = 4,
 };
-
 // LINT.ThenChange(//tools/metrics/histograms/metadata/glic/enums.xml:ActInFocusedTabErrorReason)
 
 // Reason why capturing desktop screenshot failed. This MUST be kept in sync
@@ -209,9 +206,6 @@
   bool enable_closed_captioning_feature;
   // Whether the glic closed captioning setting is enabled.
   bool closed_captioning_setting_enabled;
-  // Whether features::kGlicUserStatusCheck is enabled with
-  // features::kGlicUserStatusRefreshApi true.
-  bool enable_maybe_refresh_user_status;
 };
 
 // Options for getting tab context.
@@ -325,7 +319,6 @@
   // The web client drops the highlight.
   [MinVersion=7] kDroppedByWebClient,
 };
-
 // LINT.ThenChange(//tools/metrics/histograms/metadata/glic/enums.xml:GlicScrollToErrorReason)
 
 // A single suggestion.
@@ -535,11 +528,11 @@
   // Enrolls Chrome in the synthetic experiment group specified by
   // trial_name.group_name. Enrollment will start when the API is called and end
   // when Chrome closes.
-  SetSyntheticExperimentState(string trial_name, string group_name);
+  SetSyntheticExperimentState(string trial_name,
+                              string group_name);
 
   // Attempts to open the OS permission settings page.  No return value.
-  OpenOsPermissionSettingsMenu(
-      content_settings.mojom.ContentSettingsType type);
+  OpenOsPermissionSettingsMenu(content_settings.mojom.ContentSettingsType type);
 
   // Get the status of the OS Microphone permission currently granted to Chrome.
   GetOsMicrophonePermissionStatus() => (bool enabled);
@@ -547,11 +540,6 @@
   // Returns zero-state suggestions from the currently active tab.
   GetZeroStateSuggestionsForFocusedTab(bool? is_first_run)
       => (ZeroStateSuggestions? suggestions);
-
-  // Called when the client believes that the user's status may have changed.
-  // For example, an RPC may have been rejected due to the the service being
-  // disabled.
-  MaybeRefreshUserStatus();
 };
 
 // Data sent from the browser to the web client with panel opening information.
@@ -607,11 +595,10 @@
   // An unsupported/unknown source.
   [Default] kUnsupported = 8,
   // From the What's New page.
-  [MinVersion=1] kWhatsNew = 9,
+  [ MinVersion=1 ] kWhatsNew = 9,
   // User clicked the sign-in button and signed in.
-  [MinVersion=2] kAfterSignIn = 10,
+  [ MinVersion=2 ] kAfterSignIn = 10,
 };
-
 // LINT.ThenChange(//tools/metrics/histograms/metadata/glic/enums.xml:GlicInvocationSource, //chrome/browser/glic/glic_metrics.h:ResponseSegmentation)
 
 // Web client's operation modes.
@@ -629,7 +616,6 @@
   // Audio operation mode.
   kAudio = 1,
 };
-
 // LINT.ThenChange(//tools/metrics/histograms/metadata/glic/enums.xml:WebClientMode)
 
 // Carries back to the browser information on how to configure the panel being
@@ -782,6 +768,7 @@
 // Data about the why there is no focused tab.
 struct NoFocusedTabData {
   // Data about the active tab that could not be focused, if one exists.
+
   TabData? active_tab_data;
   // A human-readable debug message explaining why there is no focused tab.
   string no_focus_reason;
diff --git a/chrome/browser/glic/host/glic_api_browsertest.cc b/chrome/browser/glic/host/glic_api_browsertest.cc
index 95b77c6..d318fbf 100644
--- a/chrome/browser/glic/host/glic_api_browsertest.cc
+++ b/chrome/browser/glic/host/glic_api_browsertest.cc
@@ -32,7 +32,6 @@
 #include "chrome/browser/contextual_cueing/contextual_cueing_service.h"
 #include "chrome/browser/contextual_cueing/contextual_cueing_service_factory.h"
 #include "chrome/browser/contextual_cueing/mock_contextual_cueing_service.h"
-#include "chrome/browser/enterprise/browser_management/management_service_factory.h"
 #include "chrome/browser/glic/glic_keyed_service.h"
 #include "chrome/browser/glic/glic_keyed_service_factory.h"
 #include "chrome/browser/glic/glic_metrics.h"
@@ -58,8 +57,6 @@
 #include "chrome/test/interaction/interactive_browser_test.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/metrics/metrics_service.h"
-#include "components/policy/core/common/management/management_service.h"
-#include "components/policy/core/common/management/scoped_management_service_override_for_testing.h"
 #include "components/signin/public/identity_manager/identity_test_utils.h"
 #include "components/variations/synthetic_trial_registry.h"
 #include "content/public/browser/render_frame_host.h"
@@ -96,7 +93,6 @@
       "GlicApiTestSystemSettingsTest",
       "GlicApiTestWithOneTabAndContextualCueing",
       "GlicApiTestWithOneTabAndPreloading",
-      "GlicApiTestUserStatusCheckTest",
   };
 }
 
@@ -169,21 +165,16 @@
 
     features_.InitWithFeaturesAndParameters(
         /*enabled_features=*/
-        {
-            {features::kGlic,
-             {
-                 {"glic-default-hotkey", "Ctrl+G"},
-                 // Shorten load timeouts.
-                 {features::kGlicPreLoadingTimeMs.name, "20"},
-                 {features::kGlicMinLoadingTimeMs.name, "40"},
-             }},
-            {features::kGlicScrollTo, {}},
-            {features::kGlicClosedCaptioning, {}},
-            {features::kGlicApiActivationGating, {}},
-            {features::kGlicUserStatusCheck,
-             {{features::kGlicUserStatusRefreshApi.name, "true"},
-              {features::kGlicUserStatusDebounceInterval.name, "2s"}}},
-        },
+        {{features::kGlic,
+          {
+              {"glic-default-hotkey", "Ctrl+G"},
+              // Shorten load timeouts.
+              {features::kGlicPreLoadingTimeMs.name, "20"},
+              {features::kGlicMinLoadingTimeMs.name, "40"},
+          }},
+         {features::kGlicScrollTo, {}},
+         {features::kGlicClosedCaptioning, {}},
+         {features::kGlicApiActivationGating, {}}},
         /*disabled_features=*/
         {
             features::kGlicWarming,
@@ -202,16 +193,6 @@
     test::InteractiveGlicTest::TearDownOnMainThread();
   }
 
-  GlicKeyedService* GetService() {
-    Profile* profile = browser()->profile();
-    return GlicKeyedServiceFactory::GetGlicKeyedService(profile);
-  }
-
-  Host* GetHost() {
-    Profile* profile = browser()->profile();
-    return &GlicKeyedServiceFactory::GetGlicKeyedService(profile)->host();
-  }
-
   // Run the test typescript function. The typescript function must have the
   // same name as the current test.
   // If the test uses `advanceToNextStep()`, then ContinueJsTest() must be
@@ -384,6 +365,16 @@
     GlicProfileManager::ForceConnectionTypeForTesting(std::nullopt);
   }
 
+  GlicKeyedService* GetService() {
+    Profile* profile = browser()->profile();
+    return GlicKeyedServiceFactory::GetGlicKeyedService(profile);
+  }
+
+  Host* GetHost() {
+    Profile* profile = browser()->profile();
+    return &GlicKeyedServiceFactory::GetGlicKeyedService(profile)->host();
+  }
+
   auto CreateAndWarmGlic() {
     return Do([this] { GetService()->TryPreload(); });
   }
@@ -1433,69 +1424,5 @@
       GlicRequestEvent::kRequestReceivedWhileHidden, 1);
 }
 
-class GlicApiTestUserStatusCheckTest : public GlicApiTestWithOneTab {
- protected:
-  void SetUpOnMainThread() override {
-    GlicApiTestWithOneTab::SetUpOnMainThread();
-    GetService()->enabling().SetUserStatusFetchOverrideForTest(
-        base::BindRepeating(&GlicApiTestUserStatusCheckTest::UserStatusFetch,
-                            base::Unretained(this)));
-  }
-
-  void UserStatusFetch(
-      base::OnceCallback<void(const CachedUserStatus&)> callback) {
-    user_status_fetch_count_++;
-    base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-        FROM_HERE, base::BindOnce(std::move(callback), user_status_));
-  }
-
-  CachedUserStatus user_status_;
-  unsigned int user_status_fetch_count_ = 0;
-};
-
-IN_PROC_BROWSER_TEST_F(GlicApiTestUserStatusCheckTest,
-                       testMaybeRefreshUserStatus) {
-  Profile* profile = browser()->profile();
-  policy::ScopedManagementServiceOverrideForTesting platform_management(
-      policy::ManagementServiceFactory::GetForProfile(profile),
-      policy::EnterpriseManagementAuthority::CLOUD);
-  ASSERT_FALSE(GlicEnabling::EnablementForProfile(profile).DisallowedByAdmin());
-  user_status_.user_status_code = UserStatusCode::DISABLED_BY_ADMIN;
-  ExecuteJsTest();
-  ASSERT_TRUE(base::test::RunUntil([&]() {
-    return GlicEnabling::EnablementForProfile(profile).DisallowedByAdmin();
-  }));
-  EXPECT_GE(user_status_fetch_count_, 1u);
-}
-
-IN_PROC_BROWSER_TEST_F(GlicApiTestUserStatusCheckTest,
-                       testMaybeRefreshUserStatusDebounced) {
-  // As previous, but requests several updates (e.g., as though many errors
-  // were processed around the same time). An "enabled" status is assumed as
-  // otherwise the client will be unloaded.
-  //
-  // These expectations are a little loose, because we can't use mock time in
-  // browser tests yet, but they should be sufficient to catch a total lack of
-  // debouncing, at least.
-  Profile* profile = browser()->profile();
-  policy::ScopedManagementServiceOverrideForTesting platform_management(
-      policy::ManagementServiceFactory::GetForProfile(profile),
-      policy::EnterpriseManagementAuthority::CLOUD);
-  ASSERT_FALSE(GlicEnabling::EnablementForProfile(profile).DisallowedByAdmin());
-  user_status_.user_status_code = UserStatusCode::ENABLED;
-  ExecuteJsTest();
-  ASSERT_TRUE(base::test::RunUntil([&]() {
-    return user_status_fetch_count_ >= 2;
-  })) << "There should be at least two fetches (initial and debounced)";
-  {
-    base::RunLoop loop;
-    base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
-        FROM_HERE, loop.QuitClosure(), base::Seconds(5));
-    loop.Run();
-  }
-  EXPECT_LT(user_status_fetch_count_, 5u)
-      << "We should not send most of the fetches";
-}
-
 }  // namespace
 }  // namespace glic
diff --git a/chrome/browser/glic/host/glic_page_handler.cc b/chrome/browser/glic/host/glic_page_handler.cc
index eb4e7cc..5efa6c74 100644
--- a/chrome/browser/glic/host/glic_page_handler.cc
+++ b/chrome/browser/glic/host/glic_page_handler.cc
@@ -365,9 +365,6 @@
         base::FeatureList::IsEnabled(features::kGlicClosedCaptioning);
     state->closed_captioning_setting_enabled =
         pref_service_->GetBoolean(prefs::kGlicClosedCaptioningEnabled);
-    state->enable_maybe_refresh_user_status =
-        base::FeatureList::IsEnabled(features::kGlicUserStatusCheck) &&
-        features::kGlicUserStatusRefreshApi.Get();
 
     std::move(callback).Run(std::move(state));
   }
@@ -840,17 +837,6 @@
             std::move(callback), base::TimeTicks::Now()));
   }
 
-  void MaybeRefreshUserStatus() override {
-    if (!base::FeatureList::IsEnabled(features::kGlicUserStatusCheck) ||
-        !features::kGlicUserStatusRefreshApi.Get()) {
-      receiver_.ReportBadMessage(
-          "Client should not call MaybeRefreshUserStatus without the "
-          "GlicUserStatusCheck feature enabled with the refresh API.");
-      return;
-    }
-    glic_service_->enabling().UpdateUserStatusWithDebouncing();
-  }
-
   void OnOsPermissionSettingChanged(ContentSettingsType content_type,
                                     bool is_blocked) {
     // Ignore other content types.
diff --git a/chrome/browser/media/encrypted_media_supported_types_browsertest.cc b/chrome/browser/media/encrypted_media_supported_types_browsertest.cc
index b94c846..dd38d55 100644
--- a/chrome/browser/media/encrypted_media_supported_types_browsertest.cc
+++ b/chrome/browser/media/encrypted_media_supported_types_browsertest.cc
@@ -856,6 +856,18 @@
 };
 #endif  // BUILDFLAG(ENABLE_LIBRARY_CDMS)
 
+class EncryptedMediaSupportedTypesWidevinePersistentLicenseNotSupported
+    : public EncryptedMediaSupportedTypesWidevineTest {
+ protected:
+  EncryptedMediaSupportedTypesWidevinePersistentLicenseNotSupported() {
+    DisableFeature(media::kWidvinePersistentLicenseSupport);
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    EncryptedMediaSupportedTypesTest::SetUpCommandLine(command_line);
+  }
+};
+
 IN_PROC_BROWSER_TEST_F(EncryptedMediaSupportedTypesClearKeyTest, Basic) {
   EXPECT_SUCCESS(IsSupportedByKeySystem(kClearKey, kVideoWebMMimeType,
                                         video_webm_codecs()));
@@ -2265,3 +2277,10 @@
 }
 
 #endif  // BUILDFLAG(ENABLE_LIBRARY_CDMS)
+
+IN_PROC_BROWSER_TEST_F(
+    EncryptedMediaSupportedTypesWidevinePersistentLicenseNotSupported,
+    Basic) {
+  EXPECT_UNSUPPORTED(
+      IsSessionTypeSupported(kWidevine, SessionType::kPersistentLicense));
+}
diff --git a/chrome/browser/media/webrtc/thumbnail_capturer_mac.mm b/chrome/browser/media/webrtc/thumbnail_capturer_mac.mm
index 4f4baa9..b3a5e9b 100644
--- a/chrome/browser/media/webrtc/thumbnail_capturer_mac.mm
+++ b/chrome/browser/media/webrtc/thumbnail_capturer_mac.mm
@@ -27,6 +27,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/task/bind_post_task.h"
+#include "base/task/single_thread_task_runner.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/media/webrtc/delegated_source_list_capturer.h"
 #include "chrome/browser/media/webrtc/desktop_capturer_wrapper.h"
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_unittest.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager_unittest.cc
index 7f7061d..06e7b6a 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_manager_unittest.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_unittest.cc
@@ -311,10 +311,6 @@
 
     // Guard against unexpected state changes.
     EXPECT_TRUE(webrtc_state_change_instructions_.empty());
-
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS)
-    TestingBrowserProcess::GetGlobal()->ShutdownBrowserPolicyConnector();
-#endif
   }
 
   void SetUp() override {
@@ -328,6 +324,12 @@
 #endif
   }
 
+  void TearDown() override {
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS)
+    policy::BrowserPolicyConnectorBase::SetPolicyProviderForTesting(nullptr);
+#endif
+  }
+
   void SetUpNetworkConnection(bool respond_synchronously,
                               network::mojom::ConnectionType connection_type) {
     auto* tracker = network::TestNetworkConnectionTracker::GetInstance();
diff --git a/chrome/browser/metrics/structured/ash_structured_metrics_delegate.cc b/chrome/browser/metrics/structured/ash_structured_metrics_delegate.cc
index 69f927f2..b5f16dc 100644
--- a/chrome/browser/metrics/structured/ash_structured_metrics_delegate.cc
+++ b/chrome/browser/metrics/structured/ash_structured_metrics_delegate.cc
@@ -6,10 +6,7 @@
 
 #include <memory>
 
-#include "chrome/browser/ash/crosapi/crosapi_ash.h"
-#include "chrome/browser/ash/crosapi/crosapi_manager.h"
 #include "chromeos/ash/components/login/session/session_termination_manager.h"
-#include "chromeos/crosapi/mojom/structured_metrics_service.mojom.h"
 #include "chromeos/dbus/power/power_manager_client.h"
 #include "components/metrics/structured/event.h"
 #include "components/metrics/structured/histogram_util.h"
@@ -30,24 +27,14 @@
   }
 
   // Crosapi may not be initialized, in which case a pipe cannot be setup.
-  if (crosapi::CrosapiManager::IsInitialized()) {
-    crosapi::CrosapiManager::Get()->crosapi_ash()->BindStructuredMetricsService(
-        remote_.BindNewPipeAndPassReceiver());
-
-    key_events_observer_ = std::make_unique<StructuredMetricsKeyEventsObserver>(
-        user_manager::UserManager::Get(), ash::SessionTerminationManager::Get(),
-        chromeos::PowerManagerClient::Get());
-    is_initialized_ = true;
-  } else {
-    VLOG(2) << "Initialize() called before CrosApi is initialized.";
-  }
+  key_events_observer_ = std::make_unique<StructuredMetricsKeyEventsObserver>(
+      user_manager::UserManager::Get(), ash::SessionTerminationManager::Get(),
+      chromeos::PowerManagerClient::Get());
+  is_initialized_ = true;
 }
 
 void AshStructuredMetricsDelegate::RecordEvent(Event&& event) {
-  // It is OK not to check whether the remote is bound or not yet.
-  std::vector<Event> events;
-  events.emplace_back(std::move(event));
-  remote_->Record(std::move(events));
+  metrics::structured::Recorder::GetInstance()->RecordEvent(std::move(event));
 }
 
 bool AshStructuredMetricsDelegate::IsReadyToRecord() const {
diff --git a/chrome/browser/metrics/structured/ash_structured_metrics_delegate.h b/chrome/browser/metrics/structured/ash_structured_metrics_delegate.h
index b378e26..dd697ac 100644
--- a/chrome/browser/metrics/structured/ash_structured_metrics_delegate.h
+++ b/chrome/browser/metrics/structured/ash_structured_metrics_delegate.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_METRICS_STRUCTURED_ASH_STRUCTURED_METRICS_DELEGATE_H_
 
 #include "chrome/browser/metrics/structured/structured_metrics_key_events_observer.h"
-#include "chromeos/crosapi/mojom/structured_metrics_service.mojom.h"
 #include "components/metrics/structured/event.h"
 #include "components/metrics/structured/structured_metrics_client.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -28,8 +27,7 @@
       const AshStructuredMetricsDelegate& recorder) = delete;
   ~AshStructuredMetricsDelegate() override;
 
-  // Sets up the recorder. This should be called after CrosApi is initialized,
-  // which is done in PreProfileInit() of the browser process setup.
+  // Sets up the recorder.
   void Initialize();
 
   // RecordingDelegate:
@@ -37,7 +35,6 @@
   bool IsReadyToRecord() const override;
 
  private:
-  mojo::Remote<crosapi::mojom::StructuredMetricsService> remote_;
   std::unique_ptr<StructuredMetricsKeyEventsObserver> key_events_observer_;
   bool is_initialized_ = false;
 };
diff --git a/chrome/browser/ntp_tiles/ntp_tiles_browsertest.cc b/chrome/browser/ntp_tiles/ntp_tiles_browsertest.cc
index 9dab464..5a7f9df 100644
--- a/chrome/browser/ntp_tiles/ntp_tiles_browsertest.cc
+++ b/chrome/browser/ntp_tiles/ntp_tiles_browsertest.cc
@@ -64,6 +64,7 @@
   }
 
   void OnURLsAvailable(
+      bool is_user_triggered,
       const std::map<SectionType, NTPTilesVector>& sections) override {
     tiles_ = sections.at(SectionType::PERSONALIZED);
     if (quit_closure_) {
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
index fb945a4..37b6a5d0 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -2745,7 +2745,6 @@
 class SoftNavigationBrowserTest : public PageLoadMetricsBrowserTest {
  public:
   void TestSoftNavigation(bool wait_for_second_lcp) {
-    StartTracing();
     embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data");
     content::SetupCrossSiteRedirector(embedded_test_server());
     ASSERT_TRUE(embedded_test_server()->Start());
@@ -2830,72 +2829,6 @@
     // The histogram value represents the low end of the bucket, not the actual
     // value. Therefore it is lower or equal to the web exposed value.
     ASSERT_LE(lcp_value_bucket_start, lcp_start_before);
-
-    VerifyTraceEvents(StopTracing(), wait_for_second_lcp ? 3UL : 1UL);
-  }
-
- private:
-  void StartTracing() {
-    base::RunLoop wait_for_tracing;
-    content::TracingController::GetInstance()->StartTracing(
-        base::trace_event::TraceConfig(
-            "{\"included_categories\": [\"devtools.timeline\"]}"),
-        wait_for_tracing.QuitClosure());
-    wait_for_tracing.Run();
-  }
-
-  std::string StopTracing() {
-    base::RunLoop wait_for_tracing;
-    std::string trace_output;
-    content::TracingController::GetInstance()->StopTracing(
-        content::TracingController::CreateStringEndpoint(
-            base::BindLambdaForTesting(
-                [&](std::unique_ptr<std::string> trace_str) {
-                  trace_output = std::move(*trace_str);
-                  wait_for_tracing.Quit();
-                })));
-    wait_for_tracing.Run();
-    return trace_output;
-  }
-
-  void VerifyTraceEvents(const std::string& trace_str,
-                         size_t expected_event_number) {
-    std::unique_ptr<TraceAnalyzer> analyzer(TraceAnalyzer::Create(trace_str));
-    TraceEventVector events;
-    auto query =
-        Query::EventNameIs("SoftNavigationHeuristics_SoftNavigationDetected") ||
-        Query::EventNameIs("largestContentfulPaint::Candidate");
-    size_t num_events = analyzer->FindEvents(query, &events);
-    EXPECT_EQ(expected_event_number, num_events);
-
-    std::string previous_frame;
-    std::string navigation_id;
-    double soft_navigation_timestamp = 0.0;
-    for (auto* event : events) {
-      EXPECT_TRUE(event->HasStringArg("frame"));
-      std::string frame = event->GetKnownArgAsString("frame");
-      if (!previous_frame.empty()) {
-        EXPECT_EQ(frame, previous_frame);
-      }
-      previous_frame = frame;
-      if (event->name == "SoftNavigationHeuristics_SoftNavigationDetected") {
-        soft_navigation_timestamp = event->timestamp;
-        EXPECT_TRUE(event->HasStringArg("navigationId"));
-        navigation_id = event->GetKnownArgAsString("navigationId");
-      } else if (soft_navigation_timestamp > 0.0) {
-        EXPECT_LE(soft_navigation_timestamp, event->timestamp);
-        EXPECT_EQ(event->name, "largestContentfulPaint::Candidate");
-        base::Value::Dict data = event->GetKnownArgAsDict("data");
-        if (!navigation_id.empty()) {
-          EXPECT_EQ(navigation_id, *data.FindString("navigationId"));
-        }
-      }
-    }
-    // If we have more than one event, one of them needs to be a soft
-    // navigation.
-    if (expected_event_number > 1) {
-      EXPECT_TRUE(soft_navigation_timestamp > 0);
-    }
   }
 };
 
@@ -2904,8 +2837,7 @@
  public:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     PageLoadMetricsBrowserTest::SetUpCommandLine(command_line);
-    features_list_.InitWithFeatures({blink::features::kSoftNavigationHeuristics,
-                                     blink::features::kNavigationId},
+    features_list_.InitWithFeatures({blink::features::kSoftNavigationHeuristics},
                                     {});
   }
 
@@ -2913,15 +2845,12 @@
   base::test::ScopedFeatureList features_list_;
 };
 
-// TODO(crbug.com/341578843): Flaky on many platforms.
-IN_PROC_BROWSER_TEST_F(SoftNavigationBrowserTest, DISABLED_SoftNavigation) {
+IN_PROC_BROWSER_TEST_F(SoftNavigationBrowserTest, SoftNavigation) {
   TestSoftNavigation(/*wait_for_second_lcp=*/false);
 }
 
-// TODO(crbug.com/40946340): Flaky on several platforms.
 IN_PROC_BROWSER_TEST_F(
-    SoftNavigationBrowserTestWithSoftNavigationHeuristicsFlag,
-    DISABLED_SoftNavigation) {
+    SoftNavigationBrowserTestWithSoftNavigationHeuristicsFlag, SoftNavigation) {
   TestSoftNavigation(/*wait_for_second_lcp=*/true);
 }
 
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
index 0c4d03b..43522c18 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
@@ -184,9 +184,6 @@
     // Free the profile before we clear out the browser prefs.
     identity_test_env_adaptor_.reset();
     profile_.reset();
-    TestingBrowserProcess* testing_browser_process =
-        TestingBrowserProcess::GetGlobal();
-    testing_browser_process->ShutdownBrowserPolicyConnector();
     base::RunLoop run_loop;
     run_loop.RunUntilIdle();
   }
diff --git a/chrome/browser/policy/profile_policy_connector_unittest.cc b/chrome/browser/policy/profile_policy_connector_unittest.cc
index b6f5f96..d9096d4 100644
--- a/chrome/browser/policy/profile_policy_connector_unittest.cc
+++ b/chrome/browser/policy/profile_policy_connector_unittest.cc
@@ -157,7 +157,6 @@
     // it here to make sure the cleanup happens.
     BrowserPolicyConnectorBase::SetPolicyServiceForTesting(nullptr);
 
-    TestingBrowserProcess::GetGlobal()->ShutdownBrowserPolicyConnector();
     cloud_policy_manager_->Shutdown();
   }
 
diff --git a/chrome/browser/renderer_context_menu/link_to_text_menu_observer_interactive_uitest.cc b/chrome/browser/renderer_context_menu/link_to_text_menu_observer_interactive_uitest.cc
index 2e79bdb..14305c7 100644
--- a/chrome/browser/renderer_context_menu/link_to_text_menu_observer_interactive_uitest.cc
+++ b/chrome/browser/renderer_context_menu/link_to_text_menu_observer_interactive_uitest.cc
@@ -252,7 +252,14 @@
   EXPECT_EQ(u"http://foo.com/#:~:text=hello%20world", text);
 }
 
-IN_PROC_BROWSER_TEST_F(LinkToTextMenuObserverTest, CopiesLinkForEmptySelector) {
+// TODO(crbug.com/410751413): Flaky on Windows.
+#if BUILDFLAG(IS_WIN)
+#define MAYBE_CopiesLinkForEmptySelector DISABLED_CopiesLinkForEmptySelector
+#else
+#define MAYBE_CopiesLinkForEmptySelector CopiesLinkForEmptySelector
+#endif
+IN_PROC_BROWSER_TEST_F(LinkToTextMenuObserverTest,
+                       MAYBE_CopiesLinkForEmptySelector) {
   content::BrowserTestClipboardScope test_clipboard_scope;
   content::ContextMenuParams params;
   params.page_url = GURL("http://foo.com/");
@@ -375,8 +382,16 @@
       1);
 }
 
+// TODO(crbug.com/410751413): Flaky on Windows.
+#if BUILDFLAG(IS_WIN)
+#define MAYBE_LinkGenerationCopiedLinkTypeMetric_ReShare \
+  DISABLED_LinkGenerationCopiedLinkTypeMetric_ReShare
+#else
+#define MAYBE_LinkGenerationCopiedLinkTypeMetric_ReShare \
+  LinkGenerationCopiedLinkTypeMetric_ReShare
+#endif
 IN_PROC_BROWSER_TEST_F(LinkToTextMenuObserverTest,
-                       LinkGenerationCopiedLinkTypeMetric_ReShare) {
+                       MAYBE_LinkGenerationCopiedLinkTypeMetric_ReShare) {
   base::HistogramTester histogram_tester;
 
   content::BrowserTestClipboardScope test_clipboard_scope;
@@ -424,8 +439,16 @@
       "SharedHighlights.LinkGenerated.RequestedBeforeReady", 0);
 }
 
+// TODO(crbug.com/410751413): Flaky on Windows.
+#if BUILDFLAG(IS_WIN)
+#define MAYBE_LinkGenerationRequestedMetric_Success_WithDelay \
+  DISABLED_LinkGenerationRequestedMetric_Success_WithDelay
+#else
+#define MAYBE_LinkGenerationRequestedMetric_Success_WithDelay \
+  LinkGenerationRequestedMetric_Success_WithDelay
+#endif
 IN_PROC_BROWSER_TEST_F(LinkToTextMenuObserverTest,
-                       LinkGenerationRequestedMetric_Success_WithDelay) {
+                       MAYBE_LinkGenerationRequestedMetric_Success_WithDelay) {
   base::HistogramTester histogram_tester;
 
   content::BrowserTestClipboardScope test_clipboard_scope;
@@ -670,8 +693,15 @@
   EXPECT_TRUE(text.empty());
 }
 
+// TODO(crbug.com/410751413): Flaky on Windows.
+#if BUILDFLAG(IS_WIN)
+#define MAYBE_WarnsCopyingLinkToTextAndBypass \
+  DISABLED_WarnsCopyingLinkToTextAndBypass
+#else
+#define MAYBE_WarnsCopyingLinkToTextAndBypass WarnsCopyingLinkToTextAndBypass
+#endif
 IN_PROC_BROWSER_TEST_F(LinkToTextMenuObserverTest,
-                       WarnsCopyingLinkToTextAndBypass) {
+                       MAYBE_WarnsCopyingLinkToTextAndBypass) {
   data_controls::SetDataControls(browser()->profile()->GetPrefs(), {R"({
                                    "name": "rule_name",
                                    "rule_id": "rule_id",
@@ -756,8 +786,16 @@
   EXPECT_TRUE(browser()->GetFeatures().toast_controller()->IsShowingToast());
 }
 
+// TODO(crbug.com/410751413): Flaky on Windows.
+#if BUILDFLAG(IS_WIN)
+#define MAYBE_AddsRemoveMenuItemForGlicHighlight \
+  DISABLED_AddsRemoveMenuItemForGlicHighlight
+#else
+#define MAYBE_AddsRemoveMenuItemForGlicHighlight \
+  AddsRemoveMenuItemForGlicHighlight
+#endif
 IN_PROC_BROWSER_TEST_F(LinkToTextMenuObserverTest,
-                       AddsRemoveMenuItemForGlicHighlight) {
+                       MAYBE_AddsRemoveMenuItemForGlicHighlight) {
   content::ContextMenuParams params;
   params.page_url = GURL("http://foo.com/");
   params.annotation_type = blink::mojom::AnnotationType::kGlic;
diff --git a/chrome/browser/resources/ash/settings/os_settings_search_box/os_search_result_row.ts b/chrome/browser/resources/ash/settings/os_settings_search_box/os_search_result_row.ts
index a520076..f3a71e1d 100644
--- a/chrome/browser/resources/ash/settings/os_settings_search_box/os_search_result_row.ts
+++ b/chrome/browser/resources/ash/settings/os_settings_search_box/os_search_result_row.ts
@@ -811,6 +811,8 @@
         return 'os-settings:restore';
       case SearchResultIcon.kScanner:
         return 'os-settings:device-scan';
+      case SearchResultIcon.kScannerActions:
+        return 'os-settings:scanner';
       case SearchResultIcon.kSearch:
         return 'os-settings:explore';
       case SearchResultIcon.kSelectToSpeak:
diff --git a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/magnifier/magnifier_test.js b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/magnifier/magnifier_test.js
index b8ebec9..45d9ceb 100644
--- a/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/magnifier/magnifier_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/accessibility_common/mv3/magnifier/magnifier_test.js
@@ -435,27 +435,30 @@
       })();
     });
 
-TEST_F('MagnifierE2ETest', 'ScreenMagnifierChromeVoxFollowingPref', function() {
-  this.newCallback(async () => {
-    // Disable ChromeVox following for full screen magnifier, and
-    // verify prefs and state.
-    await this.setPref(
-        Magnifier.Prefs.SCREEN_MAGNIFIER_CHROMEVOX_FOCUS_FOLLOWING, false);
-    magnifier = accessibilityCommon.getMagnifierForTest();
-    magnifier.setIsInitializingForTest(false);
-    assertEquals(magnifier.type, Magnifier.Type.FULL_SCREEN);
-    assertFalse(magnifier.shouldFollowChromeVoxFocus());
+// TODO(crbug.com/417555323): Test is flaky.
+TEST_F(
+    'MagnifierE2ETest', 'DISABLED_ScreenMagnifierChromeVoxFollowingPref',
+    function() {
+      this.newCallback(async () => {
+        // Disable ChromeVox following for full screen magnifier, and
+        // verify prefs and state.
+        await this.setPref(
+            Magnifier.Prefs.SCREEN_MAGNIFIER_CHROMEVOX_FOCUS_FOLLOWING, false);
+        magnifier = accessibilityCommon.getMagnifierForTest();
+        magnifier.setIsInitializingForTest(false);
+        assertEquals(magnifier.type, Magnifier.Type.FULL_SCREEN);
+        assertFalse(magnifier.shouldFollowChromeVoxFocus());
 
-    // Enable ChromeVox following for full screen magnifier, and
-    // verify prefs and state.
-    await this.setPref(
-        Magnifier.Prefs.SCREEN_MAGNIFIER_CHROMEVOX_FOCUS_FOLLOWING, true);
-    magnifier = accessibilityCommon.getMagnifierForTest();
-    magnifier.setIsInitializingForTest(false);
-    assertEquals(magnifier.type, Magnifier.Type.FULL_SCREEN);
-    assertTrue(magnifier.shouldFollowChromeVoxFocus());
-  })();
-});
+        // Enable ChromeVox following for full screen magnifier, and
+        // verify prefs and state.
+        await this.setPref(
+            Magnifier.Prefs.SCREEN_MAGNIFIER_CHROMEVOX_FOCUS_FOLLOWING, true);
+        magnifier = accessibilityCommon.getMagnifierForTest();
+        magnifier.setIsInitializingForTest(false);
+        assertEquals(magnifier.type, Magnifier.Type.FULL_SCREEN);
+        assertTrue(magnifier.shouldFollowChromeVoxFocus());
+      })();
+    });
 
 // TODO(crbug.com/417555323): Test is flaky.
 TEST_F(
diff --git a/chrome/browser/resources/glic/glic_api/glic_api.ts b/chrome/browser/resources/glic/glic_api/glic_api.ts
index bc11911d..9fa8925 100644
--- a/chrome/browser/resources/glic/glic_api/glic_api.ts
+++ b/chrome/browser/resources/glic/glic_api/glic_api.ts
@@ -512,13 +512,6 @@
    */
   getZeroStateSuggestionsForFocusedTab?
       (is_first_run?: boolean): Promise<ZeroStateSuggestions>;
-
-  /**
-   * Called when the client believes that the user's status may have changed.
-   * For example, an RPC may have been rejected due to the the service being
-   * disabled.
-   */
-  maybeRefreshUserStatus?(): void;
 }
 /** Fields of interest from the system settings page. */
 export type OsPermissionType = 'media'|'geolocation';
diff --git a/chrome/browser/resources/glic/glic_api_impl/glic_api_client.ts b/chrome/browser/resources/glic/glic_api_impl/glic_api_client.ts
index ab9f767..8452e4c 100644
--- a/chrome/browser/resources/glic/glic_api_impl/glic_api_client.ts
+++ b/chrome/browser/resources/glic/glic_api_impl/glic_api_client.ts
@@ -259,10 +259,6 @@
       this.getClosedCaptioningSetting = undefined;
       this.setClosedCaptioningSetting = undefined;
     }
-
-    if (!state.enableMaybeRefreshUserStatus) {
-      this.maybeRefreshUserStatus = undefined;
-    }
   }
 
   webClientInitialized(
@@ -538,11 +534,6 @@
     this.sender.requestWithResponse(
         'glicBrowserDropScrollToHighlight', undefined);
   }
-
-  maybeRefreshUserStatus?(): void {
-    this.sender.requestNoResponse(
-        'glicBrowserMaybeRefreshUserStatus', undefined);
-  }
 }
 
 class GlicBrowserHostMetricsImpl implements GlicBrowserHostMetrics {
diff --git a/chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts b/chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts
index 01ed8fc0a..bc87479 100644
--- a/chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts
+++ b/chrome/browser/resources/glic/glic_api_impl/glic_api_host.ts
@@ -617,10 +617,6 @@
   glicBrowserDropScrollToHighlight(): void {
     this.handler.dropScrollToHighlight();
   }
-
-  glicBrowserMaybeRefreshUserStatus(): void {
-    this.handler.maybeRefreshUserStatus();
-  }
 }
 
 export class GlicApiHost implements PostMessageRequestHandler {
diff --git a/chrome/browser/resources/glic/glic_api_impl/request_types.ts b/chrome/browser/resources/glic/glic_api_impl/request_types.ts
index 311055d..b34ef03 100644
--- a/chrome/browser/resources/glic/glic_api_impl/request_types.ts
+++ b/chrome/browser/resources/glic/glic_api_impl/request_types.ts
@@ -212,7 +212,6 @@
       suggestions?: ZeroStateSuggestions,
     },
   };
-  glicBrowserMaybeRefreshUserStatus: {};
 }
 
 // Types of requests to the GlicWebClient.
@@ -341,7 +340,6 @@
     GetZeroStateSuggestionsForFocusedTab: 0,
     SetClosedCaptioningSetting: 0,
     DropScrollToHighlight: 0,
-    MaybeRefreshUserStatus: 0,
   };
   return apiRequestTypes;
   // LINT.ThenChange(//tools/metrics/histograms/metadata/glic/histograms.xml:ApiRequestType)
diff --git a/chrome/browser/resources/settings/settings_page/main_page_mixin.ts b/chrome/browser/resources/settings/settings_page/main_page_mixin.ts
index 6c5d4cb..9bf997210 100644
--- a/chrome/browser/resources/settings/settings_page/main_page_mixin.ts
+++ b/chrome/browser/resources/settings/settings_page/main_page_mixin.ts
@@ -362,6 +362,7 @@
               // sub-subpage entry point.
             } else if (newState === RouteState.TOP_LEVEL) {
               this.enterMainPage_(oldRoute!);
+              this.switchToSections_(TOP_LEVEL_EQUIVALENT_ROUTE);
             } else if (newState === RouteState.DIALOG) {
               // The only known cases currently for such a transition are from
               // 1) /synceSetup to /signOut
diff --git a/chrome/browser/safety_hub/android/java/src/org/chromium/chrome/browser/safety_hub/UnsubscribedNotificationsNotificationManager.java b/chrome/browser/safety_hub/android/java/src/org/chromium/chrome/browser/safety_hub/UnsubscribedNotificationsNotificationManager.java
index 1546061..81cd690 100644
--- a/chrome/browser/safety_hub/android/java/src/org/chromium/chrome/browser/safety_hub/UnsubscribedNotificationsNotificationManager.java
+++ b/chrome/browser/safety_hub/android/java/src/org/chromium/chrome/browser/safety_hub/UnsubscribedNotificationsNotificationManager.java
@@ -109,7 +109,10 @@
         Context context = ContextUtils.getApplicationContext();
         Resources res = context.getResources();
         String title =
-                res.getString(R.string.safety_hub_unsubscribed_notifications_notification_title);
+                res.getQuantityString(
+                        R.plurals.safety_hub_unsubscribed_notifications_notification_title,
+                        numRevokedPermissions,
+                        numRevokedPermissions);
         String contents =
                 res.getQuantityString(
                         R.plurals.safety_hub_unsubscribed_notifications_notification_message,
diff --git a/chrome/browser/safety_hub/android/junit/src/org/chromium/chrome/browser/safety_hub/UnsubscribedNotificationsNotificationManagerTest.java b/chrome/browser/safety_hub/android/junit/src/org/chromium/chrome/browser/safety_hub/UnsubscribedNotificationsNotificationManagerTest.java
index 219f597c..ff7c3a5 100644
--- a/chrome/browser/safety_hub/android/junit/src/org/chromium/chrome/browser/safety_hub/UnsubscribedNotificationsNotificationManagerTest.java
+++ b/chrome/browser/safety_hub/android/junit/src/org/chromium/chrome/browser/safety_hub/UnsubscribedNotificationsNotificationManagerTest.java
@@ -49,10 +49,10 @@
         assertEquals(1, notifications.size());
         Notification notification = notifications.get(0).notification;
         assertEquals(
-                "Chrome unsubscribed you from notifications",
+                "Unsubscribed from one unused site",
                 notification.extras.getString(Notification.EXTRA_TITLE));
         assertEquals(
-                "Removed notification permissions from one site you haven’t visited recently",
+                "Chrome stopped notifications from this site. You can review and manage.",
                 notification.extras.getString(Notification.EXTRA_TEXT));
         assertEquals("Review", notification.actions[0].title);
         assertNotNull(notification.actions[0].actionIntent);
@@ -68,10 +68,10 @@
         assertEquals(1, notifications.size());
         Notification notification = notifications.get(0).notification;
         assertEquals(
-                "Chrome unsubscribed you from notifications",
+                "Unsubscribed from 2 unused sites",
                 notification.extras.getString(Notification.EXTRA_TITLE));
         assertEquals(
-                "Removed notification permissions from 2 sites you haven’t visited recently",
+                "Chrome stopped notifications from these sites. You can review and manage.",
                 notification.extras.getString(Notification.EXTRA_TEXT));
     }
 
@@ -87,7 +87,10 @@
                 mMockNotificationManager.getNotifications();
         assertEquals(1, notifications.size());
         assertEquals(
-                "Removed notification permissions from one site you haven’t visited recently",
+                "Unsubscribed from one unused site",
+                notifications.get(0).notification.extras.getString(Notification.EXTRA_TITLE));
+        assertEquals(
+                "Chrome stopped notifications from this site. You can review and manage.",
                 notifications.get(0).notification.extras.getString(Notification.EXTRA_TEXT));
 
         UnsubscribedNotificationsNotificationManager.displayNotification(3);
@@ -95,7 +98,10 @@
                 mMockNotificationManager.getNotifications();
         assertEquals(1, notificationsAfter.size());
         assertEquals(
-                "Removed notification permissions from 3 sites you haven’t visited recently",
+                "Unsubscribed from 3 unused sites",
+                notificationsAfter.get(0).notification.extras.getString(Notification.EXTRA_TITLE));
+        assertEquals(
+                "Chrome stopped notifications from these sites. You can review and manage.",
                 notificationsAfter.get(0).notification.extras.getString(Notification.EXTRA_TEXT));
 
         assertThat(
@@ -121,10 +127,10 @@
                 mMockNotificationManager.getNotifications();
         assertEquals(1, notifications.size());
         assertEquals(
-                "Chrome unsubscribed you from notifications",
+                "Unsubscribed from one unused site",
                 notifications.get(0).notification.extras.getString(Notification.EXTRA_TITLE));
         assertEquals(
-                "Removed notification permissions from one site you haven’t visited recently",
+                "Chrome stopped notifications from this site. You can review and manage.",
                 notifications.get(0).notification.extras.getString(Notification.EXTRA_TEXT));
 
         UnsubscribedNotificationsNotificationManager.updateNotification(2);
@@ -132,10 +138,10 @@
                 mMockNotificationManager.getNotifications();
         assertEquals(1, notificationsAfter.size());
         assertEquals(
-                "Chrome unsubscribed you from notifications",
+                "Unsubscribed from 2 unused sites",
                 notificationsAfter.get(0).notification.extras.getString(Notification.EXTRA_TITLE));
         assertEquals(
-                "Removed notification permissions from 2 sites you haven’t visited recently",
+                "Chrome stopped notifications from these sites. You can review and manage.",
                 notificationsAfter.get(0).notification.extras.getString(Notification.EXTRA_TEXT));
 
         assertEquals(
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc
index e3296f0..d4b9566 100644
--- a/chrome/browser/search/instant_service.cc
+++ b/chrome/browser/search/instant_service.cc
@@ -192,6 +192,7 @@
 }
 
 void InstantService::OnURLsAvailable(
+    bool is_user_triggered,
     const std::map<ntp_tiles::SectionType, ntp_tiles::NTPTilesVector>&
         sections) {
   DCHECK(most_visited_sites_);
diff --git a/chrome/browser/search/instant_service.h b/chrome/browser/search/instant_service.h
index ab04cac2c..b6219d6 100644
--- a/chrome/browser/search/instant_service.h
+++ b/chrome/browser/search/instant_service.h
@@ -135,6 +135,7 @@
 
   // ntp_tiles::MostVisitedSites::Observer implementation.
   void OnURLsAvailable(
+      bool is_user_triggered,
       const std::map<ntp_tiles::SectionType, ntp_tiles::NTPTilesVector>&
           sections) override;
   void OnIconMadeAvailable(const GURL& site_url) override;
diff --git a/chrome/browser/search/instant_service_unittest.cc b/chrome/browser/search/instant_service_unittest.cc
index 9b0a735..934432c 100644
--- a/chrome/browser/search/instant_service_unittest.cc
+++ b/chrome/browser/search/instant_service_unittest.cc
@@ -58,7 +58,7 @@
   std::map<ntp_tiles::SectionType, ntp_tiles::NTPTilesVector> suggestions_map;
   suggestions_map[ntp_tiles::SectionType::PERSONALIZED] = suggestions;
 
-  instant_service_->OnURLsAvailable(suggestions_map);
+  instant_service_->OnURLsAvailable(false, suggestions_map);
 
   auto items = instant_service_->most_visited_info_->items;
   ASSERT_EQ(1, (int)items.size());
diff --git a/chrome/browser/sessions/session_restore.h b/chrome/browser/sessions/session_restore.h
index 7b65517..81ca3f0 100644
--- a/chrome/browser/sessions/session_restore.h
+++ b/chrome/browser/sessions/session_restore.h
@@ -14,7 +14,6 @@
 #include "base/gtest_prod_util.h"
 #include "base/observer_list.h"
 #include "chrome/browser/sessions/session_restore_observer.h"
-#include "components/history/core/browser/history_service.h"
 #include "components/sessions/core/session_types.h"
 #include "ui/base/window_open_disposition.h"
 
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsEntry.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsEntry.java
index cae57811..eba2121 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsEntry.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/LongScreenshotsEntry.java
@@ -10,6 +10,8 @@
 import androidx.annotation.IntDef;
 
 import org.chromium.base.Callback;
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.build.annotations.Nullable;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -26,15 +28,16 @@
  * the status of the generation. Upon receiving the BITMAP_GENERATED success code, callers can call
  * {@link getBitmap} to retrieve the generated bitmap.
  */
+@NullMarked
 public class LongScreenshotsEntry {
-    private final Rect mRect;
-    private BitmapGenerator mGenerator;
+    private final @Nullable Rect mRect;
+    private @Nullable BitmapGenerator mGenerator;
     private @EntryStatus int mCurrentStatus;
 
     // Generated bitmap
-    private Bitmap mGeneratedBitmap;
-    private EntryListener mEntryListener;
-    private final Callback<Integer> mMemoryTracker;
+    private @Nullable Bitmap mGeneratedBitmap;
+    private @Nullable EntryListener mEntryListener;
+    private final @Nullable Callback<Integer> mMemoryTracker;
 
     @IntDef({
         EntryStatus.UNKNOWN,
@@ -78,7 +81,9 @@
      * @param memoryTracker Callback to be notified of the entry's memory usage.
      */
     public LongScreenshotsEntry(
-            BitmapGenerator generator, Rect bounds, Callback<Integer> memoryTracker) {
+            @Nullable BitmapGenerator generator,
+            @Nullable Rect bounds,
+            @Nullable Callback<Integer> memoryTracker) {
         mRect = bounds;
         mGenerator = generator;
         mMemoryTracker = memoryTracker;
@@ -120,6 +125,7 @@
             return;
         }
         updateStatus(EntryStatus.BITMAP_GENERATION_IN_PROGRESS);
+        assert mRect != null;
         mGenerator.compositeBitmap(mRect, this::onBitmapGenerationError, this::onBitmapGenerated);
     }
 
@@ -135,7 +141,7 @@
      *         should only call this function after listening their EntryListener gets called with a
      *         status update.
      */
-    public Bitmap getBitmap() {
+    public @Nullable Bitmap getBitmap() {
         return mGeneratedBitmap;
     }
 
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetCoordinator.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetCoordinator.java
index edd65a89..d5d71a3 100644
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetCoordinator.java
+++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/screenshot/ScreenshotShareSheetCoordinator.java
@@ -7,6 +7,7 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 
+import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.share.share_sheet.ChromeOptionShareCallback;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.modelutil.PropertyKey;
@@ -17,6 +18,7 @@
 import java.util.Arrays;
 
 /** Coordinator for displaying the screenshot share sheet. */
+@NullMarked
 public class ScreenshotShareSheetCoordinator {
     private final ScreenshotShareSheetSaveDelegate mSaveDelegate;
     private final PropertyModel mModel;
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/EntryManagerTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/EntryManagerTest.java
index 19e897f..1879d1b 100644
--- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/EntryManagerTest.java
+++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/long_screenshots/bitmap_generation/EntryManagerTest.java
@@ -111,6 +111,7 @@
     /** Tests capture through to generation of the fullpage entry. */
     @Test
     public void testGenerateFullpageEntry() {
+        when(mBoundsManagerMock.getFullEntryBounds()).thenReturn(new Rect(0, 100, 0, 100));
         mProcessor.processCapturedTab(FAKE_CAPTURE_ADDR, Status.OK);
         mOnCompositorResultCallback.onResult(CompositorStatus.OK);
         mInOrder.verify(mObserverMock).onStatusChange(eq(EntryStatus.CAPTURE_COMPLETE));
diff --git a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninManager.java b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninManager.java
index 2529cd7..23b56c3 100644
--- a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninManager.java
+++ b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninManager.java
@@ -199,7 +199,7 @@
     /**
      * Returns the management domain if the signed in account is managed, otherwise returns null.
      */
-    String getManagementDomain();
+    @Nullable String getManagementDomain();
 
     /**
      * Verifies if the account is managed. Callback may be called either synchronously or
diff --git a/chrome/browser/sync/BUILD.gn b/chrome/browser/sync/BUILD.gn
index c5bd44a..e88d12e 100644
--- a/chrome/browser/sync/BUILD.gn
+++ b/chrome/browser/sync/BUILD.gn
@@ -161,10 +161,6 @@
     ]
   } else {
     sources += [
-      "glue/extension_data_type_controller.cc",
-      "glue/extension_data_type_controller.h",
-      "glue/extension_setting_data_type_controller.cc",
-      "glue/extension_setting_data_type_controller.h",
       "sessions/browser_list_router_helper.cc",
       "sessions/browser_list_router_helper.h",
     ]
@@ -174,19 +170,28 @@
     ]
     deps += [
       "//chrome/browser/accessibility/tree_fixing:prefs",
-      "//chrome/browser/themes",
       "//chrome/browser/ui/tabs:tab_strip",
+    ]
+  }
+  if (enable_extensions_core) {
+    sources += [
+      "glue/extension_data_type_controller.cc",
+      "glue/extension_data_type_controller.h",
+      "glue/extension_setting_data_type_controller.cc",
+      "glue/extension_setting_data_type_controller.h",
+    ]
+    public_deps += [ "//extensions/buildflags" ]
+    deps += [
+      "//extensions/browser",
+      "//extensions/browser/api/storage",
+      "//extensions/common",
+    ]
+  }
+  if (enable_extensions) {
+    deps += [
+      "//chrome/browser/themes",
       "//chrome/browser/web_applications",
     ]
-
-    if (enable_extensions) {
-      public_deps += [ "//extensions/buildflags" ]
-      deps += [
-        "//extensions/browser",
-        "//extensions/browser/api/storage",
-        "//extensions/common",
-      ]
-    }
   }
   if (is_chromeos) {
     sources += [
diff --git a/chrome/browser/sync/chrome_sync_controller_builder.cc b/chrome/browser/sync/chrome_sync_controller_builder.cc
index 78c3800..b6147b2 100644
--- a/chrome/browser/sync/chrome_sync_controller_builder.cc
+++ b/chrome/browser/sync/chrome_sync_controller_builder.cc
@@ -34,11 +34,14 @@
 #include "components/sync/service/syncable_service_based_data_type_controller.h"
 #include "content/public/browser/browser_thread.h"
 
-#if BUILDFLAG(ENABLE_EXTENSIONS)
+#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
 #include "chrome/browser/extensions/api/storage/settings_sync_util.h"  // nogncheck
-#include "chrome/browser/extensions/extension_sync_service.h"
+#include "chrome/browser/extensions/extension_sync_service.h"  // nogncheck
 #include "chrome/browser/sync/glue/extension_data_type_controller.h"
 #include "chrome/browser/sync/glue/extension_setting_data_type_controller.h"
+#endif
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
 #include "chrome/browser/web_applications/web_app_utils.h"
@@ -79,7 +82,7 @@
   security_event_recorder_.Set(security_event_recorder);
 }
 
-#if BUILDFLAG(ENABLE_EXTENSIONS)
+#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
 void ChromeSyncControllerBuilder::SetExtensionSyncService(
     ExtensionSyncService* extension_sync_service) {
   extension_sync_service_.Set(extension_sync_service);
@@ -88,7 +91,9 @@
 void ChromeSyncControllerBuilder::SetExtensionSystemProfile(Profile* profile) {
   extension_system_profile_.Set(profile);
 }
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS_CORE)
 
+#if BUILDFLAG(ENABLE_EXTENSIONS)
 void ChromeSyncControllerBuilder::SetThemeService(ThemeService* theme_service) {
   theme_service_.Set(theme_service);
 }
@@ -186,7 +191,7 @@
         std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
             security_events_delegate)));
 
-#if BUILDFLAG(ENABLE_EXTENSIONS)
+#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
     if (extension_sync_service_.value()) {
       controllers.push_back(
           std::make_unique<browser_sync::ExtensionDataTypeController>(
@@ -206,7 +211,11 @@
               browser_sync::ExtensionSettingDataTypeController::DelegateMode::
                   kTransportModeWithSingleModel,
               extension_system_profile_.value()));
+    }
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS_CORE)
 
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+    if (extension_sync_service_.value()) {
       controllers.push_back(
           std::make_unique<browser_sync::ExtensionDataTypeController>(
               syncer::APPS, data_type_store_factory,
diff --git a/chrome/browser/sync/chrome_sync_controller_builder.h b/chrome/browser/sync/chrome_sync_controller_builder.h
index 6c4c1b3..e8c7c902 100644
--- a/chrome/browser/sync/chrome_sync_controller_builder.h
+++ b/chrome/browser/sync/chrome_sync_controller_builder.h
@@ -31,8 +31,11 @@
 class WebApkSyncService;
 }  // namespace webapk
 
-#if BUILDFLAG(ENABLE_EXTENSIONS)
+#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
 class ExtensionSyncService;
+#endif
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
 class ThemeService;
 
 namespace web_app {
@@ -98,9 +101,12 @@
       syncer::DataTypeStoreService* data_type_store_service);
   void SetSecurityEventRecorder(SecurityEventRecorder* security_event_recorder);
 
-#if BUILDFLAG(ENABLE_EXTENSIONS)
+#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
   void SetExtensionSyncService(ExtensionSyncService* extension_sync_service);
   void SetExtensionSystemProfile(Profile* profile);
+#endif
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
   void SetThemeService(ThemeService* theme_service);
   void SetWebAppProvider(web_app::WebAppProvider* web_app_provider);
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
@@ -169,12 +175,15 @@
   SafeOptional<raw_ptr<syncer::DataTypeStoreService>> data_type_store_service_;
   SafeOptional<raw_ptr<SecurityEventRecorder>> security_event_recorder_;
 
-#if BUILDFLAG(ENABLE_EXTENSIONS)
+#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
   SafeOptional<raw_ptr<ExtensionSyncService>> extension_sync_service_;
   // This Profile instance has nothing special and is just the profile being
   // exercised by the factory. A more tailored name is used simply to limit its
   // usage beyond extensions.
   SafeOptional<raw_ptr<Profile>> extension_system_profile_;
+#endif
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
   SafeOptional<raw_ptr<ThemeService>> theme_service_;
   SafeOptional<raw_ptr<web_app::WebAppProvider>> web_app_provider_;
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/sync/glue/extension_data_type_controller.h b/chrome/browser/sync/glue/extension_data_type_controller.h
index d6d86b2..09a3247a 100644
--- a/chrome/browser/sync/glue/extension_data_type_controller.h
+++ b/chrome/browser/sync/glue/extension_data_type_controller.h
@@ -8,6 +8,9 @@
 #include "base/functional/callback_forward.h"
 #include "base/memory/raw_ptr.h"
 #include "components/sync/service/syncable_service_based_data_type_controller.h"
+#include "extensions/buildflags/buildflags.h"
+
+static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE));
 
 class Profile;
 
diff --git a/chrome/browser/sync/glue/extension_setting_data_type_controller.h b/chrome/browser/sync/glue/extension_setting_data_type_controller.h
index 48a8e52..6395f5fa 100644
--- a/chrome/browser/sync/glue/extension_setting_data_type_controller.h
+++ b/chrome/browser/sync/glue/extension_setting_data_type_controller.h
@@ -8,6 +8,9 @@
 #include "base/functional/callback_forward.h"
 #include "base/memory/raw_ptr.h"
 #include "components/sync/service/non_ui_syncable_service_based_data_type_controller.h"
+#include "extensions/buildflags/buildflags.h"
+
+static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE));
 
 class Profile;
 
diff --git a/chrome/browser/sync/sync_service_factory.cc b/chrome/browser/sync/sync_service_factory.cc
index 44d81d15..b0f91aef 100644
--- a/chrome/browser/sync/sync_service_factory.cc
+++ b/chrome/browser/sync/sync_service_factory.cc
@@ -88,14 +88,17 @@
 #include "extensions/buildflags/buildflags.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
+#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
+#include "chrome/browser/extensions/extension_sync_service.h"  // nogncheck
+#include "extensions/browser/api/storage/storage_frontend.h"   // nogncheck
+#include "extensions/browser/extension_system_provider.h"      // nogncheck
+#include "extensions/browser/extensions_browser_client.h"      // nogncheck
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS_CORE)
+
 #if BUILDFLAG(ENABLE_EXTENSIONS)
-#include "chrome/browser/extensions/extension_sync_service.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/browser/web_applications/web_app_provider_factory.h"
 #include "chrome/browser/web_applications/web_app_utils.h"
-#include "extensions/browser/api/storage/storage_frontend.h"  // nogncheck
-#include "extensions/browser/extension_system_provider.h"     // nogncheck
-#include "extensions/browser/extensions_browser_client.h"     // nogncheck
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 
 #if BUILDFLAG(IS_CHROMEOS)
@@ -281,9 +284,12 @@
   builder.SetSecurityEventRecorder(
       SecurityEventRecorderFactory::GetForProfile(profile));
 
-#if BUILDFLAG(ENABLE_EXTENSIONS)
+#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
   builder.SetExtensionSyncService(ExtensionSyncService::Get(profile));
   builder.SetExtensionSystemProfile(profile);
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS_CORE)
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
   builder.SetThemeService(ThemeServiceFactory::GetForProfile(profile));
   builder.SetWebAppProvider(
       web_app::AreWebAppsEnabled(profile)
@@ -563,12 +569,16 @@
 #endif  // BUILDFLAG(IS_ANDROID)
   DependsOn(WebDataServiceFactory::GetInstance());
 
-#if BUILDFLAG(ENABLE_EXTENSIONS)
+#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
   DependsOn(
       extensions::ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
   DependsOn(extensions::StorageFrontend::GetFactoryInstance());
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS_CORE)
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
   DependsOn(web_app::WebAppProviderFactory::GetInstance());
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
+
 #if BUILDFLAG(IS_CHROMEOS)
   DependsOn(app_list::AppListSyncableServiceFactory::GetInstance());
   DependsOn(
diff --git a/chrome/browser/sync/sync_service_factory_unittest.cc b/chrome/browser/sync/sync_service_factory_unittest.cc
index 0ad27fff..cae43da 100644
--- a/chrome/browser/sync/sync_service_factory_unittest.cc
+++ b/chrome/browser/sync/sync_service_factory_unittest.cc
@@ -119,10 +119,13 @@
     datatypes.Put(syncer::SECURITY_EVENTS);
     datatypes.Put(syncer::SUPERVISED_USER_SETTINGS);
 
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-    datatypes.Put(syncer::APPS);
+#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
     datatypes.Put(syncer::EXTENSIONS);
     datatypes.Put(syncer::EXTENSION_SETTINGS);
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS_CORE)
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+    datatypes.Put(syncer::APPS);
     datatypes.Put(syncer::APP_SETTINGS);
     datatypes.Put(syncer::WEB_APPS);
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 3bb1657a..f762243dd 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -1959,12 +1959,14 @@
         other {Chrome found # reused passwords that you could improve}}
       </message>
       <message name="IDS_SAFETY_HUB_UNSUBSCRIBED_NOTIFICATIONS_NOTIFICATION_TITLE" desc="Title for the notification sent from Safety Hub for telling the user that some notifications have been unsubscribed.">
-        Chrome unsubscribed you from notifications
+        {NUM_REVOKED_PERMISSIONS, plural,
+        =1 {Unsubscribed from one unused site}
+        other {Unsubscribed from # unused sites}}
       </message>
       <message name="IDS_SAFETY_HUB_UNSUBSCRIBED_NOTIFICATIONS_NOTIFICATION_MESSAGE" desc="Message for the notification sent from Safety Hub for telling the user that some notifications have been unsubscribed.">
         {NUM_REVOKED_PERMISSIONS, plural,
-        =1 {Removed notification permissions from one site you haven’t visited recently}
-        other {Removed notification permissions from # sites you haven’t visited recently}}
+        =1 {Chrome stopped notifications from this site. You can review and manage.}
+        other {Chrome stopped notifications from these sites. You can review and manage.}}
       </message>
       <message name="IDS_SAFETY_HUB_UNSUBSCRIBED_NOTIFICATIONS_NOTIFICATION_ACK" desc="Button to acknowledge the notification sent from Safety Hub for telling the user that some notifications have been unsubscribed.">
         Got it
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SAFETY_HUB_UNSUBSCRIBED_NOTIFICATIONS_NOTIFICATION_MESSAGE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SAFETY_HUB_UNSUBSCRIBED_NOTIFICATIONS_NOTIFICATION_MESSAGE.png.sha1
index 9b924a7..fa15dd0 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SAFETY_HUB_UNSUBSCRIBED_NOTIFICATIONS_NOTIFICATION_MESSAGE.png.sha1
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SAFETY_HUB_UNSUBSCRIBED_NOTIFICATIONS_NOTIFICATION_MESSAGE.png.sha1
@@ -1 +1 @@
-a8c910db1ae65cf9e830d0369dfe3ac8cab3c5c4
\ No newline at end of file
+fd867c4b1c87d3170256e30f0e22824fa1763854
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SAFETY_HUB_UNSUBSCRIBED_NOTIFICATIONS_NOTIFICATION_TITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SAFETY_HUB_UNSUBSCRIBED_NOTIFICATIONS_NOTIFICATION_TITLE.png.sha1
index 9b924a7..fa15dd0 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SAFETY_HUB_UNSUBSCRIBED_NOTIFICATIONS_NOTIFICATION_TITLE.png.sha1
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_SAFETY_HUB_UNSUBSCRIBED_NOTIFICATIONS_NOTIFICATION_TITLE.png.sha1
@@ -1 +1 @@
-a8c910db1ae65cf9e830d0369dfe3ac8cab3c5c4
\ No newline at end of file
+fd867c4b1c87d3170256e30f0e22824fa1763854
\ No newline at end of file
diff --git a/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/TopUiThemeColorProvider.java b/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/TopUiThemeColorProvider.java
index 8dcdf0a8..3d6ac63 100644
--- a/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/TopUiThemeColorProvider.java
+++ b/chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/theme/TopUiThemeColorProvider.java
@@ -89,7 +89,7 @@
      * @return Theme color or the given fallback color if the default color is
      *         used or there is no current tab.
      */
-    public int getThemeColorOrFallback(Tab tab, int fallbackColor) {
+    public int getThemeColorOrFallback(@Nullable Tab tab, int fallbackColor) {
         return (tab == null || mIsDefaultColorUsed) ? fallbackColor : getThemeColor();
     }
 
diff --git a/chrome/browser/ui/ash/quick_answers/ui/quick_answers_pixeltest.cc b/chrome/browser/ui/ash/quick_answers/ui/quick_answers_pixeltest.cc
index d1981d099..1479e01 100644
--- a/chrome/browser/ui/ash/quick_answers/ui/quick_answers_pixeltest.cc
+++ b/chrome/browser/ui/ash/quick_answers/ui/quick_answers_pixeltest.cc
@@ -370,7 +370,6 @@
   structured_result.definition_result->phonetics_info.query_text = kTestQuery;
   structured_result.definition_result->phonetics_info.phonetics_audio =
       GURL(kTestPhoneticsUrl);
-  structured_result.definition_result->phonetics_info.tts_audio_enabled = true;
   GetQuickAnswersUiController()->RenderQuickAnswersViewWithResult(
       structured_result);
 
@@ -526,7 +525,6 @@
   structured_result.definition_result->phonetics_info.query_text = kTestQuery;
   structured_result.definition_result->phonetics_info.phonetics_audio =
       GURL(kTestPhoneticsUrl);
-  structured_result.definition_result->phonetics_info.tts_audio_enabled = true;
   GetQuickAnswersUiController()->RenderQuickAnswersViewWithResult(
       structured_result);
 
diff --git a/chrome/browser/ui/ash/quick_answers/ui/quick_answers_view.cc b/chrome/browser/ui/ash/quick_answers/ui/quick_answers_view.cc
index 832511b..c8c8ce00 100644
--- a/chrome/browser/ui/ash/quick_answers/ui/quick_answers_view.cc
+++ b/chrome/browser/ui/ash/quick_answers/ui/quick_answers_view.cc
@@ -627,14 +627,14 @@
   SwitchTo(retry_view_);
 }
 
-bool QuickAnswersView::ShouldAddPhoneticsAudioButton(ResultType result_type,
-                                                     GURL phonetics_audio,
-                                                     bool tts_audio_enabled) {
+bool QuickAnswersView::ShouldAddPhoneticsAudioButton(
+    ResultType result_type,
+    const quick_answers::PhoneticsInfo& phonetics_info) {
   if (result_type != ResultType::kDefinitionResult) {
     return false;
   }
 
-  return !phonetics_audio.is_empty() || tts_audio_enabled;
+  return phonetics_info.PhoneticsInfoAvailable();
 }
 
 void QuickAnswersView::SetMockGenerateTtsCallbackForTesting(
diff --git a/chrome/browser/ui/ash/quick_answers/ui/quick_answers_view.h b/chrome/browser/ui/ash/quick_answers/ui/quick_answers_view.h
index 19000c27..631cb30 100644
--- a/chrome/browser/ui/ash/quick_answers/ui/quick_answers_view.h
+++ b/chrome/browser/ui/ash/quick_answers/ui/quick_answers_view.h
@@ -109,9 +109,9 @@
  private:
   bool HasFocusInside();
   void AddFrameButtons();
-  bool ShouldAddPhoneticsAudioButton(ResultType result_type,
-                                     GURL phonetics_audio,
-                                     bool tts_audio_enabled);
+  bool ShouldAddPhoneticsAudioButton(
+      ResultType result_type,
+      const quick_answers::PhoneticsInfo& phonetics_info);
   void AddPhoneticsAudioButton(
       const quick_answers::PhoneticsInfo& phonetics_info,
       View* container);
diff --git a/chrome/browser/ui/ash/quick_answers/ui/quick_answers_view_unittest.cc b/chrome/browser/ui/ash/quick_answers/ui/quick_answers_view_unittest.cc
index b421885..52ff916c 100644
--- a/chrome/browser/ui/ash/quick_answers/ui/quick_answers_view_unittest.cc
+++ b/chrome/browser/ui/ash/quick_answers/ui/quick_answers_view_unittest.cc
@@ -355,7 +355,6 @@
   definition_result.phonetics_info.query_text = kPhoneticsInfoQueryText;
   definition_result.phonetics_info.phonetics_audio =
       GURL(kPhoneticsInfoAudioUrl);
-  definition_result.phonetics_info.tts_audio_enabled = true;
   SendResult(definition_result);
 
   ResultView* result_view = GetQuickAnswersView()->GetResultViewForTesting();
@@ -523,7 +522,6 @@
   definition_result.phonetics_info.query_text = kPhoneticsInfoQueryText;
   definition_result.phonetics_info.phonetics_audio =
       GURL(kPhoneticsInfoAudioUrl);
-  definition_result.phonetics_info.tts_audio_enabled = true;
   SendResult(definition_result);
 
   ResultView* result_view = GetQuickAnswersView()->GetResultViewForTesting();
@@ -626,7 +624,6 @@
   definition_result.phonetics_info.query_text = kPhoneticsInfoQueryText;
   definition_result.phonetics_info.phonetics_audio =
       GURL(kPhoneticsInfoAudioUrl);
-  definition_result.phonetics_info.tts_audio_enabled = true;
   SendResult(definition_result);
 
   EXPECT_EQ(GetQuickAnswersView()->GetAccessibleDescription(),
@@ -648,7 +645,6 @@
   definition_result.phonetics_info.query_text = kPhoneticsInfoQueryText;
   definition_result.phonetics_info.phonetics_audio =
       GURL(kPhoneticsInfoAudioUrl);
-  definition_result.phonetics_info.tts_audio_enabled = true;
   SendResult(definition_result);
 
   EXPECT_EQ(GetQuickAnswersView()->GetAccessibleDescription(),
diff --git a/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.cc b/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.cc
index fae6e91e..9ad20ea 100644
--- a/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.cc
+++ b/chrome/browser/ui/autofill/payments/chrome_payments_autofill_client.cc
@@ -920,6 +920,7 @@
 #endif
 }
 
+// TODO(crbug.com/423866731): Add unit tests for this method.
 bool ChromePaymentsAutofillClient::ShowTouchToFillLoyaltyCard(
     base::WeakPtr<TouchToFillDelegate> delegate,
     std::vector<autofill::LoyaltyCard> loyalty_cards_to_suggest) {
@@ -941,10 +942,15 @@
       tracker->WouldTriggerHelpUI(
           feature_engagement::kIPHAutofillEnableLoyaltyCardsFeature);
 
-  return GetTouchToFillPaymentMethodController()->ShowLoyaltyCards(
-      std::make_unique<TouchToFillPaymentMethodViewImpl>(web_contents()),
-      delegate, std::move(affiliated_loyalty_cards),
-      std::move(loyalty_cards_to_suggest), first_time_usage);
+  const bool loyalty_cards_shown =
+      GetTouchToFillPaymentMethodController()->ShowLoyaltyCards(
+          std::make_unique<TouchToFillPaymentMethodViewImpl>(web_contents()),
+          delegate, std::move(affiliated_loyalty_cards),
+          std::move(loyalty_cards_to_suggest), first_time_usage);
+  if (first_time_usage && loyalty_cards_shown) {
+    tracker->NotifyEvent("keyboard_accessory_loyalty_cards_autofilled");
+  }
+  return loyalty_cards_shown;
 #else
   // Touch To Fill is not supported on Desktop.
   NOTREACHED();
diff --git a/chrome/browser/ui/browser_navigator_params.cc b/chrome/browser/ui/browser_navigator_params.cc
index 1b4cad0..c0f3bd4 100644
--- a/chrome/browser/ui/browser_navigator_params.cc
+++ b/chrome/browser/ui/browser_navigator_params.cc
@@ -76,7 +76,7 @@
   this->should_replace_current_entry = params.should_replace_current_entry;
   this->post_data = params.post_data;
   this->started_from_context_menu = params.started_from_context_menu;
-  this->open_pwa_window_if_possible = params.open_app_window_if_possible;
+  this->is_service_worker_open_window = params.is_service_worker_open_window;
   this->user_gesture = params.user_gesture;
   this->blob_url_loader_factory = params.blob_url_loader_factory;
   this->href_translate = params.href_translate;
diff --git a/chrome/browser/ui/browser_navigator_params.h b/chrome/browser/ui/browser_navigator_params.h
index 262d8602..e8e7297 100644
--- a/chrome/browser/ui/browser_navigator_params.h
+++ b/chrome/browser/ui/browser_navigator_params.h
@@ -316,9 +316,9 @@
   // Optional URLLoaderFactory to facilitate blob URL loading.
   scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory;
 
-  // Indicates that the navigation should happen in an pwa window if
-  // possible, i.e. if the is a PWA installed for the target URL.
-  bool open_pwa_window_if_possible = false;
+  // Indicates that this is a service worker openWindow() call targeting a new
+  // window.
+  bool is_service_worker_open_window = false;
 
   // The time when the input which led to the navigation occurred. Currently
   // only set when a link is clicked or the navigation takes place from the
diff --git a/chrome/browser/ui/browser_window/desktop_browser_window_capabilities.cc b/chrome/browser/ui/browser_window/desktop_browser_window_capabilities.cc
index 0b42d3d..f3f47345 100644
--- a/chrome/browser/ui/browser_window/desktop_browser_window_capabilities.cc
+++ b/chrome/browser/ui/browser_window/desktop_browser_window_capabilities.cc
@@ -41,3 +41,9 @@
 bool DesktopBrowserWindowCapabilities::IsAttemptingToCloseBrowser() const {
   return delegate_->IsAttemptingToCloseBrowser();
 }
+
+void DesktopBrowserWindowCapabilities::SetWebContentsBlocked(
+    content::WebContents* web_contents,
+    bool blocked) {
+  return delegate_->SetWebContentsBlocked(web_contents, blocked);
+}
diff --git a/chrome/browser/ui/browser_window/public/browser_window_interface.h b/chrome/browser/ui/browser_window/public/browser_window_interface.h
index 012e2c4..b9499d4 100644
--- a/chrome/browser/ui/browser_window/public/browser_window_interface.h
+++ b/chrome/browser/ui/browser_window/public/browser_window_interface.h
@@ -274,17 +274,6 @@
   // incremental migration.
   virtual Browser* GetBrowserForMigrationOnly() = 0;
 
-  // Changes the blocked state of |web_contents|. WebContentses are considered
-  // blocked while displaying a web contents modal dialog. During that time
-  // renderer host will ignore any UI interaction within WebContents outside of
-  // the currently displaying dialog.
-  // Note that this is a duplicate of the same method in
-  // WebContentsModalDialogManagerDelegate. This is because there are two ways
-  // to open tab-modal dialogs, either via TabDialogManager or via
-  // //components/web_modal. See crbug.com/377820808.
-  virtual void SetWebContentsBlocked(content::WebContents* web_contents,
-                                     bool blocked) = 0;
-
   // Checks if the browser popup is tab modal dialog.
   virtual bool IsTabModalPopupDeprecated() const = 0;
 
diff --git a/chrome/browser/ui/browser_window/public/desktop_browser_window_capabilities.h b/chrome/browser/ui/browser_window/public/desktop_browser_window_capabilities.h
index 8fbbf3b6..a86313a8c 100644
--- a/chrome/browser/ui/browser_window/public/desktop_browser_window_capabilities.h
+++ b/chrome/browser/ui/browser_window/public/desktop_browser_window_capabilities.h
@@ -13,6 +13,10 @@
 class DesktopBrowserWindowCapabilitiesDelegate;
 class UnownedUserDataHost;
 
+namespace content {
+class WebContents;
+}
+
 // A collection of capabilities related to desktop browser windows. Most
 // functionality should go on this class, rather than being exposed on
 // BrowserWindowInterface.
@@ -37,6 +41,16 @@
   // See Browser::IsAttemptingToCloseBrowser() for more details.
   bool IsAttemptingToCloseBrowser() const;
 
+  // Changes the blocked state of |web_contents|. WebContentses are considered
+  // blocked while displaying a web contents modal dialog. During that time
+  // renderer host will ignore any UI interaction within WebContents outside of
+  // the currently displaying dialog.
+  // Note that this is a duplicate of the same method in
+  // WebContentsModalDialogManagerDelegate. This is because there are two ways
+  // to open tab-modal dialogs, either via TabDialogManager or via
+  // //components/web_modal. See crbug.com/377820808.
+  void SetWebContentsBlocked(content::WebContents* web_contents, bool blocked);
+
  private:
   // The associated delegate. Must outlive this class.
   raw_ptr<DesktopBrowserWindowCapabilitiesDelegate> delegate_ = nullptr;
diff --git a/chrome/browser/ui/browser_window/public/desktop_browser_window_capabilities_delegate.h b/chrome/browser/ui/browser_window/public/desktop_browser_window_capabilities_delegate.h
index 535e89b7..2d57fe85 100644
--- a/chrome/browser/ui/browser_window/public/desktop_browser_window_capabilities_delegate.h
+++ b/chrome/browser/ui/browser_window/public/desktop_browser_window_capabilities_delegate.h
@@ -5,11 +5,17 @@
 #ifndef CHROME_BROWSER_UI_BROWSER_WINDOW_PUBLIC_DESKTOP_BROWSER_WINDOW_CAPABILITIES_DELEGATE_H_
 #define CHROME_BROWSER_UI_BROWSER_WINDOW_PUBLIC_DESKTOP_BROWSER_WINDOW_CAPABILITIES_DELEGATE_H_
 
+namespace content {
+class WebContents;
+}
+
 class DesktopBrowserWindowCapabilitiesDelegate {
  public:
   // These mirror the DesktopBrowserWindowCapabilities functions of the same
   // name.
   virtual bool IsAttemptingToCloseBrowser() const = 0;
+  virtual void SetWebContentsBlocked(content::WebContents* web_contents,
+                                     bool blocked) = 0;
 };
 
 #endif  // CHROME_BROWSER_UI_BROWSER_WINDOW_PUBLIC_DESKTOP_BROWSER_WINDOW_CAPABILITIES_DELEGATE_H_
diff --git a/chrome/browser/ui/browser_window/test/mock_browser_window_interface.h b/chrome/browser/ui/browser_window/test/mock_browser_window_interface.h
index 13107d59..b707d4d 100644
--- a/chrome/browser/ui/browser_window/test/mock_browser_window_interface.h
+++ b/chrome/browser/ui/browser_window/test/mock_browser_window_interface.h
@@ -80,10 +80,6 @@
               (),
               (override));
   MOCK_METHOD(Browser*, GetBrowserForMigrationOnly, (), (override));
-  MOCK_METHOD(void,
-              SetWebContentsBlocked,
-              (content::WebContents*, bool),
-              (override));
   MOCK_METHOD(bool, IsTabModalPopupDeprecated, (), (const, override));
   MOCK_METHOD(ui::BaseWindow*, GetWindow, (), (override));
   MOCK_METHOD(DesktopBrowserWindowCapabilities*, capabilities, (), (override));
diff --git a/chrome/browser/ui/passwords/password_change_ui_controller.cc b/chrome/browser/ui/passwords/password_change_ui_controller.cc
index a999039..db6c434 100644
--- a/chrome/browser/ui/passwords/password_change_ui_controller.cc
+++ b/chrome/browser/ui/passwords/password_change_ui_controller.cc
@@ -43,7 +43,9 @@
     bool with_privacy_notice,
     std::u16string email) {
   ui::DialogModelLabel::TextReplacement link = ui::DialogModelLabel::CreateLink(
-      IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_SETTINGS_LINK,
+      with_privacy_notice
+          ? IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_DIALOG_LINK_WITH_PRIVACY_NOTICE
+          : IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_DIALOG_LINK_WITHOUT_PRIVACY_NOTICE,
       std::move(navigate_to_settings_callback));
 
   ui::DialogModel::Builder dialog_builder;
@@ -53,10 +55,10 @@
   dialog_builder.SetIcon(
       ui::ImageModel::FromVectorIcon(GooglePasswordManagerVectorIcon()));
   dialog_builder.SetTitle(l10n_util::GetStringUTF16(
-      IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_BUBBLE_TITLE));
+      IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_DIALOG_TITLE));
   dialog_builder.AddParagraph(ui::DialogModelLabel::CreateWithReplacements(
-      IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_BUBBLE_DETAILS,
-      {link, ui::DialogModelLabel::CreatePlainText(std::move(email))}));
+      IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_DIALOG_DETAILS,
+      {ui::DialogModelLabel::CreatePlainText(std::move(email)), link}));
   dialog_builder.AddCancelButton(base::DoNothing(),
                                  ui::DialogModel::Button::Params().SetLabel(
                                      l10n_util::GetStringUTF16(IDS_NO_THANKS)));
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_service_proxy.cc b/chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_service_proxy.cc
index 2b41603..21861d5 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_service_proxy.cc
+++ b/chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_service_proxy.cc
@@ -377,6 +377,11 @@
   NOTREACHED();
 }
 
+bool TabGroupSyncServiceProxy::HadSharedTabGroupsLastSession(
+    bool open_shared_tab_groups) {
+  return false;
+}
+
 void TabGroupSyncServiceProxy::OnLastTabClosed(
     const SavedTabGroup& saved_tab_group) {}
 
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_service_proxy.h b/chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_service_proxy.h
index 4ef5107..ceb238a 100644
--- a/chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_service_proxy.h
+++ b/chrome/browser/ui/tabs/saved_tab_groups/tab_group_sync_service_proxy.h
@@ -138,6 +138,7 @@
       TabGroupSyncService::UrlRestrictionCallback callback) override;
   std::unique_ptr<std::vector<SavedTabGroup>>
   TakeSharedTabGroupsAvailableAtStartupForMessaging() override;
+  bool HadSharedTabGroupsLastSession(bool open_shared_tab_groups) override;
   void OnLastTabClosed(const SavedTabGroup& saved_tab_group) override;
 
   void AddObserver(Observer* observer) override;
diff --git a/chrome/browser/ui/tabs/tab_dialog_manager.cc b/chrome/browser/ui/tabs/tab_dialog_manager.cc
index 9457140..f42166d 100644
--- a/chrome/browser/ui/tabs/tab_dialog_manager.cc
+++ b/chrome/browser/ui/tabs/tab_dialog_manager.cc
@@ -12,6 +12,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/scoped_observation.h"
 #include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
+#include "chrome/browser/ui/browser_window/public/desktop_browser_window_capabilities.h"
 #include "chrome/browser/ui/tabs/public/tab_features.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "components/back_forward_cache/back_forward_cache_disable.h"
@@ -282,8 +283,10 @@
   if (params_->disable_input) {
     scoped_ignore_input_events_ =
         tab_interface_->GetContents()->IgnoreInputEvents(std::nullopt);
-    tab_interface_->GetBrowserWindowInterface()->SetWebContentsBlocked(
-        tab_interface_->GetContents(), /*blocked=*/true);
+    tab_interface_->GetBrowserWindowInterface()
+        ->capabilities()
+        ->SetWebContentsBlocked(tab_interface_->GetContents(),
+                                /*blocked=*/true);
   }
   tab_dialog_widget_observer_ =
       std::make_unique<TabDialogWidgetObserver>(this, widget_.get());
@@ -326,8 +329,9 @@
   tab_dialog_widget_observer_.reset();
   scoped_ignore_input_events_.reset();
   browser_window_widget_observer_.reset();
-  tab_interface_->GetBrowserWindowInterface()->SetWebContentsBlocked(
-      tab_interface_->GetContents(), /*blocked=*/false);
+  tab_interface_->GetBrowserWindowInterface()
+      ->capabilities()
+      ->SetWebContentsBlocked(tab_interface_->GetContents(), /*blocked=*/false);
 }
 
 void TabDialogManager::DidFinishNavigation(
diff --git a/chrome/browser/ui/views/profiles/first_run_interactive_uitest.cc b/chrome/browser/ui/views/profiles/first_run_interactive_uitest.cc
index 610e316e..bd53846 100644
--- a/chrome/browser/ui/views/profiles/first_run_interactive_uitest.cc
+++ b/chrome/browser/ui/views/profiles/first_run_interactive_uitest.cc
@@ -742,10 +742,10 @@
 
 IN_PROC_BROWSER_TEST_P(FirstRunParameterizedInteractiveUiTest, DeclineSync) {
   bool should_skip_test = false;
-#if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_64_BITS)
+#if BUILDFLAG(IS_WIN)
   // TODO(crbug.com/366082752): Re-enable this test
   should_skip_test = true;
-#endif  // WIN && ARCH_CPU_64_BITS
+#endif  // WIN
   if (should_skip_test) {
     GTEST_SKIP() << "Test is flaky on win64";
   }
diff --git a/chrome/browser/ui/views/promos/ios_promo_bubble.cc b/chrome/browser/ui/views/promos/ios_promo_bubble.cc
index 6750fef..41c19150 100644
--- a/chrome/browser/ui/views/promos/ios_promo_bubble.cc
+++ b/chrome/browser/ui/views/promos/ios_promo_bubble.cc
@@ -343,7 +343,11 @@
       views::BubbleDialogDelegate::CreateBubble(std::move(promo_bubble));
   widget->Show();
 
-  highlighted_button->SetVisible(true);
+  // `highlighted_button` can be null when the promo_bubble's page action is
+  // anchored to the right hand side/RHS of the omnibox.
+  if (highlighted_button) {
+    highlighted_button->SetVisible(true);
+  }
 }
 
 // static
diff --git a/chrome/browser/ui/views/side_panel/read_anything/read_anything_service.cc b/chrome/browser/ui/views/side_panel/read_anything/read_anything_service.cc
index cf04d16..2761947 100644
--- a/chrome/browser/ui/views/side_panel/read_anything/read_anything_service.cc
+++ b/chrome/browser/ui/views/side_panel/read_anything/read_anything_service.cc
@@ -215,9 +215,14 @@
 
 #if !BUILDFLAG(IS_CHROMEOS)
 void ReadAnythingService::InstallComponent(const base::FilePath& new_dir) {
-  const base::FilePath::CharType* manifest =
-      features::IsWasmTtsComponentUpdaterV3Enabled() ? kManifestV3FileName
-                                                     : kManifestFileName;
+  const base::FilePath::CharType* manifest;
+  if (features::IsWasmTtsComponentUpdaterV3Enabled()) {
+    VLOG(1) << "Installing TTS component using V3 engine";
+    manifest = kManifestV3FileName;
+  } else {
+    VLOG(1) << "Installing TTS component using V2 engine";
+    manifest = kManifestFileName;
+  }
   EmbeddedA11yExtensionLoader::GetInstance()->Init();
   EmbeddedA11yExtensionLoader::GetInstance()->InstallExtensionWithIdAndPath(
       extension_misc::kComponentUpdaterTTSEngineExtensionId, new_dir, manifest,
diff --git a/chrome/browser/ui/views/tabs/tab_search_container_browsertest.cc b/chrome/browser/ui/views/tabs/tab_search_container_browsertest.cc
index 1bbdbc87..2ea254ec 100644
--- a/chrome/browser/ui/views/tabs/tab_search_container_browsertest.cc
+++ b/chrome/browser/ui/views/tabs/tab_search_container_browsertest.cc
@@ -29,6 +29,12 @@
 #include "ui/gfx/animation/slide_animation.h"
 #include "ui/views/test/views_test_utils.h"
 
+namespace {
+
+using ::testing::AssertionFailure;
+using ::testing::AssertionResult;
+using ::testing::AssertionSuccess;
+
 class TabSearchContainerBrowserTest : public InProcessBrowserTest {
  public:
   TabSearchContainerBrowserTest() {
@@ -52,6 +58,27 @@
         ->tab_search_container_for_testing();
   }
 
+  // Returns an assertion result that the expansion animation is closing.
+  AssertionResult ExpansionAnimationIsClosing() {
+    if (!tab_search_container()) {
+      return AssertionFailure() << "tab_search_container is null.";
+    }
+    if (!tab_search_container()->animation_session_for_testing()) {
+      return AssertionFailure() << "animation_session_for_testing is null.";
+    }
+    if (!tab_search_container()
+             ->animation_session_for_testing()
+             ->expansion_animation()) {
+      return AssertionFailure() << "expansion_animation is null.";
+    }
+    return tab_search_container()
+                   ->animation_session_for_testing()
+                   ->expansion_animation()
+                   ->IsClosing()
+               ? AssertionSuccess()
+               : AssertionFailure() << "expansion_animation is not closing.";
+  }
+
  protected:
   void ResetAnimation(int value) {
     if (tab_search_container()->animation_session_for_testing()) {
@@ -245,10 +272,7 @@
   tab_search_container()->SetLockedExpansionModeForTesting(
       LockedExpansionMode::kNone, nullptr);
 
-  ASSERT_TRUE(tab_search_container()
-                  ->animation_session_for_testing()
-                  ->expansion_animation()
-                  ->IsClosing());
+  EXPECT_TRUE(ExpansionAnimationIsClosing());
 }
 
 IN_PROC_BROWSER_TEST_F(TabSearchContainerBrowserTest,
@@ -264,10 +288,7 @@
 
   tab_search_container()->OnAutoTabGroupButtonClicked();
 
-  EXPECT_TRUE(tab_search_container()
-                  ->animation_session_for_testing()
-                  ->expansion_animation()
-                  ->IsClosing());
+  EXPECT_TRUE(ExpansionAnimationIsClosing());
 }
 
 IN_PROC_BROWSER_TEST_F(TabSearchContainerBrowserTest,
@@ -283,10 +304,7 @@
 
   tab_search_container()->OnAutoTabGroupButtonDismissed();
 
-  EXPECT_TRUE(tab_search_container()
-                  ->animation_session_for_testing()
-                  ->expansion_animation()
-                  ->IsClosing());
+  EXPECT_TRUE(ExpansionAnimationIsClosing());
 }
 
 // TODO(crbug.com/414839512): Fix flaky test.
@@ -320,10 +338,7 @@
       LockedExpansionMode::kNone,
       tab_search_container()->auto_tab_group_button());
 
-  ASSERT_TRUE(tab_search_container()
-                  ->animation_session_for_testing()
-                  ->expansion_animation()
-                  ->IsClosing());
+  EXPECT_TRUE(ExpansionAnimationIsClosing());
 }
 
 IN_PROC_BROWSER_TEST_F(TabSearchContainerBrowserTest,
@@ -477,10 +492,7 @@
   tab_search_container()->HideTabOrganization(
       tab_search_container()->auto_tab_group_button());
 
-  EXPECT_TRUE(tab_search_container()
-                  ->animation_session_for_testing()
-                  ->expansion_animation()
-                  ->IsClosing());
+  EXPECT_TRUE(ExpansionAnimationIsClosing());
 
   EXPECT_EQ(tab_search_container()
                 ->animation_session_for_testing()
@@ -528,10 +540,7 @@
   tab_search_container()->HideTabOrganization(
       tab_search_container()->tab_declutter_button());
 
-  ASSERT_TRUE(tab_search_container()
-                  ->animation_session_for_testing()
-                  ->expansion_animation()
-                  ->IsClosing());
+  EXPECT_TRUE(ExpansionAnimationIsClosing());
 }
 
 IN_PROC_BROWSER_TEST_F(TabSearchContainerBrowserTest,
@@ -555,3 +564,5 @@
 
   ASSERT_FALSE(tab_search_container()->animation_session_for_testing());
 }
+
+}  // namespace
diff --git a/chrome/browser/ui/web_applications/navigation_capturing_process.cc b/chrome/browser/ui/web_applications/navigation_capturing_process.cc
index 86cb26e..b9674c6de 100644
--- a/chrome/browser/ui/web_applications/navigation_capturing_process.cc
+++ b/chrome/browser/ui/web_applications/navigation_capturing_process.cc
@@ -96,13 +96,6 @@
   return true;
 }
 
-bool IsServiceWorkerClientOpenNavigation(const NavigateParams& params) {
-  return params.open_pwa_window_if_possible &&
-         ui::PageTransitionCoreTypeIs(params.transition,
-                                      ui::PAGE_TRANSITION_AUTO_TOPLEVEL) &&
-         params.disposition == WindowOpenDisposition::NEW_FOREGROUND_TAB;
-}
-
 // Returns true if an auxiliary browsing context is getting created, so
 // navigation should be done in the same container that it was triggered in.
 bool IsAuxiliaryBrowsingContext(const NavigateParams& nav_params) {
@@ -252,12 +245,9 @@
   }
 
   auto result = base::WrapUnique(new NavigationCapturingProcess(params));
-  // The `open_pwa_window_if_possible` flag is implemented in navigation
-  // capturing logic, even if otherwise the reimpl experiment isn't enabled.
-
   const bool should_handle_navigations_in_app =
       result->IsNavigationCapturingReimplExperimentEnabled() ||
-      params.open_pwa_window_if_possible ||
+      params.is_service_worker_open_window ||
       content::SiteIsolationPolicy::ShouldUrlUseApplicationIsolationLevel(
           profile, params.url);
 
@@ -403,10 +393,8 @@
   // needed.
   navigation_capturing_enabled_ =
       IsNavigationCapturingReimplExperimentEnabled();
-  bool is_service_worker_clients_open_window =
-      IsServiceWorkerClientOpenNavigation(params);
   debug_data_.Set("is_service_worker_clients_open_window",
-                  is_service_worker_clients_open_window);
+                  params.is_service_worker_open_window);
 
   if (isolated_web_app_navigation_) {
     return HandleIsolatedWebAppNavigation(params);
@@ -414,7 +402,7 @@
 
   CHECK(!isolated_web_app_navigation_);
   // Handle service worker related navigations if any here.
-  if (is_service_worker_clients_open_window && !navigation_capturing_enabled_) {
+  if (params.is_service_worker_open_window && !navigation_capturing_enabled_) {
     // See service_worker_client_utils::OpenWindow() for more details.
     CHECK(!params.browser);
     CHECK_EQ(disposition_, WindowOpenDisposition::NEW_FOREGROUND_TAB);
@@ -449,7 +437,7 @@
   // The service worker clients API currently uses
   // PAGE_TRANSITION_AUTO_TOPLEVEL, which is normally considered invalid for
   // navigation capturing. Explicitly allow that.
-  if (!is_service_worker_clients_open_window &&
+  if (!params.is_service_worker_open_window &&
       !IsPageTransitionValidForNavigationCapturing(params.transition)) {
     return CapturingDisabled();
   }
diff --git a/chrome/browser/ui/web_applications/web_app_navigate_browsertest.cc b/chrome/browser/ui/web_applications/web_app_navigate_browsertest.cc
index d2c8565b..511e600 100644
--- a/chrome/browser/ui/web_applications/web_app_navigate_browsertest.cc
+++ b/chrome/browser/ui/web_applications/web_app_navigate_browsertest.cc
@@ -34,13 +34,13 @@
     params.is_renderer_initiated = true;
     params.user_gesture = false;
     params.initiator_origin = url::Origin::Create(GetGoogleURL());
-    params.open_pwa_window_if_possible = true;
+    params.is_service_worker_open_window = true;
     return params;
   }
 };
 
-// This test verifies that navigating with "open_pwa_window_if_possible = true"
-// opens a new app window if there is an installed Web App for the URL.
+// This test verifies that navigating with "is_service_worker_open_window =
+// true" opens a new app window if there is an installed Web App for the URL.
 IN_PROC_BROWSER_TEST_F(WebAppServiceWorkerOpenWindowBrowserTest,
                        AppInstalled_ServiceWorkerOpenWindow) {
   InstallPWA(GetGoogleURL());
diff --git a/chrome/browser/ui/webui/ash/settings/pages/search/search_section.cc b/chrome/browser/ui/webui/ash/settings/pages/search/search_section.cc
index f5b230a..caa4b0c 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/search/search_section.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/search/search_section.cc
@@ -161,6 +161,18 @@
   return tags;
 }
 
+base::span<const SearchConcept> GetScannerSearchConcepts() {
+  static constexpr auto tags = std::to_array<SearchConcept>({
+      {IDS_OS_SETTINGS_TAG_SUGGESTED_ACTIONS,
+       mojom::kSystemPreferencesSectionPath,
+       mojom::SearchResultIcon::kScannerActions,
+       mojom::SearchResultDefaultRank::kMedium,
+       mojom::SearchResultType::kSetting,
+       {.setting = mojom::Setting::kScannerOnOff}},
+  });
+  return tags;
+}
+
 base::span<const SearchConcept> GetAssistantSearchConcepts() {
   static constexpr auto tags = std::to_array<SearchConcept>({
       {IDS_OS_SETTINGS_TAG_ASSISTANT,
@@ -354,6 +366,9 @@
   SearchTagRegistry::ScopedTagUpdater updater = registry()->StartUpdate();
 
   updater.AddSearchTags(GetSearchPageSearchConcepts());
+  if (IsScannerSettingsToggleVisible()) {
+    updater.AddSearchTags(GetScannerSearchConcepts());
+  }
 
   AssistantState* assistant_state = AssistantState::Get();
   if (IsAssistantAllowed() && assistant_state) {
diff --git a/chrome/browser/ui/webui/ash/settings/search/mojom/search_result_icon.mojom b/chrome/browser/ui/webui/ash/settings/search/mojom/search_result_icon.mojom
index 073726a..2b92447 100644
--- a/chrome/browser/ui/webui/ash/settings/search/mojom/search_result_icon.mojom
+++ b/chrome/browser/ui/webui/ash/settings/search/mojom/search_result_icon.mojom
@@ -73,6 +73,7 @@
   kReset,
   kRestore,
   kScanner,
+  kScannerActions,
   kSearch,
   kSelectToSpeak,
   kShield,
diff --git a/chrome/browser/ui/webui/cr_components/most_visited/most_visited_handler.cc b/chrome/browser/ui/webui/cr_components/most_visited/most_visited_handler.cc
index cb2418f..a9483f4 100644
--- a/chrome/browser/ui/webui/cr_components/most_visited/most_visited_handler.cc
+++ b/chrome/browser/ui/webui/cr_components/most_visited/most_visited_handler.cc
@@ -273,6 +273,7 @@
 }
 
 void MostVisitedHandler::OnURLsAvailable(
+    bool is_user_triggered,
     const std::map<ntp_tiles::SectionType, ntp_tiles::NTPTilesVector>&
         sections) {
   auto* template_url_service =
diff --git a/chrome/browser/ui/webui/cr_components/most_visited/most_visited_handler.h b/chrome/browser/ui/webui/cr_components/most_visited/most_visited_handler.h
index 5ae5d811..e777c30 100644
--- a/chrome/browser/ui/webui/cr_components/most_visited/most_visited_handler.h
+++ b/chrome/browser/ui/webui/cr_components/most_visited/most_visited_handler.h
@@ -82,6 +82,7 @@
  private:
   // ntp_tiles::MostVisitedSites::Observer:
   void OnURLsAvailable(
+      bool is_user_triggered,
       const std::map<ntp_tiles::SectionType, ntp_tiles::NTPTilesVector>&
           sections) override;
   void OnIconMadeAvailable(const GURL& site_url) override;
diff --git a/chrome/browser/ui/webui/top_chrome/webui_contents_preload_manager.cc b/chrome/browser/ui/webui/top_chrome/webui_contents_preload_manager.cc
index acc7737..848a5ca 100644
--- a/chrome/browser/ui/webui/top_chrome/webui_contents_preload_manager.cc
+++ b/chrome/browser/ui/webui/top_chrome/webui_contents_preload_manager.cc
@@ -118,6 +118,11 @@
   return webui->GetController();
 }
 
+bool IsShowingErrorPage(content::WebContents* web_contents) {
+  return web_contents->GetSiteInstance()->GetSiteURL().SchemeIs(
+      content::kChromeErrorScheme);
+}
+
 }  // namespace
 
 // A stub WebUI page embdeder that captures the ready-to-show signal.
@@ -162,6 +167,18 @@
       return;
     }
 
+    // The enterprise policy might block navigation to the WebUI. When such
+    // policy is in place, the WebUI object is created on LoadURL(), then
+    // asynchronously the navigation commit fails, destroying the WebUI object
+    // and the RFH. For unknown reasons the primary main RFH of the WebContents
+    // might be dangling at this point, causing a crash on calling
+    // WebContents::GetWebUI(). See https://crbug.com/409389408.
+    // TODO(crbug.com/424551539): figure out why the primary main RFH is
+    // dangling.
+    if (IsShowingErrorPage(web_contents_)) {
+      return;
+    }
+
     content::WebUIController* webui_controller =
         GetWebUIController(web_contents_);
     if (!webui_controller) {
@@ -318,7 +335,8 @@
 }
 
 void WebUIContentsPreloadManager::MaybePreloadForBrowserContext(
-    content::BrowserContext* browser_context, PreloadReason preload_reason) {
+    content::BrowserContext* browser_context,
+    PreloadReason preload_reason) {
   pending_preload_.reset();
 
   if (!ShouldPreloadForBrowserContext(browser_context)) {
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index 12bf340f..c888bd5 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1749729434-18eb946046f04c541bf5f2c204e19183b2eb9196-ea6e80c17deabbd235a4d48d9ad4d3315117a73b.profdata
+chrome-android32-main-1749793413-7daf7a2fc3724b067ec30357f24238042c6b45b4-cdfe1f2e8a7f0dda65e5575431ff3103b4984cc6.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index 75629c0c1..952ca9a 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1749751040-5ff1a4a9f4b0e005a1c28b3e10e6f3dbe2b0ba67-d0c1258f6c13394215f4e10fe4dc5bf29245da8c.profdata
+chrome-android64-main-1749805554-27b6326e34ee53c654b2d59d077d7c21d7dd7f28-d2dad1bfa09a047f6c5c5be5ff1216295cf9babb.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index c99da0a3..1ca32797 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1749729434-f19a34ce7c3b435fe0ba8805dd577b7631c39dac-ea6e80c17deabbd235a4d48d9ad4d3315117a73b.profdata
+chrome-linux-main-1749793413-51a80ee7b88ffe8d73f1c96f006df2e20a8f5e99-cdfe1f2e8a7f0dda65e5575431ff3103b4984cc6.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index f0b9663..464b314 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1749765447-28fe27d552f7c5f266a907b79b1c3431887db5d8-515f499b6b9f2050341f4ef789b4a77e5b027b4e.profdata
+chrome-mac-arm-main-1749807913-66503ee708e795836d7879ae3df8020a431707d3-2ee6659a03b5abac00465b2d33057a576a5c593b.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 143fdac5..6d38ebd0 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1749729434-03efd9c008dde047e2bccd79b90219498715fcd7-ea6e80c17deabbd235a4d48d9ad4d3315117a73b.profdata
+chrome-mac-main-1749793413-f7e678c1187b199f8985972ee0f371d469f15f01-cdfe1f2e8a7f0dda65e5575431ff3103b4984cc6.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index 893c2ee..5cfc7733 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1749729434-b19bc68d27adad7328b96ba38bf6c54369944bbb-ea6e80c17deabbd235a4d48d9ad4d3315117a73b.profdata
+chrome-win-arm64-main-1749793413-625369a899ac3e84be48ece80628bd5b5533497e-cdfe1f2e8a7f0dda65e5575431ff3103b4984cc6.profdata
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 16e9995..1bbe5f7 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -442,23 +442,6 @@
                    &kGlicUserStatusCheck,
                    "glic-user-status-request-delay-jitter",
                    0.005);
-
-// When true, the Glic API exposes a method to propose refreshing the
-// user status.
-BASE_FEATURE_PARAM(bool,
-                   kGlicUserStatusRefreshApi,
-                   &kGlicUserStatusCheck,
-                   "glic-user-status-refresh-api",
-                   true);
-
-// The minimum time between user status update requests, when triggered by
-// the Glic API (or another reason that might occur frequently).
-BASE_FEATURE_PARAM(base::TimeDelta,
-                   kGlicUserStatusDebounceInterval,
-                   &kGlicUserStatusCheck,
-                   "glic-user-status-debounce-interval",
-                   base::Seconds(5));
-
 BASE_FEATURE(kGlicFreURLConfig,
              "GlicFreURLConfig",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 0a13325..a7aadec 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -248,11 +248,6 @@
 // This is the maximum deviation. The jitter to the delay is a uniformly random
 // sample from the chosen deviation. The value should be less than 1.
 extern const base::FeatureParam<double> kGlicUserStatusRequestDelayJitter;
-COMPONENT_EXPORT(CHROME_FEATURES)
-extern const base::FeatureParam<bool> kGlicUserStatusRefreshApi;
-COMPONENT_EXPORT(CHROME_FEATURES)
-extern const base::FeatureParam<base::TimeDelta>
-    kGlicUserStatusDebounceInterval;
 
 COMPONENT_EXPORT(CHROME_FEATURES) BASE_DECLARE_FEATURE(kGlicFreURLConfig);
 COMPONENT_EXPORT(CHROME_FEATURES)
diff --git a/chrome/common/extensions/sync_helper.h b/chrome/common/extensions/sync_helper.h
index 47017aa..d25f5622 100644
--- a/chrome/common/extensions/sync_helper.h
+++ b/chrome/common/extensions/sync_helper.h
@@ -5,6 +5,10 @@
 #ifndef CHROME_COMMON_EXTENSIONS_SYNC_HELPER_H_
 #define CHROME_COMMON_EXTENSIONS_SYNC_HELPER_H_
 
+#include "extensions/buildflags/buildflags.h"
+
+static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE));
+
 namespace extensions {
 
 class Extension;
diff --git a/chrome/common/features.gni b/chrome/common/features.gni
index 1078abe..701848ee 100644
--- a/chrome/common/features.gni
+++ b/chrome/common/features.gni
@@ -52,7 +52,9 @@
 
   # Hangout services is an extension that adds extra features to Hangouts.
   # It is enableable separately to facilitate testing.
-  enable_hangout_services_extension = is_chrome_branded
+  # TODO(crbug.com/424596489): Enable on desktop Android once the
+  # enterprise.hardwarePlatform and webrtcLoggingPrivate APIs are supported.
+  enable_hangout_services_extension = is_chrome_branded && !is_desktop_android
 
   enable_service_discovery = (enable_mdns && !is_android) || is_mac
 
diff --git a/chrome/enterprise_companion/enterprise_companion.cc b/chrome/enterprise_companion/enterprise_companion.cc
index 3dcbbcf..83a3606 100644
--- a/chrome/enterprise_companion/enterprise_companion.cc
+++ b/chrome/enterprise_companion/enterprise_companion.cc
@@ -32,8 +32,10 @@
 
 #if BUILDFLAG(IS_WIN)
 #include "base/i18n/icu_util.h"
+#include "base/path_service.h"
 #include "base/strings/stringprintf.h"
 #include "base/win/windows_version.h"
+#include "chrome/enterprise_companion/installer.h"
 #endif
 
 namespace enterprise_companion {
@@ -85,6 +87,34 @@
   base::ThreadPoolInstance::Get()->Start(init_params);
 }
 
+#if BUILDFLAG(IS_WIN)
+// Perform ICU initialization at best-effort. In official builds ICU data is
+// distributed as a file alongside the application, however this may not be
+// available due to external modification (e.g. antivirus, enterprise management
+// tools, adventurous users etc.)
+void TryInitializeICU() {
+#if ENTERPRISE_COMPANION_USE_ICU_DATA_FILE
+  base::FilePath exe_path;
+  if (!base::PathService::Get(base::FILE_EXE, &exe_path)) {
+    VLOG(1) << "Failed to retrieve the current executable's path.";
+    return;
+  }
+  if (!base::PathExists(exe_path.DirName().Append(kIcuDataFileName))) {
+    VLOG(1) << "ICU data file is not present; ICU libraries will not be "
+               "initialized which may cause resolution of proxies containing "
+               "non-ASCII Unicode code points to crash "
+               "(https://crbug.com/420737997).";
+    return;
+  }
+#endif  // ENTERPRISE_COMPANION_USE_ICU_DATA_FILE
+  // InitializeICU may CHECK, though the conditional returns above try to
+  // mitigate this. See https://crbug.com/445616.
+  if (!base::i18n::InitializeICU()) {
+    VLOG(1) << "Failed to initialize ICU";
+  }
+}
+#endif  // BUILDFLAG(IS_WIN)
+
 std::unique_ptr<App> CreateAppForCommandLine(base::CommandLine* command_line) {
   if (command_line->HasSwitch(kShutdownSwitch)) {
     return CreateAppShutdown();
@@ -163,7 +193,7 @@
   InitializeCrashReporting();
 
 #if BUILDFLAG(IS_WIN)
-  CHECK(base::i18n::InitializeICU()) << "Failed to initialize ICU";
+  TryInitializeICU();
 #endif
 
   // Records a backtrace in the log, crashes the program, saves a crash dump,
diff --git a/chrome/enterprise_companion/installer.h b/chrome/enterprise_companion/installer.h
index 9d2c391..dfc524c 100644
--- a/chrome/enterprise_companion/installer.h
+++ b/chrome/enterprise_companion/installer.h
@@ -16,7 +16,12 @@
 extern const wchar_t kRegValuePV[];
 // The registry value under `kAppRegKey` which stores the application's name.
 extern const wchar_t kRegValueName[];
-#endif
+
+#if ENTERPRISE_COMPANION_USE_ICU_DATA_FILE
+extern const wchar_t kIcuDataFileName[];
+#endif  // ENTERPRISE_COMPANION_USE_ICU_DATA_FILE
+
+#endif  // BUILDFLAG(IS_WIN)
 
 // Install the Chrome Enterprise Companion App.
 bool Install();
diff --git a/chrome/installer/linux/BUILD.gn b/chrome/installer/linux/BUILD.gn
index 00478ab2..3a7cd8c 100644
--- a/chrome/installer/linux/BUILD.gn
+++ b/chrome/installer/linux/BUILD.gn
@@ -120,6 +120,7 @@
     additional_deps,
     "debian/deb_version.py",
     "debian/package_version_interval.py",
+    "//build/action_helpers.py",
   ]
   outputs = [ "$root_out_dir/deb_common.deps" ]
   args = [
diff --git a/chrome/installer/linux/debian/merge_package_versions.py b/chrome/installer/linux/debian/merge_package_versions.py
index 53fd7ea..07c922ab 100755
--- a/chrome/installer/linux/debian/merge_package_versions.py
+++ b/chrome/installer/linux/debian/merge_package_versions.py
@@ -3,10 +3,16 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import os
 import sys
 
 import package_version_interval
 
+sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)),
+                             os.path.pardir, os.path.pardir, os.path.pardir,
+                             os.path.pardir, 'build'))
+import action_helpers
+
 if len(sys.argv) < 3:
   print ('Usage: %s output_deps_file input1_deps_file input2_deps_file ...' %
          sys.argv[0])
@@ -38,7 +44,7 @@
     if should_append_interval_set:
       package_interval_sets.append(interval_set)
 
-with open(output_filename, 'w') as output_file:
+with action_helpers.atomic_output(output_filename, mode='w') as output_file:
   lines = [interval_set.formatted() + '\n'
            for interval_set in package_interval_sets]
   output_file.write(''.join(sorted(lines)))
diff --git a/chrome/services/speech/speech_recognition_recognizer_impl.cc b/chrome/services/speech/speech_recognition_recognizer_impl.cc
index 909b925..af16e5c 100644
--- a/chrome/services/speech/speech_recognition_recognizer_impl.cc
+++ b/chrome/services/speech/speech_recognition_recognizer_impl.cc
@@ -25,6 +25,7 @@
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/services/speech/soda/soda_client_impl.h"
+#include "chrome/services/speech/speech_timestamp_estimator.h"
 #include "components/soda/constants.h"
 #include "google_apis/google_api_keys.h"
 #include "media/base/audio_buffer.h"
@@ -212,6 +213,31 @@
   if (!client_remote_.is_bound())
     return;
 
+  if (event.is_final && event.timing_information.has_value()) {
+    using SpeechTimestamp = SpeechTimestampEstimator::SpeechTimestamp;
+    auto& timing_info = event.timing_information.value();
+
+    // During ResetSoda(), we reset `timestamp_estimator_`, and the next few
+    // transcriptions might have missing or wrong timestamps, but they should
+    // quickly return to being consistent.
+    //
+    // Indeed, due to threading, there might be `OnRecognitionEvent()` calls in
+    // flight from a previous SODA session, which arrive after
+    // `timestamp_estimator_` is reset. If the `timing_info` passed to the new
+    // estimator is out of bounds, nothing happens and `media_timestamps` will
+    // be empty. If the `timing_info` is in bounds, `media_timestamps` will have
+    // the wrong timestamps, and those timestamps will also be missing from
+    // future transcriptions.
+    //
+    // Correctly handling this scenario would add a fair bit more complexity,
+    // which might not be warranted at this time.
+    auto media_timestamps = timestamp_estimator_->TakeTimestampsInRange(
+        SpeechTimestamp(timing_info.audio_start_time),
+        SpeechTimestamp(timing_info.audio_end_time));
+
+    timing_info.originating_media_timestamps = std::move(media_timestamps);
+  }
+
   client_remote_->OnSpeechRecognitionRecognitionEvent(
       std::move(event),
       base::BindOnce(&SpeechRecognitionRecognizerImpl::
@@ -254,6 +280,7 @@
       config_paths_(config_paths),
       primary_language_name_(primary_language_name),
       mask_offensive_words_(mask_offensive_words),
+      timestamp_estimator_(std::make_unique<SpeechTimestampEstimator>()),
       speech_recognition_service_(speech_recognition_service) {
   recognition_event_callback_ = base::BindPostTaskToCurrentDefault(
       base::BindRepeating(&SpeechRecognitionRecognizerImpl::OnRecognitionEvent,
@@ -341,6 +368,10 @@
     return;
   }
 
+  auto buffer_duration = SpeechTimestampEstimator::PlaybackDuration(
+      media::AudioTimestampHelper::FramesToTime(buffer->frame_count,
+                                                buffer->sample_rate));
+
   // Skip this buffer if there has been no nonzero data for several seconds.
   if (options_->skip_continuously_empty_audio) {
     const bool buffer_is_zero =
@@ -350,14 +381,31 @@
     if (!buffer_is_zero) {
       last_non_empty_audio_time_ = now;
     }
-    if (now - last_non_empty_audio_time_ > base::Seconds(10)) {
+
+    // Brief periods of empty audio can be meaningful input to the speech
+    // recognition engine. Only drop `buffer` after 10s of silence to save on
+    // computations, once we're fairly sure the silence isn't meaningful.
+    constexpr base::TimeDelta kSilenceThreshold = base::Seconds(10);
+    if (now - last_non_empty_audio_time_ > kSilenceThreshold) {
       // No nonzero data for several seconds. Don't send this buffer of zeroes.
+
+      // Forward `media_start_pts` since we can seek into the middle of long
+      // stretches of silence.
+      AddMediaTimestampToEstimator(media_start_pts);
+
+      timestamp_estimator_->OnSilentMediaDropped(std::move(buffer_duration));
       return;
     }
   }
 
   // OK, everything is verified, let's send the audio.
   SendAudioToSpeechRecognitionServiceInternal(std::move(buffer));
+
+  // Update `timestamp_estimator_` after sending audio to SODA, since it might
+  // be reset along with SODA after audio parameter changes.
+  AddMediaTimestampToEstimator(media_start_pts);
+
+  timestamp_estimator_->AppendDuration(std::move(buffer_duration));
 }
 
 void SpeechRecognitionRecognizerImpl::OnSpeechRecognitionError() {
@@ -559,6 +607,8 @@
   config.callback_handle = this;
   CHECK(soda_client_);
   soda_client_->Reset(config, sample_rate_, channel_count_);
+
+  timestamp_estimator_ = std::make_unique<SpeechTimestampEstimator>();
 }
 
 soda::chrome::ExtendedSodaConfigMsg*
@@ -566,4 +616,14 @@
   return &config_msg_;
 }
 
+void SpeechRecognitionRecognizerImpl::AddMediaTimestampToEstimator(
+    const std::optional<base::TimeDelta>& media_start_pts) {
+  if (!media_start_pts.has_value()) {
+    return;
+  }
+
+  timestamp_estimator_->AddPlaybackStart(
+      SpeechTimestampEstimator::MediaTimestamp(media_start_pts.value()));
+}
+
 }  // namespace speech
diff --git a/chrome/services/speech/speech_recognition_recognizer_impl.h b/chrome/services/speech/speech_recognition_recognizer_impl.h
index 9fa831c4..0110961 100644
--- a/chrome/services/speech/speech_recognition_recognizer_impl.h
+++ b/chrome/services/speech/speech_recognition_recognizer_impl.h
@@ -26,6 +26,8 @@
 
 namespace speech {
 
+class SpeechTimestampEstimator;
+
 class SpeechRecognitionRecognizerImpl
     : public media::mojom::SpeechRecognitionRecognizer,
       public AudioSourceConsumer,
@@ -166,6 +168,10 @@
   // Reset and initialize the SODA client.
   void ResetSoda();
 
+  // Updates `timestamp_estimator_` with `media_start_pts`.
+  void AddMediaTimestampToEstimator(
+      const std::optional<base::TimeDelta>& media_start_pts);
+
   // The remote endpoint for the mojo pipe used to return transcribed audio from
   // the speech recognition service to the browser process.
   mojo::Remote<media::mojom::SpeechRecognitionRecognizerClient> client_remote_;
@@ -199,6 +205,10 @@
   // Used when options_->skip_continuously_empty_audio == true.
   base::Time last_non_empty_audio_time_ = base::Time::Now();
 
+  // Tracks which media timestamps originated speech transcriptions.
+  // This is reset (and pending estimated are lost) every time SODA is reset.
+  std::unique_ptr<SpeechTimestampEstimator> timestamp_estimator_;
+
   // Whether the speech recognition session contains any recognized speech. Used
   // for logging purposes only.
   bool session_contains_speech_ = false;
diff --git a/chrome/services/speech/speech_timestamp_estimator.cc b/chrome/services/speech/speech_timestamp_estimator.cc
index c955c4d..e0cba85 100644
--- a/chrome/services/speech/speech_timestamp_estimator.cc
+++ b/chrome/services/speech/speech_timestamp_estimator.cc
@@ -227,11 +227,12 @@
   results.reserve(playbacks.size());
 
   // Convert playback chunks into media start/end presentation timestamps.
-  std::ranges::transform(playbacks, std::back_inserter(results),
-                         [](const PlaybackChunk& chunk) {
-                           return std::make_pair(chunk.media_start.value(),
-                                                 chunk.MediaEnd().value());
-                         });
+  std::ranges::transform(
+      playbacks, std::back_inserter(results),
+      [](const PlaybackChunk& chunk) -> media::MediaTimestampRange {
+        return {.start = chunk.media_start.value(),
+                .end = chunk.MediaEnd().value()};
+      });
 
   return results;
 }
diff --git a/chrome/services/speech/speech_timestamp_estimator.h b/chrome/services/speech/speech_timestamp_estimator.h
index d3b5698..6337eb4 100644
--- a/chrome/services/speech/speech_timestamp_estimator.h
+++ b/chrome/services/speech/speech_timestamp_estimator.h
@@ -11,6 +11,7 @@
 #include "base/containers/circular_deque.h"
 #include "base/time/time.h"
 #include "base/types/strong_alias.h"
+#include "media/mojo/mojom/speech_recognition_result.h"
 
 namespace speech {
 
@@ -42,8 +43,7 @@
 
   // Note: these `base::TimeDelta`s are `MediaTimestamp`s, but avoid forcing
   // callers to deal with the `base::StrongAlias`.
-  using MediaTimestampRange = std::pair<base::TimeDelta, base::TimeDelta>;
-  using MediaRanges = std::vector<MediaTimestampRange>;
+  using MediaRanges = std::vector<media::MediaTimestampRange>;
 
   // Represents a chunk of originating media played for a certain amount of
   // time, and its position in the queue of all audio sent to the speech
diff --git a/chrome/services/speech/speech_timestamp_estimator_unittest.cc b/chrome/services/speech/speech_timestamp_estimator_unittest.cc
index 2ce9571f..131c4fea 100644
--- a/chrome/services/speech/speech_timestamp_estimator_unittest.cc
+++ b/chrome/services/speech/speech_timestamp_estimator_unittest.cc
@@ -14,7 +14,7 @@
 using SpeechTimestamp = SpeechTimestampEstimator::SpeechTimestamp;
 using PlaybackDuration = SpeechTimestampEstimator::PlaybackDuration;
 using MediaTimestamp = SpeechTimestampEstimator::MediaTimestamp;
-using MediaTimestampRange = SpeechTimestampEstimator::MediaTimestampRange;
+using MediaTimestampRange = media::MediaTimestampRange;
 using MediaRanges = SpeechTimestampEstimator::MediaRanges;
 
 using SpeechTimestampRange = std::pair<SpeechTimestamp, SpeechTimestamp>;
@@ -25,19 +25,17 @@
 }
 
 MediaTimestampRange MediaSecondsRange(int start, int end) {
-  return {base::Seconds(start), base::Seconds(end)};
+  return {.start = base::Seconds(start), .end = base::Seconds(end)};
 }
 
-void VerifyRanges(const MediaRanges& actual, const MediaRanges& expected) {
-  EXPECT_EQ(actual.size(), expected.size());
-  for (auto [actual_range, expected_range] : base::zip(actual, expected)) {
-    auto [actual_start, actual_end] = actual_range;
-    auto [expected_start, expected_end] = expected_range;
+void VerifyRanges(const MediaRanges& actual_ranges,
+                  const MediaRanges& expected_ranges) {
+  EXPECT_EQ(actual_ranges.size(), expected_ranges.size());
+  for (auto [actual, expected] : base::zip(actual_ranges, expected_ranges)) {
+    EXPECT_EQ(actual.start, expected.start);
+    EXPECT_EQ(actual.end, expected.end);
 
-    EXPECT_EQ(actual_start, expected_start);
-    EXPECT_EQ(actual_end, expected_end);
-
-    EXPECT_LT(actual_start, actual_end);
+    EXPECT_LT(actual.start, actual.end);
   }
 }
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index c77c8d09..6281ef7 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -9120,6 +9120,8 @@
       "../browser/extensions/extension_prefs_unittest.cc",
       "../browser/extensions/extension_prefs_unittest.h",
       "../browser/extensions/extension_service_unittest.cc",
+      "../browser/extensions/extension_sync_data_unittest.cc",
+      "../browser/extensions/extension_sync_service_unittest.cc",
       "../browser/extensions/external_policy_loader_unittest.cc",
       "../browser/extensions/forced_extensions/force_installed_metrics_unittest.cc",
       "../browser/extensions/forced_extensions/force_installed_test_base.cc",
@@ -9293,8 +9295,6 @@
       "../browser/extensions/extension_protocols_unittest.cc",
       "../browser/extensions/extension_safety_check_utils_unittest.cc",
       "../browser/extensions/extension_special_storage_policy_unittest.cc",
-      "../browser/extensions/extension_sync_data_unittest.cc",
-      "../browser/extensions/extension_sync_service_unittest.cc",
       "../browser/extensions/extension_tab_util_unittest.cc",
       "../browser/extensions/extension_telemetry_service_verdict_handler_unittest.cc",
       "../browser/extensions/extension_test_message_listener_unittest.cc",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/TopBottomLinksPageStation.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/TopBottomLinksPageStation.java
index 1031b371..a6f240a 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/TopBottomLinksPageStation.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/testhtmls/TopBottomLinksPageStation.java
@@ -7,6 +7,7 @@
 import android.util.Pair;
 
 import org.chromium.base.test.transit.Facility;
+import org.chromium.base.test.transit.Transition;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.transit.context_menu.LinkContextMenuFacility;
 import org.chromium.chrome.test.transit.page.PageStation;
@@ -59,6 +60,7 @@
         public BottomFacility scrollToBottom() {
             return mHostStation
                     .scrollPageDownWithGestureTo()
+                    .withOptions(Transition.retryOption())
                     .exitFacilityAnd(this)
                     .enterFacility(new BottomFacility());
         }
@@ -84,6 +86,7 @@
         public TopFacility scrollToTop() {
             return mHostStation
                     .scrollPageUpWithGestureTo()
+                    .withOptions(Transition.retryOption())
                     .exitFacilityAnd(this)
                     .enterFacility(new TopFacility());
         }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/suggestions/mostvisited/FakeMostVisitedSites.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/suggestions/mostvisited/FakeMostVisitedSites.java
index 62a2db6..f511dc27 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/suggestions/mostvisited/FakeMostVisitedSites.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/suggestions/mostvisited/FakeMostVisitedSites.java
@@ -71,7 +71,7 @@
     @Override
     public void setObserver(Observer observer, int numResults) {
         mObserver = observer;
-        notifyTileSuggestionsAvailable();
+        notifyTileSuggestionsAvailable(/* isUserTriggered= */ false);
     }
 
     @Override
@@ -105,26 +105,38 @@
     }
 
     /**
-     * Sets new tile suggestion data.
+     * Sets new tile suggestion data, assuming triggered by user action.
      *
      * <p>If there is an observer it will be notified and the call has to be made on the UI thread.
      */
     public void setTileSuggestions(List<SiteSuggestion> suggestions) {
         mSites = new ArrayList<>(suggestions);
-        notifyTileSuggestionsAvailable();
+        notifyTileSuggestionsAvailable(/* isUserTriggered= */ true);
+    }
+
+    /** Same as above, but assumes no direct user involvement. */
+    public void setTileSuggestionsPassive(List<SiteSuggestion> suggestions) {
+        mSites = new ArrayList<>(suggestions);
+        notifyTileSuggestionsAvailable(/* isUserTriggered= */ false);
     }
 
     /**
-     * Sets new tile suggestion data.
+     * Sets new tile suggestion data, assuming triggered by user action.
      *
-     * If there is an observer it will be notified and the call has to be made on the UI thread.
+     * <p>If there is an observer it will be notified and the call has to be made on the UI thread.
      */
     public void setTileSuggestions(SiteSuggestion... suggestions) {
         setTileSuggestions(Arrays.asList(suggestions));
     }
 
+    /** Same as above, but assumes no direct user involvement. */
+    public void setTileSuggestionsPassive(SiteSuggestion... suggestions) {
+        setTileSuggestionsPassive(Arrays.asList(suggestions));
+    }
+
     /**
-     * Sets new tile suggestion data, generating fake data for the missing properties.
+     * Sets new tile suggestion data, generating fake data for the missing properties, assuming
+     * triggered by user action.
      *
      * <p>If there is an observer it will be notified and the call has to be made on the UI thread.
      *
@@ -135,7 +147,14 @@
         setTileSuggestions(createSiteSuggestions(urls));
     }
 
-    /** @return An unmodifiable view of the current list of sites. */
+    /** Same as above, but assumes no direct user involvement. */
+    public void setTileSuggestionsPassive(String... urls) {
+        setTileSuggestionsPassive(createSiteSuggestions(urls));
+    }
+
+    /**
+     * @return An unmodifiable view of the current list of sites.
+     */
     public List<SiteSuggestion> getCurrentSites() {
         return Collections.unmodifiableList(mSites);
     }
@@ -159,7 +178,7 @@
                 TileSectionType.PERSONALIZED);
     }
 
-    private void notifyTileSuggestionsAvailable() {
+    private void notifyTileSuggestionsAvailable(boolean isUserTriggered) {
         if (mObserver == null) return;
 
         // Notifying the observer usually results in view modifications, so this call should always
@@ -169,6 +188,6 @@
         // a signal that the test started and this is not the setup anymore.
         ThreadUtils.assertOnUiThread();
 
-        mObserver.onSiteSuggestionsAvailable(mSites);
+        mObserver.onSiteSuggestionsAvailable(isUserTriggered, mSites);
     }
 }
diff --git a/chrome/test/base/testing_browser_process.cc b/chrome/test/base/testing_browser_process.cc
index ef96dc2..02d09c7 100644
--- a/chrome/test/base/testing_browser_process.cc
+++ b/chrome/test/base/testing_browser_process.cc
@@ -10,6 +10,7 @@
 #include "base/notreached.h"
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
+#include "base/test/task_environment.h"
 #include "base/time/default_clock.h"
 #include "base/time/default_tick_clock.h"
 #include "build/build_config.h"
@@ -137,24 +138,26 @@
 }
 
 // static
-void TestingBrowserProcess::StartTearDown() {
-  TestingBrowserProcess* browser_process = TestingBrowserProcess::GetGlobal();
-  if (browser_process) {
-    browser_process->ShutdownBrowserPolicyConnector();
-  }
-}
-
-// static
 void TestingBrowserProcess::TearDownAndDeleteInstance() {
-  TestingBrowserProcess::StartTearDown();
   TestingBrowserProcess::DeleteInstance();
 }
 
 TestingBrowserProcess::TestingBrowserProcess()
     : platform_part_(std::make_unique<TestingBrowserProcessPlatformPart>()),
-      os_crypt_async_(os_crypt_async::GetTestOSCryptAsyncForTesting()) {}
+      os_crypt_async_(os_crypt_async::GetTestOSCryptAsyncForTesting()) {
+  // Observe TaskEnvironment to get a chance to teardown components before
+  // ThreadPool is destroyed.
+  // In production, BrowserProcess is destroyed while ThreadPool is still
+  // active.
+  base::test::TaskEnvironment::AddDestructionObserver(this);
+}
 
 TestingBrowserProcess::~TestingBrowserProcess() {
+  base::test::TaskEnvironment::RemoveDestructionObserver(this);
+
+  // Tear down components for tests that do not have TaskEnvironment.
+  MaybeStartTearDown();
+
   EXPECT_FALSE(local_state_);
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   extensions::ExtensionsBrowserClient::Set(nullptr);
@@ -587,6 +590,12 @@
   features_->application_locale_storage()->Set("en");
 }
 
+void TestingBrowserProcess::WillDestroyCurrentTaskEnvironment() {
+  // BrowserProcessImpl::StartTearDown() is triggered on PostMainMessageLoop in
+  // production, which happens before ThreadPool is destroyed.
+  MaybeStartTearDown();
+}
+
 resource_coordinator::TabManager* TestingBrowserProcess::GetTabManager() {
   return resource_coordinator_parts()->tab_manager();
 }
@@ -630,6 +639,15 @@
   local_state_ = local_state;
 }
 
+void TestingBrowserProcess::MaybeStartTearDown() {
+  if (is_torn_down_) {
+    return;
+  }
+  is_torn_down_ = true;
+
+  ShutdownBrowserPolicyConnector();
+}
+
 void TestingBrowserProcess::ShutdownBrowserPolicyConnector() {
   if (browser_policy_connector_) {
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/test/base/testing_browser_process.h b/chrome/test/base/testing_browser_process.h
index 384bb16..07e8e1e 100644
--- a/chrome/test/base/testing_browser_process.h
+++ b/chrome/test/base/testing_browser_process.h
@@ -17,6 +17,7 @@
 
 #include "base/memory/raw_ptr.h"
 #include "base/memory/ref_counted.h"
+#include "base/test/task_environment.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
@@ -70,7 +71,9 @@
 class VariationsService;
 }
 
-class TestingBrowserProcess : public BrowserProcess {
+class TestingBrowserProcess
+    : public BrowserProcess,
+      public base::test::TaskEnvironment::DestructionObserver {
  public:
   // Initializes |g_browser_process| with a new TestingBrowserProcess.
   static void CreateInstance();
@@ -171,6 +174,9 @@
   GlobalFeatures* GetFeatures() override;
   void CreateGlobalFeaturesForTesting() override;
 
+  // TaskEnvironment::DestructionObserver:
+  void WillDestroyCurrentTaskEnvironment() override;
+
   // Set the local state for tests. Consumer is responsible for cleaning it up
   // afterwards (using ScopedTestingLocalState, for example).
   void SetLocalState(PrefService* local_state);
@@ -192,7 +198,6 @@
   void SetSystemNotificationHelper(
       std::unique_ptr<SystemNotificationHelper> system_notification_helper);
   void SetShuttingDown(bool is_shutting_down);
-  void ShutdownBrowserPolicyConnector();
   TestingBrowserProcessPlatformPart* GetTestPlatformPart();
   void SetStatusTray(std::unique_ptr<StatusTray> status_tray);
 #if !BUILDFLAG(IS_ANDROID)
@@ -206,17 +211,23 @@
 #endif
 
  private:
-  // Perform necessary cleanup prior to destruction of |g_browser_process|
-  static void StartTearDown();
-
   // See CreateInstance() and DestoryInstance() above.
   TestingBrowserProcess();
   ~TestingBrowserProcess() override;
 
   void Init();
 
+  // Perform necessary cleanup prior to destruction of |g_browser_process|
+  void MaybeStartTearDown();
+
+  void ShutdownBrowserPolicyConnector();
+
+  // The value returned by `IsShuttingDown()`.
   bool is_shutting_down_ = false;
 
+  // Used as a guard for `MaybeStartTearDown()`.
+  bool is_torn_down_ = false;
+
   std::unique_ptr<policy::ChromeBrowserPolicyConnector>
       browser_policy_connector_;
   bool created_browser_policy_connector_ = false;
diff --git a/chrome/test/data/webui/glic/api_test.ts b/chrome/test/data/webui/glic/api_test.ts
index 165b30b..d46ef8a 100644
--- a/chrome/test/data/webui/glic/api_test.ts
+++ b/chrome/test/data/webui/glic/api_test.ts
@@ -903,19 +903,6 @@
     assertEquals('createTab: failed', errorMessage);
   }
 
-  async testMaybeRefreshUserStatus() {
-    assertTrue(!!this.host.maybeRefreshUserStatus);
-    this.host.maybeRefreshUserStatus();
-  }
-
-  async testMaybeRefreshUserStatusDebounced() {
-    assertTrue(!!this.host.maybeRefreshUserStatus);
-    for (let i = 0; i < 10; i++) {
-      this.host.maybeRefreshUserStatus();
-      await sleep(100);
-    }
-  }
-
   private async closePanelAndWaitUntilInactive() {
     assertTrue(!!this.host.closePanel);
     await this.host.closePanel();
diff --git a/chrome/test/data/webui/glic/test_client/index.html b/chrome/test/data/webui/glic/test_client/index.html
index 135888c..8bca9ff 100644
--- a/chrome/test/data/webui/glic/test_client/index.html
+++ b/chrome/test/data/webui/glic/test_client/index.html
@@ -396,7 +396,6 @@
   <span id="syncCookieStatus"></span>
   <button id="testLogsBn">test logs</button>
   <button id="testClipboardSave">Save Junk To Clipboard</button>
-  <button id="maybeRefreshUserStatusBn">maybeRefreshUserStatus()</button>
 </div>
 <div class="section">
   <h1>Demo Test Utils</h1>
diff --git a/chrome/test/data/webui/glic/test_client/page_element_types.ts b/chrome/test/data/webui/glic/test_client/page_element_types.ts
index a6127cc..4c61230 100644
--- a/chrome/test/data/webui/glic/test_client/page_element_types.ts
+++ b/chrome/test/data/webui/glic/test_client/page_element_types.ts
@@ -123,7 +123,6 @@
   setClosedCaptioningFalse: HTMLButtonElement;
   dropScrollToHighlightBtn: HTMLButtonElement;
   copyAPCToClipboardBtn: HTMLButtonElement;
-  maybeRefreshUserStatusBn: HTMLButtonElement;
 }
 
 export const $: PageElementTypes = new Proxy({}, {
diff --git a/chrome/test/data/webui/glic/test_client/test_client.ts b/chrome/test/data/webui/glic/test_client/test_client.ts
index 561bcaf..ba5e41f 100644
--- a/chrome/test/data/webui/glic/test_client/test_client.ts
+++ b/chrome/test/data/webui/glic/test_client/test_client.ts
@@ -190,16 +190,6 @@
   }
 });
 
-$.maybeRefreshUserStatusBn.addEventListener('click', async () => {
-  logMessage('Calling maybeRefreshUserStatus...');
-  try {
-    await getBrowser()!.maybeRefreshUserStatus!();
-    logMessage('maybeRefreshUserStatus done.');
-  } catch (e) {
-    logMessage(`maybeRefreshUserStatus failed: ${e}`);
-  }
-});
-
 window.addEventListener('load', () => {
   $.desktopScreenshot.addEventListener('click', async () => {
     logMessage('Requesting desktop screenshot...');
diff --git a/chrome/test/data/webui/settings/settings_browsertest.cc b/chrome/test/data/webui/settings/settings_browsertest.cc
index 59eec30..74a7454 100644
--- a/chrome/test/data/webui/settings/settings_browsertest.cc
+++ b/chrome/test/data/webui/settings/settings_browsertest.cc
@@ -522,8 +522,7 @@
 }
 #endif
 
-// TODO(crbug.com/40719198): Flaky on all OSes. Enable the test.
-IN_PROC_BROWSER_TEST_F(SettingsTest, DISABLED_ResetPage) {
+IN_PROC_BROWSER_TEST_F(SettingsTest, ResetPage) {
   RunTest("settings/reset_page_test.js", "mocha.run()");
 }
 
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 70e2c7d..bc420767 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-16317.0.0-1069542
\ No newline at end of file
+16317.0.0-1069550
\ No newline at end of file
diff --git a/chromeos/components/quick_answers/quick_answers_model.cc b/chromeos/components/quick_answers/quick_answers_model.cc
index 8863d798..f8b161d 100644
--- a/chromeos/components/quick_answers/quick_answers_model.cc
+++ b/chromeos/components/quick_answers/quick_answers_model.cc
@@ -65,10 +65,6 @@
 }
 
 bool PhoneticsInfo::TtsAudioAvailable() const {
-  if (!tts_audio_enabled) {
-    return false;
-  }
-
   return !query_text.empty() && !locale.empty();
 }
 
diff --git a/chromeos/components/quick_answers/quick_answers_model.h b/chromeos/components/quick_answers/quick_answers_model.h
index ea17afdb9..3dbe7f7 100644
--- a/chromeos/components/quick_answers/quick_answers_model.h
+++ b/chromeos/components/quick_answers/quick_answers_model.h
@@ -139,10 +139,6 @@
   // For other type of results the URL will be empty.
   GURL phonetics_audio;
 
-  // Set to true if tts audio (`query_text` and `locale`) can be used.
-  // TODO(b/346794579): remove this field.
-  bool tts_audio_enabled = false;
-
   // Query text and locale which will be used for tts if enabled and
   // there is no phonetics audio available.
   std::string query_text;
diff --git a/chromeos/components/quick_answers/quick_answers_model_unittest.cc b/chromeos/components/quick_answers/quick_answers_model_unittest.cc
index a406cd8..dc146cd 100644
--- a/chromeos/components/quick_answers/quick_answers_model_unittest.cc
+++ b/chromeos/components/quick_answers/quick_answers_model_unittest.cc
@@ -175,21 +175,8 @@
   EXPECT_FALSE(phonetics_info.TtsAudioAvailable());
 }
 
-TEST(PhoneticsInfoTest, HasTtsAudioButDisabled) {
-  PhoneticsInfo phonetics_info;
-  ASSERT_FALSE(phonetics_info.tts_audio_enabled)
-      << "tts_audio_enabled is false by default";
-  phonetics_info.locale = kPhoneticsInfoLocale;
-  phonetics_info.query_text = kPhoneticsInfoQueryText;
-
-  EXPECT_FALSE(phonetics_info.PhoneticsInfoAvailable());
-  EXPECT_FALSE(phonetics_info.AudioUrlAvailable());
-  EXPECT_FALSE(phonetics_info.TtsAudioAvailable());
-}
-
 TEST(PhoneticsInfoTest, TtsAudio) {
   PhoneticsInfo phonetics_info;
-  phonetics_info.tts_audio_enabled = true;
   phonetics_info.locale = kPhoneticsInfoLocale;
   phonetics_info.query_text = kPhoneticsInfoQueryText;
 
diff --git a/chromeos/components/quick_answers/search_result_parsers/definition_result_parser.cc b/chromeos/components/quick_answers/search_result_parsers/definition_result_parser.cc
index a5876b1..f5f09fb 100644
--- a/chromeos/components/quick_answers/search_result_parsers/definition_result_parser.cc
+++ b/chromeos/components/quick_answers/search_result_parsers/definition_result_parser.cc
@@ -418,8 +418,9 @@
   // Check if tts audio is enabled for the query.
   std::optional<bool> tts_audio_enabled =
       first_phonetics->FindBool(kPhoneticsTtsAudioEnabledKey);
-  if (tts_audio_enabled) {
-    phonetics_info->tts_audio_enabled = tts_audio_enabled.value();
+  if (tts_audio_enabled && !tts_audio_enabled.value()) {
+    phonetics_info->query_text.clear();
+    phonetics_info->locale.clear();
   }
   return phonetics_info;
 }
diff --git a/chromeos/components/quick_answers/search_result_parsers/definition_result_parser_unittest.cc b/chromeos/components/quick_answers/search_result_parsers/definition_result_parser_unittest.cc
index 5af75198..1858376 100644
--- a/chromeos/components/quick_answers/search_result_parsers/definition_result_parser_unittest.cc
+++ b/chromeos/components/quick_answers/search_result_parsers/definition_result_parser_unittest.cc
@@ -179,7 +179,6 @@
   EXPECT_EQ(definition_result->phonetics_info.locale, "en");
   EXPECT_EQ(definition_result->phonetics_info.phonetics_audio,
             GURL(kPhoneticsAudioUrlWithProtocol));
-  EXPECT_FALSE(definition_result->phonetics_info.tts_audio_enabled);
 
   EXPECT_EQ(definition_result->sense.definition, expected_answer);
 }
@@ -224,7 +223,6 @@
   EXPECT_EQ(definition_result->phonetics_info.locale, "en");
   EXPECT_EQ(definition_result->phonetics_info.phonetics_audio,
             GURL(kPhoneticsAudioUrlWithProtocol));
-  EXPECT_FALSE(definition_result->phonetics_info.tts_audio_enabled);
 
   EXPECT_EQ(
       definition_result->sense.definition,
diff --git a/chromeos/crosapi/mojom/BUILD.gn b/chromeos/crosapi/mojom/BUILD.gn
index f0aa206f..180251f7 100644
--- a/chromeos/crosapi/mojom/BUILD.gn
+++ b/chromeos/crosapi/mojom/BUILD.gn
@@ -14,7 +14,6 @@
     "cros_display_config.mojom",
     "crosapi.mojom",
     "desk_profiles.mojom",
-    "device_attributes.mojom",
     "diagnostics_service.mojom",
     "document_scan.mojom",
     "file_change_service_bridge.mojom",
diff --git a/chromeos/crosapi/mojom/crosapi.mojom b/chromeos/crosapi/mojom/crosapi.mojom
index 014dae9..c28001f 100644
--- a/chromeos/crosapi/mojom/crosapi.mojom
+++ b/chromeos/crosapi/mojom/crosapi.mojom
@@ -15,7 +15,6 @@
 import "chromeos/crosapi/mojom/clipboard_history.mojom";
 import "chromeos/crosapi/mojom/cros_display_config.mojom";
 import "chromeos/crosapi/mojom/desk_profiles.mojom";
-import "chromeos/crosapi/mojom/device_attributes.mojom";
 import "chromeos/crosapi/mojom/diagnostics_service.mojom";
 import "chromeos/crosapi/mojom/document_scan.mojom";
 import "chromeos/crosapi/mojom/file_change_service_bridge.mojom";
@@ -35,7 +34,6 @@
 import "chromeos/crosapi/mojom/print_preview_cros.mojom";
 import "chromeos/crosapi/mojom/probe_service.mojom";
 import "chromeos/crosapi/mojom/remoting.mojom";
-import "chromeos/crosapi/mojom/structured_metrics_service.mojom";
 import "chromeos/crosapi/mojom/telemetry_diagnostic_routine_service.mojom";
 import "chromeos/crosapi/mojom/telemetry_event_service.mojom";
 import "chromeos/crosapi/mojom/telemetry_management_service.mojom";
@@ -116,13 +114,7 @@
   // BindDesk@103 was removed.
   // BindDeskProfileObserver@124 was removed.
   // BindDeskTemplate@71 was removed.
-
-  // Binds the device attributes service which is used by enterprise extension
-  // APIs to query information about the device.
-  // Added in M89.
-  [MinVersion=12] BindDeviceAttributes@17(
-      pending_receiver<DeviceAttributes> receiver);
-
+  // BindDeviceAttributes@17 was removed.
   // BindDeviceOAuth2TokenService@95 was removed.
   // BindDeviceSettingsService@59 was removed.
 
@@ -261,13 +253,7 @@
   // BindSmartReaderClient@107 was removed.
   // BindSpeechRecognition@84 was removed.
   // BindStableVideoDecoderFactory@56 was removed.
-
-  // Binds the StructuredMetricsService interface to record events.
-  // Added in M96.
-  [MinVersion=48]
-  BindStructuredMetricsService@52(
-      pending_receiver<StructuredMetricsService> receiver);
-
+  // BindStructuredMetricsService@52 was removed.
   // BindSuggestionService@136 was removed.
   // BindTrustedVaultBackend@121 was removed.
   // BindTrustedVaultBackendService@145 was removed.
diff --git a/chromeos/crosapi/mojom/device_attributes.mojom b/chromeos/crosapi/mojom/device_attributes.mojom
deleted file mode 100644
index cd2985e..0000000
--- a/chromeos/crosapi/mojom/device_attributes.mojom
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// Next MinVersion: 2
-
-module crosapi.mojom;
-
-// Returned by methods that either return a string or an error.
-union DeviceAttributesStringResult {
-  // Implies failure.
-  string error_message;
-
-  // Implies success.
-  string contents;
-};
-
-// This API provides Lacros with access to device attributes. These methods will
-// all return an error if the user is not affiliated with the device, which is
-// an enterprise policy concept.
-[Uuid="117591ac-5d9e-481c-936f-842b64e790c0"]
-interface DeviceAttributes {
-  // Fetches the value of the device identifier of the directory API that is
-  // generated by the server and identifies the cloud record of the device for
-  // querying in the cloud directory API. See
-  // https://developers.google.com/admin-sdk/directory/v1/guides/manage-chrome-devices.
-  GetDirectoryDeviceId@0() => (DeviceAttributesStringResult result);
-
-  // Fetches the device's serial number.
-  GetDeviceSerialNumber@1() => (DeviceAttributesStringResult result);
-
-  // Fetches the administrator-annotated Asset Id.
-  GetDeviceAssetId@2() => (DeviceAttributesStringResult result);
-
-  // Fetches the administrator-annotated Location.
-  GetDeviceAnnotatedLocation@3() => (DeviceAttributesStringResult result);
-
-  // Fetches the device's hostname as set by DeviceHostnameTemplate policy.
-  GetDeviceHostname@4() => (DeviceAttributesStringResult result);
-
-  // Fetches the user type by device type segment for metrics. The user type
-  // and the device type are combined to construct device type segment for
-  // metrics via UserTypeByDeviceTypeMetricsProvider::ConstructUmaValue from
-  // the ash side. Though this value is not an enum it's version-skew stable
-  // as it's used by UKM(ChromeOS.WebsiteUsageTime) which already depends on
-  // version stability.
-  [MinVersion=1]
-  GetDeviceTypeForMetrics@5() => (int32 device_type);
-};
diff --git a/chromeos/crosapi/mojom/structured_metrics_service.mojom b/chromeos/crosapi/mojom/structured_metrics_service.mojom
index 5934cec3..4ac3b00 100644
--- a/chromeos/crosapi/mojom/structured_metrics_service.mojom
+++ b/chromeos/crosapi/mojom/structured_metrics_service.mojom
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// TODO(crbug.com/354842935): while this interface is originally designed
+// to be used as a part of crosapi, now it is used for the communication
+// with recorder_ui web app. Rework to make this turn into the dedicated
+// api for the communication, and update the build rules.
+
 module crosapi.mojom;
 
 import "components/metrics/structured/mojom/event.mojom";
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt
index e7ddfce2..20841108 100644
--- a/chromeos/profiles/atom.afdo.newest.txt
+++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-atom-139-7204.17-1749436011-benchmark-139.0.7230.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-atom-139-7204.17-1749436011-benchmark-139.0.7234.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt
index 24b66ec..f173ad1 100644
--- a/chromeos/profiles/bigcore.afdo.newest.txt
+++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-bigcore-139-7204.8-1749436445-benchmark-139.0.7230.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-bigcore-139-7204.8-1749436445-benchmark-139.0.7234.0-r1-redacted.afdo.xz
diff --git a/clank b/clank
index bce0ee1..495257e 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit bce0ee19815b3b46f811a323eafa5a89ea508d34
+Subproject commit 495257e25198d1739ddaddd2f1c63e98e0d107e5
diff --git a/components/autofill/core/browser/autofill_field.cc b/components/autofill/core/browser/autofill_field.cc
index 16af52a..bf09a78f 100644
--- a/components/autofill/core/browser/autofill_field.cc
+++ b/components/autofill/core/browser/autofill_field.cc
@@ -544,6 +544,12 @@
     // predictions get precedence over the server predictions.
     believe_server = believe_server && (heuristic_type_local != IBAN_VALUE);
 
+    // For loyalty card fields the heuristic predictions get precedence over
+    // `UNKNOWN_TYPE` server prediction.
+    believe_server =
+        believe_server && !(heuristic_type_local == LOYALTY_MEMBERSHIP_ID &&
+                            server_type_local == UNKNOWN_TYPE);
+
     if (believe_server) {
       return {AutofillType(server_type_local),
               AutofillPredictionSource::kServerCrowdsourcing};
diff --git a/components/autofill/core/browser/autofill_field_unittest.cc b/components/autofill/core/browser/autofill_field_unittest.cc
index d577abb8..5d7801e 100644
--- a/components/autofill/core/browser/autofill_field_unittest.cc
+++ b/components/autofill/core/browser/autofill_field_unittest.cc
@@ -456,6 +456,24 @@
             .heuristic_type = EMAIL_OR_LOYALTY_MEMBERSHIP_ID,
             .expected_result = EMAIL_OR_LOYALTY_MEMBERSHIP_ID,
             .expected_source = AutofillPredictionSource::kHeuristics},
+        AutofillLocalHeuristicsOverridesParams{
+            .html_field_type = HtmlFieldType::kUnrecognized,
+            .server_type = NO_SERVER_DATA,
+            .heuristic_type = LOYALTY_MEMBERSHIP_ID,
+            .expected_result = LOYALTY_MEMBERSHIP_ID,
+            .expected_source = AutofillPredictionSource::kHeuristics},
+        AutofillLocalHeuristicsOverridesParams{
+            .html_field_type = HtmlFieldType::kUnrecognized,
+            .server_type = UNKNOWN_TYPE,
+            .heuristic_type = LOYALTY_MEMBERSHIP_ID,
+            .expected_result = LOYALTY_MEMBERSHIP_ID,
+            .expected_source = AutofillPredictionSource::kHeuristics},
+        AutofillLocalHeuristicsOverridesParams{
+            .html_field_type = HtmlFieldType::kUnrecognized,
+            .server_type = PHONE_HOME_NUMBER,
+            .heuristic_type = LOYALTY_MEMBERSHIP_ID,
+            .expected_result = PHONE_HOME_NUMBER,
+            .expected_source = AutofillPredictionSource::kServerCrowdsourcing},
         // Test non-override behaviour.
         AutofillLocalHeuristicsOverridesParams{
             .html_field_type = HtmlFieldType::kStreetAddress,
diff --git a/components/autofill/core/browser/data_model/addresses/autofill_i18n_formatting_expressions.h b/components/autofill/core/browser/data_model/addresses/autofill_i18n_formatting_expressions.h
index 98f60b44..d946b40 100644
--- a/components/autofill/core/browser/data_model/addresses/autofill_i18n_formatting_expressions.h
+++ b/components/autofill/core/browser/data_model/addresses/autofill_i18n_formatting_expressions.h
@@ -41,7 +41,7 @@
       {{"FR", ADDRESS_HOME_STREET_ADDRESS}, u"${ADDRESS_HOME_STREET_LOCATION;;}\n${ADDRESS_HOME_OVERFLOW;;}"},
       {{"FR", ADDRESS_HOME_STREET_LOCATION}, u"${ADDRESS_HOME_HOUSE_NUMBER;;} ${ADDRESS_HOME_STREET_NAME;;}"},
       {{"IN", ADDRESS_HOME_ADDRESS}, u"${ADDRESS_HOME_STREET_LOCATION;;}\n${ADDRESS_HOME_DEPENDENT_LOCALITY;;}\n${ADDRESS_HOME_LANDMARK;;}\n${ADDRESS_HOME_CITY;;}\n${ADDRESS_HOME_STATE;;}\n${ADDRESS_HOME_ZIP;;}"},
-      {{"IN", ADDRESS_HOME_STREET_ADDRESS}, u"${ADDRESS_HOME_STREET_LOCATION;;}, ${ADDRESS_HOME_DEPENDENT_LOCALITY;;}\n${ADDRESS_HOME_LANDMARK;;}"},
+      {{"IN", ADDRESS_HOME_STREET_ADDRESS}, u"${ADDRESS_HOME_STREET_LOCATION_AND_LOCALITY;;}\n${ADDRESS_HOME_LANDMARK;;}"},
       {{"IN", ADDRESS_HOME_STREET_LOCATION_AND_LOCALITY}, u"${ADDRESS_HOME_STREET_LOCATION;;}, ${ADDRESS_HOME_DEPENDENT_LOCALITY;;}"},
       {{"IN", ADDRESS_HOME_DEPENDENT_LOCALITY_AND_LANDMARK}, u"${ADDRESS_HOME_DEPENDENT_LOCALITY;;}, ${ADDRESS_HOME_LANDMARK;;}"},
       {{"IN", ADDRESS_HOME_STREET_LOCATION_AND_LANDMARK}, u"${ADDRESS_HOME_STREET_LOCATION;;}, ${ADDRESS_HOME_LANDMARK;;}"},
diff --git a/components/autofill/core/browser/data_quality/validation_unittest.cc b/components/autofill/core/browser/data_quality/validation_unittest.cc
index b5d1d606..b6bb85d 100644
--- a/components/autofill/core/browser/data_quality/validation_unittest.cc
+++ b/components/autofill/core/browser/data_quality/validation_unittest.cc
@@ -8,6 +8,7 @@
 
 #include <string>
 
+#include "base/strings/utf_ostream_operators.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
diff --git a/components/autofill/core/browser/form_import/form_data_importer.cc b/components/autofill/core/browser/form_import/form_data_importer.cc
index a95392c..44b06df 100644
--- a/components/autofill/core/browser/form_import/form_data_importer.cc
+++ b/components/autofill/core/browser/form_import/form_data_importer.cc
@@ -850,10 +850,7 @@
           *extracted_credit_card, fetched_card_instrument_id_,
           card_was_fetched_from_cache_)) {
     virtual_card_enrollment_manager->InitVirtualCardEnroll(
-        *extracted_credit_card, VirtualCardEnrollmentSource::kDownstream,
-        base::BindOnce(
-            &VirtualCardEnrollmentManager::ShowVirtualCardEnrollBubble,
-            virtual_card_enrollment_manager->GetWeakPtr()));
+        *extracted_credit_card, VirtualCardEnrollmentSource::kDownstream);
     return true;
   }
 
diff --git a/components/autofill/core/browser/form_import/form_data_importer_unittest.cc b/components/autofill/core/browser/form_import/form_data_importer_unittest.cc
index 152eec4..6d1be2d3 100644
--- a/components/autofill/core/browser/form_import/form_data_importer_unittest.cc
+++ b/components/autofill/core/browser/form_import/form_data_importer_unittest.cc
@@ -496,13 +496,13 @@
       InitVirtualCardEnroll,
       (const CreditCard& credit_card,
        VirtualCardEnrollmentSource virtual_card_enrollment_source,
-       VirtualCardEnrollmentManager::VirtualCardEnrollmentFieldsLoadedCallback
-           virtual_card_enrollment_fields_loaded_callback,
        std::optional<payments::GetDetailsForEnrollmentResponseDetails>
            get_details_for_enrollment_response_details,
        PrefService* user_prefs,
        VirtualCardEnrollmentManager::RiskAssessmentFunction
-           risk_assessment_function),
+           risk_assessment_function,
+       VirtualCardEnrollmentManager::VirtualCardEnrollmentFieldsLoadedCallback
+           virtual_card_enrollment_fields_loaded_callback),
       (override));
 };
 
diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager_test_api.h b/components/autofill/core/browser/foundations/browser_autofill_manager_test_api.h
index c8eea9f..4f5e529 100644
--- a/components/autofill/core/browser/foundations/browser_autofill_manager_test_api.h
+++ b/components/autofill/core/browser/foundations/browser_autofill_manager_test_api.h
@@ -46,6 +46,11 @@
         .form_interactions_flow_id_for_test();
   }
 
+  FormInteractionsFlowId loyalty_card_form_interactions_flow_id() const {
+    return manager_->metrics_->loyalty_card_form_event_logger
+        .form_interactions_flow_id_for_test();
+  }
+
   autofill_metrics::CreditCardFormEventLogger* credit_card_form_event_logger() {
     return &manager_->metrics_->credit_card_form_event_logger;
   }
diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc b/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc
index 3746e2a..83166fc 100644
--- a/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/foundations/browser_autofill_manager_unittest.cc
@@ -85,6 +85,7 @@
 #include "components/autofill/core/browser/integrators/plus_addresses/mock_autofill_plus_address_delegate.h"
 #include "components/autofill/core/browser/metrics/form_events/form_events.h"
 #include "components/autofill/core/browser/metrics/log_event.h"
+#include "components/autofill/core/browser/metrics/ukm_metrics_test_utils.h"
 #include "components/autofill/core/browser/ml_model/autofill_ai/mock_autofill_ai_model_cache.h"
 #include "components/autofill/core/browser/ml_model/autofill_ai/mock_autofill_ai_model_executor.h"
 #include "components/autofill/core/browser/payments/amount_extraction_manager.h"
@@ -189,6 +190,7 @@
 using upload_contents_matchers::FieldsAre;
 using upload_contents_matchers::FormSignatureIs;
 using upload_contents_matchers::ObservedSubmissionIs;
+using UkmAutofillKeyMetricsType = ukm::builders::Autofill_KeyMetrics;
 
 constexpr Suggestion::Icon kAddressEntryIcon = Suggestion::Icon::kAccount;
 constexpr char kPlusAddress[] = "plus+remote@plus.plus";
@@ -2091,9 +2093,14 @@
 
   FormData form =
       test::GetFormData({.fields = {{.role = LOYALTY_MEMBERSHIP_ID}}});
+  form.set_main_frame_origin(
+      url::Origin::Create(GURL("https://example.test/")));
 
   FormsSeen({form});
   OnAskForValuesToFill(form, form.fields()[0]);
+  // This ensures that the event loggers are notified about suggestions shown.
+  external_delegate()->OnSuggestionsShown(external_delegate()->suggestions());
+  FormSubmitted(form);
 
   external_delegate()->CheckSuggestions(
       form.fields()[0].global_id(),
@@ -2103,6 +2110,32 @@
        Suggestion(l10n_util::GetStringUTF8(IDS_AUTOFILL_MANAGE_LOYALTY_CARDS),
                   "", Suggestion::Icon::kSettings,
                   SuggestionType::kManageLoyaltyCard)});
+
+  FormInteractionsFlowId flow_id =
+      test_api(manager()).loyalty_card_form_interactions_flow_id();
+
+  // Make sure key metrics are logged.
+  base::HistogramTester histogram_tester;
+  test_api(client().GetAutofillDriverFactory()).Reset(driver());
+  histogram_tester.ExpectBucketCount(
+      "Autofill.KeyMetrics.FillingReadiness.LoyaltyCard", 1, 1);
+  histogram_tester.ExpectBucketCount(
+      "Autofill.KeyMetrics.FillingAcceptance.LoyaltyCard", 0, 1);
+  histogram_tester.ExpectTotalCount(
+      "Autofill.KeyMetrics.FillingCorrectness.LoyaltyCard", 0);
+  histogram_tester.ExpectBucketCount(
+      "Autofill.KeyMetrics.FillingAssistance.LoyaltyCard", 0, 1);
+  autofill_metrics::VerifyUkm(
+      client().GetUkmRecorder(), form, UkmAutofillKeyMetricsType::kEntryName,
+      {{{UkmAutofillKeyMetricsType::kFillingReadinessName, 1},
+        {UkmAutofillKeyMetricsType::kFillingAcceptanceName, 0},
+        {UkmAutofillKeyMetricsType::kFillingAssistanceName, 0},
+        {UkmAutofillKeyMetricsType::kAutofillFillsName, 0},
+        {UkmAutofillKeyMetricsType::kFormElementUserModificationsName, 0},
+        {UkmAutofillKeyMetricsType::kFlowIdName, flow_id.value()},
+        {UkmAutofillKeyMetricsType::kFormTypesName,
+         AutofillMetrics::FormTypesToBitVector(
+             {FormTypeNameForLogging::kLoyaltyCardForm})}}});
 }
 
 // Tests that when both email and loyalty card suggestions are available, they
diff --git a/components/autofill/core/browser/metrics/form_events/loyalty_card_form_event_logger.cc b/components/autofill/core/browser/metrics/form_events/loyalty_card_form_event_logger.cc
index a70bdb46d..8af3984 100644
--- a/components/autofill/core/browser/metrics/form_events/loyalty_card_form_event_logger.cc
+++ b/components/autofill/core/browser/metrics/form_events/loyalty_card_form_event_logger.cc
@@ -28,6 +28,7 @@
   FieldType field_type = field.Type().GetStorableType();
   field_types_with_shown_suggestions_.erase(field_type);
   field_types_with_accepted_suggestions_.insert(field_type);
+  ++form_interaction_counts_.autofill_fills;
 }
 
 void LoyaltyCardFormEventLogger::RecordPollSuggestions() {}
diff --git a/components/autofill/core/browser/metrics/form_events/loyalty_card_form_event_logger_unittest.cc b/components/autofill/core/browser/metrics/form_events/loyalty_card_form_event_logger_unittest.cc
index c0dffc1c..295cc47f 100644
--- a/components/autofill/core/browser/metrics/form_events/loyalty_card_form_event_logger_unittest.cc
+++ b/components/autofill/core/browser/metrics/form_events/loyalty_card_form_event_logger_unittest.cc
@@ -8,13 +8,17 @@
 #include "components/autofill/core/browser/data_manager/valuables/valuables_data_manager_test_api.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/metrics/autofill_metrics_test_base.h"
+#include "components/autofill/core/browser/metrics/ukm_metrics_test_utils.h"
 #include "components/autofill/core/browser/test_utils/valuables_data_test_utils.h"
 #include "components/autofill/core/common/autofill_test_utils.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace autofill::autofill_metrics {
 
+using UkmAutofillKeyMetricsType = ukm::builders::Autofill_KeyMetrics;
 using test::CreateTestFormField;
+using ::testing::IsEmpty;
 
 // Parameterized test where the parameter indicates how far we went through
 // the funnel:
@@ -163,6 +167,8 @@
     SubmitForm(form);
   }
 
+  FormInteractionsFlowId flow_id =
+      test_api(autofill_manager()).loyalty_card_form_interactions_flow_id();
   ResetDriverToCommitMetrics();
 
   // Phase 2: Validate KeyMetrics expectations.
@@ -185,6 +191,19 @@
             LOYALTY_MEMBERSHIP_ID, /*suggestion_accepted=*/true),
         1);
 
+    VerifyUkm(
+        &test_ukm_recorder(), form, UkmAutofillKeyMetricsType::kEntryName,
+        {{{UkmAutofillKeyMetricsType::kFillingReadinessName, 1},
+          {UkmAutofillKeyMetricsType::kFillingAcceptanceName, 1},
+          {UkmAutofillKeyMetricsType::kFillingCorrectnessName, 1},
+          {UkmAutofillKeyMetricsType::kFillingAssistanceName, 1},
+          {UkmAutofillKeyMetricsType::kAutofillFillsName, 1},
+          {UkmAutofillKeyMetricsType::kFormElementUserModificationsName, 0},
+          {UkmAutofillKeyMetricsType::kFlowIdName, flow_id.value()},
+          {UkmAutofillKeyMetricsType::kFormTypesName,
+           AutofillMetrics::FormTypesToBitVector(
+               {FormTypeNameForLogging::kLoyaltyCardForm})}}});
+
   } else {
     histogram_tester.ExpectTotalCount(
         "Autofill.KeyMetrics.FillingReadiness.LoyaltyCard", 0);
@@ -200,6 +219,10 @@
         "Autofill.Autocomplete.Off.FillingAcceptance.LoyaltyCard", 0);
     histogram_tester.ExpectTotalCount(
         "Autofill.KeyMetrics.FillingAcceptance.GroupedByFocusedFieldType", 0);
+
+    EXPECT_THAT(test_ukm_recorder().GetEntriesByName(
+                    UkmAutofillKeyMetricsType::kEntryName),
+                IsEmpty());
   }
   if (user_accepted_suggestion) {
     histogram_tester.ExpectBucketCount(
@@ -250,6 +273,8 @@
                                               form_.fields()[0].global_id());
   SubmitForm(form_);
 
+  FormInteractionsFlowId flow_id =
+      test_api(autofill_manager()).loyalty_card_form_interactions_flow_id();
   ResetDriverToCommitMetrics();
 
   histogram_tester.ExpectBucketCount(
@@ -264,6 +289,16 @@
       "Autofill.KeyMetrics.FormSubmission.NotAutofilled.LoyaltyCard", 0);
   histogram_tester.ExpectTotalCount(
       "Autofill.KeyMetrics.FillingAcceptance.GroupedByFocusedFieldType", 0);
+
+  VerifyUkm(&test_ukm_recorder(), form_, UkmAutofillKeyMetricsType::kEntryName,
+            {{{UkmAutofillKeyMetricsType::kFillingReadinessName, 1},
+              {UkmAutofillKeyMetricsType::kFillingAssistanceName, 0},
+              {UkmAutofillKeyMetricsType::kAutofillFillsName, 0},
+              {UkmAutofillKeyMetricsType::kFormElementUserModificationsName, 0},
+              {UkmAutofillKeyMetricsType::kFlowIdName, flow_id.value()},
+              {UkmAutofillKeyMetricsType::kFormTypesName,
+               AutofillMetrics::FormTypesToBitVector(
+                   {FormTypeNameForLogging::kLoyaltyCardForm})}}});
 }
 
 // Validate Autofill.KeyMetrics.* in case the user does not accept a suggestion.
@@ -281,6 +316,8 @@
   SimulateUserChangedField(form_, form_.fields()[1]);
   SubmitForm(form_);
 
+  FormInteractionsFlowId flow_id =
+      test_api(autofill_manager()).loyalty_card_form_interactions_flow_id();
   ResetDriverToCommitMetrics();
 
   histogram_tester.ExpectBucketCount(
@@ -298,6 +335,17 @@
       GetBucketForAcceptanceMetricsGroupedByFieldType(
           field_types_[1], /*suggestion_accepted=*/false),
       1);
+
+  VerifyUkm(&test_ukm_recorder(), form_, UkmAutofillKeyMetricsType::kEntryName,
+            {{{UkmAutofillKeyMetricsType::kFillingReadinessName, 1},
+              {UkmAutofillKeyMetricsType::kFillingAcceptanceName, 0},
+              {UkmAutofillKeyMetricsType::kFillingAssistanceName, 0},
+              {UkmAutofillKeyMetricsType::kAutofillFillsName, 0},
+              {UkmAutofillKeyMetricsType::kFormElementUserModificationsName, 2},
+              {UkmAutofillKeyMetricsType::kFlowIdName, flow_id.value()},
+              {UkmAutofillKeyMetricsType::kFormTypesName,
+               AutofillMetrics::FormTypesToBitVector(
+                   {FormTypeNameForLogging::kLoyaltyCardForm})}}});
 }
 // Validate Autofill.KeyMetrics.* in case the user has to fix the filled data.
 TEST_F(LoyaltyCardFormEventLoggerBaseKeyMetricsTest, LogUserFixesFilledData) {
@@ -315,6 +363,8 @@
   SimulateUserChangedField(form_, form_.fields()[1]);
   SubmitForm(form_);
 
+  FormInteractionsFlowId flow_id =
+      test_api(autofill_manager()).loyalty_card_form_interactions_flow_id();
   ResetDriverToCommitMetrics();
 
   histogram_tester.ExpectBucketCount(
@@ -332,6 +382,18 @@
       GetBucketForAcceptanceMetricsGroupedByFieldType(
           field_types_[1], /*suggestion_accepted=*/true),
       1);
+
+  VerifyUkm(&test_ukm_recorder(), form_, UkmAutofillKeyMetricsType::kEntryName,
+            {{{UkmAutofillKeyMetricsType::kFillingReadinessName, 1},
+              {UkmAutofillKeyMetricsType::kFillingAcceptanceName, 1},
+              {UkmAutofillKeyMetricsType::kFillingCorrectnessName, 0},
+              {UkmAutofillKeyMetricsType::kFillingAssistanceName, 1},
+              {UkmAutofillKeyMetricsType::kAutofillFillsName, 1},
+              {UkmAutofillKeyMetricsType::kFormElementUserModificationsName, 1},
+              {UkmAutofillKeyMetricsType::kFlowIdName, flow_id.value()},
+              {UkmAutofillKeyMetricsType::kFormTypesName,
+               AutofillMetrics::FormTypesToBitVector(
+                   {FormTypeNameForLogging::kLoyaltyCardForm})}}});
 }
 
 // Validate Autofill.KeyMetrics.* in case the user fixes the filled data but
@@ -366,6 +428,10 @@
       "Autofill.KeyMetrics.FormSubmission.Autofilled.LoyaltyCard", 0, 1);
   histogram_tester.ExpectTotalCount(
       "Autofill.KeyMetrics.FillingAcceptance.GroupedByFocusedFieldType", 0);
+
+  EXPECT_THAT(test_ukm_recorder().GetEntriesByName(
+                  UkmAutofillKeyMetricsType::kEntryName),
+              IsEmpty());
 }
 
 }  // namespace autofill::autofill_metrics
diff --git a/components/autofill/core/browser/payments/credit_card_save_manager.cc b/components/autofill/core/browser/payments/credit_card_save_manager.cc
index 4ef09f68..7085ffe08 100644
--- a/components/autofill/core/browser/payments/credit_card_save_manager.cc
+++ b/components/autofill/core/browser/payments/credit_card_save_manager.cc
@@ -598,11 +598,9 @@
 
   if (auto* virtual_card_enrollment_manager =
       client_->GetPaymentsAutofillClient()->GetVirtualCardEnrollmentManager()) {
-    virtual_card_enrollment_manager->InitVirtualCardEnroll(
+    virtual_card_enrollment_manager
+      ->InitVirtualCardEnroll(
         credit_card, VirtualCardEnrollmentSource::kUpstream,
-        base::BindOnce(
-            &VirtualCardEnrollmentManager::ShowVirtualCardEnrollBubble,
-            virtual_card_enrollment_manager->GetWeakPtr()),
         std::move(get_details_for_enrollment_response_details));
   }
 }
diff --git a/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc b/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
index 8602c00b..e107614 100644
--- a/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
+++ b/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
@@ -315,13 +315,13 @@
       InitVirtualCardEnroll,
       (const CreditCard& credit_card,
        VirtualCardEnrollmentSource virtual_card_enrollment_source,
-       VirtualCardEnrollmentManager::VirtualCardEnrollmentFieldsLoadedCallback
-           virtual_card_enrollment_fields_loaded_callback,
        std::optional<payments::GetDetailsForEnrollmentResponseDetails>
            get_details_for_enrollment_response_details,
        PrefService* user_prefs,
        VirtualCardEnrollmentManager::RiskAssessmentFunction
-           risk_assessment_function),
+           risk_assessment_function,
+       VirtualCardEnrollmentManager::VirtualCardEnrollmentFieldsLoadedCallback
+           virtual_card_enrollment_fields_loaded_callback),
       (override));
 };
 
@@ -6801,7 +6801,7 @@
         .WillOnce(DoAll(
             SaveArg<0>(&arg_credit_card),
             SaveArg<1>(&arg_virtual_card_enrollment_source),
-            SaveArg<3>(&arg_get_details_for_enrollment_response_details)));
+            SaveArg<2>(&arg_get_details_for_enrollment_response_details)));
   }
   credit_card_save_manager_->set_upload_request_card(test::GetCreditCard());
   credit_card_save_manager_->OnDidUploadCard(
diff --git a/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.cc b/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.cc
index 158bdc5..6f4471bf 100644
--- a/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.cc
+++ b/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.cc
@@ -47,14 +47,11 @@
 
 void TestVirtualCardEnrollmentManager::Reset() {
   reset_called_ = true;
-  VirtualCardEnrollmentManager::Reset();
 }
 
-void TestVirtualCardEnrollmentManager::ShowVirtualCardEnrollBubble(
-    VirtualCardEnrollmentFields* virtual_card_enrollment_fields) {
+void TestVirtualCardEnrollmentManager::ShowVirtualCardEnrollBubble() {
   bubble_shown_ = true;
-  VirtualCardEnrollmentManager::ShowVirtualCardEnrollBubble(
-      virtual_card_enrollment_fields);
+  VirtualCardEnrollmentManager::ShowVirtualCardEnrollBubble();
 }
 
 void TestVirtualCardEnrollmentManager::
diff --git a/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h b/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h
index 68e050d..9e7004e 100644
--- a/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h
+++ b/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h
@@ -62,6 +62,13 @@
     autofill_client_ = autofill_client;
   }
 
+  void SetVirtualCardEnrollmentFieldsLoadedCallback(
+      VirtualCardEnrollmentFieldsLoadedCallback
+          virtual_card_enrollment_fields_loaded_callback) {
+    virtual_card_enrollment_fields_loaded_callback_ =
+        std::move(virtual_card_enrollment_fields_loaded_callback);
+  }
+
   void set_ignore_strike_database(bool ignore_strike_database) {
     ignore_strike_database_ = ignore_strike_database;
   }
@@ -80,8 +87,7 @@
       VirtualCardEnrollmentRequestType type,
       payments::PaymentsAutofillClient::PaymentsRpcResult result) override;
   void Reset() override;
-  void ShowVirtualCardEnrollBubble(
-      VirtualCardEnrollmentFields* virtual_card_enrollment_fields) override;
+  void ShowVirtualCardEnrollBubble() override;
 
   void OnVirtualCardEnrollmentBubbleCancelled();
 
diff --git a/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc b/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc
index 804aa8f..df170b4 100644
--- a/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc
+++ b/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc
@@ -98,12 +98,12 @@
 void VirtualCardEnrollmentManager::InitVirtualCardEnroll(
     const CreditCard& credit_card,
     VirtualCardEnrollmentSource virtual_card_enrollment_source,
-    VirtualCardEnrollmentFieldsLoadedCallback
-        virtual_card_enrollment_fields_loaded_callback,
     std::optional<payments::GetDetailsForEnrollmentResponseDetails>
         get_details_for_enrollment_response_details,
     PrefService* user_prefs,
-    RiskAssessmentFunction risk_assessment_function) {
+    RiskAssessmentFunction risk_assessment_function,
+    VirtualCardEnrollmentFieldsLoadedCallback
+        virtual_card_enrollment_fields_loaded_callback) {
   if (base::FeatureList::IsEnabled(
           features::
               kAutofillEnableMultipleRequestInVirtualCardDownstreamEnrollment)) {
@@ -128,10 +128,6 @@
   SetInitialVirtualCardEnrollFields(credit_card,
                                     virtual_card_enrollment_source);
 
-  CHECK(virtual_card_enrollment_fields_loaded_callback);
-  virtual_card_enrollment_fields_loaded_callback_ =
-      std::move(virtual_card_enrollment_fields_loaded_callback);
-
   if (get_details_for_enrollment_response_details.has_value() &&
       IsValidGetDetailsForEnrollmentResponseDetails(
           get_details_for_enrollment_response_details.value())) {
@@ -142,9 +138,12 @@
   // |autofill_client_| being nullptr denotes that we are in the Clank settings
   // page virtual card enrollment use case, so we will need to use
   // |risk_assessment_function_| to load risk data as we do not have access to
-  // web contents.
+  // web contents, and |virtual_card_enrollment_fields_loaded_callback_| to
+  // display the UI.
   if (!autofill_client_) {
     risk_assessment_function_ = std::move(risk_assessment_function);
+    virtual_card_enrollment_fields_loaded_callback_ =
+        std::move(virtual_card_enrollment_fields_loaded_callback);
   }
 
   LoadRiskDataAndContinueFlow(
@@ -280,9 +279,8 @@
 void VirtualCardEnrollmentManager::
     AddStrikeToBlockOfferingVirtualCardEnrollment(
         const std::string& instrument_id) {
-  if (!GetVirtualCardEnrollmentStrikeDatabase()) {
+  if (!GetVirtualCardEnrollmentStrikeDatabase())
     return;
-  }
 
   GetVirtualCardEnrollmentStrikeDatabase()->AddStrike(instrument_id);
 
@@ -296,9 +294,8 @@
 void VirtualCardEnrollmentManager::
     RemoveAllStrikesToBlockOfferingVirtualCardEnrollment(
         const std::string& instrument_id) {
-  if (!GetVirtualCardEnrollmentStrikeDatabase()) {
+  if (!GetVirtualCardEnrollmentStrikeDatabase())
     return;
-  }
 
   // Before we remove the existing strikes for the card, log the strike number
   // first.
@@ -315,29 +312,6 @@
           VIRTUAL_CARD_ENROLLMENT_STRIKE_DATABASE_STRIKES_CLEARED);
 }
 
-void VirtualCardEnrollmentManager::ShowVirtualCardEnrollBubble(
-    VirtualCardEnrollmentFields* virtual_card_enrollment_fields) {
-  CHECK(autofill_client_);
-  LogUiLatencyMetrics();
-
-  autofill_client_->GetPaymentsAutofillClient()->ShowVirtualCardEnrollDialog(
-      *virtual_card_enrollment_fields,
-      base::BindOnce(
-          &VirtualCardEnrollmentManager::Enroll, weak_ptr_factory_.GetWeakPtr(),
-          /*virtual_card_enrollment_update_response_callback=*/
-          base::BindOnce(
-              &VirtualCardEnrollmentManager::OnVirtualCardEnrollCompleted,
-              weak_ptr_factory_.GetWeakPtr())),
-      base::BindOnce(
-          &VirtualCardEnrollmentManager::OnVirtualCardEnrollmentBubbleCancelled,
-          weak_ptr_factory_.GetWeakPtr()));
-}
-
-base::WeakPtr<VirtualCardEnrollmentManager>
-VirtualCardEnrollmentManager::GetWeakPtr() {
-  return weak_ptr_factory_.GetWeakPtr();
-}
-
 void VirtualCardEnrollmentManager::SetSaveCardBubbleAcceptedTimestamp(
     base::Time save_card_bubble_accepted_timestamp) {
   save_card_bubble_accepted_timestamp_ =
@@ -415,6 +389,23 @@
   }
 }
 
+void VirtualCardEnrollmentManager::ShowVirtualCardEnrollBubble() {
+  DCHECK(autofill_client_);
+  LogUiLatencyMetrics();
+
+  autofill_client_->GetPaymentsAutofillClient()->ShowVirtualCardEnrollDialog(
+      state_.virtual_card_enrollment_fields,
+      base::BindOnce(
+          &VirtualCardEnrollmentManager::Enroll, weak_ptr_factory_.GetWeakPtr(),
+          /*virtual_card_enrollment_update_response_callback=*/
+          base::BindOnce(
+              &VirtualCardEnrollmentManager::OnVirtualCardEnrollCompleted,
+              weak_ptr_factory_.GetWeakPtr())),
+      base::BindOnce(
+          &VirtualCardEnrollmentManager::OnVirtualCardEnrollmentBubbleCancelled,
+          weak_ptr_factory_.GetWeakPtr()));
+}
+
 void VirtualCardEnrollmentManager::OnVirtualCardEnrollmentBubbleCancelled() {
     AddStrikeToBlockOfferingVirtualCardEnrollment(base::NumberToString(
         state_.virtual_card_enrollment_fields.credit_card.instrument_id()));
@@ -437,8 +428,8 @@
     // card art image is set to then display in the bubble.
     EnsureCardArtImageIsSetBeforeShowingUI();
 
-    std::move(virtual_card_enrollment_fields_loaded_callback_)
-        .Run(&state_.virtual_card_enrollment_fields);
+    // Shows the virtual card enroll bubble.
+    ShowVirtualCardEnrollBubble();
   } else {
     // We are not in the upstream case where we received the
     // GetDetailsForEnrollmentResponseDetails in the UploadCardResponseDetails,
@@ -518,8 +509,16 @@
   // card art image is set to then display in the bubble.
   EnsureCardArtImageIsSetBeforeShowingUI();
 
-  std::move(virtual_card_enrollment_fields_loaded_callback_)
-      .Run(&state_.virtual_card_enrollment_fields);
+  if (autofill_client_) {
+    ShowVirtualCardEnrollBubble();
+  } else {
+    // If the |autofill_client_| is not present, it means that the request is
+    // from Android settings page, thus run the callback with the
+    // |virtual_card_enrollment_fields_|, which would show the enrollment
+    // dialog.
+    std::move(virtual_card_enrollment_fields_loaded_callback_)
+        .Run(&state_.virtual_card_enrollment_fields);
+  }
 }
 
 void VirtualCardEnrollmentManager::SetGetDetailsForEnrollmentResponseDetails(
diff --git a/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h b/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h
index 850aa56..87f6a388 100644
--- a/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h
+++ b/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h
@@ -129,19 +129,15 @@
       std::optional<int64_t> fetched_card_instrument_id,
       std::optional<bool> card_unmasked_from_cache);
 
-  // Starting point for the VCN enroll flow. The fields in `credit_card` will
+  // Starting point for the VCN enroll flow. The fields in |credit_card| will
   // be used throughout the flow, such as for request fields as well as credit
   // card specific fields for the bubble to display.
-  // `virtual_card_enrollment_source` will be used by
-  // `virtual_card_enrollment_update_response_callback_` to differentiate
-  // different bubbles based on the source we originated from.
+  // |virtual_card_enrollment_source| will be used by
+  // ShowVirtualCardEnrollBubble() to differentiate different bubbles based on
+  // the source we originated from.
   virtual void InitVirtualCardEnroll(
       const CreditCard& credit_card,
       VirtualCardEnrollmentSource virtual_card_enrollment_source,
-      // Callback that be run once the `state_.virtual_card_enrollment_fields_`
-      // is loaded from the server response.
-      VirtualCardEnrollmentFieldsLoadedCallback
-          virtual_card_enrollment_fields_loaded_callback,
       // |get_details_for_enrollment_response_details| will be populated if we
       // are in the optimized upstream case, where we receive the
       // GetDetailsForEnrollmentResponseDetails from the
@@ -158,7 +154,11 @@
       // will take in a |callback|, |obfuscated_gaia_id|, and |user_prefs| that
       // will end up being passed into the overloaded risk_util::LoadRiskData()
       // call that does not require web contents.
-      RiskAssessmentFunction risk_assessment_function = base::DoNothing());
+      RiskAssessmentFunction risk_assessment_function = base::DoNothing(),
+      // Callback that be run once the `state_.virtual_card_enrollment_fields_`
+      // is loaded from the server response. The callback would trigger the
+      // enrollment dialog in the Settings page on Android.
+      VirtualCardEnrollmentFieldsLoadedCallback = base::DoNothing());
 
   // Uses `payments_network_interface_` to send the enroll request. `state_`'s
   // `vcn_context_token_`, which should be set when we receive the
@@ -196,14 +196,6 @@
   void RemoveAllStrikesToBlockOfferingVirtualCardEnrollment(
       const std::string& instrument_id);
 
-  // Shows the VirtualCardEnrollmentBubble.
-  // `virtual_card_enrollment_fields` will contain all of the dynamic fields
-  // VirtualCardEnrollmentBubbleController needs to display the correct bubble.
-  virtual void ShowVirtualCardEnrollBubble(
-      VirtualCardEnrollmentFields* virtual_card_enrollment_fields);
-
-  base::WeakPtr<VirtualCardEnrollmentManager> GetWeakPtr();
-
   // Clears the strikes on the associated virtual card enrollment strike
   // database.
   void ClearAllStrikesForTesting();
@@ -259,8 +251,14 @@
       PrefService* user_prefs,
       base::OnceCallback<void(const std::string&)> callback);
 
+  // Shows the VirtualCardEnrollmentBubble. |state_|'s
+  // |virtual_card_enrollment_fields| will contain all of the dynamic fields
+  // VirtualCardEnrollmentBubbleController needs to display the correct bubble.
+  virtual void ShowVirtualCardEnrollBubble();
+
   // Callback triggered after the VirtualCardEnrollmentFields are loaded from
-  // the server response.
+  // the server response. Note: This is only called when the `autofill_client_`
+  // is not available.
   VirtualCardEnrollmentFieldsLoadedCallback
       virtual_card_enrollment_fields_loaded_callback_;
 
@@ -308,8 +306,7 @@
   // GetDetailsForEnrollRequest, and will be used by
   // `payments_network_interface_`. `state_`'s
   // `virtual_card_enrollment_fields_`'s `virtual_card_enrollment_source` is
-  // passed here so that it can be forwarded to the
-  // `virtual_card_enrollment_fields_loaded_callback_`.
+  // passed here so that it can be forwarded to ShowVirtualCardEnrollBubble.
   void GetDetailsForEnroll();
 
   // Handles the response from the GetDetailsForEnrollRequest. |result| and
@@ -350,11 +347,8 @@
   // enrollment from the settings page.
   void LogUiLatencyMetrics();
 
+  FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest, Enroll);
   FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest,
-                           Metrics_LatencySinceUpstream);
-  FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest,
-                           Metrics_LatencySinceDownstream);
-  FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerParamTest,
                            OnDidGetDetailsForEnrollResponse);
   FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest,
                            OnDidGetDetailsForEnrollResponse_NoAutofillClient);
diff --git a/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc b/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc
index 55c1dd1d..c57fc37 100644
--- a/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc
+++ b/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc
@@ -18,7 +18,6 @@
 #include "components/autofill/core/browser/foundations/test_autofill_driver.h"
 #include "components/autofill/core/browser/metrics/autofill_metrics.h"
 #include "components/autofill/core/browser/metrics/payments/virtual_card_enrollment_metrics.h"
-#include "components/autofill/core/browser/payments/multiple_request_payments_network_interface_base.h"
 #include "components/autofill/core/browser/payments/payments_autofill_client.h"
 #include "components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.h"
 #include "components/autofill/core/browser/payments/payments_util.h"
@@ -70,7 +69,6 @@
         std::make_unique<TestVirtualCardEnrollmentManager>(
             &payments_data_manager(), &payments_network_interface(),
             autofill_client_.get());
-    SetUpCard();
   }
 
   void SetUpCard() {
@@ -107,10 +105,15 @@
       const TestLegalMessageLine& issuer_legal_message,
       bool make_image_present) {
     payments_data_manager().ClearCachedImages();
+    SetUpCard();
+    auto* state = virtual_card_enrollment_manager_
+                      ->GetVirtualCardEnrollmentProcessState();
     if (make_image_present) {
-      CHECK(card_);
       SetValidCardArtImageForCard(*card_);
+    } else {
+      state->virtual_card_enrollment_fields.card_art_image = nullptr;
     }
+    state->virtual_card_enrollment_fields.credit_card = *card_;
 
     payments::GetDetailsForEnrollmentResponseDetails response;
     response.vcn_context_token = kTestVcnContextToken;
@@ -122,18 +125,25 @@
   // TODO(crbug.com/303715506): This part does not test the desired behavior on
   // iOS as the virtual card enrollment strikedatabase on iOS is not initialized
   // (guarded by the feature flag).
-  // Strike database tests bypass the InitVirtualCardEnroll call. Hence set the
-  // VirtualCardEnrollmentProcessState specifically.
   void SetUpStrikeDatabaseTest() {
     VirtualCardEnrollmentProcessState* state =
         virtual_card_enrollment_manager_
             ->GetVirtualCardEnrollmentProcessState();
     state->vcn_context_token = kTestVcnContextToken;
+    SetUpCard();
     state->virtual_card_enrollment_fields.credit_card = *card_;
-    state->virtual_card_enrollment_fields.virtual_card_enrollment_source =
-        VirtualCardEnrollmentSource::kDownstream;
     payments_data_manager().SetPaymentsCustomerData(
         std::make_unique<PaymentsCustomerData>("123456"));
+    EXPECT_FALSE(
+        virtual_card_enrollment_manager_->ShouldBlockVirtualCardEnrollment(
+            base::NumberToString(state->virtual_card_enrollment_fields
+                                     .credit_card.instrument_id()),
+            VirtualCardEnrollmentSource::kUpstream));
+    EXPECT_FALSE(
+        virtual_card_enrollment_manager_->ShouldBlockVirtualCardEnrollment(
+            base::NumberToString(state->virtual_card_enrollment_fields
+                                     .credit_card.instrument_id()),
+            VirtualCardEnrollmentSource::kDownstream));
   }
 
  protected:
@@ -162,9 +172,55 @@
   std::unique_ptr<CreditCard> card_;
 };
 
+TEST_F(VirtualCardEnrollmentManagerTest, InitVirtualCardEnroll) {
+  for (VirtualCardEnrollmentSource virtual_card_enrollment_source :
+       {VirtualCardEnrollmentSource::kUpstream,
+        VirtualCardEnrollmentSource::kDownstream,
+        VirtualCardEnrollmentSource::kSettingsPage}) {
+    for (bool make_image_present : {true, false}) {
+      SCOPED_TRACE(testing::Message()
+                   << " virtual_card_enrollment_source="
+                   << static_cast<int>(virtual_card_enrollment_source)
+                   << ", make_image_present=" << make_image_present);
+      payments_data_manager().ClearCachedImages();
+      SetUpCard();
+      auto* state = virtual_card_enrollment_manager_
+                        ->GetVirtualCardEnrollmentProcessState();
+      state->risk_data.reset();
+      state->virtual_card_enrollment_fields.card_art_image = nullptr;
+      if (make_image_present)
+        SetValidCardArtImageForCard(*card_);
+#if BUILDFLAG(IS_ANDROID)
+      virtual_card_enrollment_manager_->SetAutofillClient(nullptr);
+#endif
+
+      virtual_card_enrollment_manager_->InitVirtualCardEnroll(
+          *card_, virtual_card_enrollment_source, std::nullopt,
+          virtual_card_enrollment_manager_->AutofillClientIsPresent()
+              ? user_prefs()
+              : nullptr,
+          base::DoNothing());
+
+      // CreditCard class overloads equality operator to check that GUIDs,
+      // origins, and the contents of the two cards are equal.
+      EXPECT_EQ(*card_, state->virtual_card_enrollment_fields.credit_card);
+      EXPECT_EQ(
+          make_image_present,
+          state->virtual_card_enrollment_fields.card_art_image != nullptr);
+      EXPECT_TRUE(state->risk_data.has_value());
+
+      // Reset to avoid that state keeps track of card art images that will be
+      // invalidated at the start of the next loop.
+      virtual_card_enrollment_manager_
+          ->ResetVirtualCardEnrollmentProcessState();
+    }
+  }
+}
+
 TEST_F(VirtualCardEnrollmentManagerTest,
        InitVirtualCardEnroll_GetDetailsForEnrollmentResponseReceived) {
   payments_data_manager().ClearCachedImages();
+  SetUpCard();
   auto* state =
       virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState();
   state->risk_data.reset();
@@ -185,7 +241,7 @@
       get_details_for_enrollment_response_details_optional =
           get_details_for_enrollment_response_details;
   virtual_card_enrollment_manager_->InitVirtualCardEnroll(
-      *card_, VirtualCardEnrollmentSource::kUpstream, base::DoNothing(),
+      *card_, VirtualCardEnrollmentSource::kUpstream,
       get_details_for_enrollment_response_details_optional);
 
   // CreditCard class overloads equality operator to check that GUIDs,
@@ -210,6 +266,7 @@
       virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState();
   state->virtual_card_enrollment_fields.virtual_card_enrollment_source =
       VirtualCardEnrollmentSource::kUpstream;
+  SetUpCard();
   state->virtual_card_enrollment_fields.credit_card = *card_;
   state->risk_data.reset();
 
@@ -233,7 +290,99 @@
       /*sample=*/true, 1);
 }
 
-#if BUILDFLAG(IS_ANDROID)
+TEST_F(VirtualCardEnrollmentManagerTest, OnDidGetDetailsForEnrollResponse) {
+  base::HistogramTester histogram_tester;
+  const TestLegalMessageLine google_legal_message =
+      TestLegalMessageLine("google_test_legal_message");
+  const TestLegalMessageLine issuer_legal_message =
+      TestLegalMessageLine("issuer_test_legal_message");
+  for (VirtualCardEnrollmentSource source :
+       {VirtualCardEnrollmentSource::kUpstream,
+        VirtualCardEnrollmentSource::kDownstream,
+        VirtualCardEnrollmentSource::kSettingsPage}) {
+// TODO(crbug.com/40223706): Makes the following test
+// PersonalDataManagerTest.AddUpdateRemoveCreditCards fail on iOS.
+// That other test fails when SetNetworkImageInResourceBundle is called here.
+#if BUILDFLAG(IS_IOS)
+    for (bool make_image_present : {true}) {
+#else
+    for (bool make_image_present : {true, false}) {
+#endif  // BUILDFLAG(IS_IOS)
+      virtual_card_enrollment_manager_
+          ->get_details_for_enrollment_request_sent_timestamp_ =
+          base::Time::Now();
+      payments::GetDetailsForEnrollmentResponseDetails response =
+          std::move(SetUpOnDidGetDetailsForEnrollResponse(
+              google_legal_message, issuer_legal_message, make_image_present));
+      auto* state = virtual_card_enrollment_manager_
+                        ->GetVirtualCardEnrollmentProcessState();
+      state->virtual_card_enrollment_fields.virtual_card_enrollment_source =
+          source;
+
+      NiceMock<ui::MockResourceBundleDelegate> delegate;
+      std::unique_ptr<ui::ResourceBundle::SharedInstanceSwapperForTesting>
+          resource_bundle_swapper;
+
+      gfx::Image network_image;
+      if (!make_image_present) {
+        network_image = gfx::test::CreateImage(32, 30);
+        resource_bundle_swapper = std::make_unique<
+            ui::ResourceBundle::SharedInstanceSwapperForTesting>();
+        SetNetworkImageInResourceBundle(
+            &delegate,
+            state->virtual_card_enrollment_fields.credit_card.network(),
+            network_image);
+      }
+
+      task_environment_.FastForwardBy(base::Milliseconds(5));
+
+      virtual_card_enrollment_manager_->OnDidGetDetailsForEnrollResponse(
+          payments::PaymentsAutofillClient::PaymentsRpcResult::kSuccess,
+          response);
+
+      EXPECT_TRUE(state->vcn_context_token.has_value());
+      EXPECT_EQ(state->vcn_context_token, response.vcn_context_token);
+      VirtualCardEnrollmentFields virtual_card_enrollment_fields =
+          virtual_card_enrollment_manager_
+              ->GetVirtualCardEnrollmentProcessState()
+              ->virtual_card_enrollment_fields;
+      EXPECT_TRUE(
+          virtual_card_enrollment_fields.google_legal_message[0].text() ==
+          google_legal_message.text());
+      EXPECT_TRUE(
+          virtual_card_enrollment_fields.issuer_legal_message[0].text() ==
+          issuer_legal_message.text());
+
+      // The |card_art_image| should always be present. If there is no card art
+      // image available, it should be set to the network image.
+      EXPECT_TRUE(virtual_card_enrollment_fields.card_art_image != nullptr);
+      if (!make_image_present) {
+        EXPECT_TRUE(
+            virtual_card_enrollment_fields.card_art_image->BackedBySameObjectAs(
+                network_image.AsImageSkia()));
+      }
+      histogram_tester.ExpectUniqueSample(
+          "Autofill.VirtualCard.GetDetailsForEnrollment.Result." +
+              VirtualCardEnrollmentSourceToMetricSuffix(source),
+          /*sample=*/true, make_image_present ? 1 : 2);
+      histogram_tester.ExpectBucketCount(
+          "Autofill.VirtualCard.GetDetailsForEnrollment.Latency." +
+              VirtualCardEnrollmentSourceToMetricSuffix(source) +
+              PaymentsRpcResultToMetricsSuffix(
+                  payments::PaymentsAutofillClient::PaymentsRpcResult::
+                      kSuccess),
+          /*sample=*/5, make_image_present ? 1 : 2);
+
+      // Avoid dangling pointers to artwork.
+      virtual_card_enrollment_manager_
+          ->ResetVirtualCardEnrollmentProcessState();
+      if (!make_image_present) {
+        ui::ResourceBundle::CleanupSharedInstance();
+      }
+    }
+  }
+}
+
 TEST_F(VirtualCardEnrollmentManagerTest,
        OnDidGetDetailsForEnrollResponse_NoAutofillClient) {
   base::HistogramTester histogram_tester;
@@ -245,20 +394,22 @@
       std::move(SetUpOnDidGetDetailsForEnrollResponse(
           google_legal_message, issuer_legal_message,
           /*make_image_present=*/true));
+  auto* state =
+      virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState();
+  state->virtual_card_enrollment_fields.virtual_card_enrollment_source =
+      VirtualCardEnrollmentSource::kSettingsPage;
+
   virtual_card_enrollment_manager_->SetAutofillClient(nullptr);
   base::MockCallback<TestVirtualCardEnrollmentManager::
                          VirtualCardEnrollmentFieldsLoadedCallback>
       virtual_card_enrollment_fields_loaded_callback;
-
+  virtual_card_enrollment_manager_
+      ->SetVirtualCardEnrollmentFieldsLoadedCallback(
+          virtual_card_enrollment_fields_loaded_callback.Get());
   EXPECT_CALL(virtual_card_enrollment_fields_loaded_callback, Run(_));
-  virtual_card_enrollment_manager_->InitVirtualCardEnroll(
-      *card_, VirtualCardEnrollmentSource::kSettingsPage,
-      virtual_card_enrollment_fields_loaded_callback.Get());
   virtual_card_enrollment_manager_->OnDidGetDetailsForEnrollResponse(
       payments::PaymentsAutofillClient::PaymentsRpcResult::kSuccess, response);
 
-  auto* state =
-      virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState();
   EXPECT_TRUE(state->vcn_context_token.has_value());
   EXPECT_EQ(state->vcn_context_token, response.vcn_context_token);
   VirtualCardEnrollmentFields virtual_card_enrollment_fields =
@@ -273,31 +424,27 @@
       "Autofill.VirtualCard.GetDetailsForEnrollment.Result.SettingsPage",
       /*sample=*/true, 1);
 }
-#endif
 
 TEST_F(VirtualCardEnrollmentManagerTest,
        OnDidGetDetailsForEnrollResponse_Reset) {
   base::HistogramTester histogram_tester;
-  // Ignore strike database to avoid its required delay cooldown.
-  virtual_card_enrollment_manager_->set_ignore_strike_database(true);
-
+  auto* state =
+      virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState();
+  state->virtual_card_enrollment_fields.virtual_card_enrollment_source =
+      VirtualCardEnrollmentSource::kSettingsPage;
   for (payments::PaymentsAutofillClient::PaymentsRpcResult result :
        {payments::PaymentsAutofillClient::PaymentsRpcResult::
             kVcnRetrievalTryAgainFailure,
         payments::PaymentsAutofillClient::PaymentsRpcResult::
             kVcnRetrievalPermanentFailure}) {
-    virtual_card_enrollment_manager_->InitVirtualCardEnroll(
-        *card_, VirtualCardEnrollmentSource::kDownstream, base::DoNothing());
     virtual_card_enrollment_manager_->SetResetCalled(false);
+
     virtual_card_enrollment_manager_->OnDidGetDetailsForEnrollResponse(
         result, payments::GetDetailsForEnrollmentResponseDetails());
+
     EXPECT_TRUE(virtual_card_enrollment_manager_->GetResetCalled());
   }
-  histogram_tester.ExpectUniqueSample(
-      "Autofill.VirtualCard.GetDetailsForEnrollment.Result.Downstream",
-      /*sample=*/false, 2);
 
-#if BUILDFLAG(IS_ANDROID)
   // Ensure the clank settings page use-case works as expected.
   virtual_card_enrollment_manager_->SetAutofillClient(nullptr);
   for (payments::PaymentsAutofillClient::PaymentsRpcResult result :
@@ -305,17 +452,96 @@
             kVcnRetrievalTryAgainFailure,
         payments::PaymentsAutofillClient::PaymentsRpcResult::
             kVcnRetrievalPermanentFailure}) {
-    virtual_card_enrollment_manager_->InitVirtualCardEnroll(
-        *card_, VirtualCardEnrollmentSource::kSettingsPage, base::DoNothing());
     virtual_card_enrollment_manager_->SetResetCalled(false);
+
     virtual_card_enrollment_manager_->OnDidGetDetailsForEnrollResponse(
         result, payments::GetDetailsForEnrollmentResponseDetails());
+
     EXPECT_TRUE(virtual_card_enrollment_manager_->GetResetCalled());
   }
   histogram_tester.ExpectUniqueSample(
       "Autofill.VirtualCard.GetDetailsForEnrollment.Result.SettingsPage",
-      /*sample=*/false, 2);
-#endif
+      /*sample=*/false, 4);
+}
+
+TEST_F(VirtualCardEnrollmentManagerTest, Enroll) {
+  VirtualCardEnrollmentProcessState* state =
+      virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState();
+  state->vcn_context_token = kTestVcnContextToken;
+  SetUpCard();
+  SetValidCardArtImageForCard(*card_);
+  payments_data_manager().SetPaymentsCustomerData(
+      std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456"));
+
+  for (VirtualCardEnrollmentSource virtual_card_enrollment_source :
+       {VirtualCardEnrollmentSource::kUpstream,
+        VirtualCardEnrollmentSource::kDownstream,
+        VirtualCardEnrollmentSource::kSettingsPage}) {
+    base::HistogramTester histogram_tester;
+    SCOPED_TRACE(testing::Message()
+                 << " virtual_card_enrollment_source="
+                 << static_cast<int>(virtual_card_enrollment_source));
+    state->virtual_card_enrollment_fields.virtual_card_enrollment_source =
+        virtual_card_enrollment_source;
+    virtual_card_enrollment_manager_->SetPaymentsRpcResult(
+        payments::PaymentsAutofillClient::PaymentsRpcResult::kNone);
+
+    payments_network_interface().set_update_virtual_card_enrollment_result(
+        payments::PaymentsAutofillClient::PaymentsRpcResult::kSuccess);
+    virtual_card_enrollment_manager_->Enroll(
+        /*virtual_card_enrollment_update_response_callback=*/std::nullopt);
+
+    payments::UpdateVirtualCardEnrollmentRequestDetails request_details =
+        payments_network_interface()
+            .update_virtual_card_enrollment_request_details();
+    EXPECT_TRUE(request_details.vcn_context_token.has_value());
+    EXPECT_EQ(request_details.vcn_context_token, kTestVcnContextToken);
+    EXPECT_EQ(request_details.virtual_card_enrollment_source,
+              virtual_card_enrollment_source);
+    EXPECT_EQ(request_details.virtual_card_enrollment_request_type,
+              VirtualCardEnrollmentRequestType::kEnroll);
+    EXPECT_EQ(request_details.billing_customer_number, 123456);
+    EXPECT_EQ(virtual_card_enrollment_manager_->GetPaymentsRpcResult(),
+              payments::PaymentsAutofillClient::PaymentsRpcResult::kSuccess);
+
+    std::string suffix;
+    switch (virtual_card_enrollment_source) {
+      case VirtualCardEnrollmentSource::kUpstream:
+        suffix = "Upstream";
+        break;
+      case VirtualCardEnrollmentSource::kDownstream:
+        suffix = "Downstream";
+        break;
+      case VirtualCardEnrollmentSource::kSettingsPage:
+        suffix = "SettingsPage";
+        break;
+      default:
+        NOTREACHED();
+    }
+
+    // Verifies the logging.
+    histogram_tester.ExpectUniqueSample(
+        "Autofill.VirtualCard.Enroll.Attempt." + suffix,
+        /*sample=*/true, 1);
+    histogram_tester.ExpectBucketCount(
+        "Autofill.VirtualCard.Enroll.Result." + suffix,
+        /*sample=*/true, 1);
+
+    // Starts another request and makes sure it fails.
+    payments_network_interface().set_update_virtual_card_enrollment_result(
+        payments::PaymentsAutofillClient::PaymentsRpcResult::
+            kVcnRetrievalPermanentFailure);
+    virtual_card_enrollment_manager_->Enroll(
+        /*virtual_card_enrollment_update_response_callback=*/std::nullopt);
+
+    // Verifies the logging.
+    histogram_tester.ExpectUniqueSample(
+        "Autofill.VirtualCard.Enroll.Attempt." + suffix,
+        /*sample=*/true, 2);
+    histogram_tester.ExpectBucketCount(
+        "Autofill.VirtualCard.Enroll.Result." + suffix,
+        /*sample=*/false, 1);
+  }
 }
 
 TEST_F(VirtualCardEnrollmentManagerTest, Unenroll) {
@@ -374,12 +600,19 @@
   base::HistogramTester histogram_tester;
   SetUpStrikeDatabaseTest();
 
-  virtual_card_enrollment_manager_
-      ->AddStrikeToBlockOfferingVirtualCardEnrollment(
-          base::NumberToString(card_->instrument_id()));
+  VirtualCardEnrollmentProcessState* state =
+      virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState();
+  // Reject the bubble and log strike.
+  virtual_card_enrollment_manager_->OnVirtualCardEnrollmentBubbleCancelled();
+
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.StrikeDatabase.NthStrikeAdded.VirtualCardEnrollment",
+      /*sample=*/1, /*count=*/1);
   EXPECT_EQ(
       virtual_card_enrollment_manager_->GetVirtualCardEnrollmentStrikeDatabase()
-          ->GetStrikes(base::NumberToString(card_->instrument_id())),
+          ->GetStrikes(
+              base::NumberToString(state->virtual_card_enrollment_fields
+                                       .credit_card.instrument_id())),
       1);
 
   // Ensure a strike has been removed after enrollment accepted.
@@ -387,7 +620,9 @@
       /*virtual_card_enrollment_update_response_callback=*/std::nullopt);
   EXPECT_EQ(
       virtual_card_enrollment_manager_->GetVirtualCardEnrollmentStrikeDatabase()
-          ->GetStrikes(base::NumberToString(card_->instrument_id())),
+          ->GetStrikes(
+              base::NumberToString(state->virtual_card_enrollment_fields
+                                       .credit_card.instrument_id())),
       0);
 
   histogram_tester.ExpectBucketCount(
@@ -395,7 +630,8 @@
   histogram_tester.ExpectBucketCount(
       "Autofill.VirtualCardEnrollmentStrikeDatabase." +
           VirtualCardEnrollmentSourceToMetricSuffix(
-              VirtualCardEnrollmentSource::kDownstream),
+              state->virtual_card_enrollment_fields
+                  .virtual_card_enrollment_source),
       VirtualCardEnrollmentStrikeDatabaseEvent::
           VIRTUAL_CARD_ENROLLMENT_STRIKE_DATABASE_STRIKES_CLEARED,
       1);
@@ -405,25 +641,28 @@
   base::HistogramTester histogram_tester;
   SetUpStrikeDatabaseTest();
 
-  // Log one strike for the card.
-  virtual_card_enrollment_manager_
-      ->AddStrikeToBlockOfferingVirtualCardEnrollment(
-          base::NumberToString(card_->instrument_id()));
+  // Reject the bubble and log strike.
+  virtual_card_enrollment_manager_->OnVirtualCardEnrollmentBubbleCancelled();
 
   histogram_tester.ExpectUniqueSample(
       "Autofill.StrikeDatabase.NthStrikeAdded.VirtualCardEnrollment",
       /*sample=*/1, /*count=*/1);
 
+  VirtualCardEnrollmentProcessState* state =
+      virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState();
   // Ensure a strike has been logged.
   EXPECT_EQ(
       virtual_card_enrollment_manager_->GetVirtualCardEnrollmentStrikeDatabase()
-          ->GetStrikes(base::NumberToString(card_->instrument_id())),
+          ->GetStrikes(
+              base::NumberToString(state->virtual_card_enrollment_fields
+                                       .credit_card.instrument_id())),
       1);
 
   histogram_tester.ExpectBucketCount(
       "Autofill.VirtualCardEnrollmentStrikeDatabase." +
           VirtualCardEnrollmentSourceToMetricSuffix(
-              VirtualCardEnrollmentSource::kDownstream),
+              state->virtual_card_enrollment_fields
+                  .virtual_card_enrollment_source),
       VirtualCardEnrollmentStrikeDatabaseEvent::
           VIRTUAL_CARD_ENROLLMENT_STRIKE_DATABASE_STRIKE_LOGGED,
       1);
@@ -432,26 +671,17 @@
 TEST_F(VirtualCardEnrollmentManagerTest, StrikeDatabase_BubbleBlocked) {
   base::HistogramTester histogram_tester;
   SetUpStrikeDatabaseTest();
-  EXPECT_FALSE(
-      virtual_card_enrollment_manager_->ShouldBlockVirtualCardEnrollment(
-          base::NumberToString(card_->instrument_id()),
-          VirtualCardEnrollmentSource::kUpstream));
-  EXPECT_FALSE(
-      virtual_card_enrollment_manager_->ShouldBlockVirtualCardEnrollment(
-          base::NumberToString(card_->instrument_id()),
-          VirtualCardEnrollmentSource::kDownstream));
 
   for (int i = 0; i < virtual_card_enrollment_manager_
                           ->GetVirtualCardEnrollmentStrikeDatabase()
                           ->GetMaxStrikesLimit();
        i++) {
-    virtual_card_enrollment_manager_
-        ->AddStrikeToBlockOfferingVirtualCardEnrollment(
-            base::NumberToString(card_->instrument_id()));
+    // Reject the bubble and log strike.
+    virtual_card_enrollment_manager_->OnVirtualCardEnrollmentBubbleCancelled();
 
     histogram_tester.ExpectBucketCount(
         "Autofill.StrikeDatabase.NthStrikeAdded.VirtualCardEnrollment",
-        /*sample=*/i + 1, /*expected_count=*/1);
+        /*sample=*/i + 1, /*count=*/1);
 
     for (VirtualCardEnrollmentSource source :
          {VirtualCardEnrollmentSource::kUpstream,
@@ -469,7 +699,7 @@
        {VirtualCardEnrollmentSource::kUpstream,
         VirtualCardEnrollmentSource::kDownstream}) {
     virtual_card_enrollment_manager_->InitVirtualCardEnroll(
-        *card_, source, base::DoNothing(), std::nullopt,
+        *card_, source, std::nullopt,
         virtual_card_enrollment_manager_->AutofillClientIsPresent()
             ? user_prefs()
             : nullptr,
@@ -482,19 +712,24 @@
         source, 1);
   }
 
+  VirtualCardEnrollmentProcessState* state =
+      virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState();
   EXPECT_TRUE(
       virtual_card_enrollment_manager_->ShouldBlockVirtualCardEnrollment(
-          base::NumberToString(card_->instrument_id()),
+          base::NumberToString(state->virtual_card_enrollment_fields.credit_card
+                                   .instrument_id()),
           VirtualCardEnrollmentSource::kUpstream));
   EXPECT_TRUE(
       virtual_card_enrollment_manager_->ShouldBlockVirtualCardEnrollment(
-          base::NumberToString(card_->instrument_id()),
+          base::NumberToString(state->virtual_card_enrollment_fields.credit_card
+                                   .instrument_id()),
           VirtualCardEnrollmentSource::kDownstream));
 }
 
 TEST_F(VirtualCardEnrollmentManagerTest,
        StrikeDatabase_EnrollmentAttemptFailed) {
   base::HistogramTester histogram_tester;
+  SetUpStrikeDatabaseTest();
 
   std::vector<payments::PaymentsAutofillClient::PaymentsRpcResult>
       failure_results = {
@@ -505,24 +740,29 @@
               kClientSideTimeout,
       };
 
+  VirtualCardEnrollmentProcessState* state =
+      virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState();
+
   for (int i = 0; i < static_cast<int>(failure_results.size()); i++) {
-    SetUpStrikeDatabaseTest();
     virtual_card_enrollment_manager_
         ->OnDidGetUpdateVirtualCardEnrollmentResponse(
             VirtualCardEnrollmentRequestType::kEnroll, failure_results[i]);
     histogram_tester.ExpectBucketCount(
         "Autofill.StrikeDatabase.NthStrikeAdded.VirtualCardEnrollment",
-        /*sample=*/i + 1, /*expected_count=*/1);
+        /*sample=*/i + 1, /*count=*/1);
 
     EXPECT_EQ(virtual_card_enrollment_manager_
                   ->GetVirtualCardEnrollmentStrikeDatabase()
-                  ->GetStrikes(base::NumberToString(card_->instrument_id())),
+                  ->GetStrikes(
+                      base::NumberToString(state->virtual_card_enrollment_fields
+                                               .credit_card.instrument_id())),
               i + 1);
 
     histogram_tester.ExpectBucketCount(
         "Autofill.VirtualCardEnrollmentStrikeDatabase." +
             VirtualCardEnrollmentSourceToMetricSuffix(
-                VirtualCardEnrollmentSource::kDownstream),
+                state->virtual_card_enrollment_fields
+                    .virtual_card_enrollment_source),
         VirtualCardEnrollmentStrikeDatabaseEvent::
             VIRTUAL_CARD_ENROLLMENT_STRIKE_DATABASE_STRIKE_LOGGED,
         i + 1);
@@ -538,9 +778,8 @@
                           ->GetVirtualCardEnrollmentStrikeDatabase()
                           ->GetMaxStrikesLimit();
        i++) {
-    virtual_card_enrollment_manager_
-        ->AddStrikeToBlockOfferingVirtualCardEnrollment(
-            base::NumberToString(card_->instrument_id()));
+    // Reject the bubble and log strike.
+    virtual_card_enrollment_manager_->OnVirtualCardEnrollmentBubbleCancelled();
 
     histogram_tester.ExpectBucketCount(
         "Autofill.StrikeDatabase.NthStrikeAdded.VirtualCardEnrollment",
@@ -550,7 +789,10 @@
   // Make sure enrollment is not blocked through settings page.
   EXPECT_FALSE(
       virtual_card_enrollment_manager_->ShouldBlockVirtualCardEnrollment(
-          base::NumberToString(card_->instrument_id()),
+          base::NumberToString(
+              virtual_card_enrollment_manager_
+                  ->GetVirtualCardEnrollmentProcessState()
+                  ->virtual_card_enrollment_fields.credit_card.instrument_id()),
           VirtualCardEnrollmentSource::kSettingsPage));
 }
 
@@ -561,6 +803,7 @@
   VirtualCardEnrollmentProcessState* state =
       virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState();
   state->vcn_context_token = kTestVcnContextToken;
+  SetUpCard();
   state->virtual_card_enrollment_fields.credit_card = *card_;
   payments_data_manager().SetPaymentsCustomerData(
       std::make_unique<PaymentsCustomerData>("123456"));
@@ -583,22 +826,20 @@
     // Start enrollment and ensures VirtualCardEnrollmentFields is set
     // correctly.
     virtual_card_enrollment_manager_->InitVirtualCardEnroll(
-        *card_, VirtualCardEnrollmentSource::kDownstream, base::DoNothing());
+        *card_, VirtualCardEnrollmentSource::kDownstream);
     EXPECT_FALSE(state->virtual_card_enrollment_fields.last_show);
-    // Log one strike for the card.
-    virtual_card_enrollment_manager_
-        ->AddStrikeToBlockOfferingVirtualCardEnrollment(
-            base::NumberToString(card_->instrument_id()));
+    // Reject the bubble and log strike.
+    virtual_card_enrollment_manager_->OnVirtualCardEnrollmentBubbleCancelled();
 
     histogram_tester.ExpectBucketCount(
         "Autofill.StrikeDatabase.NthStrikeAdded.VirtualCardEnrollment",
-        /*sample=*/i + 1, /*expected_count=*/1);
+        /*sample=*/i + 1, /*count=*/1);
   }
 
   // Start enrollment and ensures VirtualCardEnrollmentFields is set
   // correctly.
   virtual_card_enrollment_manager_->InitVirtualCardEnroll(
-      *card_, VirtualCardEnrollmentSource::kDownstream, base::DoNothing());
+      *card_, VirtualCardEnrollmentSource::kDownstream);
   EXPECT_TRUE(state->virtual_card_enrollment_fields.last_show);
 }
 
@@ -609,21 +850,19 @@
   SetUpStrikeDatabaseTest();
   VirtualCardEnrollmentProcessState* state =
       virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState();
+  SetUpCard();
   card_->set_instrument_id(11223344);
   state->virtual_card_enrollment_fields.credit_card = *card_;
 
   virtual_card_enrollment_manager_->InitVirtualCardEnroll(
-      *card_, VirtualCardEnrollmentSource::kDownstream, base::DoNothing(),
-      std::nullopt,
+      *card_, VirtualCardEnrollmentSource::kDownstream, std::nullopt,
       virtual_card_enrollment_manager_->AutofillClientIsPresent() ? user_prefs()
                                                                   : nullptr,
       base::DoNothing());
 
   // Logs one strike for the card and makes sure that the enrollment offer is
   // blocked.
-  virtual_card_enrollment_manager_
-      ->AddStrikeToBlockOfferingVirtualCardEnrollment(
-          base::NumberToString(card_->instrument_id()));
+  virtual_card_enrollment_manager_->OnVirtualCardEnrollmentBubbleCancelled();
 
   histogram_tester.ExpectUniqueSample(
       "Autofill.StrikeDatabase.NthStrikeAdded.VirtualCardEnrollment",
@@ -671,207 +910,12 @@
       ->virtual_card_enrollment_fields.virtual_card_enrollment_source =
       VirtualCardEnrollmentSource::kUpstream;
   task_environment_.FastForwardBy(base::Minutes(1));
-  virtual_card_enrollment_manager_->ShowVirtualCardEnrollBubble(
-      &virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState()
-           ->virtual_card_enrollment_fields);
+  virtual_card_enrollment_manager_->ShowVirtualCardEnrollBubble();
   histogram_tester.ExpectTimeBucketCount(
       "Autofill.VirtualCardEnrollBubble.LatencySinceUpstream", base::Minutes(1),
       1);
 }
 
-class VirtualCardEnrollmentManagerParamTest
-    : public VirtualCardEnrollmentManagerTest,
-      public ::testing::WithParamInterface<VirtualCardEnrollmentSource> {
- public:
-  VirtualCardEnrollmentSource source() const { return GetParam(); }
-};
-
-INSTANTIATE_TEST_SUITE_P(
-    VirtualCardEnrollmentManagerTest,
-    VirtualCardEnrollmentManagerParamTest,
-    ::testing::Values(VirtualCardEnrollmentSource::kUpstream,
-                      VirtualCardEnrollmentSource::kDownstream,
-                      VirtualCardEnrollmentSource::kSettingsPage));
-
-TEST_P(VirtualCardEnrollmentManagerParamTest, InitVirtualCardEnroll) {
-  for (bool make_image_present : {true, false}) {
-    SCOPED_TRACE(testing::Message()
-                 << ", make_image_present=" << make_image_present);
-    payments_data_manager().ClearCachedImages();
-    auto* state = virtual_card_enrollment_manager_
-                      ->GetVirtualCardEnrollmentProcessState();
-    state->risk_data.reset();
-    state->virtual_card_enrollment_fields.card_art_image = nullptr;
-    if (make_image_present) {
-      SetValidCardArtImageForCard(*card_);
-    }
-#if BUILDFLAG(IS_ANDROID)
-    virtual_card_enrollment_manager_->SetAutofillClient(nullptr);
-#endif
-
-    virtual_card_enrollment_manager_->InitVirtualCardEnroll(
-        *card_, source(), base::DoNothing(), std::nullopt,
-        virtual_card_enrollment_manager_->AutofillClientIsPresent()
-            ? user_prefs()
-            : nullptr,
-        base::DoNothing());
-
-    // CreditCard class overloads equality operator to check that GUIDs,
-    // origins, and the contents of the two cards are equal.
-    EXPECT_EQ(*card_, state->virtual_card_enrollment_fields.credit_card);
-    EXPECT_EQ(make_image_present,
-              state->virtual_card_enrollment_fields.card_art_image != nullptr);
-    EXPECT_TRUE(state->risk_data.has_value());
-
-    // Reset to avoid that state keeps track of card art images that will be
-    // invalidated at the start of the next loop.
-    virtual_card_enrollment_manager_->ResetVirtualCardEnrollmentProcessState();
-  }
-}
-
-TEST_P(VirtualCardEnrollmentManagerParamTest, Enroll) {
-  SetValidCardArtImageForCard(*card_);
-  payments_data_manager().SetPaymentsCustomerData(
-      std::make_unique<PaymentsCustomerData>(/*customer_id=*/"123456"));
-  for (payments::PaymentsRpcResult result :
-       {payments::PaymentsRpcResult::kSuccess,
-        payments::PaymentsRpcResult::kPermanentFailure}) {
-    base::HistogramTester histogram_tester;
-    SCOPED_TRACE(testing::Message()
-                 << " Payments Rpc result= " << static_cast<int>(result));
-    VirtualCardEnrollmentProcessState* state =
-        virtual_card_enrollment_manager_
-            ->GetVirtualCardEnrollmentProcessState();
-    state->vcn_context_token = kTestVcnContextToken;
-    state->virtual_card_enrollment_fields.credit_card = *card_;
-    state->virtual_card_enrollment_fields.virtual_card_enrollment_source =
-        source();
-    virtual_card_enrollment_manager_->SetPaymentsRpcResult(
-        payments::PaymentsAutofillClient::PaymentsRpcResult::kNone);
-    payments_network_interface().set_update_virtual_card_enrollment_result(
-        result);
-
-    virtual_card_enrollment_manager_->Enroll(
-        /*virtual_card_enrollment_update_response_callback=*/std::nullopt);
-
-    payments::UpdateVirtualCardEnrollmentRequestDetails request_details =
-        payments_network_interface()
-            .update_virtual_card_enrollment_request_details();
-    EXPECT_TRUE(request_details.vcn_context_token.has_value());
-    EXPECT_EQ(request_details.vcn_context_token, kTestVcnContextToken);
-    EXPECT_EQ(request_details.virtual_card_enrollment_source, source());
-    EXPECT_EQ(request_details.virtual_card_enrollment_request_type,
-              VirtualCardEnrollmentRequestType::kEnroll);
-    EXPECT_EQ(request_details.billing_customer_number, 123456);
-    EXPECT_EQ(virtual_card_enrollment_manager_->GetPaymentsRpcResult(), result);
-
-    std::string suffix;
-    switch (source()) {
-      case VirtualCardEnrollmentSource::kUpstream:
-        suffix = "Upstream";
-        break;
-      case VirtualCardEnrollmentSource::kDownstream:
-        suffix = "Downstream";
-        break;
-      case VirtualCardEnrollmentSource::kSettingsPage:
-        suffix = "SettingsPage";
-        break;
-      default:
-        NOTREACHED();
-    }
-    // Verifies the logging.
-    histogram_tester.ExpectUniqueSample(
-        "Autofill.VirtualCard.Enroll.Attempt." + suffix,
-        /*sample=*/true, 1);
-    histogram_tester.ExpectBucketCount(
-        "Autofill.VirtualCard.Enroll.Result." + suffix,
-        /*sample=*/result ==
-            payments::PaymentsAutofillClient::PaymentsRpcResult::kSuccess,
-        1);
-  }
-}
-
-TEST_P(VirtualCardEnrollmentManagerParamTest,
-       OnDidGetDetailsForEnrollResponse) {
-  base::HistogramTester histogram_tester;
-  const TestLegalMessageLine google_legal_message =
-      TestLegalMessageLine("google_test_legal_message");
-  const TestLegalMessageLine issuer_legal_message =
-      TestLegalMessageLine("issuer_test_legal_message");
-  // Ignore strike database to avoid its required delay cooldown.
-  virtual_card_enrollment_manager_->set_ignore_strike_database(true);
-// TODO(crbug.com/40223706): Makes the following test
-// PersonalDataManagerTest.AddUpdateRemoveCreditCards fail on iOS.
-// That other test fails when SetNetworkImageInResourceBundle is called here.
-#if BUILDFLAG(IS_IOS)
-  for (bool make_image_present : {true}) {
-#else
-  for (bool make_image_present : {true, false}) {
-#endif  // BUILDFLAG(IS_IOS)
-    SCOPED_TRACE(testing::Message()
-                 << ", make_image_present=" << make_image_present);
-    payments::GetDetailsForEnrollmentResponseDetails response =
-        std::move(SetUpOnDidGetDetailsForEnrollResponse(
-            google_legal_message, issuer_legal_message, make_image_present));
-    NiceMock<ui::MockResourceBundleDelegate> delegate;
-    std::unique_ptr<ui::ResourceBundle::SharedInstanceSwapperForTesting>
-        resource_bundle_swapper;
-
-    gfx::Image network_image;
-    if (!make_image_present) {
-      network_image = gfx::test::CreateImage(32, 30);
-      resource_bundle_swapper = std::make_unique<
-          ui::ResourceBundle::SharedInstanceSwapperForTesting>();
-      SetNetworkImageInResourceBundle(&delegate, card_->network(),
-                                      network_image);
-    }
-
-    virtual_card_enrollment_manager_->InitVirtualCardEnroll(*card_, source(),
-                                                            base::DoNothing());
-    task_environment_.FastForwardBy(base::Milliseconds(5));
-    virtual_card_enrollment_manager_->OnDidGetDetailsForEnrollResponse(
-        payments::PaymentsAutofillClient::PaymentsRpcResult::kSuccess,
-        response);
-
-    auto* state = virtual_card_enrollment_manager_
-                      ->GetVirtualCardEnrollmentProcessState();
-    EXPECT_TRUE(state->vcn_context_token.has_value());
-    EXPECT_EQ(state->vcn_context_token, response.vcn_context_token);
-    VirtualCardEnrollmentFields virtual_card_enrollment_fields =
-        virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState()
-            ->virtual_card_enrollment_fields;
-    EXPECT_TRUE(virtual_card_enrollment_fields.google_legal_message[0].text() ==
-                google_legal_message.text());
-    EXPECT_TRUE(virtual_card_enrollment_fields.issuer_legal_message[0].text() ==
-                issuer_legal_message.text());
-
-    // The |card_art_image| should always be present. If there is no card art
-    // image available, it should be set to the network image.
-    EXPECT_TRUE(virtual_card_enrollment_fields.card_art_image != nullptr);
-    if (!make_image_present) {
-      EXPECT_TRUE(
-          virtual_card_enrollment_fields.card_art_image->BackedBySameObjectAs(
-              network_image.AsImageSkia()));
-    }
-    histogram_tester.ExpectUniqueSample(
-        "Autofill.VirtualCard.GetDetailsForEnrollment.Result." +
-            VirtualCardEnrollmentSourceToMetricSuffix(source()),
-        /*sample=*/true, make_image_present ? 1 : 2);
-    histogram_tester.ExpectBucketCount(
-        "Autofill.VirtualCard.GetDetailsForEnrollment.Latency." +
-            VirtualCardEnrollmentSourceToMetricSuffix(source()) +
-            PaymentsRpcResultToMetricsSuffix(
-                payments::PaymentsAutofillClient::PaymentsRpcResult::kSuccess),
-        /*sample=*/5, make_image_present ? 1 : 2);
-
-    // Avoid dangling pointers to artwork.
-    virtual_card_enrollment_manager_->ResetVirtualCardEnrollmentProcessState();
-    if (!make_image_present) {
-      ui::ResourceBundle::CleanupSharedInstance();
-    }
-  }
-}
-
 class DownstreamLatencyMetricsTest
     : public VirtualCardEnrollmentManagerTest,
       public ::testing::WithParamInterface<bool> {
@@ -890,16 +934,11 @@
       CreditCard::VirtualCardEnrollmentState::kUnenrolledAndEligible);
   virtual_card_enrollment_manager_->ShouldOfferVirtualCardEnrollment(
       card, card.instrument_id(), card_unmasked_from_cache());
-  VirtualCardEnrollmentFields* virtual_card_enrollment_fields =
-      &virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState()
-           ->virtual_card_enrollment_fields;
-  virtual_card_enrollment_fields->virtual_card_enrollment_source =
+  virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState()
+      ->virtual_card_enrollment_fields.virtual_card_enrollment_source =
       VirtualCardEnrollmentSource::kDownstream;
-
   task_environment_.FastForwardBy(base::Minutes(1));
-  virtual_card_enrollment_manager_->ShowVirtualCardEnrollBubble(
-      virtual_card_enrollment_fields);
-
+  virtual_card_enrollment_manager_->ShowVirtualCardEnrollBubble();
   histogram_tester.ExpectTimeBucketCount(
       "Autofill.VirtualCardEnrollBubble.LatencySinceDownstream",
       base::Minutes(1), card_unmasked_from_cache() ? 0 : 1);
diff --git a/components/autofill/core/browser/ui/autofill_external_delegate.cc b/components/autofill/core/browser/ui/autofill_external_delegate.cc
index 5404e2e..468182ec7 100644
--- a/components/autofill/core/browser/ui/autofill_external_delegate.cc
+++ b/components/autofill/core/browser/ui/autofill_external_delegate.cc
@@ -238,6 +238,7 @@
       // that a merchant has saved. This indicates there could be Autofill
       // suggestions related to standalone CVC fields.
     case SuggestionType::kVirtualCreditCardEntry:
+    case SuggestionType::kLoyaltyCardEntry:
       return true;
     case SuggestionType::kAccountStoragePasswordEntry:
     case SuggestionType::kAllSavedPasswordsEntry:
@@ -260,7 +261,6 @@
     case SuggestionType::kGeneratePasswordEntry:
     case SuggestionType::kIbanEntry:
     case SuggestionType::kInsecureContextPaymentDisabledMessage:
-    case SuggestionType::kLoyaltyCardEntry:
     case SuggestionType::kManageAddress:
     case SuggestionType::kManageAutofillAi:
     case SuggestionType::kManageCreditCard:
diff --git a/components/autofill/core/common/credit_card_number_validation_unittest.cc b/components/autofill/core/common/credit_card_number_validation_unittest.cc
index 10c7b4c..38f89d1c 100644
--- a/components/autofill/core/common/credit_card_number_validation_unittest.cc
+++ b/components/autofill/core/common/credit_card_number_validation_unittest.cc
@@ -7,6 +7,7 @@
 #include <cstddef>
 #include <string>
 
+#include "base/strings/utf_ostream_operators.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "components/autofill/core/common/autofill_payments_features.h"
diff --git a/components/browser_ui/widget/android/BUILD.gn b/components/browser_ui/widget/android/BUILD.gn
index 64f3fa1..07fe67e 100644
--- a/components/browser_ui/widget/android/BUILD.gn
+++ b/components/browser_ui/widget/android/BUILD.gn
@@ -41,6 +41,7 @@
     "java/src/org/chromium/components/browser_ui/widget/RadioButtonWithDescriptionAndAuxButton.java",
     "java/src/org/chromium/components/browser_ui/widget/RadioButtonWithDescriptionLayout.java",
     "java/src/org/chromium/components/browser_ui/widget/RadioButtonWithEditText.java",
+    "java/src/org/chromium/components/browser_ui/widget/RichRadioButton.java",
     "java/src/org/chromium/components/browser_ui/widget/RoundedCornerImageView.java",
     "java/src/org/chromium/components/browser_ui/widget/RoundedCornerOutlineProvider.java",
     "java/src/org/chromium/components/browser_ui/widget/RoundedIconGenerator.java",
@@ -244,6 +245,7 @@
     "java/res/drawable/home_surface_ui_background.xml",
     "java/res/drawable/ic_arrow_back_24dp.xml",
     "java/res/drawable/ic_check_googblue_24dp_animated.xml",
+    "java/res/drawable/ic_custom_radio_unchecked.xml",
     "java/res/drawable/ic_offline_pin_blue_white.xml",
     "java/res/drawable/ic_settings_gear_24dp.xml",
     "java/res/drawable/ic_settings_gear_24dp.xml",
@@ -257,6 +259,8 @@
     "java/res/drawable/oval_surface_0.xml",
     "java/res/drawable/oval_surface_1.xml",
     "java/res/drawable/query_tile_overlay.xml",
+    "java/res/drawable/rich_radio_button_background.xml",
+    "java/res/drawable/rich_radio_button_selector.xml",
     "java/res/drawable/rounded_corner_card.xml",
     "java/res/drawable/rounded_rectangle_surface_0.xml",
     "java/res/drawable/rounded_rectangle_surface_container_low.xml",
@@ -299,6 +303,7 @@
     "java/res/layout/radio_button_layout_element.xml",
     "java/res/layout/radio_button_with_description.xml",
     "java/res/layout/radio_button_with_edit_text.xml",
+    "java/res/layout/rich_radio_button.xml",
     "java/res/layout/search_toolbar.xml",
     "java/res/layout/selectable_list_layout.xml",
     "java/res/layout/spinner_button_wrapper.xml",
@@ -376,6 +381,7 @@
     "java/src/org/chromium/components/browser_ui/widget/RadioButtonWithDescriptionLayoutTest.java",
     "java/src/org/chromium/components/browser_ui/widget/RadioButtonWithEditTextTest.java",
     "java/src/org/chromium/components/browser_ui/widget/RadioButtonWithIconRenderTest.java",
+    "java/src/org/chromium/components/browser_ui/widget/RichRadioButtonRenderTest.java",
     "java/src/org/chromium/components/browser_ui/widget/RoundedIconGeneratorTest.java",
     "java/src/org/chromium/components/browser_ui/widget/WrappingLayoutTest.java",
     "java/src/org/chromium/components/browser_ui/widget/dragreorder/DragReorderableRecyclerViewAdapterTest.java",
@@ -435,6 +441,7 @@
     "test/java/res/drawable/test_ic_star_border_black_24dp.xml",
     "test/java/res/drawable/test_ic_vintage_filter.xml",
     "test/java/res/drawable/test_illustration.xml",
+    "test/java/res/drawable/test_location_precise.xml",
     "test/java/res/drawable/test_logo_avatar_anonymous.xml",
     "test/java/res/layout/checkbox_with_description_render_test.xml",
     "test/java/res/layout/dual_control_test_layout.xml",
@@ -443,6 +450,7 @@
     "test/java/res/layout/radio_button_with_description_layout_test.xml",
     "test/java/res/layout/radio_button_with_edit_text_test.xml",
     "test/java/res/layout/radio_button_with_icon_render_test.xml",
+    "test/java/res/layout/rich_radio_button_render_test.xml",
     "test/java/res/layout/touch_tracking_list_view_test.xml",
     "test/java/res/layout/touch_tracking_list_view_test_item.xml",
     "test/java/res/values/strings.xml",
diff --git a/components/browser_ui/widget/android/java/res/drawable/ic_custom_radio_unchecked.xml b/components/browser_ui/widget/android/java/res/drawable/ic_custom_radio_unchecked.xml
new file mode 100644
index 0000000..1a25aeda
--- /dev/null
+++ b/components/browser_ui/widget/android/java/res/drawable/ic_custom_radio_unchecked.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2025 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:width="24dp"
+    android:height="24dp">
+    <group>
+        <clip-path
+            android:pathData="M0 0H24V24H0V0Z" />
+        <path
+            android:pathData="M12 22C10.6167 22 9.31667 21.7417 8.1 21.225C6.88333 20.6917 5.825 19.975 4.925 19.075C4.025 18.175 3.30833 17.1167 2.775 15.9C2.25833 14.6833 2 13.3833 2 12C2 10.6167 2.25833 9.31667 2.775 8.1C3.30833 6.88333 4.025 5.825 4.925 4.925C5.825 4.025 6.88333 3.31667 8.1 2.8C9.31667 2.26667 10.6167 2 12 2C13.3833 2 14.6833 2.26667 15.9 2.8C17.1167 3.31667 18.175 4.025 19.075 4.925C19.975 5.825 20.6833 6.88333 21.2 8.1C21.7333 9.31667 22 10.6167 22 12C22 13.3833 21.7333 14.6833 21.2 15.9C20.6833 17.1167 19.975 18.175 19.075 19.075C18.175 19.975 17.1167 20.6917 15.9 21.225C14.6833 21.7417 13.3833 22 12 22ZM12 20C14.2333 20 16.125 19.225 17.675 17.675C19.225 16.125 20 14.2333 20 12C20 9.76667 19.225 7.875 17.675 6.325C16.125 4.775 14.2333 4 12 4C9.76667 4 7.875 4.775 6.325 6.325C4.775 7.875 4 9.76667 4 12C4 14.2333 4.775 16.125 6.325 17.675C7.875 19.225 9.76667 20 12 20Z"
+            android:fillColor="#303030" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/components/browser_ui/widget/android/java/res/drawable/rich_radio_button_background.xml b/components/browser_ui/widget/android/java/res/drawable/rich_radio_button_background.xml
new file mode 100644
index 0000000..9c45168
--- /dev/null
+++ b/components/browser_ui/widget/android/java/res/drawable/rich_radio_button_background.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2025 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@macro/default_card_bg_color" />
+    <corners android:radius="@dimen/card_rounded_corner_radius" />
+</shape>
\ No newline at end of file
diff --git a/components/browser_ui/widget/android/java/res/drawable/rich_radio_button_selector.xml b/components/browser_ui/widget/android/java/res/drawable/rich_radio_button_selector.xml
new file mode 100644
index 0000000..48eb8adb
--- /dev/null
+++ b/components/browser_ui/widget/android/java/res/drawable/rich_radio_button_selector.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2025 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_checked="true"
+          android:drawable="@drawable/ic_check_circle_filled_green_24dp" />
+
+    <item android:drawable="@drawable/ic_custom_radio_unchecked" />
+</selector>
\ No newline at end of file
diff --git a/components/browser_ui/widget/android/java/res/layout/rich_radio_button.xml b/components/browser_ui/widget/android/java/res/layout/rich_radio_button.xml
new file mode 100644
index 0000000..144b5ae
--- /dev/null
+++ b/components/browser_ui/widget/android/java/res/layout/rich_radio_button.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2025 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/root_item_layout"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal"
+    android:padding="16dp"
+    android:gravity="center_vertical"
+    android:background="@drawable/rich_radio_button_background">
+
+    <FrameLayout
+        android:id="@+id/rich_radio_button_icon_container"
+        android:layout_width="80dp"
+        android:layout_height="80dp"
+        android:layout_marginEnd="8dp"
+        android:background="@drawable/rich_radio_button_background"
+        android:gravity="center"
+        android:clipToOutline="true">
+            <org.chromium.ui.widget.ChromeImageView
+                android:id="@+id/rich_radio_button_icon"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_gravity="center"
+                android:scaleType="centerInside"
+                android:visibility="gone" />
+    </FrameLayout>
+
+    <LinearLayout
+        android:id="@+id/rich_radio_button_text_container"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/rich_radio_button_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:ellipsize="end"
+            android:textAppearance="@style/TextAppearance.TextLarge.Primary" />
+
+        <TextView
+            android:id="@+id/rich_radio_button_description"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:ellipsize="end"
+            android:textAppearance="@style/TextAppearance.TextMedium.Secondary"
+            android:layout_marginTop="4dp"
+            android:visibility="gone"
+            />
+    </LinearLayout>
+
+    <RadioButton
+        android:id="@+id/rich_radio_button_radio_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:clickable="false"
+        android:focusable="false"
+        android:layout_marginStart="16dp"
+        android:button="@null"
+        android:drawableEnd="@drawable/rich_radio_button_selector"
+        android:drawableTint="?attr/colorPrimary" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RichRadioButton.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RichRadioButton.java
new file mode 100644
index 0000000..7a3e761
--- /dev/null
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RichRadioButton.java
@@ -0,0 +1,142 @@
+// Copyright 2025 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.components.browser_ui.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Checkable;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.RadioButton;
+import android.widget.TextView;
+
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.view.AccessibilityDelegateCompat;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+
+import org.chromium.build.annotations.NullMarked;
+import org.chromium.ui.widget.ChromeImageView;
+
+/**
+ * A custom view that combines a RadioButton with an optional icon, title, and optional description.
+ * It implements the {@link Checkable} interface to behave like a standard radio button and provides
+ * methods to customize its content and layout.
+ */
+@NullMarked
+public class RichRadioButton extends LinearLayout implements Checkable {
+
+    private FrameLayout mIconContainer;
+    private ChromeImageView mItemIcon;
+    private TextView mItemTitle;
+    private TextView mItemDescription;
+    private RadioButton mItemRadioButton;
+
+    private boolean mIsChecked;
+
+    public RichRadioButton(@NonNull Context context) {
+        super(context);
+        init(context);
+    }
+
+    public RichRadioButton(@NonNull Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        init(context);
+    }
+
+    public RichRadioButton(
+            @NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(context);
+    }
+
+    private void init(@NonNull Context context) {
+        LayoutInflater.from(context).inflate(R.layout.rich_radio_button, this, true);
+
+        mIconContainer = findViewById(R.id.rich_radio_button_icon_container);
+        mItemIcon = findViewById(R.id.rich_radio_button_icon);
+        mItemTitle = findViewById(R.id.rich_radio_button_title);
+        mItemDescription = findViewById(R.id.rich_radio_button_description);
+        mItemRadioButton = findViewById(R.id.rich_radio_button_radio_button);
+
+        setOnClickListener(v -> toggle());
+
+        ViewCompat.setAccessibilityDelegate(
+                this,
+                new AccessibilityDelegateCompat() {
+                    @Override
+                    public void onInitializeAccessibilityNodeInfo(
+                            View host, AccessibilityNodeInfoCompat info) {
+                        super.onInitializeAccessibilityNodeInfo(host, info);
+                        info.setCheckable(true);
+                        info.setChecked(mIsChecked);
+                        info.setClassName(RadioButton.class.getName());
+                    }
+                });
+    }
+
+    /**
+     * Binds data to the item view.
+     *
+     * @param iconResId Optional drawable resource ID for the icon. Pass 0 to hide the icon.
+     * @param title The title text for the item.
+     * @param description Optional description text. Pass null or empty string to hide.
+     */
+    public void setItemData(
+            @DrawableRes int iconResId,
+            @NonNull String title,
+            @Nullable String description,
+            boolean isVertical) {
+        if (iconResId != 0) {
+            mItemIcon.setImageResource(iconResId);
+            mItemIcon.setVisibility(VISIBLE);
+            mIconContainer.setVisibility(VISIBLE);
+        } else {
+            mItemIcon.setVisibility(GONE);
+            mIconContainer.setVisibility(GONE);
+        }
+        mItemTitle.setText(title);
+        if (description != null && !description.isEmpty()) {
+            mItemDescription.setText(description);
+            mItemDescription.setVisibility(VISIBLE);
+        } else {
+            mItemDescription.setVisibility(GONE);
+        }
+    }
+
+    @Override
+    public void setChecked(boolean checked) {
+        if (mIsChecked != checked) {
+            mIsChecked = checked;
+            mItemRadioButton.setChecked(checked);
+            refreshDrawableState();
+        }
+    }
+
+    @Override
+    public boolean isChecked() {
+        return mIsChecked;
+    }
+
+    @Override
+    public void toggle() {
+        setChecked(!mIsChecked);
+    }
+
+    private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
+
+    @Override
+    public int[] onCreateDrawableState(int extraForSpace) {
+        final int[] drawableState = super.onCreateDrawableState(extraForSpace + 1);
+        if (isChecked()) {
+            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
+        }
+        return drawableState;
+    }
+}
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RichRadioButtonRenderTest.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RichRadioButtonRenderTest.java
new file mode 100644
index 0000000..dde8ea0f
--- /dev/null
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/RichRadioButtonRenderTest.java
@@ -0,0 +1,182 @@
+// Copyright 2025 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.components.browser_ui.widget;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.BaseActivityTestRule;
+import org.chromium.base.test.params.BaseJUnit4RunnerDelegate;
+import org.chromium.base.test.params.ParameterAnnotations.ClassParameter;
+import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate;
+import org.chromium.base.test.params.ParameterSet;
+import org.chromium.base.test.params.ParameterizedRunner;
+import org.chromium.base.test.util.Batch;
+import org.chromium.base.test.util.Feature;
+import org.chromium.components.browser_ui.widget.test.R;
+import org.chromium.ui.test.util.BlankUiTestActivity;
+import org.chromium.ui.test.util.NightModeTestUtils;
+import org.chromium.ui.test.util.RenderTestRule;
+
+import java.util.List;
+
+/** Render test for {@link RichRadioButton}. */
+@RunWith(ParameterizedRunner.class)
+@UseRunnerDelegate(BaseJUnit4RunnerDelegate.class)
+@Batch(Batch.UNIT_TESTS)
+public class RichRadioButtonRenderTest {
+    @ClassParameter
+    private static final List<ParameterSet> sClassParams =
+            new NightModeTestUtils.NightModeParams().getParameters();
+
+    @ClassRule
+    public static final BaseActivityTestRule<BlankUiTestActivity> sActivityTestRule =
+            new BaseActivityTestRule<>(BlankUiTestActivity.class);
+
+    private static Activity sActivity;
+
+    private static final int REVISION = 1;
+    private static final String REVISION_DESCRIPTION =
+            "Initial render test for RichRadioButton covering various states and orientations.";
+
+    @Rule
+    public RenderTestRule mRenderTestRule =
+            RenderTestRule.Builder.withPublicCorpus()
+                    .setRevision(REVISION)
+                    .setDescription(REVISION_DESCRIPTION)
+                    .setBugComponent(RenderTestRule.Component.UI_BROWSER_MOBILE)
+                    .build();
+
+    private LinearLayout mLayout;
+
+    private RichRadioButton mRichRbHorizontalFullUnchecked;
+    private RichRadioButton mRichRbHorizontalTitleChecked;
+    private RichRadioButton mRichRbHorizontalMinimalUnchecked;
+
+    private final int mFakeBgColor;
+
+    public RichRadioButtonRenderTest(boolean nightModeEnabled) {
+        mFakeBgColor = nightModeEnabled ? Color.BLACK : Color.WHITE;
+        NightModeTestUtils.setUpNightModeForBlankUiTestActivity(nightModeEnabled);
+        mRenderTestRule.setNightModeEnabled(nightModeEnabled);
+    }
+
+    @BeforeClass
+    public static void setupSuite() {
+        sActivity = sActivityTestRule.launchActivity(null);
+    }
+
+    @AfterClass
+    public static void tearDownSuite() {
+        NightModeTestUtils.tearDownNightModeForBlankUiTestActivity();
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        Activity activity = sActivity;
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    View content =
+                            LayoutInflater.from(activity)
+                                    .inflate(R.layout.rich_radio_button_render_test, null, false);
+                    activity.setContentView(content);
+
+                    mLayout = content.findViewById(R.id.test_rich_radio_button_layout);
+                    mLayout.setBackgroundColor(mFakeBgColor);
+
+                    int displayWidth = activity.getResources().getDisplayMetrics().widthPixels;
+                    mLayout.measure(
+                            View.MeasureSpec.makeMeasureSpec(
+                                    displayWidth, View.MeasureSpec.EXACTLY),
+                            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
+                    mLayout.layout(0, 0, mLayout.getMeasuredWidth(), mLayout.getMeasuredHeight());
+
+                    mRichRbHorizontalFullUnchecked =
+                            mLayout.findViewById(R.id.rich_rb_horizontal_full_unchecked);
+                    mRichRbHorizontalTitleChecked =
+                            mLayout.findViewById(R.id.rich_rb_horizontal_title_checked);
+                    mRichRbHorizontalMinimalUnchecked =
+                            mLayout.findViewById(R.id.rich_rb_horizontal_minimal_unchecked);
+                });
+
+        Assert.assertNotNull(mLayout);
+        Assert.assertNotNull(mRichRbHorizontalFullUnchecked);
+        Assert.assertNotNull(mRichRbHorizontalTitleChecked);
+        Assert.assertNotNull(mRichRbHorizontalMinimalUnchecked);
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"RenderTest", "RichRadioButton"})
+    public void testRichRbHorizontalFullUnchecked() throws Exception {
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    mRichRbHorizontalFullUnchecked.setItemData(
+                            R.drawable.test_location_precise,
+                            "Precise Location",
+                            "Provides exact location coordinates.",
+                            false);
+                    mRichRbHorizontalFullUnchecked.setChecked(false);
+                });
+        mRenderTestRule.render(mRichRbHorizontalFullUnchecked, "rich_rb_horizontal_full_unchecked");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"RenderTest", "RichRadioButton"})
+    public void testRichRbHorizontalTitleChecked() throws Exception {
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    mRichRbHorizontalTitleChecked.setItemData(
+                            R.drawable.test_location_precise, "Simple Option", null, false);
+                    mRichRbHorizontalTitleChecked.setChecked(true);
+                });
+        mRenderTestRule.render(mRichRbHorizontalTitleChecked, "rich_rb_horizontal_title_checked");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"RenderTest", "RichRadioButton"})
+    public void testRichRbHorizontalMinimalUnchecked() throws Exception {
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    mRichRbHorizontalMinimalUnchecked.setItemData(0, "Minimal Option", null, false);
+                    mRichRbHorizontalMinimalUnchecked.setChecked(false);
+                });
+        mRenderTestRule.render(
+                mRichRbHorizontalMinimalUnchecked, "rich_rb_horizontal_minimal_unchecked");
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"RenderTest", "RichRadioButton"})
+    public void testRichRbHorizontalFullChecked() throws Exception {
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    mRichRbHorizontalFullUnchecked.setItemData(
+                            R.drawable.test_location_precise,
+                            "Checked Item",
+                            "This item is now checked.",
+                            false);
+                    mRichRbHorizontalFullUnchecked.setChecked(true);
+                });
+        mRenderTestRule.render(mRichRbHorizontalFullUnchecked, "rich_rb_horizontal_full_checked");
+    }
+}
diff --git a/components/browser_ui/widget/android/test/java/res/drawable/test_location_precise.xml b/components/browser_ui/widget/android/test/java/res/drawable/test_location_precise.xml
new file mode 100644
index 0000000..842d4713
--- /dev/null
+++ b/components/browser_ui/widget/android/test/java/res/drawable/test_location_precise.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2025 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="80dp"
+    android:height="80dp"
+    android:viewportWidth="80"
+    android:viewportHeight="80">
+  <group>
+    <clip-path
+        android:pathData="M0,0h80v80h-80z"/>
+    <path
+        android:pathData="M0,0h80v80h-80z"
+        android:fillColor="#F1F3F4"/>
+    <path
+        android:pathData="M81.5,21.5L42.344,17.202C41.122,17.068 39.887,17.123 38.681,17.364L19.509,21.198C15.459,22.008 12.11,24.844 10.644,28.705L-2,62"
+        android:strokeWidth="2"
+        android:fillColor="#00000000"
+        android:strokeColor="#DADCE0"/>
+    <path
+        android:pathData="M-6,9L86,72"
+        android:strokeWidth="2"
+        android:fillColor="#00000000"
+        android:strokeColor="#DADCE0"/>
+    <path
+        android:pathData="M20.169,53.776L-2,46.5L-8.5,80.5L26.824,103L32.001,73.612L20.169,53.776Z"
+        android:fillColor="#A8DAB5"/>
+    <path
+        android:pathData="M30,86L36.198,44.382C36.704,40.99 38.762,38.028 41.764,36.371L49.776,31.951C50.916,31.322 51.936,30.495 52.787,29.51L61,20L78.5,-4"
+        android:strokeWidth="2"
+        android:fillColor="#00000000"
+        android:strokeColor="#DADCE0"/>
+    <path
+        android:pathData="M50.486,72.296a5.5,4.5 105.673,1 0,8.665 2.431a5.5,4.5 105.673,1 0,-8.665 -2.431z"
+        android:strokeWidth="2"
+        android:fillColor="#A8DAB5"
+        android:strokeColor="#DADCE0"/>
+    <path
+        android:pathData="M62.077,18.699m-2.888,-0.81a3,3 57.086,1 1,5.777 1.621a3,3 60.818,1 1,-5.777 -1.621"
+        android:strokeWidth="2"
+        android:fillColor="#F1F3F4"
+        android:strokeColor="#DADCE0"/>
+    <path
+        android:pathData="M57,68.5L61.682,59.136C62.548,57.404 63.82,55.908 65.389,54.775L71.051,50.685C71.682,50.229 72.267,49.714 72.798,49.145L86,35"
+        android:strokeWidth="2"
+        android:fillColor="#00000000"
+        android:strokeColor="#DADCE0"/>
+    <path
+        android:pathData="M50,71.5L33.5,66.5"
+        android:strokeWidth="2"
+        android:fillColor="#00000000"
+        android:strokeColor="#DADCE0"/>
+    <path
+        android:pathData="M59.5,75.5L83,83.5"
+        android:strokeWidth="2"
+        android:fillColor="#00000000"
+        android:strokeColor="#DADCE0"/>
+    <path
+        android:pathData="M53,79L49.5,89L82.5,96"
+        android:strokeWidth="2"
+        android:fillColor="#00000000"
+        android:strokeColor="#DADCE0"/>
+    <path
+        android:pathData="M-7.5,44.5L13.801,51.471C17.792,52.777 21.158,55.514 23.251,59.154L28.58,68.421C30.472,71.712 31.208,75.542 30.671,79.299L29.5,87.5"
+        android:strokeWidth="2"
+        android:fillColor="#00000000"
+        android:strokeColor="#DADCE0"/>
+    <path
+        android:pathData="M15,-7L38.743,16.531L86,63"
+        android:strokeWidth="2"
+        android:fillColor="#00000000"
+        android:strokeColor="#DADCE0"/>
+    <path
+        android:pathData="M25,30.5L17.5,53"
+        android:strokeWidth="2"
+        android:fillColor="#00000000"
+        android:strokeColor="#DADCE0"/>
+    <path
+        android:pathData="M89,12L75,20.5L63.5,40.5L53.5,49.5L43,69L40,88"
+        android:strokeWidth="2"
+        android:fillColor="#00000000"
+        android:strokeColor="#DADCE0"/>
+    <path
+        android:pathData="M5.447,18.308L-7.294,27.116C-9.392,28.567 -12.293,27.474 -12.913,25C-13.193,23.886 -12.932,22.706 -12.209,21.813L1.566,4.805C3.066,2.953 5.099,1.608 7.391,0.952L9.355,0.39C12.007,-0.369 14.862,0.302 16.898,2.163C18.244,3.392 19.126,5.047 19.396,6.849L19.986,10.779C20.065,11.311 19.99,11.854 19.767,12.344C19.432,13.083 18.791,13.64 18.012,13.868L9.585,16.335C8.109,16.767 6.712,17.433 5.447,18.308Z"
+        android:strokeWidth="2"
+        android:fillColor="#78D9EC"
+        android:strokeColor="#DADCE0"/>
+    <path
+        android:pathData="M39.228,39.683m-5.956,-0.727a6,6 74.012,1 1,11.912 1.455a6,6 74.012,1 1,-11.912 -1.455"
+        android:fillColor="#ffffff"/>
+    <path
+        android:pathData="M35.059,39.174a4.2,4.2 51.963,1 0,8.338 1.018a4.2,4.2 51.963,1 0,-8.338 -1.018z"
+        android:fillColor="#1967D2"/>
+  </group>
+</vector>
diff --git a/components/browser_ui/widget/android/test/java/res/layout/rich_radio_button_render_test.xml b/components/browser_ui/widget/android/test/java/res/layout/rich_radio_button_render_test.xml
new file mode 100644
index 0000000..275ab39
--- /dev/null
+++ b/components/browser_ui/widget/android/test/java/res/layout/rich_radio_button_render_test.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2025 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/test_rich_radio_button_layout"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:padding="16dp">
+
+    <org.chromium.components.browser_ui.widget.RichRadioButton
+        android:id="@+id/rich_rb_horizontal_full_unchecked"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="8dp" />
+
+    <org.chromium.components.browser_ui.widget.RichRadioButton
+        android:id="@+id/rich_rb_horizontal_title_checked"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="8dp" />
+
+    <org.chromium.components.browser_ui.widget.RichRadioButton
+        android:id="@+id/rich_rb_horizontal_minimal_unchecked"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="8dp" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/components/cdm/renderer/key_system_support_update.cc b/components/cdm/renderer/key_system_support_update.cc
index 41cb0cc..83c9c52 100644
--- a/components/cdm/renderer/key_system_support_update.cc
+++ b/components/cdm/renderer/key_system_support_update.cc
@@ -257,7 +257,9 @@
 
 // Returns whether persistent-license session can be supported.
 bool CanSupportPersistentLicense() {
-  // Do not support persistent-license if the process cannot persist data.
+  if (!base::FeatureList::IsEnabled(media::kWidvinePersistentLicenseSupport)) {
+    return false;
+  }
 
 #if BUILDFLAG(IS_CHROMEOS)
   // On ChromeOS, platform verification is similar to CDM host verification
@@ -293,6 +295,7 @@
 base::flat_set<CdmSessionType> UpdatePersistentLicenseSupport(
     bool can_persist_data,
     base::flat_set<CdmSessionType> session_types) {
+  // Do not support persistent-license if the process cannot persist data.
   if (!can_persist_data || !CanSupportPersistentLicense()) {
     session_types.erase(CdmSessionType::kPersistentLicense);
   }
diff --git a/components/collaboration/internal/messaging/messaging_backend_service_impl_unittest.cc b/components/collaboration/internal/messaging/messaging_backend_service_impl_unittest.cc
index bbbed57..f8730090 100644
--- a/components/collaboration/internal/messaging/messaging_backend_service_impl_unittest.cc
+++ b/components/collaboration/internal/messaging/messaging_backend_service_impl_unittest.cc
@@ -178,7 +178,6 @@
               (override));
   MOCK_METHOD(void, Initialize, (), (override));
   MOCK_METHOD(bool, IsInitialized, (), (override));
-  MOCK_METHOD(bool, HadSharedTabGroupsLastSession, (bool), (override));
 };
 
 class MockDataSharingChangeNotifier : public DataSharingChangeNotifier {
diff --git a/components/collaboration/internal/messaging/tab_group_change_notifier.h b/components/collaboration/internal/messaging/tab_group_change_notifier.h
index a64c534a..5bc8a08 100644
--- a/components/collaboration/internal/messaging/tab_group_change_notifier.h
+++ b/components/collaboration/internal/messaging/tab_group_change_notifier.h
@@ -92,11 +92,6 @@
 
   // Whether this instance has finished initialization.
   virtual bool IsInitialized() = 0;
-
-  // Returns if shared tab group existed during startup. If
-  // `open_shared_tab_groups` is true, returns whether there were open shared
-  // tab groups during startup.
-  virtual bool HadSharedTabGroupsLastSession(bool open_shared_tab_groups) = 0;
 };
 
 }  // namespace collaboration::messaging
diff --git a/components/collaboration/internal/messaging/tab_group_change_notifier_impl.cc b/components/collaboration/internal/messaging/tab_group_change_notifier_impl.cc
index 4b58920..1320fdb5 100644
--- a/components/collaboration/internal/messaging/tab_group_change_notifier_impl.cc
+++ b/components/collaboration/internal/messaging/tab_group_change_notifier_impl.cc
@@ -158,14 +158,6 @@
     last_known_tab_groups_ = ConvertToMapOfSharedTabGroup(*original_tab_groups);
   }
 
-  had_shared_tab_groups_on_startup_ = !last_known_tab_groups_.empty();
-  for (const auto& [guid, group] : last_known_tab_groups_) {
-    if (group.local_group_id().has_value()) {
-      had_open_shared_tab_groups_on_startup_ = true;
-      break;
-    }
-  }
-
   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
       FROM_HERE,
       base::BindOnce(
@@ -190,12 +182,6 @@
              tab_groups::SyncBridgeUpdateType::kDisableSync;
 }
 
-bool TabGroupChangeNotifierImpl::HadSharedTabGroupsLastSession(
-    bool open_shared_tab_groups) {
-  return open_shared_tab_groups ? had_open_shared_tab_groups_on_startup_
-                                : had_shared_tab_groups_on_startup_;
-}
-
 void TabGroupChangeNotifierImpl::OnTabGroupAdded(
     const tab_groups::SavedTabGroup& group,
     tab_groups::TriggerSource source) {
diff --git a/components/collaboration/internal/messaging/tab_group_change_notifier_impl.h b/components/collaboration/internal/messaging/tab_group_change_notifier_impl.h
index 33cb461..2ee4a34 100644
--- a/components/collaboration/internal/messaging/tab_group_change_notifier_impl.h
+++ b/components/collaboration/internal/messaging/tab_group_change_notifier_impl.h
@@ -38,7 +38,6 @@
   void RemoveObserver(TabGroupChangeNotifier::Observer* observer) override;
   void Initialize() override;
   bool IsInitialized() override;
-  bool HadSharedTabGroupsLastSession(bool open_shared_tab_groups) override;
 
   void OnTabGroupOpenedOrClosed(
       const base::Uuid& sync_id,
@@ -129,12 +128,6 @@
   // has been applied.
   bool ignore_tab_selection_events_ = false;
 
-  // Whether shared tab groups existed during startup.
-  bool had_shared_tab_groups_on_startup_ = false;
-
-  // Whether open shared tab groups existed during startup.
-  bool had_open_shared_tab_groups_on_startup_ = false;
-
   base::WeakPtrFactory<TabGroupChangeNotifierImpl> weak_ptr_factory_{this};
 };
 
diff --git a/components/collaboration/internal/messaging/tab_group_change_notifier_impl_unittest.cc b/components/collaboration/internal/messaging/tab_group_change_notifier_impl_unittest.cc
index dc532f4..bbdb1b9a 100644
--- a/components/collaboration/internal/messaging/tab_group_change_notifier_impl_unittest.cc
+++ b/components/collaboration/internal/messaging/tab_group_change_notifier_impl_unittest.cc
@@ -420,42 +420,6 @@
             tab_group_4_received_color.color());
 }
 
-TEST_F(TabGroupChangeNotifierImplTest,
-       TestHadSharedTabGroupsOnStartup_OpenGroups) {
-  tab_groups::SavedTabGroup tab_group_1 = CreateTestSharedTabGroup();
-  tab_group_1.SetLocalGroupId(tab_groups::test::GenerateRandomTabGroupID());
-  InitializeNotifier({tab_group_1}, /*init_tab_groups=*/{});
-
-  EXPECT_TRUE(notifier_->HadSharedTabGroupsLastSession(
-      /*open_shared_tab_groups=*/false));
-  EXPECT_TRUE(notifier_->HadSharedTabGroupsLastSession(
-      /*open_shared_tab_groups=*/true));
-}
-
-TEST_F(TabGroupChangeNotifierImplTest,
-       TestHadSharedTabGroupsOnStartup_NoOpenGroups) {
-  tab_groups::SavedTabGroup tab_group_1 = CreateTestSharedTabGroup();
-  InitializeNotifier({tab_group_1},
-                     /*init_tab_groups=*/{});
-
-  EXPECT_TRUE(notifier_->HadSharedTabGroupsLastSession(
-      /*open_shared_tab_groups=*/false));
-  EXPECT_FALSE(notifier_->HadSharedTabGroupsLastSession(
-      /*open_shared_tab_groups=*/true));
-}
-
-TEST_F(TabGroupChangeNotifierImplTest,
-       TestHadSharedTabGroupsOnStartup_NoGroups) {
-  InitializeNotifier(
-      /*startup_tab_groups=*/{},
-      /*init_tab_groups=*/{});
-
-  EXPECT_FALSE(notifier_->HadSharedTabGroupsLastSession(
-      /*open_shared_tab_groups=*/false));
-  EXPECT_FALSE(notifier_->HadSharedTabGroupsLastSession(
-      /*open_shared_tab_groups=*/true));
-}
-
 TEST_F(TabGroupChangeNotifierImplTest, TestTabGroupsAddedLocally) {
   // Initialize the notifier with an empty set of tab groups available on
   // startup and on init.
diff --git a/components/embedder_support/android/BUILD.gn b/components/embedder_support/android/BUILD.gn
index 0b633d0b..d3c2ed6 100644
--- a/components/embedder_support/android/BUILD.gn
+++ b/components/embedder_support/android/BUILD.gn
@@ -367,6 +367,7 @@
     "//third_party/blink/public:blink_headers_java",
     "//third_party/junit",
     "//ui/android:ui_java",
+    "//ui/android:ui_java_test_support",
     "//url:url_java",
   ]
 }
diff --git a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/view/ContentView.java b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/view/ContentView.java
index a7cb945..db2a721 100644
--- a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/view/ContentView.java
+++ b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/view/ContentView.java
@@ -7,6 +7,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.os.Build;
 import android.os.Handler;
 import android.util.SparseArray;
 import android.view.DragEvent;
@@ -25,6 +26,8 @@
 import android.view.inputmethod.InputConnection;
 import android.widget.FrameLayout;
 
+import androidx.annotation.VisibleForTesting;
+
 import org.chromium.base.ObserverList;
 import org.chromium.base.TraceEvent;
 import org.chromium.build.annotations.EnsuresNonNullIf;
@@ -32,6 +35,7 @@
 import org.chromium.build.annotations.Nullable;
 import org.chromium.components.autofill.AndroidAutofillFeatures;
 import org.chromium.components.embedder_support.util.TouchEventFilter;
+import org.chromium.content_public.browser.GestureListenerManager;
 import org.chromium.content_public.browser.ImeAdapter;
 import org.chromium.content_public.browser.RenderCoordinates;
 import org.chromium.content_public.browser.SmartClipProvider;
@@ -39,11 +43,13 @@
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.WebContentsAccessibility;
 import org.chromium.ui.accessibility.AccessibilityState;
+import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.base.EventForwarder;
 import org.chromium.ui.base.EventOffsetHandler;
 import org.chromium.ui.base.ViewAndroidDelegate;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.dragdrop.DragEventDispatchHelper.DragEventDispatchDestination;
+import org.chromium.ui.util.MotionEventUtils;
 
 import java.util.function.Supplier;
 
@@ -78,9 +84,12 @@
     private ViewEventSink mViewEventSink;
     @Nullable private Supplier<PointerIcon> mStylusWritingIconSupplier;
 
+    // TODO(b/422918648): Remove this.
+    @Nullable private MotionEvent mPendingTwoFingerSwipeDownEvent;
+
     /**
-     * The desired size of this view in {@link MeasureSpec}. Set by the host
-     * when it should be different from that of the parent.
+     * The desired size of this view in {@link MeasureSpec}. Set by the host when it should be
+     * different from that of the parent.
      */
     private int mDesiredWidthMeasureSpec = DEFAULT_MEASURE_SPEC;
 
@@ -393,10 +402,60 @@
         return forwarder != null ? forwarder.onDragEvent(event, this) : false;
     }
 
+    @VisibleForTesting
+    boolean maybeHandleTwoFingerSwipeEvent(
+            MotionEvent event, EventForwarder forwarder, GestureListenerManager gestureManager) {
+        // HACK: InputFlinger (namely, in GestureConverter::handleFling()) may generate fake touch
+        // events after a Two-finger swipe on a trackpad which is an ACTION_DOWN MotionEvent
+        // immediately followed by ACTION_CANCEL. These events are to stop the active fling scroll,
+        // but may cause unexpected behaviors in web contents when not scrolling. Ignore them
+        // unless there is an active fling scroll. (b/405275205).
+        // TODO(b/422918648): Remove this desktop-only hack.
+        if (forwarder == null || gestureManager == null) {
+            return false;
+        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
+                && Build.VERSION.SDK_INT <= 38
+                && DeviceFormFactor.isDesktop()) {
+            if (mPendingTwoFingerSwipeDownEvent != null) {
+                // We expect to receive a two finger swipe event after having received a down from
+                // two finger swipe.
+                assert (event.getClassification() == MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE);
+            }
+            if (MotionEventUtils.isTrackpadEvent(event)
+                    && event.getClassification() == MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE
+                    && forwarder != null) {
+                if (mPendingTwoFingerSwipeDownEvent != null) {
+                    MotionEvent lastEvent = mPendingTwoFingerSwipeDownEvent;
+                    mPendingTwoFingerSwipeDownEvent = null;
+                    // Ignore ACTION_DOWN followed by ACTION_CANCEL unless there is an active fling
+                    // scroll. If there is, send them to cancel the scroll.
+                    if (event.getAction() == MotionEvent.ACTION_CANCEL
+                            && !gestureManager.hasActiveFlingScroll()) {
+                        return true;
+                    }
+                    // Send the stored event.
+                    forwarder.onTouchEvent(lastEvent);
+                }
+                // Store ACTION_DOWN event to see if the next event is ACTION_CANCEL or not.
+                if (event.getAction() == MotionEvent.ACTION_DOWN) {
+                    mPendingTwoFingerSwipeDownEvent = MotionEvent.obtain(event);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         if (TouchEventFilter.hasInvalidToolType(event)) return false;
         EventForwarder forwarder = getEventForwarder();
+        GestureListenerManager gestureManager =
+                webContentsAttached() ? GestureListenerManager.fromWebContents(mWebContents) : null;
+        if (maybeHandleTwoFingerSwipeEvent(event, forwarder, gestureManager)) {
+            return true;
+        }
         boolean ret = forwarder != null ? forwarder.onTouchEvent(event) : false;
         return ret;
     }
diff --git a/components/embedder_support/android/junit/src/org/chromium/components/embedder_support/view/ContentViewTest.java b/components/embedder_support/android/junit/src/org/chromium/components/embedder_support/view/ContentViewTest.java
index 8247399..bf07726 100644
--- a/components/embedder_support/android/junit/src/org/chromium/components/embedder_support/view/ContentViewTest.java
+++ b/components/embedder_support/android/junit/src/org/chromium/components/embedder_support/view/ContentViewTest.java
@@ -5,14 +5,21 @@
 package org.chromium.components.embedder_support.view;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.mockito.MockitoAnnotations.openMocks;
 
 import android.content.Context;
+import android.os.Build;
 import android.util.SparseArray;
 import android.view.MotionEvent;
 import android.view.PointerIcon;
@@ -27,9 +34,14 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.robolectric.annotation.Config;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.content_public.browser.GestureListenerManager;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.ui.base.DeviceFormFactor;
+import org.chromium.ui.base.EventForwarder;
+import org.chromium.ui.base.MotionEventTestUtils;
 import org.chromium.ui.base.ViewAndroidDelegate;
 
 /**
@@ -92,4 +104,69 @@
         mContentView.autofill(values);
         verify(mViewDelegate).autofill(values);
     }
+
+    private MotionEvent getTwoFingerSwipeTrackpadEvent(int action) {
+        // Use Mockito.spy to override the return value of getClassification(). For some reason,
+        // MotionEvent.obtain() ignores the specified classification value when in unit tests.
+        // b/424066383.
+        MotionEvent event = spy(MotionEventTestUtils.getTrackpadEvent(action, 0));
+        when(event.getClassification()).thenReturn(MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE);
+        return event;
+    }
+
+    @Test
+    @SmallTest
+    @Config(sdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    public void testIgnoreFakeTwoFingerSwipeEventsOnDesktop() {
+        // This is a test for desktop-only hack.
+        if (!DeviceFormFactor.isDesktop()) {
+            return;
+        }
+        EventForwarder forwarder = mock(EventForwarder.class);
+        GestureListenerManager gestureManager = mock(GestureListenerManager.class);
+
+        // ACTION_DOWN followed by ACTION_CANCEL with no active fling scroll. ACTION_DOWN and
+        // ACTION_CANCEL are consumed and not sent to EventForwarder.
+        when(gestureManager.hasActiveFlingScroll()).thenReturn(false);
+        assertTrue(
+                mContentView.maybeHandleTwoFingerSwipeEvent(
+                        getTwoFingerSwipeTrackpadEvent(MotionEvent.ACTION_DOWN),
+                        forwarder,
+                        gestureManager));
+        assertTrue(
+                mContentView.maybeHandleTwoFingerSwipeEvent(
+                        getTwoFingerSwipeTrackpadEvent(MotionEvent.ACTION_CANCEL),
+                        forwarder,
+                        gestureManager));
+        verify(forwarder, never()).onTouchEvent(any());
+
+        // ACTION_DOWN followed by ACTION_CANCEL with an active fling scroll. ACTION_DOWN gets sent
+        // to EventForwarder, and ACTION_CANCEL is not consumed.
+        when(gestureManager.hasActiveFlingScroll()).thenReturn(true);
+        assertTrue(
+                mContentView.maybeHandleTwoFingerSwipeEvent(
+                        getTwoFingerSwipeTrackpadEvent(MotionEvent.ACTION_DOWN),
+                        forwarder,
+                        gestureManager));
+        assertFalse(
+                mContentView.maybeHandleTwoFingerSwipeEvent(
+                        getTwoFingerSwipeTrackpadEvent(MotionEvent.ACTION_CANCEL),
+                        forwarder,
+                        gestureManager));
+        verify(forwarder, times(1)).onTouchEvent(any());
+
+        // ACTION_DOWN followed by ACTION_MOVE. ACTION_DOWN gets sent to EventForwarder, and
+        // ACTION_MOVE is not consumed.
+        assertTrue(
+                mContentView.maybeHandleTwoFingerSwipeEvent(
+                        getTwoFingerSwipeTrackpadEvent(MotionEvent.ACTION_DOWN),
+                        forwarder,
+                        gestureManager));
+        assertFalse(
+                mContentView.maybeHandleTwoFingerSwipeEvent(
+                        getTwoFingerSwipeTrackpadEvent(MotionEvent.ACTION_MOVE),
+                        forwarder,
+                        gestureManager));
+        verify(forwarder, times(2)).onTouchEvent(any());
+    }
 }
diff --git a/components/ntp_tiles/most_visited_sites.cc b/components/ntp_tiles/most_visited_sites.cc
index 2aae51db..d876c22 100644
--- a/components/ntp_tiles/most_visited_sites.cc
+++ b/components/ntp_tiles/most_visited_sites.cc
@@ -277,7 +277,7 @@
 
   // Immediately build the current set of tiles, getting suggestions from
   // TopSites.
-  BuildCurrentTiles();
+  BuildCurrentTiles(/* is_user_triggered= */ false);
   // Also start a request for fresh suggestions.
   Refresh();
 }
@@ -295,7 +295,7 @@
 }
 
 void MostVisitedSites::RefreshTiles() {
-  BuildCurrentTiles();
+  BuildCurrentTiles(/* is_user_triggered= */ false);
 }
 
 void MostVisitedSites::InitializeCustomLinks() {
@@ -325,7 +325,7 @@
 
   custom_links_action_count_ = -1;
   custom_links_manager_->Uninitialize();
-  BuildCurrentTiles();
+  BuildCurrentTiles(/* is_user_triggered= */ true);
 }
 
 bool MostVisitedSites::IsCustomLinksInitialized() {
@@ -340,7 +340,7 @@
 void MostVisitedSites::EnableCustomLinks(bool enable) {
   if (is_custom_links_enabled_ != enable) {
     is_custom_links_enabled_ = enable;
-    BuildCurrentTiles();
+    BuildCurrentTiles(/* is_user_triggered= */ true);
   }
 }
 
@@ -351,7 +351,7 @@
 void MostVisitedSites::SetShortcutsVisible(bool visible) {
   if (is_shortcuts_visible_ != visible) {
     is_shortcuts_visible_ = visible;
-    BuildCurrentTiles();
+    BuildCurrentTiles(/* is_user_triggered= */ true);
   }
 }
 
@@ -412,7 +412,7 @@
   if (custom_links_action_count_-- == 1) {
     UninitializeCustomLinks();
   } else if (custom_links_manager_->UndoAction()) {
-    BuildCurrentTiles();
+    BuildCurrentTiles(/* is_user_triggered= */ true);
   }
 }
 
@@ -445,7 +445,7 @@
 
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
 void MostVisitedSites::OnURLFilterChanged() {
-  BuildCurrentTiles();
+  BuildCurrentTiles(/* is_user_triggered= */ false);
 }
 #endif
 
@@ -470,19 +470,20 @@
 #endif
 }
 
-void MostVisitedSites::InitiateTopSitesQuery() {
+void MostVisitedSites::InitiateTopSitesQuery(bool is_user_triggered) {
   if (!top_sites_) {
     return;
   }
   if (top_sites_weak_ptr_factory_.HasWeakPtrs()) {
     return;  // Ongoing query.
   }
-  top_sites_->GetMostVisitedURLs(
-      base::BindOnce(&MostVisitedSites::OnMostVisitedURLsAvailable,
-                     top_sites_weak_ptr_factory_.GetWeakPtr()));
+  top_sites_->GetMostVisitedURLs(base::BindOnce(
+      &MostVisitedSites::OnMostVisitedURLsAvailable,
+      top_sites_weak_ptr_factory_.GetWeakPtr(), is_user_triggered));
 }
 
 void MostVisitedSites::OnMostVisitedURLsAvailable(
+    bool is_user_triggered,
     const history::MostVisitedURLList& visited_list) {
   // Ignore the event if tiles are exclusively provided by custom links.
   if (IsExclusivelyCustomLinks()) {
@@ -519,16 +520,16 @@
     tiles.push_back(std::move(tile));
   }
 
-  InitiateNotificationForNewTiles(std::move(tiles));
+  InitiateNotificationForNewTiles(is_user_triggered, std::move(tiles));
 }
 
-void MostVisitedSites::BuildCurrentTiles() {
+void MostVisitedSites::BuildCurrentTiles(bool is_user_triggered) {
   ReloadCustomLinksCache();
   if (IsExclusivelyCustomLinks()) {
-    SaveTilesAndNotify(NTPTilesVector(),
+    SaveTilesAndNotify(is_user_triggered, NTPTilesVector(),
                        std::map<SectionType, NTPTilesVector>());
   } else {
-    InitiateTopSitesQuery();
+    InitiateTopSitesQuery(is_user_triggered);
   }
 }
 
@@ -611,13 +612,15 @@
 }
 
 void MostVisitedSites::OnHomepageTitleDetermined(
+    bool is_user_triggered,
     NTPTilesVector tiles,
     const std::optional<std::u16string>& title) {
   if (!title.has_value()) {
     return;  // If there is no title, the most recent tile was already sent out.
   }
 
-  MergeMostVisitedTiles(InsertHomeTile(std::move(tiles), title.value()));
+  MergeMostVisitedTiles(is_user_triggered,
+                        InsertHomeTile(std::move(tiles), title.value()));
 }
 
 NTPTilesVector MostVisitedSites::InsertHomeTile(
@@ -682,7 +685,7 @@
     if (custom_links_action_count_ != -1) {
       custom_links_action_count_++;
     }
-    BuildCurrentTiles();
+    BuildCurrentTiles(/* is_user_triggered= */ true);
   } else if (is_first_action) {
     // We don't want to keep custom links initialized if the first action after
     // initialization failed.
@@ -693,7 +696,7 @@
 
 void MostVisitedSites::OnCustomLinksChanged() {
   DCHECK(custom_links_manager_);
-  BuildCurrentTiles();
+  BuildCurrentTiles(/* is_user_triggered= */ true);
 }
 
 void MostVisitedSites::ReloadCustomLinksCache() {
@@ -728,11 +731,12 @@
 }
 
 void MostVisitedSites::InitiateNotificationForNewTiles(
+    bool is_user_triggered,
     NTPTilesVector new_tiles) {
   if (ShouldAddHomeTile() && !HasHomeTile(new_tiles)) {
     homepage_client_->QueryHomepageTitle(
         base::BindOnce(&MostVisitedSites::OnHomepageTitleDetermined,
-                       base::Unretained(this), new_tiles));
+                       base::Unretained(this), is_user_triggered, new_tiles));
     GURL homepage_url = homepage_client_->GetHomepageUrl();
     icon_cacher_->StartFetchMostLikely(
         homepage_url,
@@ -743,10 +747,11 @@
     // copy of new tiles.
     new_tiles = InsertHomeTile(std::move(new_tiles), std::u16string());
   }
-  MergeMostVisitedTiles(std::move(new_tiles));
+  MergeMostVisitedTiles(is_user_triggered, std::move(new_tiles));
 }
 
-void MostVisitedSites::MergeMostVisitedTiles(NTPTilesVector personal_tiles) {
+void MostVisitedSites::MergeMostVisitedTiles(bool is_user_triggered,
+                                             NTPTilesVector personal_tiles) {
   std::set<std::string> used_hosts;
 
   size_t num_actual_tiles = 0;
@@ -762,7 +767,8 @@
       MergeTiles(std::move(personal_tiles),
                  std::move(sections[SectionType::PERSONALIZED]));
 
-  SaveTilesAndNotify(std::move(new_tiles), std::move(sections));
+  SaveTilesAndNotify(is_user_triggered, std::move(new_tiles),
+                     std::move(sections));
 }
 
 NTPTilesVector MostVisitedSites::ImposeCustomLinks(NTPTilesVector tiles) {
@@ -786,6 +792,7 @@
 }
 
 void MostVisitedSites::SaveTilesAndNotify(
+    bool is_user_triggered,
     NTPTilesVector new_tiles,
     std::map<SectionType, NTPTilesVector> sections) {
   // TODO(crbug.com/40802205):
@@ -819,7 +826,7 @@
   }
   sections[SectionType::PERSONALIZED] = *current_tiles_;
   for (auto& observer : observers_) {
-    observer.OnURLsAvailable(sections);
+    observer.OnURLsAvailable(is_user_triggered, sections);
   }
 }
 
@@ -893,7 +900,9 @@
   if (!IsExclusivelyCustomLinks()) {
     // Call InitiateTopSitesQuery() instead of BuildCurrentTiles() to skip
     // unneeded |custom_links_cache_| update.
-    InitiateTopSitesQuery();
+    bool is_user_triggered =
+        (change_reason == TopSitesObserver::ChangeReason::BLOCKED_URLS);
+    InitiateTopSitesQuery(is_user_triggered);
   }
 }
 
diff --git a/components/ntp_tiles/most_visited_sites.h b/components/ntp_tiles/most_visited_sites.h
index c620743..b16e015 100644
--- a/components/ntp_tiles/most_visited_sites.h
+++ b/components/ntp_tiles/most_visited_sites.h
@@ -93,8 +93,13 @@
   // The observer to be notified when the list of most visited sites changes.
   class Observer : public base::CheckedObserver {
    public:
+    // |is_user_triggered| specifies whether the event is caused by direct user
+    // action in MV tiles. The UI can use this to decide whether MV tile updates
+    // (in multiple NTPs) should be eager (for responsiveness) or deferred (for
+    // tile stability).
     // |sections| must at least contain the PERSONALIZED section.
     virtual void OnURLsAvailable(
+        bool is_user_triggered,
         const std::map<SectionType, NTPTilesVector>& sections) = 0;
     virtual void OnIconMadeAvailable(const GURL& site_url) = 0;
   };
@@ -293,15 +298,16 @@
   size_t GetMaxNumSites() const;
 
   // Initialize the query to Top Sites.
-  void InitiateTopSitesQuery();
+  void InitiateTopSitesQuery(bool is_user_triggered);
 
   // Callback for when data is available from TopSites.
   void OnMostVisitedURLsAvailable(
+      bool is_user_triggered,
       const history::MostVisitedURLList& visited_list);
 
   // Builds the current tileset based on available caches and notifies the
   // observer.
-  void BuildCurrentTiles();
+  void BuildCurrentTiles(bool is_user_triggered);
 
   // Creates tiles for all popular site sections. Uses |num_actual_tiles| and
   // |used_hosts| to restrict results for the PERSONALIZED section.
@@ -331,11 +337,13 @@
 
   // Initiates a query for the homepage tile if needed and calls
   // |SaveTilesAndNotify| in the end.
-  void InitiateNotificationForNewTiles(NTPTilesVector new_tiles);
+  void InitiateNotificationForNewTiles(bool is_user_triggered,
+                                       NTPTilesVector new_tiles);
 
   // Takes the personal tiles and merges in popular tiles if appropriate. Calls
   // |SaveTilesAndNotify| at the end.
-  void MergeMostVisitedTiles(NTPTilesVector personal_tiles);
+  void MergeMostVisitedTiles(bool is_user_triggered,
+                             NTPTilesVector personal_tiles);
 
   // Removes pre installed apps which turn invalid because of migration.
   NTPTilesVector RemoveInvalidPreinstallApps(NTPTilesVector new_tiles);
@@ -346,7 +354,8 @@
 
   // Saves the new tiles and notifies the observer if the tiles were actually
   // changed.
-  void SaveTilesAndNotify(NTPTilesVector new_tiles,
+  void SaveTilesAndNotify(bool is_user_triggered,
+                          NTPTilesVector new_tiles,
                           std::map<SectionType, NTPTilesVector> sections);
 
   void OnPopularSitesDownloaded(bool success);
@@ -365,7 +374,8 @@
   NTPTilesVector InsertHomeTile(NTPTilesVector tiles,
                                 const std::u16string& title) const;
 
-  void OnHomepageTitleDetermined(NTPTilesVector tiles,
+  void OnHomepageTitleDetermined(bool is_user_triggered,
+                                 NTPTilesVector tiles,
                                  const std::optional<std::u16string>& title);
 
   // Returns true if there is a valid homepage that can be pinned as tile.
diff --git a/components/ntp_tiles/most_visited_sites_unittest.cc b/components/ntp_tiles/most_visited_sites_unittest.cc
index 7e30e2c..2135c8085 100644
--- a/components/ntp_tiles/most_visited_sites_unittest.cc
+++ b/components/ntp_tiles/most_visited_sites_unittest.cc
@@ -176,8 +176,9 @@
 
 class MockMostVisitedSitesObserver : public MostVisitedSites::Observer {
  public:
-  MOCK_METHOD1(OnURLsAvailable,
-               void(const std::map<SectionType, NTPTilesVector>& sections));
+  MOCK_METHOD2(OnURLsAvailable,
+               void(bool is_user_triggered,
+                    const std::map<SectionType, NTPTilesVector>& sections));
   MOCK_METHOD1(OnIconMadeAvailable, void(const GURL& site_url));
 };
 
@@ -543,8 +544,9 @@
   EXPECT_CALL(*mock_top_sites_, IsBlocked(Eq(GURL(kHomepageUrl))))
       .Times(AnyNumber())
       .WillRepeatedly(Return(false));
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(FirstPersonalizedTileIs(
-                                  u"", kHomepageUrl, TileSource::HOMEPAGE)));
+  EXPECT_CALL(mock_observer_,
+              OnURLsAvailable(_, FirstPersonalizedTileIs(
+                                     u"", kHomepageUrl, TileSource::HOMEPAGE)));
   most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
                                                   /*max_num_sites=*/3);
   base::RunLoop().RunUntilIdle();
@@ -555,11 +557,12 @@
       .WillRepeatedly(
           base::test::RunOnceCallbackRepeatedly<0>(MostVisitedURLList{}));
   EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
-  EXPECT_CALL(mock_observer_,
-              OnURLsAvailable(Contains(
-                  Pair(SectionType::PERSONALIZED,
-                       Not(Contains(MatchesTile(u"", kHomepageUrl,
-                                                TileSource::HOMEPAGE)))))));
+  EXPECT_CALL(
+      mock_observer_,
+      OnURLsAvailable(
+          _, Contains(Pair(SectionType::PERSONALIZED,
+                           Not(Contains(MatchesTile(u"", kHomepageUrl,
+                                                    TileSource::HOMEPAGE)))))));
   most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
                                                   /*max_num_sites=*/3);
   base::RunLoop().RunUntilIdle();
@@ -581,16 +584,19 @@
       .WillRepeatedly(Return(false));
   {
     testing::Sequence seq;
-    EXPECT_CALL(mock_observer_,
-                OnURLsAvailable(Contains(
-                    Pair(SectionType::PERSONALIZED,
-                         Not(Contains(MatchesTile(u"", kHomepageUrl,
-                                                  TileSource::HOMEPAGE)))))));
-    EXPECT_CALL(mock_observer_,
-                OnURLsAvailable(Contains(
-                    Pair(SectionType::PERSONALIZED,
-                         Not(Contains(MatchesTile(kHomepageTitle, kHomepageUrl,
-                                                  TileSource::HOMEPAGE)))))));
+    EXPECT_CALL(
+        mock_observer_,
+        OnURLsAvailable(
+            _, Contains(Pair(SectionType::PERSONALIZED,
+                             Not(Contains(MatchesTile(
+                                 u"", kHomepageUrl, TileSource::HOMEPAGE)))))));
+    EXPECT_CALL(
+        mock_observer_,
+        OnURLsAvailable(
+            _,
+            Contains(Pair(SectionType::PERSONALIZED,
+                          Not(Contains(MatchesTile(kHomepageTitle, kHomepageUrl,
+                                                   TileSource::HOMEPAGE)))))));
   }
   most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
                                                   /*max_num_sites=*/3);
@@ -609,8 +615,9 @@
   EXPECT_CALL(*mock_top_sites_, IsBlocked(Eq(GURL(kHomepageUrl))))
       .Times(AnyNumber())
       .WillRepeatedly(Return(false));
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(FirstPersonalizedTileIs(
-                                  u"", kHomepageUrl, TileSource::HOMEPAGE)));
+  EXPECT_CALL(mock_observer_,
+              OnURLsAvailable(_, FirstPersonalizedTileIs(
+                                     u"", kHomepageUrl, TileSource::HOMEPAGE)));
   most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
                                                   /*max_num_sites=*/3);
   base::RunLoop().RunUntilIdle();
@@ -622,8 +629,10 @@
       .WillRepeatedly(
           base::test::RunOnceCallbackRepeatedly<0>(MostVisitedURLList{}));
   EXPECT_CALL(*mock_top_sites_, SyncWithHistory()).Times(0);
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(Not(FirstPersonalizedTileIs(
-                                  u"", kHomepageUrl, TileSource::HOMEPAGE))));
+  EXPECT_CALL(
+      mock_observer_,
+      OnURLsAvailable(_, Not(FirstPersonalizedTileIs(u"", kHomepageUrl,
+                                                     TileSource::HOMEPAGE))));
   most_visited_sites_->RefreshTiles();
   base::RunLoop().RunUntilIdle();
 }
@@ -640,7 +649,7 @@
       .WillRepeatedly(Return(false));
   EXPECT_CALL(
       mock_observer_,
-      OnURLsAvailable(Contains(Pair(SectionType::PERSONALIZED, IsEmpty()))));
+      OnURLsAvailable(_, Contains(Pair(SectionType::PERSONALIZED, IsEmpty()))));
   most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
                                                   /*max_num_sites=*/0);
   base::RunLoop().RunUntilIdle();
@@ -658,9 +667,10 @@
       .WillRepeatedly(Return(false));
   EXPECT_CALL(
       mock_observer_,
-      OnURLsAvailable(Contains(Pair(
-          SectionType::PERSONALIZED,
-          ElementsAre(MatchesTile(u"", kHomepageUrl, TileSource::HOMEPAGE))))));
+      OnURLsAvailable(
+          _, Contains(Pair(SectionType::PERSONALIZED,
+                           ElementsAre(MatchesTile(u"", kHomepageUrl,
+                                                   TileSource::HOMEPAGE))))));
   most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
                                                   /*max_num_sites=*/1);
   base::RunLoop().RunUntilIdle();
@@ -683,8 +693,8 @@
       .Times(AnyNumber())
       .WillRepeatedly(Return(false));
   std::map<SectionType, NTPTilesVector> sections;
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
-      .WillOnce(SaveArg<0>(&sections));
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _))
+      .WillOnce(SaveArg<1>(&sections));
   most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
                                                   /*max_num_sites=*/4);
   base::RunLoop().RunUntilIdle();
@@ -711,8 +721,8 @@
                              MakeMostVisitedURL(kTestTitle, kTestUrl)}));
   EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
   std::map<SectionType, NTPTilesVector> sections;
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
-      .WillRepeatedly(SaveArg<0>(&sections));
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _))
+      .WillRepeatedly(SaveArg<1>(&sections));
 
   most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
                                                   /*max_num_sites=*/2);
@@ -743,8 +753,8 @@
       .Times(AnyNumber())
       .WillRepeatedly(Return(false));
   std::map<SectionType, NTPTilesVector> sections;
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
-      .WillOnce(SaveArg<0>(&sections));
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _))
+      .WillOnce(SaveArg<1>(&sections));
   most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
                                                   /*max_num_sites=*/8);
   base::RunLoop().RunUntilIdle();
@@ -768,11 +778,13 @@
       .WillRepeatedly(Return(false));
   EXPECT_CALL(
       mock_observer_,
-      OnURLsAvailable(Contains(Pair(
-          SectionType::PERSONALIZED,
-          AllOf(Contains(MatchesTile(u"", kHomepageUrl, TileSource::HOMEPAGE)),
-                Not(Contains(MatchesTile(u"", kHomepageUrl,
-                                         TileSource::TOP_SITES))))))));
+      OnURLsAvailable(
+          _, Contains(Pair(
+                 SectionType::PERSONALIZED,
+                 AllOf(Contains(MatchesTile(u"", kHomepageUrl,
+                                            TileSource::HOMEPAGE)),
+                       Not(Contains(MatchesTile(u"", kHomepageUrl,
+                                                TileSource::TOP_SITES))))))));
   most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
                                                   /*max_num_sites=*/3);
   base::RunLoop().RunUntilIdle();
@@ -788,11 +800,12 @@
   EXPECT_CALL(*mock_top_sites_, IsBlocked(Eq(GURL(kHomepageUrl))))
       .Times(AnyNumber())
       .WillRepeatedly(Return(false));
-  EXPECT_CALL(mock_observer_,
-              OnURLsAvailable(Contains(
-                  Pair(SectionType::PERSONALIZED,
-                       Not(Contains(MatchesTile(u"", kHomepageUrl,
-                                                TileSource::HOMEPAGE)))))));
+  EXPECT_CALL(
+      mock_observer_,
+      OnURLsAvailable(
+          _, Contains(Pair(SectionType::PERSONALIZED,
+                           Not(Contains(MatchesTile(u"", kHomepageUrl,
+                                                    TileSource::HOMEPAGE)))))));
   most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
                                                   /*max_num_sites=*/3);
   base::RunLoop().RunUntilIdle();
@@ -810,9 +823,10 @@
   EXPECT_CALL(*mock_top_sites_, IsBlocked(Eq(kEmptyHomepageUrl)))
       .Times(AnyNumber())
       .WillRepeatedly(Return(false));
-  EXPECT_CALL(mock_observer_,
-              OnURLsAvailable(Not(FirstPersonalizedTileIs(
-                  u"", kEmptyHomepageUrl, TileSource::HOMEPAGE))));
+  EXPECT_CALL(
+      mock_observer_,
+      OnURLsAvailable(_, Not(FirstPersonalizedTileIs(u"", kEmptyHomepageUrl,
+                                                     TileSource::HOMEPAGE))));
   most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
                                                   /*max_num_sites=*/3);
   base::RunLoop().RunUntilIdle();
@@ -832,11 +846,12 @@
   EXPECT_CALL(*mock_top_sites_, IsBlocked(Eq(GURL(kHomepageUrl))))
       .Times(AtLeast(1))
       .WillRepeatedly(Return(true));
-  EXPECT_CALL(mock_observer_,
-              OnURLsAvailable(Contains(
-                  Pair(SectionType::PERSONALIZED,
-                       Not(Contains(MatchesTile(u"", kHomepageUrl,
-                                                TileSource::HOMEPAGE)))))));
+  EXPECT_CALL(
+      mock_observer_,
+      OnURLsAvailable(
+          _, Contains(Pair(SectionType::PERSONALIZED,
+                           Not(Contains(MatchesTile(u"", kHomepageUrl,
+                                                    TileSource::HOMEPAGE)))))));
 
   most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
                                                   /*max_num_sites=*/3);
@@ -854,11 +869,12 @@
   EXPECT_CALL(*mock_top_sites_, IsBlocked(Eq(GURL(kHomepageUrl))))
       .Times(AtLeast(1))
       .WillRepeatedly(Return(true));
-  EXPECT_CALL(mock_observer_,
-              OnURLsAvailable(Contains(
-                  Pair(SectionType::PERSONALIZED,
-                       Not(Contains(MatchesTile(u"", kHomepageUrl,
-                                                TileSource::HOMEPAGE)))))));
+  EXPECT_CALL(
+      mock_observer_,
+      OnURLsAvailable(
+          _, Contains(Pair(SectionType::PERSONALIZED,
+                           Not(Contains(MatchesTile(u"", kHomepageUrl,
+                                                    TileSource::HOMEPAGE)))))));
 
   most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
                                                   /*max_num_sites=*/3);
@@ -871,9 +887,10 @@
       .WillRepeatedly(Return(false));
   EXPECT_CALL(
       mock_observer_,
-      OnURLsAvailable(Contains(Pair(
-          SectionType::PERSONALIZED,
-          Contains(MatchesTile(u"", kHomepageUrl, TileSource::HOMEPAGE))))));
+      OnURLsAvailable(
+          _, Contains(Pair(SectionType::PERSONALIZED,
+                           Contains(MatchesTile(u"", kHomepageUrl,
+                                                TileSource::HOMEPAGE))))));
 
   most_visited_sites_->OnURLFilterChanged();
 
@@ -903,8 +920,8 @@
               MakeMostVisitedURL(u"Google", "http://www.google.com/")}));
   EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
   std::map<SectionType, NTPTilesVector> sections;
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
-      .WillOnce(SaveArg<0>(&sections));
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _))
+      .WillOnce(SaveArg<1>(&sections));
 
   most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
                                                   /*max_num_sites=*/6);
@@ -937,14 +954,16 @@
   InSequence seq;
   EXPECT_CALL(
       mock_observer_,
-      OnURLsAvailable(Contains(Pair(
-          SectionType::PERSONALIZED,
-          ElementsAre(
-              MatchesTile(u"Site 1", "http://site1/", TileSource::TOP_SITES),
-              MatchesTile(u"PopularSite1", "http://popularsite1/",
-                          TileSource::POPULAR),
-              MatchesTile(u"PopularSite2", "http://popularsite2/",
-                          TileSource::POPULAR))))));
+      OnURLsAvailable(
+          _,
+          Contains(Pair(
+              SectionType::PERSONALIZED,
+              ElementsAre(MatchesTile(u"Site 1", "http://site1/",
+                                      TileSource::TOP_SITES),
+                          MatchesTile(u"PopularSite1", "http://popularsite1/",
+                                      TileSource::POPULAR),
+                          MatchesTile(u"PopularSite2", "http://popularsite2/",
+                                      TileSource::POPULAR))))));
   EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
 
   most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
@@ -957,7 +976,7 @@
       .WillOnce(base::test::RunOnceCallback<0>(
           MostVisitedURLList{MakeMostVisitedURL(u"Site 2", "http://site2/")}));
   EXPECT_CALL(*mock_top_sites_, IsBlocked(_)).WillRepeatedly(Return(false));
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_));
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _));
   mock_top_sites_->NotifyTopSitesChanged(
       history::TopSitesObserver::ChangeReason::MOST_VISITED);
   base::RunLoop().RunUntilIdle();
@@ -973,8 +992,8 @@
               MakeMostVisitedURL(u"Google", "http://www.google.com/")}));
   EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
   std::map<SectionType, NTPTilesVector> sections;
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
-      .WillOnce(SaveArg<0>(&sections));
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _))
+      .WillOnce(SaveArg<1>(&sections));
 
   most_visited_sites_->AddMostVisitedURLsObserver(&mock_observer_,
                                                   /*max_num_sites=*/2);
@@ -992,10 +1011,10 @@
   sections.clear();
   std::map<SectionType, NTPTilesVector> sections_other;
   EXPECT_CALL(*mock_top_sites_, SyncWithHistory()).Times(1);
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
-      .WillRepeatedly(SaveArg<0>(&sections));
-  EXPECT_CALL(mock_other_observer_, OnURLsAvailable(_))
-      .WillOnce(SaveArg<0>(&sections_other));
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _))
+      .WillRepeatedly(SaveArg<1>(&sections));
+  EXPECT_CALL(mock_other_observer_, OnURLsAvailable(_, _))
+      .WillOnce(SaveArg<1>(&sections_other));
   most_visited_sites_->RefreshTiles();
   most_visited_sites_->AddMostVisitedURLsObserver(&mock_other_observer_,
                                                   /*max_num_sites=*/2);
@@ -1068,8 +1087,8 @@
     EXPECT_CALL(*mock_top_sites_, SyncWithHistory());
     EXPECT_CALL(*mock_custom_links_manager_, IsInitialized())
         .WillRepeatedly(Return(false));
-    EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
-        .WillOnce(SaveArg<0>(sections));
+    EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _))
+        .WillOnce(SaveArg<1>(sections));
   }
 
   void SetUpBuildWithCustomLinks(
@@ -1079,8 +1098,8 @@
         .WillRepeatedly(Return(true));
     EXPECT_CALL(*mock_custom_links_manager_, GetLinks())
         .WillOnce(ReturnRef(expected_links));
-    EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
-        .WillOnce(SaveArg<0>(sections));
+    EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _))
+        .WillOnce(SaveArg<1>(sections));
   }
 
   void SetUpBuildWithTopSitesAndCustomLinks(
@@ -1095,8 +1114,8 @@
         .WillRepeatedly(Return(true));
     EXPECT_CALL(*mock_custom_links_manager_, GetLinks())
         .WillOnce(ReturnRef(expected_links));
-    EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
-        .WillOnce(SaveArg<0>(sections));
+    EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _))
+        .WillOnce(SaveArg<1>(sections));
   }
 
   // `expected_url` is assumed to be duplicated in the Custom link and the
@@ -1144,7 +1163,7 @@
   EXPECT_TRUE(most_visited_sites_->IsShortcutsVisible());
 
   // Hide shortcuts. Observer should get notified.
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_)).Times(1);
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _)).Times(1);
   most_visited_sites_->SetShortcutsVisible(false);
   base::RunLoop().RunUntilIdle();
 
@@ -1152,12 +1171,12 @@
   EXPECT_FALSE(most_visited_sites_->IsShortcutsVisible());
 
   // Attempt to hide the shortcuts again. This should be ignored.
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_)).Times(0);
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _)).Times(0);
   most_visited_sites_->SetShortcutsVisible(false);
   base::RunLoop().RunUntilIdle();
 
   // Make the shortcuts visible. Observer should get notified.
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_)).Times(1);
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _)).Times(1);
   most_visited_sites_->SetShortcutsVisible(true);
   base::RunLoop().RunUntilIdle();
 
@@ -1203,8 +1222,8 @@
           MostVisitedURLList{MakeMostVisitedURL(kTestTitle, kTestUrl)}));
   EXPECT_CALL(*mock_custom_links_manager_, IsInitialized())
       .WillRepeatedly(Return(false));
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
-      .WillOnce(SaveArg<0>(&sections));
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _))
+      .WillOnce(SaveArg<1>(&sections));
   most_visited_sites_->UninitializeCustomLinks();
   base::RunLoop().RunUntilIdle();
   tiles = sections.at(SectionType::PERSONALIZED);
@@ -1246,7 +1265,7 @@
 
   // Initiate notification for new Top Sites. This should be ignored.
   VerifyAndClearExpectations();
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_)).Times(0);
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _)).Times(0);
   top_sites_callbacks_.Notify(
       MostVisitedURLList({MakeMostVisitedURL(u"Site 2", "http://site2/")}));
   base::RunLoop().RunUntilIdle();
@@ -1277,7 +1296,7 @@
   EXPECT_CALL(*mock_top_sites_, GetMostVisitedURLs(_))
       .WillRepeatedly(base::test::RunOnceCallbackRepeatedly<0>(
           MostVisitedURLList{MakeMostVisitedURL(kTestTitle, kTestUrl)}));
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_)).Times(1);
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _)).Times(1);
   most_visited_sites_->EnableCustomLinks(false);
   base::RunLoop().RunUntilIdle();
 
@@ -1318,8 +1337,8 @@
           MostVisitedURLList{MakeMostVisitedURL(kTestTitle, kTestUrl)}));
   EXPECT_CALL(*mock_custom_links_manager_, IsInitialized())
       .WillRepeatedly(Return(false));
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
-      .WillOnce(SaveArg<0>(&sections));
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _))
+      .WillOnce(SaveArg<1>(&sections));
 
   most_visited_sites_->EnableCustomLinks(false);
   base::RunLoop().RunUntilIdle();
@@ -1552,8 +1571,8 @@
       .WillRepeatedly(Return(true));
   EXPECT_CALL(*mock_custom_links_manager_, GetLinks())
       .WillRepeatedly(ReturnRef(expected_links));
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
-      .WillOnce(SaveArg<0>(&sections));
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _))
+      .WillOnce(SaveArg<1>(&sections));
   most_visited_sites_->AddCustomLink(GURL("test.com"), u"test");
   base::RunLoop().RunUntilIdle();
   CheckSingleCustomLink(sections.at(SectionType::PERSONALIZED), kTestTitle,
@@ -1571,8 +1590,8 @@
           MostVisitedURLList{MakeMostVisitedURL(kTestTitle, kTestUrl)}));
   EXPECT_CALL(*mock_custom_links_manager_, IsInitialized())
       .WillRepeatedly(Return(false));
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
-      .WillOnce(SaveArg<0>(&sections));
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _))
+      .WillOnce(SaveArg<1>(&sections));
   most_visited_sites_->UndoCustomLinkAction();
   base::RunLoop().RunUntilIdle();
   tiles = sections.at(SectionType::PERSONALIZED);
@@ -1610,8 +1629,8 @@
       .WillRepeatedly(Return(true));
   EXPECT_CALL(*mock_custom_links_manager_, GetLinks())
       .WillRepeatedly(ReturnRef(expected_links));
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
-      .WillRepeatedly(SaveArg<0>(&sections));
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _))
+      .WillRepeatedly(SaveArg<1>(&sections));
   most_visited_sites_->UpdateCustomLink(GURL("test.com"), GURL("test.com"),
                                         u"test");
   base::RunLoop().RunUntilIdle();
@@ -1649,8 +1668,8 @@
       .WillRepeatedly(Return(true));
   EXPECT_CALL(*mock_custom_links_manager_, GetLinks())
       .WillRepeatedly(ReturnRef(expected_links));
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
-      .WillOnce(SaveArg<0>(&sections));
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _))
+      .WillOnce(SaveArg<1>(&sections));
   most_visited_sites_->AddCustomLinkTo(GURL("test2.com"), u"test2", 0);
   base::RunLoop().RunUntilIdle();
 }
@@ -1684,7 +1703,7 @@
   EXPECT_CALL(*mock_custom_links_manager_, IsInitialized())
       .WillRepeatedly(Return(false));
   EXPECT_CALL(*mock_custom_links_manager_, Uninitialize());
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_)).Times(1);
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _)).Times(1);
   most_visited_sites_->AddCustomLink(GURL(kTestUrl), u"test");
   base::RunLoop().RunUntilIdle();
 
@@ -1697,7 +1716,7 @@
   EXPECT_CALL(*mock_custom_links_manager_, IsInitialized())
       .WillRepeatedly(Return(false));
   EXPECT_CALL(*mock_custom_links_manager_, Uninitialize());
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_)).Times(1);
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _)).Times(1);
   most_visited_sites_->UpdateCustomLink(GURL("test.com"), GURL("test2.com"),
                                         u"test");
   base::RunLoop().RunUntilIdle();
@@ -1711,7 +1730,7 @@
   EXPECT_CALL(*mock_custom_links_manager_, IsInitialized())
       .WillRepeatedly(Return(false));
   EXPECT_CALL(*mock_custom_links_manager_, Uninitialize());
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_)).Times(1);
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _)).Times(1);
   most_visited_sites_->ReorderCustomLink(GURL("test.com"), 1);
   base::RunLoop().RunUntilIdle();
 
@@ -1724,7 +1743,7 @@
   EXPECT_CALL(*mock_custom_links_manager_, IsInitialized())
       .WillRepeatedly(Return(false));
   EXPECT_CALL(*mock_custom_links_manager_, Uninitialize());
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_)).Times(1);
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _)).Times(1);
   most_visited_sites_->DeleteCustomLink(GURL("test.com"));
   base::RunLoop().RunUntilIdle();
 }
@@ -1759,8 +1778,8 @@
       .WillRepeatedly(Return(true));
   EXPECT_CALL(*mock_custom_links_manager_, GetLinks())
       .WillRepeatedly(ReturnRef(expected_links));
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
-      .WillOnce(SaveArg<0>(&sections));
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _))
+      .WillOnce(SaveArg<1>(&sections));
   custom_links_callback.Run();
   base::RunLoop().RunUntilIdle();
   // Not using CheckSingleCustomLink(), since URLs in the Custom link and the
@@ -1788,8 +1807,8 @@
           MostVisitedURLList{MakeMostVisitedURL(kTestTitle1, kTestUrl1)}));
   EXPECT_CALL(*mock_custom_links_manager_, IsInitialized())
       .WillRepeatedly(Return(false));
-  EXPECT_CALL(mock_observer_, OnURLsAvailable(_))
-      .WillOnce(SaveArg<0>(&sections));
+  EXPECT_CALL(mock_observer_, OnURLsAvailable(_, _))
+      .WillOnce(SaveArg<1>(&sections));
   custom_links_callback.Run();
   base::RunLoop().RunUntilIdle();
   tiles = sections.at(SectionType::PERSONALIZED);
diff --git a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
index 00efd013..901ee036a 100644
--- a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
+++ b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
@@ -267,6 +267,7 @@
 }
 
 void NTPTilesInternalsMessageHandler::OnURLsAvailable(
+    bool is_user_triggered,
     const std::map<SectionType, NTPTilesVector>& sections) {
   cancelable_task_tracker_.TryCancelAll();
 
diff --git a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h
index 70547966..939404a5 100644
--- a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h
+++ b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.h
@@ -62,6 +62,7 @@
 
   // MostVisitedSites::Observer.
   void OnURLsAvailable(
+      bool is_user_triggered,
       const std::map<SectionType, NTPTilesVector>& sections) override;
   void OnIconMadeAvailable(const GURL& site_url) override;
 
diff --git a/components/policy/core/common/remote_commands/remote_commands_constants.cc b/components/policy/core/common/remote_commands/remote_commands_constants.cc
index b33c0d1..23375c24 100644
--- a/components/policy/core/common/remote_commands/remote_commands_constants.cc
+++ b/components/policy/core/common/remote_commands/remote_commands_constants.cc
@@ -6,6 +6,8 @@
 
 #include <stdint.h>
 
+#include <ostream>
+
 #include "base/feature_list.h"
 #include "base/notreached.h"
 #include "components/invalidation/invalidation_constants.h"
diff --git a/components/policy/proto/device_management_backend.proto b/components/policy/proto/device_management_backend.proto
index 42ee2b00..778f65d 100644
--- a/components/policy/proto/device_management_backend.proto
+++ b/components/policy/proto/device_management_backend.proto
@@ -569,7 +569,8 @@
 }
 
 message PolicyFetchRequest {
-  reserved 5;
+  reserved 5, 11;
+  reserved "invalidation_topics_only";
 
   // This is the policy type, which maps to D3 policy type internally.
   // By convention, we use "/" as separator to create policy namespace.
@@ -654,11 +655,6 @@
   // to the client and should be forwarded from the invalidation notification.
   optional string policy_invalidation_info = 10 [deprecated = true];
 
-  // Whether or not the client only supports the new PolicyData invalidation
-  // topics. If true, only the policy_invalidation_topic and
-  // command_invalidation_topic fields will be set in the PolicyData response.
-  optional bool invalidation_topics_only = 11 [deprecated = true];
-
   // If this is an affiliated user, this is the device's DMToken.
   optional string device_dm_token = 12;
 
diff --git a/components/saved_tab_groups/internal/tab_group_sync_service_impl.cc b/components/saved_tab_groups/internal/tab_group_sync_service_impl.cc
index c039f9b6..428f16c 100644
--- a/components/saved_tab_groups/internal/tab_group_sync_service_impl.cc
+++ b/components/saved_tab_groups/internal/tab_group_sync_service_impl.cc
@@ -253,6 +253,12 @@
   return std::move(shared_tab_groups_available_at_startup_for_messaging_);
 }
 
+bool TabGroupSyncServiceImpl::HadSharedTabGroupsLastSession(
+    bool open_shared_tab_groups) {
+  return open_shared_tab_groups ? had_open_shared_tab_groups_on_startup_
+                                : had_shared_tab_groups_on_startup_;
+}
+
 void TabGroupSyncServiceImpl::AddObserver(
     TabGroupSyncService::Observer* observer) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -1754,6 +1760,11 @@
 
     // Dereference to create a safe copy.
     shared_tab_groups_available_at_startup_for_messaging_->push_back(*group);
+
+    had_shared_tab_groups_on_startup_ = true;
+    if (group->local_group_id().has_value()) {
+      had_open_shared_tab_groups_on_startup_ = true;
+    }
   }
 }
 
diff --git a/components/saved_tab_groups/internal/tab_group_sync_service_impl.h b/components/saved_tab_groups/internal/tab_group_sync_service_impl.h
index 821136d6..f1fdcfcf 100644
--- a/components/saved_tab_groups/internal/tab_group_sync_service_impl.h
+++ b/components/saved_tab_groups/internal/tab_group_sync_service_impl.h
@@ -186,6 +186,7 @@
 
   std::unique_ptr<std::vector<SavedTabGroup>>
   TakeSharedTabGroupsAvailableAtStartupForMessaging() override;
+  bool HadSharedTabGroupsLastSession(bool open_shared_tab_groups) override;
   void OnLastTabClosed(const SavedTabGroup& saved_tab_group) override;
 
   void AddObserver(TabGroupSyncService::Observer* observer) override;
@@ -428,6 +429,12 @@
   std::unique_ptr<std::vector<SavedTabGroup>>
       shared_tab_groups_available_at_startup_for_messaging_;
 
+  // Whether shared tab groups existed during startup.
+  bool had_shared_tab_groups_on_startup_ = false;
+
+  // Whether open shared tab groups existed during startup.
+  bool had_open_shared_tab_groups_on_startup_ = false;
+
   // Temporary in-memory mapping from collaboration ID to title for tab groups
   // that we/ have previously known about. This is to facilitate displaying of
   // tab group titles in the UI when a user is removed from a tab group.
diff --git a/components/saved_tab_groups/internal/tab_group_sync_service_unittest.cc b/components/saved_tab_groups/internal/tab_group_sync_service_unittest.cc
index b97d15a..deba3efa 100644
--- a/components/saved_tab_groups/internal/tab_group_sync_service_unittest.cc
+++ b/components/saved_tab_groups/internal/tab_group_sync_service_unittest.cc
@@ -2946,4 +2946,49 @@
       << "Not all GUIDs were found: " << base::JoinString(guid_strings, ", ");
 }
 
+TEST_F(EmptyTabGroupSyncServiceTest,
+       TestHadSharedTabGroupsOnStartup_OpenGroups) {
+  SavedTabGroup shared_group_1(test::CreateTestSavedTabGroup());
+  shared_group_1.SetCollaborationId(CollaborationId("collaboration"));
+  shared_group_1.SetLocalGroupId(test::GenerateRandomTabGroupID());
+
+  model_->LoadStoredEntries(
+      /*groups=*/{shared_group_1},
+      /*tabs=*/{});
+  task_environment_.RunUntilIdle();
+
+  EXPECT_TRUE(tab_group_sync_service_->HadSharedTabGroupsLastSession(
+      /*open_shared_tab_groups=*/false));
+  EXPECT_TRUE(tab_group_sync_service_->HadSharedTabGroupsLastSession(
+      /*open_shared_tab_groups=*/true));
+}
+
+TEST_F(EmptyTabGroupSyncServiceTest,
+       TestHadSharedTabGroupsOnStartup_NoOpenGroups) {
+  SavedTabGroup shared_group_1(test::CreateTestSavedTabGroup());
+  shared_group_1.SetCollaborationId(CollaborationId("collaboration"));
+
+  model_->LoadStoredEntries(
+      /*groups=*/{shared_group_1},
+      /*tabs=*/{});
+  task_environment_.RunUntilIdle();
+
+  EXPECT_TRUE(tab_group_sync_service_->HadSharedTabGroupsLastSession(
+      /*open_shared_tab_groups=*/false));
+  EXPECT_FALSE(tab_group_sync_service_->HadSharedTabGroupsLastSession(
+      /*open_shared_tab_groups=*/true));
+}
+
+TEST_F(EmptyTabGroupSyncServiceTest, TestHadSharedTabGroupsOnStartup_NoGroups) {
+  model_->LoadStoredEntries(
+      /*groups=*/{},
+      /*tabs=*/{});
+  task_environment_.RunUntilIdle();
+
+  EXPECT_FALSE(tab_group_sync_service_->HadSharedTabGroupsLastSession(
+      /*open_shared_tab_groups=*/false));
+  EXPECT_FALSE(tab_group_sync_service_->HadSharedTabGroupsLastSession(
+      /*open_shared_tab_groups=*/true));
+}
+
 }  // namespace tab_groups
diff --git a/components/saved_tab_groups/public/tab_group_sync_service.h b/components/saved_tab_groups/public/tab_group_sync_service.h
index bc218ae..5486451 100644
--- a/components/saved_tab_groups/public/tab_group_sync_service.h
+++ b/components/saved_tab_groups/public/tab_group_sync_service.h
@@ -386,6 +386,11 @@
   virtual std::unique_ptr<std::vector<SavedTabGroup>>
   TakeSharedTabGroupsAvailableAtStartupForMessaging() = 0;
 
+  // Returns if shared tab group existed during startup. If
+  // `open_shared_tab_groups` is true, returns whether there were open shared
+  // tab groups during startup.
+  virtual bool HadSharedTabGroupsLastSession(bool open_shared_tab_groups) = 0;
+
   // Called when the last tab in a group is closed.
   virtual void OnLastTabClosed(const SavedTabGroup& saved_tab_group) = 0;
 
diff --git a/components/saved_tab_groups/test_support/fake_tab_group_sync_service.cc b/components/saved_tab_groups/test_support/fake_tab_group_sync_service.cc
index 6d78942..7fc6dc1d 100644
--- a/components/saved_tab_groups/test_support/fake_tab_group_sync_service.cc
+++ b/components/saved_tab_groups/test_support/fake_tab_group_sync_service.cc
@@ -451,6 +451,11 @@
   return std::make_unique<std::vector<SavedTabGroup>>();
 }
 
+bool FakeTabGroupSyncService::HadSharedTabGroupsLastSession(
+    bool open_shared_tab_groups) {
+  return false;
+}
+
 void FakeTabGroupSyncService::OnLastTabClosed(
     const SavedTabGroup& saved_tab_group) {}
 
diff --git a/components/saved_tab_groups/test_support/fake_tab_group_sync_service.h b/components/saved_tab_groups/test_support/fake_tab_group_sync_service.h
index c0ce82f..a094b506 100644
--- a/components/saved_tab_groups/test_support/fake_tab_group_sync_service.h
+++ b/components/saved_tab_groups/test_support/fake_tab_group_sync_service.h
@@ -114,6 +114,7 @@
       TabGroupSyncService::UrlRestrictionCallback callback) override;
   std::unique_ptr<std::vector<SavedTabGroup>>
   TakeSharedTabGroupsAvailableAtStartupForMessaging() override;
+  bool HadSharedTabGroupsLastSession(bool open_shared_tab_groups) override;
   void OnLastTabClosed(const SavedTabGroup& saved_tab_group) override;
   void AddObserver(Observer* observer) override;
   void RemoveObserver(Observer* observer) override;
diff --git a/components/saved_tab_groups/test_support/mock_tab_group_sync_service.h b/components/saved_tab_groups/test_support/mock_tab_group_sync_service.h
index 4995187..8e5718de 100644
--- a/components/saved_tab_groups/test_support/mock_tab_group_sync_service.h
+++ b/components/saved_tab_groups/test_support/mock_tab_group_sync_service.h
@@ -142,6 +142,7 @@
   MOCK_METHOD(std::unique_ptr<std::vector<SavedTabGroup>>,
               TakeSharedTabGroupsAvailableAtStartupForMessaging,
               ());
+  MOCK_METHOD(bool, HadSharedTabGroupsLastSession, (bool), (override));
   MOCK_METHOD(void, OnLastTabClosed, (const SavedTabGroup&));
 
   MOCK_METHOD(void, AddObserver, (Observer*));
diff --git a/components/search_engines/android/template_url_service_android.cc b/components/search_engines/android/template_url_service_android.cc
index d6f428c..e10bb88 100644
--- a/components/search_engines/android/template_url_service_android.cc
+++ b/components/search_engines/android/template_url_service_android.cc
@@ -20,6 +20,7 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/notreached.h"
 #include "base/strings/string_util.h"
+#include "base/strings/utf_ostream_operators.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/google/core/common/google_util.h"
 #include "components/search_engines/android/template_url_android.h"
diff --git a/components/search_engines/template_url_service_unittest.cc b/components/search_engines/template_url_service_unittest.cc
index 61a85c27..261247e 100644
--- a/components/search_engines/template_url_service_unittest.cc
+++ b/components/search_engines/template_url_service_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/command_line.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
+#include "base/strings/utf_ostream_operators.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/search_engines/search_engine_choice/search_engine_choice_service.h"
 #include "components/search_engines/search_engine_choice/search_engine_choice_utils.h"
diff --git a/components/security_state/content/android/java/src/org/chromium/components/security_state/SecurityStateModel.java b/components/security_state/content/android/java/src/org/chromium/components/security_state/SecurityStateModel.java
index cfab738..9006d10 100644
--- a/components/security_state/content/android/java/src/org/chromium/components/security_state/SecurityStateModel.java
+++ b/components/security_state/content/android/java/src/org/chromium/components/security_state/SecurityStateModel.java
@@ -28,7 +28,7 @@
         return SecurityStateModelJni.get().getSecurityLevelForWebContents(webContents);
     }
 
-    public static boolean isContentDangerous(WebContents webContents) {
+    public static boolean isContentDangerous(@Nullable WebContents webContents) {
         return getSecurityLevelForWebContents(webContents) == ConnectionSecurityLevel.DANGEROUS;
     }
 
diff --git a/components/sync_bookmarks/bookmark_local_data_batch_uploader_unittest.cc b/components/sync_bookmarks/bookmark_local_data_batch_uploader_unittest.cc
index 3fbd80d..6a6beb2 100644
--- a/components/sync_bookmarks/bookmark_local_data_batch_uploader_unittest.cc
+++ b/components/sync_bookmarks/bookmark_local_data_batch_uploader_unittest.cc
@@ -8,6 +8,7 @@
 #include <utility>
 #include <variant>
 
+#include "base/strings/utf_ostream_operators.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_future.h"
 #include "components/bookmarks/browser/bookmark_model.h"
diff --git a/components/sync_bookmarks/local_bookmark_to_account_merger_unittest.cc b/components/sync_bookmarks/local_bookmark_to_account_merger_unittest.cc
index e04cd67..42b9538 100644
--- a/components/sync_bookmarks/local_bookmark_to_account_merger_unittest.cc
+++ b/components/sync_bookmarks/local_bookmark_to_account_merger_unittest.cc
@@ -11,6 +11,7 @@
 #include <variant>
 #include <vector>
 
+#include "base/strings/utf_ostream_operators.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/uuid.h"
 #include "components/bookmarks/browser/bookmark_model.h"
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn
index c44e3bbb..60e850a 100644
--- a/components/viz/service/BUILD.gn
+++ b/components/viz/service/BUILD.gn
@@ -147,8 +147,6 @@
     "display_embedder/compositor_gpu_thread.h",
     "display_embedder/image_context_impl.cc",
     "display_embedder/image_context_impl.h",
-    "display_embedder/in_process_gpu_memory_buffer_manager.cc",
-    "display_embedder/in_process_gpu_memory_buffer_manager.h",
     "display_embedder/output_presenter.h",
     "display_embedder/output_presenter_gl.cc",
     "display_embedder/output_presenter_gl.h",
diff --git a/components/viz/service/display_embedder/in_process_gpu_memory_buffer_manager.cc b/components/viz/service/display_embedder/in_process_gpu_memory_buffer_manager.cc
deleted file mode 100644
index 15e846e..0000000
--- a/components/viz/service/display_embedder/in_process_gpu_memory_buffer_manager.cc
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display_embedder/in_process_gpu_memory_buffer_manager.h"
-
-#include <utility>
-
-#include "base/functional/bind.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/task/single_thread_task_runner.h"
-#include "base/trace_event/memory_dump_manager.h"
-#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
-#include "gpu/command_buffer/service/sync_point_manager.h"
-#include "gpu/ipc/common/gpu_client_ids.h"
-#include "gpu/ipc/common/gpu_memory_buffer_impl.h"
-#include "gpu/ipc/service/gpu_memory_buffer_factory.h"
-
-namespace viz {
-namespace {
-
-void DestroyOnThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-                     gpu::GpuMemoryBufferImpl::DestructionCallback callback) {
-  if (task_runner->BelongsToCurrentThread()) {
-    std::move(callback).Run();
-  } else {
-    task_runner->PostTask(FROM_HERE, std::move(callback));
-  }
-}
-
-}  // namespace
-
-InProcessGpuMemoryBufferManager::InProcessGpuMemoryBufferManager(
-    gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
-    gpu::SyncPointManager* sync_point_manager)
-    : client_id_(gpu::kDisplayCompositorClientId),
-      pool_(base::MakeRefCounted<base::UnsafeSharedMemoryPool>()),
-      gpu_memory_buffer_factory_(gpu_memory_buffer_factory),
-      sync_point_manager_(sync_point_manager),
-      task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()) {
-  base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
-      this, "InProcessGpuMemoryBufferManager", task_runner_);
-
-  weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
-}
-
-InProcessGpuMemoryBufferManager::~InProcessGpuMemoryBufferManager() {
-  DCHECK(task_runner_->BelongsToCurrentThread());
-  base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
-      this);
-}
-
-std::unique_ptr<gfx::GpuMemoryBuffer>
-InProcessGpuMemoryBufferManager::CreateGpuMemoryBuffer(
-    const gfx::Size& size,
-    gfx::BufferFormat format,
-    gfx::BufferUsage usage,
-    gpu::SurfaceHandle surface_handle,
-    base::WaitableEvent* shutdown_event) {
-  gfx::GpuMemoryBufferId id(next_gpu_memory_id_++);
-  gfx::GpuMemoryBufferHandle buffer_handle =
-      gpu_memory_buffer_factory_->CreateGpuMemoryBuffer(
-          id, size, /*framebuffer_size=*/size, format, usage, client_id_,
-          surface_handle);
-
-  gpu::AllocatedBufferInfo buffer_info(buffer_handle, size, format);
-
-  auto callback = base::BindOnce(
-      &InProcessGpuMemoryBufferManager::DestroyGpuMemoryBuffer, weak_ptr_, id);
-  auto gmb = gpu_memory_buffer_support_.CreateGpuMemoryBufferImplFromHandle(
-      std::move(buffer_handle), size, format, usage,
-      base::BindOnce(&DestroyOnThread, task_runner_, std::move(callback)), this,
-      pool_);
-
-  if (gmb)
-    allocated_buffers_.insert(std::make_pair(id, buffer_info));
-
-  return gmb;
-}
-
-bool InProcessGpuMemoryBufferManager::OnMemoryDump(
-    const base::trace_event::MemoryDumpArgs& args,
-    base::trace_event::ProcessMemoryDump* pmd) {
-  DCHECK(task_runner_->BelongsToCurrentThread());
-  uint64_t client_tracing_process_id =
-      base::trace_event::MemoryDumpManager::GetInstance()
-          ->GetTracingProcessId();
-
-  for (auto& buffer_pair : allocated_buffers_) {
-    auto& buffer_info = buffer_pair.second;
-    if (!buffer_info.OnMemoryDump(pmd, client_id_, client_tracing_process_id))
-      return false;
-  }
-
-  return true;
-}
-
-void InProcessGpuMemoryBufferManager::DestroyGpuMemoryBuffer(
-    gfx::GpuMemoryBufferId id) {
-  allocated_buffers_.erase(id);
-  gpu_memory_buffer_factory_->DestroyGpuMemoryBuffer(id, client_id_);
-}
-
-}  // namespace viz
diff --git a/components/viz/service/display_embedder/in_process_gpu_memory_buffer_manager.h b/components/viz/service/display_embedder/in_process_gpu_memory_buffer_manager.h
deleted file mode 100644
index 41e631a..0000000
--- a/components/viz/service/display_embedder/in_process_gpu_memory_buffer_manager.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_IN_PROCESS_GPU_MEMORY_BUFFER_MANAGER_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_IN_PROCESS_GPU_MEMORY_BUFFER_MANAGER_H_
-
-#include <memory>
-
-#include "base/containers/flat_map.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/memory/unsafe_shared_memory_pool.h"
-#include "base/memory/weak_ptr.h"
-#include "base/trace_event/memory_dump_provider.h"
-#include "components/viz/service/viz_service_export.h"
-#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
-#include "gpu/ipc/common/gpu_memory_buffer_support.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}
-
-namespace gpu {
-class GpuMemoryBufferFactory;
-class SyncPointManager;
-}
-
-namespace viz {
-
-// GpuMemoryBufferManager implementation usable from any thread in the GPU
-// process. Must be created and destroyed on the same thread.
-class VIZ_SERVICE_EXPORT InProcessGpuMemoryBufferManager
-    : public gpu::GpuMemoryBufferManager,
-      public base::trace_event::MemoryDumpProvider {
- public:
-  // |gpu_memory_buffer_factory| and |sync_point_manager| must outlive |this|.
-  InProcessGpuMemoryBufferManager(
-      gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
-      gpu::SyncPointManager* sync_point_manager);
-
-  InProcessGpuMemoryBufferManager(const InProcessGpuMemoryBufferManager&) =
-      delete;
-  InProcessGpuMemoryBufferManager& operator=(
-      const InProcessGpuMemoryBufferManager&) = delete;
-
-  // Note: Any GpuMemoryBuffers that haven't been destroyed yet will be leaked
-  // until the GpuMemoryBufferFactory is destroyed.
-  ~InProcessGpuMemoryBufferManager() override;
-
-  // gpu::GpuMemoryBufferManager:
-  std::unique_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
-      const gfx::Size& size,
-      gfx::BufferFormat format,
-      gfx::BufferUsage usage,
-      gpu::SurfaceHandle surface_handle,
-      base::WaitableEvent* shutdown_event) override;
-
-  // base::trace_event::MemoryDumpProvider:
-  bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
-                    base::trace_event::ProcessMemoryDump* pmd) override;
-
- private:
-  // Provided as callback when a GpuMemoryBuffer should be destroyed.
-  void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id);
-
-  gpu::GpuMemoryBufferSupport gpu_memory_buffer_support_;
-  const int client_id_;
-  int next_gpu_memory_id_ = 1;
-
-  scoped_refptr<base::UnsafeSharedMemoryPool> pool_;
-
-  const raw_ptr<gpu::GpuMemoryBufferFactory> gpu_memory_buffer_factory_;
-  const raw_ptr<gpu::SyncPointManager> sync_point_manager_;
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-
-  base::flat_map<gfx::GpuMemoryBufferId, gpu::AllocatedBufferInfo>
-      allocated_buffers_;
-
-  base::WeakPtr<InProcessGpuMemoryBufferManager> weak_ptr_;
-  base::WeakPtrFactory<InProcessGpuMemoryBufferManager> weak_ptr_factory_{this};
-};
-
-}  // namespace viz
-
-#endif  // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_IN_PROCESS_GPU_MEMORY_BUFFER_MANAGER_H_
diff --git a/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.cc b/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.cc
index 2636804f..224ebc52 100644
--- a/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.cc
+++ b/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.cc
@@ -11,7 +11,6 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/task/bind_post_task.h"
 #include "base/task/sequenced_task_runner.h"
-#include "components/viz/service/display_embedder/in_process_gpu_memory_buffer_manager.h"
 #include "components/viz/service/gl/gpu_service_impl.h"
 #include "gpu/command_buffer/client/client_shared_image.h"
 #include "gpu/command_buffer/service/scheduler_sequence.h"
@@ -29,11 +28,9 @@
  public:
   explicit GmbVideoFramePoolContext(
       GpuServiceImpl* gpu_service,
-      InProcessGpuMemoryBufferManager* gpu_memory_buffer_manager,
       gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
       base::OnceClosure on_context_lost)
       : gpu_service_(gpu_service),
-        gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
         gpu_memory_buffer_factory_(gpu_memory_buffer_factory),
         on_context_lost_(
             base::BindPostTaskToCurrentDefault(std::move(on_context_lost))) {
@@ -177,7 +174,6 @@
   }
 
   const raw_ptr<GpuServiceImpl> gpu_service_;
-  const raw_ptr<InProcessGpuMemoryBufferManager> gpu_memory_buffer_manager_;
   const raw_ptr<gpu::GpuMemoryBufferFactory> gpu_memory_buffer_factory_;
 
   // Closure that we need to call when context loss happens.
@@ -196,10 +192,8 @@
 
 GmbVideoFramePoolContextProviderImpl::GmbVideoFramePoolContextProviderImpl(
     GpuServiceImpl* gpu_service,
-    InProcessGpuMemoryBufferManager* gpu_memory_buffer_manager,
     gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory)
     : gpu_service_(gpu_service),
-      gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
       gpu_memory_buffer_factory_(gpu_memory_buffer_factory) {}
 
 GmbVideoFramePoolContextProviderImpl::~GmbVideoFramePoolContextProviderImpl() =
@@ -209,8 +203,7 @@
 GmbVideoFramePoolContextProviderImpl::CreateContext(
     base::OnceClosure on_context_lost) {
   return std::make_unique<GmbVideoFramePoolContext>(
-      gpu_service_, gpu_memory_buffer_manager_, gpu_memory_buffer_factory_,
-      std::move(on_context_lost));
+      gpu_service_, gpu_memory_buffer_factory_, std::move(on_context_lost));
 }
 
 }  // namespace viz
diff --git a/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.h b/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.h
index fb31640..8e17a0e 100644
--- a/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.h
+++ b/components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.h
@@ -18,14 +18,12 @@
 namespace viz {
 
 class GpuServiceImpl;
-class InProcessGpuMemoryBufferManager;
 
 class VIZ_SERVICE_EXPORT GmbVideoFramePoolContextProviderImpl
     : public GmbVideoFramePoolContextProvider {
  public:
   explicit GmbVideoFramePoolContextProviderImpl(
       GpuServiceImpl* gpu_service,
-      InProcessGpuMemoryBufferManager* gpu_memory_buffer_manager,
       gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory);
 
   GmbVideoFramePoolContextProviderImpl(
@@ -40,7 +38,6 @@
 
  private:
   const raw_ptr<GpuServiceImpl> gpu_service_;
-  const raw_ptr<InProcessGpuMemoryBufferManager> gpu_memory_buffer_manager_;
   const raw_ptr<gpu::GpuMemoryBufferFactory> gpu_memory_buffer_factory_;
 };
 
diff --git a/components/viz/service/main/viz_compositor_thread_runner_impl.cc b/components/viz/service/main/viz_compositor_thread_runner_impl.cc
index 2ff7fe1c..1fd24576 100644
--- a/components/viz/service/main/viz_compositor_thread_runner_impl.cc
+++ b/components/viz/service/main/viz_compositor_thread_runner_impl.cc
@@ -19,7 +19,6 @@
 #include "build/build_config.h"
 #include "components/viz/common/features.h"
 #include "components/viz/common/switches.h"
-#include "components/viz/service/display_embedder/in_process_gpu_memory_buffer_manager.h"
 #include "components/viz/service/display_embedder/output_surface_provider_impl.h"
 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
 #include "components/viz/service/frame_sinks/gmb_video_frame_pool_context_provider_impl.h"
@@ -165,10 +164,6 @@
 
   if (gpu_service) {
     // Create OutputSurfaceProvider usable for GPU + software compositing.
-    gpu_memory_buffer_manager_ =
-        std::make_unique<InProcessGpuMemoryBufferManager>(
-            gpu_service->gpu_memory_buffer_factory(),
-            gpu_service->sync_point_manager());
     output_surface_provider_ =
         std::make_unique<OutputSurfaceProviderImpl>(gpu_service, headless);
 
@@ -176,8 +171,7 @@
     // manager to create GMB-backed video frames.
     gmb_video_frame_pool_context_provider_ =
         std::make_unique<GmbVideoFramePoolContextProviderImpl>(
-            gpu_service, gpu_memory_buffer_manager_.get(),
-            gpu_service->gpu_memory_buffer_factory());
+            gpu_service, gpu_service->gpu_memory_buffer_factory());
   } else {
     // Create OutputSurfaceProvider usable for software compositing only.
     output_surface_provider_ =
@@ -239,7 +233,6 @@
   hint_session_factory_.reset();
   output_surface_provider_.reset();
   gmb_video_frame_pool_context_provider_.reset();
-  gpu_memory_buffer_manager_.reset();
 }
 
 }  // namespace viz
diff --git a/components/viz/service/main/viz_compositor_thread_runner_impl.h b/components/viz/service/main/viz_compositor_thread_runner_impl.h
index 3610ef8..43c80b24 100644
--- a/components/viz/service/main/viz_compositor_thread_runner_impl.h
+++ b/components/viz/service/main/viz_compositor_thread_runner_impl.h
@@ -27,7 +27,6 @@
 class FrameSinkManagerImpl;
 class GmbVideoFramePoolContextProvider;
 class HintSessionFactory;
-class InProcessGpuMemoryBufferManager;
 class OutputSurfaceProvider;
 class SharedImageInterfaceProvider;
 
@@ -82,7 +81,6 @@
 
   // Start variables to be accessed only on |task_runner_|.
   std::unique_ptr<HintSessionFactory> hint_session_factory_;
-  std::unique_ptr<InProcessGpuMemoryBufferManager> gpu_memory_buffer_manager_;
   std::unique_ptr<OutputSurfaceProvider> output_surface_provider_;
   // `gmb_video_frame_pool_context_provider_` depends on
   // `gpu_memory_buffer_manager_`. It must be created last, deleted first.
diff --git a/components/wallet/OWNERS b/components/wallet/OWNERS
index 574ef5d..1725378 100644
--- a/components/wallet/OWNERS
+++ b/components/wallet/OWNERS
@@ -1,2 +1 @@
-hanfeng@google.com
 vizcay@google.com
diff --git a/components/webapps/browser/webapps_client.h b/components/webapps/browser/webapps_client.h
index 5741db3..f63dcd2 100644
--- a/components/webapps/browser/webapps_client.h
+++ b/components/webapps/browser/webapps_client.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/auto_reset.h"
+#include "base/functional/callback_forward.h"
 #include "build/build_config.h"
 #include "components/security_state/core/security_state.h"
 #include "components/webapps/common/web_app_id.h"
diff --git a/content/browser/back_forward_cache_features_browsertest.cc b/content/browser/back_forward_cache_features_browsertest.cc
index 30ddcfa1..cae468f 100644
--- a/content/browser/back_forward_cache_features_browsertest.cc
+++ b/content/browser/back_forward_cache_features_browsertest.cc
@@ -1059,38 +1059,6 @@
   EXPECT_EQ(1, CountWorkerClients(current_frame_host()));
 }
 
-// TODO(crbug.com/40290702): Shared workers are not available on Android.
-#if BUILDFLAG(IS_ANDROID)
-#define MAYBE_PageWithSharedWorkerNotCached \
-  DISABLED_PageWithSharedWorkerNotCached
-#else
-#define MAYBE_PageWithSharedWorkerNotCached PageWithSharedWorkerNotCached
-#endif
-IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
-                       MAYBE_PageWithSharedWorkerNotCached) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-
-  EXPECT_TRUE(NavigateToURL(
-      shell(),
-      embedded_test_server()->GetURL(
-          "a.com", "/back_forward_cache/page_with_shared_worker.html")));
-  RenderFrameDeletedObserver delete_observer_rfh_a(current_frame_host());
-
-  // Navigate away.
-  EXPECT_TRUE(NavigateToURL(
-      shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
-
-  // The page with the unsupported feature should be deleted (not cached).
-  delete_observer_rfh_a.WaitUntilDeleted();
-
-  // Go back.
-  ASSERT_TRUE(HistoryGoBack(web_contents()));
-  ExpectNotRestored(
-      {NotRestoredReason::kBlocklistedFeatures},
-      {blink::scheduler::WebSchedulerTrackedFeature::kSharedWorker}, {}, {}, {},
-      FROM_HERE);
-}
-
 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
                        AllowedFeaturesForSubframesDoNotEvict) {
   // The main purpose of this test is to check that when a state of a subframe
diff --git a/content/browser/browsing_data/browsing_data_remover_impl.cc b/content/browser/browsing_data/browsing_data_remover_impl.cc
index 977e3ab..ede448a 100644
--- a/content/browser/browsing_data/browsing_data_remover_impl.cc
+++ b/content/browser/browsing_data/browsing_data_remover_impl.cc
@@ -507,6 +507,11 @@
         StoragePartition::REMOVE_DATA_MASK_DEVICE_BOUND_SESSIONS;
   }
 
+  if ((remove_mask & DATA_TYPE_COOKIES) || (remove_mask & DATA_TYPE_CACHE)) {
+    storage_partition_remove_mask |=
+        StoragePartition::REMOVE_KEEPALIVE_LOADS_ATTEMPTING_RETRY;
+  }
+
   if (storage_partition_remove_mask) {
     // If cookies are supposed to be conditionally deleted from the storage
     // partition, create the deletion info object.
diff --git a/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc b/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc
index d58d77a..a0aa14c 100644
--- a/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc
+++ b/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc
@@ -546,7 +546,8 @@
   StoragePartitionRemovalData removal_data = GetStoragePartitionRemovalData();
   EXPECT_EQ(removal_data.remove_mask,
             StoragePartition::REMOVE_DATA_MASK_COOKIES |
-                StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUPS);
+                StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUPS |
+                StoragePartition::REMOVE_KEEPALIVE_LOADS_ATTEMPTING_RETRY);
   EXPECT_EQ(removal_data.quota_storage_remove_mask,
             StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL);
   EXPECT_EQ(removal_data.remove_begin, GetBeginTime());
@@ -564,7 +565,8 @@
   StoragePartitionRemovalData removal_data = GetStoragePartitionRemovalData();
   EXPECT_EQ(removal_data.remove_mask,
             StoragePartition::REMOVE_DATA_MASK_COOKIES |
-                StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUPS);
+                StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUPS |
+                StoragePartition::REMOVE_KEEPALIVE_LOADS_ATTEMPTING_RETRY);
   EXPECT_EQ(removal_data.quota_storage_remove_mask,
             StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL);
   EXPECT_EQ(removal_data.remove_begin, GetBeginTime());
@@ -590,7 +592,8 @@
   StoragePartitionRemovalData removal_data = GetStoragePartitionRemovalData();
   EXPECT_EQ(removal_data.remove_mask,
             StoragePartition::REMOVE_DATA_MASK_COOKIES |
-                StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUPS);
+                StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUPS |
+                StoragePartition::REMOVE_KEEPALIVE_LOADS_ATTEMPTING_RETRY);
   EXPECT_EQ(removal_data.quota_storage_remove_mask,
             StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL);
   EXPECT_EQ(removal_data.remove_begin, GetBeginTime());
@@ -767,7 +770,8 @@
   StoragePartitionRemovalData removal_data = GetStoragePartitionRemovalData();
   EXPECT_EQ(removal_data.remove_mask,
             StoragePartition::REMOVE_DATA_MASK_COOKIES |
-                StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUPS);
+                StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUPS |
+                StoragePartition::REMOVE_KEEPALIVE_LOADS_ATTEMPTING_RETRY);
   EXPECT_EQ(removal_data.quota_storage_remove_mask,
             StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL);
 }
@@ -1369,8 +1373,7 @@
   EXPECT_TRUE(removal_data[1].remove_code_cache);
 }
 
-TEST_F(BrowsingDataRemoverImplTest,
-       RemoveShaderCacheAndInterstGroupPermissionsCache) {
+TEST_F(BrowsingDataRemoverImplTest, RemoveCache) {
   BlockUntilBrowsingDataRemoved(base::Time(), base::Time::Max(),
                                 BrowsingDataRemover::DATA_TYPE_CACHE, false);
   auto removal_data = GetStoragePartitionRemovalDataListAndReset();
@@ -1378,7 +1381,8 @@
   EXPECT_EQ(
       removal_data[0].remove_mask,
       StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE |
-          StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUP_PERMISSIONS_CACHE);
+          StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUP_PERMISSIONS_CACHE |
+          StoragePartition::REMOVE_KEEPALIVE_LOADS_ATTEMPTING_RETRY);
 }
 
 TEST_F(BrowsingDataRemoverImplTest, RemoveAttributionReporting) {
@@ -1755,7 +1759,8 @@
       StoragePartition::REMOVE_DATA_MASK_INDEXEDDB;
   uint32_t dom_storage_and_cookie_mask =
       dom_storage_mask | StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUPS |
-      StoragePartition::REMOVE_DATA_MASK_COOKIES;
+      StoragePartition::REMOVE_DATA_MASK_COOKIES |
+      StoragePartition::REMOVE_KEEPALIVE_LOADS_ATTEMPTING_RETRY;
   BlockUntilBrowsingDataRemoved(base::Time(), base::Time::Max(),
                                 BrowsingDataRemover::DATA_TYPE_COOKIES |
                                     BrowsingDataRemover::DATA_TYPE_DOM_STORAGE,
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index e6ffa2b..7546a7830 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -328,6 +328,7 @@
 #endif
 #if BUILDFLAG(IS_WIN)
     switches::kWebNNOrtLoggingLevel,
+    switches::kWebNNOrtDumpModel,
 #endif
 };
 
diff --git a/content/browser/loader/keep_alive_url_browsertest.cc b/content/browser/loader/keep_alive_url_browsertest.cc
index bdd878d..78c8680 100644
--- a/content/browser/loader/keep_alive_url_browsertest.cc
+++ b/content/browser/loader/keep_alive_url_browsertest.cc
@@ -1370,6 +1370,62 @@
       /*retried_count=*/kMaxRetryCountPerFactoryForTesting);
 }
 
+// Test that a loader attempting retry will be deleted by clearing
+// cookies/cache.
+IN_PROC_BROWSER_TEST_P(KeepAliveFetchRetryBrowserTest,
+                       ClearingDataClearsLoaderAttemptingRetry) {
+  ASSERT_TRUE(server()->Start());
+  const auto beacon_url = server()->GetURL(kPrimaryHost, kKeepAliveEndpoint);
+  // Always fail the fetch with a network changed error.
+  std::unique_ptr<URLLoaderInterceptor> url_interceptor =
+      URLLoaderInterceptor::SetupRequestFailForURL(beacon_url,
+                                                   net::ERR_NETWORK_CHANGED);
+  ASSERT_TRUE(NavigateToURL(web_contents(),
+                            server()->GetURL(kPrimaryHost, "/title1.html")));
+  ASSERT_TRUE(ExecJs(web_contents(),
+                     JsReplace(R"(
+                      window.fetchPromise = fetch($1, {
+                        keepalive: true,
+                        retryOptions: {
+                          maxAttempts: 10,
+                          initialDelay: (1000 * 3600 * 24), // 1 day
+                          retryNonIdempotent: true
+                        }});)",
+                               beacon_url),
+                     content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES));
+
+  // Wait for the first load to fail.
+  loaders_observer().WaitForTotalOnComplete({net::ERR_NETWORK_CHANGED});
+
+  // The loader is now waiting for its retry attempt (which is scheduled for
+  // 1 day from now).
+  ASSERT_EQ(loader_service()->NumLoadersForTesting(), 1u);
+  ASSERT_EQ(loader_service()->NumLoadersAttemptingRetryForTesting(), 1u);
+
+  // Simulate clearing cookies.
+  base::RunLoop run_loop;
+  static_cast<StoragePartitionImpl*>(
+      web_contents()->GetBrowserContext()->GetDefaultStoragePartition())
+      ->ClearData(StoragePartition::REMOVE_KEEPALIVE_LOADS_ATTEMPTING_RETRY,
+                  StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
+                  blink::StorageKey(), base::Time(), base::Time::Max(),
+                  run_loop.QuitClosure());
+  run_loop.Run();
+  // The pending retry loader is deleted.
+  ASSERT_EQ(loader_service()->NumLoadersForTesting(), 0u);
+  ASSERT_EQ(loader_service()->NumLoadersAttemptingRetryForTesting(), 0u);
+
+  // No retry happened and the failure is not forwarded to the renderer because
+  // the loader is deleted while it's waiting for retry.
+  ExpectFetchKeepAliveHistogram(
+      FetchKeepAliveRequestMetricType::kFetch,
+      ExpectedTotalRequests(/*browser=*/1, /*renderer=*/1),
+      ExpectedStartedRequests(/*browser=*/1, /*renderer=*/1),
+      ExpectedSucceededRequests(/*browser=*/0, /*renderer=*/0),
+      ExpectedFailedRequests(/*browser=*/1),
+      /*retried_count=*/0);
+}
+
 // TODO(crbug.com/417930271): test unload, redirects, timeout, attribution.
 
 }  // namespace content
diff --git a/content/browser/loader/keep_alive_url_loader.h b/content/browser/loader/keep_alive_url_loader.h
index f3349dda..afcb386b 100644
--- a/content/browser/loader/keep_alive_url_loader.h
+++ b/content/browser/loader/keep_alive_url_loader.h
@@ -337,6 +337,10 @@
                            SelfDeletionOnMaxAge);
   FRIEND_TEST_ALL_PREFIXES(KeepAliveURLLoaderServiceRetryTest,
                            ErrorCodeRetryEligibility_OnlyIfServerUnreached);
+  FRIEND_TEST_ALL_PREFIXES(KeepAliveURLLoaderServiceRetryTest,
+                           RetryAttemptedOnDisconnect);
+  FRIEND_TEST_ALL_PREFIXES(KeepAliveURLLoaderServiceRetryTest,
+                           CookiesClearingWillDeleteRetryingLoader);
 
   // These values are persisted to logs. Entries should not be renumbered and
   // numeric values should never be reused.
diff --git a/content/browser/loader/keep_alive_url_loader_service.cc b/content/browser/loader/keep_alive_url_loader_service.cc
index 5077007..8bfecda 100644
--- a/content/browser/loader/keep_alive_url_loader_service.cc
+++ b/content/browser/loader/keep_alive_url_loader_service.cc
@@ -166,6 +166,19 @@
     }
   }
 
+  void ClearKeepAliveURLLoadersAttemptingRetry() {
+    std::vector<mojo::ReceiverId> loader_ids_to_remove;
+    for (const auto& [loader_id, weak_ptr_loader] : weak_ptr_loaders_) {
+      if (weak_ptr_loader && weak_ptr_loader->IsAttemptingRetry()) {
+        loader_ids_to_remove.push_back(loader_id);
+      }
+    }
+
+    for (auto loader_id : loader_ids_to_remove) {
+      RemoveLoader(loader_id);
+    }
+  }
+
   // For testing only:
   base::WeakPtr<KeepAliveURLLoader> GetLoaderWithRequestIdForTesting(
       int32_t request_id) const {
@@ -183,6 +196,15 @@
   size_t NumDisconnectedLoadersForTesting() const {
     return disconnected_loaders_.size();
   }
+  size_t NumLoadersAttemptingRetryForTesting() const {
+    int count = 0;
+    for (const auto& [_, weak_ptr_loader] : weak_ptr_loaders_) {
+      if (weak_ptr_loader->IsAttemptingRetry()) {
+        count++;
+      }
+    }
+    return count;
+  }
 
  protected:
   // Creates a new KeepAliveURLLoader from the factory of the `context` to load
@@ -644,6 +666,11 @@
       request_id);  // IN-TEST
 }
 
+void KeepAliveURLLoaderService::ClearKeepAliveURLLoadersAttemptingRetry() {
+  url_loader_factories_->ClearKeepAliveURLLoadersAttemptingRetry();
+  fetch_later_loader_factories_->ClearKeepAliveURLLoadersAttemptingRetry();
+}
+
 size_t KeepAliveURLLoaderService::NumLoadersForTesting() const {
   return url_loader_factories_->NumLoadersForTesting() +         // IN-TEST
          fetch_later_loader_factories_->NumLoadersForTesting();  // IN-TEST
@@ -655,6 +682,13 @@
              ->NumDisconnectedLoadersForTesting();  // IN-TEST
 }
 
+size_t KeepAliveURLLoaderService::NumLoadersAttemptingRetryForTesting() const {
+  return url_loader_factories_
+             ->NumLoadersAttemptingRetryForTesting() +  // IN-TEST
+         fetch_later_loader_factories_
+             ->NumLoadersAttemptingRetryForTesting();  // IN-TEST
+}
+
 void KeepAliveURLLoaderService::SetLoaderObserverForTesting(
     scoped_refptr<KeepAliveURLLoader::TestObserver> observer) {
   loader_test_observer_ = observer;
diff --git a/content/browser/loader/keep_alive_url_loader_service.h b/content/browser/loader/keep_alive_url_loader_service.h
index fb19770..152e9291 100644
--- a/content/browser/loader/keep_alive_url_loader_service.h
+++ b/content/browser/loader/keep_alive_url_loader_service.h
@@ -192,11 +192,16 @@
   // down.
   void Shutdown();
 
+  // Called when user data is cleared that requires clearing pending retry
+  // loads as well.
+  void ClearKeepAliveURLLoadersAttemptingRetry();
+
   // For testing only:
   base::WeakPtr<KeepAliveURLLoader> GetLoaderWithRequestIdForTesting(
       int32_t request_id) const;
   size_t NumLoadersForTesting() const;
   size_t NumDisconnectedLoadersForTesting() const;
+  size_t NumLoadersAttemptingRetryForTesting() const;
   void SetLoaderObserverForTesting(
       scoped_refptr<KeepAliveURLLoader::TestObserver> observer);
   void SetURLLoaderThrottlesGetterForTesting(
diff --git a/content/browser/pointer_lock_browsertest.cc b/content/browser/pointer_lock_browsertest.cc
index f15bb423..f386dea 100644
--- a/content/browser/pointer_lock_browsertest.cc
+++ b/content/browser/pointer_lock_browsertest.cc
@@ -31,6 +31,10 @@
 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
 #include "content/browser/web_contents/web_contents_view_aura.h"
 #endif  // USE_AURA
+#if BUILDFLAG(IS_ANDROID)
+#include "content/browser/renderer_host/render_widget_host_view_android.h"
+#include "content/browser/web_contents/web_contents_view_android.h"
+#endif  // BUILDFLAG(IS_ANDROID)
 
 namespace content {
 
@@ -113,6 +117,57 @@
       });
 }
 #endif  // USE_AURA
+#if BUILDFLAG(IS_ANDROID)
+class MockPointerLockRenderWidgetHostView : public RenderWidgetHostViewAndroid {
+ public:
+  MockPointerLockRenderWidgetHostView(RenderWidgetHostImpl* rwhi,
+                                      gfx::NativeView parent_native_view,
+                                      cc::slim::Layer* parent_layer)
+      : RenderWidgetHostViewAndroid(rwhi, parent_native_view, parent_layer) {}
+  ~MockPointerLockRenderWidgetHostView() override {
+    if (pointer_locked_) {
+      UnlockPointer();
+    }
+  }
+
+  blink::mojom::PointerLockResult LockPointer(
+      bool request_unadjusted_movement) override {
+    pointer_locked_ = true;
+
+    return blink::mojom::PointerLockResult::kSuccess;
+  }
+
+  blink::mojom::PointerLockResult ChangePointerLock(
+      bool request_unadjusted_movement) override {
+    return blink::mojom::PointerLockResult::kSuccess;
+  }
+
+  void UnlockPointer() override {
+    if (RenderWidgetHostImpl* host =
+            RenderWidgetHostImpl::From(GetRenderWidgetHost())) {
+      host->LostPointerLock();
+    }
+    pointer_locked_ = false;
+  }
+
+  bool IsPointerLocked() override { return pointer_locked_; }
+
+  bool HasFocus() override { return true; }
+  bool CanBePointerLocked() override { return true; }
+
+ private:
+  bool pointer_locked_ = false;
+};
+
+void InstallCreateHooksForPointerLockBrowserTests() {
+  WebContentsViewAndroid::InstallCreateHookForTests(
+      [](RenderWidgetHostImpl* rwhi, gfx::NativeView parent_native_view,
+         cc::slim::Layer* parent_layer) -> RenderWidgetHostViewAndroid* {
+        return new MockPointerLockRenderWidgetHostView(rwhi, parent_native_view,
+                                                       parent_layer);
+      });
+}
+#endif  // BUILDFLAG(IS_ANDROID)
 
 class PointerLockBrowserTest : public ContentBrowserTest {
  public:
@@ -292,6 +347,9 @@
       child->current_frame_host()->GetView());
 
   WaitForHitTestData(child->current_frame_host());
+  // Make sure that page_scale is 1, on Android page scale is not guaranteed to
+  // be 1
+  web_contents()->SetPageScale(1.0);
 
   std::string set_mouse_move_event_listener = R"(
     mouseMoveExecuted = new Promise(function (resolve, reject) {
@@ -539,6 +597,9 @@
       child->current_frame_host()->GetView());
 
   WaitForHitTestData(child->current_frame_host());
+  // Make sure that page_scale is 1, on Android page scale is not guaranteed to
+  // be 1
+  web_contents()->SetPageScale(1.0);
 
   // Add a mouse move event listener to the root frame.
   EXPECT_TRUE(ExecJs(
@@ -698,8 +759,16 @@
   EXPECT_TRUE(ExecJs(shell(), "", EXECUTE_SCRIPT_NO_USER_GESTURE));
 }
 
+// unajustedMovement flag is not supported on Android
+#if BUILDFLAG(IS_ANDROID)
+#define MAYBE_PointerLockRequestUnadjustedMovement \
+  DISABLED_PointerLockRequestUnadjustedMovement
+#else
+#define MAYBE_PointerLockRequestUnadjustedMovement \
+  PointerLockRequestUnadjustedMovement
+#endif
 IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest,
-                       PointerLockRequestUnadjustedMovement) {
+                       MAYBE_PointerLockRequestUnadjustedMovement) {
   GURL main_url(embedded_test_server()->GetURL(
       "a.com", "/cross_site_iframe_factory.html?a(b)"));
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
diff --git a/content/browser/renderer_host/isolated_web_app_throttle.cc b/content/browser/renderer_host/isolated_web_app_throttle.cc
index 71e7c46..39f9b38 100644
--- a/content/browser/renderer_host/isolated_web_app_throttle.cc
+++ b/content/browser/renderer_host/isolated_web_app_throttle.cc
@@ -162,7 +162,6 @@
   OpenURLParams params(url, Referrer(),
                        WindowOpenDisposition::NEW_FOREGROUND_TAB, transition,
                        /*is_renderer_initiated=*/false);
-  params.open_app_window_if_possible = true;
   GetContentClient()->browser()->OpenURL(
       navigation_handle()->GetStartingSiteInstance(), params,
       base::DoNothing());
diff --git a/content/browser/service_worker/service_worker_client_utils.cc b/content/browser/service_worker/service_worker_client_utils.cc
index 83c7700b..633ce85 100644
--- a/content/browser/service_worker/service_worker_client_utils.cc
+++ b/content/browser/service_worker/service_worker_client_utils.cc
@@ -536,9 +536,11 @@
           ? WindowOpenDisposition::NEW_POPUP
           : WindowOpenDisposition::NEW_FOREGROUND_TAB,
       ui::PAGE_TRANSITION_AUTO_TOPLEVEL, true /* is_renderer_initiated */);
-  // TODO(https://crbug.com/382542907): Remove `open_pwa_window_if_possible` or
-  // make it IWA-specific.
-  params.open_app_window_if_possible = type == WindowType::NEW_TAB_WINDOW;
+
+  // Technically this field is equivalent to (disposition == NEW_FOREGROUND_TAB)
+  // && (transition == AUTO_TOPLEVEL) && is_renderer_initiated; this
+  // constellation of params is unique to just service worker navigations.
+  params.is_service_worker_open_window = type == WindowType::NEW_TAB_WINDOW;
   params.initiator_origin =
       url::Origin::Create(script_url.DeprecatedGetOriginAsURL());
 
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 3e412a9..d7bcdd8 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -914,6 +914,7 @@
       CdmStorageManager* cdm_storage_manager,
 #endif  // BUILDFLAG(ENABLE_LIBRARY_CDMS)
       network::mojom::DeviceBoundSessionManager* device_bound_session_manager,
+      KeepAliveURLLoaderService* keep_alive_url_loader_service,
       bool perform_storage_cleanup,
       const base::Time begin,
       const base::Time end);
@@ -2776,7 +2777,8 @@
 #if BUILDFLAG(ENABLE_LIBRARY_CDMS)
       cdm_storage_manager_.get(),
 #endif  // BUILDFLAG(ENABLE_LIBRARY_CDMS)
-      GetDeviceBoundSessionManager(), perform_storage_cleanup, begin, end);
+      GetDeviceBoundSessionManager(), GetKeepAliveURLLoaderService(),
+      perform_storage_cleanup, begin, end);
 }
 
 void StoragePartitionImpl::DeletionHelperDone(base::OnceClosure callback) {
@@ -2962,6 +2964,7 @@
     CdmStorageManager* cdm_storage_manager,
 #endif  // BUILDFLAG(ENABLE_LIBRARY_CDMS)
     network::mojom::DeviceBoundSessionManager* device_bound_session_manager,
+    KeepAliveURLLoaderService* keep_alive_url_loader_service,
     bool perform_storage_cleanup,
     const base::Time begin,
     const base::Time end) {
@@ -3207,6 +3210,11 @@
         mojo::WrapCallbackWithDefaultInvokeIfNotRun(CreateTaskCompletionClosure(
             TracingDataType::kDeviceBoundSessions)));
   }
+
+  if (remove_mask_ & REMOVE_KEEPALIVE_LOADS_ATTEMPTING_RETRY &&
+      keep_alive_url_loader_service) {
+    keep_alive_url_loader_service->ClearKeepAliveURLLoadersAttemptingRetry();
+  }
 }
 
 void StoragePartitionImpl::ClearDataForOrigin(
diff --git a/content/browser/web_contents/web_contents_view_android.cc b/content/browser/web_contents/web_contents_view_android.cc
index 2dec987b..4917393 100644
--- a/content/browser/web_contents/web_contents_view_android.cc
+++ b/content/browser/web_contents/web_contents_view_android.cc
@@ -64,6 +64,9 @@
 
 namespace {
 
+WebContentsViewAndroid::RenderWidgetHostViewCreateFunction
+    g_create_render_widget_host_view = nullptr;
+
 // Returns the minimum distance in DIPs, for drag event being considered as an
 // intentional drag.
 int DragMovementThresholdDip() {
@@ -119,6 +122,13 @@
   return rv;
 }
 
+// static
+void WebContentsViewAndroid::InstallCreateHookForTests(
+    RenderWidgetHostViewCreateFunction create_render_widget_host_view) {
+  CHECK_EQ(nullptr, g_create_render_widget_host_view);
+  g_create_render_widget_host_view = create_render_widget_host_view;
+}
+
 WebContentsViewAndroid::WebContentsViewAndroid(
     WebContentsImpl* web_contents,
     std::unique_ptr<WebContentsViewDelegate> delegate)
@@ -264,8 +274,11 @@
   // native view (i.e. ContentView) how to obtain a reference to this widget in
   // order to paint it.
   RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(render_widget_host);
-  auto* rwhv = new RenderWidgetHostViewAndroid(
-      rwhi, &view_, parent_for_web_page_widgets_.get());
+  auto* rwhv = g_create_render_widget_host_view
+                   ? g_create_render_widget_host_view(
+                         rwhi, &view_, parent_for_web_page_widgets_.get())
+                   : new RenderWidgetHostViewAndroid(
+                         rwhi, &view_, parent_for_web_page_widgets_.get());
   rwhv->SetSynchronousCompositorClient(synchronous_compositor_client_);
   return rwhv;
 }
diff --git a/content/browser/web_contents/web_contents_view_android.h b/content/browser/web_contents/web_contents_view_android.h
index 8320b15..eaa3013 100644
--- a/content/browser/web_contents/web_contents_view_android.h
+++ b/content/browser/web_contents/web_contents_view_android.h
@@ -10,8 +10,10 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "content/browser/renderer_host/render_view_host_delegate_view.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/web_contents/web_contents_view.h"
 #include "content/browser/web_contents/web_contents_view_drag_security_info.h"
+#include "content/common/content_export.h"
 #include "content/public/browser/web_contents_view_delegate.h"
 #include "content/public/common/drop_data.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
@@ -155,6 +157,15 @@
 
   WebContentsImpl* web_contents() { return web_contents_; }
 
+  using RenderWidgetHostViewCreateFunction =
+      RenderWidgetHostViewAndroid* (*)(RenderWidgetHostImpl*,
+                                       gfx::NativeView,
+                                       cc::slim::Layer*);
+
+  // Used to override the creation of RenderWidgetHostViews in tests.
+  CONTENT_EXPORT static void InstallCreateHookForTests(
+      RenderWidgetHostViewCreateFunction create_render_widget_host_view);
+
  private:
   void OnDragEntered(const gfx::PointF& location,
                      const gfx::PointF& screen_location);
diff --git a/content/public/android/java/src/org/chromium/content/browser/GestureListenerManagerImpl.java b/content/public/android/java/src/org/chromium/content/browser/GestureListenerManagerImpl.java
index ec3d92f..e64d3d168 100644
--- a/content/public/android/java/src/org/chromium/content/browser/GestureListenerManagerImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/GestureListenerManagerImpl.java
@@ -223,6 +223,7 @@
     }
 
     /** Returns whether there's an active, ongoing fling scroll. */
+    @Override
     public boolean hasActiveFlingScroll() {
         return mHasActiveFlingScroll;
     }
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/GestureListenerManager.java b/content/public/android/java/src/org/chromium/content_public/browser/GestureListenerManager.java
index 713a8d1..fb3b2fd 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/GestureListenerManager.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/GestureListenerManager.java
@@ -62,7 +62,13 @@
     boolean isScrollInProgress();
 
     /**
+     * @return Whether there's an active, ongoing fling scroll.
+     */
+    boolean hasActiveFlingScroll();
+
+    /**
      * Enable or disable multi-touch zoom support.
+     *
      * @param supportsMultiTouchZoom {@code true} if the feature is enabled.
      */
     void updateMultiTouchZoomSupport(boolean supportsMultiTouchZoom);
diff --git a/content/public/browser/navigation_controller.cc b/content/public/browser/navigation_controller.cc
index 08c7fd6e..4ef5480 100644
--- a/content/public/browser/navigation_controller.cc
+++ b/content/public/browser/navigation_controller.cc
@@ -72,7 +72,7 @@
   //
   //   The following OpenURLParams don't have an equivalent in LoadURLParams:
   //     disposition
-  //     open_app_window_if_possible
+  //     is_service_worker_open_window
   //     source_render_frame_id
   //     source_render_process_id
   //     triggering_event_info
diff --git a/content/public/browser/page_navigator.h b/content/public/browser/page_navigator.h
index 9e0fcb5..d8df5510 100644
--- a/content/public/browser/page_navigator.h
+++ b/content/public/browser/page_navigator.h
@@ -146,9 +146,9 @@
   // Optional URLLoaderFactory to facilitate navigation to a blob URL.
   scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory;
 
-  // Indicates that the navigation should happen in an app window if
-  // possible, i.e. if an app for the URL is installed.
-  bool open_app_window_if_possible = false;
+  // Indicates that this is a service worker openWindow() call targeting a new
+  // window.
+  bool is_service_worker_open_window = false;
 
   // If this navigation was initiated from a link that specified the
   // hrefTranslate attribute, this contains the attribute's value (a BCP47
diff --git a/content/public/browser/storage_partition.h b/content/public/browser/storage_partition.h
index fa25146..395f79f 100644
--- a/content/public/browser/storage_partition.h
+++ b/content/public/browser/storage_partition.h
@@ -228,6 +228,11 @@
     // user-initiated clearing.
     REMOVE_DATA_MASK_INTEREST_GROUPS_USER_CLEAR = 1 << 20,
 
+    // Keepalive loads might be kept around in memory for a long time when
+    // waiting for a chance to retry. They should be removed as part of
+    // user-initiated clearing.
+    REMOVE_KEEPALIVE_LOADS_ATTEMPTING_RETRY = 1 << 21,
+
     REMOVE_DATA_MASK_ALL = 0xFFFFFFFF,
 
     // Corresponds to storage::kStorageTypeTemporary, which is equivalent to
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index b77283f1..33c4ce8d 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -2197,8 +2197,6 @@
     ]
     sources -= [
       "../browser/media/session/audio_focus_delegate_default_browsertest.cc",
-      "../browser/pointer_lock_browsertest.cc",
-      "../browser/pointer_lock_browsertest.h",
     ]
     deps += [
       ":android_test_message_pump_support",
diff --git a/content/test/content_test_bundle_data.filelist b/content/test/content_test_bundle_data.filelist
index 6ff8297..c7471b8 100644
--- a/content/test/content_test_bundle_data.filelist
+++ b/content/test/content_test_bundle_data.filelist
@@ -6581,7 +6581,6 @@
 data/back_forward_cache/page_with_nonexistent_script.html
 data/back_forward_cache/page_with_pageshow.html
 data/back_forward_cache/page_with_same_origin_subframe_with_pageshow.html
-data/back_forward_cache/page_with_shared_worker.html
 data/back_forward_cache/page_with_wakelock.html
 data/back_forward_cache/page_with_webgl.html
 data/back_forward_cache/page_with_websocket_external_script.html
@@ -6597,7 +6596,6 @@
 data/back_forward_cache/service_worker_post_message.js
 data/back_forward_cache/service_worker_registration.html
 data/back_forward_cache/service_worker_registration.js
-data/back_forward_cache/shared_worker.js
 data/back_forward_cache/websocket_external_script.js
 data/back_forward_cache/webusb/nested-worker.js
 data/back_forward_cache/webusb/worker.js
diff --git a/content/test/data/back_forward_cache/page_with_shared_worker.html b/content/test/data/back_forward_cache/page_with_shared_worker.html
deleted file mode 100644
index 82cf488..0000000
--- a/content/test/data/back_forward_cache/page_with_shared_worker.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<html>
-<head></head>
-<body>This page has a shared worker.</body>
-  <script>
-    const worker = new SharedWorker('/back_forward_cache/shared_worker.js');
-  </script>
-</html>
diff --git a/device/vr/openxr/DEPS b/device/vr/openxr/DEPS
index 16d0ce6..f138dfe 100644
--- a/device/vr/openxr/DEPS
+++ b/device/vr/openxr/DEPS
@@ -7,7 +7,6 @@
   "+gpu/command_buffer/client/shared_image_interface.h",
   "+gpu/command_buffer/common/shared_image_usage.h",
   "+gpu/GLES2/gl2extchromium.h",
-  "+gpu/ipc/common/gpu_memory_buffer_impl_dxgi.h",
   "+third_party/openxr/src/include/openxr",
   "+components/version_info",
 ]
diff --git a/device/vr/openxr/openxr_api_wrapper.cc b/device/vr/openxr/openxr_api_wrapper.cc
index 9c93c11..37607fa3 100644
--- a/device/vr/openxr/openxr_api_wrapper.cc
+++ b/device/vr/openxr/openxr_api_wrapper.cc
@@ -41,9 +41,8 @@
 
 #if BUILDFLAG(IS_WIN)
 #include <dxgi1_2.h>
-
-#include "gpu/ipc/common/gpu_memory_buffer_impl_dxgi.h"
 #endif
+
 namespace device {
 
 namespace {
diff --git a/device/vr/openxr/windows/openxr_graphics_binding_d3d11.cc b/device/vr/openxr/windows/openxr_graphics_binding_d3d11.cc
index 33fea1f..f99f06e9 100644
--- a/device/vr/openxr/windows/openxr_graphics_binding_d3d11.cc
+++ b/device/vr/openxr/windows/openxr_graphics_binding_d3d11.cc
@@ -23,7 +23,6 @@
 #include "gpu/command_buffer/client/client_shared_image.h"
 #include "gpu/command_buffer/client/shared_image_interface.h"
 #include "gpu/command_buffer/common/shared_image_usage.h"
-#include "gpu/ipc/common/gpu_memory_buffer_impl_dxgi.h"
 #include "third_party/openxr/src/include/openxr/openxr.h"
 #include "ui/gfx/gpu_fence.h"
 #include "ui/gfx/gpu_memory_buffer_handle.h"
diff --git a/google_apis/gcm/tools/mcs_probe.cc b/google_apis/gcm/tools/mcs_probe.cc
index d035475..8ab2296f 100644
--- a/google_apis/gcm/tools/mcs_probe.cc
+++ b/google_apis/gcm/tools/mcs_probe.cc
@@ -10,7 +10,6 @@
 #include <cstddef>
 #include <cstdio>
 #include <memory>
-#include <set>
 #include <string>
 #include <utility>
 #include <vector>
@@ -18,6 +17,7 @@
 #include "base/at_exit.h"
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
+#include "base/containers/flat_set.h"
 #include "base/files/scoped_file.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
@@ -366,7 +366,7 @@
   builder.set_host_resolver(
       net::HostResolver::CreateStandaloneResolver(net_log_));
   http_auth_preferences_.set_allowed_schemes(
-      std::set<std::string>{net::kBasicAuthScheme});
+      base::flat_set<std::string>({net::kBasicAuthScheme}));
   builder.SetHttpAuthHandlerFactory(
       net::HttpAuthHandlerRegistryFactory::Create(&http_auth_preferences_));
   builder.set_proxy_resolution_service(
diff --git a/gpu/command_buffer/service/graphite_shared_context.cc b/gpu/command_buffer/service/graphite_shared_context.cc
index e62fa454..8d33b9a3 100644
--- a/gpu/command_buffer/service/graphite_shared_context.cc
+++ b/gpu/command_buffer/service/graphite_shared_context.cc
@@ -65,26 +65,74 @@
 }  // namespace
 
 // Helper class used by subclasses to acquire |lock_| if it exists.
+// Recursive lock is permitted for locking will be skipped upon reentance.
 class SCOPED_LOCKABLE GraphiteSharedContext::AutoLock {
   STACK_ALLOCATED();
-
  public:
   explicit AutoLock(const GraphiteSharedContext* context)
-      EXCLUSIVE_LOCK_FUNCTION(context->lock_)
-      : auto_lock_(context->lock_ ? &context->lock_.value() : nullptr) {}
-  ~AutoLock() UNLOCK_FUNCTION() = default;
+      EXCLUSIVE_LOCK_FUNCTION(context->lock_);
 
-  AutoLock(const AutoLock&) = delete;
-  AutoLock& operator=(const AutoLock&) = delete;
+  AutoLock(AutoLock&) = delete;
+  AutoLock& operator=(AutoLock&) = delete;
+
+  ~AutoLock() UNLOCK_FUNCTION();
 
  private:
-  base::AutoLockMaybe auto_lock_;
+  std::optional<base::AutoLockMaybe> auto_lock_;
+  const GraphiteSharedContext* context_;
 };
 
+// |context->locked_thread_id_| reflects the thread where |lock_| is acquired.
+// It should only be changed from Invalid to Current, or Current to Invalid.
+// It is accessed with `memory_order_relaxed` as writing to |locked_thread_id_|
+// is guarded by |context->lock_|.
+//
+// The logic of detecting recursive lock with
+// "current_thread_id == locked_thread_id_":
+// - There is no concurrent write hazard for |locked_thread_id|.
+// - If Thread1 holds |lock_| and it tries to re-acquire |lock_| after
+//   re-entering GraphiteSharedContext, |locked_thread_id_| can be read back
+//   safely now as no one can write to |locked_thread_id_| when |lock_| is held
+//   by Thread1. It is determined a recursive lock if the current thread id is
+//   |locked_thread_id_|. Locking should be skipped here to avoid a deadlock.
+// - If Thread1 has held |lock_| and is writing to |locked_thread_id_| while
+//   Thread2 is trying to read it, it means Thread1 changes the id between
+//   kInvalidThreadId and Thread1::Id() so neither of them matches the current
+//   Thread2 id. Thread2 can proceed to acquire the lock.
+//
+
+GraphiteSharedContext::AutoLock::AutoLock(const GraphiteSharedContext* context)
+    : context_(context) {
+  base::PlatformThreadId current_thread_id = base::PlatformThread::CurrentId();
+
+  if (!context->lock_ || current_thread_id == context->locked_thread_id_.load(
+                                                  std::memory_order_relaxed)) {
+    // Skip if is_thread_safe is disabled or it's a recursive lock.
+  } else {
+    auto_lock_.emplace(&context->lock_.value());
+
+    // |locked_thread_id_| must be kInvalid after the lock is acquired.
+    CHECK_EQ(context_->locked_thread_id_.load(std::memory_order_relaxed),
+             base::kInvalidThreadId);
+    context_->locked_thread_id_.store(current_thread_id,
+                                      std::memory_order_relaxed);
+  }
+}
+
+GraphiteSharedContext::AutoLock::~AutoLock() {
+  if (auto_lock_.has_value()) {
+    CHECK_EQ(context_->locked_thread_id_.load(std::memory_order_relaxed),
+             base::PlatformThread::CurrentId());
+    context_->locked_thread_id_.store(base::kInvalidThreadId,
+                                      std::memory_order_relaxed);
+  }
+}
+
 GraphiteSharedContext::GraphiteSharedContext(
     std::unique_ptr<skgpu::graphite::Context> graphite_context,
     bool is_thread_safe)
     : graphite_context_(std::move(graphite_context)) {
+  DCHECK(graphite_context_);
   if (is_thread_safe) {
     lock_.emplace();
   }
diff --git a/gpu/command_buffer/service/graphite_shared_context.h b/gpu/command_buffer/service/graphite_shared_context.h
index 4d0337b..f53f4326e 100644
--- a/gpu/command_buffer/service/graphite_shared_context.h
+++ b/gpu/command_buffer/service/graphite_shared_context.h
@@ -5,6 +5,8 @@
 #ifndef GPU_COMMAND_BUFFER_SERVICE_GRAPHITE_SHARED_CONTEXT_H_
 #define GPU_COMMAND_BUFFER_SERVICE_GRAPHITE_SHARED_CONTEXT_H_
 
+#include <atomic>
+
 #include "base/functional/callback.h"
 #include "base/synchronization/lock.h"
 #include "gpu/gpu_gles2_export.h"
@@ -151,6 +153,12 @@
   // Valid only when |is_thread_safe| is set to true in Ctor.
   mutable std::optional<base::Lock> lock_;
 
+  // This is the id of the thread where |lock_| is acquired, used for detecting
+  // recursive lock. |locked_thread_id_| is set to kInvalidThreadId when
+  // is_thread_safe is not enabled or when |lock_| is released.
+  mutable std::atomic<base::PlatformThreadId> locked_thread_id_{
+      base::kInvalidThreadId};
+
   const std::unique_ptr<skgpu::graphite::Context> graphite_context_;
 };
 
diff --git a/gpu/webgpu/callback.h b/gpu/webgpu/callback.h
index cd7380a..fdff81af 100644
--- a/gpu/webgpu/callback.h
+++ b/gpu/webgpu/callback.h
@@ -57,13 +57,13 @@
   }
 
   R Run(Args... args) &&
-    requires base::is_instantiation<base::OnceCallback, BaseCallback>
+    requires base::is_instantiation<BaseCallback, base::OnceCallback>
   {
     return std::move(callback_).Run(std::forward<Args>(args)...);
   }
 
   R Run(Args... args) const&
-    requires base::is_instantiation<base::RepeatingCallback, BaseCallback>
+    requires base::is_instantiation<BaseCallback, base::RepeatingCallback>
   {
     return callback_.Run(std::forward<Args>(args)...);
   }
@@ -117,7 +117,7 @@
 };
 
 template <typename CallbackType>
-  requires base::is_instantiation<base::OnceCallback, CallbackType>
+  requires base::is_instantiation<CallbackType, base::OnceCallback>
 auto MakeWGPUOnceCallback(CallbackType&& cb) {
   return new gpu::webgpu::WGPUOnceCallback<typename CallbackType::RunType>(
       std::move(cb));
@@ -136,7 +136,7 @@
 }
 
 template <typename CallbackType>
-  requires base::is_instantiation<base::RepeatingCallback, CallbackType>
+  requires base::is_instantiation<CallbackType, base::RepeatingCallback>
 auto MakeWGPURepeatingCallback(CallbackType&& cb) {
   return new gpu::webgpu::WGPURepeatingCallback<typename CallbackType::RunType>(
       std::move(cb));
diff --git a/internal b/internal
index 9fd28e7..fc82705 160000
--- a/internal
+++ b/internal
@@ -1 +1 @@
-Subproject commit 9fd28e7faf34a6ae2ee795d2aebafe88abe80407
+Subproject commit fc8270585d35ff4b1d05c06fbc75fa5fb7d8d63e
diff --git a/ios/chrome/browser/authentication/ui_bundled/BUILD.gn b/ios/chrome/browser/authentication/ui_bundled/BUILD.gn
index 4b4f0b2b..a9757ac 100644
--- a/ios/chrome/browser/authentication/ui_bundled/BUILD.gn
+++ b/ios/chrome/browser/authentication/ui_bundled/BUILD.gn
@@ -237,6 +237,8 @@
   sources = [
     "expected_signin_histograms.h",
     "expected_signin_histograms.mm",
+    "separate_profiles_util.h",
+    "separate_profiles_util.mm",
     "signin_earl_grey.h",
     "signin_earl_grey.mm",
     "signin_earl_grey_app_interface.h",
@@ -255,11 +257,14 @@
     "//components/signin/public/base",
     "//components/sync/base",
     "//ios/chrome/app/strings",
+    "//ios/chrome/browser/authentication/ui_bundled/account_menu:constants",
     "//ios/chrome/browser/authentication/ui_bundled/cells:constants",
+    "//ios/chrome/browser/authentication/ui_bundled/history_sync:pref_names",
     "//ios/chrome/browser/authentication/ui_bundled/signin:constants",
     "//ios/chrome/browser/authentication/ui_bundled/views:views_constants",
     "//ios/chrome/browser/first_run/ui_bundled:constants",
     "//ios/chrome/browser/metrics/model:eg_test_support+eg2",
+    "//ios/chrome/browser/ntp/ui_bundled:constants",
     "//ios/chrome/browser/recent_tabs/ui_bundled:ui_constants",
     "//ios/chrome/browser/settings/ui_bundled:constants",
     "//ios/chrome/browser/settings/ui_bundled/google_services:constants",
@@ -283,8 +288,6 @@
     "separate_profiles_egtest.mm",
     "separate_profiles_migration_egtest.mm",
     "separate_profiles_rollback_egtest.mm",
-    "separate_profiles_util.h",
-    "separate_profiles_util.mm",
   ]
   deps = [
     ":eg_test_support+eg2",
diff --git a/ios/chrome/browser/authentication/ui_bundled/account_menu/account_menu_egtest.mm b/ios/chrome/browser/authentication/ui_bundled/account_menu/account_menu_egtest.mm
index 73daf64..aec167c 100644
--- a/ios/chrome/browser/authentication/ui_bundled/account_menu/account_menu_egtest.mm
+++ b/ios/chrome/browser/authentication/ui_bundled/account_menu/account_menu_egtest.mm
@@ -7,6 +7,7 @@
 #import "base/strings/sys_string_conversions.h"
 #import "base/test/ios/wait_util.h"
 #import "ios/chrome/browser/authentication/ui_bundled/account_menu/account_menu_constants.h"
+#import "ios/chrome/browser/authentication/ui_bundled/separate_profiles_util.h"
 #import "ios/chrome/browser/authentication/ui_bundled/signin_earl_grey.h"
 #import "ios/chrome/browser/authentication/ui_bundled/signin_earl_grey_ui_test_util.h"
 #import "ios/chrome/browser/bookmarks/ui_bundled/bookmark_earl_grey.h"
@@ -76,6 +77,15 @@
 
 @implementation AccountMenuTestCase
 
++ (void)setUpForTestCase {
+  [SigninEarlGrey setUseFakeResponsesForProfileSeparationPolicyRequests];
+}
+
++ (void)tearDown {
+  [SigninEarlGrey clearUseFakeResponsesForProfileSeparationPolicyRequests];
+  [super tearDown];
+}
+
 - (AppLaunchConfiguration)appConfigurationForTestCase {
   AppLaunchConfiguration config = [super appConfigurationForTestCase];
 
@@ -486,6 +496,14 @@
                   IDS_IOS_MANAGED_SIGNIN_WITH_USER_POLICY_CONTINUE_BUTTON_LABEL)),
               grey_interactable(), nil)] performAction:grey_tap()];
 
+  if ([SigninEarlGrey areSeparateProfilesForManagedAccountsEnabled]) {
+    // Dismiss the history sync screen.
+    [ChromeEarlGrey waitForMatcher:HistoryScreenMatcher()];
+    [[EarlGrey selectElementWithMatcher:chrome_test_util::
+                                            PromoScreenSecondaryButtonMatcher()]
+        performAction:grey_tap()];
+  }
+
   [self assertSnackbarShownAndDismissItWithIdentity:kManagedIdentity1];
   [SigninEarlGrey verifySignedInWithFakeIdentity:kManagedIdentity1];
   [self assertAccountMenuIsNotShown];
@@ -519,6 +537,14 @@
                   IDS_IOS_MANAGED_SIGNIN_WITH_USER_POLICY_CONTINUE_BUTTON_LABEL)),
               grey_interactable(), nil)] performAction:grey_tap()];
 
+  if ([SigninEarlGrey areSeparateProfilesForManagedAccountsEnabled]) {
+    // Dismiss the history sync screen.
+    [ChromeEarlGrey waitForMatcher:HistoryScreenMatcher()];
+    [[EarlGrey selectElementWithMatcher:chrome_test_util::
+                                            PromoScreenSecondaryButtonMatcher()]
+        performAction:grey_tap()];
+  }
+
   [self assertSnackbarShownAndDismissItWithIdentity:kManagedIdentity2];
   [self assertAccountMenuIsNotShown];
   [SigninEarlGrey verifySignedInWithFakeIdentity:kManagedIdentity2];
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_coordinator.h b/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_coordinator.h
index 71516b45..0619c85 100644
--- a/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_coordinator.h
+++ b/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_coordinator.h
@@ -35,9 +35,13 @@
     delegate;
 @property(nonatomic, weak) id<ConsistencyLayoutDelegate> layoutDelegate;
 
-- (void)start NS_UNAVAILABLE;
-// Starts the coordinator with the selected identity.
-- (void)startWithSelectedIdentity:(id<SystemIdentity>)selectedIdentity;
+- (instancetype)initWithBaseViewController:(UIViewController*)viewController
+                                   browser:(Browser*)browser
+                          selectedIdentity:(id<SystemIdentity>)selectedIdentity
+    NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)initWithBaseViewController:(UIViewController*)viewController
+                                   browser:(Browser*)browser NS_UNAVAILABLE;
 
 @end
 
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_coordinator.mm b/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_coordinator.mm
index 99de5e26..a012a64 100644
--- a/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_coordinator.mm
+++ b/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_account_chooser/consistency_account_chooser_coordinator.mm
@@ -29,14 +29,27 @@
 
 @end
 
-@implementation ConsistencyAccountChooserCoordinator
+@implementation ConsistencyAccountChooserCoordinator {
+  id<SystemIdentity> _selectedIdentity;
+}
 
-- (void)startWithSelectedIdentity:(id<SystemIdentity>)selectedIdentity {
+- (instancetype)initWithBaseViewController:(UIViewController*)viewController
+                                   browser:(Browser*)browser
+                          selectedIdentity:
+                              (id<SystemIdentity>)selectedIdentity {
+  self = [super initWithBaseViewController:viewController browser:browser];
+  if (self) {
+    _selectedIdentity = selectedIdentity;
+  }
+  return self;
+}
+
+- (void)start {
   [super start];
   base::RecordAction(
       base::UserMetricsAction("Signin_BottomSheet_IdentityChooser_Opened"));
   self.mediator = [[ConsistencyAccountChooserMediator alloc]
-      initWithSelectedIdentity:selectedIdentity
+      initWithSelectedIdentity:_selectedIdentity
                identityManager:IdentityManagerFactory::GetForProfile(
                                    self.profile)
          accountManagerService:ChromeAccountManagerServiceFactory::
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_view_controller.mm b/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_view_controller.mm
index b9959000..b1f5770 100644
--- a/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_view_controller.mm
+++ b/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_view_controller.mm
@@ -249,23 +249,31 @@
 #pragma mark - UI actions
 
 - (void)skipButtonAction:(id)sender {
+  base::RecordAction(
+      base::UserMetricsAction("Signin_BottomSheet_DefaultAccount_Skip"));
   [self.actionDelegate consistencyDefaultAccountViewControllerSkip:self];
 }
 
 - (void)identityButtonControlAction:(id)sender forEvent:(UIEvent*)event {
+  base::RecordAction(base::UserMetricsAction(
+      "Signin_BottomSheet_DefaultAccount_IdentityButtonTapped"));
   [self.actionDelegate
       consistencyDefaultAccountViewControllerOpenIdentityChooser:self];
 }
 
 - (void)primaryButtonAction:
     (ConsistencyDefaultAccountViewController*)viewController {
-  // If the IdentityButtonControl is hidden, there is no account avaiable on the
-  // device.
   if (!self.identityButtonControl.hidden) {
+    base::RecordAction(
+        base::UserMetricsAction("Signin_BottomSheet_DefaultAccount_Signin"));
     [self.actionDelegate
         consistencyDefaultAccountViewControllerContinueWithSelectedIdentity:
             self];
   } else {
+    // If the IdentityButtonControl is hidden, there is no account available on
+    // the device.
+    base::RecordAction(base::UserMetricsAction(
+        "Signin_BottomSheet_DefaultAccount_AddAccount"));
     [self.actionDelegate
         consistencyDefaultAccountViewControllerAddAccountAndSignin:self];
   }
diff --git a/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_promo_signin_coordinator.mm b/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_promo_signin_coordinator.mm
index 932f38c3..5dbd2c66 100644
--- a/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_promo_signin_coordinator.mm
+++ b/ios/chrome/browser/authentication/ui_bundled/signin/consistency_promo_signin/consistency_promo_signin_coordinator.mm
@@ -430,12 +430,12 @@
     (ConsistencyDefaultAccountCoordinator*)coordinator {
   self.accountChooserCoordinator = [[ConsistencyAccountChooserCoordinator alloc]
       initWithBaseViewController:self.navigationController
-                         browser:self.browser];
+                         browser:self.browser
+                selectedIdentity:self.defaultAccountCoordinator
+                                     .selectedIdentity];
   self.accountChooserCoordinator.delegate = self;
   self.accountChooserCoordinator.layoutDelegate = self;
-  [self.accountChooserCoordinator
-      startWithSelectedIdentity:self.defaultAccountCoordinator
-                                    .selectedIdentity];
+  [self.accountChooserCoordinator start];
   [self.navigationController
       pushViewController:self.accountChooserCoordinator.viewController
                 animated:YES];
diff --git a/ios/chrome/browser/autofill/ui_bundled/authentication/authentication_egtest_util.h b/ios/chrome/browser/autofill/ui_bundled/authentication/authentication_egtest_util.h
index 6c366407..e8e2e395 100644
--- a/ios/chrome/browser/autofill/ui_bundled/authentication/authentication_egtest_util.h
+++ b/ios/chrome/browser/autofill/ui_bundled/authentication/authentication_egtest_util.h
@@ -30,4 +30,8 @@
 // sent out.
 extern NSString* const kSelectChallengeOptionResponseSuccess;
 
+// The fake response from the payment server when a success code is successfully
+// sent out.
+extern NSString* const kUnmaskCardSuccessResponseNoAuthNeeded;
+
 #endif  // IOS_CHROME_BROWSER_AUTOFILL_UI_BUNDLED_AUTHENTICATION_AUTHENTICATION_EGTEST_UTIL_H_
diff --git a/ios/chrome/browser/autofill/ui_bundled/authentication/authentication_egtest_util.mm b/ios/chrome/browser/autofill/ui_bundled/authentication/authentication_egtest_util.mm
index 4c494d80..d376300 100644
--- a/ios/chrome/browser/autofill/ui_bundled/authentication/authentication_egtest_util.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/authentication/authentication_egtest_util.mm
@@ -32,3 +32,6 @@
     @"selectchallengeoption";
 NSString* const kSelectChallengeOptionResponseSuccess =
     @"{\"context_token\":\"fake_context_token\"}";
+NSString* const kUnmaskCardSuccessResponseNoAuthNeeded =
+    @"{ \"pan\": \"5411111111112109\",\"dcvv\": \"123\", "
+    @"\"expiration\":{\"month\":4, \"year\":2100} }";
diff --git a/ios/chrome/browser/autofill/ui_bundled/bottom_sheet/BUILD.gn b/ios/chrome/browser/autofill/ui_bundled/bottom_sheet/BUILD.gn
index bc6dd8f..c79566ea 100644
--- a/ios/chrome/browser/autofill/ui_bundled/bottom_sheet/BUILD.gn
+++ b/ios/chrome/browser/autofill/ui_bundled/bottom_sheet/BUILD.gn
@@ -168,6 +168,7 @@
     "//ios/chrome/browser/autofill/ui_bundled:autofill_ui_constants",
     "//ios/chrome/browser/autofill/ui_bundled:eg_test_support+eg2",
     "//ios/chrome/browser/autofill/ui_bundled/authentication:card_unmask_authentication_selection_constants",
+    "//ios/chrome/browser/autofill/ui_bundled/authentication:egtest_util",
     "//ios/chrome/browser/autofill/ui_bundled/manual_fill:eg_test_support+eg2",
     "//ios/chrome/browser/metrics/model:eg_test_support+eg2",
     "//ios/chrome/browser/settings/ui_bundled:settings_root_constants",
diff --git a/ios/chrome/browser/autofill/ui_bundled/bottom_sheet/payments_suggestion_bottom_sheet_egtest.mm b/ios/chrome/browser/autofill/ui_bundled/bottom_sheet/payments_suggestion_bottom_sheet_egtest.mm
index 2a70828..b6e35b2 100644
--- a/ios/chrome/browser/autofill/ui_bundled/bottom_sheet/payments_suggestion_bottom_sheet_egtest.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/bottom_sheet/payments_suggestion_bottom_sheet_egtest.mm
@@ -15,6 +15,7 @@
 #import "components/strings/grit/components_strings.h"
 #import "components/url_formatter/elide_url.h"
 #import "ios/chrome/browser/autofill/model/features.h"
+#import "ios/chrome/browser/autofill/ui_bundled/authentication/authentication_egtest_util.h"
 #import "ios/chrome/browser/autofill/ui_bundled/autofill_app_interface.h"
 #import "ios/chrome/browser/autofill/ui_bundled/autofill_ui_constants.h"
 #import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_matchers.h"
@@ -37,17 +38,10 @@
 
 namespace {
 
-const char kCreditCardUrl[] = "/credit_card.html";
 const char kCreditCardWithAutofocusUrl[] = "/credit_card_autofocused.html";
-const char kFormCardName[] = "CCName";
 const char kFormCardNumber[] = "CCNo";
 const char kFormCardExpirationMonth[] = "CCExpiresMonth";
 const char kFormCardExpirationYear[] = "CCExpiresYear";
-NSString* const kTriggeringRequestUrl =
-    @"https://payments.google.com/payments/apis-secure/creditcardservice/"
-    @"getrealpan?s7e_suffix=chromewallet";
-NSString* const kSuccessResponseNoAuthNeeded =
-    @"{ \"pan\": \"5411111111112109\" }";
 
 // Matcher for the credit card suggestion chip.
 id<GREYMatcher> KeyboardAccessoryCreditCardSuggestionChip() {
@@ -512,9 +506,10 @@
                       chrome_test_util::StaticTextWithAccessibilityLabelId(
                           IDS_AUTOFILL_CARD_UNMASK_PROGRESS_DIALOG_TITLE)];
   // Fake the successful server response that triggers Dismiss.
-  [AutofillAppInterface setPaymentsResponse:kSuccessResponseNoAuthNeeded
-                                 forRequest:kTriggeringRequestUrl
-                              withErrorCode:net::HTTP_OK];
+  [AutofillAppInterface
+      setPaymentsResponse:kUnmaskCardSuccessResponseNoAuthNeeded
+               forRequest:kUnmaskCardRequestUrl
+            withErrorCode:net::HTTP_OK];
   // This delay is the autodismiss delay (1 second) + extra time to avoid
   // flakiness on the simulators (2 seconds).
   const base::TimeDelta total_delay_for_dismiss =
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/fallback_coordinator_egtest.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/fallback_coordinator_egtest.mm
index 0f1c10d..59f399af 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/fallback_coordinator_egtest.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/fallback_coordinator_egtest.mm
@@ -290,7 +290,13 @@
 // Tests the mediator stops observing objects when the incognito BVC is
 // destroyed. Waiting for dealloc was causing a race condition with the
 // autorelease pool, and some times a DCHECK will be hit.
-- (void)testOpeningIncognitoTabsDoNotLeak {
+// TODO(crbug.com/40776865): Test fails on Simulator.
+#if TARGET_IPHONE_SIMULATOR
+#define MAYBE_testOpeningIncognitoTabsDoNotLeak DISABLED_testOpeningIncognitoTabsDoNotLeak
+#else
+#define MAYBE_testOpeningIncognitoTabsDoNotLeak testOpeningIncognitoTabsDoNotLeak
+#endif  // TARGET_IPHONE_SIMULATOR
+- (void)MAYBE_testOpeningIncognitoTabsDoNotLeak {
   [AutofillAppInterface saveExampleProfile];
 
   const GURL URL = self.testServer->GetURL(kFormHTMLFile);
diff --git a/ios/chrome/browser/autofill/ui_bundled/progress_dialog/BUILD.gn b/ios/chrome/browser/autofill/ui_bundled/progress_dialog/BUILD.gn
index 499e33d..f582764 100644
--- a/ios/chrome/browser/autofill/ui_bundled/progress_dialog/BUILD.gn
+++ b/ios/chrome/browser/autofill/ui_bundled/progress_dialog/BUILD.gn
@@ -53,6 +53,7 @@
     "//ios/chrome/app/strings",
     "//ios/chrome/browser/autofill/ui_bundled:autofill_ui_constants",
     "//ios/chrome/browser/autofill/ui_bundled:eg_test_support+eg2",
+    "//ios/chrome/browser/autofill/ui_bundled/authentication:egtest_util",
     "//ios/chrome/browser/shared/ui/symbols",
     "//ios/chrome/test/earl_grey:eg_test_support+eg2",
     "//ios/testing/earl_grey:eg_test_support+eg2",
diff --git a/ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_egtest.mm b/ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_egtest.mm
index c7de6a4..ce7a1a7 100644
--- a/ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_egtest.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/progress_dialog/autofill_progress_dialog_egtest.mm
@@ -9,6 +9,7 @@
 #import "components/autofill/core/browser/test_utils/autofill_test_utils.h"
 #import "components/autofill/core/common/autofill_payments_features.h"
 #import "components/strings/grit/components_strings.h"
+#import "ios/chrome/browser/autofill/ui_bundled/authentication/authentication_egtest_util.h"
 #import "ios/chrome/browser/autofill/ui_bundled/autofill_app_interface.h"
 #import "ios/chrome/browser/autofill/ui_bundled/autofill_ui_constants.h"
 #import "ios/chrome/browser/shared/ui/symbols/symbols.h"
@@ -23,19 +24,6 @@
 #import "net/test/embedded_test_server/default_handlers.h"
 #import "ui/base/l10n/l10n_util.h"
 
-namespace {
-
-const char kTestPageUrl[] = "/credit_card.html";
-NSString* const kTriggeringRequestUrl =
-    @"https://payments.google.com/payments/apis-secure/creditcardservice/"
-    @"getrealpan?s7e_suffix=chromewallet";
-NSString* const kSuccessResponseNoAuthNeeded =
-    @"{ \"pan\": \"5411111111112109\" }";
-const char kAutofillTestString[] = "Autofill Test";
-const char kFormCardName[] = "CCName";
-
-}  // namespace
-
 @interface AutofillProgressDialogDismissEGTest : ChromeTestCase {
   NSString* _enrolledCardNameAndLastFour;
 }
@@ -59,7 +47,7 @@
   [AutofillAppInterface setMandatoryReauthEnabled:NO];
   net::test_server::RegisterDefaultHandlers(self.testServer);
   GREYAssertTrue(self.testServer->Start(), @"Failed to start test server.");
-  GURL testURL = self.testServer->GetURL(kTestPageUrl);
+  GURL testURL = self.testServer->GetURL(kCreditCardUrl);
   [ChromeEarlGrey loadURL:testURL];
   [ChromeEarlGrey waitForWebStateContainingText:kAutofillTestString];
   [AutofillAppInterface considerCreditCardFormSecureForTesting];
@@ -115,9 +103,10 @@
       assertWithMatcher:grey_sufficientlyVisible()];
 
   // Fake the successful server response that triggers Dismiss.
-  [AutofillAppInterface setPaymentsResponse:kSuccessResponseNoAuthNeeded
-                                 forRequest:kTriggeringRequestUrl
-                              withErrorCode:net::HTTP_OK];
+  [AutofillAppInterface
+      setPaymentsResponse:kUnmaskCardSuccessResponseNoAuthNeeded
+               forRequest:kUnmaskCardRequestUrl
+            withErrorCode:net::HTTP_OK];
 
   // This delay is the autodismiss delay (1 second) + extra time to avoid
   // flakiness on the simulators (2 seconds).
diff --git a/ios/chrome/browser/ntp_tiles/model/most_visited_sites_observer_bridge.h b/ios/chrome/browser/ntp_tiles/model/most_visited_sites_observer_bridge.h
index 249eb65..dbc016e 100644
--- a/ios/chrome/browser/ntp_tiles/model/most_visited_sites_observer_bridge.h
+++ b/ios/chrome/browser/ntp_tiles/model/most_visited_sites_observer_bridge.h
@@ -41,6 +41,7 @@
   ~MostVisitedSitesObserverBridge() override;
 
   void OnURLsAvailable(
+      bool is_user_triggered,
       const std::map<SectionType, NTPTilesVector>& sections) override;
   void OnIconMadeAvailable(const GURL& site_url) override;
 
diff --git a/ios/chrome/browser/ntp_tiles/model/most_visited_sites_observer_bridge.mm b/ios/chrome/browser/ntp_tiles/model/most_visited_sites_observer_bridge.mm
index 2f831fb..69db31b 100644
--- a/ios/chrome/browser/ntp_tiles/model/most_visited_sites_observer_bridge.mm
+++ b/ios/chrome/browser/ntp_tiles/model/most_visited_sites_observer_bridge.mm
@@ -14,6 +14,7 @@
 MostVisitedSitesObserverBridge::~MostVisitedSitesObserverBridge() {}
 
 void MostVisitedSitesObserverBridge::OnURLsAvailable(
+    bool is_user_triggered,
     const std::map<SectionType, NTPTilesVector>& sections) {
   const NTPTilesVector& most_visited = sections.at(SectionType::PERSONALIZED);
   [observer_ onMostVisitedURLsAvailable:most_visited];
diff --git a/ios/chrome/browser/promos_manager/ui_bundled/promos_manager_coordinator.mm b/ios/chrome/browser/promos_manager/ui_bundled/promos_manager_coordinator.mm
index 0797d5e8..823e7e088 100644
--- a/ios/chrome/browser/promos_manager/ui_bundled/promos_manager_coordinator.mm
+++ b/ios/chrome/browser/promos_manager/ui_bundled/promos_manager_coordinator.mm
@@ -144,6 +144,8 @@
   DCHECK(ShouldPromoManagerDisplayPromos());
   if ((self = [super initWithBaseViewController:viewController
                                         browser:browser])) {
+    CHECK(viewController, base::NotFatalUntil::M140);
+    CHECK(browser, base::NotFatalUntil::M140);
     _applicationCommandHandler = applicationHandler;
     _credentialProviderPromoCommandHandler = credentialProviderPromoHandler;
     _dockingPromoCommandHandler = dockingPromoHandler;
@@ -169,6 +171,12 @@
   return self;
 }
 
+- (void)dealloc {
+  CHECK(!_mediator, base::NotFatalUntil::M140);
+  CHECK(!self.viewController, base::NotFatalUntil::M140);
+  CHECK(!self.banneredViewController, base::NotFatalUntil::M140);
+}
+
 #pragma mark - Public
 
 - (void)start {
diff --git a/ios/chrome/browser/promos_manager/ui_bundled/promos_manager_coordinator_unittest.mm b/ios/chrome/browser/promos_manager/ui_bundled/promos_manager_coordinator_unittest.mm
index b9d7c97f..3bdbb00 100644
--- a/ios/chrome/browser/promos_manager/ui_bundled/promos_manager_coordinator_unittest.mm
+++ b/ios/chrome/browser/promos_manager/ui_bundled/promos_manager_coordinator_unittest.mm
@@ -71,6 +71,7 @@
   }
 
   void TearDown() override {
+    [coordinator_ stop];
     [scene_state_ shutdown];
     scene_state_ = nil;
     PlatformTest::TearDown();
diff --git a/ios/components/io_thread/ios_io_thread.mm b/ios/components/io_thread/ios_io_thread.mm
index b4b50ff..7fb7275 100644
--- a/ios/components/io_thread/ios_io_thread.mm
+++ b/ios/components/io_thread/ios_io_thread.mm
@@ -11,6 +11,7 @@
 
 #import "base/check_op.h"
 #import "base/command_line.h"
+#import "base/containers/flat_set.h"
 #import "base/environment.h"
 #import "base/functional/bind.h"
 #import "base/functional/callback_helpers.h"
@@ -73,7 +74,11 @@
 
 namespace {
 
-const char kSupportedAuthSchemes[] = "basic,digest,ntlm";
+constexpr auto kSupportedAuthSchemes = std::to_array<std::string_view>({
+    net::kBasicAuthScheme,
+    net::kDigestAuthScheme,
+    net::kNtlmAuthScheme,
+});
 
 }  // namespace
 
@@ -266,13 +271,11 @@
 }
 
 void IOSIOThread::CreateDefaultAuthPreferences() {
-  std::vector<std::string> supported_schemes =
-      base::SplitString(kSupportedAuthSchemes, ",", base::TRIM_WHITESPACE,
-                        base::SPLIT_WANT_NONEMPTY);
   globals_->http_auth_preferences =
       std::make_unique<net::HttpAuthPreferences>();
-  globals_->http_auth_preferences->set_allowed_schemes(std::set<std::string>(
-      supported_schemes.begin(), supported_schemes.end()));
+  globals_->http_auth_preferences->set_allowed_schemes(
+      base::flat_set<std::string>(kSupportedAuthSchemes.begin(),
+                                  kSupportedAuthSchemes.end()));
 }
 
 void IOSIOThread::ClearHostCache() {
diff --git a/ios_internal b/ios_internal
index 27a3b55..9359be0 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit 27a3b55cbe85ff91ece1b77557c87338d6a96984
+Subproject commit 9359be07f1fa746ee3d0332c9292639e6c5effcf
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index d48d31a..dcb8dce 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -396,6 +396,18 @@
              "WebrtcMediaCapabilitiesParameters",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
+// Controls the persistent license support for protected media that uses
+// widevine.
+BASE_FEATURE(kWidvinePersistentLicenseSupport,
+             "WidvinePersistentLicenseSupport",
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
+             // TODO(crbug.com/423458074): This will rollout slowly as an
+             // experiment eventually becoming disabled by default.
+             base::FEATURE_ENABLED_BY_DEFAULT);
+#else
+             base::FEATURE_ENABLED_BY_DEFAULT);
+#endif  // BUILDFLAG(ENABLE_LIBRARY_CDMS)
+
 // Display the Cast overlay button on the media controls.
 BASE_FEATURE(kMediaCastOverlayButton,
              "MediaCastOverlayButton",
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index bfa1dbe..d3b11e4b8 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -385,6 +385,7 @@
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kWebRTCHardwareVideoEncoderFrameDrop);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kWebRTCColorAccuracy);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kWebrtcMediaCapabilitiesParameters);
+MEDIA_EXPORT BASE_DECLARE_FEATURE(kWidvinePersistentLicenseSupport);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kResolutionBasedDecoderPriority);
 
 #if BUILDFLAG(IS_ANDROID)
diff --git a/media/fuchsia/video/fuchsia_video_decoder.cc b/media/fuchsia/video/fuchsia_video_decoder.cc
index b995e1455..46cec555 100644
--- a/media/fuchsia/video/fuchsia_video_decoder.cc
+++ b/media/fuchsia/video/fuchsia_video_decoder.cc
@@ -690,7 +690,16 @@
 }
 
 void FuchsiaVideoDecoder::CallNextDecodeCallback() {
-  DCHECK(!decode_callbacks_.empty());
+  if (decode_callbacks_.empty()) {
+    // Besides the potential possibilities of unexpected calling this function
+    // more times than expected, triggering this condition may also mean that we
+    // executed the callback too early and ignored some of the frames.
+    // The root cause is still being investigated, and will be fixed later.
+    // TODO(crbug.com/423634129): Remove this log once the root cause is fixed.
+    LOG(WARNING)
+        << "Called CallNextDecodeCallback more times than expected.";
+    return;
+  }
   auto cb = std::move(decode_callbacks_.front());
   decode_callbacks_.pop_front();
 
diff --git a/media/mojo/mojom/BUILD.gn b/media/mojo/mojom/BUILD.gn
index 2ca0bedf..e3ca85c2 100644
--- a/media/mojo/mojom/BUILD.gn
+++ b/media/mojo/mojom/BUILD.gn
@@ -870,6 +870,10 @@
           cpp = "::media::HypothesisParts"
         },
         {
+          mojom = "media.mojom.MediaTimestampRange"
+          cpp = "::media::MediaTimestampRange"
+        },
+        {
           mojom = "media.mojom.TimingInformation"
           cpp = "::media::TimingInformation"
         },
diff --git a/media/mojo/mojom/speech_recognition.mojom b/media/mojo/mojom/speech_recognition.mojom
index a0d248a..f6a18030 100644
--- a/media/mojo/mojom/speech_recognition.mojom
+++ b/media/mojo/mojom/speech_recognition.mojom
@@ -12,7 +12,7 @@
 import "mojo/public/mojom/base/unguessable_token.mojom";
 import "ui/gfx/geometry/mojom/geometry.mojom";
 
-// Next MinVersion: 11
+// Next MinVersion: 12
 
 // Corresponds to the LangIdEvent.ConfidenceInterval defined in
 // http://google3/speech/soda/public/soda_event.proto.
@@ -141,6 +141,12 @@
   mojo_base.mojom.TimeDelta hypothesis_part_offset;
 };
 
+[Stable]
+struct MediaTimestampRange {
+  mojo_base.mojom.TimeDelta start;
+  mojo_base.mojom.TimeDelta end;
+};
+
 // The timing information for the transcript.
 [Stable]
 struct TimingInformation {
@@ -157,6 +163,16 @@
   // must be optional. Hypothesis parts maybe non-empty optional containing a
   // zero length vector if no words were spoken during the event's time span.
   array<HypothesisParts>? hypothesis_parts;
+
+  // The presentation timestamps of media that originated the transcription.
+  // Might contain multiple (possibly overlapping) ranges if the originating
+  // media was seeked. Ranges will appear in the order in which the audio was
+  // given to SODA, such that the first range matches `audio_start_time`, and
+  // the last range matches `audio_end_time`.
+  // Note: this metadata is provided by Chromium, and doesn't have a SODA
+  //       equivalent.
+  [MinVersion=11]
+  array<MediaTimestampRange>? originating_media_timestamps;
 };
 
 // A speech recognition result created by the speech service and passed to the
diff --git a/media/mojo/mojom/speech_recognition_result.h b/media/mojo/mojom/speech_recognition_result.h
index 5d8757b..dcfe824 100644
--- a/media/mojo/mojom/speech_recognition_result.h
+++ b/media/mojo/mojom/speech_recognition_result.h
@@ -37,6 +37,16 @@
   base::TimeDelta hypothesis_part_offset;
 };
 
+// A [`start`, `end`) range of media presentation timestamps.
+struct MediaTimestampRange {
+  // Inclusive start of the range.
+  base::TimeDelta start;
+  // Exclusive end of the range.
+  base::TimeDelta end;
+
+  bool operator==(const MediaTimestampRange& rhs) const = default;
+};
+
 struct TimingInformation {
   TimingInformation();
   TimingInformation(const TimingInformation&);
@@ -60,6 +70,15 @@
   // must be optional. Hypothesis parts maybe non-empty optional containing a
   // zero length vector if no words were spoken during the event's time span.
   std::optional<std::vector<HypothesisParts>> hypothesis_parts;
+
+  // The presentation timestamps of media that originated the transcription.
+  // Might contain multiple (possibly overlapping) ranges if the originating
+  // media was seeked. Ranges will appear in the order in which the audio was
+  // given to SODA, such that the first range matches `audio_start_time`, and
+  // the last range matches `audio_end_time`.
+  // Note: this metadata is provided by Chromium, and doesn't have a SODA
+  //       equivalent.
+  std::optional<std::vector<MediaTimestampRange>> originating_media_timestamps;
 };
 
 // A speech recognition result created by the speech service and passed to the
diff --git a/media/mojo/mojom/speech_recognition_result_mojom_traits.cc b/media/mojo/mojom/speech_recognition_result_mojom_traits.cc
index fdec03c5..ac77e65ee 100644
--- a/media/mojo/mojom/speech_recognition_result_mojom_traits.cc
+++ b/media/mojo/mojom/speech_recognition_result_mojom_traits.cc
@@ -30,6 +30,26 @@
   return true;
 }
 
+bool StructTraits<media::mojom::MediaTimestampRangeDataView,
+                  media::MediaTimestampRange>::
+    Read(media::mojom::MediaTimestampRangeDataView data,
+         media::MediaTimestampRange* out) {
+  base::TimeDelta start;
+  base::TimeDelta end;
+
+  if (!data.ReadStart(&start) || !data.ReadEnd(&end)) {
+    return false;
+  }
+
+  if (start >= end) {
+    return false;
+  }
+
+  out->start = start;
+  out->end = end;
+  return true;
+}
+
 bool StructTraits<media::mojom::TimingInformationDataView,
                   media::TimingInformation>::
     Read(media::mojom::TimingInformationDataView data,
@@ -37,10 +57,13 @@
   base::TimeDelta audio_start_time = kZeroTime;
   base::TimeDelta audio_end_time = kZeroTime;
   std::optional<std::vector<media::HypothesisParts>> hypothesis_parts;
+  std::optional<std::vector<media::MediaTimestampRange>>
+      originating_media_timestamps;
 
   if (!data.ReadAudioStartTime(&audio_start_time) ||
       !data.ReadAudioEndTime(&audio_end_time) ||
-      !data.ReadHypothesisParts(&hypothesis_parts)) {
+      !data.ReadHypothesisParts(&hypothesis_parts) ||
+      !data.ReadOriginatingMediaTimestamps(&originating_media_timestamps)) {
     return false;
   }
 
@@ -59,9 +82,13 @@
     }
   }
 
+  // `originating_media_timestamps` should have already failed to deserialize if
+  // any of its MediaTimestampRanges has a start a `start` >= `end`.
+
   out->audio_start_time = audio_start_time;
   out->audio_end_time = audio_end_time;
   out->hypothesis_parts = std::move(hypothesis_parts);
+  out->originating_media_timestamps = std::move(originating_media_timestamps);
   return true;
 }
 
diff --git a/media/mojo/mojom/speech_recognition_result_mojom_traits.h b/media/mojo/mojom/speech_recognition_result_mojom_traits.h
index 2be168a..e8b3372 100644
--- a/media/mojo/mojom/speech_recognition_result_mojom_traits.h
+++ b/media/mojo/mojom/speech_recognition_result_mojom_traits.h
@@ -33,6 +33,22 @@
 };
 
 template <>
+class StructTraits<media::mojom::MediaTimestampRangeDataView,
+                   media::MediaTimestampRange> {
+ public:
+  static base::TimeDelta start(const media::MediaTimestampRange& r) {
+    return r.start;
+  }
+
+  static base::TimeDelta end(const media::MediaTimestampRange& r) {
+    return r.end;
+  }
+
+  static bool Read(media::mojom::MediaTimestampRangeDataView data,
+                   media::MediaTimestampRange* out);
+};
+
+template <>
 class StructTraits<media::mojom::TimingInformationDataView,
                    media::TimingInformation> {
  public:
@@ -49,6 +65,11 @@
     return r.hypothesis_parts;
   }
 
+  static const ::std::optional<std::vector<media::MediaTimestampRange>>&
+  originating_media_timestamps(const media::TimingInformation& r) {
+    return r.originating_media_timestamps;
+  }
+
   static bool Read(media::mojom::TimingInformationDataView data,
                    media::TimingInformation* out);
 };
diff --git a/media/mojo/mojom/speech_recognition_result_mojom_traits_unittest.cc b/media/mojo/mojom/speech_recognition_result_mojom_traits_unittest.cc
index 54e9b45..0b8720ff 100644
--- a/media/mojo/mojom/speech_recognition_result_mojom_traits_unittest.cc
+++ b/media/mojo/mojom/speech_recognition_result_mojom_traits_unittest.cc
@@ -108,4 +108,68 @@
   EXPECT_EQ(valid_result, output);
 }
 
+TEST(SpeechRecognitionResultStructTraitsTest,
+     WithInvalidOriginatingMediaTimestamps) {
+  constexpr auto verify_serialization_round_trip_fails =
+      [](media::MediaTimestampRange invalid_range) {
+        media::SpeechRecognitionResult invalid_result("hello world", true);
+        invalid_result.timing_information = media::TimingInformation();
+        invalid_result.timing_information->audio_start_time = kZeroTime;
+        invalid_result.timing_information->audio_end_time = base::Seconds(1);
+        invalid_result.timing_information->originating_media_timestamps =
+            std::vector<media::MediaTimestampRange>();
+        auto& originating_media_timestamps =
+            invalid_result.timing_information->originating_media_timestamps
+                .value();
+
+        originating_media_timestamps.push_back(std::move(invalid_range));
+
+        std::vector<uint8_t> data =
+            media::mojom::SpeechRecognitionResult::Serialize(&invalid_result);
+        media::SpeechRecognitionResult output;
+        EXPECT_FALSE(media::mojom::SpeechRecognitionResult::Deserialize(
+            std::move(data), &output));
+      };
+
+  // `start` should always be before `end`
+  verify_serialization_round_trip_fails(
+      {.start = base::Seconds(10), .end = base::Seconds(5)});
+
+  // A 0 duration range is technically legal, but senders should have removed
+  // this range beforehand.
+  verify_serialization_round_trip_fails(
+      {.start = base::Seconds(10), .end = base::Seconds(10)});
+}
+
+TEST(SpeechRecognitionResultStructTraitsTest,
+     WithValidOriginatingMediaTimestamps) {
+  media::SpeechRecognitionResult invalid_result("hello world", true);
+  invalid_result.timing_information = media::TimingInformation();
+  invalid_result.timing_information->audio_start_time = kZeroTime;
+  invalid_result.timing_information->audio_end_time = base::Seconds(1);
+  invalid_result.timing_information->originating_media_timestamps =
+      std::vector<media::MediaTimestampRange>();
+  auto& originating_media_timestamps =
+      invalid_result.timing_information->originating_media_timestamps.value();
+
+  const media::MediaTimestampRange first_range{.start = base::Seconds(5),
+                                               .end = base::Seconds(10)};
+  // Overlapping ranges are allowed
+  const media::MediaTimestampRange second_range{.start = base::Seconds(6),
+                                                .end = base::Seconds(11)};
+  originating_media_timestamps.push_back(first_range);
+  originating_media_timestamps.push_back(second_range);
+
+  std::vector<uint8_t> data =
+      media::mojom::SpeechRecognitionResult::Serialize(&invalid_result);
+  media::SpeechRecognitionResult output;
+  EXPECT_TRUE(media::mojom::SpeechRecognitionResult::Deserialize(
+      std::move(data), &output));
+  const auto& media_timestamps =
+      output.timing_information->originating_media_timestamps.value();
+  EXPECT_EQ(media_timestamps.size(), 2u);
+  EXPECT_EQ(media_timestamps[0], first_range);
+  EXPECT_EQ(media_timestamps[1], second_range);
+}
+
 }  // namespace media
diff --git a/mojo/public/cpp/bindings/array_data_view.h b/mojo/public/cpp/bindings/array_data_view.h
index 5b022afd..718259e 100644
--- a/mojo/public/cpp/bindings/array_data_view.h
+++ b/mojo/public/cpp/bindings/array_data_view.h
@@ -70,7 +70,7 @@
 };
 
 template <typename T>
-  requires(!base::is_instantiation<std::optional, T>)
+  requires(!base::is_instantiation<T, std::optional>)
 class ArrayDataViewImpl<
     T,
     typename std::enable_if<
@@ -103,7 +103,7 @@
 };
 
 template <typename T>
-  requires(base::is_instantiation<std::optional, T>)
+  requires(base::is_instantiation<T, std::optional>)
 class ArrayDataViewImpl<
     T,
     typename std::enable_if<
diff --git a/mojo/public/cpp/bindings/lib/array_internal.h b/mojo/public/cpp/bindings/lib/array_internal.h
index f5f804b2..9c73510b 100644
--- a/mojo/public/cpp/bindings/lib/array_internal.h
+++ b/mojo/public/cpp/bindings/lib/array_internal.h
@@ -194,7 +194,7 @@
 // TODO(ffred): consider merging with the optional<bool> specialization using
 // if constexpr.
 template <typename T>
-  requires(base::is_instantiation<std::optional, T>)
+  requires(base::is_instantiation<T, std::optional>)
 struct ArrayDataTraits<T> {
   using StorageType = typename T::value_type;
 
diff --git a/mojo/public/cpp/bindings/lib/array_serialization.h b/mojo/public/cpp/bindings/lib/array_serialization.h
index fd26ce9..0f0be5d 100644
--- a/mojo/public/cpp/bindings/lib/array_serialization.h
+++ b/mojo/public/cpp/bindings/lib/array_serialization.h
@@ -163,7 +163,7 @@
 template <typename MojomType,
           typename MaybeConstUserType,
           typename UserTypeIterator>
-  requires(!base::is_instantiation<std::optional, typename MojomType::Element>)
+  requires(!base::is_instantiation<typename MojomType::Element, std::optional>)
 struct ArraySerializer<
     MojomType,
     MaybeConstUserType,
@@ -212,7 +212,7 @@
 template <typename MojomType,
           typename MaybeConstUserType,
           typename UserTypeIterator>
-  requires(base::is_instantiation<std::optional, typename MojomType::Element>)
+  requires(base::is_instantiation<typename MojomType::Element, std::optional>)
 struct ArraySerializer<
     MojomType,
     MaybeConstUserType,
diff --git a/mojo/public/cpp/bindings/lib/array_serialization_send_validation.h b/mojo/public/cpp/bindings/lib/array_serialization_send_validation.h
index dbe9943..17b23c5 100644
--- a/mojo/public/cpp/bindings/lib/array_serialization_send_validation.h
+++ b/mojo/public/cpp/bindings/lib/array_serialization_send_validation.h
@@ -74,7 +74,7 @@
           typename MaybeConstUserType,
           SendValidation send_validation,
           typename UserTypeIterator>
-  requires(!base::is_instantiation<std::optional, typename MojomType::Element>)
+  requires(!base::is_instantiation<typename MojomType::Element, std::optional>)
 struct SendValidationArraySerializer<
     MojomType,
     MaybeConstUserType,
@@ -121,7 +121,7 @@
           typename MaybeConstUserType,
           SendValidation send_validation,
           typename UserTypeIterator>
-  requires(base::is_instantiation<std::optional, typename MojomType::Element>)
+  requires(base::is_instantiation<typename MojomType::Element, std::optional>)
 struct SendValidationArraySerializer<
     MojomType,
     MaybeConstUserType,
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 5349ee4..d2ecebc 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -607,7 +607,6 @@
     "http/http_auth_multi_round_parse.h",
     "http/http_auth_preferences.cc",
     "http/http_auth_preferences.h",
-    "http/http_auth_scheme.cc",
     "http/http_auth_scheme.h",
     "http/http_basic_state.cc",
     "http/http_basic_state.h",
@@ -3511,6 +3510,7 @@
       "cookies/cookie_monster_perftest.cc",
       "disk_cache/disk_cache_perftest.cc",
       "extras/sqlite/sqlite_persistent_cookie_store_perftest.cc",
+      "http/http_request_headers_perftest.cc",
       "socket/udp_socket_perftest.cc",
       "spdy/spdy_http_utils_perftest.cc",
       "url_request/url_request_quic_perftest.cc",
diff --git a/net/base/upload_data_stream.cc b/net/base/upload_data_stream.cc
index 69c840b..8b4c183 100644
--- a/net/base/upload_data_stream.cc
+++ b/net/base/upload_data_stream.cc
@@ -70,6 +70,7 @@
                            CompletionOnceCallback callback) {
   DCHECK(!callback.is_null() || IsInMemory());
   DCHECK(initialized_successfully_);
+  CHECK(buf);
   DCHECK_GT(buf_len, 0);
 
   net_log_.BeginEvent(NetLogEventType::UPLOAD_DATA_STREAM_READ,
diff --git a/net/dns/host_resolver_manager.cc b/net/dns/host_resolver_manager.cc
index 644ae1d..181b1ec 100644
--- a/net/dns/host_resolver_manager.cc
+++ b/net/dns/host_resolver_manager.cc
@@ -801,7 +801,7 @@
   // `https_svcb_options_.enable` has precedence, so if enabled, ignore any
   // other related features.
   if (https_svcb_options_.enable && out_job_key.host.HasScheme()) {
-    static const char* const kSchemesForHttpsQuery[] = {
+    static constexpr std::string_view kSchemesForHttpsQuery[] = {
         url::kHttpScheme, url::kHttpsScheme, url::kWsScheme, url::kWssScheme};
     if (base::Contains(kSchemesForHttpsQuery, out_job_key.host.GetScheme())) {
       effective_types.Put(DnsQueryType::HTTPS);
diff --git a/net/http/http_auth_handler_factory.cc b/net/http/http_auth_handler_factory.cc
index c875ec1d..49ae267 100644
--- a/net/http/http_auth_handler_factory.cc
+++ b/net/http/http_auth_handler_factory.cc
@@ -4,6 +4,7 @@
 
 #include "net/http/http_auth_handler_factory.h"
 
+#include <array>
 #include <optional>
 #include <set>
 #include <string_view>
@@ -54,6 +55,15 @@
   return dict;
 }
 
+// Since there are at most 4 schemes, a linear search is faster than a binary
+// search because it can cheaply discard strings when the length doesn't match.
+constexpr auto kDefaultAuthSchemes =
+    std::to_array<std::string_view>({kBasicAuthScheme, kDigestAuthScheme,
+#if BUILDFLAG(USE_KERBEROS) && !BUILDFLAG(IS_ANDROID)
+                                     kNegotiateAuthScheme,
+#endif
+                                     kNtlmAuthScheme});
+
 }  // namespace
 
 int HttpAuthHandlerFactory::CreateAuthHandlerFromString(
@@ -249,11 +259,10 @@
 
 bool HttpAuthHandlerRegistryFactory::IsSchemeAllowed(
     const std::string& scheme) const {
-  const std::set<std::string>& allowed_schemes =
-      http_auth_preferences() && http_auth_preferences()->allowed_schemes()
-          ? *http_auth_preferences()->allowed_schemes()
-          : default_auth_schemes_;
-  return allowed_schemes.find(scheme) != allowed_schemes.end();
+  if (http_auth_preferences() && http_auth_preferences()->allowed_schemes()) {
+    return base::Contains(*http_auth_preferences()->allowed_schemes(), scheme);
+  }
+  return base::Contains(kDefaultAuthSchemes, scheme);
 }
 
 #if BUILDFLAG(USE_KERBEROS) && !BUILDFLAG(IS_ANDROID) && BUILDFLAG(IS_POSIX)
diff --git a/net/http/http_auth_handler_factory.h b/net/http/http_auth_handler_factory.h
index 0d174da1..f95e38ee 100644
--- a/net/http/http_auth_handler_factory.h
+++ b/net/http/http_auth_handler_factory.h
@@ -259,13 +259,6 @@
 
   using FactoryMap =
       std::map<std::string, std::unique_ptr<HttpAuthHandlerFactory>>;
-  std::set<std::string> default_auth_schemes_ {
-    kBasicAuthScheme, kDigestAuthScheme,
-#if BUILDFLAG(USE_KERBEROS) && !BUILDFLAG(IS_ANDROID)
-        kNegotiateAuthScheme,
-#endif
-        kNtlmAuthScheme
-  };
   FactoryMap factory_map_;
 };
 
diff --git a/net/http/http_auth_preferences.h b/net/http/http_auth_preferences.h
index 88f5341..4727f46c 100644
--- a/net/http/http_auth_preferences.h
+++ b/net/http/http_auth_preferences.h
@@ -7,9 +7,9 @@
 
 #include <memory>
 #include <optional>
-#include <set>
 #include <string>
 
+#include "base/containers/flat_set.h"
 #include "base/functional/callback.h"
 #include "build/build_config.h"
 #include "net/base/net_export.h"
@@ -91,12 +91,12 @@
   }
 #endif  // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
 
-  const std::optional<std::set<std::string>>& allowed_schemes() const {
+  const std::optional<base::flat_set<std::string>>& allowed_schemes() const {
     return allowed_schemes_;
   }
 
   void set_allowed_schemes(
-      const std::optional<std::set<std::string>>& allowed_schemes) {
+      const std::optional<base::flat_set<std::string>>& allowed_schemes) {
     allowed_schemes_ = allowed_schemes;
   }
 
@@ -140,7 +140,7 @@
   bool allow_gssapi_library_load_ = true;
 #endif  // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
 
-  std::optional<std::set<std::string>> allowed_schemes_;
+  std::optional<base::flat_set<std::string>> allowed_schemes_;
   std::unique_ptr<URLSecurityManager> security_manager_;
   base::RepeatingCallback<bool(const url::SchemeHostPort&)>
       http_auth_scheme_filter_ =
diff --git a/net/http/http_auth_scheme.cc b/net/http/http_auth_scheme.cc
deleted file mode 100644
index 040f5b0..0000000
--- a/net/http/http_auth_scheme.cc
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2015 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/http/http_auth_scheme.h"
-
-namespace net {
-const char kBasicAuthScheme[] = "basic";
-const char kDigestAuthScheme[] = "digest";
-const char kNtlmAuthScheme[] = "ntlm";
-const char kNegotiateAuthScheme[] = "negotiate";
-const char kSpdyProxyAuthScheme[] = "spdyproxy";
-const char kMockAuthScheme[] = "mock";
-}  // namespace net
diff --git a/net/http/http_auth_scheme.h b/net/http/http_auth_scheme.h
index 99ec247c..78e31a8a0 100644
--- a/net/http/http_auth_scheme.h
+++ b/net/http/http_auth_scheme.h
@@ -5,15 +5,13 @@
 #ifndef NET_HTTP_HTTP_AUTH_SCHEME_H_
 #define NET_HTTP_HTTP_AUTH_SCHEME_H_
 
-#include "net/base/net_export.h"
-
 namespace net {
-NET_EXPORT extern const char kBasicAuthScheme[];
-NET_EXPORT extern const char kDigestAuthScheme[];
-NET_EXPORT extern const char kNtlmAuthScheme[];
-NET_EXPORT extern const char kNegotiateAuthScheme[];
-NET_EXPORT extern const char kSpdyProxyAuthScheme[];
-NET_EXPORT extern const char kMockAuthScheme[];
+inline constexpr char kBasicAuthScheme[] = "basic";
+inline constexpr char kDigestAuthScheme[] = "digest";
+inline constexpr char kNtlmAuthScheme[] = "ntlm";
+inline constexpr char kNegotiateAuthScheme[] = "negotiate";
+inline constexpr char kSpdyProxyAuthScheme[] = "spdyproxy";
+inline constexpr char kMockAuthScheme[] = "mock";
 }  // namespace net
 
 #endif  // NET_HTTP_HTTP_AUTH_SCHEME_H_
diff --git a/net/http/http_proxy_client_socket_fuzzer.cc b/net/http/http_proxy_client_socket_fuzzer.cc
index 83471207..a830679 100644
--- a/net/http/http_proxy_client_socket_fuzzer.cc
+++ b/net/http/http_proxy_client_socket_fuzzer.cc
@@ -4,15 +4,15 @@
 
 #include "net/http/http_proxy_client_socket.h"
 
+#include <fuzzer/FuzzedDataProvider.h>
 #include <stddef.h>
 #include <stdint.h>
 
-#include <fuzzer/FuzzedDataProvider.h>
-
 #include <memory>
 #include <string>
 
 #include "base/check_op.h"
+#include "base/containers/flat_set.h"
 #include "base/strings/utf_string_conversions.h"
 #include "net/base/address_list.h"
 #include "net/base/auth.h"
@@ -54,8 +54,8 @@
   net::HttpAuthCache auth_cache(
       false /* key_server_entries_by_network_anonymization_key */);
   net::HttpAuthPreferences http_auth_preferences;
-  http_auth_preferences.set_allowed_schemes(
-      std::set<std::string>{net::kBasicAuthScheme, net::kDigestAuthScheme});
+  http_auth_preferences.set_allowed_schemes(base::flat_set<std::string>{
+      net::kBasicAuthScheme, net::kDigestAuthScheme});
   net::HttpAuthHandlerRegistryFactory auth_handler_factory(
       &http_auth_preferences);
 
diff --git a/net/http/http_request_headers.cc b/net/http/http_request_headers.cc
index 06e6b1a..b292b19 100644
--- a/net/http/http_request_headers.cc
+++ b/net/http/http_request_headers.cc
@@ -21,6 +21,7 @@
 #include "net/http/http_util.h"
 #include "net/log/net_log_capture_mode.h"
 #include "net/log/net_log_values.h"
+#include "third_party/abseil-cpp/absl/container/inlined_vector.h"
 
 namespace net {
 
@@ -213,13 +214,22 @@
 }
 
 std::string HttpRequestHeaders::ToString() const {
-  std::string output;
+  static constexpr std::string_view kColon = ": ";
+  static constexpr std::string_view kCrNl = "\r\n";
+
+  // As of January 2024, 99% of of HttpRequestHeaders objects had 27 headers or
+  // less. Allow space for 128 string pieces without heap allocation as it is a
+  // nice round number.
+  absl::InlinedVector<std::string_view, 128> pieces;
+  const size_t expected_size = headers_.size() * 4 + 1;
+
+  pieces.reserve(expected_size);
   for (const auto& header : headers_) {
-    base::StringAppendF(&output, "%s: %s\r\n", header.key.c_str(),
-                        header.value.c_str());
+    pieces.insert(pieces.end(), {header.key, kColon, header.value, kCrNl});
   }
-  output.append("\r\n");
-  return output;
+  pieces.push_back(kCrNl);
+  CHECK_EQ(pieces.size(), expected_size);
+  return base::StrCat(pieces);
 }
 
 base::Value::Dict HttpRequestHeaders::NetLogParams(
diff --git a/net/http/http_request_headers_perftest.cc b/net/http/http_request_headers_perftest.cc
new file mode 100644
index 0000000..b7fa9444
--- /dev/null
+++ b/net/http/http_request_headers_perftest.cc
@@ -0,0 +1,55 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/http/http_request_headers.h"
+
+#include <string>
+
+#include "third_party/google_benchmark/src/include/benchmark/benchmark.h"
+
+namespace net {
+
+namespace {
+
+void BM_HttpRequestHeadersToString(::benchmark::State& state) {
+  HttpRequestHeaders http_request_headers;
+  http_request_headers.SetHeader(
+      "Accept",
+      "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/"
+      "webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7");
+  http_request_headers.SetHeader("Accept-Encoding", "gzip, deflate, br");
+  http_request_headers.SetHeader("Accept-Language", "en-GB,en;q=0.9");
+  http_request_headers.SetHeader("Cache-Control", "max-age=0");
+  http_request_headers.SetHeader(
+      "Cookie",
+      "WMF-Last-Access=xxxxxxxxxxx; WMF-Last-Access-Global=xxxxxxxxxxx; "
+      "GeoIP=xxxxxxxxxxxxxxxxxxxxxxxxxxx; NetworkProbeLimit=0.001; "
+      "enwikimwuser-sessionId=xxxxxxxxxxxxxxxxxxxx");
+  http_request_headers.SetHeader(
+      "Sec-Ch-Ua",
+      "\"Google Chrome\";v=\"117\", \"Not;A=Brand\";v=\"8\", "
+      "\"Chromium\";v=\"117\"");
+  http_request_headers.SetHeader("Sec-Ch-Ua-Mobile", "?0");
+  http_request_headers.SetHeader("Sec-Ch-Ua-Platform", "\"Linux\"");
+  http_request_headers.SetHeader("Sec-Fetch-Dest", "document");
+  http_request_headers.SetHeader("Sec-Fetch-Mode", "navigate");
+  http_request_headers.SetHeader("Sec-Fetch-Site", "none");
+  http_request_headers.SetHeader("Sec-Fetch-User", "?1");
+  http_request_headers.SetHeader("Upgrade-Insecure-Requests", "1");
+  http_request_headers.SetHeader(
+      "User-Agent",
+      "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) "
+      "Chrome/117.0.0.0 Safari/537.36");
+
+  for (auto _ : state) {
+    std::string as_string = http_request_headers.ToString();
+    ::benchmark::DoNotOptimize(as_string);
+  }
+}
+
+BENCHMARK(BM_HttpRequestHeadersToString)->MinWarmUpTime(1.0);
+
+}  // namespace
+
+}  // namespace net
diff --git a/net/http/http_stream_pool_attempt_manager.cc b/net/http/http_stream_pool_attempt_manager.cc
index c78b2b8..5a0cfd6 100644
--- a/net/http/http_stream_pool_attempt_manager.cc
+++ b/net/http/http_stream_pool_attempt_manager.cc
@@ -195,8 +195,8 @@
 }
 
 HttpStreamPool::AttemptManager::~AttemptManager() {
-  base::UmaHistogramTimes("Net.HttpStreamPool.AttemptManagerAliveTime",
-                          base::TimeTicks::Now() - created_time_);
+  base::UmaHistogramLongTimes100("Net.HttpStreamPool.AttemptManagerAliveTime2",
+                                 base::TimeTicks::Now() - created_time_);
   net_log().EndEvent(NetLogEventType::HTTP_STREAM_POOL_ATTEMPT_MANAGER_ALIVE);
   group_->net_log().AddEventReferencingSource(
       NetLogEventType::HTTP_STREAM_POOL_GROUP_ATTEMPT_MANAGER_DESTROYED,
@@ -207,7 +207,7 @@
 void HttpStreamPool::AttemptManager::RequestStream(Job* job) {
   CHECK(availability_state_ == AvailabilityState::kAvailable);
 
-  TRACE_EVENT_INSTANT("net.stream", "AttemptManager::StartJob", track_,
+  TRACE_EVENT_INSTANT("net.stream", "AttemptManager::RequestStream", track_,
                       NetLogWithSourceToFlow(job->request_net_log()));
 
   net_log_.AddEvent(
@@ -849,7 +849,7 @@
       NetLogEventType::HTTP_STREAM_POOL_ATTEMPT_MANAGER_QUIC_ATTEMPT_COMPLETED,
       [&] {
         base::Value::Dict dict = GetStatesAsNetLogParams();
-        dict.Set("result", ErrorToString(rv));
+        dict.Set("result", rv);
         if (net_error_details_.quic_connection_error != quic::QUIC_NO_ERROR) {
           dict.Set("quic_error", quic::QuicErrorCodeToString(
                                      net_error_details_.quic_connection_error));
@@ -936,6 +936,15 @@
            CanAttemptResultToString(CanAttemptConnection()));
   dict.Set("service_endpoint_request_finished",
            service_endpoint_request_finished_);
+  if (service_endpoint_request_ &&
+      !service_endpoint_request_->GetEndpointResults().empty()) {
+    base::Value::List service_endpoints;
+    for (const auto& endpoint :
+         service_endpoint_request_->GetEndpointResults()) {
+      service_endpoints.Append(endpoint.ToValue());
+    }
+    dict.Set("service_endpoints", std::move(service_endpoints));
+  }
   dict.Set("tcp_based_attempt_state",
            TcpBasedAttemptStateToString(tcp_based_attempt_state_));
   dict.Set("tcp_based_attempt_delay_ms",
@@ -996,7 +1005,7 @@
   dict.Set("enable_alternative_services", IsAlternativeServiceEnabled());
   dict.Set("quic_attempt_alive", !!quic_attempt_);
   if (quic_attempt_result_.has_value()) {
-    dict.Set("quic_attempt_result", ErrorToString(*quic_attempt_result_));
+    dict.Set("quic_attempt_result", *quic_attempt_result_);
   }
   return dict;
 }
diff --git a/net/http/http_stream_pool_job.cc b/net/http/http_stream_pool_job.cc
index 1991f34..9bc9b8d 100644
--- a/net/http/http_stream_pool_job.cc
+++ b/net/http/http_stream_pool_job.cc
@@ -123,15 +123,15 @@
   // completed.
   if (result_.has_value()) {
     constexpr std::string_view kCompleteTimeHistogramName =
-        "Net.HttpStreamPool.JobCompleteTime2.";
+        "Net.HttpStreamPool.JobCompleteTime3.";
     base::TimeDelta complete_time = base::TimeTicks::Now() - create_time_;
     if (*result_ == OK) {
       const std::string_view protocol = NegotiatedProtocolToHistogramSuffix(
           negotiated_protocol_.value_or(NextProto::kProtoUnknown));
-      base::UmaHistogramTimes(
+      base::UmaHistogramLongTimes100(
           base::StrCat({kCompleteTimeHistogramName, protocol}), complete_time);
     } else {
-      base::UmaHistogramTimes(
+      base::UmaHistogramLongTimes100(
           base::StrCat({kCompleteTimeHistogramName, "Failure"}), complete_time);
       base::UmaHistogramSparse("Net.HttpStreamPool.JobErrorCode", -*result_);
     }
diff --git a/net/http/http_stream_pool_tcp_based_attempt.cc b/net/http/http_stream_pool_tcp_based_attempt.cc
index 9665787..5b4091b 100644
--- a/net/http/http_stream_pool_tcp_based_attempt.cc
+++ b/net/http/http_stream_pool_tcp_based_attempt.cc
@@ -98,8 +98,8 @@
 
 HttpStreamPool::TcpBasedAttempt::~TcpBasedAttempt() {
   base::TimeDelta elapsed = base::TimeTicks::Now() - start_time_;
-  base::UmaHistogramTimes(
-      base::StrCat({"Net.HttpStreamPool.TcpBasedAttemptTime.",
+  base::UmaHistogramMediumTimes(
+      base::StrCat({"Net.HttpStreamPool.TcpBasedAttemptTime2.",
                     GetResultHistogramSuffix(result_)}),
       elapsed);
 
@@ -115,9 +115,9 @@
             {"Net.HttpStreamPool.TcpBasedAttemptCanceledInitialAttemptState.",
              suffix}),
         *manager_->initial_attempt_state());
-    base::UmaHistogramTimes(
+    base::UmaHistogramLongTimes100(
         base::StrCat(
-            {"Net.HttpStreamPool.TcpBasedAttemptCanceledTime.", suffix}),
+            {"Net.HttpStreamPool.TcpBasedAttemptCanceledTime2.", suffix}),
         elapsed);
   }
 
@@ -140,6 +140,7 @@
   manager_->net_log().AddEvent(
       NetLogEventType::HTTP_STREAM_POOL_TCP_BASED_ATTEMPT_START, [&] {
         base::Value::Dict dict = manager_->GetStatesAsNetLogParams();
+        dict.Set("ip_endpoint", ip_endpoint().ToString());
         attempt()->net_log().source().AddToEventParameters(dict);
         return dict;
       });
@@ -198,8 +199,9 @@
   }
 
   CHECK(!ssl_config_wait_start_time_.is_null());
-  base::UmaHistogramTimes("Net.HttpStreamPool.TcpBasedAttemptSSLConfigWaitTime",
-                          base::TimeTicks::Now() - ssl_config_wait_start_time_);
+  base::UmaHistogramMediumTimes(
+      "Net.HttpStreamPool.TcpBasedAttemptSSLConfigWaitTime2",
+      base::TimeTicks::Now() - ssl_config_wait_start_time_);
 
   if (!is_slow_ && !slow_timer_.IsRunning()) {
     // Resume the slow timer as `attempt_` will start a TLS handshake.
diff --git a/net/third_party/quiche/src b/net/third_party/quiche/src
index 9194c7e..611b64f 160000
--- a/net/third_party/quiche/src
+++ b/net/third_party/quiche/src
@@ -1 +1 @@
-Subproject commit 9194c7eec5a1e6ac9034a8ee7fd18804fb9a7125
+Subproject commit 611b64ffd0f17e96d31ff1d3e52ff1df0c9219f8
diff --git a/net/third_party/uri_template/uri_template.cc b/net/third_party/uri_template/uri_template.cc
index 754249e..c8929d9 100644
--- a/net/third_party/uri_template/uri_template.cc
+++ b/net/third_party/uri_template/uri_template.cc
@@ -26,6 +26,7 @@
 
 #include <set>
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include "base/strings/escape.h"
@@ -41,8 +42,8 @@
 // the expanded url.
 struct UriTemplateConfig {
  public:
-  UriTemplateConfig(const char* prefix,
-                    const char* joiner,
+  UriTemplateConfig(std::string_view prefix,
+                    std::string_view joiner,
                     bool requires_variable_assignment,
                     bool allow_reserved_expansion,
                     bool no_variable_assignment_if_empty = false)
@@ -56,7 +57,7 @@
                    const string& value,
                    bool use_prefix,
                    string* target) const {
-    string joiner = use_prefix ? prefix_ : joiner_;
+    const std::string& joiner = use_prefix ? prefix_ : joiner_;
     if (requires_variable_assignment_) {
       if (value.empty() && no_variable_assignment_if_empty_) {
         target->append(joiner + EscapedValue(variable));
@@ -81,8 +82,8 @@
     return escaped;
   }
 
-  const char* prefix_;
-  const char* joiner_;
+  std::string prefix_;
+  std::string joiner_;
   bool requires_variable_assignment_;
   bool no_variable_assignment_if_empty_;
   bool allow_reserved_expansion_;
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 96cb7af5..4126605 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -112,6 +112,8 @@
 #include "net/device_bound_sessions/session_service.h"
 #endif  // BUILDFLAG(ENABLE_DEVICE_BOUND_SESSIONS)
 
+namespace net {
+
 namespace {
 
 // These values are persisted to logs. Entries should not be renumbered and
@@ -129,11 +131,11 @@
 }
 
 base::Value::Dict FirstPartySetMetadataNetLogParams(
-    const net::FirstPartySetMetadata& first_party_set_metadata,
+    const FirstPartySetMetadata& first_party_set_metadata,
     const int64_t* const fps_cache_filter) {
   base::Value::Dict dict;
   auto entry_or_empty =
-      [](const std::optional<net::FirstPartySetEntry>& entry) -> std::string {
+      [](const std::optional<FirstPartySetEntry>& entry) -> std::string {
     return entry.has_value() ? entry->GetDebugString() : "none";
   };
 
@@ -151,13 +153,13 @@
     const std::string& cookie_name,
     const std::string& cookie_domain,
     const std::string& cookie_path,
-    const std::optional<net::CookiePartitionKey>& partition_key,
-    const net::CookieInclusionStatus& status,
-    net::NetLogCaptureMode capture_mode) {
+    const std::optional<CookiePartitionKey>& partition_key,
+    const CookieInclusionStatus& status,
+    NetLogCaptureMode capture_mode) {
   base::Value::Dict dict;
   dict.Set("operation", operation);
   dict.Set("status", status.GetDebugString());
-  if (net::NetLogCaptureIncludesSensitive(capture_mode)) {
+  if (NetLogCaptureIncludesSensitive(capture_mode)) {
     if (!cookie_name.empty())
       dict.Set("name", cookie_name);
     if (!cookie_domain.empty())
@@ -170,9 +172,9 @@
   // does not have the ability to influence the key's value.
   std::string partition_key_str;
   if (partition_key.has_value()) {
-    base::expected<net::CookiePartitionKey::SerializedCookiePartitionKey,
+    base::expected<CookiePartitionKey::SerializedCookiePartitionKey,
                    std::string>
-        serialized = net::CookiePartitionKey::Serialize(partition_key);
+        serialized = CookiePartitionKey::Serialize(partition_key);
     partition_key_str = serialized.has_value()
                             ? serialized.value().GetDebugString()
                             : serialized.error();
@@ -187,7 +189,7 @@
 // which is expected to be ordered with the leaf cert first and the root cert
 // last. This complements the per-verification histogram
 // Net.Certificate.TrustAnchor.Verify
-void LogTrustAnchor(const net::HashValueVector& spki_hashes) {
+void LogTrustAnchor(const HashValueVector& spki_hashes) {
   // Don't record metrics if there are no hashes; this is true if the HTTP
   // load did not come from an active network connection, such as the disk
   // cache or a synthesized response.
@@ -196,28 +198,28 @@
 
   int32_t id = 0;
   for (const auto& hash : spki_hashes) {
-    id = net::GetNetTrustAnchorHistogramIdForSPKI(hash);
+    id = GetNetTrustAnchorHistogramIdForSPKI(hash);
     if (id != 0)
       break;
   }
   base::UmaHistogramSparse("Net.Certificate.TrustAnchor.Request", id);
 }
 
-net::CookieOptions CreateCookieOptions(
-    net::CookieOptions::SameSiteCookieContext same_site_context) {
-  net::CookieOptions options;
+CookieOptions CreateCookieOptions(
+    CookieOptions::SameSiteCookieContext same_site_context) {
+  CookieOptions options;
   options.set_return_excluded_cookies();
   options.set_include_httponly();
   options.set_same_site_cookie_context(same_site_context);
   return options;
 }
 
-bool IsTLS13OverTCP(const net::HttpResponseInfo& response_info) {
+bool IsTLS13OverTCP(const HttpResponseInfo& response_info) {
   // Although IETF QUIC also uses TLS 1.3, our QUIC connections report
   // SSL_CONNECTION_VERSION_QUIC.
-  return net::SSLConnectionStatusToVersion(
+  return SSLConnectionStatusToVersion(
              response_info.ssl_info.connection_status) ==
-         net::SSL_CONNECTION_VERSION_TLS1_3;
+         SSL_CONNECTION_VERSION_TLS1_3;
 }
 
 GURL UpgradeSchemeToCryptographic(const GURL& insecure_url) {
@@ -247,19 +249,19 @@
   kMaxValue = kZstd,
 };
 
-ContentEncodingType ToContentEncodingType(net::SourceStreamType type) {
+ContentEncodingType ToContentEncodingType(SourceStreamType type) {
   switch (type) {
-    case net::SourceStreamType::kBrotli:
+    case SourceStreamType::kBrotli:
       return ContentEncodingType::kBrotli;
-    case net::SourceStreamType::kDeflate:
+    case SourceStreamType::kDeflate:
       return ContentEncodingType::kDeflate;
-    case net::SourceStreamType::kGzip:
+    case SourceStreamType::kGzip:
       return ContentEncodingType::kGZip;
-    case net::SourceStreamType::kZstd:
+    case SourceStreamType::kZstd:
       return ContentEncodingType::kZstd;
-    case net::SourceStreamType::kUnknown:
+    case SourceStreamType::kUnknown:
       return ContentEncodingType::kUnknown;
-    case net::SourceStreamType::kNone:
+    case SourceStreamType::kNone:
       return ContentEncodingType::kUnknown;
   }
 }
@@ -299,34 +301,33 @@
 // LINT.ThenChange(//tools/metrics/histograms/metadata/enums.xml:HttpRequestSSLUpgradeDecision)
 
 HttpRequestSSLUpgradeDecision GetMetricForSSLUpgradeDecision(
-    net::SSLUpgradeDecision upgrade_decision,
+    SSLUpgradeDecision upgrade_decision,
     bool is_secure) {
   switch (upgrade_decision) {
-    case net::SSLUpgradeDecision::kNoUpgrade:
+    case SSLUpgradeDecision::kNoUpgrade:
       return is_secure ? HttpRequestSSLUpgradeDecision::kSSLNoUpgrade
                        : HttpRequestSSLUpgradeDecision::kInsecureNoUpgrade;
-    case net::SSLUpgradeDecision::kStaticUpgrade:
+    case SSLUpgradeDecision::kStaticUpgrade:
       return is_secure ? HttpRequestSSLUpgradeDecision::kSSLStaticUpgrade
                        : HttpRequestSSLUpgradeDecision::kInsecureStaticUpgrade;
-    case net::SSLUpgradeDecision::kDynamicUpgrade:
+    case SSLUpgradeDecision::kDynamicUpgrade:
       return is_secure ? HttpRequestSSLUpgradeDecision::kSSLDynamicUpgrade
                        : HttpRequestSSLUpgradeDecision::kInsecureDynamicUpgrade;
   }
   NOTREACHED();
 }
 
-void RecordSTSHistograms(net::SSLUpgradeDecision upgrade_decision,
+void RecordSTSHistograms(SSLUpgradeDecision upgrade_decision,
                          bool is_secure,
                          int load_flags) {
   // Embrace the layering violation and only record the histogram for main frame
   // navigations. It's possible to record this outside of net/, but the code is
   // a lot more complicated, and while this flag is deprecated, there are no
   // current plans to remove it. See crbug.com/516499 .
-  if (!(load_flags & net::LOAD_MAIN_FRAME_DEPRECATED)) {
+  if (!(load_flags & LOAD_MAIN_FRAME_DEPRECATED)) {
     return;
   }
-  const bool sts_enabled =
-      upgrade_decision != net::SSLUpgradeDecision::kNoUpgrade;
+  const bool sts_enabled = upgrade_decision != SSLUpgradeDecision::kNoUpgrade;
   HttpRequestStsState sts_state = HttpRequestStsState::kUnknown;
   if (is_secure) {
     sts_state = (sts_enabled ? HttpRequestStsState::kProtectedHttps
@@ -342,9 +343,19 @@
       GetMetricForSSLUpgradeDecision(upgrade_decision, is_secure));
 }
 
-}  // namespace
+bool ClearSiteDataHeaderContainsCookiesOrWildcard(
+    const HttpResponseHeaders* headers) {
+  size_t iter = 0;
+  while (auto maybe_token =
+             headers->EnumerateHeader(&iter, kClearSiteDataHeader)) {
+    if (maybe_token == kDatatypeCookies || maybe_token == kDatatypeWildcard) {
+      return true;
+    }
+  }
+  return false;
+}
 
-namespace net {
+}  // namespace
 
 std::unique_ptr<URLRequestJob> URLRequestHttpJob::Create(URLRequest* request) {
   const GURL& url = request->url();
@@ -370,8 +381,8 @@
     // the request is in no-credential mode so that the http site can't read
     // or set cookies which are shared across http/https, then skip the
     // upgrade.
-    if (((request->load_flags() & net::LOAD_SHOULD_BYPASS_HSTS) ==
-         net::LOAD_SHOULD_BYPASS_HSTS)) {
+    if (((request->load_flags() & LOAD_SHOULD_BYPASS_HSTS) ==
+         LOAD_SHOULD_BYPASS_HSTS)) {
       CHECK(request->allow_credentials() == false);
     } else {
       // Check for HSTS upgrade.
@@ -441,7 +452,7 @@
   request_info_.frame_origin = request_->isolation_info().frame_origin();
   request_info_.is_subframe_document_resource =
       request_->isolation_info().request_type() ==
-      net::IsolationInfo::RequestType::kSubFrame;
+      IsolationInfo::RequestType::kSubFrame;
   request_info_.is_main_frame_navigation =
       request_->isolation_info().IsMainFrameRequest();
   request_info_.initiator = request_->initiator();
@@ -449,7 +460,7 @@
   request_info_.priority_incremental = request_->priority_incremental();
   request_info_.secure_dns_policy = request_->secure_dns_policy();
   request_info_.traffic_annotation =
-      net::MutableNetworkTrafficAnnotationTag(request_->traffic_annotation());
+      MutableNetworkTrafficAnnotationTag(request_->traffic_annotation());
   request_info_.socket_tag = request_->socket_tag();
   request_info_.idempotency = request_->GetIdempotency();
 #if BUILDFLAG(ENABLE_REPORTING)
@@ -805,7 +816,7 @@
           request_->isolation_info().request_type() ||
       request_->force_main_frame_for_same_site_cookies();
   CookieOptions::SameSiteCookieContext same_site_context =
-      net::cookie_util::ComputeSameSiteContextForRequest(
+      cookie_util::ComputeSameSiteContextForRequest(
           request_->method(), request_->url_chain(),
           request_->site_for_cookies(), request_->initiator(),
           is_main_frame_navigation, force_ignore_site_for_cookies);
@@ -868,25 +879,25 @@
     // is iterated over. Get metrics for every cookie which is included.
     for (const auto& c : maybe_included_cookies) {
       bool request_is_secure = request_->url().SchemeIsCryptographic();
-      net::CookieSourceScheme cookie_scheme = c.cookie.SourceScheme();
+      CookieSourceScheme cookie_scheme = c.cookie.SourceScheme();
       CookieRequestScheme cookie_request_schemes;
 
       switch (cookie_scheme) {
-        case net::CookieSourceScheme::kSecure:
+        case CookieSourceScheme::kSecure:
           cookie_request_schemes =
               request_is_secure
                   ? CookieRequestScheme::kSecureSetSecureRequest
                   : CookieRequestScheme::kSecureSetNonsecureRequest;
           break;
 
-        case net::CookieSourceScheme::kNonSecure:
+        case CookieSourceScheme::kNonSecure:
           cookie_request_schemes =
               request_is_secure
                   ? CookieRequestScheme::kNonsecureSetSecureRequest
                   : CookieRequestScheme::kNonsecureSetNonsecureRequest;
           break;
 
-        case net::CookieSourceScheme::kUnset:
+        case CookieSourceScheme::kUnset:
           cookie_request_schemes = CookieRequestScheme::kUnsetCookieScheme;
           break;
       }
@@ -1033,19 +1044,8 @@
 
   // If we're clearing the cookies as part of a clear-site-data header we must
   // not also write new ones in the same response.
-  bool clear_site_data_prevents_cookies_from_being_stored = false;
-  std::string clear_site_data_header =
-      headers->GetNormalizedHeader(kClearSiteDataHeader)
-          .value_or(std::string());
-  std::vector<std::string> clear_site_data_types =
-      ClearSiteDataHeaderContents(clear_site_data_header);
-  std::set<std::string> clear_site_data_set(clear_site_data_types.begin(),
-                                            clear_site_data_types.end());
-  if (clear_site_data_set.find(kDatatypeCookies) != clear_site_data_set.end() ||
-      clear_site_data_set.find(kDatatypeWildcard) !=
-          clear_site_data_set.end()) {
-    clear_site_data_prevents_cookies_from_being_stored = true;
-  }
+  bool clear_site_data_prevents_cookies_from_being_stored =
+      ClearSiteDataHeaderContainsCookiesOrWildcard(headers);
 
   std::optional<base::Time> server_time = GetResponseHeaders()->GetDateValue();
 
@@ -1061,7 +1061,7 @@
           request_->isolation_info().request_type() ||
       request_->force_main_frame_for_same_site_cookies();
   CookieOptions::SameSiteCookieContext same_site_context =
-      net::cookie_util::ComputeSameSiteContextForResponse(
+      cookie_util::ComputeSameSiteContextForResponse(
           request_->url_chain(), request_->site_for_cookies(),
           request_->initiator(), is_main_frame_navigation,
           force_ignore_site_for_cookies);
@@ -1090,9 +1090,9 @@
 
     num_cookie_lines_left_++;
 
-    std::unique_ptr<CanonicalCookie> cookie = net::CanonicalCookie::Create(
+    std::unique_ptr<CanonicalCookie> cookie = CanonicalCookie::Create(
         request_->url(), cookie_string, base::Time::Now(), server_time,
-        request_->cookie_partition_key(), net::CookieSourceType::kHTTP,
+        request_->cookie_partition_key(), CookieSourceType::kHTTP,
         &returned_status);
 
     std::optional<CanonicalCookie> cookie_to_return = std::nullopt;
@@ -1110,8 +1110,7 @@
       // in this case.
       if (returned_status.IsInclude()) {
         returned_status.AddExclusionReason(
-            net::CookieInclusionStatus::ExclusionReason::
-                EXCLUDE_USER_PREFERENCES);
+            CookieInclusionStatus::ExclusionReason::EXCLUDE_USER_PREFERENCES);
       }
     }
     if (clear_site_data_prevents_cookies_from_being_stored) {
@@ -1229,7 +1228,7 @@
     return;
 
   // Don't accept HSTS headers for localhost. (crbug.com/41251622)
-  if (net::IsLocalHostname(request_info_.url.host()) &&
+  if (IsLocalHostname(request_info_.url.host()) &&
       base::FeatureList::IsEnabled(features::kIgnoreHSTSForLocalhost)) {
     return;
   }
@@ -1469,7 +1468,7 @@
 }
 
 void URLRequestHttpJob::GetClientSideContentDecodingTypes(
-    std::vector<net::SourceStreamType>* types) const {
+    std::vector<SourceStreamType>* types) const {
   CHECK(types);
   *types = client_side_content_decoding_types_;
 }
@@ -2020,7 +2019,7 @@
       }
 
       auto& proxy_chain = response_info_->proxy_chain;
-      bool direct_only = net::features::kIpPrivacyDirectOnly.Get();
+      bool direct_only = features::kIpPrivacyDirectOnly.Get();
       if (proxy_chain.is_for_ip_protection()) {
         base::UmaHistogramTimes("Net.HttpJob.IpProtection.TotalTimeNotCached2",
                                 total_time);
diff --git a/pdf/pdf_view_web_plugin.cc b/pdf/pdf_view_web_plugin.cc
index 50236408..6d932090 100644
--- a/pdf/pdf_view_web_plugin.cc
+++ b/pdf/pdf_view_web_plugin.cc
@@ -143,14 +143,6 @@
 
 constexpr base::TimeDelta kFindResultCooldown = base::Milliseconds(100);
 
-#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
-// This constant should have the same value as the one in
-// `pdf_view_web_plugin_unittest.cc`.
-// LINT.IfChange(searchify_state_propagation_delay)
-constexpr base::TimeDelta kSearchifyStatePropagationDelay = base::Seconds(1);
-// LINT.ThenChange(//pdf/pdf_view_web_plugin_unittest.cc:searchify_state_propagation_delay)
-#endif
-
 constexpr std::string_view kChromeExtensionHost =
     "chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/";
 
@@ -1549,48 +1541,52 @@
 
 #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
 void PdfViewWebPlugin::OnSearchifyStateChange(bool busy) {
-  if (!busy) {
-    if (show_searchify_in_progress_) {
-      show_searchify_in_progress_ = false;
-      // The UI is asked to hide the progress indicator with 1s delay, so that
-      // when the OCR process finishes in less than 1s, the indicator would not
-      // flicker.
-      base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
+  switch (searchify_state_) {
+    case SearchifyState::kNotStarted:
+      // Expected to be called only to say searchify started.
+      CHECK(busy);
+      pdf_host_->OnSearchifyStarted();
+      searchify_state_ = SearchifyState::kStarted;
+      break;
+
+    case SearchifyState::kStarted:
+      // Expected to be called only to say searchify stopped.
+      CHECK(!busy);
+      searchify_state_ = SearchifyState::kStopped;
+      break;
+
+    case SearchifyState::kShowingInProgress:
+      // Expected to be called only to say searchify stopped.
+      CHECK(!busy);
+      // Executing the script directly may cause a crash in blink as it might be
+      // during layout change, hence posting it (crbug.com/401142034).
+      base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
           FROM_HERE,
           base::BindOnce(&PdfViewWebPlugin::SetShowSearchifyInProgress,
-                         weak_factory_.GetWeakPtr(), /*show=*/false),
-          kSearchifyStatePropagationDelay);
-    }
-    return;
-  }
+                         weak_factory_.GetWeakPtr(), /*show=*/false));
+      searchify_state_ = SearchifyState::kStopped;
+      break;
 
-  if (!searchify_started_) {
-    searchify_started_ = true;
-    pdf_host_->OnSearchifyStarted();
+    case SearchifyState::kStopped:
+      // Expected to be called only to say searchify started again.
+      CHECK(busy);
+      searchify_state_ = SearchifyState::kStarted;
+      break;
   }
+}
 
-  if (!show_searchify_in_progress_) {
-    show_searchify_in_progress_ = true;
+void PdfViewWebPlugin::MaybeShowSearchifyInProgress() {
+  if (searchify_state_ == SearchifyState::kStarted) {
+    searchify_state_ = SearchifyState::kShowingInProgress;
     // Executing the script directly may cause a crash in blink as it might be
     // during layout change, hence posting it (crbug.com/401142034).
     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
         FROM_HERE, base::BindOnce(&PdfViewWebPlugin::SetShowSearchifyInProgress,
                                   weak_factory_.GetWeakPtr(), /*show=*/true));
-    return;
   }
 }
 
 void PdfViewWebPlugin::SetShowSearchifyInProgress(bool show) {
-  // Searchify tasks are expected to be quite fast most of the times, and if so,
-  // progress indicator should be kept visible for at least 1s to avoiding
-  // flickering.
-  // A false `show` and a true `show_searchify_in_progress_` means that during
-  // the 1s after OCR stopped, it started again and hence the UI should keep the
-  // progress bar visible.
-  if (!show && show_searchify_in_progress_) {
-    return;
-  }
-
   client_->PostMessage(base::Value::Dict()
                            .Set("type", "showSearchifyInProgress")
                            .Set("show", show));
diff --git a/pdf/pdf_view_web_plugin.h b/pdf/pdf_view_web_plugin.h
index a462383..b9da790 100644
--- a/pdf/pdf_view_web_plugin.h
+++ b/pdf/pdf_view_web_plugin.h
@@ -400,6 +400,7 @@
 #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
   void OnSearchifyStateChange(bool busy) override;
   void OnHasSearchifyText() override;
+  void MaybeShowSearchifyInProgress() override;
 #endif
 
   // pdf::mojom::PdfListener:
@@ -996,10 +997,14 @@
   uint32_t max_save_buffer_size_;
 
 #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
-  bool show_searchify_in_progress_ = false;
+  enum class SearchifyState {
+    kNotStarted,
+    kStarted,
+    kShowingInProgress,
+    kStopped,
+  };
 
-  // Tells if searchify ever started.
-  bool searchify_started_ = false;
+  SearchifyState searchify_state_ = SearchifyState::kNotStarted;
 #endif
 
   base::WeakPtrFactory<PdfViewWebPlugin> weak_factory_{this};
diff --git a/pdf/pdf_view_web_plugin_unittest.cc b/pdf/pdf_view_web_plugin_unittest.cc
index 78ef52f0..8a10574 100644
--- a/pdf/pdf_view_web_plugin_unittest.cc
+++ b/pdf/pdf_view_web_plugin_unittest.cc
@@ -137,14 +137,6 @@
 
 constexpr SkColor kPaintColor = SK_ColorRED;
 
-#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
-// This constant should have the same value as the one in
-// `pdf_view_web_plugin.cc`.
-// LINT.IfChange(searchify_state_propagation_delay)
-constexpr base::TimeDelta kSearchifyStatePropagationDelay = base::Seconds(1);
-// LINT.ThenChange(//pdf/pdf_view_web_plugin.cc:searchify_state_propagation_delay)
-#endif
-
 struct PaintParams {
   // The plugin container's device scale.
   float device_scale;
@@ -1851,35 +1843,60 @@
 }
 
 #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
+// Searchify in progress not shown when searchify just starts.
 TEST_F(PdfViewWebPluginTest, OnSearchifyStarted) {
   base::Value::Dict message = GenerateShowSearchifyInProgressMessage(true);
 
-  EXPECT_CALL(*client_ptr_, PostMessage(Eq(std::ref(message))));
+  EXPECT_CALL(*client_ptr_, PostMessage(Eq(std::ref(message)))).Times(0);
+  EXPECT_CALL(pdf_host_, OnSearchifyStarted);
 
   plugin_->OnSearchifyStateChange(true);
 
-  EXPECT_CALL(pdf_host_, OnSearchifyStarted);
-
   pdf_receiver_.FlushForTesting();
 }
 
-TEST_F(PdfViewWebPluginTest, OnSearchifyStartedAndStoppedFast) {
-  base::Value::Dict message_show = GenerateShowSearchifyInProgressMessage(true);
-  base::Value::Dict message_hide =
-      GenerateShowSearchifyInProgressMessage(false);
+// Searchify in progress not shown when searchify didn't starts.
+TEST_F(PdfViewWebPluginTest, OnSearchifyNotStartedAndMaybeShowInProgress) {
+  base::Value::Dict message = GenerateShowSearchifyInProgressMessage(true);
 
-  // Since "hide" message is sent with some delay, it is expected to only
-  // observe one "show" message.
-  EXPECT_CALL(*client_ptr_, PostMessage(Eq(std::ref(message_show))));
-  EXPECT_CALL(*client_ptr_, PostMessage(Eq(std::ref(message_hide)))).Times(0);
+  EXPECT_CALL(*client_ptr_, PostMessage(Eq(std::ref(message)))).Times(0);
+  EXPECT_CALL(pdf_host_, OnSearchifyStarted).Times(0);
+
+  plugin_->MaybeShowSearchifyInProgress();
+
+  pdf_receiver_.FlushForTesting();
+}
+
+// Searchify in progress shown when asked after start.
+TEST_F(PdfViewWebPluginTest, OnSearchifyStartedAndMaybeShowInProgress) {
+  base::Value::Dict message = GenerateShowSearchifyInProgressMessage(true);
+
+  EXPECT_CALL(*client_ptr_, PostMessage(Eq(std::ref(message))));
+  EXPECT_CALL(pdf_host_, OnSearchifyStarted);
+
+  plugin_->OnSearchifyStateChange(true);
+  plugin_->MaybeShowSearchifyInProgress();
+
+  pdf_receiver_.FlushForTesting();
+}
+
+// Searchify in progress not shown when asked after stop.
+TEST_F(PdfViewWebPluginTest,
+       OnSearchifyStartedAndStoppedAndMaybeShowInProgress) {
+  base::Value::Dict message_show = GenerateShowSearchifyInProgressMessage(true);
+
+  EXPECT_CALL(*client_ptr_, PostMessage(Eq(std::ref(message_show)))).Times(0);
+  EXPECT_CALL(pdf_host_, OnSearchifyStarted);
 
   plugin_->OnSearchifyStateChange(true);
   plugin_->OnSearchifyStateChange(false);
+  plugin_->MaybeShowSearchifyInProgress();
 
   pdf_receiver_.FlushForTesting();
 }
 
-TEST_F(PdfViewWebPluginTest, OnSearchifyStopped) {
+// Searchify in progress hides after stop.
+TEST_F(PdfViewWebPluginTest, OnSearchifyShowProgressHideAfterStopped) {
   base::Value::Dict message_show = GenerateShowSearchifyInProgressMessage(true);
   base::Value::Dict message_hide =
       GenerateShowSearchifyInProgressMessage(false);
@@ -1888,38 +1905,9 @@
   EXPECT_CALL(*client_ptr_, PostMessage(Eq(std::ref(message_hide))));
 
   plugin_->OnSearchifyStateChange(true);
+  plugin_->MaybeShowSearchifyInProgress();
   plugin_->OnSearchifyStateChange(false);
 
-  // Wait for the state to be propagated and indicator be hidden.
-  base::RunLoop run_loop;
-  base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
-      FROM_HERE, run_loop.QuitClosure(), kSearchifyStatePropagationDelay);
-  run_loop.Run();
-}
-
-TEST_F(PdfViewWebPluginTest, OnSearchifyStartedAndStoppedAndStarted) {
-  base::Value::Dict message_show = GenerateShowSearchifyInProgressMessage(true);
-  base::Value::Dict message_hide =
-      GenerateShowSearchifyInProgressMessage(false);
-
-  // Since `PdfViewWebPlugin` does not keep two distinct states for "progress
-  // indicator is showing" and "progress indicator will be hidden a bit later",
-  // an unnecessary show message is sent to UI. This has no effect in the UI as
-  // the progress indicator is already showing.
-  EXPECT_CALL(*client_ptr_, PostMessage(Eq(std::ref(message_show)))).Times(2);
-  EXPECT_CALL(*client_ptr_, PostMessage(Eq(std::ref(message_hide)))).Times(0);
-
-  plugin_->OnSearchifyStateChange(true);
-  plugin_->OnSearchifyStateChange(false);
-
-  // Wait, but not enough for the state to be propagated.
-  base::RunLoop run_loop;
-  base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
-      FROM_HERE, run_loop.QuitClosure(), kSearchifyStatePropagationDelay / 2);
-  run_loop.Run();
-
-  plugin_->OnSearchifyStateChange(true);
-
   pdf_receiver_.FlushForTesting();
 }
 
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 14707984..2000376 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -1454,6 +1454,10 @@
   }
 
   OnTextOrLinkAreaClickInternal(point_data, click_count);
+
+#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
+  client_->MaybeShowSearchifyInProgress();
+#endif
   return true;
 }
 
@@ -1911,6 +1915,10 @@
     return;
   }
 
+#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
+  client_->MaybeShowSearchifyInProgress();
+#endif
+
   bool first_search = (current_find_text_ != text);
   int character_to_start_searching_from = 0;
   if (first_search) {
diff --git a/pdf/pdfium/pdfium_engine_client.h b/pdf/pdfium/pdfium_engine_client.h
index 9ee53f2..eb3f461 100644
--- a/pdf/pdfium/pdfium_engine_client.h
+++ b/pdf/pdfium/pdfium_engine_client.h
@@ -211,6 +211,10 @@
   // Notifies that at least one page is searchified. This function is called at
   // most once.
   virtual void OnHasSearchifyText() = 0;
+
+  // Show searchify in progress indicator if searchify is running and the
+  // indicator is not showing.
+  virtual void MaybeShowSearchifyInProgress() = 0;
 #endif
 };
 
diff --git a/pdf/pdfium/pdfium_engine_unittest.cc b/pdf/pdfium/pdfium_engine_unittest.cc
index ded269c8..41cf36f 100644
--- a/pdf/pdfium/pdfium_engine_unittest.cc
+++ b/pdf/pdfium/pdfium_engine_unittest.cc
@@ -138,9 +138,6 @@
 #if BUILDFLAG(ENABLE_PDF_INK2)
   MOCK_METHOD(bool, IsInAnnotationMode, (), (const override));
 #endif  // BUILDFLAG(ENABLE_PDF_INK2)
-#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
-  MOCK_METHOD(void, OnSearchifyStateChange, (bool), (override));
-#endif
 };
 
 }  // namespace
diff --git a/pdf/preview_mode_client.cc b/pdf/preview_mode_client.cc
index db5c99b..77e1d32 100644
--- a/pdf/preview_mode_client.cc
+++ b/pdf/preview_mode_client.cc
@@ -186,6 +186,10 @@
 void PreviewModeClient::OnHasSearchifyText() {
   NOTREACHED();
 }
+
+void PreviewModeClient::MaybeShowSearchifyInProgress() {
+  NOTREACHED();
+}
 #endif
 
 }  // namespace chrome_pdf
diff --git a/pdf/preview_mode_client.h b/pdf/preview_mode_client.h
index a8e8b81..22e93df6 100644
--- a/pdf/preview_mode_client.h
+++ b/pdf/preview_mode_client.h
@@ -81,6 +81,7 @@
 #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
   void OnSearchifyStateChange(bool busy) override;
   void OnHasSearchifyText() override;
+  void MaybeShowSearchifyInProgress() override;
 #endif
 
  private:
diff --git a/pdf/test/test_client.cc b/pdf/test/test_client.cc
index 2179ae1..405b7743 100644
--- a/pdf/test/test_client.cc
+++ b/pdf/test/test_client.cc
@@ -82,6 +82,8 @@
 void TestClient::OnSearchifyStateChange(bool busy) {}
 
 void TestClient::OnHasSearchifyText() {}
+
+void TestClient::MaybeShowSearchifyInProgress() {}
 #endif
 
 }  // namespace chrome_pdf
diff --git a/pdf/test/test_client.h b/pdf/test/test_client.h
index ba9cafc..f51f52c5 100644
--- a/pdf/test/test_client.h
+++ b/pdf/test/test_client.h
@@ -51,6 +51,7 @@
 #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
   void OnSearchifyStateChange(bool busy) override;
   void OnHasSearchifyText() override;
+  void MaybeShowSearchifyInProgress() override;
 #endif
 
  private:
diff --git a/remoting/base/cloud_service_client.cc b/remoting/base/cloud_service_client.cc
index eda7c85..1956f0c 100644
--- a/remoting/base/cloud_service_client.cc
+++ b/remoting/base/cloud_service_client.cc
@@ -436,7 +436,7 @@
     const std::string& session_reauth_token,
     const std::string& session_id,
     std::string_view instance_identity_token,
-    std::unique_ptr<ProtobufHttpRequestConfig::RetryPolicy> retry_policy,
+    scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy> retry_policy,
     ReauthorizeHostCallback callback) {
   constexpr char path[] = "/v1alpha/sessionAuthz:reauthorizeHost";
 
@@ -462,7 +462,7 @@
     const std::string& method,
     std::unique_ptr<google::protobuf::MessageLite> request_message,
     CallbackType callback,
-    std::unique_ptr<ProtobufHttpRequestConfig::RetryPolicy> retry_policy) {
+    scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy> retry_policy) {
   auto request_config =
       std::make_unique<ProtobufHttpRequestConfig>(traffic_annotation);
   request_config->path = path;
diff --git a/remoting/base/cloud_service_client.h b/remoting/base/cloud_service_client.h
index 34b476b..a0288f0 100644
--- a/remoting/base/cloud_service_client.h
+++ b/remoting/base/cloud_service_client.h
@@ -11,6 +11,7 @@
 #include <string_view>
 
 #include "base/functional/callback_forward.h"
+#include "base/memory/scoped_refptr.h"
 #include "remoting/base/protobuf_http_client.h"
 #include "remoting/base/protobuf_http_request_config.h"
 
@@ -127,7 +128,7 @@
       const std::string& session_reauth_token,
       const std::string& session_id,
       std::string_view instance_identity_token,
-      std::unique_ptr<ProtobufHttpRequestConfig::RetryPolicy> retry_policy,
+      scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy> retry_policy,
       ReauthorizeHostCallback callback);
 
   void CancelPendingRequests();
@@ -147,8 +148,8 @@
       const std::string& method,
       std::unique_ptr<google::protobuf::MessageLite> request_message,
       CallbackType callback,
-      std::unique_ptr<ProtobufHttpRequestConfig::RetryPolicy> retry_policy =
-          ProtobufHttpRequestConfig::CreateDefaultRetryPolicy());
+      scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy> retry_policy =
+          ProtobufHttpRequestConfig::GetSimpleRetryPolicy());
 
   // The customer API_KEY to use for calling the Remoting Cloud API.
   std::string api_key_;
diff --git a/remoting/base/corp_logging_service_client.cc b/remoting/base/corp_logging_service_client.cc
index 7546b15..66b86ea 100644
--- a/remoting/base/corp_logging_service_client.cc
+++ b/remoting/base/corp_logging_service_client.cc
@@ -80,6 +80,7 @@
   request_config->provide_certificate = true;
   request_config->request_message =
       internal::GetReportSessionDisconnectedRequest(request_struct);
+  request_config->UseSimpleRetryPolicy();
   auto request =
       std::make_unique<ProtobufHttpRequest>(std::move(request_config));
   request->SetResponseCallback(base::BindOnce([](const HttpStatus& status,
diff --git a/remoting/base/corp_service_client.cc b/remoting/base/corp_service_client.cc
index 3a6b03e..9ac702b1 100644
--- a/remoting/base/corp_service_client.cc
+++ b/remoting/base/corp_service_client.cc
@@ -84,10 +84,13 @@
           policy_exception_justification:
             "Not implemented."
         })");
+
+  // ProvisionCorpMachine is non-idempotent (potentially multiple host records
+  // will be created), so retries may not be safe.
   ExecuteRequest(
       traffic_annotation, internal::GetMachineProvisioningRequestPath(),
-      net::HttpRequestHeaders::kPostMethod,
-      /*unauthenticated=*/true,
+      net::HttpRequestHeaders::kPostMethod, /*unauthenticated=*/true,
+      /*enable_retries=*/false,
       internal::GetMachineProvisioningRequest(
           owner_email, fqdn, public_key, STRINGIZE(VERSION), existing_host_id),
           std::move(callback));
@@ -134,6 +137,7 @@
                  internal::GetReportProvisioningErrorRequestPath(),
                  net::HttpRequestHeaders::kPostMethod,
                  /*unauthenticated=*/true,
+                 /*enable_retries=*/true,
                  internal::GetReportProvisioningErrorRequest(
                      directory_id, error_message, version),
                  std::move(callback));
@@ -170,9 +174,11 @@
           policy_exception_justification:
             "Not implemented."
         })");
+
+  // HeartbeatSender has its own retry logic, so we disable it here.
   ExecuteRequest(traffic_annotation, internal::GetSendHeartbeatRequestPath(),
                  net::HttpRequestHeaders::kPostMethod,
-                 /*unauthenticated=*/false,
+                 /*unauthenticated=*/false, /*enable_retries=*/false,
                  internal::GetSendHeartbeatRequest(directory_id),
                  std::move(callback));
 }
@@ -223,6 +229,7 @@
       traffic_annotation, internal::GetUpdateRemoteAccessHostRequestPath(),
       net::HttpRequestHeaders::kPatchMethod,
       /*unauthenticated=*/false,
+      /*enable_retries=*/true,
       internal::GetUpdateRemoteAccessHostRequest(
           directory_id, std::move(host_version), std::move(signaling_id),
           std::move(offline_reason), std::move(os_name), std::move(os_version)),
@@ -239,6 +246,7 @@
     const std::string& path,
     const std::string& method,
     bool unauthenticated,
+    bool enable_retries,
     std::unique_ptr<google::protobuf::MessageLite> request_message,
     CallbackType callback) {
   auto request_config =
@@ -255,6 +263,9 @@
   }
   request_config->provide_certificate = true;
   request_config->request_message = std::move(request_message);
+  if (enable_retries) {
+    request_config->UseSimpleRetryPolicy();
+  }
   auto request =
       std::make_unique<ProtobufHttpRequest>(std::move(request_config));
   request->SetResponseCallback(std::move(callback));
diff --git a/remoting/base/corp_service_client.h b/remoting/base/corp_service_client.h
index 308f0e6..c05ab63 100644
--- a/remoting/base/corp_service_client.h
+++ b/remoting/base/corp_service_client.h
@@ -88,6 +88,7 @@
       const std::string& path,
       const std::string& method,
       bool unauthenticated,
+      bool enable_retries,
       std::unique_ptr<google::protobuf::MessageLite> request_message,
       CallbackType callback);
 
diff --git a/remoting/base/corp_session_authz_service_client.cc b/remoting/base/corp_session_authz_service_client.cc
index 63addbfa2..d16a70a 100644
--- a/remoting/base/corp_session_authz_service_client.cc
+++ b/remoting/base/corp_session_authz_service_client.cc
@@ -213,7 +213,7 @@
     std::string_view verb,
     std::unique_ptr<google::protobuf::MessageLite> request_message,
     CallbackType callback,
-    std::unique_ptr<ProtobufHttpRequestConfig::RetryPolicy> retry_policy) {
+    scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy> retry_policy) {
   auto request_config =
       std::make_unique<ProtobufHttpRequestConfig>(traffic_annotation);
   request_config->path = base::StrCat({session_authz_path_, ":", verb});
diff --git a/remoting/base/corp_session_authz_service_client.h b/remoting/base/corp_session_authz_service_client.h
index 04985880..5c97c427 100644
--- a/remoting/base/corp_session_authz_service_client.h
+++ b/remoting/base/corp_session_authz_service_client.h
@@ -58,8 +58,8 @@
       std::string_view verb,
       std::unique_ptr<google::protobuf::MessageLite> request_message,
       CallbackType callback,
-      std::unique_ptr<ProtobufHttpRequestConfig::RetryPolicy> retry_policy =
-          ProtobufHttpRequestConfig::CreateDefaultRetryPolicy());
+      scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy> retry_policy =
+          ProtobufHttpRequestConfig::GetSimpleRetryPolicy());
 
   std::unique_ptr<OAuthTokenGetter> oauth_token_getter_;
   ProtobufHttpClient http_client_;
diff --git a/remoting/base/directory_service_client.cc b/remoting/base/directory_service_client.cc
index 32209c1..1d97aac 100644
--- a/remoting/base/directory_service_client.cc
+++ b/remoting/base/directory_service_client.cc
@@ -157,13 +157,15 @@
   auto delete_host_request = std::make_unique<apis::v1::DeleteHostRequest>();
   delete_host_request->set_host_id(host_id);
   ExecuteRequest(kDeleteHostTrafficAnnotation, path,
-                 std::move(delete_host_request), std::move(callback));
+                 /*enable_retries=*/true, std::move(delete_host_request),
+                 std::move(callback));
 }
 
 void DirectoryServiceClient::GetHostList(GetHostListCallback callback) {
   constexpr char path[] = "/v1/directory:gethostlist";
 
   ExecuteRequest(kGetHostListTrafficAnnotation, path,
+                 /*enable_retries=*/true,
                  std::make_unique<apis::v1::GetHostListRequest>(),
                  std::move(callback));
 }
@@ -178,7 +180,8 @@
   request->set_client_os_version(STRINGIZE(VERSION));
 
   // TODO: joedow - Fix the traffic annotation.
-  ExecuteRequest(kGetHostListTrafficAnnotation, path, std::move(request),
+  ExecuteRequest(kGetHostListTrafficAnnotation, path,
+                 /*enable_retries=*/true, std::move(request),
                  std::move(callback));
 }
 
@@ -214,7 +217,9 @@
     }
   }
 
-  ExecuteRequest(kLegacyHeartbeatTrafficAnnotation, path, std::move(request),
+  // HeartbeatSender has its own retry logic, so we disable it here.
+  ExecuteRequest(kLegacyHeartbeatTrafficAnnotation, path,
+                 /*enable_retries=*/false, std::move(request),
                  std::move(callback));
 }
 
@@ -233,7 +238,10 @@
   register_host_request->set_host_name(host_name);
   register_host_request->set_public_key(public_key);
   register_host_request->set_host_client_id(host_client_id);
-  ExecuteRequest(kRegisterHostTrafficAnnotation, path,
+
+  // RegisterHost is non-idempotent (potentially multiple host records will be
+  // created), so retries may not be safe.
+  ExecuteRequest(kRegisterHostTrafficAnnotation, path, /*enable_retries=*/false,
                  std::move(register_host_request), std::move(callback));
 }
 
@@ -244,7 +252,9 @@
   auto request = std::make_unique<apis::v1::SendHeartbeatRequest>();
   request->set_host_id(directory_id);
 
-  ExecuteRequest(kSendHeartbeatTrafficAnnotation, path, std::move(request),
+  // HeartbeatSender has its own retry logic, so we disable it here.
+  ExecuteRequest(kSendHeartbeatTrafficAnnotation, path,
+                 /*enable_retries=*/false, std::move(request),
                  std::move(callback));
 }
 
@@ -256,12 +266,16 @@
 void DirectoryServiceClient::ExecuteRequest(
     const net::NetworkTrafficAnnotationTag& traffic_annotation,
     const std::string& path,
+    bool enable_retries,
     std::unique_ptr<google::protobuf::MessageLite> request_message,
     CallbackType callback) {
   auto request_config =
       std::make_unique<ProtobufHttpRequestConfig>(traffic_annotation);
   request_config->path = path;
   request_config->request_message = std::move(request_message);
+  if (enable_retries) {
+    request_config->UseSimpleRetryPolicy();
+  }
 
   auto request =
       std::make_unique<ProtobufHttpRequest>(std::move(request_config));
diff --git a/remoting/base/directory_service_client.h b/remoting/base/directory_service_client.h
index 63e1231..d13f254f 100644
--- a/remoting/base/directory_service_client.h
+++ b/remoting/base/directory_service_client.h
@@ -90,6 +90,7 @@
   void ExecuteRequest(
       const net::NetworkTrafficAnnotationTag& traffic_annotation,
       const std::string& path,
+      bool enable_retries,
       std::unique_ptr<google::protobuf::MessageLite> request_message,
       CallbackType callback);
 
diff --git a/remoting/base/protobuf_http_client_unittest.cc b/remoting/base/protobuf_http_client_unittest.cc
index fd5c88e1..7dac2fd 100644
--- a/remoting/base/protobuf_http_client_unittest.cc
+++ b/remoting/base/protobuf_http_client_unittest.cc
@@ -466,8 +466,7 @@
   MockEchoResponseCallback response_callback;
 
   auto request_config = CreateDefaultRequestConfig();
-  request_config->retry_policy =
-      ProtobufHttpRequestConfig::CreateDefaultRetryPolicy();
+  request_config->UseSimpleRetryPolicy();
   auto request = CreateDefaultTestRequest(std::move(request_config));
   request->SetResponseCallback(response_callback.Get());
   client_.ExecuteRequest(std::move(request));
@@ -506,8 +505,7 @@
   MockEchoResponseCallback response_callback;
 
   auto request_config = CreateDefaultRequestConfig();
-  request_config->retry_policy =
-      ProtobufHttpRequestConfig::CreateDefaultRetryPolicy();
+  request_config->UseSimpleRetryPolicy();
   auto request = CreateDefaultTestRequest(std::move(request_config));
   request->SetResponseCallback(response_callback.Get());
   client_.ExecuteRequest(std::move(request));
@@ -551,8 +549,7 @@
   MockEchoResponseCallback response_callback;
 
   auto request_config = CreateDefaultRequestConfig();
-  request_config->retry_policy =
-      ProtobufHttpRequestConfig::CreateDefaultRetryPolicy();
+  request_config->UseSimpleRetryPolicy();
   auto request = CreateDefaultTestRequest(std::move(request_config));
   request->SetResponseCallback(response_callback.Get());
   client_.ExecuteRequest(std::move(request));
diff --git a/remoting/base/protobuf_http_request_base.cc b/remoting/base/protobuf_http_request_base.cc
index 3cff8905e..135662d8 100644
--- a/remoting/base/protobuf_http_request_base.cc
+++ b/remoting/base/protobuf_http_request_base.cc
@@ -8,8 +8,10 @@
 
 #include "base/containers/fixed_flat_set.h"
 #include "base/logging.h"
+#include "base/memory/raw_ptr.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
+#include "net/base/backoff_entry.h"
 #include "net/base/net_errors.h"
 #include "remoting/base/protobuf_http_request_config.h"
 #include "remoting/base/scoped_protobuf_http_request.h"
@@ -19,22 +21,23 @@
 namespace remoting {
 
 struct ProtobufHttpRequestBase::RetryEntry {
-  explicit RetryEntry(const net::BackoffEntry::Policy* policy)
-      : backoff_entry(policy) {}
+  explicit RetryEntry(
+      const ProtobufHttpRequestConfig::RetryPolicy& retry_policy)
+      : backoff_entry(retry_policy.backoff_policy) {
+    retry_deadline = base::TimeTicks::Now() + retry_policy.retry_timeout;
+  }
+
   ~RetryEntry() = default;
 
   net::BackoffEntry backoff_entry;
   base::OneShotTimer retry_timer;
+  base::TimeTicks retry_deadline;
 };
 
 ProtobufHttpRequestBase::ProtobufHttpRequestBase(
     std::unique_ptr<ProtobufHttpRequestConfig> config)
     : config_(std::move(config)) {
   config_->Validate();
-  if (config_->retry_policy) {
-    retry_entry_ =
-        std::make_unique<RetryEntry>(config_->retry_policy->backoff_policy);
-  }
 }
 
 ProtobufHttpRequestBase::~ProtobufHttpRequestBase() {
@@ -85,7 +88,7 @@
   }
   retry_entry_->backoff_entry.InformOfRequest(false);
   if (retry_entry_->backoff_entry.GetReleaseTime() >=
-      config_->retry_policy->retry_deadline) {
+      retry_entry_->retry_deadline) {
     LOG(WARNING) << "No more retries remaining.";
     return false;
   }
@@ -105,6 +108,9 @@
   DCHECK(!create_url_loader_);
   DCHECK(!invalidator_);
 
+  if (config_->retry_policy) {
+    retry_entry_ = std::make_unique<RetryEntry>(*config_->retry_policy);
+  }
   loader_factory_ = loader_factory;
   create_url_loader_ = std::move(create_url_loader);
   invalidator_ = std::move(invalidator);
diff --git a/remoting/base/protobuf_http_request_base.h b/remoting/base/protobuf_http_request_base.h
index 06d1140b..ed5de15 100644
--- a/remoting/base/protobuf_http_request_base.h
+++ b/remoting/base/protobuf_http_request_base.h
@@ -100,12 +100,14 @@
 
   std::unique_ptr<const ProtobufHttpRequestConfig> config_;
 
-  // Non-null iff `config_.retry_policy` is configured.
-  std::unique_ptr<RetryEntry> retry_entry_;
-
   // These are only set after StartRequest() is called.
   CreateUrlLoader create_url_loader_;
   raw_ptr<network::mojom::URLLoaderFactory> loader_factory_;
+  // Non-null iff StartRequest() is called and `config_.retry_policy` is
+  // configured.
+  // `retry_entry_` must be deleted before `config_` since it holds a raw_ptr to
+  // `config_`.
+  std::unique_ptr<RetryEntry> retry_entry_;
 
 #if DCHECK_IS_ON()
   base::TimeTicks request_deadline_;
diff --git a/remoting/base/protobuf_http_request_config.cc b/remoting/base/protobuf_http_request_config.cc
index 39f0fd2..46a3189 100644
--- a/remoting/base/protobuf_http_request_config.cc
+++ b/remoting/base/protobuf_http_request_config.cc
@@ -4,23 +4,16 @@
 
 #include "remoting/base/protobuf_http_request_config.h"
 
+#include "base/memory/scoped_refptr.h"
+#include "base/no_destructor.h"
 #include "base/time/time.h"
 #include "third_party/protobuf/src/google/protobuf/message_lite.h"
 
 namespace remoting {
 
 // static
-std::unique_ptr<ProtobufHttpRequestConfig::RetryPolicy>
-ProtobufHttpRequestConfig::CreateRetryPolicy(
-    const net::BackoffEntry::Policy& backoff_policy,
-    base::TimeTicks retry_deadline) {
-  return std::make_unique<ProtobufHttpRequestConfig::RetryPolicy>(
-      &backoff_policy, retry_deadline);
-}
-
-// static
-std::unique_ptr<ProtobufHttpRequestConfig::RetryPolicy>
-ProtobufHttpRequestConfig::CreateDefaultRetryPolicy() {
+scoped_refptr<const ProtobufHttpRequestConfig::RetryPolicy>
+ProtobufHttpRequestConfig::GetSimpleRetryPolicy() {
   static constexpr net::BackoffEntry::Policy kBackoffPolicy = {
       .num_errors_to_ignore = 0,
       .initial_delay_ms = base::Seconds(1).InMilliseconds(),
@@ -33,8 +26,14 @@
       .always_use_initial_delay = false,
   };
 
-  return CreateRetryPolicy(kBackoffPolicy,
-                           base::TimeTicks::Now() + base::Minutes(1));
+  static base::NoDestructor<scoped_refptr<RetryPolicy>> policy([]() {
+    auto policy = base::MakeRefCounted<RetryPolicy>();
+    policy->backoff_policy = &kBackoffPolicy;
+    policy->retry_timeout = base::Minutes(1);
+    return policy;
+  }());
+
+  return *policy;
 }
 
 ProtobufHttpRequestConfig::ProtobufHttpRequestConfig(
@@ -48,4 +47,8 @@
   DCHECK(!path.empty());
 }
 
+void ProtobufHttpRequestConfig::UseSimpleRetryPolicy() {
+  retry_policy = GetSimpleRetryPolicy();
+}
+
 }  // namespace remoting
diff --git a/remoting/base/protobuf_http_request_config.h b/remoting/base/protobuf_http_request_config.h
index 7042a967..e225f1b 100644
--- a/remoting/base/protobuf_http_request_config.h
+++ b/remoting/base/protobuf_http_request_config.h
@@ -9,6 +9,8 @@
 #include <string>
 
 #include "base/memory/raw_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/time/time.h"
 #include "net/base/backoff_entry.h"
 #include "net/http/http_request_headers.h"
@@ -26,25 +28,25 @@
 // Common configurations for unary and stream protobuf http requests. Caller
 // needs to set all fields in this struct unless otherwise documented.
 struct ProtobufHttpRequestConfig {
-  struct RetryPolicy {
+  struct RetryPolicy : public base::RefCountedThreadSafe<RetryPolicy> {
     // `backoff_policy` must outlive `this`. In most cases you want to define
     // the policy as a `static constexpr` then set this to point to it.
     raw_ptr<const net::BackoffEntry::Policy> backoff_policy;
 
-    // A deadline after which the request will no longer be retried.
-    base::TimeTicks retry_deadline;
+    // A duration counted from when the first attempt of the request is made,
+    // after which the request will no longer be retried.
+    base::TimeDelta retry_timeout;
+
+   private:
+    friend class base::RefCountedThreadSafe<RetryPolicy>;
+
+    ~RetryPolicy() = default;
   };
 
-  // Helper function to create a unique_ptr of RetryPolicy. See comments in the
-  // struct.
-  static std::unique_ptr<RetryPolicy> CreateRetryPolicy(
-      const net::BackoffEntry::Policy& backoff_policy,
-      base::TimeTicks retry_deadline);
-
-  // Creates the default RetryPolicy that retries for up to ~1 minute (counted
-  // from when this method is called) with exponential backoff, suitable for
-  // most simple short running operations.
-  static std::unique_ptr<RetryPolicy> CreateDefaultRetryPolicy();
+  // Returns a simple RetryPolicy that retries for up to ~1 minute (counted
+  // from when the first attempt of the request is made) with exponential
+  // backoff, suitable for most simple short running operations.
+  static scoped_refptr<const RetryPolicy> GetSimpleRetryPolicy();
 
   explicit ProtobufHttpRequestConfig(
       const net::NetworkTrafficAnnotationTag& traffic_annotation);
@@ -53,6 +55,9 @@
   // Runs DCHECK's on the fields to make sure all fields have been set up.
   void Validate() const;
 
+  // This is equivalent to setting `retry_policy` to GetSimpleRetryPolicy().
+  void UseSimpleRetryPolicy();
+
   const net::NetworkTrafficAnnotationTag traffic_annotation;
   std::unique_ptr<google::protobuf::MessageLite> request_message;
   std::string path;
@@ -63,10 +68,11 @@
   // Optional. Only needed when the request requires an API key.
   std::string api_key;
 
-  // If configured, request will be automatically retried if the error code
-  // is one of ABORTED, UNAVAILABLE, or NETWORK_ERROR.
+  // If configured, request will be automatically retried if the error code is
+  // one of ABORTED, UNAVAILABLE, or NETWORK_ERROR. Set this to null to disable
+  // retries.
   // NOTE: `retry_policy` is currently not supported by stream requests.
-  std::unique_ptr<RetryPolicy> retry_policy;
+  scoped_refptr<const RetryPolicy> retry_policy;
 };
 
 }  // namespace remoting
diff --git a/remoting/base/session_authz_service_client.cc b/remoting/base/session_authz_service_client.cc
index 2fda6a3..b5ba227 100644
--- a/remoting/base/session_authz_service_client.cc
+++ b/remoting/base/session_authz_service_client.cc
@@ -4,12 +4,14 @@
 
 #include "remoting/base/session_authz_service_client.h"
 
+#include "base/memory/scoped_refptr.h"
+#include "base/time/time.h"
 #include "remoting/base/protobuf_http_request_config.h"
 
 namespace remoting {
 
 // static
-std::unique_ptr<ProtobufHttpRequestConfig::RetryPolicy>
+scoped_refptr<ProtobufHttpRequestConfig::RetryPolicy>
 SessionAuthzServiceClient::GetReauthRetryPolicy(
     base::TimeTicks token_expire_time) {
   static constexpr net::BackoffEntry::Policy kBackoffPolicy = {
@@ -23,9 +25,13 @@
       // initial delay is technically used.
       .always_use_initial_delay = false,
   };
+
+  auto policy = base::MakeRefCounted<ProtobufHttpRequestConfig::RetryPolicy>();
+  policy->backoff_policy = &kBackoffPolicy;
   // Add some leeway to account for network latencies.
-  return ProtobufHttpRequestConfig::CreateRetryPolicy(
-      kBackoffPolicy, token_expire_time - base::Seconds(5));
+  policy->retry_timeout =
+      token_expire_time - base::TimeTicks::Now() - base::Seconds(5);
+  return policy;
 }
 
 }  // namespace remoting
diff --git a/remoting/base/session_authz_service_client.h b/remoting/base/session_authz_service_client.h
index 12bda29..318c60e 100644
--- a/remoting/base/session_authz_service_client.h
+++ b/remoting/base/session_authz_service_client.h
@@ -9,6 +9,7 @@
 #include <string_view>
 
 #include "base/functional/callback_forward.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/time/time.h"
 #include "remoting/base/http_status.h"
 #include "remoting/base/protobuf_http_request_config.h"
@@ -45,7 +46,7 @@
                                ReauthorizeHostCallback callback) = 0;
 
  protected:
-  static std::unique_ptr<ProtobufHttpRequestConfig::RetryPolicy>
+  static scoped_refptr<ProtobufHttpRequestConfig::RetryPolicy>
   GetReauthRetryPolicy(base::TimeTicks token_expire_time);
 
   SessionAuthzServiceClient() = default;
diff --git a/remoting/protocol/ice_config_fetcher_default.cc b/remoting/protocol/ice_config_fetcher_default.cc
index 3b17f37..45b9a0f 100644
--- a/remoting/protocol/ice_config_fetcher_default.cc
+++ b/remoting/protocol/ice_config_fetcher_default.cc
@@ -97,6 +97,7 @@
     request_config->authenticated = false;
     request_config->api_key = google_apis::GetRemotingAPIKey();
   }
+  request_config->UseSimpleRetryPolicy();
   auto request =
       std::make_unique<ProtobufHttpRequest>(std::move(request_config));
   request->SetResponseCallback(base::BindOnce(
diff --git a/remoting/signaling/ftl_messaging_client.cc b/remoting/signaling/ftl_messaging_client.cc
index d9437362f..f4ac2068 100644
--- a/remoting/signaling/ftl_messaging_client.cc
+++ b/remoting/signaling/ftl_messaging_client.cc
@@ -234,8 +234,11 @@
     request->add_dest_registration_ids(destination_registration_id);
   }
 
+  // SendMessage is non-idempotent (potentially duplicate messages will be
+  // sent), so retries may not be safe.
   ExecuteRequest(kSendMessageTrafficAnnotation, kSendMessagePath,
-                 std::move(request), &FtlMessagingClient::OnSendMessageResponse,
+                 /*enable_retries=*/false, std::move(request),
+                 &FtlMessagingClient::OnSendMessageResponse,
                  std::move(on_done));
 }
 
@@ -257,12 +260,16 @@
 void FtlMessagingClient::ExecuteRequest(
     const net::NetworkTrafficAnnotationTag& tag,
     const std::string& path,
+    bool enable_retries,
     std::unique_ptr<google::protobuf::MessageLite> request,
     CallbackFunctor callback_functor,
     DoneCallback on_done) {
   auto config = std::make_unique<ProtobufHttpRequestConfig>(tag);
   config->request_message = std::move(request);
   config->path = path;
+  if (enable_retries) {
+    config->UseSimpleRetryPolicy();
+  }
   auto http_request = std::make_unique<ProtobufHttpRequest>(std::move(config));
   http_request->SetResponseCallback(base::BindOnce(
       callback_functor, base::Unretained(this), std::move(on_done)));
@@ -285,6 +292,7 @@
   VLOG(1) << "Acking " << request.message_ids_size() << " messages";
 
   ExecuteRequest(kAckMessagesTrafficAnnotation, kBatchAckMessagesPath,
+                 /*enable_retries=*/true,
                  std::make_unique<ftl::BatchAckMessagesRequest>(request),
                  &FtlMessagingClient::OnBatchAckMessagesResponse,
                  std::move(on_done));
diff --git a/remoting/signaling/ftl_messaging_client.h b/remoting/signaling/ftl_messaging_client.h
index 9fcc84f..05f1beb6 100644
--- a/remoting/signaling/ftl_messaging_client.h
+++ b/remoting/signaling/ftl_messaging_client.h
@@ -74,6 +74,7 @@
   template <typename CallbackFunctor>
   void ExecuteRequest(const net::NetworkTrafficAnnotationTag& tag,
                       const std::string& path,
+                      bool enable_retries,
                       std::unique_ptr<google::protobuf::MessageLite> request,
                       CallbackFunctor callback_functor,
                       DoneCallback on_done);
diff --git a/services/network/chunked_data_pipe_upload_data_stream.cc b/services/network/chunked_data_pipe_upload_data_stream.cc
index 76d64484..a7e4eee 100644
--- a/services/network/chunked_data_pipe_upload_data_stream.cc
+++ b/services/network/chunked_data_pipe_upload_data_stream.cc
@@ -83,8 +83,8 @@
 
 int ChunkedDataPipeUploadDataStream::ReadInternal(net::IOBuffer* buf,
                                                   int buf_len) {
-  DCHECK(!buf_);
-  DCHECK(buf);
+  CHECK(!buf_);
+  CHECK(buf);
   DCHECK_GT(buf_len, 0);
 
   // If there was an error either passed to the ReadCallback or as a result of
@@ -218,7 +218,7 @@
 }
 
 void ChunkedDataPipeUploadDataStream::OnHandleReadable(MojoResult result) {
-  DCHECK(buf_);
+  CHECK(buf_);
 
   // Final result of the Read() call, to be passed to the consumer.
   // Swap out |buf_| and |buf_len_|
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 3481539c..298b0e90 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -19,6 +19,7 @@
 #include "base/check.h"
 #include "base/check_op.h"
 #include "base/command_line.h"
+#include "base/containers/flat_set.h"
 #include "base/containers/to_vector.h"
 #include "base/containers/unique_ptr_adapters.h"
 #include "base/dcheck_is_on.h"
@@ -2599,9 +2600,10 @@
       http_auth_dynamic_network_service_params->allow_gssapi_library_load);
 #endif  // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
   if (http_auth_dynamic_network_service_params->allowed_schemes.has_value()) {
-    http_auth_merged_preferences_.set_allowed_schemes(std::set<std::string>(
-        http_auth_dynamic_network_service_params->allowed_schemes->begin(),
-        http_auth_dynamic_network_service_params->allowed_schemes->end()));
+    http_auth_merged_preferences_.set_allowed_schemes(
+        base::flat_set<std::string>(
+            http_auth_dynamic_network_service_params->allowed_schemes->begin(),
+            http_auth_dynamic_network_service_params->allowed_schemes->end()));
   } else {
     http_auth_merged_preferences_.set_allowed_schemes(std::nullopt);
   }
diff --git a/services/webnn/BUILD.gn b/services/webnn/BUILD.gn
index badd3091..3576913 100644
--- a/services/webnn/BUILD.gn
+++ b/services/webnn/BUILD.gn
@@ -177,6 +177,8 @@
       "ort/context_provider_ort.h",
       "ort/graph_builder_ort.cc",
       "ort/graph_builder_ort.h",
+      "ort/graph_impl_ort.cc",
+      "ort/graph_impl_ort.h",
       "ort/model_editor.cc",
       "ort/model_editor.h",
       "ort/ort_data_type.cc",
diff --git a/services/webnn/ort/buffer_content_ort.h b/services/webnn/ort/buffer_content_ort.h
index 6beced3..137d57e5 100644
--- a/services/webnn/ort/buffer_content_ort.h
+++ b/services/webnn/ort/buffer_content_ort.h
@@ -21,6 +21,7 @@
 
   ~BufferContentOrt();
 
+  OrtValue* tensor() const { return tensor_.get(); }
   base::span<uint8_t> AsSpan() const;
 
  private:
diff --git a/services/webnn/ort/context_impl_ort.cc b/services/webnn/ort/context_impl_ort.cc
index 7407579..07f4cba 100644
--- a/services/webnn/ort/context_impl_ort.cc
+++ b/services/webnn/ort/context_impl_ort.cc
@@ -6,6 +6,7 @@
 
 #include "base/notimplemented.h"
 #include "services/webnn/ort/buffer_content_ort.h"
+#include "services/webnn/ort/graph_impl_ort.h"
 #include "services/webnn/ort/tensor_impl_ort.h"
 #include "services/webnn/public/cpp/supported_data_types.h"
 #include "services/webnn/public/mojom/webnn_context_provider.mojom.h"
@@ -61,7 +62,8 @@
        /*batch_normalization_input=*/{},
        /*batch_normalization_mean=*/{},
        /*cast_input=*/{SupportedDataTypes::All(), kMaxRank},
-       /*clamp_input=*/{},
+       /*clamp_input=*/
+       {DataTypeConstraint::kAllDataTypesAtLeast8bits, kMaxRank},
        /*concat_inputs=*/{},
        /*conv2d_input=*/{},
        /*conv2d_bias=*/{},
@@ -194,8 +196,10 @@
         constant_operands,
     base::flat_map<OperandId, WebNNTensorImpl*> constant_tensor_operands,
     CreateGraphImplCallback callback) {
-  // TODO(crbug.com/416535744): Implement GraphImpl for ORT backend.
-  NOTIMPLEMENTED();
+  GraphImplOrt::CreateAndBuild(
+      std::move(receiver), std::move(graph_info),
+      std::move(compute_resource_info), std::move(constant_operands),
+      std::move(constant_tensor_operands), this, std::move(callback));
 }
 
 void ContextImplOrt::CreateTensorImpl(
diff --git a/services/webnn/ort/graph_builder_ort.cc b/services/webnn/ort/graph_builder_ort.cc
index 941f3ed..00daf053 100644
--- a/services/webnn/ort/graph_builder_ort.cc
+++ b/services/webnn/ort/graph_builder_ort.cc
@@ -15,6 +15,7 @@
 #include "services/webnn/public/mojom/webnn_error.mojom.h"
 #include "services/webnn/public/mojom/webnn_graph.mojom.h"
 #include "services/webnn/webnn_constant_operand.h"
+#include "third_party/fp16/src/include/fp16.h"
 
 namespace webnn::ort {
 
@@ -46,6 +47,7 @@
 constexpr base::cstring_view kOpTypeReciprocal = "Reciprocal";
 constexpr base::cstring_view kOpTypeCast = "Cast";
 
+constexpr base::cstring_view kOpTypeClamp = "Clip";
 constexpr base::cstring_view kOpTypeGelu = "Gelu";
 constexpr base::cstring_view kOpTypeGemm = "Gemm";
 constexpr base::cstring_view kOpTypeHardSwish = "HardSwish";
@@ -59,6 +61,7 @@
 constexpr base::cstring_view kOpTypeMaxPool2d = "MaxPool";
 constexpr base::cstring_view kOpTypeLpPool2d = "LpPool";
 
+constexpr std::string_view kInserted = "Inserted";
 constexpr std::string_view kUnderscore = "_";
 
 std::string GetOperandName(std::string_view label, OperandId id) {
@@ -66,6 +69,64 @@
                           kUnderscore);
 }
 
+// Maps a DataType to a `ONNXTensorElementDataType`. Other `TensorTypeMap`
+// overloads may be declared below as needed.
+//
+// Example: TensorTypeMap<uint32_t>::value ->
+// ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32
+template <typename DataType>
+  requires internal::IsSupportedTensorType<DataType>
+struct TensorTypeMap;
+
+template <>
+struct TensorTypeMap<float> {
+  static constexpr ONNXTensorElementDataType value =
+      ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT;
+};
+
+// Use uint16_t to carry bits of float16.
+template <>
+struct TensorTypeMap<uint16_t> {
+  static constexpr ONNXTensorElementDataType value =
+      ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT16;
+};
+
+template <>
+struct TensorTypeMap<int32_t> {
+  static constexpr ONNXTensorElementDataType value =
+      ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32;
+};
+
+template <>
+struct TensorTypeMap<uint32_t> {
+  static constexpr ONNXTensorElementDataType value =
+      ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32;
+};
+
+template <>
+struct TensorTypeMap<int64_t> {
+  static constexpr ONNXTensorElementDataType value =
+      ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64;
+};
+
+template <>
+struct TensorTypeMap<uint64_t> {
+  static constexpr ONNXTensorElementDataType value =
+      ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64;
+};
+
+template <>
+struct TensorTypeMap<int8_t> {
+  static constexpr ONNXTensorElementDataType value =
+      ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8;
+};
+
+template <>
+struct TensorTypeMap<uint8_t> {
+  static constexpr ONNXTensorElementDataType value =
+      ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8;
+};
+
 }  // namespace
 
 // static
@@ -108,6 +169,42 @@
                           kUnderscore);
 }
 
+std::string GraphBuilderOrt::GenerateOperandName() {
+  next_operand_id_++;
+  CHECK(next_operand_id_.IsValid());
+  return base::JoinString(
+      {kInserted, base::NumberToString(
+                      static_cast<uint32_t>(next_operand_id_.ValueOrDie()))},
+      kUnderscore);
+}
+
+template <typename DataType>
+  requires internal::IsSupportedTensorType<DataType>
+std::string GraphBuilderOrt::CreateInitializer(
+    base::span<const int64_t> shape,
+    base::span<const DataType> data) {
+  std::string name = GenerateOperandName();
+  base::span<const uint8_t> byte_span;
+  if constexpr (std::floating_point<DataType>) {
+    // Floating point types do not have unique object representations, but
+    // this code appears to be using a byte span to type-erase, which is fine.
+    byte_span = base::as_byte_span(base::allow_nonunique_obj, data);
+  } else {
+    byte_span = base::as_byte_span(data);
+  }
+
+  model_editor_.AddInitializer(name, TensorTypeMap<DataType>::value, shape,
+                               byte_span);
+  return name;
+}
+
+template <typename DataType>
+  requires internal::IsSupportedTensorType<DataType>
+std::string GraphBuilderOrt::CreateScalarInitializer(const DataType& value) {
+  return CreateInitializer<DataType>(
+      /*shape=*/{}, base::span_from_ref(value));
+}
+
 template <typename T>
 void GraphBuilderOrt::AddBinaryOperation(const T& operation,
                                          base::cstring_view op_type) {
@@ -283,6 +380,86 @@
   }
 }
 
+void GraphBuilderOrt::AddClampOperation(const mojom::Clamp& clamp) {
+  const std::string node = GenerateOperationName(clamp.label);
+  const std::string input = GetOperandNameById(clamp.input_operand_id);
+  const std::string output = GetOperandNameById(clamp.output_operand_id);
+
+  const DataTypeLimits& data_type_limits = context_properties_.data_type_limits;
+  const OperandDescriptor& input_descriptor =
+      GetOperand(clamp.input_operand_id).descriptor;
+  CHECK(data_type_limits.clamp_input.Supports(input_descriptor));
+
+  const OperandDataType input_data_type = input_descriptor.data_type();
+
+  // Min and max are 0-D operands with the same data type of input.
+  std::string min;
+  std::string max;
+  switch (input_data_type) {
+    case OperandDataType::kFloat32: {
+      min = CreateScalarInitializer(clamp.min_value);
+      max = CreateScalarInitializer(clamp.max_value);
+      break;
+    }
+    case OperandDataType::kFloat16: {
+      min = CreateScalarInitializer(fp16_ieee_from_fp32_value(clamp.min_value));
+      max = CreateScalarInitializer(fp16_ieee_from_fp32_value(clamp.max_value));
+      break;
+    }
+    case OperandDataType::kInt32: {
+      min = CreateScalarInitializer(
+          base::saturated_cast<int32_t>(clamp.min_value));
+      max = CreateScalarInitializer(
+          base::saturated_cast<int32_t>(clamp.max_value));
+      break;
+    }
+    case OperandDataType::kUint32: {
+      min = CreateScalarInitializer(
+          base::saturated_cast<uint32_t>(clamp.min_value));
+      max = CreateScalarInitializer(
+          base::saturated_cast<uint32_t>(clamp.max_value));
+      break;
+    }
+    case OperandDataType::kInt64: {
+      min = CreateScalarInitializer(
+          base::saturated_cast<int64_t>(clamp.min_value));
+      max = CreateScalarInitializer(
+          base::saturated_cast<int64_t>(clamp.max_value));
+      break;
+    }
+    case OperandDataType::kUint64: {
+      min = CreateScalarInitializer(
+          base::saturated_cast<uint64_t>(clamp.min_value));
+      max = CreateScalarInitializer(
+          base::saturated_cast<uint64_t>(clamp.max_value));
+      break;
+    }
+    case OperandDataType::kInt8: {
+      min = CreateScalarInitializer(
+          base::saturated_cast<int8_t>(clamp.min_value));
+      max = CreateScalarInitializer(
+          base::saturated_cast<int8_t>(clamp.max_value));
+      break;
+    }
+    case OperandDataType::kUint8: {
+      min = CreateScalarInitializer(
+          base::saturated_cast<uint8_t>(clamp.min_value));
+      max = CreateScalarInitializer(
+          base::saturated_cast<uint8_t>(clamp.max_value));
+      break;
+    }
+    default: {
+      NOTREACHED() << "[WebNN] Clamp only supports data type float32, float16, "
+                      "int32, uint32, int64, uint64, int8 and uint8.";
+    }
+  }
+
+  std::array<const char*, 3> inputs = {input.c_str(), min.c_str(), max.c_str()};
+  std::array<const char*, 1> outputs = {output.c_str()};
+
+  model_editor_.AddNode(kOpTypeClamp, node, inputs, outputs);
+}
+
 void GraphBuilderOrt::AddGemmOperation(const mojom::Gemm& gemm) {
   const std::string node = GenerateOperationName(gemm.label);
   const std::string input_a = GetOperandNameById(gemm.a_operand_id);
@@ -415,8 +592,7 @@
                              mojom::ErrorPtr>
 GraphBuilderOrt::BuildModel() {
   for (OperandId input_id : graph_info_->input_operands) {
-    model_editor_.AddInput(GetOperandNameById(input_id),
-                           GetOperand(input_id).descriptor);
+    model_editor_.AddInput(GetOperandNameById(input_id), GetOperand(input_id));
   }
 
   for (auto& [constant_id, constant_operand] : constant_operands_) {
@@ -429,6 +605,10 @@
     const DataTypeLimits& data_type_limits =
         context_properties_.data_type_limits;
     switch (operation->which()) {
+      case mojom::Operation::Tag::kClamp: {
+        AddClampOperation(*operation->get_clamp());
+        break;
+      }
       case mojom::Operation::Tag::kElementWiseBinary: {
         AddElementWiseBinaryOperation(*operation->get_element_wise_binary());
         break;
@@ -485,7 +665,6 @@
       }
       case mojom::Operation::Tag::kArgMinMax:
       case mojom::Operation::Tag::kBatchNormalization:
-      case mojom::Operation::Tag::kClamp:
       case mojom::Operation::Tag::kConcat:
       case mojom::Operation::Tag::kConv2d:
       case mojom::Operation::Tag::kCumulativeSum:
@@ -528,7 +707,7 @@
 
   for (OperandId output_id : graph_info_->output_operands) {
     model_editor_.AddOutput(GetOperandNameById(output_id),
-                            GetOperand(output_id).descriptor);
+                            GetOperand(output_id));
   }
 
   return model_editor_.BuildAndTakeModelInfo();
diff --git a/services/webnn/ort/graph_builder_ort.h b/services/webnn/ort/graph_builder_ort.h
index 7350e89..b06bcd2 100644
--- a/services/webnn/ort/graph_builder_ort.h
+++ b/services/webnn/ort/graph_builder_ort.h
@@ -12,6 +12,7 @@
 #include "base/containers/span.h"
 #include "base/memory/raw_ref.h"
 #include "base/memory/stack_allocated.h"
+#include "base/numerics/checked_math.h"
 #include "base/strings/cstring_view.h"
 #include "base/types/expected.h"
 #include "services/webnn/ort/model_editor.h"
@@ -26,6 +27,26 @@
 
 namespace ort {
 
+namespace internal {
+
+// Supported tensor types for immediate values. The list can be expanded as
+// needed.
+template <typename T, typename... U>
+concept IsAnyOf = (std::same_as<T, U> || ...);
+
+template <typename T>
+concept IsSupportedTensorType = IsAnyOf<T,
+                                        float,
+                                        uint16_t,
+                                        int32_t,
+                                        uint32_t,
+                                        int64_t,
+                                        uint64_t,
+                                        int8_t,
+                                        uint8_t>;
+
+}  // namespace internal
+
 // This class converts WebNN graph to ORT model.
 //
 // The instances of the class may not be allocated on the heap, but as a member
@@ -64,17 +85,37 @@
   // Get the name of an existing operand by its id.
   std::string GetOperandNameById(OperandId operand_id) const;
 
+  // Generate the unique name of a newly created operand by combining a prefix
+  // "inserted" and `next_operand_id_`, and then increase `next_operand_id_`.
+  std::string GenerateOperandName();
+
   // Generate a unique name for a newly created operation by combining
   // `label` and `next_operation_id_`. ORT model doesn't allow duplicate
   // names.
   std::string GenerateOperationName(std::string_view label);
 
+  // Create a new initializer for the graph with the given shape and data,
+  // returning the name of the initializer.
+  template <typename DataType>
+    requires internal::IsSupportedTensorType<DataType>
+  std::string CreateInitializer(base::span<const int64_t> shape,
+                                base::span<const DataType> data);
+
+  // A helper method wrapping the `CreateInitializer` above. It creates a
+  // scalar initializer with the given scalar value (tensor of empty shape) to
+  // the graph, returning the name of the initializer.
+  template <typename DataType>
+    requires internal::IsSupportedTensorType<DataType>
+  std::string CreateScalarInitializer(const DataType& value);
+
   template <typename T>
   void AddBinaryOperation(const T& operation, base::cstring_view op_type);
   template <typename T>
   void AddUnaryOperation(const T& operation, base::cstring_view op_type);
 
   void AddCastOperation(const mojom::ElementWiseUnary& cast);
+
+  void AddClampOperation(const mojom::Clamp& clamp);
   void AddElementWiseBinaryOperation(
       const mojom::ElementWiseBinary& element_wise_binary);
   void AddElementWiseUnaryOperation(
@@ -87,6 +128,10 @@
   BuildModel();
 
   // An increasing id starting from 0, used for generating unique names for each
+  // operand.
+  base::CheckedNumeric<uint32_t> next_operand_id_ = 0;
+
+  // An increasing id starting from 0, used for generating unique names for each
   // operation.
   OperationId next_operation_id_ = 0;
 
diff --git a/services/webnn/ort/graph_impl_ort.cc b/services/webnn/ort/graph_impl_ort.cc
new file mode 100644
index 0000000..a342f6b
--- /dev/null
+++ b/services/webnn/ort/graph_impl_ort.cc
@@ -0,0 +1,307 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/webnn/ort/graph_impl_ort.h"
+
+#include "base/command_line.h"
+#include "base/notimplemented.h"
+#include "base/task/bind_post_task.h"
+#include "base/task/thread_pool.h"
+#include "base/types/expected_macros.h"
+#include "services/webnn/error.h"
+#include "services/webnn/ort/context_impl_ort.h"
+#include "services/webnn/ort/model_editor.h"
+#include "services/webnn/ort/ort_status.h"
+#include "services/webnn/ort/platform_functions_ort.h"
+#include "services/webnn/ort/scoped_ort_types.h"
+#include "services/webnn/ort/tensor_impl_ort.h"
+#include "services/webnn/public/mojom/webnn_context_provider.mojom.h"
+#include "services/webnn/public/mojom/webnn_error.mojom.h"
+#include "services/webnn/public/mojom/webnn_graph.mojom.h"
+#include "services/webnn/resource_task.h"
+#include "services/webnn/webnn_constant_operand.h"
+#include "services/webnn/webnn_graph_impl.h"
+#include "third_party/onnxruntime_headers/src/include/onnxruntime/core/session/onnxruntime_c_api.h"
+
+namespace webnn::ort {
+
+namespace {
+
+std::vector<std::pair<std::string,
+                      scoped_refptr<QueueableResourceState<BufferContentOrt>>>>
+ToNamedBufferStates(
+    const base::flat_map<std::string, WebNNTensorImpl*>& named_tensors) {
+  std::vector<std::pair<
+      std::string, scoped_refptr<QueueableResourceState<BufferContentOrt>>>>
+      buffer_states_vec;
+  buffer_states_vec.reserve(named_tensors.size());
+
+  for (const auto& [name, tensor] : named_tensors) {
+    buffer_states_vec.emplace_back(
+        name, static_cast<TensorImplOrt*>(tensor)->GetBufferState());
+  }
+
+  return buffer_states_vec;
+}
+
+}  // namespace
+
+// Represents the collection of resources associated with a particular graph.
+// These resources may outlive their associated `GraphImplOrt` instance while
+// executing the graph.
+class GraphImplOrt::ComputeResources {
+ public:
+  ComputeResources(ScopedOrtEnv env,
+                   ScopedOrtSession session,
+                   std::vector<base::HeapArray<uint8_t>> external_data,
+                   base::flat_map<std::string, std::string>
+                       operand_input_name_to_onnx_input_name,
+                   base::flat_map<std::string, std::string>
+                       operand_output_name_to_onnx_output_name)
+      : operand_input_name_to_onnx_input_name_(
+            std::move(operand_input_name_to_onnx_input_name)),
+        operand_output_name_to_onnx_output_name_(
+            std::move(operand_output_name_to_onnx_output_name)),
+        external_data_(std::move(external_data)),
+        env_(std::move(env)),
+        session_(std::move(session)) {}
+
+  ~ComputeResources() = default;
+
+  void OrtRunSync(
+      std::vector<std::pair<std::string, const OrtValue*>> named_input_tensors,
+      std::vector<std::pair<std::string, OrtValue*>> named_output_tensors) {
+    ScopedTrace scoped_trace("GraphImplOrt::ComputeResources::OrtRunSync");
+    std::vector<const char*> input_names;
+    std::vector<const OrtValue*> input_tensors;
+    input_names.reserve(named_input_tensors.size());
+    input_tensors.reserve(named_input_tensors.size());
+    for (const auto& [name, tensor] : named_input_tensors) {
+      input_names.push_back(
+          operand_input_name_to_onnx_input_name_.at(name).c_str());
+      input_tensors.push_back(tensor);
+    }
+
+    std::vector<const char*> output_names;
+    std::vector<OrtValue*> output_tensors;
+    output_names.reserve(named_output_tensors.size());
+    output_tensors.reserve(named_output_tensors.size());
+    for (const auto& [name, tensor] : named_output_tensors) {
+      output_names.push_back(
+          operand_output_name_to_onnx_output_name_.at(name).c_str());
+      output_tensors.push_back(tensor);
+    }
+
+    const OrtApi* ort_api = PlatformFunctions::GetInstance()->ort_api();
+    CHECK_STATUS(ort_api->Run(session_.get(), nullptr, input_names.data(),
+                              input_tensors.data(), input_names.size(),
+                              output_names.data(), output_names.size(),
+                              output_tensors.data()));
+  }
+
+ private:
+  base::flat_map<std::string, std::string>
+      operand_input_name_to_onnx_input_name_;
+  base::flat_map<std::string, std::string>
+      operand_output_name_to_onnx_output_name_;
+  std::vector<base::HeapArray<uint8_t>> external_data_;
+
+  // `env` should be prior to `session`. That ensures releasing `env` after
+  // releasing the session. This avoids unloading the providers DLLs being
+  // used during `session` destruction.
+  ScopedOrtEnv env_;
+  ScopedOrtSession session_;
+};
+
+// static
+void GraphImplOrt::CreateAndBuild(
+    mojo::PendingAssociatedReceiver<mojom::WebNNGraph> receiver,
+    mojom::GraphInfoPtr graph_info,
+    ComputeResourceInfo compute_resource_info,
+    base::flat_map<OperandId, std::unique_ptr<WebNNConstantOperand>>
+        constant_operands,
+    base::flat_map<OperandId, WebNNTensorImpl*> constant_tensor_operands,
+    ContextImplOrt* context,
+    WebNNContextImpl::CreateGraphImplCallback callback) {
+  ScopedTrace scoped_trace("GraphImplOrt::CreateAndBuild");
+
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE,
+      {base::TaskPriority::USER_BLOCKING,
+       base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN, base::MayBlock()},
+      base::BindOnce(&GraphImplOrt::CreateAndBuildOnBackgroundThread,
+                     std::move(graph_info), context->session_options(),
+                     context->properties(), std::move(constant_operands),
+                     std::move(scoped_trace)),
+      base::BindOnce(&GraphImplOrt::DidCreateAndBuild, std::move(receiver),
+                     context->AsWeakPtr(), std::move(compute_resource_info),
+                     std::move(callback)));
+}
+
+// static
+base::expected<std::unique_ptr<GraphImplOrt::ComputeResources>, mojom::ErrorPtr>
+GraphImplOrt::CreateAndBuildOnBackgroundThread(
+    mojom::GraphInfoPtr graph_info,
+    scoped_refptr<SessionOptions> session_options,
+    ContextProperties context_properties,
+    base::flat_map<OperandId, std::unique_ptr<WebNNConstantOperand>>
+        constant_operands,
+    ScopedTrace scoped_trace) {
+  scoped_trace.AddStep("Create model info");
+
+  ASSIGN_OR_RETURN(std::unique_ptr<ModelEditor::ModelInfo> model_info,
+                   GraphBuilderOrt::CreateAndBuild(
+                       *graph_info, std::move(context_properties),
+                       std::move(constant_operands)));
+
+  scoped_trace.AddStep("Initializing ORT");
+  // `CreateEnv()` will increase the reference count and return the reference of
+  // the existing `OrtEnv` instance that is created by context provider. `env`
+  // will be owned by `GraphImplOrt::Session` that ensures releasing `OrtEnv`
+  // reference after releasing `OrtSession`.
+  const OrtApi* ort_api = PlatformFunctions::GetInstance()->ort_api();
+  ScopedOrtEnv env;
+  if (ORT_CALL_FAILED(ort_api->CreateEnv(ORT_LOGGING_LEVEL_ERROR, "WebNN",
+                                         ScopedOrtEnv::Receiver(env).get()))) {
+    return base::unexpected(
+        mojom::Error::New(mojom::Error::Code::kUnknownError,
+                          "Failed to create the ONNX Runtime environment."));
+  }
+
+  scoped_trace.AddStep("Create session from model");
+  ScopedOrtSession session;
+  const OrtModelEditorApi* ort_model_editor_api =
+      PlatformFunctions::GetInstance()->ort_model_editor_api();
+  if (ORT_CALL_FAILED(ort_model_editor_api->CreateSessionFromModel(
+          env.get(), model_info->model.get(), session_options->get(),
+          ScopedOrtSession::Receiver(session).get()))) {
+    return base::unexpected(mojom::Error::New(mojom::Error::Code::kUnknownError,
+                                              "Failed to create session."));
+  }
+
+  scoped_trace.AddStep("Create compute resources");
+  return base::WrapUnique(new GraphImplOrt::ComputeResources(
+      std::move(env), std::move(session), std::move(model_info->external_data),
+      std::move(model_info->operand_input_name_to_onnx_input_name),
+      std::move(model_info->operand_output_name_to_onnx_output_name)));
+}
+
+// static
+void GraphImplOrt::DidCreateAndBuild(
+    mojo::PendingAssociatedReceiver<mojom::WebNNGraph> receiver,
+    base::WeakPtr<WebNNContextImpl> context,
+    ComputeResourceInfo compute_resource_info,
+    WebNNContextImpl::CreateGraphImplCallback callback,
+    base::expected<std::unique_ptr<GraphImplOrt::ComputeResources>,
+                   mojom::ErrorPtr> result) {
+  if (!context) {
+    return;
+  }
+
+  if (!result.has_value()) {
+    std::move(callback).Run(base::unexpected(std::move(result.error())));
+    return;
+  }
+
+  // TODO(crbug.com/418031018): Get devices that will be used for dispatch.
+  std::move(callback).Run(base::WrapUnique(new GraphImplOrt(
+      std::move(receiver), std::move(compute_resource_info),
+      std::move(result.value()), static_cast<ContextImplOrt*>(context.get()),
+      /*devices=*/{})));
+}
+
+GraphImplOrt::~GraphImplOrt() = default;
+
+GraphImplOrt::GraphImplOrt(
+    mojo::PendingAssociatedReceiver<mojom::WebNNGraph> receiver,
+    ComputeResourceInfo compute_resource_info,
+    std::unique_ptr<GraphImplOrt::ComputeResources> compute_resources,
+    ContextImplOrt* context,
+    std::vector<mojom::Device> devices)
+    : WebNNGraphImpl(std::move(receiver),
+                     context,
+                     std::move(compute_resource_info),
+                     std::move(devices)) {
+  compute_resources_state_ =
+      base::MakeRefCounted<QueueableResourceState<ComputeResources>>(
+          std::move(compute_resources));
+}
+
+void GraphImplOrt::DispatchImpl(
+    base::flat_map<std::string, WebNNTensorImpl*> named_input_tensors,
+    base::flat_map<std::string, WebNNTensorImpl*> named_output_tensors) {
+  ScopedTrace scoped_trace("GraphImplOrt::DispatchImpl");
+  std::vector<std::pair<
+      std::string, scoped_refptr<QueueableResourceState<BufferContentOrt>>>>
+      named_input_buffer_states = ToNamedBufferStates(named_input_tensors);
+  std::vector<std::pair<
+      std::string, scoped_refptr<QueueableResourceState<BufferContentOrt>>>>
+      named_output_buffer_states = ToNamedBufferStates(named_output_tensors);
+
+  // Input tensors will be read from while the graph is executing, so lock them
+  // them as shared/read-only.
+  std::vector<scoped_refptr<QueueableResourceStateBase>> shared_resources;
+  shared_resources.reserve(named_input_tensors.size());
+  for (const auto& [_, buffer_state] : named_input_buffer_states) {
+    shared_resources.push_back(buffer_state);
+  }
+
+  // Exclusively reserve all output tensors, which will be written to.
+  std::vector<scoped_refptr<QueueableResourceStateBase>> exclusive_resources;
+  // Extra +1 is for the compute resources.
+  exclusive_resources.reserve(1 + named_output_tensors.size());
+  exclusive_resources.push_back(compute_resources_state_);
+  for (const auto& [_, buffer_state] : named_output_buffer_states) {
+    exclusive_resources.push_back(buffer_state);
+  }
+
+  auto task = base::MakeRefCounted<ResourceTask>(
+      std::move(shared_resources), std::move(exclusive_resources),
+      base::BindOnce(
+          [](scoped_refptr<QueueableResourceState<ComputeResources>>
+                 compute_resources_state,
+             std::vector<std::pair<
+                 std::string,
+                 scoped_refptr<QueueableResourceState<BufferContentOrt>>>>
+                 named_input_buffer_states,
+             std::vector<std::pair<
+                 std::string,
+                 scoped_refptr<QueueableResourceState<BufferContentOrt>>>>
+                 named_output_buffer_states,
+             base::OnceClosure completion_closure) {
+            ComputeResources* raw_compute_resources =
+                compute_resources_state->GetExclusivelyLockedResource();
+
+            std::vector<std::pair<std::string, const OrtValue*>>
+                named_input_tensors;
+            named_input_tensors.reserve(named_input_buffer_states.size());
+            std::vector<std::pair<std::string, OrtValue*>> named_output_tensors;
+            named_output_tensors.reserve(named_output_buffer_states.size());
+
+            for (const auto& [name, buffer] : named_input_buffer_states) {
+              named_input_tensors.emplace_back(
+                  name, buffer->GetSharedLockedResource().tensor());
+            }
+            for (const auto& [name, buffer] : named_output_buffer_states) {
+              named_output_tensors.emplace_back(
+                  name, buffer->GetExclusivelyLockedResource()->tensor());
+            }
+
+            // Compute tasks can take a significant amount of time, use the
+            // thread pool to avoid blocking the main thread.
+            base::ThreadPool::PostTaskAndReply(
+                FROM_HERE,
+                base::BindOnce(&ComputeResources::OrtRunSync,
+                               base::Unretained(raw_compute_resources),
+                               std::move(named_input_tensors),
+                               std::move(named_output_tensors)),
+                std::move(completion_closure));
+          },
+          compute_resources_state_, std::move(named_input_buffer_states),
+          std::move(named_output_buffer_states)));
+
+  task->Enqueue();
+}
+
+}  // namespace webnn::ort
diff --git a/services/webnn/ort/graph_impl_ort.h b/services/webnn/ort/graph_impl_ort.h
new file mode 100644
index 0000000..4f16407
--- /dev/null
+++ b/services/webnn/ort/graph_impl_ort.h
@@ -0,0 +1,93 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_WEBNN_ORT_GRAPH_IMPL_ORT_H_
+#define SERVICES_WEBNN_ORT_GRAPH_IMPL_ORT_H_
+
+#include <memory>
+#include <string>
+
+#include "base/containers/flat_map.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/types/expected.h"
+#include "services/webnn/ort/graph_builder_ort.h"
+#include "services/webnn/public/cpp/webnn_trace.h"
+#include "services/webnn/public/mojom/webnn_error.mojom-forward.h"
+#include "services/webnn/public/mojom/webnn_graph.mojom-forward.h"
+#include "services/webnn/queueable_resource_state.h"
+#include "services/webnn/webnn_context_impl.h"
+#include "services/webnn/webnn_graph_impl.h"
+
+namespace webnn {
+
+class WebNNConstantOperand;
+
+namespace ort {
+
+class ContextImplOrt;
+class SessionOptions;
+
+// GraphImplOrt inherits from WebNNGraphImpl to represent an ORT graph
+// implementation. It is mainly responsible for building an ORT
+// model from mojom::GraphInfo via ort::GraphBuilderOrt, then executing the
+// graph.
+class GraphImplOrt final : public WebNNGraphImpl {
+ public:
+  static void CreateAndBuild(
+      mojo::PendingAssociatedReceiver<mojom::WebNNGraph> receiver,
+      mojom::GraphInfoPtr graph_info,
+      ComputeResourceInfo compute_resource_info,
+      base::flat_map<OperandId, std::unique_ptr<WebNNConstantOperand>>
+          constant_operands,
+      base::flat_map<OperandId, WebNNTensorImpl*> constant_tensor_operands,
+      ContextImplOrt* context,
+      WebNNContextImpl::CreateGraphImplCallback callback);
+
+  GraphImplOrt(const GraphImplOrt&) = delete;
+  GraphImplOrt& operator=(const GraphImplOrt&) = delete;
+  ~GraphImplOrt() override;
+
+ private:
+  class ComputeResources;
+
+  GraphImplOrt(mojo::PendingAssociatedReceiver<mojom::WebNNGraph> receiver,
+               ComputeResourceInfo compute_resource_info,
+               std::unique_ptr<ComputeResources> compute_resources,
+               ContextImplOrt* context,
+               std::vector<mojom::Device> devices);
+
+  static base::expected<std::unique_ptr<ComputeResources>, mojom::ErrorPtr>
+  CreateAndBuildOnBackgroundThread(
+      mojom::GraphInfoPtr graph_info,
+      scoped_refptr<SessionOptions> session_options,
+      ContextProperties context_properties,
+      base::flat_map<OperandId, std::unique_ptr<WebNNConstantOperand>>
+          constant_operands,
+      ScopedTrace scoped_trace);
+
+  static void DidCreateAndBuild(
+      mojo::PendingAssociatedReceiver<mojom::WebNNGraph> receiver,
+      base::WeakPtr<WebNNContextImpl> context,
+      ComputeResourceInfo compute_resource_info,
+      WebNNContextImpl::CreateGraphImplCallback callback,
+      base::expected<std::unique_ptr<ComputeResources>, mojom::ErrorPtr>
+          result);
+
+  // Execute the compiled platform graph asynchronously. The inputs were
+  // validated in base class so we can use them to compute directly.
+  void DispatchImpl(
+      base::flat_map<std::string, WebNNTensorImpl*> named_input_tensors,
+      base::flat_map<std::string, WebNNTensorImpl*> named_output_tensors)
+      override;
+
+  scoped_refptr<QueueableResourceState<ComputeResources>>
+      compute_resources_state_;
+  base::WeakPtrFactory<GraphImplOrt> weak_factory_{this};
+};
+
+}  // namespace ort
+}  // namespace webnn
+
+#endif  // SERVICES_WEBNN_ORT_GRAPH_IMPL_ORT_H_
diff --git a/services/webnn/ort/model_editor.cc b/services/webnn/ort/model_editor.cc
index 93990ab..efd6715 100644
--- a/services/webnn/ort/model_editor.cc
+++ b/services/webnn/ort/model_editor.cc
@@ -90,15 +90,21 @@
 ModelEditor::~ModelEditor() = default;
 
 void ModelEditor::AddInput(base::cstring_view name,
-                           const OperandDescriptor& descriptor) {
+                           const mojom::Operand& input) {
   CHECK(!has_built_);
-  inputs_.push_back(CreateOrtValueInfo(name, descriptor));
+  inputs_.push_back(CreateOrtValueInfo(name, input.descriptor));
+  CHECK(input.name.has_value());
+  operand_input_name_to_onnx_input_name_map.emplace_back(input.name.value(),
+                                                         name);
 }
 
 void ModelEditor::AddOutput(base::cstring_view name,
-                            const OperandDescriptor& descriptor) {
+                            const mojom::Operand& output) {
   CHECK(!has_built_);
-  outputs_.push_back(CreateOrtValueInfo(name, descriptor));
+  outputs_.push_back(CreateOrtValueInfo(name, output.descriptor));
+  CHECK(output.name.has_value());
+  operand_output_name_to_onnx_output_name_map.emplace_back(output.name.value(),
+                                                           name);
 }
 
 void ModelEditor::AddInitializer(
@@ -127,6 +133,9 @@
                                  base::span<const uint8_t> data) {
   CHECK(!has_built_);
 
+  // TODO(crbug.com/423673304): After enabling OV EP, we need to add a
+  // workaround here since in-memory external data support for OV is still
+  // on-going.
   bool use_external_data = data.size() >= kMinExternalDataSize;
   if (use_external_data) {
     AddInitializerAsExternalData(name, data_type, shape,
@@ -301,6 +310,13 @@
 
   has_built_ = true;
 
+  model_info_->operand_input_name_to_onnx_input_name =
+      base::flat_map<std::string, std::string>(
+          std::move(operand_input_name_to_onnx_input_name_map));
+  model_info_->operand_output_name_to_onnx_output_name =
+      base::flat_map<std::string, std::string>(
+          std::move(operand_output_name_to_onnx_output_name_map));
+
   return std::move(model_info_);
 }
 
diff --git a/services/webnn/ort/model_editor.h b/services/webnn/ort/model_editor.h
index 5c0d963..0abe0f2 100644
--- a/services/webnn/ort/model_editor.h
+++ b/services/webnn/ort/model_editor.h
@@ -10,11 +10,13 @@
 #include <vector>
 
 #include "base/component_export.h"
+#include "base/containers/flat_map.h"
 #include "base/containers/heap_array.h"
 #include "base/containers/span.h"
 #include "base/strings/cstring_view.h"
 #include "services/webnn/ort/scoped_ort_types.h"
 #include "services/webnn/public/cpp/operand_descriptor.h"
+#include "services/webnn/public/mojom/webnn_graph.mojom.h"
 #include "services/webnn/webnn_constant_operand.h"
 
 namespace webnn::ort {
@@ -30,6 +32,10 @@
     ScopedOrtModel model;
     // The external data should be kept alive during graph inferencing.
     std::vector<base::HeapArray<uint8_t>> external_data;
+    base::flat_map<std::string, std::string>
+        operand_input_name_to_onnx_input_name;
+    base::flat_map<std::string, std::string>
+        operand_output_name_to_onnx_output_name;
   };
 
   ModelEditor();
@@ -37,9 +43,9 @@
   ModelEditor(const ModelEditor&) = delete;
   ModelEditor& operator=(const ModelEditor&) = delete;
 
-  void AddInput(base::cstring_view name, const OperandDescriptor& descriptor);
+  void AddInput(base::cstring_view name, const mojom::Operand& input);
 
-  void AddOutput(base::cstring_view name, const OperandDescriptor& descriptor);
+  void AddOutput(base::cstring_view name, const mojom::Operand& output);
 
   void AddInitializer(base::cstring_view name,
                       std::unique_ptr<WebNNConstantOperand> constant_operand);
@@ -97,6 +103,11 @@
   std::unique_ptr<ModelInfo> model_info_;
 
   bool has_built_ = false;
+
+  std::vector<std::pair<std::string, std::string>>
+      operand_input_name_to_onnx_input_name_map;
+  std::vector<std::pair<std::string, std::string>>
+      operand_output_name_to_onnx_output_name_map;
 };
 
 }  // namespace webnn::ort
diff --git a/services/webnn/ort/model_editor_test.cc b/services/webnn/ort/model_editor_test.cc
index 5fd8153..509cba9 100644
--- a/services/webnn/ort/model_editor_test.cc
+++ b/services/webnn/ort/model_editor_test.cc
@@ -28,7 +28,10 @@
   auto input_desc = OperandDescriptor::CreateForDeserialization(
       OperandDataType::kUint32, {4, 2, 4});
   ASSERT_TRUE(input_desc.has_value());
-  model_editor.AddInput(input, input_desc.value());
+  mojom::OperandPtr input_operand =
+      mojom::Operand::New(mojom::Operand::Kind::kInput,
+                          std::move(input_desc.value()), "input_operand");
+  model_editor.AddInput(input, *input_operand);
 
   // Add two initializers.
   constexpr base::cstring_view add_initializer = "add_initializer";
@@ -81,9 +84,13 @@
       gather_outputs, gather_attrs);
 
   // Add an output.
-  model_editor.AddOutput(output, OperandDescriptor::CreateForDeserialization(
-                                     OperandDataType::kUint32, {4, 4, 4})
-                                     .value());
+  auto output_desc = OperandDescriptor::CreateForDeserialization(
+      OperandDataType::kUint32, {4, 4, 4});
+  ASSERT_TRUE(output_desc.has_value());
+  mojom::OperandPtr output_operand =
+      mojom::Operand::New(mojom::Operand::Kind::kOutput,
+                          std::move(output_desc.value()), "output_operand");
+  model_editor.AddOutput(output, *output_operand);
 
   std::unique_ptr<ModelEditor::ModelInfo> model_info =
       model_editor.BuildAndTakeModelInfo();
@@ -103,7 +110,10 @@
   auto input_desc = OperandDescriptor::CreateForDeserialization(
       OperandDataType::kInt32, {1, 1, 1, 1});
   ASSERT_TRUE(input_desc.has_value());
-  model_editor.AddInput(input, input_desc.value());
+  mojom::OperandPtr input_operand =
+      mojom::Operand::New(mojom::Operand::Kind::kInput,
+                          std::move(input_desc.value()), "input_operand");
+  model_editor.AddInput(input, *input_operand);
 
   // Add an initializer which is an empty tensor that represents an empty shape
   // of a scalar.
@@ -125,7 +135,10 @@
   auto output_desc =
       OperandDescriptor::CreateForDeserialization(OperandDataType::kInt32, {});
   ASSERT_TRUE(output_desc.has_value());
-  model_editor.AddOutput(output, output_desc.value());
+  mojom::OperandPtr output_operand =
+      mojom::Operand::New(mojom::Operand::Kind::kOutput,
+                          std::move(output_desc.value()), "output_operand");
+  model_editor.AddOutput(output, *output_operand);
 
   std::unique_ptr<ModelEditor::ModelInfo> model_info =
       model_editor.BuildAndTakeModelInfo();
diff --git a/services/webnn/ort/ort_session_options.cc b/services/webnn/ort/ort_session_options.cc
index 8b732ac..55fea2e 100644
--- a/services/webnn/ort/ort_session_options.cc
+++ b/services/webnn/ort/ort_session_options.cc
@@ -4,11 +4,14 @@
 
 #include "services/webnn/ort/ort_session_options.h"
 
+#include "base/command_line.h"
+#include "base/strings/stringprintf.h"
 #include "services/webnn/ort/ort_status.h"
 #include "services/webnn/ort/platform_functions_ort.h"
 #include "services/webnn/public/cpp/webnn_trace.h"
 #include "services/webnn/public/mojom/webnn_device.mojom.h"
 #include "services/webnn/public/mojom/webnn_error.mojom.h"
+#include "services/webnn/webnn_switches.h"
 #include "third_party/onnxruntime_headers/src/include/onnxruntime/core/session/onnxruntime_session_options_config_keys.h"
 
 namespace webnn::ort {
@@ -29,8 +32,18 @@
   ScopedOrtSessionOptions session_options;
   CHECK_STATUS(ort_api->CreateSessionOptions(
       ScopedOrtSessionOptions::Receiver(session_options).get()));
-  // TODO(crbug.com/416539420): Add a switch to dump model once ORT backend can
-  // build a model.
+
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kWebNNOrtDumpModel)) {
+    static uint64_t dump_count = 0;
+    base::FilePath dump_directory =
+        base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+            switches::kWebNNOrtDumpModel);
+    base::FilePath dump_path = dump_directory.AppendASCII(
+        base::StringPrintf("model%d.onnx", dump_count++));
+    CHECK_STATUS(ort_api->SetOptimizedModelFilePath(session_options.get(),
+                                                    dump_path.value().c_str()));
+  }
 
   // Enable strict shape type inference check. All inconsistencies encountered
   // will expose errors during session creation. For example, if the graph
diff --git a/services/webnn/ort/scoped_ort_types.h b/services/webnn/ort/scoped_ort_types.h
index aad9423..138a723 100644
--- a/services/webnn/ort/scoped_ort_types.h
+++ b/services/webnn/ort/scoped_ort_types.h
@@ -34,6 +34,13 @@
 };
 
 template <>
+struct ScopedOrtTypeTraitsHelper<OrtSession*> {
+  static void Free(OrtSession* value) {
+    PlatformFunctions::GetInstance()->ort_api()->ReleaseSession(value);
+  }
+};
+
+template <>
 struct ScopedOrtTypeTraitsHelper<OrtSessionOptions*> {
   static void Free(OrtSessionOptions* value) {
     PlatformFunctions::GetInstance()->ort_api()->ReleaseSessionOptions(value);
@@ -117,6 +124,7 @@
 }  // namespace internal
 
 using ScopedOrtEnv = internal::ScopedOrtType<OrtEnv>;
+using ScopedOrtSession = internal::ScopedOrtType<OrtSession>;
 using ScopedOrtSessionOptions = internal::ScopedOrtType<OrtSessionOptions>;
 using ScopedOrtStatus = internal::ScopedOrtType<OrtStatus>;
 using ScopedOrtValue = internal::ScopedOrtType<OrtValue>;
diff --git a/services/webnn/webnn_switches.h b/services/webnn/webnn_switches.h
index e7773582..515f44c5 100644
--- a/services/webnn/webnn_switches.h
+++ b/services/webnn/webnn_switches.h
@@ -32,6 +32,10 @@
 // Other severity levels could be "INFO", "WARNING", "ERROR" (default), and
 // "FATAL".
 inline constexpr char kWebNNOrtLoggingLevel[] = "webnn-ort-logging-level";
+// Set the folder specified by --webnn-ort-dump-model for ONNX Runtime to save
+// optimized ONNX model after graph level transformations.
+// Usage: --no-sandbox --webnn-ort-dump-model=/tmp/ort_models
+inline constexpr char kWebNNOrtDumpModel[] = "webnn-ort-dump-model";
 #endif  // BUILDFLAG(IS_WIN)
 
 }  // namespace switches
diff --git a/storage/browser/blob/features.cc b/storage/browser/blob/features.cc
index 627acff..c3d9ed0 100644
--- a/storage/browser/blob/features.cc
+++ b/storage/browser/blob/features.cc
@@ -4,12 +4,20 @@
 
 #include "storage/browser/blob/features.h"
 
+#include "build/buildflag.h"
+
 namespace features {
 
 // Please keep features in alphabetical order.
 BASE_FEATURE(kBlockCrossPartitionBlobUrlFetching,
              "BlockCrossPartitionBlobUrlFetching",
+// TODO(crbug.com/421810301): Temporarily disable this feature on ChromeOS due
+// to a regression.
+#if BUILDFLAG(IS_CHROMEOS)
+             base::FEATURE_DISABLED_BY_DEFAULT);
+#else
              base::FEATURE_ENABLED_BY_DEFAULT);
+#endif
 
 // Please keep features in alphabetical order.
 
diff --git a/testing/buildbot/filters/android.emulator.media_unittests.filter b/testing/buildbot/filters/android.emulator.media_unittests.filter
index 58f97f7..bb9be25 100644
--- a/testing/buildbot/filters/android.emulator.media_unittests.filter
+++ b/testing/buildbot/filters/android.emulator.media_unittests.filter
@@ -7,3 +7,6 @@
 -AllNdkEncoderTests/NdkVideoEncoderAcceleratorTest.HandleEncodingError/h264_baseline__PIXEL_FORMAT_NV12
 -AllNdkEncoderTests/NdkVideoEncoderAcceleratorTest.HandleEncodingError/h264_main__PIXEL_FORMAT_I420
 -AllNdkEncoderTests/NdkVideoEncoderAcceleratorTest.HandleEncodingError/h264_baseline__PIXEL_FORMAT_I420
+
+# https://crbug.com/391490503
+-AAC/AACAudioEncoderTest.*
diff --git a/testing/libfuzzer/fuzztest_wrapper.cpp b/testing/libfuzzer/fuzztest_wrapper.cpp
index fed72cd..87ba37b 100644
--- a/testing/libfuzzer/fuzztest_wrapper.cpp
+++ b/testing/libfuzzer/fuzztest_wrapper.cpp
@@ -15,6 +15,7 @@
 #include "base/process/launch.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
+#include "base/strings/utf_ostream_operators.h"
 #include "base/strings/utf_string_conversions.h"
 #include "testing/libfuzzer/fuzztest_wrapper_buildflags.h"
 
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 01c0ae7..2598697 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -16336,6 +16336,7 @@
                 {
                     "name": "Enabled",
                     "params": {
+                        "autofill_address": "true",
                         "lens_overlay": "true",
                         "memory_saver": "true",
                         "offer_notification": "true",
diff --git a/third_party/abseil-cpp/absl/base/BUILD.gn b/third_party/abseil-cpp/absl/base/BUILD.gn
index 6f581bf..98e75941 100644
--- a/third_party/abseil-cpp/absl/base/BUILD.gn
+++ b/third_party/abseil-cpp/absl/base/BUILD.gn
@@ -37,7 +37,6 @@
 }
 
 absl_source_set("nullability") {
-  sources = [ "internal/nullability_deprecated.h" ]
   public = [ "nullability.h" ]
   deps = [
     ":config",
diff --git a/third_party/abseil-cpp/absl/base/internal/nullability_deprecated.h b/third_party/abseil-cpp/absl/base/internal/nullability_deprecated.h
deleted file mode 100644
index 1cd20c25..0000000
--- a/third_party/abseil-cpp/absl/base/internal/nullability_deprecated.h
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2023 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-#ifndef ABSL_BASE_INTERNAL_NULLABILITY_DEPRECATED_H_
-#define ABSL_BASE_INTERNAL_NULLABILITY_DEPRECATED_H_
-
-#include "absl/base/attributes.h"
-#include "absl/base/config.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace nullability_internal {
-
-template <typename T>
-using NullableImpl
-#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
-    [[clang::annotate("Nullable")]]
-#endif
-// Don't add the _Nullable attribute in Objective-C compiles. Many Objective-C
-// projects enable the `-Wnullable-to-nonnull-conversion warning`, which is
-// liable to produce false positives.
-#if ABSL_HAVE_FEATURE(nullability_on_classes) && !defined(__OBJC__)
-    = T _Nullable;
-#else
-    = T;
-#endif
-
-template <typename T>
-using NonnullImpl
-#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
-    [[clang::annotate("Nonnull")]]
-#endif
-#if ABSL_HAVE_FEATURE(nullability_on_classes) && !defined(__OBJC__)
-    = T _Nonnull;
-#else
-    = T;
-#endif
-
-template <typename T>
-using NullabilityUnknownImpl
-#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
-    [[clang::annotate("Nullability_Unspecified")]]
-#endif
-#if ABSL_HAVE_FEATURE(nullability_on_classes) && !defined(__OBJC__)
-    = T _Null_unspecified;
-#else
-    = T;
-#endif
-
-}  // namespace nullability_internal
-
-// The following template aliases are deprecated forms of nullability
-// annotations. They have some limitations, for example, an incompatibility with
-// `auto*` pointers, as `auto` cannot be used in a template argument.
-//
-// It is important to note that these annotations are not distinct strong
-// *types*. They are alias templates defined to be equal to the underlying
-// pointer type. A pointer annotated `Nonnull<T*>`, for example, is simply a
-// pointer of type `T*`.
-//
-// Prefer the macro style annotations in `absl/base/nullability.h` instead.
-
-// absl::Nonnull, analogous to absl_nonnull
-//
-// Example:
-// absl::Nonnull<int*> foo;
-// Is equivalent to:
-// int* absl_nonnull foo;
-template <typename T>
-using Nonnull =
-    nullability_internal::NonnullImpl<T>;
-
-// absl::Nullable, analogous to absl_nullable
-//
-// Example:
-// absl::Nullable<int*> foo;
-// Is equivalent to:
-// int* absl_nullable foo;
-template <typename T>
-using Nullable =
-    nullability_internal::NullableImpl<T>;
-
-// absl::NullabilityUnknown, analogous to absl_nullability_unknown
-//
-// Example:
-// absl::NullabilityUnknown<int*> foo;
-// Is equivalent to:
-// int* absl_nullability_unknown foo;
-template <typename T>
-using NullabilityUnknown =
-    nullability_internal::NullabilityUnknownImpl<T>;
-
-ABSL_NAMESPACE_END
-}  // namespace absl
-
-#endif  // ABSL_BASE_INTERNAL_NULLABILITY_DEPRECATED_H_
-
diff --git a/third_party/abseil-cpp/absl/base/nullability.h b/third_party/abseil-cpp/absl/base/nullability.h
index 3a5d6e8..2796a361 100644
--- a/third_party/abseil-cpp/absl/base/nullability.h
+++ b/third_party/abseil-cpp/absl/base/nullability.h
@@ -184,7 +184,6 @@
 #define ABSL_BASE_NULLABILITY_H_
 
 #include "absl/base/config.h"
-#include "absl/base/internal/nullability_deprecated.h"
 
 // ABSL_POINTERS_DEFAULT_NONNULL
 //
diff --git a/third_party/abseil-cpp/absl/base/nullability_test.cc b/third_party/abseil-cpp/absl/base/nullability_test.cc
index bccc388..bccf1af4 100644
--- a/third_party/abseil-cpp/absl/base/nullability_test.cc
+++ b/third_party/abseil-cpp/absl/base/nullability_test.cc
@@ -14,16 +14,13 @@
 
 #include "absl/base/nullability.h"
 
-#include <cassert>
 #include <memory>
 #include <type_traits>
 #include <utility>
 
 #include "gtest/gtest.h"
-#include "absl/base/attributes.h"
 
 namespace {
-namespace macro_annotations {
 void funcWithNonnullArg(int* absl_nonnull /*arg*/) {}
 template <typename T>
 void funcWithDeducedNonnullArg(T* absl_nonnull /*arg*/) {}
@@ -90,117 +87,4 @@
   EXPECT_TRUE((std::is_same<absl_nullable T, T>::value));
   EXPECT_TRUE((std::is_same<absl_nullability_unknown T, T>::value));
 }
-}  // namespace macro_annotations
-
-// Allow testing of the deprecated type alias annotations.
-ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
-
-using ::absl::Nonnull;
-using ::absl::NullabilityUnknown;
-using ::absl::Nullable;
-namespace type_alias_annotations {
-
-void funcWithNonnullArg(Nonnull<int*> /*arg*/) {}
-template <typename T>
-void funcWithDeducedNonnullArg(Nonnull<T*> /*arg*/) {}
-
-TEST(NonnullTest, NonnullArgument) {
-  int var = 0;
-  funcWithNonnullArg(&var);
-  funcWithDeducedNonnullArg(&var);
-}
-
-Nonnull<int*> funcWithNonnullReturn() {
-  static int var = 0;
-  return &var;
-}
-
-TEST(NonnullTest, NonnullReturn) {
-  auto var = funcWithNonnullReturn();
-  (void)var;
-}
-
-TEST(PassThroughTest, PassesThroughRawPointerToInt) {
-  EXPECT_TRUE((std::is_same<Nonnull<int*>, int*>::value));
-  EXPECT_TRUE((std::is_same<Nullable<int*>, int*>::value));
-  EXPECT_TRUE((std::is_same<NullabilityUnknown<int*>, int*>::value));
-}
-
-TEST(PassThroughTest, PassesThroughRawPointerToVoid) {
-  EXPECT_TRUE((std::is_same<Nonnull<void*>, void*>::value));
-  EXPECT_TRUE((std::is_same<Nullable<void*>, void*>::value));
-  EXPECT_TRUE((std::is_same<NullabilityUnknown<void*>, void*>::value));
-}
-
-TEST(PassThroughTest, PassesThroughUniquePointerToInt) {
-  using T = std::unique_ptr<int>;
-  EXPECT_TRUE((std::is_same<Nonnull<T>, T>::value));
-  EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
-  EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
-}
-
-TEST(PassThroughTest, PassesThroughSharedPointerToInt) {
-  using T = std::shared_ptr<int>;
-  EXPECT_TRUE((std::is_same<Nonnull<T>, T>::value));
-  EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
-  EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
-}
-
-TEST(PassThroughTest, PassesThroughSharedPointerToVoid) {
-  using T = std::shared_ptr<void>;
-  EXPECT_TRUE((std::is_same<Nonnull<T>, T>::value));
-  EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
-  EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
-}
-
-TEST(PassThroughTest, PassesThroughPointerToMemberObject) {
-  using T = decltype(&std::pair<int, int>::first);
-  EXPECT_TRUE((std::is_same<Nonnull<T>, T>::value));
-  EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
-  EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
-}
-
-TEST(PassThroughTest, PassesThroughPointerToMemberFunction) {
-  using T = decltype(&std::unique_ptr<int>::reset);
-  EXPECT_TRUE((std::is_same<Nonnull<T>, T>::value));
-  EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
-  EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
-}
-
-}  // namespace type_alias_annotations
-}  // namespace
-
-// Nullable ADL lookup test
-namespace util {
-// Helper for NullableAdlTest.  Returns true, denoting that argument-dependent
-// lookup found this implementation of DidAdlWin.  Must be in namespace
-// util itself, not a nested anonymous namespace.
-template <typename T>
-bool DidAdlWin(T*) {
-  return true;
-}
-
-// Because this type is defined in namespace util, an unqualified call to
-// DidAdlWin with a pointer to MakeAdlWin will find the above implementation.
-struct MakeAdlWin {};
-}  // namespace util
-
-namespace {
-// Returns false, denoting that ADL did not inspect namespace util.  If it
-// had, the better match (T*) above would have won out over the (...) here.
-bool DidAdlWin(...) { return false; }
-
-TEST(NullableAdlTest, NullableAddsNothingToArgumentDependentLookup) {
-  // Treatment: util::Nullable<int*> contributes nothing to ADL because
-  // int* itself doesn't.
-  EXPECT_FALSE(DidAdlWin((int*)nullptr));
-  EXPECT_FALSE(DidAdlWin((Nullable<int*>)nullptr));
-
-  // Control: Argument-dependent lookup does find the implementation in
-  // namespace util when the underlying pointee type resides there.
-  EXPECT_TRUE(DidAdlWin((util::MakeAdlWin*)nullptr));
-  EXPECT_TRUE(DidAdlWin((Nullable<util::MakeAdlWin*>)nullptr));
-}
-
-ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
 }  // namespace
diff --git a/third_party/abseil-cpp/patches/0004-add-deprecated-nullability.patch b/third_party/abseil-cpp/patches/0004-add-deprecated-nullability.patch
deleted file mode 100644
index 82f4260..0000000
--- a/third_party/abseil-cpp/patches/0004-add-deprecated-nullability.patch
+++ /dev/null
@@ -1,270 +0,0 @@
-TODO: crbug.com/412943761 - Remove deprecated nullability once third_party deps
-stop depending on it.
-
-diff --git a/third_party/abseil-cpp/absl/base/internal/nullability_deprecated.h b/third_party/abseil-cpp/absl/base/internal/nullability_deprecated.h
-new file mode 100644
-index 0000000000000..1cd20c259f4c4
---- /dev/null
-+++ b/third_party/abseil-cpp/absl/base/internal/nullability_deprecated.h
-@@ -0,0 +1,107 @@
-+// Copyright 2023 The Abseil Authors.
-+//
-+// Licensed under the Apache License, Version 2.0 (the "License");
-+// you may not use this file except in compliance with the License.
-+// You may obtain a copy of the License at
-+//
-+//      https://www.apache.org/licenses/LICENSE-2.0
-+//
-+// Unless required by applicable law or agreed to in writing, software
-+// distributed under the License is distributed on an "AS IS" BASIS,
-+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+// See the License for the specific language governing permissions and
-+// limitations under the License.
-+#ifndef ABSL_BASE_INTERNAL_NULLABILITY_DEPRECATED_H_
-+#define ABSL_BASE_INTERNAL_NULLABILITY_DEPRECATED_H_
-+
-+#include "absl/base/attributes.h"
-+#include "absl/base/config.h"
-+
-+namespace absl {
-+ABSL_NAMESPACE_BEGIN
-+namespace nullability_internal {
-+
-+template <typename T>
-+using NullableImpl
-+#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
-+    [[clang::annotate("Nullable")]]
-+#endif
-+// Don't add the _Nullable attribute in Objective-C compiles. Many Objective-C
-+// projects enable the `-Wnullable-to-nonnull-conversion warning`, which is
-+// liable to produce false positives.
-+#if ABSL_HAVE_FEATURE(nullability_on_classes) && !defined(__OBJC__)
-+    = T _Nullable;
-+#else
-+    = T;
-+#endif
-+
-+template <typename T>
-+using NonnullImpl
-+#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
-+    [[clang::annotate("Nonnull")]]
-+#endif
-+#if ABSL_HAVE_FEATURE(nullability_on_classes) && !defined(__OBJC__)
-+    = T _Nonnull;
-+#else
-+    = T;
-+#endif
-+
-+template <typename T>
-+using NullabilityUnknownImpl
-+#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
-+    [[clang::annotate("Nullability_Unspecified")]]
-+#endif
-+#if ABSL_HAVE_FEATURE(nullability_on_classes) && !defined(__OBJC__)
-+    = T _Null_unspecified;
-+#else
-+    = T;
-+#endif
-+
-+}  // namespace nullability_internal
-+
-+// The following template aliases are deprecated forms of nullability
-+// annotations. They have some limitations, for example, an incompatibility with
-+// `auto*` pointers, as `auto` cannot be used in a template argument.
-+//
-+// It is important to note that these annotations are not distinct strong
-+// *types*. They are alias templates defined to be equal to the underlying
-+// pointer type. A pointer annotated `Nonnull<T*>`, for example, is simply a
-+// pointer of type `T*`.
-+//
-+// Prefer the macro style annotations in `absl/base/nullability.h` instead.
-+
-+// absl::Nonnull, analogous to absl_nonnull
-+//
-+// Example:
-+// absl::Nonnull<int*> foo;
-+// Is equivalent to:
-+// int* absl_nonnull foo;
-+template <typename T>
-+using Nonnull =
-+    nullability_internal::NonnullImpl<T>;
-+
-+// absl::Nullable, analogous to absl_nullable
-+//
-+// Example:
-+// absl::Nullable<int*> foo;
-+// Is equivalent to:
-+// int* absl_nullable foo;
-+template <typename T>
-+using Nullable =
-+    nullability_internal::NullableImpl<T>;
-+
-+// absl::NullabilityUnknown, analogous to absl_nullability_unknown
-+//
-+// Example:
-+// absl::NullabilityUnknown<int*> foo;
-+// Is equivalent to:
-+// int* absl_nullability_unknown foo;
-+template <typename T>
-+using NullabilityUnknown =
-+    nullability_internal::NullabilityUnknownImpl<T>;
-+
-+ABSL_NAMESPACE_END
-+}  // namespace absl
-+
-+#endif  // ABSL_BASE_INTERNAL_NULLABILITY_DEPRECATED_H_
-+
-diff --git a/third_party/abseil-cpp/absl/base/nullability.h b/third_party/abseil-cpp/absl/base/nullability.h
-index 2796a36125b60..3a5d6e83e2060 100644
---- a/third_party/abseil-cpp/absl/base/nullability.h
-+++ b/third_party/abseil-cpp/absl/base/nullability.h
-@@ -184,6 +184,7 @@
- #define ABSL_BASE_NULLABILITY_H_
- 
- #include "absl/base/config.h"
-+#include "absl/base/internal/nullability_deprecated.h"
- 
- // ABSL_POINTERS_DEFAULT_NONNULL
- //
-diff --git a/third_party/abseil-cpp/absl/base/nullability_test.cc b/third_party/abseil-cpp/absl/base/nullability_test.cc
-index bccf1af45fe2c..bccc388beb9d4 100644
---- a/third_party/abseil-cpp/absl/base/nullability_test.cc
-+++ b/third_party/abseil-cpp/absl/base/nullability_test.cc
-@@ -14,13 +14,16 @@
- 
- #include "absl/base/nullability.h"
- 
-+#include <cassert>
- #include <memory>
- #include <type_traits>
- #include <utility>
- 
- #include "gtest/gtest.h"
-+#include "absl/base/attributes.h"
- 
- namespace {
-+namespace macro_annotations {
- void funcWithNonnullArg(int* absl_nonnull /*arg*/) {}
- template <typename T>
- void funcWithDeducedNonnullArg(T* absl_nonnull /*arg*/) {}
-@@ -87,4 +90,117 @@ TEST(PassThroughTest, PassesThroughPointerToMemberFunction) {
-   EXPECT_TRUE((std::is_same<absl_nullable T, T>::value));
-   EXPECT_TRUE((std::is_same<absl_nullability_unknown T, T>::value));
- }
-+}  // namespace macro_annotations
-+
-+// Allow testing of the deprecated type alias annotations.
-+ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
-+
-+using ::absl::Nonnull;
-+using ::absl::NullabilityUnknown;
-+using ::absl::Nullable;
-+namespace type_alias_annotations {
-+
-+void funcWithNonnullArg(Nonnull<int*> /*arg*/) {}
-+template <typename T>
-+void funcWithDeducedNonnullArg(Nonnull<T*> /*arg*/) {}
-+
-+TEST(NonnullTest, NonnullArgument) {
-+  int var = 0;
-+  funcWithNonnullArg(&var);
-+  funcWithDeducedNonnullArg(&var);
-+}
-+
-+Nonnull<int*> funcWithNonnullReturn() {
-+  static int var = 0;
-+  return &var;
-+}
-+
-+TEST(NonnullTest, NonnullReturn) {
-+  auto var = funcWithNonnullReturn();
-+  (void)var;
-+}
-+
-+TEST(PassThroughTest, PassesThroughRawPointerToInt) {
-+  EXPECT_TRUE((std::is_same<Nonnull<int*>, int*>::value));
-+  EXPECT_TRUE((std::is_same<Nullable<int*>, int*>::value));
-+  EXPECT_TRUE((std::is_same<NullabilityUnknown<int*>, int*>::value));
-+}
-+
-+TEST(PassThroughTest, PassesThroughRawPointerToVoid) {
-+  EXPECT_TRUE((std::is_same<Nonnull<void*>, void*>::value));
-+  EXPECT_TRUE((std::is_same<Nullable<void*>, void*>::value));
-+  EXPECT_TRUE((std::is_same<NullabilityUnknown<void*>, void*>::value));
-+}
-+
-+TEST(PassThroughTest, PassesThroughUniquePointerToInt) {
-+  using T = std::unique_ptr<int>;
-+  EXPECT_TRUE((std::is_same<Nonnull<T>, T>::value));
-+  EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
-+  EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
-+}
-+
-+TEST(PassThroughTest, PassesThroughSharedPointerToInt) {
-+  using T = std::shared_ptr<int>;
-+  EXPECT_TRUE((std::is_same<Nonnull<T>, T>::value));
-+  EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
-+  EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
-+}
-+
-+TEST(PassThroughTest, PassesThroughSharedPointerToVoid) {
-+  using T = std::shared_ptr<void>;
-+  EXPECT_TRUE((std::is_same<Nonnull<T>, T>::value));
-+  EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
-+  EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
-+}
-+
-+TEST(PassThroughTest, PassesThroughPointerToMemberObject) {
-+  using T = decltype(&std::pair<int, int>::first);
-+  EXPECT_TRUE((std::is_same<Nonnull<T>, T>::value));
-+  EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
-+  EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
-+}
-+
-+TEST(PassThroughTest, PassesThroughPointerToMemberFunction) {
-+  using T = decltype(&std::unique_ptr<int>::reset);
-+  EXPECT_TRUE((std::is_same<Nonnull<T>, T>::value));
-+  EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
-+  EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
-+}
-+
-+}  // namespace type_alias_annotations
-+}  // namespace
-+
-+// Nullable ADL lookup test
-+namespace util {
-+// Helper for NullableAdlTest.  Returns true, denoting that argument-dependent
-+// lookup found this implementation of DidAdlWin.  Must be in namespace
-+// util itself, not a nested anonymous namespace.
-+template <typename T>
-+bool DidAdlWin(T*) {
-+  return true;
-+}
-+
-+// Because this type is defined in namespace util, an unqualified call to
-+// DidAdlWin with a pointer to MakeAdlWin will find the above implementation.
-+struct MakeAdlWin {};
-+}  // namespace util
-+
-+namespace {
-+// Returns false, denoting that ADL did not inspect namespace util.  If it
-+// had, the better match (T*) above would have won out over the (...) here.
-+bool DidAdlWin(...) { return false; }
-+
-+TEST(NullableAdlTest, NullableAddsNothingToArgumentDependentLookup) {
-+  // Treatment: util::Nullable<int*> contributes nothing to ADL because
-+  // int* itself doesn't.
-+  EXPECT_FALSE(DidAdlWin((int*)nullptr));
-+  EXPECT_FALSE(DidAdlWin((Nullable<int*>)nullptr));
-+
-+  // Control: Argument-dependent lookup does find the implementation in
-+  // namespace util when the underlying pointee type resides there.
-+  EXPECT_TRUE(DidAdlWin((util::MakeAdlWin*)nullptr));
-+  EXPECT_TRUE(DidAdlWin((Nullable<util::MakeAdlWin*>)nullptr));
-+}
-+
-+ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
- }  // namespace
--- 
-2.49.0.1164.gab81da1b16-goog
-
diff --git a/third_party/androidx/build.gradle b/third_party/androidx/build.gradle
index 829c63db..09782c0 100644
--- a/third_party/androidx/build.gradle
+++ b/third_party/androidx/build.gradle
@@ -307,7 +307,7 @@
     google()
     maven {
         // This URL is generated by the fetch_all_androidx.py script.
-        url 'https://androidx.dev/snapshots/builds/13637298/artifacts/repository'
+        url 'https://androidx.dev/snapshots/builds/13641215/artifacts/repository'
     }
     mavenCentral()
 }
diff --git a/third_party/angle b/third_party/angle
index 5d63c8d..ce156f3 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit 5d63c8d5a09ec399a2603f87fd8c1775abbe7c56
+Subproject commit ce156f3bc3547d7467a4b9db047b13c54e47cffd
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index db62a1dc..e3786a8 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -10,6 +10,7 @@
 #include "base/time/time.h"
 #include "build/android_buildflags.h"
 #include "build/build_config.h"
+#include "build/buildflag.h"
 #include "build/chromecast_buildflags.h"
 #include "third_party/blink/public/common/features_generated.h"
 #include "third_party/blink/public/common/forcedark/forcedark_switches.h"
@@ -727,7 +728,13 @@
 // window's top-level site.
 BASE_FEATURE(kEnforceNoopenerOnBlobURLNavigation,
              "EnforceNoopenerOnBlobURLNavigation",
+// TODO(crbug.com/421810301): Temporarily disable this feature on ChromeOS due
+// to a regression.
+#if BUILDFLAG(IS_CHROMEOS)
+             base::FEATURE_DISABLED_BY_DEFAULT);
+#else
              base::FEATURE_ENABLED_BY_DEFAULT);
+#endif
 
 BASE_FEATURE(kEventTimingIgnorePresentationTimeFromUnexpectedFrameSource,
              "EventTimingIgnorePresentationTimeFromUnexpectedFrameSource",
diff --git a/third_party/blink/renderer/core/clipboard/data_transfer.cc b/third_party/blink/renderer/core/clipboard/data_transfer.cc
index 80be058..cbe1bbee 100644
--- a/third_party/blink/renderer/core/clipboard/data_transfer.cc
+++ b/third_party/blink/renderer/core/clipboard/data_transfer.cc
@@ -113,14 +113,12 @@
 
     // Maximum reasonable dimension for a drag image which won't crash during
     // memory allocation and DnD operation.
-    if (RuntimeEnabledFeatures::DnDScaleHeightAndWidthToMaxDimensionEnabled()) {
-      const int kMaxDimension = 64 * 128;
-      if (absolute_bounding_box.width() > kMaxDimension) {
-        absolute_bounding_box.set_width(kMaxDimension);
-      }
-      if (absolute_bounding_box.height() > kMaxDimension) {
-        absolute_bounding_box.set_height(kMaxDimension);
-      }
+    const int kMaxDimension = 64 * 128;
+    if (absolute_bounding_box.width() > kMaxDimension) {
+      absolute_bounding_box.set_width(kMaxDimension);
+    }
+    if (absolute_bounding_box.height() > kMaxDimension) {
+      absolute_bounding_box.set_height(kMaxDimension);
     }
 
     gfx::RectF bounding_box =
diff --git a/third_party/blink/renderer/core/css/element_rule_collector.cc b/third_party/blink/renderer/core/css/element_rule_collector.cc
index e748eb5..9c689b2 100644
--- a/third_party/blink/renderer/core/css/element_rule_collector.cc
+++ b/third_party/blink/renderer/core/css/element_rule_collector.cc
@@ -944,6 +944,22 @@
     }
   }
 
+  if (element.HasLocalName(html_names::kInputTag.LocalName())) {
+    if (const AtomicString& input_type =
+            element.getAttribute(html_names::kTypeAttr);
+        !input_type.IsNull()) {
+      for (const auto bundle : match_request.RuleSetsWithInputRules()) {
+        if (CollectMatchingRulesForList<stop_at_first_match>(
+                bundle.rule_set->InputRules(input_type.LowerASCII()),
+                match_request, bundle.rule_set, bundle.style_sheet_index,
+                checker, context.context) &&
+            stop_at_first_match) {
+          return true;
+        }
+      }
+    }
+  }
+
   if (element.IsLink()) {
     for (const auto bundle : match_request.RuleSetsWithLinkPseudoClassRules()) {
       if (CollectMatchingRulesForList<stop_at_first_match>(
diff --git a/third_party/blink/renderer/core/css/resolver/match_request.cc b/third_party/blink/renderer/core/css/resolver/match_request.cc
index c802c92..a154316 100644
--- a/third_party/blink/renderer/core/css/resolver/match_request.cc
+++ b/third_party/blink/renderer/core/css/resolver/match_request.cc
@@ -21,6 +21,9 @@
   if (!rule_set->UniversalRules().empty()) {
     has_universal_rules_ |= rule_set_mask;
   }
+  if (rule_set->HasAnyInputRules()) {
+    has_any_input_rules_ |= rule_set_mask;
+  }
   if (!rule_set->LinkPseudoClassRules().empty()) {
     has_link_pseudo_class_rules_ |= rule_set_mask;
   }
diff --git a/third_party/blink/renderer/core/css/resolver/match_request.h b/third_party/blink/renderer/core/css/resolver/match_request.h
index 4757be0d..489684c9 100644
--- a/third_party/blink/renderer/core/css/resolver/match_request.h
+++ b/third_party/blink/renderer/core/css/resolver/match_request.h
@@ -83,6 +83,7 @@
     DCHECK_EQ(style_sheet_first_index_, other.style_sheet_first_index_);
     DCHECK_EQ(single_scope_, other.single_scope_);
     DCHECK_EQ(has_any_attr_rules_, other.has_any_attr_rules_);
+    DCHECK_EQ(has_any_input_rules_, other.has_any_input_rules_);
     DCHECK_EQ(has_universal_rules_, other.has_universal_rules_);
     DCHECK_EQ(need_style_synchronized_, other.need_style_synchronized_);
     DCHECK_EQ(has_link_pseudo_class_rules_, other.has_link_pseudo_class_rules_);
@@ -109,9 +110,12 @@
   RuleSetBitmap single_scope_ = 0;
   RuleSetBitmap not_single_scope_ = 0;
 
-  // Which RuleSets have any attribute rules at all.
+  // Which RuleSets have any (non-input[type]) attribute rules at all.
   RuleSetBitmap has_any_attr_rules_ = 0;
 
+  // Which RuleSets have any input[type] rules at all.
+  RuleSetBitmap has_any_input_rules_ = 0;
+
   // Which RuleSets have any universal rules.
   RuleSetBitmap has_universal_rules_ = 0;
 
@@ -252,6 +256,10 @@
     return RuleSetIteratorProxy(
         &rule_set_group_, rule_set_group_.has_universal_rules_ & enabled_);
   }
+  RuleSetIteratorProxy RuleSetsWithInputRules() const {
+    return RuleSetIteratorProxy(
+        &rule_set_group_, rule_set_group_.has_any_input_rules_ & enabled_);
+  }
   RuleSetIteratorProxy RuleSetsWithLinkPseudoClassRules() const {
     return RuleSetIteratorProxy(
         &rule_set_group_,
diff --git a/third_party/blink/renderer/core/css/rule_set.cc b/third_party/blink/renderer/core/css/rule_set.cc
index 32bcbfa..5221dd6a 100644
--- a/third_party/blink/renderer/core/css/rule_set.cc
+++ b/third_party/blink/renderer/core/css/rule_set.cc
@@ -356,7 +356,6 @@
                                   AtomicString& part_name,
                                   AtomicString& picker_name,
                                   CSSSelector::PseudoType& pseudo_type) {
-  is_exact_attr = false;
   switch (selector->Match()) {
     case CSSSelector::kId:
       id = selector->Value();
@@ -463,13 +462,12 @@
       attr_value = g_empty_atom;
       break;
     case CSSSelector::kAttributeExact:
-      is_exact_attr = true;
-      [[fallthrough]];
     case CSSSelector::kAttributeHyphen:
     case CSSSelector::kAttributeList:
     case CSSSelector::kAttributeContain:
     case CSSSelector::kAttributeBegin:
     case CSSSelector::kAttributeEnd:
+      is_exact_attr = (selector->Match() == CSSSelector::kAttributeExact);
       attr_name = selector->Attribute().LocalName();
       attr_value = selector->Value();
       break;
@@ -569,7 +567,7 @@
   all_rules_.push_back(rule_data);
 #endif  // DCHECK_IS_ON()
 
-  bool is_exact_attr;
+  bool is_exact_attr = false;
   const CSSSelector* it = ExtractBestSelectorValues(
       component, style_scope, id, class_name, attr_name, attr_value,
       is_exact_attr, custom_pseudo_element_name, tag_name, part_name,
@@ -599,6 +597,25 @@
   }
 
   if (!attr_name.empty()) {
+    // input[type="<foo>"] have their own RuleMap.
+    if (tag_name == html_names::kInputTag.LocalName() &&
+        attr_name == html_names::kTypeAttr.LocalName() && is_exact_attr) {
+      // Same logic as tag_name below. Note that this will not
+      // mark the rules in the UA stylesheet as covered by bucketing
+      // (because they only match elements in the HTML namespace),
+      // even though they are the most common input[type="<foo>"] rules.
+      if (bucket_coverage == BucketCoverage::kCompute) {
+        MarkAsCoveredByBucketing(component, [](const CSSSelector& selector) {
+          return selector.Match() == CSSSelector::kTag &&
+                 selector.TagQName().LocalName() ==
+                     html_names::kInputTag.LocalName() &&
+                 selector.TagQName().NamespaceURI() == g_star_atom;
+        });
+      }
+      AddToRuleSet(attr_value.LowerASCII(), input_rules_, rule_data);
+      return;
+    }
+
     AddToRuleSet(attr_name, attr_rules_, rule_data);
     if (attr_name == html_names::kStyleAttr) {
       has_bucket_for_style_attr_ = true;
@@ -1163,6 +1180,8 @@
     // NOTE: attr_substring_matchers_ will be rebuilt in CompactRules().
     tag_rules_.AddFilteredRulesFromOtherSet(other.tag_rules_, only_include,
                                             other, *this);
+    input_rules_.AddFilteredRulesFromOtherSet(other.input_rules_, only_include,
+                                              other, *this);
     ua_shadow_pseudo_element_rules_.AddFilteredRulesFromOtherSet(
         other.ua_shadow_pseudo_element_rules_, only_include, other, *this);
     AddFilteredRulesFromOtherBucket(other, other.link_pseudo_class_rules_,
@@ -1447,7 +1466,7 @@
       AtomicString tag_name;
       AtomicString part_name;
       AtomicString picker_name;
-      bool is_exact_attr;
+      bool is_exact_attr = false;
       CSSSelector::PseudoType pseudo_type = CSSSelector::kPseudoUnknown;
       const StyleScope* style_scope = scope_seeker.Seek(rule.GetPosition());
       ExtractBestSelectorValues(rule.Selector(), style_scope, id, class_name,
@@ -1509,6 +1528,7 @@
   CreateSubstringMatchers(attr_rules_, scope_intervals_,
                           attr_substring_matchers_);
   tag_rules_.Compact();
+  input_rules_.Compact();
   ua_shadow_pseudo_element_rules_.Compact();
   link_pseudo_class_rules_.shrink_to_fit();
   cue_pseudo_rules_.shrink_to_fit();
@@ -1579,6 +1599,9 @@
   for (const auto& item : tag_rules_) {
     DCHECK(IsRuleListSorted(item.value));
   }
+  for (const auto& item : input_rules_) {
+    DCHECK(IsRuleListSorted(item.value));
+  }
   for (const auto& item : ua_shadow_pseudo_element_rules_) {
     DCHECK(IsRuleListSorted(item.value));
   }
@@ -1626,6 +1649,7 @@
   visitor->Trace(class_rules_);
   visitor->Trace(attr_rules_);
   visitor->Trace(tag_rules_);
+  visitor->Trace(input_rules_);
   visitor->Trace(ua_shadow_pseudo_element_rules_);
   visitor->Trace(link_pseudo_class_rules_);
   visitor->Trace(cue_pseudo_rules_);
diff --git a/third_party/blink/renderer/core/css/rule_set.h b/third_party/blink/renderer/core/css/rule_set.h
index 0acffdd2..de78371 100644
--- a/third_party/blink/renderer/core/css/rule_set.h
+++ b/third_party/blink/renderer/core/css/rule_set.h
@@ -436,6 +436,20 @@
   base::span<const RuleData> TagRules(const AtomicString& key) const {
     return tag_rules_.Find(key);
   }
+  bool HasAnyInputRules() const { return !input_rules_.IsEmpty(); }
+
+  // Rules with a subject of the form input[type="<key>"], including
+  // case-insensitive ones. These are common in our UA stylesheet
+  // and would otherwise give large amounts of false positives in bucketing,
+  // so we special-case this. We do not verify the namespace of the tag
+  // nor the attribute; that is up to selector matching. This allows us
+  // to include such rules both from the UA stylesheet (which only affects
+  // elements in the HTML namespace) and from author stylesheets (which
+  // typically do not include a namespace).
+  base::span<const RuleData> InputRules(const AtomicString& key) const {
+    return input_rules_.Find(key);
+  }
+
   base::span<const RuleData> UAShadowPseudoElementRules(
       const AtomicString& key) const {
     return ua_shadow_pseudo_element_rules_.Find(key);
@@ -716,6 +730,7 @@
   SubstringMatcherMap attr_substring_matchers_;
   RuleMap tag_rules_;
   RuleMap ua_shadow_pseudo_element_rules_;
+  RuleMap input_rules_;
   HeapVector<RuleData> link_pseudo_class_rules_;
   HeapVector<RuleData> cue_pseudo_rules_;
   HeapVector<RuleData> focus_pseudo_class_rules_;
diff --git a/third_party/blink/renderer/core/css/selector_checker.cc b/third_party/blink/renderer/core/css/selector_checker.cc
index 5ee0d037..1cfe15b4 100644
--- a/third_party/blink/renderer/core/css/selector_checker.cc
+++ b/third_party/blink/renderer/core/css/selector_checker.cc
@@ -68,6 +68,7 @@
 #include "third_party/blink/renderer/core/html/html_dialog_element.h"
 #include "third_party/blink/renderer/core/html/html_document.h"
 #include "third_party/blink/renderer/core/html/html_frame_element_base.h"
+#include "third_party/blink/renderer/core/html/html_menu_item_element.h"
 #include "third_party/blink/renderer/core/html/html_permission_element.h"
 #include "third_party/blink/renderer/core/html/html_slot_element.h"
 #include "third_party/blink/renderer/core/html/media/html_audio_element.h"
@@ -2368,6 +2369,9 @@
         if (option_element->Selected()) {
           return true;
         }
+      } else if (auto* menu_item_element =
+                     DynamicTo<HTMLMenuItemElement>(element)) {
+        return menu_item_element->ShouldAppearChecked();
       }
       break;
     }
diff --git a/third_party/blink/renderer/core/css/style_property_serializer.cc b/third_party/blink/renderer/core/css/style_property_serializer.cc
index 45f60a9ae..d1714b6f 100644
--- a/third_party/blink/renderer/core/css/style_property_serializer.cc
+++ b/third_party/blink/renderer/core/css/style_property_serializer.cc
@@ -1535,26 +1535,16 @@
 String StylePropertySerializer::Get2Values(
     const StylePropertyShorthand& shorthand) const {
   // Assume the properties are in the usual order start, end.
-  int start_value_index =
-      property_set_.FindPropertyIndex(*shorthand.properties()[0]);
-  int end_value_index =
-      property_set_.FindPropertyIndex(*shorthand.properties()[1]);
-
-  if (start_value_index == -1 || end_value_index == -1) {
-    return String();
-  }
-
-  PropertyValueForSerializer start =
-      property_set_.PropertyAt(start_value_index);
-  PropertyValueForSerializer end = property_set_.PropertyAt(end_value_index);
-
-  bool show_end = !base::ValuesEquivalent(start.Value(), end.Value());
+  const CSSValue& start_value =
+      *property_set_.GetPropertyCSSValue(*shorthand.properties()[0]);
+  const CSSValue& end_value =
+      *property_set_.GetPropertyCSSValue(*shorthand.properties()[1]);
 
   StringBuilder result;
-  result.Append(start.Value()->CssText());
-  if (show_end) {
+  result.Append(start_value.CssText());
+  if (start_value != end_value) {
     result.Append(' ');
-    result.Append(end.Value()->CssText());
+    result.Append(end_value.CssText());
   }
   return result.ReleaseString();
 }
@@ -1562,46 +1552,32 @@
 String StylePropertySerializer::Get4Values(
     const StylePropertyShorthand& shorthand) const {
   // Assume the properties are in the usual order top, right, bottom, left.
-  int top_value_index =
-      property_set_.FindPropertyIndex(*shorthand.properties()[0]);
-  int right_value_index =
-      property_set_.FindPropertyIndex(*shorthand.properties()[1]);
-  int bottom_value_index =
-      property_set_.FindPropertyIndex(*shorthand.properties()[2]);
-  int left_value_index =
-      property_set_.FindPropertyIndex(*shorthand.properties()[3]);
+  const CSSValue& top_value =
+      *property_set_.GetPropertyCSSValue(*shorthand.properties()[0]);
+  const CSSValue& right_value =
+      *property_set_.GetPropertyCSSValue(*shorthand.properties()[1]);
+  const CSSValue& bottom_value =
+      *property_set_.GetPropertyCSSValue(*shorthand.properties()[2]);
+  const CSSValue& left_value =
+      *property_set_.GetPropertyCSSValue(*shorthand.properties()[3]);
 
-  if (top_value_index == -1 || right_value_index == -1 ||
-      bottom_value_index == -1 || left_value_index == -1) {
-    return String();
-  }
-
-  PropertyValueForSerializer top = property_set_.PropertyAt(top_value_index);
-  PropertyValueForSerializer right =
-      property_set_.PropertyAt(right_value_index);
-  PropertyValueForSerializer bottom =
-      property_set_.PropertyAt(bottom_value_index);
-  PropertyValueForSerializer left = property_set_.PropertyAt(left_value_index);
-
-  bool show_left = !base::ValuesEquivalent(right.Value(), left.Value());
-  bool show_bottom =
-      !base::ValuesEquivalent(top.Value(), bottom.Value()) || show_left;
-  bool show_right =
-      !base::ValuesEquivalent(top.Value(), right.Value()) || show_bottom;
+  const bool show_left = right_value != left_value;
+  const bool show_bottom = top_value != bottom_value || show_left;
+  const bool show_right = top_value != right_value || show_bottom;
 
   StringBuilder result;
-  result.Append(top.Value()->CssText());
+  result.Append(top_value.CssText());
   if (show_right) {
     result.Append(' ');
-    result.Append(right.Value()->CssText());
+    result.Append(right_value.CssText());
   }
   if (show_bottom) {
     result.Append(' ');
-    result.Append(bottom.Value()->CssText());
+    result.Append(bottom_value.CssText());
   }
   if (show_left) {
     result.Append(' ');
-    result.Append(left.Value()->CssText());
+    result.Append(left_value.CssText());
   }
   return result.ReleaseString();
 }
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 16b846bc..620a38a 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -175,6 +175,7 @@
 #include "third_party/blink/renderer/core/html/html_html_element.h"
 #include "third_party/blink/renderer/core/html/html_image_element.h"
 #include "third_party/blink/renderer/core/html/html_link_element.h"
+#include "third_party/blink/renderer/core/html/html_menu_item_element.h"
 #include "third_party/blink/renderer/core/html/html_plugin_element.h"
 #include "third_party/blink/renderer/core/html/html_quote_element.h"
 #include "third_party/blink/renderer/core/html/html_script_element.h"
@@ -4456,6 +4457,11 @@
                         child_recalc_context);
     UpdateColumnPseudoElements(child_change, child_recalc_context);
 
+    if (IsA<HTMLMenuItemElement>(this)) {
+      UpdatePseudoElement(kPseudoIdCheckMark, child_change,
+                          child_recalc_context);
+    }
+
     if (HTMLSelectElement::CustomizableSelectEnabled(this)) {
       if (DynamicTo<HTMLOptionElement>(this)) {
         UpdatePseudoElement(kPseudoIdCheckMark, child_change,
@@ -9572,7 +9578,9 @@
       }
       return false;
     };
-    if (!is_option_in_appearance_base_select(this)) {
+    const HTMLMenuItemElement* menu_item = DynamicTo<HTMLMenuItemElement>(this);
+    const bool checkable_menu_item = menu_item && menu_item->IsCheckable();
+    if (!is_option_in_appearance_base_select(this) && !checkable_menu_item) {
       return false;
     }
   }
diff --git a/third_party/blink/renderer/core/dom/pseudo_element.cc b/third_party/blink/renderer/core/dom/pseudo_element.cc
index fc3cb39..5735f1a 100644
--- a/third_party/blink/renderer/core/dom/pseudo_element.cc
+++ b/third_party/blink/renderer/core/dom/pseudo_element.cc
@@ -40,6 +40,7 @@
 #include "third_party/blink/renderer/core/frame/web_feature.h"
 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
 #include "third_party/blink/renderer/core/html/forms/html_option_element.h"
+#include "third_party/blink/renderer/core/html/html_menu_item_element.h"
 #include "third_party/blink/renderer/core/html/html_quote_element.h"
 #include "third_party/blink/renderer/core/input_type_names.h"
 #include "third_party/blink/renderer/core/layout/generated_children.h"
@@ -83,11 +84,12 @@
                                      PseudoId pseudo_id,
                                      const AtomicString& view_transition_name) {
   if (pseudo_id == kPseudoIdCheckMark) {
-    CHECK(HTMLSelectElement::CustomizableSelectEnabled(parent));
+    CHECK(HTMLSelectElement::CustomizableSelectEnabled(parent) ||
+          RuntimeEnabledFeatures::MenuElementsEnabled());
 
-    if (!IsA<HTMLOptionElement>(parent)) {
-      // The `::checkmark` pseudo element should only be created for option
-      // elements.
+    if (!IsA<HTMLOptionElement>(parent) && !IsA<HTMLMenuItemElement>(parent)) {
+      // The `::checkmark` pseudo element should only be created for option and
+      // menuitem elements.
       return nullptr;
     }
   }
diff --git a/third_party/blink/renderer/core/editing/caret_display_item_client.cc b/third_party/blink/renderer/core/editing/caret_display_item_client.cc
index 1120fb3..4f175db8 100644
--- a/third_party/blink/renderer/core/editing/caret_display_item_client.cc
+++ b/third_party/blink/renderer/core/editing/caret_display_item_client.cc
@@ -39,6 +39,7 @@
 #include "third_party/blink/renderer/core/paint/paint_info.h"
 #include "third_party/blink/renderer/core/paint/paint_invalidator.h"
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
+#include "third_party/blink/renderer/platform/graphics/color.h"
 #include "third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h"
 #include "third_party/blink/renderer/platform/graphics/dark_mode_filter.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
@@ -221,6 +222,14 @@
     color_ = new_color;
   }
 
+  // TODO(https://crbug.com/353713061):
+  // https://drafts.csswg.org/css-ui/#caret-color When caret-shape is block,
+  // ensuring good visibility and contrast is best achieved with a UA-determined
+  // color other than currentColor.
+  if (caret_shape == CaretShape::kBlock) {
+    // Temporarily setting opacity to 0.5.
+    color_.SetAlpha(0.5);
+  }
   auto new_local_rect = rect_and_block.caret_rect;
   // TODO(crbug.com/1123630): Avoid paint invalidation on caret movement.
   if (new_local_rect != local_rect_) {
diff --git a/third_party/blink/renderer/core/editing/local_caret_rect_test.cc b/third_party/blink/renderer/core/editing/local_caret_rect_test.cc
index a3ada07..5bd2b8a 100644
--- a/third_party/blink/renderer/core/editing/local_caret_rect_test.cc
+++ b/third_party/blink/renderer/core/editing/local_caret_rect_test.cc
@@ -109,6 +109,48 @@
   EXPECT_EQ(LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(29, 0, 1, 10)),
             LocalCaretRectOfPosition(PositionWithAffinity(
                 Position(foo, 3), TextAffinity::kDownstream)));
+
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 0), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 1), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 2), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(29, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 3), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 0), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 1), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 2), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(29, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 3), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
 }
 
 TEST_F(LocalCaretRectTest, MixedHeightText) {
@@ -131,6 +173,48 @@
   EXPECT_EQ(LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(29, 0, 1, 10)),
             LocalCaretRectOfPosition(PositionWithAffinity(
                 Position(foo, 3), TextAffinity::kDownstream)));
+
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 0), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 1), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 2), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(29, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 3), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 0), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 1), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 2), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(29, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 3), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
 }
 
 TEST_F(LocalCaretRectTest, RtlText) {
@@ -154,6 +238,48 @@
   EXPECT_EQ(LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 0, 1, 10)),
             LocalCaretRectOfPosition(PositionWithAffinity(
                 Position(foo, 3), TextAffinity::kDownstream)));
+
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 0), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 1), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 2), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 3), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 0), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 1), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 2), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 3), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
 }
 
 TEST_F(LocalCaretRectTest, ClampingAndRounding) {
@@ -170,10 +296,23 @@
       </style>
       <div id=root>def</div>)HTML");
   const Node* text = GetElementById("root")->firstChild();
+  // caret-shape: bar
   EXPECT_EQ(
       LocalCaretRect(text->GetLayoutObject(), PhysicalRect(149, 0, 1, 30)),
       LocalCaretRectOfPosition(
           PositionWithAffinity(Position(text, 3), TextAffinity::kDownstream)));
+  // caret-shape: block
+  EXPECT_EQ(
+      LocalCaretRect(text->GetLayoutObject(), PhysicalRect(149, 0, 30, 30)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text, 3), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  // caret-shape: underscore
+  EXPECT_EQ(
+      LocalCaretRect(text->GetLayoutObject(), PhysicalRect(149, 29, 30, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text, 3), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
 }
 
 TEST_F(LocalCaretRectTest, OverflowTextLtr) {
@@ -260,6 +399,7 @@
       "font: 10px/10px Ahem; width: 30px; height: 30px'>XXXYYYZZZ</div>");
   const Node* foo = GetElementById("div")->firstChild();
 
+  // caret-shape: bar
   EXPECT_EQ(LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 0, 10, 1)),
             LocalCaretRectOfPosition(PositionWithAffinity(
                 Position(foo, 0), TextAffinity::kDownstream)));
@@ -298,6 +438,132 @@
   EXPECT_EQ(LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 29, 10, 1)),
             LocalCaretRectOfPosition(PositionWithAffinity(
                 Position(foo, 9), TextAffinity::kDownstream)));
+
+  // caret-shape: block
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 0), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 1), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 20, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 2), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 29, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 3), TextAffinity::kUpstream),
+          CaretShape::kBlock));
+
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 3), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 4), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 20, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 5), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 29, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 6), TextAffinity::kUpstream),
+          CaretShape::kBlock));
+
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 6), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 7), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 20, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 8), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 29, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 9), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+
+  // caret-shape: underscore
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 0, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 0), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 10, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 1), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 20, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 2), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 29, 1, 10)),
+            LocalCaretRectOfPosition(
+                PositionWithAffinity(Position(foo, 3), TextAffinity::kUpstream),
+                CaretShape::kUnderscore));
+
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 0, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 3), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 10, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 4), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 20, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 5), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 29, 1, 10)),
+            LocalCaretRectOfPosition(
+                PositionWithAffinity(Position(foo, 6), TextAffinity::kUpstream),
+                CaretShape::kUnderscore));
+
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 0, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 6), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 10, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 7), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 20, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 8), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 29, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 9), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
 }
 
 TEST_F(LocalCaretRectTest, VerticalLRText) {
@@ -309,6 +575,7 @@
       "font: 10px/10px Ahem; width: 30px; height: 30px'>XXXYYYZZZ</div>");
   const Node* foo = GetElementById("div")->firstChild();
 
+  // caret-shape: bar
   EXPECT_EQ(LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 0, 10, 1)),
             LocalCaretRectOfPosition(PositionWithAffinity(
                 Position(foo, 0), TextAffinity::kDownstream)));
@@ -347,6 +614,131 @@
   EXPECT_EQ(LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 29, 10, 1)),
             LocalCaretRectOfPosition(PositionWithAffinity(
                 Position(foo, 9), TextAffinity::kDownstream)));
+
+  // caret-shape: block
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 0), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 1), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 20, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 2), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 29, 10, 10)),
+            LocalCaretRectOfPosition(
+                PositionWithAffinity(Position(foo, 3), TextAffinity::kUpstream),
+                CaretShape::kBlock));
+
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 3), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 4), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 20, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 5), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 29, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 6), TextAffinity::kUpstream),
+          CaretShape::kBlock));
+
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 6), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 7), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 20, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 8), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 29, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 9), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+
+  // caret-shape: underscore
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 0, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 0), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 10, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 1), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 20, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 2), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 29, 1, 10)),
+            LocalCaretRectOfPosition(
+                PositionWithAffinity(Position(foo, 3), TextAffinity::kUpstream),
+                CaretShape::kUnderscore));
+
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 0, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 3), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 10, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 4), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 20, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 5), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 29, 1, 10)),
+            LocalCaretRectOfPosition(
+                PositionWithAffinity(Position(foo, 6), TextAffinity::kUpstream),
+                CaretShape::kUnderscore));
+
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 0, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 6), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 10, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 7), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 20, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 8), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 29, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 9), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
 }
 
 TEST_F(LocalCaretRectTest, OverflowTextVerticalLtr) {
@@ -435,6 +827,7 @@
       "word-break: break-all'>XXXXXX</div>");
   const Node* foo = GetElementById("div")->firstChild();
 
+  // caret-shape: bar
   // First line
   EXPECT_EQ(LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 0, 1, 10)),
             LocalCaretRectOfPosition(PositionWithAffinity(
@@ -462,6 +855,93 @@
   EXPECT_EQ(LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(29, 10, 1, 10)),
             LocalCaretRectOfPosition(PositionWithAffinity(
                 Position(foo, 6), TextAffinity::kDownstream)));
+
+  // caret-shape: block
+  // First line
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 0), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 1), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 2), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(29, 0, 10, 10)),
+            LocalCaretRectOfPosition(
+                PositionWithAffinity(Position(foo, 3), TextAffinity::kUpstream),
+                CaretShape::kBlock));
+
+  // Second line
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 3), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 4), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 5), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(29, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 6), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+
+  // caret-shape: underscore
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 0), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 1), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 2), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(29, 9, 10, 1)),
+            LocalCaretRectOfPosition(
+                PositionWithAffinity(Position(foo, 3), TextAffinity::kUpstream),
+                CaretShape::kUnderscore));
+
+  // Second line
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 19, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 3), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(10, 19, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 4), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(20, 19, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 5), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(29, 19, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 6), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
 }
 
 TEST_F(LocalCaretRectTest, SoftLineWrapBetweenMultipleTextNodes) {
@@ -481,6 +961,7 @@
   const Node* text_d = GetElementById("span-d")->firstChild();
 
   const Position after_c(text_c, 1);
+  // caret-shape: bar
   EXPECT_EQ(
       LocalCaretRect(text_c->GetLayoutObject(), PhysicalRect(29, 0, 1, 10)),
       LocalCaretRectOfPosition(
@@ -490,7 +971,32 @@
       LocalCaretRectOfPosition(
           PositionWithAffinity(after_c, TextAffinity::kDownstream)));
 
+  // caret-shape: block
+  EXPECT_EQ(
+      LocalCaretRect(text_c->GetLayoutObject(), PhysicalRect(29, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(after_c, TextAffinity::kUpstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(text_d->GetLayoutObject(), PhysicalRect(0, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(after_c, TextAffinity::kDownstream),
+          CaretShape::kBlock));
+
+  // caret-shape: underscore
+  EXPECT_EQ(
+      LocalCaretRect(text_c->GetLayoutObject(), PhysicalRect(29, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(after_c, TextAffinity::kUpstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(text_d->GetLayoutObject(), PhysicalRect(0, 19, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(after_c, TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+
   const Position before_d(text_d, 0);
+  // caret-shape: bar
   EXPECT_EQ(
       LocalCaretRect(text_d->GetLayoutObject(), PhysicalRect(0, 10, 1, 10)),
       LocalCaretRectOfPosition(
@@ -499,6 +1005,30 @@
       LocalCaretRect(text_d->GetLayoutObject(), PhysicalRect(0, 10, 1, 10)),
       LocalCaretRectOfPosition(
           PositionWithAffinity(before_d, TextAffinity::kDownstream)));
+
+  // caret-shape: block
+  EXPECT_EQ(
+      LocalCaretRect(text_d->GetLayoutObject(), PhysicalRect(0, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(before_d, TextAffinity::kUpstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(text_d->GetLayoutObject(), PhysicalRect(0, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(before_d, TextAffinity::kDownstream),
+          CaretShape::kBlock));
+
+  // caret-shape: underscore
+  EXPECT_EQ(
+      LocalCaretRect(text_d->GetLayoutObject(), PhysicalRect(0, 19, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(before_d, TextAffinity::kUpstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(text_d->GetLayoutObject(), PhysicalRect(0, 19, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(before_d, TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
 }
 
 TEST_F(LocalCaretRectTest, SoftLineWrapBetweenMultipleTextNodesRtl) {
@@ -519,6 +1049,7 @@
   const Node* text_d = GetElementById("span-d")->firstChild();
 
   const Position after_c(text_c, 1);
+  // caret-shape: bar
   EXPECT_EQ(
       LocalCaretRect(text_c->GetLayoutObject(), PhysicalRect(0, 0, 1, 10)),
       LocalCaretRectOfPosition(
@@ -528,7 +1059,32 @@
       LocalCaretRectOfPosition(
           PositionWithAffinity(after_c, TextAffinity::kDownstream)));
 
+  // caret-shape: block
+  EXPECT_EQ(
+      LocalCaretRect(text_c->GetLayoutObject(), PhysicalRect(0, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(after_c, TextAffinity::kUpstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(text_d->GetLayoutObject(), PhysicalRect(20, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(after_c, TextAffinity::kDownstream),
+          CaretShape::kBlock));
+
+  // caret-shape: underscore
+  EXPECT_EQ(
+      LocalCaretRect(text_c->GetLayoutObject(), PhysicalRect(0, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(after_c, TextAffinity::kUpstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(text_d->GetLayoutObject(), PhysicalRect(20, 19, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(after_c, TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+
   const Position before_d(text_d, 0);
+  // caret-shape: bar
   EXPECT_EQ(
       LocalCaretRect(text_d->GetLayoutObject(), PhysicalRect(29, 10, 1, 10)),
       LocalCaretRectOfPosition(
@@ -537,6 +1093,180 @@
       LocalCaretRect(text_d->GetLayoutObject(), PhysicalRect(29, 10, 1, 10)),
       LocalCaretRectOfPosition(
           PositionWithAffinity(before_d, TextAffinity::kDownstream)));
+
+  // caret-shape: block
+  EXPECT_EQ(
+      LocalCaretRect(text_d->GetLayoutObject(), PhysicalRect(20, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(before_d, TextAffinity::kUpstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(text_d->GetLayoutObject(), PhysicalRect(20, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(before_d, TextAffinity::kDownstream),
+          CaretShape::kBlock));
+
+  // caret-shape: underscore
+  EXPECT_EQ(
+      LocalCaretRect(text_d->GetLayoutObject(), PhysicalRect(20, 19, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(before_d, TextAffinity::kUpstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(text_d->GetLayoutObject(), PhysicalRect(20, 19, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(before_d, TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+}
+
+TEST_F(LocalCaretRectTest, MultipleTextNodesVlr) {
+  // This test only records the current behavior. Future changes are allowed.
+  LoadAhem();
+  SetBodyContent(
+      "<bdo style='font: 10px/10px Ahem; writing-mode: vertical-lr;'>"
+      "<span id=span-ab>Ab</span>"
+      "<br>"
+      "<span id=span-cd style='font: 30px/30px Ahem'>cD</span>"
+      "</bdo>");
+  const Node* text_ab = GetElementById("span-ab")->firstChild();
+  const Node* text_cd = GetElementById("span-cd")->firstChild();
+
+  // caret-shape: bar
+  EXPECT_EQ(
+      LocalCaretRect(text_ab->GetLayoutObject(), PhysicalRect(0, 0, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text_ab, 0), TextAffinity::kUpstream)));
+  EXPECT_EQ(
+      LocalCaretRect(text_ab->GetLayoutObject(), PhysicalRect(0, 10, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text_ab, 1), TextAffinity::kUpstream)));
+  EXPECT_EQ(
+      LocalCaretRect(text_cd->GetLayoutObject(), PhysicalRect(10, 0, 30, 1)),
+      LocalCaretRectOfPosition(PositionWithAffinity(
+          Position(text_cd, 0), TextAffinity::kDownstream)));
+  EXPECT_EQ(
+      LocalCaretRect(text_cd->GetLayoutObject(), PhysicalRect(10, 30, 30, 1)),
+      LocalCaretRectOfPosition(PositionWithAffinity(
+          Position(text_cd, 1), TextAffinity::kDownstream)));
+
+  // caret-shape: block
+  EXPECT_EQ(
+      LocalCaretRect(text_ab->GetLayoutObject(), PhysicalRect(0, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text_ab, 0), TextAffinity::kUpstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(text_ab->GetLayoutObject(), PhysicalRect(0, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text_ab, 1), TextAffinity::kUpstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(text_cd->GetLayoutObject(), PhysicalRect(10, 0, 30, 30)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text_cd, 0), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(text_cd->GetLayoutObject(), PhysicalRect(10, 30, 30, 30)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text_cd, 1), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+
+  // caret-shape: underscore
+  EXPECT_EQ(
+      LocalCaretRect(text_ab->GetLayoutObject(), PhysicalRect(0, 0, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text_ab, 0), TextAffinity::kUpstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(text_ab->GetLayoutObject(), PhysicalRect(0, 10, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text_ab, 1), TextAffinity::kUpstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(text_cd->GetLayoutObject(), PhysicalRect(10, 0, 1, 30)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text_cd, 0), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(text_cd->GetLayoutObject(), PhysicalRect(10, 30, 1, 30)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text_cd, 1), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+}
+
+TEST_F(LocalCaretRectTest, MultipleTextNodesVrl) {
+  // This test only records the current behavior. Future changes are allowed.
+  LoadAhem();
+  SetBodyContent(
+      "<bdo style='font: 10px/10px Ahem; writing-mode: vertical-rl;'>"
+      "<span id=span-ab>Ab</span>"
+      "<br>"
+      "<span id=span-cd style='font: 30px/30px Ahem'>cD</span>"
+      "</bdo>");
+  const Node* text_ab = GetElementById("span-ab")->firstChild();
+  const Node* text_cd = GetElementById("span-cd")->firstChild();
+
+  // caret-shape: bar
+  EXPECT_EQ(
+      LocalCaretRect(text_ab->GetLayoutObject(), PhysicalRect(30, 0, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text_ab, 0), TextAffinity::kUpstream)));
+  EXPECT_EQ(
+      LocalCaretRect(text_ab->GetLayoutObject(), PhysicalRect(30, 10, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text_ab, 1), TextAffinity::kUpstream)));
+  EXPECT_EQ(
+      LocalCaretRect(text_cd->GetLayoutObject(), PhysicalRect(0, 0, 30, 1)),
+      LocalCaretRectOfPosition(PositionWithAffinity(
+          Position(text_cd, 0), TextAffinity::kDownstream)));
+  EXPECT_EQ(
+      LocalCaretRect(text_cd->GetLayoutObject(), PhysicalRect(0, 30, 30, 1)),
+      LocalCaretRectOfPosition(PositionWithAffinity(
+          Position(text_cd, 1), TextAffinity::kDownstream)));
+
+  // caret-shape: block
+  EXPECT_EQ(
+      LocalCaretRect(text_ab->GetLayoutObject(), PhysicalRect(30, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text_ab, 0), TextAffinity::kUpstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(text_ab->GetLayoutObject(), PhysicalRect(30, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text_ab, 1), TextAffinity::kUpstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(text_cd->GetLayoutObject(), PhysicalRect(0, 0, 30, 30)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text_cd, 0), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(text_cd->GetLayoutObject(), PhysicalRect(0, 30, 30, 30)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text_cd, 1), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+
+  // caret-shape: underscore
+  EXPECT_EQ(
+      LocalCaretRect(text_ab->GetLayoutObject(), PhysicalRect(30, 0, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text_ab, 0), TextAffinity::kUpstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(text_ab->GetLayoutObject(), PhysicalRect(30, 10, 1, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text_ab, 1), TextAffinity::kUpstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(text_cd->GetLayoutObject(), PhysicalRect(0, 0, 1, 30)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text_cd, 0), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(text_cd->GetLayoutObject(), PhysicalRect(0, 30, 1, 30)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(text_cd, 1), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
 }
 
 TEST_F(LocalCaretRectTest, CaretRectAtBR) {
@@ -547,9 +1277,24 @@
       "<div style='font: 10px/10px Ahem; width: 30px'><br>foo</div>");
   const Element& br = *QuerySelector("br");
 
+  // caret-shape: bar
   EXPECT_EQ(LocalCaretRect(br.GetLayoutObject(), PhysicalRect(0, 0, 1, 10)),
             LocalCaretRectOfPosition(PositionWithAffinity(
                 Position::BeforeNode(br), TextAffinity::kDownstream)));
+
+  // caret-shape: block
+  EXPECT_EQ(
+      LocalCaretRect(br.GetLayoutObject(), PhysicalRect(0, 0, 10, 10)),
+      LocalCaretRectOfPosition(PositionWithAffinity(Position::BeforeNode(br),
+                                                    TextAffinity::kDownstream),
+                               CaretShape::kBlock));
+
+  // caret-shape: underscore
+  EXPECT_EQ(
+      LocalCaretRect(br.GetLayoutObject(), PhysicalRect(0, 9, 10, 1)),
+      LocalCaretRectOfPosition(PositionWithAffinity(Position::BeforeNode(br),
+                                                    TextAffinity::kDownstream),
+                               CaretShape::kUnderscore));
 }
 
 TEST_F(LocalCaretRectTest, CaretRectAtRtlBR) {
@@ -561,9 +1306,24 @@
       "<br>foo</bdo>");
   const Element& br = *QuerySelector("br");
 
+  // caret-shape: bar
   EXPECT_EQ(LocalCaretRect(br.GetLayoutObject(), PhysicalRect(29, 0, 1, 10)),
             LocalCaretRectOfPosition(PositionWithAffinity(
                 Position::BeforeNode(br), TextAffinity::kDownstream)));
+
+  // caret-shape: block
+  EXPECT_EQ(
+      LocalCaretRect(br.GetLayoutObject(), PhysicalRect(20, 0, 10, 10)),
+      LocalCaretRectOfPosition(PositionWithAffinity(Position::BeforeNode(br),
+                                                    TextAffinity::kDownstream),
+                               CaretShape::kBlock));
+
+  // caret-shape: underscore
+  EXPECT_EQ(
+      LocalCaretRect(br.GetLayoutObject(), PhysicalRect(20, 9, 10, 1)),
+      LocalCaretRectOfPosition(PositionWithAffinity(Position::BeforeNode(br),
+                                                    TextAffinity::kDownstream),
+                               CaretShape::kUnderscore));
 }
 
 TEST_F(LocalCaretRectTest, Images) {
@@ -697,6 +1457,7 @@
   const LayoutObject* first_letter = AssociatedLayoutObjectOf(*foo, 0);
   const LayoutObject* remaining_text = AssociatedLayoutObjectOf(*foo, 1);
 
+  // caret-shape: bar
   EXPECT_EQ(LocalCaretRect(first_letter, PhysicalRect(0, 0, 1, 10)),
             LocalCaretRectOfPosition(PositionWithAffinity(
                 Position(foo, 0), TextAffinity::kDownstream)));
@@ -709,6 +1470,50 @@
   EXPECT_EQ(LocalCaretRect(remaining_text, PhysicalRect(20, 0, 1, 10)),
             LocalCaretRectOfPosition(PositionWithAffinity(
                 Position(foo, 3), TextAffinity::kDownstream)));
+
+  // caret-shape: block
+  EXPECT_EQ(
+      LocalCaretRect(first_letter, PhysicalRect(0, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 0), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(remaining_text, PhysicalRect(0, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 1), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(remaining_text, PhysicalRect(10, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 2), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(remaining_text, PhysicalRect(20, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 3), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+
+  // caret-shape: underscore
+  EXPECT_EQ(
+      LocalCaretRect(first_letter, PhysicalRect(0, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 0), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(remaining_text, PhysicalRect(0, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 1), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(remaining_text, PhysicalRect(10, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 2), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(remaining_text, PhysicalRect(20, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 3), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
 }
 
 TEST_F(LocalCaretRectTest, AfterLineBreak) {
@@ -718,6 +1523,7 @@
   const Node* foo = div->firstChild();
   const Node* first_br = foo->nextSibling();
   const Node* second_br = first_br->nextSibling();
+  // caret-shape: bar
   EXPECT_EQ(LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(30, 0, 1, 10)),
             LocalCaretRectOfPosition(PositionWithAffinity(
                 Position::AfterNode(*foo), TextAffinity::kDownstream)));
@@ -729,6 +1535,44 @@
       LocalCaretRect(second_br->GetLayoutObject(), PhysicalRect(0, 10, 1, 10)),
       LocalCaretRectOfPosition(PositionWithAffinity(
           Position::AfterNode(*second_br), TextAffinity::kDownstream)));
+
+  // caret-shape: block
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(30, 0, 10, 10)),
+      LocalCaretRectOfPosition(PositionWithAffinity(Position::AfterNode(*foo),
+                                                    TextAffinity::kDownstream),
+                               CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(second_br->GetLayoutObject(), PhysicalRect(0, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position::AfterNode(*first_br),
+                               TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(second_br->GetLayoutObject(), PhysicalRect(0, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position::AfterNode(*second_br),
+                               TextAffinity::kDownstream),
+          CaretShape::kBlock));
+
+  // caret-shape: underscore
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(30, 9, 10, 1)),
+      LocalCaretRectOfPosition(PositionWithAffinity(Position::AfterNode(*foo),
+                                                    TextAffinity::kDownstream),
+                               CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(second_br->GetLayoutObject(), PhysicalRect(0, 19, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position::AfterNode(*first_br),
+                               TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(second_br->GetLayoutObject(), PhysicalRect(0, 19, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position::AfterNode(*second_br),
+                               TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
 }
 
 TEST_F(LocalCaretRectTest, AfterLineBreakInPre) {
@@ -736,6 +1580,7 @@
   SetBodyContent("<pre style='font: 10px/10px Ahem;'>foo\n\n</pre>");
   const Node* pre = GetDocument().body()->firstChild();
   const Node* foo = pre->firstChild();
+  // caret-shape: bar
   EXPECT_EQ(LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(30, 0, 1, 10)),
             LocalCaretRectOfPosition(PositionWithAffinity(
                 Position(foo, 3), TextAffinity::kDownstream)));
@@ -745,6 +1590,40 @@
   EXPECT_EQ(LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 10, 1, 10)),
             LocalCaretRectOfPosition(PositionWithAffinity(
                 Position(foo, 5), TextAffinity::kDownstream)));
+
+  // caret-shape: block
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(30, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 3), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 4), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 5), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+
+  // caret-shape: underscore
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(30, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 3), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 19, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 4), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(0, 19, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 5), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
 }
 
 TEST_F(LocalCaretRectTest, AfterLineBreakInPre2) {
@@ -755,6 +1634,7 @@
   const Node* pre = GetDocument().body()->firstChild();
   const Node* foo = pre->firstChild();
   const Node* br = foo->nextSibling();
+  // caret-shape: bar
   EXPECT_EQ(LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(30, 0, 1, 10)),
             LocalCaretRectOfPosition(PositionWithAffinity(
                 Position(foo, 3), TextAffinity::kDownstream)));
@@ -764,6 +1644,40 @@
   EXPECT_EQ(LocalCaretRect(br->GetLayoutObject(), PhysicalRect(0, 10, 1, 10)),
             LocalCaretRectOfPosition(PositionWithAffinity(
                 Position::AfterNode(*br), TextAffinity::kDownstream)));
+
+  // caret-shape: block
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(30, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 3), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(br->GetLayoutObject(), PhysicalRect(0, 10, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 4), TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  EXPECT_EQ(
+      LocalCaretRect(br->GetLayoutObject(), PhysicalRect(0, 10, 10, 10)),
+      LocalCaretRectOfPosition(PositionWithAffinity(Position::AfterNode(*br),
+                                                    TextAffinity::kDownstream),
+                               CaretShape::kBlock));
+
+  // caret-shape: underscore
+  EXPECT_EQ(
+      LocalCaretRect(foo->GetLayoutObject(), PhysicalRect(30, 9, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 3), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(br->GetLayoutObject(), PhysicalRect(0, 19, 10, 1)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(Position(foo, 4), TextAffinity::kDownstream),
+          CaretShape::kUnderscore));
+  EXPECT_EQ(
+      LocalCaretRect(br->GetLayoutObject(), PhysicalRect(0, 19, 10, 1)),
+      LocalCaretRectOfPosition(PositionWithAffinity(Position::AfterNode(*br),
+                                                    TextAffinity::kDownstream),
+                               CaretShape::kUnderscore));
 }
 
 TEST_F(LocalCaretRectTest, AfterLineBreakTextArea) {
@@ -771,10 +1685,24 @@
   SetBodyContent("<textarea style='font: 10px/10px Ahem; '>foo\n\n</textarea>");
   const auto* textarea = ToTextControl(GetDocument().body()->firstChild());
   const Node* inner_text = textarea->InnerEditorElement()->firstChild();
+  // caret-shape: bar
   EXPECT_EQ(
       LocalCaretRect(inner_text->GetLayoutObject(), PhysicalRect(30, 0, 1, 10)),
       LocalCaretRectOfPosition(PositionWithAffinity(
           Position(inner_text, 3), TextAffinity::kDownstream)));
+  // caret-shape: block
+  EXPECT_EQ(
+      LocalCaretRect(inner_text->GetLayoutObject(),
+                     PhysicalRect(30, 0, 10, 10)),
+      LocalCaretRectOfPosition(PositionWithAffinity(Position(inner_text, 3),
+                                                    TextAffinity::kDownstream),
+                               CaretShape::kBlock));
+  // caret-shape: underscore
+  EXPECT_EQ(
+      LocalCaretRect(inner_text->GetLayoutObject(), PhysicalRect(30, 9, 10, 1)),
+      LocalCaretRectOfPosition(PositionWithAffinity(Position(inner_text, 3),
+                                                    TextAffinity::kDownstream),
+                               CaretShape::kUnderscore));
 
   // Test the second line.
   const Node* br_in_2nd_line = inner_text->nextSibling()->nextSibling();
@@ -1006,13 +1934,54 @@
             LocalCaretRectOf(Position(text, 23)).rect);
 }
 
+// Caret in empty block in multi Columns
+TEST_F(LocalCaretRectTest, MultiColumnEmptyBlock) {
+  LoadAhem();
+  InsertStyleElement(
+      "div { font: 10px/10px Ahem; width: 30px; }"
+      "parent { columns: 2;}"
+      "editor { height: 100px; padding: 10px }");
+  SetBodyContent(
+      "<div id=parent>"
+      "<div id=editor contenteditable>"
+      "</div>"
+      "</div>");
+
+  const auto& editor = *GetElementById("editor");
+  EXPECT_EQ(PhysicalRect(0, 0, 1, 10),
+            LocalCaretRectOfPosition(
+                PositionWithAffinity(Position::FirstPositionInNode(editor)))
+                .rect);
+  EXPECT_EQ(PhysicalRect(0, 0, 10, 10),
+            LocalCaretRectOfPosition(
+                PositionWithAffinity(Position::FirstPositionInNode(editor)),
+                CaretShape::kBlock)
+                .rect);
+  EXPECT_EQ(PhysicalRect(0, 10, 10, 1),
+            LocalCaretRectOfPosition(
+                PositionWithAffinity(Position::FirstPositionInNode(editor)),
+                CaretShape::kUnderscore)
+                .rect);
+}
+
 TEST_F(LocalCaretRectTest, UnicodeBidiPlaintextWithDifferentBlockDirection) {
   LoadAhem();
   InsertStyleElement("div { font: 10px/10px Ahem; unicode-bidi: plaintext }");
   const Position position = SetCaretTextToBody("<div dir='rtl'>|abc</div>");
-  const PhysicalRect caret_rect =
+  PhysicalRect caret_rect =
       LocalCaretRectOfPosition(PositionWithAffinity(position)).rect;
+  // caret-shape: bar
   EXPECT_EQ(PhysicalRect(0, 0, 1, 10), caret_rect);
+  // caret-shape: block
+  caret_rect = LocalCaretRectOfPosition(PositionWithAffinity(position),
+                                        CaretShape::kBlock)
+                   .rect;
+  EXPECT_EQ(PhysicalRect(0, 0, 10, 10), caret_rect);
+  // caret-shape: underscore
+  caret_rect = LocalCaretRectOfPosition(PositionWithAffinity(position),
+                                        CaretShape::kUnderscore)
+                   .rect;
+  EXPECT_EQ(PhysicalRect(0, 9, 10, 1), caret_rect);
 }
 
 // http://crbug.com/835779
@@ -1027,10 +1996,23 @@
       "</div>");
 
   const Element& br = *QuerySelector("br");
+  // caret-shape: bar
   EXPECT_EQ(
       PhysicalRect(50, 10, 1, 10),
       LocalCaretRectOfPosition(PositionWithAffinity(Position::AfterNode(br)))
           .rect);
+  // caret-shape: block
+  EXPECT_EQ(
+      PhysicalRect(50, 10, 10, 10),
+      LocalCaretRectOfPosition(PositionWithAffinity(Position::AfterNode(br)),
+                               CaretShape::kBlock)
+          .rect);
+  // caret-shape: underscore
+  EXPECT_EQ(
+      PhysicalRect(50, 19, 10, 1),
+      LocalCaretRectOfPosition(PositionWithAffinity(Position::AfterNode(br)),
+                               CaretShape::kUnderscore)
+          .rect);
 }
 
 TEST_F(LocalCaretRectTest, BidiTextWithImage) {
@@ -1069,9 +2051,21 @@
   const Position position =
       SetCaretTextToBody("<bdo dir=rtl>AAA  |BBB<span>CCC</span></bdo>");
   const Node* text = position.AnchorNode();
+  // caret-shape: bar
   EXPECT_EQ(LocalCaretRect(text->GetLayoutObject(), PhysicalRect(60, 0, 1, 10)),
             LocalCaretRectOfPosition(
                 PositionWithAffinity(position, TextAffinity::kDownstream)));
+  // caret-shape: block
+  EXPECT_EQ(
+      LocalCaretRect(text->GetLayoutObject(), PhysicalRect(50, 0, 10, 10)),
+      LocalCaretRectOfPosition(
+          PositionWithAffinity(position, TextAffinity::kDownstream),
+          CaretShape::kBlock));
+  // caret-shape: underscore
+  EXPECT_EQ(LocalCaretRect(text->GetLayoutObject(), PhysicalRect(50, 9, 10, 1)),
+            LocalCaretRectOfPosition(
+                PositionWithAffinity(position, TextAffinity::kDownstream),
+                CaretShape::kUnderscore));
 }
 
 // https://crbug.com/936988
@@ -1084,8 +2078,20 @@
   const Node* text = div->firstChild()->firstChild();
 
   const Position position = Position::LastPositionInNode(*div);
+  // caret-shape: bar
   EXPECT_EQ(LocalCaretRect(text->GetLayoutObject(), PhysicalRect(30, 0, 1, 10)),
             LocalCaretRectOfPosition(PositionWithAffinity(position)));
+
+  // caret-shape: block
+  EXPECT_EQ(
+      LocalCaretRect(text->GetLayoutObject(), PhysicalRect(30, 0, 10, 10)),
+      LocalCaretRectOfPosition(PositionWithAffinity(position),
+                               CaretShape::kBlock));
+
+  // caret-shape: underscore
+  EXPECT_EQ(LocalCaretRect(text->GetLayoutObject(), PhysicalRect(30, 9, 10, 1)),
+            LocalCaretRectOfPosition(PositionWithAffinity(position),
+                                     CaretShape::kUnderscore));
 }
 
 // http://crbug.com/688015
@@ -1582,12 +2588,30 @@
       "<svg viewBox='0 0 160 120'><text x='10' y='10'>Text</text></svg>");
 
   const Text& text = To<Text>(*QuerySelector("text")->firstChild());
+  // caret-shape: bar
   EXPECT_EQ(LocalCaretRect(text.GetLayoutObject(), PhysicalRect(10, 2, 1, 10)),
             LocalCaretRectOf(Position(text, 0)));
+  // caret-shape: block
+  EXPECT_EQ(LocalCaretRect(text.GetLayoutObject(), PhysicalRect(10, 2, 10, 10)),
+            LocalCaretRectOf(Position(text, 0), CaretShape::kBlock));
+  // caret-shape: underscore
+  EXPECT_EQ(LocalCaretRect(text.GetLayoutObject(), PhysicalRect(10, 11, 10, 1)),
+            LocalCaretRectOf(Position(text, 0), CaretShape::kUnderscore));
+
+  // caret-shape: block
   EXPECT_EQ(LocalCaretRect(text.GetLayoutObject(), PhysicalRect(20, 2, 1, 10)),
             LocalCaretRectOf(Position(text, 1)));
+  EXPECT_EQ(LocalCaretRect(text.GetLayoutObject(), PhysicalRect(20, 2, 10, 10)),
+            LocalCaretRectOf(Position(text, 1), CaretShape::kBlock));
+  EXPECT_EQ(LocalCaretRect(text.GetLayoutObject(), PhysicalRect(20, 11, 10, 1)),
+            LocalCaretRectOf(Position(text, 1), CaretShape::kUnderscore));
+  // caret-shape: underscore
   EXPECT_EQ(LocalCaretRect(text.GetLayoutObject(), PhysicalRect(30, 2, 1, 10)),
             LocalCaretRectOf(Position(text, 2)));
+  EXPECT_EQ(LocalCaretRect(text.GetLayoutObject(), PhysicalRect(30, 2, 10, 10)),
+            LocalCaretRectOf(Position(text, 2), CaretShape::kBlock));
+  EXPECT_EQ(LocalCaretRect(text.GetLayoutObject(), PhysicalRect(30, 11, 10, 1)),
+            LocalCaretRectOf(Position(text, 2), CaretShape::kUnderscore));
 }
 
 TEST_F(LocalCaretRectTest, AbsoluteCaretAtStartOrEndOfNonEditableBidi) {
diff --git a/third_party/blink/renderer/core/fetch/trust_token_to_mojom.cc b/third_party/blink/renderer/core/fetch/trust_token_to_mojom.cc
index 44a629e..04bde86a 100644
--- a/third_party/blink/renderer/core/fetch/trust_token_to_mojom.cc
+++ b/third_party/blink/renderer/core/fetch/trust_token_to_mojom.cc
@@ -8,6 +8,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/v8_private_token.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/text/strcat.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index 06f0571..fd11c03a 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -4713,11 +4713,16 @@
                                  TransformState::kAccumulateTransform);
 }
 
-LayoutUnit LocalFrameView::CaretWidth() const {
+LayoutUnit LocalFrameView::BarCaretWidth() const {
   return LayoutUnit(std::max<float>(
       1.0f, GetChromeClient()->WindowToViewportScalar(&GetFrame(), 1.0f)));
 }
 
+LayoutUnit LocalFrameView::ScaleCssPixelForCaret(float width) const {
+  return LayoutUnit(std::max<float>(
+      width, GetChromeClient()->WindowToViewportScalar(&GetFrame(), width)));
+}
+
 void LocalFrameView::RegisterTapEvent(Element* target) {
   if (tap_friendliness_checker_) {
     tap_friendliness_checker_->RegisterTapEvent(target);
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.h b/third_party/blink/renderer/core/frame/local_frame_view.h
index 02dc185f..171ce803 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.h
+++ b/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -729,7 +729,10 @@
   void SetVisualViewportOrOverlayNeedsRepaint();
   bool VisualViewportOrOverlayNeedsRepaintForTesting() const;
 
-  LayoutUnit CaretWidth() const;
+  LayoutUnit BarCaretWidth() const;
+  // Returns the max value between the given float value of width and viewpoint
+  // scale in LayoutUnit.
+  LayoutUnit ScaleCssPixelForCaret(float width) const;
 
   size_t PaintFrameCount() const { return paint_frame_count_; }
 
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc
index 08b59b5..c69bfe6d 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.cc
@@ -183,16 +183,6 @@
   Thread::Current()->AddTaskObserver(this);
 }
 
-scoped_refptr<StaticBitmapImage>
-CanvasRenderingContext::PaintRenderingResultsToSnapshot(
-    SourceDrawingBuffer source_buffer,
-    FlushReason reason) {
-  CanvasResourceProvider* provider =
-      PaintRenderingResultsToCanvas(source_buffer);
-
-  return provider ? provider->Snapshot(reason) : nullptr;
-}
-
 void CanvasRenderingContext::DidProcessTask(
     const base::PendingTask& /* pending_task */) {
   RenderTaskEnded();
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
index dc1e5ae4f..087bfaa 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
@@ -71,7 +71,6 @@
 namespace blink {
 
 class CanvasElementHitTestRegion;
-class CanvasResourceProvider;
 class ComputedStyle;
 class Document;
 class Element;
@@ -207,13 +206,10 @@
   void DidDraw(const SkIRect& dirty_rect, CanvasPerformanceMonitor::DrawType);
 
   // Returns a StaticBitmapImage containing the current content, or nullptr if
-  // it was not possible to obtain that content. For historical reasons, some
-  // clients need to know whether in the case of failure the
-  // CanvasResourceProvider being used internally was present; such clients can
-  // pass in `had_canvas_resource_provider`.
-  scoped_refptr<StaticBitmapImage> PaintRenderingResultsToSnapshot(
+  // it was not possible to obtain that content.
+  virtual scoped_refptr<StaticBitmapImage> PaintRenderingResultsToSnapshot(
       SourceDrawingBuffer source_buffer,
-      FlushReason reason);
+      FlushReason reason) = 0;
 
   // WebGL-specific methods
   virtual void ClearMarkedCanvasDirty() {}
@@ -299,11 +295,6 @@
 
   virtual int AllocatedBufferCountPerPixel() { NOTREACHED(); }
 
-  bool DrawsViaGpu() {
-    return Host() && Host()->ResourceProvider() &&
-           Host()->ResourceProvider()->IsAccelerated();
-  }
-
   // OffscreenCanvas-specific methods.
   virtual bool PushFrame() { return false; }
   virtual ImageBitmap* TransferToImageBitmap(ScriptState* script_state,
@@ -348,11 +339,6 @@
 
   bool did_print_in_current_task() const { return did_print_in_current_task_; }
 
-  // Returns a CanvasResourceProvider containing the current content, or nullptr
-  // if it was not possible to obtain that content.
-  virtual CanvasResourceProvider* PaintRenderingResultsToCanvas(
-      SourceDrawingBuffer) = 0;
-
  protected:
   CanvasRenderingContext(CanvasRenderingContextHost*,
                          const CanvasContextCreationAttributesCore&,
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
index ac83a36..3e632be 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.cc
@@ -146,7 +146,7 @@
 CanvasResourceProvider*
 CanvasRenderingContextHost::GetOrCreateCanvasResourceProviderForCanvas2D() {
   CHECK(IsRenderingContext2D());
-  auto* provider = ResourceProvider();
+  auto* provider = GetResourceProviderForCanvas2D();
   if (!provider && !did_fail_to_create_resource_provider_) {
     if (IsValidImageSize()) {
       provider = CreateCanvasResourceProvider2D();
@@ -170,7 +170,7 @@
   if (!provider && !did_fail_to_create_resource_provider_) {
     if (IsValidImageSize()) {
       ReplaceResourceProvider(CreateCanvasResourceProviderWebGL());
-      provider = ResourceProvider();
+      provider = GetResourceProviderForWebGL();
     }
     if (!provider) {
       did_fail_to_create_resource_provider_ = true;
@@ -187,7 +187,7 @@
 CanvasResourceProvider*
 CanvasRenderingContextHost::GetOrCreateCanvasResourceProviderForWebGPU() {
   CHECK(IsWebGPU());
-  auto* provider = ResourceProvider();
+  auto* provider = GetResourceProviderForWebGPU();
   if (!provider && !did_fail_to_create_resource_provider_) {
     if (IsValidImageSize()) {
       provider = CreateCanvasResourceProviderWebGPU();
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h
index 57555e6..0148e7b 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h
@@ -139,11 +139,15 @@
 
   CanvasResourceProvider* GetResourceProviderForWebGL() const {
     CHECK(IsWebGL());
-    return ResourceProvider();
+    return ResourceProviderDEPRECATED();
+  }
+  CanvasResourceProvider* GetResourceProviderForWebGPU() const {
+    CHECK(IsWebGPU());
+    return ResourceProviderDEPRECATED();
   }
   CanvasResourceProvider* GetResourceProviderForCanvas2D() const {
     CHECK(IsRenderingContext2D());
-    return ResourceProvider();
+    return ResourceProviderDEPRECATED();
   }
 
   void FlushRecordingForCanvas2D(FlushReason reason);
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index 40aaf2f7..e708fca 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -869,7 +869,7 @@
              frame_dispatcher_ && !dirty_rect_.IsEmpty() &&
              GetOrCreateCanvasResourceProviderForCanvas2D()) {
     if (scoped_refptr<CanvasResource> canvas_resource =
-            ResourceProvider()->ProduceCanvasResource(reason)) {
+            GetResourceProviderForCanvas2D()->ProduceCanvasResource(reason)) {
       const gfx::Rect src_rect(Size());
       dirty_rect_.Intersect(src_rect);
       const gfx::Rect int_dirty = dirty_rect_;
@@ -2137,51 +2137,31 @@
 }
 
 void HTMLCanvasElement::UpdateMemoryUsage() {
-  int non_gpu_buffer_count = 0;
-  int gpu_buffer_count = 0;
-
   if (!IsRenderingContext2D() && !IsWebGL())
     return;
-  if (context_ && context_->DrawsViaGpu()) {
+
+  int buffer_count = context_->AllocatedBufferCountPerPixel();
+  auto* provider = IsWebGL() ? GetResourceProviderForWebGL()
+                             : GetResourceProviderForCanvas2D();
+  if (provider && provider->IsAccelerated()) {
     // The number of internal GPU buffers vary between one (stable
     // non-displayed state) and three (triple-buffered animations).
     // Adding 2 is a pessimistic but relevant estimate.
     // Note: These buffers might be allocated in GPU memory.
-    gpu_buffer_count += 2;
-  }
-
-  // NOTE: One of the callsites of this method is DiscardResourceProvider(), at
-  // which point the context is not necessarily present (e.g., if
-  // DiscardResourceProvider() is called due to an initial setSize() call on the
-  // canvas).
-  if (context_) {
-    non_gpu_buffer_count += context_->AllocatedBufferCountPerPixel();
+    buffer_count += 2;
   }
 
   // NOTE: All formats used by canvas are either 8-bit or 16-bit.
   const int bytes_per_pixel = GetRenderingContextFormat().BitsPerPixel() / 8;
 
-  intptr_t gpu_memory_usage = 0;
   uint32_t canvas_width = std::min(kMaximumCanvasSize, width());
   uint32_t canvas_height = std::min(kMaximumCanvasSize, height());
 
-  if (gpu_buffer_count) {
-    // Switch from cpu mode to gpu mode
-    base::CheckedNumeric<intptr_t> checked_usage =
-        gpu_buffer_count * bytes_per_pixel;
-    checked_usage *= canvas_width;
-    checked_usage *= canvas_height;
-    gpu_memory_usage =
-        checked_usage.ValueOrDefault(std::numeric_limits<intptr_t>::max());
-  }
-
   // Recomputation of externally memory usage computation is carried out
   // in all cases.
-  base::CheckedNumeric<intptr_t> checked_usage =
-      non_gpu_buffer_count * bytes_per_pixel;
+  base::CheckedNumeric<intptr_t> checked_usage = buffer_count * bytes_per_pixel;
   checked_usage *= canvas_width;
   checked_usage *= canvas_height;
-  checked_usage += gpu_memory_usage;
   intptr_t externally_allocated_memory =
       checked_usage.ValueOrDefault(std::numeric_limits<intptr_t>::max());
   // Subtracting two intptr_t that are known to be positive will never
diff --git a/third_party/blink/renderer/core/html/forms/html_field_set_element.cc b/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
index 9307800..7b6cbd62 100644
--- a/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
@@ -31,6 +31,7 @@
 #include "third_party/blink/renderer/core/html/custom/element_internals.h"
 #include "third_party/blink/renderer/core/html/forms/html_legend_element.h"
 #include "third_party/blink/renderer/core/html/html_collection.h"
+#include "third_party/blink/renderer/core/html/html_menu_item_element.h"
 #include "third_party/blink/renderer/core/html_names.h"
 #include "third_party/blink/renderer/core/layout/forms/layout_fieldset.h"
 #include "third_party/blink/renderer/core/layout/layout_block.h"
@@ -64,6 +65,34 @@
 
 }  // namespace
 
+void HTMLFieldSetElement::ParseAttribute(
+    const AttributeModificationParams& params) {
+  const QualifiedName& name = params.name;
+  const AtomicString& old_value = params.old_value;
+  const AtomicString& new_value = params.new_value;
+
+  if (name == html_names::kCheckableAttr) {
+    // Uncheck all child menu items, if any exist, when `checkable` content
+    // attribute is removed.
+    if (new_value.empty()) {
+      UpdateMenuItemCheckableExclusivity(/*checked_menu_item=*/nullptr);
+    } else if (EqualIgnoringASCIICase(new_value, keywords::kSingle) &&
+               !old_value.empty()) {
+      HTMLMenuItemElement* first_checked_menu_item = nullptr;
+      for (HTMLMenuItemElement& menu_item :
+           Traversal<HTMLMenuItemElement>::DescendantsOf(*this)) {
+        if (menu_item.checked()) {
+          first_checked_menu_item = &menu_item;
+          break;
+        }
+      }
+      UpdateMenuItemCheckableExclusivity(first_checked_menu_item);
+    }
+  } else {
+    HTMLFormControlElement::ParseAttribute(params);
+  }
+}
+
 HTMLFieldSetElement::HTMLFieldSetElement(Document& document)
     : HTMLFormControlElement(html_names::kFieldsetTag, document) {
   // This class has DidRecalcStyle().
@@ -205,6 +234,21 @@
   return false;
 }
 
+void HTMLFieldSetElement::UpdateMenuItemCheckableExclusivity(
+    HTMLMenuItemElement* checked_menu_item) {
+  // If `checked_menu_item` is null, then uncheck *all* child menuitems.
+  DCHECK(!checked_menu_item || checked_menu_item->checked());
+  DCHECK(!EqualIgnoringASCIICase(FastGetAttribute(html_names::kCheckableAttr),
+                                 keywords::kMultiple));
+
+  for (HTMLMenuItemElement& menu_item :
+       Traversal<HTMLMenuItemElement>::DescendantsOf(*this)) {
+    if (&menu_item != checked_menu_item) {
+      menu_item.setChecked(false);
+    }
+  }
+}
+
 // <fieldset> should never be considered disabled, but should still match the
 // :enabled or :disabled pseudo-classes according to whether the attribute is
 // set or not. See here for context:
diff --git a/third_party/blink/renderer/core/html/forms/html_field_set_element.h b/third_party/blink/renderer/core/html/forms/html_field_set_element.h
index 93fd054..6c31fc1 100644
--- a/third_party/blink/renderer/core/html/forms/html_field_set_element.h
+++ b/third_party/blink/renderer/core/html/forms/html_field_set_element.h
@@ -30,6 +30,7 @@
 namespace blink {
 
 class HTMLCollection;
+class HTMLMenuItemElement;
 
 class CORE_EXPORT HTMLFieldSetElement final : public HTMLFormControlElement {
   DEFINE_WRAPPERTYPEINFO();
@@ -41,6 +42,7 @@
   HTMLCollection* elements();
 
   bool IsDisabledFormControl() const override;
+  void UpdateMenuItemCheckableExclusivity(HTMLMenuItemElement*);
 
  protected:
   void DisabledAttributeChanged() override;
@@ -48,6 +50,7 @@
   void DidMoveToNewDocument(Document& old_document) override;
 
  private:
+  void ParseAttribute(const AttributeModificationParams&) override;
   bool IsEnumeratable() const override { return true; }
   FocusableState SupportsFocus(UpdateBehavior update_behavior) const override;
   LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
diff --git a/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc b/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc
index 3f04043..836ebfa8 100644
--- a/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc
+++ b/third_party/blink/renderer/core/html/forms/text_control_inner_elements.cc
@@ -157,7 +157,9 @@
     style_builder.SetHasLineIfEmpty(true);
   }
   if (!start_style.ApplyControlFixedSize(host)) {
-    Length caret_width(GetDocument().View()->CaretWidth(), Length::kFixed);
+    // TODO(https://crbug.com/353713061): Add support for caret-shape:
+    // underscore and caret-shape: block cases.
+    Length caret_width(GetDocument().View()->BarCaretWidth(), Length::kFixed);
     if (IsHorizontalWritingMode(style_builder.GetWritingMode())) {
       style_builder.SetMinWidth(caret_width);
     } else {
diff --git a/third_party/blink/renderer/core/html/html_attribute_names.json5 b/third_party/blink/renderer/core/html/html_attribute_names.json5
index 5be9c54c..cbcbe21 100644
--- a/third_party/blink/renderer/core/html/html_attribute_names.json5
+++ b/third_party/blink/renderer/core/html/html_attribute_names.json5
@@ -45,6 +45,7 @@
     "challenge",
     "charoff",
     "charset",
+    "checkable",
     "checked",
     "cite",
     "class",
diff --git a/third_party/blink/renderer/core/html/html_menu_item_element.cc b/third_party/blink/renderer/core/html/html_menu_item_element.cc
index ffaa07148..9f222ba8 100644
--- a/third_party/blink/renderer/core/html/html_menu_item_element.cc
+++ b/third_party/blink/renderer/core/html/html_menu_item_element.cc
@@ -10,6 +10,7 @@
 #include "third_party/blink/renderer/core/events/command_event.h"
 #include "third_party/blink/renderer/core/events/keyboard_event.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/html/forms/html_field_set_element.h"
 #include "third_party/blink/renderer/core/html/html_menu_bar_element.h"
 #include "third_party/blink/renderer/core/html/html_menu_list_element.h"
 #include "third_party/blink/renderer/core/html_names.h"
@@ -26,11 +27,14 @@
 void HTMLMenuItemElement::Trace(Visitor* visitor) const {
   visitor->Trace(nearest_ancestor_menu_bar_);
   visitor->Trace(nearest_ancestor_menu_list_);
+  visitor->Trace(nearest_ancestor_field_set_);
   HTMLElement::Trace(visitor);
 }
 
 bool HTMLMenuItemElement::MatchesDefaultPseudoClass() const {
-  return FastHasAttribute(html_names::kCheckedAttr);
+  // TODO(406566432): This should consider the `defaultchecked` when
+  // implemented.
+  return false;
 }
 
 bool HTMLMenuItemElement::MatchesEnabledPseudoClass() const {
@@ -45,12 +49,6 @@
       PseudoStateChanged(CSSSelector::kPseudoDisabled);
       PseudoStateChanged(CSSSelector::kPseudoEnabled);
     }
-  } else if (name == html_names::kCheckedAttr) {
-    if (params.old_value.IsNull() != params.new_value.IsNull() && !is_dirty_) {
-      setChecked(!params.new_value.IsNull());
-      is_dirty_ = false;
-    }
-    PseudoStateChanged(CSSSelector::kPseudoDefault);
   } else {
     HTMLElement::ParseAttribute(params);
   }
@@ -119,22 +117,48 @@
   return CommandEventType::kNone;
 }
 
-bool HTMLMenuItemElement::Checked() const {
+bool HTMLMenuItemElement::IsCheckable() const {
+  return nearest_ancestor_menu_list_ && nearest_ancestor_field_set_ &&
+         nearest_ancestor_field_set_->FastGetAttribute(
+             html_names::kCheckableAttr);
+}
+
+bool HTMLMenuItemElement::checked() const {
   return is_checked_;
 }
 
 void HTMLMenuItemElement::setChecked(bool checked) {
   is_dirty_ = true;
-  if (is_checked_ == checked) {
+  // Some menu items are not "checkable", and the `checked` IDL attribute is
+  // only stateful for checkable menu items.
+  if (is_checked_ == checked || (checked && !IsCheckable())) {
     return;
   }
 
   is_checked_ = checked;
   PseudoStateChanged(CSSSelector::kPseudoChecked);
 
+  // Only update the exclusivity of all other menu items rooted under the same
+  // fieldset *if* `this` is becoming checked under a fieldset that enforces
+  // exclusivity. If it is becoming unchecked, we don't have to worry about
+  // manually unchecking other menu items in the exclusive set, because it is
+  // permitted to have zero menu items checked.
+  DCHECK(nearest_ancestor_field_set_);
+  const AtomicString& checkable =
+      nearest_ancestor_field_set_->FastGetAttribute(html_names::kCheckableAttr);
+  if (is_checked_ && EqualIgnoringASCIICase(checkable, keywords::kSingle)) {
+    nearest_ancestor_field_set_->UpdateMenuItemCheckableExclusivity(this);
+  }
+
   // TODO: Accessibility mapping.
 }
 
+bool HTMLMenuItemElement::ShouldAppearChecked() const {
+  // `this` should only appear checked if we are checked, and we're in a
+  // checkable <fieldset> in a <menulist>.
+  return IsCheckable() && checked();
+}
+
 void HTMLMenuItemElement::SetDirty(bool value) {
   is_dirty_ = value;
 }
@@ -175,6 +199,12 @@
 
 void HTMLMenuItemElement::DefaultEventHandler(Event& event) {
   if (event.type() == event_type_names::kDOMActivate) {
+    // A menu item's checkability and ability to invoke a command are
+    // exclusive. That is, we don't explicitly disallow checkable menu items
+    // that do both, so we always give `setChecked()` the chance to set `this`
+    // as checked—this will only take effect if `IsCheckable()` is true.
+    setChecked(!checked());
+
     // Menuitems with a commandfor will dispatch a CommandEvent on the
     // invoker, and run HandleCommandInternal to perform default logic.
     if (auto* command_target = commandForElement()) {
@@ -333,16 +363,34 @@
   }
 }
 
+void HTMLMenuItemElement::ResetNearestAncestorFieldSet() {
+  nearest_ancestor_field_set_ = nullptr;
+  // TODO(https://crbug.com/406566432): See if we want to allow ancestor field
+  // sets higher up than just the immediate parent.
+  HTMLFieldSetElement* field_set = DynamicTo<HTMLFieldSetElement>(parentNode());
+  if (!field_set) {
+    return;
+  }
+
+  nearest_ancestor_field_set_ = field_set;
+}
+
 Node::InsertionNotificationRequest HTMLMenuItemElement::InsertedInto(
     ContainerNode& insertion_point) {
   auto return_value = HTMLElement::InsertedInto(insertion_point);
+
+  // Run various ancestor/state resets.
   ResetNearestAncestorMenuBarOrMenuList();
+  ResetNearestAncestorFieldSet();
   return return_value;
 }
 
 void HTMLMenuItemElement::RemovedFrom(ContainerNode& insertion_point) {
   HTMLElement::RemovedFrom(insertion_point);
+
+  // Run various ancestor/state resets.
   ResetNearestAncestorMenuBarOrMenuList();
+  ResetNearestAncestorFieldSet();
   return;
 }
 
diff --git a/third_party/blink/renderer/core/html/html_menu_item_element.h b/third_party/blink/renderer/core/html/html_menu_item_element.h
index 78ffe68d..94274c4 100644
--- a/third_party/blink/renderer/core/html/html_menu_item_element.h
+++ b/third_party/blink/renderer/core/html/html_menu_item_element.h
@@ -10,6 +10,7 @@
 
 namespace blink {
 
+class HTMLFieldSetElement;
 class HTMLMenuBarElement;
 class HTMLMenuListElement;
 
@@ -23,8 +24,11 @@
 
   int index() const;
 
-  bool Checked() const;
+  bool IsCheckable() const;
+  bool checked() const;
+  // This only sets `this` to checked if `IsCheckable()` is true.
   void setChecked(bool);
+  bool ShouldAppearChecked() const;
 
   HTMLMenuBarElement* OwnerMenuBarElement() const;
   HTMLMenuListElement* OwnerMenuListElement() const;
@@ -58,9 +62,14 @@
 
   // Traverse ancestors to find the nearest menubar or menulist ancestor.
   void ResetNearestAncestorMenuBarOrMenuList();
+  // Traverse ancestors to find the nearest fieldset ancestor.
+  void ResetNearestAncestorFieldSet();
 
   Member<HTMLMenuBarElement> nearest_ancestor_menu_bar_;
   Member<HTMLMenuListElement> nearest_ancestor_menu_list_;
+  // Could be null forever; it is only used to allow `this` to be checkable, if
+  // `this` is immediately nested inside a `<fieldset checkable>`.
+  Member<HTMLFieldSetElement> nearest_ancestor_field_set_;
 
   // Represents 'checkedness'.
   bool is_checked_;
diff --git a/third_party/blink/renderer/core/html/html_menu_item_element.idl b/third_party/blink/renderer/core/html/html_menu_item_element.idl
index 586783c..ad0afdc 100644
--- a/third_party/blink/renderer/core/html/html_menu_item_element.idl
+++ b/third_party/blink/renderer/core/html/html_menu_item_element.idl
@@ -8,7 +8,7 @@
     RuntimeEnabled=MenuElements
 ] interface HTMLMenuItemElement : HTMLElement {
     [CEReactions, Reflect] attribute boolean disabled;
-    [ImplementedAs=Checked] attribute boolean checked;
+    [CEReactions] attribute boolean checked;
 
     // Command Invokers
     [RuntimeEnabled=HTMLCommandAttributes, CEReactions, Reflect=commandfor] attribute Element? commandForElement;
diff --git a/third_party/blink/renderer/core/html/keywords.json5 b/third_party/blink/renderer/core/html/keywords.json5
index 725f2ca8..ab67589 100644
--- a/third_party/blink/renderer/core/html/keywords.json5
+++ b/third_party/blink/renderer/core/html/keywords.json5
@@ -121,6 +121,11 @@
     "show",
     "hide",
 
+    // Experimental fieldset attribute for the menu elements proposal.
+    // https://open-ui.org/components/menu.explainer/.
+    "single",
+    "multiple",
+
     // hidden=until-found attribute
     // https://html.spec.whatwg.org/#the-hidden-attribute
     "until-found",
diff --git a/third_party/blink/renderer/core/html/resources/html.css b/third_party/blink/renderer/core/html/resources/html.css
index 0aca0c1..ef34fa5 100644
--- a/third_party/blink/renderer/core/html/resources/html.css
+++ b/third_party/blink/renderer/core/html/resources/html.css
@@ -2093,6 +2093,21 @@
   menulist menuitem {
     display: block;
   }
+
+  menulist > fieldset {
+    margin-inline: 0;
+    border: none;
+    padding-block: 0;
+    padding-inline: 0;
+  }
+
+  menuitem::checkmark {
+    content: '\2713';
+  }
+
+  menuitem:not(:checked)::checkmark {
+    visibility: hidden;
+  }
 }
 
 /* TODO choose appearance:auto styles and set them in here with !important */
diff --git a/third_party/blink/renderer/core/layout/inline/caret_rect.cc b/third_party/blink/renderer/core/layout/inline/caret_rect.cc
index 59c59e82..fb2f5e0 100644
--- a/third_party/blink/renderer/core/layout/inline/caret_rect.cc
+++ b/third_party/blink/renderer/core/layout/inline/caret_rect.cc
@@ -12,6 +12,8 @@
 #include "third_party/blink/renderer/core/layout/layout_block_flow.h"
 #include "third_party/blink/renderer/core/layout/layout_text_combine.h"
 #include "third_party/blink/renderer/core/layout/physical_box_fragment.h"
+#include "third_party/blink/renderer/core/layout/text_utils.h"
+#include "third_party/blink/renderer/platform/text/character_break_iterator.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
 
 namespace blink {
@@ -66,7 +68,7 @@
 
   const LocalFrameView* frame_view =
       cursor.Current().GetLayoutObject()->GetDocument().View();
-  caret_rect.size.inline_size = frame_view->CaretWidth();
+  caret_rect.size.inline_size = frame_view->BarCaretWidth();
 
   const bool is_ltr = IsLtr(ResolvedDirection(cursor));
   if (!is_atomic_inline) {
@@ -107,35 +109,153 @@
   return LayoutUnit(ClampTo<LayoutUnit>(value, min_ceil, max_floor).Round());
 }
 
-PhysicalRect ComputeLocalCaretRectAtTextOffset(const InlineCursor& cursor,
-                                               unsigned offset,
-                                               CaretShape caret_shape) {
+LayoutUnit ComputeCharacterWidthAtOffset(const InlineCursor& cursor,
+                                         unsigned offset,
+                                         const ComputedStyle& style) {
+  const LocalFrameView* frame_view =
+      cursor.Current().GetLayoutObject()->GetFrameView();
+  unsigned cluster_size =
+      LengthOfGraphemeCluster(cursor.CurrentText().ToString(), offset);
+  float width = ComputeTextWidth(
+      StringView(cursor.CurrentText(), offset, cluster_size), style);
+
+  return frame_view->ScaleCssPixelForCaret(width);
+}
+
+LogicalRect ComputeNextCharacterLogicalRect(const InlineCursor& cursor,
+                                            unsigned offset,
+                                            CaretShape caret_shape) {
+  const LocalFrameView* frame_view =
+      cursor.Current().GetLayoutObject()->GetFrameView();
+  LayoutUnit caret_width = frame_view->BarCaretWidth();
+
+  const ComputedStyle& style = cursor.Current().Style();
+
+  WritingModeConverter converter({style.GetWritingMode(), TextDirection::kLtr},
+                                 cursor.Current().Size());
+  LogicalRect caret_rect;
+  LayoutUnit cursor_block_size =
+      converter.ToLogical(cursor.Current().Size()).block_size;
+
+  LayoutUnit cursor_inline_size = caret_width;
+  LayoutUnit cursor_block_offset;
+
+  if (offset < cursor.Current().TextEndOffset()) {
+    cursor_inline_size = ComputeCharacterWidthAtOffset(
+        cursor, offset - cursor.Current().TextStartOffset(), style);
+  } else {
+    // If the next fragment is text, we need to get the width and height of
+    // the first visible character in this fragment.
+    auto next = cursor;
+    next.MoveToNext();
+    if (next && next.Current().IsText() && !cursor.Current().IsLineBreak()) {
+      const ComputedStyle& style_next = next.Current().Style();
+      WritingModeConverter converter_next(
+          {style_next.GetWritingMode(), ResolvedDirection(next)},
+          next.Current().Size());
+      cursor_inline_size = ComputeCharacterWidthAtOffset(next, 0, style_next);
+      cursor_block_size =
+          converter_next.ToLogical(next.Current().Size()).block_size;
+      switch (style.GetWritingMode()) {
+        case WritingMode::kHorizontalTb:
+          cursor_block_offset =
+              next.Current().OffsetInContainerFragment().top -
+              cursor.Current().OffsetInContainerFragment().top;
+          break;
+        case WritingMode::kVerticalRl:
+        case WritingMode::kVerticalLr:
+        case WritingMode::kSidewaysRl:
+        case WritingMode::kSidewaysLr:
+          cursor_block_offset =
+              next.Current().OffsetInContainerFragment().left -
+              cursor.Current().OffsetInContainerFragment().left;
+          break;
+      }
+    } else {
+      // If there is no visible character after the insertion point, the UA must
+      // render the caret after the last visible character.
+      cursor_inline_size = ComputeCharacterWidthAtOffset(
+          cursor, offset - cursor.Current().TextStartOffset() - 1, style);
+    }
+  }
+  caret_rect.offset.block_offset = cursor_block_offset;
+
+  if (caret_shape == CaretShape::kBlock) {
+    caret_rect.size.block_size = cursor_block_size;
+    caret_rect.size.inline_size = cursor_inline_size;
+  } else {
+    caret_rect.size.block_size = caret_width;
+    caret_rect.size.inline_size = cursor_inline_size;
+    if (!IsFlippedLinesWritingMode(style.GetWritingMode())) {
+      caret_rect.offset.block_offset += cursor_block_size - caret_width;
+    }
+  }
+  return caret_rect;
+}
+
+LogicalRect ComputeLogicalCaretRectAtTextOffset(const InlineCursor& cursor,
+                                                unsigned offset,
+                                                CaretShape caret_shape) {
   DCHECK(cursor.Current().IsText());
   DCHECK_GE(offset, cursor.Current().TextStartOffset());
   DCHECK_LE(offset, cursor.Current().TextEndOffset());
 
   const LocalFrameView* frame_view =
       cursor.Current().GetLayoutObject()->GetDocument().View();
-  LayoutUnit caret_width = frame_view->CaretWidth();
+  LayoutUnit caret_width = frame_view->BarCaretWidth();
 
   const ComputedStyle& style = cursor.Current().Style();
-  const bool is_horizontal = style.IsHorizontalWritingMode();
 
   WritingModeConverter converter({style.GetWritingMode(), TextDirection::kLtr},
                                  cursor.Current().Size());
   LogicalRect caret_rect;
-  caret_rect.size.inline_size = caret_width;
-  caret_rect.size.block_size =
+  LayoutUnit cursor_block_size =
       converter.ToLogical(cursor.Current().Size()).block_size;
+  if (caret_shape != CaretShape::kBar &&
+      !IsA<LayoutTextCombine>(cursor.Current().GetLayoutObject()->Parent()))
+      [[unlikely]] {
+    // Get the width of the "next" character, or width of the last visible
+    // character if there is no visible next character.
+    caret_rect = ComputeNextCharacterLogicalRect(cursor, offset, caret_shape);
+  } else {
+    caret_rect.size.inline_size = caret_width;
+    caret_rect.size.block_size = cursor_block_size;
+  }
 
   LayoutUnit caret_left = cursor.CaretInlinePositionForOffset(offset);
   if (cursor.CurrentItem()->IsSvgText()) {
     caret_left /= cursor.CurrentItem()->SvgScalingFactor();
   }
-  if (!cursor.Current().IsLineBreak())
+  if (!cursor.Current().IsLineBreak() && caret_shape == CaretShape::kBar) {
     caret_left -= caret_width / 2;
+  }
+
   caret_rect.offset.inline_offset = caret_left;
 
+  if (caret_shape == CaretShape::kBlock ||
+      caret_shape == CaretShape::kUnderscore) {
+    if (!IsLtr(ResolvedDirection(cursor))) {
+      caret_rect.offset.inline_offset =
+          caret_left - caret_rect.size.inline_size;
+    }
+  }
+
+  return caret_rect;
+}
+
+PhysicalRect ComputeLocalCaretRectAtTextOffset(const InlineCursor& cursor,
+                                               unsigned offset,
+                                               CaretShape caret_shape) {
+  const LocalFrameView* frame_view =
+      cursor.Current().GetLayoutObject()->GetFrameView();
+  LayoutUnit caret_width = frame_view->BarCaretWidth();
+  const ComputedStyle& style = cursor.Current().Style();
+  const bool is_horizontal = style.IsHorizontalWritingMode();
+
+  WritingModeConverter converter({style.GetWritingMode(), TextDirection::kLtr},
+                                 cursor.Current().Size());
+  LogicalRect caret_rect =
+      ComputeLogicalCaretRectAtTextOffset(cursor, offset, caret_shape);
   PhysicalRect physical_caret_rect = converter.ToPhysical(caret_rect);
 
   // Adjust the location to be relative to the inline formatting context.
@@ -143,6 +263,8 @@
       physical_caret_rect.offset + cursor.Current().OffsetInContainerFragment();
   const auto* const text_combine = DynamicTo<LayoutTextCombine>(
       cursor.Current().GetLayoutObject()->Parent());
+  // TODO(https://crbug.com/353713061): Add caret-shape support for combine
+  // text.
   if (text_combine) [[unlikely]] {
     caret_location =
         text_combine->AdjustOffsetForLocalCaretRect(caret_location);
@@ -263,4 +385,10 @@
           &caret_position.cursor.ContainerFragment()};
 }
 
+LogicalRect GetCaretRectAtTextOffset(const InlineCursor& cursor,
+                                     unsigned text_offset,
+                                     CaretShape caret_shape) {
+  return ComputeLogicalCaretRectAtTextOffset(cursor, text_offset, caret_shape);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/inline/caret_rect.h b/third_party/blink/renderer/core/layout/inline/caret_rect.h
index 5c8de81..db2c2111 100644
--- a/third_party/blink/renderer/core/layout/inline/caret_rect.h
+++ b/third_party/blink/renderer/core/layout/inline/caret_rect.h
@@ -13,6 +13,8 @@
 
 struct InlineCaretPosition;
 struct LocalCaretRect;
+struct LogicalRect;
+class InlineCursor;
 class ComputedStyle;
 
 enum class CaretShape { kBar, kBlock, kUnderscore };
@@ -27,6 +29,12 @@
 // is adjusted to span the containing line box in the block direction.
 LocalCaretRect ComputeLocalSelectionRect(const InlineCaretPosition&);
 
+// Given the inlineCursor and caret shape, get the logical rect of the caret at
+// the given offset.
+LogicalRect GetCaretRectAtTextOffset(const InlineCursor&,
+                                     unsigned text_offset,
+                                     CaretShape);
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_INLINE_CARET_RECT_H_
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 09c72ec..4ebe10d0 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -3199,7 +3199,9 @@
   // They never refer to children.
   // FIXME: Paint the carets inside empty blocks differently than the carets
   // before/after elements.
-  LayoutUnit caret_width = GetFrameView()->CaretWidth();
+  // TODO(crbug.com/353713061): Add support for caret-shape: underscore and
+  // caret-shape: block cases.
+  LayoutUnit caret_width = GetFrameView()->BarCaretWidth();
   LogicalSize size(LogicalWidth(), LogicalHeight());
 
   LayoutUnit caret_block_size = size.block_size;
diff --git a/third_party/blink/renderer/core/layout/layout_box_model_object.cc b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
index 2fa4a20..52c469c 100644
--- a/third_party/blink/renderer/core/layout/layout_box_model_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_box_model_object.cc
@@ -842,7 +842,7 @@
               {current_style.GetWritingMode(), TextDirection::kLtr});
   x = border_padding.inline_start;
   max_x = width - border_padding.inline_end;
-  LayoutUnit caret_width = GetFrameView()->CaretWidth();
+  LayoutUnit caret_width = GetFrameView()->BarCaretWidth();
 
   switch (alignment) {
     case kAlignLeft:
@@ -873,6 +873,17 @@
     height = LayoutUnit(font_data->GetFontMetrics().Height());
   LayoutUnit vertical_space = FirstLineHeight() - height;
   LayoutUnit block_start = border_padding.block_start + (vertical_space / 2);
+  if (caret_shape != CaretShape::kBar && font_data) [[unlikely]] {
+    if (caret_shape == CaretShape::kBlock) {
+      caret_width = LayoutUnit(font_data->AvgCharWidth());
+    } else if (caret_shape == CaretShape::kUnderscore) {
+      height = caret_width;
+      caret_width = LayoutUnit(font_data->AvgCharWidth());
+      block_start =
+          block_start + LayoutUnit(font_data->GetFontMetrics().Height());
+    }
+  }
+
   return LogicalRect(x, block_start, caret_width, height);
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_box_model_object_test.cc b/third_party/blink/renderer/core/layout/layout_box_model_object_test.cc
index aabbd27..d0a32f47d 100644
--- a/third_party/blink/renderer/core/layout/layout_box_model_object_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_box_model_object_test.cc
@@ -43,6 +43,8 @@
 INSTANTIATE_PAINT_TEST_SUITE_P(LayoutBoxModelObjectTest);
 
 // This test doesn't need to be a parameterized test.
+// TODO(https://crbug.com/353713061): caret-shape property doesn't apply for
+// browsing only case.
 TEST_P(LayoutBoxModelObjectTest, LocalCaretRectForEmptyElementVertical) {
   LoadAhem();
   SetBodyInnerHTML(R"HTML(
@@ -80,6 +82,8 @@
   constexpr LayoutUnit kPaddingRight = LayoutUnit(3);
   constexpr LayoutUnit kPaddingLeft = LayoutUnit(7);
   constexpr LayoutUnit kFontHeight = LayoutUnit(10);
+  constexpr LayoutUnit kFontWidth = LayoutUnit(10);
+  // width for bar and height for underscore.
   constexpr LayoutUnit kCaretWidth = LayoutUnit(1);
 
   {
@@ -87,11 +91,23 @@
     EXPECT_EQ(PhysicalRect(rl->Size().width - kPaddingRight - kFontHeight,
                            kPaddingTop, kFontHeight, kCaretWidth),
               rl->LocalCaretRect(0, CaretShape::kBar));
+    EXPECT_EQ(PhysicalRect(rl->Size().width - kPaddingRight - kFontHeight,
+                           kPaddingTop, kFontHeight, kFontWidth),
+              rl->LocalCaretRect(0, CaretShape::kBlock));
+    EXPECT_EQ(PhysicalRect(
+                  rl->Size().width - kPaddingRight - kFontHeight - kCaretWidth,
+                  kPaddingTop, kCaretWidth, kFontWidth),
+              rl->LocalCaretRect(0, CaretShape::kUnderscore));
   }
   {
     auto* lr = GetLayoutBoxByElementId("target-lr");
     EXPECT_EQ(PhysicalRect(kPaddingLeft, kPaddingTop, kFontHeight, kCaretWidth),
               lr->LocalCaretRect(0, CaretShape::kBar));
+    EXPECT_EQ(PhysicalRect(kPaddingLeft, kPaddingTop, kFontHeight, kFontWidth),
+              lr->LocalCaretRect(0, CaretShape::kBlock));
+    EXPECT_EQ(PhysicalRect(kPaddingLeft + kFontHeight, kPaddingTop, kCaretWidth,
+                           kFontWidth),
+              lr->LocalCaretRect(0, CaretShape::kUnderscore));
   }
   {
     auto* inline_rl =
@@ -99,6 +115,12 @@
     EXPECT_EQ(PhysicalRect(LayoutUnit(), kPaddingTop - kCaretWidth, kFontHeight,
                            kCaretWidth),
               inline_rl->LocalCaretRect(0, CaretShape::kBar));
+    EXPECT_EQ(PhysicalRect(LayoutUnit(), kPaddingTop - kCaretWidth, kFontHeight,
+                           kFontWidth),
+              inline_rl->LocalCaretRect(0, CaretShape::kBlock));
+    EXPECT_EQ(PhysicalRect(LayoutUnit() - kCaretWidth,
+                           kPaddingTop - kCaretWidth, kCaretWidth, kFontWidth),
+              inline_rl->LocalCaretRect(0, CaretShape::kUnderscore));
   }
   {
     auto* inline_lr =
@@ -106,6 +128,12 @@
     EXPECT_EQ(PhysicalRect(kFontHeight, kPaddingTop - kCaretWidth, kFontHeight,
                            kCaretWidth),
               inline_lr->LocalCaretRect(0, CaretShape::kBar));
+    EXPECT_EQ(PhysicalRect(kFontHeight, kPaddingTop - kCaretWidth, kFontHeight,
+                           kFontWidth),
+              inline_lr->LocalCaretRect(0, CaretShape::kBlock));
+    EXPECT_EQ(PhysicalRect(kFontHeight + kFontHeight, kPaddingTop - kCaretWidth,
+                           kCaretWidth, kFontWidth),
+              inline_lr->LocalCaretRect(0, CaretShape::kUnderscore));
   }
 }
 
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
index 784295a0..ee9412fd 100644
--- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
+++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
@@ -553,7 +553,7 @@
     return nullptr;
   }
 
-  if (CanvasResourceProvider* provider = ResourceProvider()) {
+  if (CanvasResourceProvider* provider = ResourceProviderDEPRECATED()) {
     if (!provider->IsValid()) {
       // The canvas context is not lost but the provider is invalid. This
       // happens if the GPU process dies in the middle of a render task. The
@@ -633,17 +633,17 @@
 
   ReplaceResourceProvider(std::move(provider));
 
-  if (ResourceProvider() && ResourceProvider()->IsValid()) {
+  if (ResourceProviderDEPRECATED() && ResourceProviderDEPRECATED()->IsValid()) {
     // todo(crbug/1064363)  Add a separate UMA for Offscreen Canvas usage and
     // understand if the if (ResourceProvider() &&
     // ResourceProvider()->IsValid()) is really needed.
     base::UmaHistogramBoolean("Blink.Canvas.ResourceProviderIsAccelerated",
-                              ResourceProvider()->IsAccelerated());
+                              ResourceProviderDEPRECATED()->IsAccelerated());
     base::UmaHistogramEnumeration("Blink.Canvas.ResourceProviderType",
-                                  ResourceProvider()->GetType());
+                                  ResourceProviderDEPRECATED()->GetType());
     DidDraw();
   }
-  return ResourceProvider();
+  return ResourceProviderDEPRECATED();
 }
 
 void OffscreenCanvas::DidDraw(const SkIRect& rect) {
diff --git a/third_party/blink/renderer/core/paint/box_fragment_painter.cc b/third_party/blink/renderer/core/paint/box_fragment_painter.cc
index 46812fb..0978992 100644
--- a/third_party/blink/renderer/core/paint/box_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/box_fragment_painter.cc
@@ -21,6 +21,7 @@
 #include "third_party/blink/renderer/core/layout/grid/layout_grid.h"
 #include "third_party/blink/renderer/core/layout/hit_test_location.h"
 #include "third_party/blink/renderer/core/layout/hit_test_result.h"
+#include "third_party/blink/renderer/core/layout/inline/caret_rect.h"
 #include "third_party/blink/renderer/core/layout/inline/fragment_items.h"
 #include "third_party/blink/renderer/core/layout/inline/inline_cursor.h"
 #include "third_party/blink/renderer/core/layout/inline/physical_line_box_fragment.h"
@@ -576,6 +577,9 @@
       info.phase = PaintPhase::kDescendantBlockBackgroundsOnly;
   }
 
+  LocalFrame* frame = box_fragment_.GetLayoutObject()->GetFrame();
+  CaretShape shape = frame->Selection().GetCaretShape();
+
   if (original_phase != PaintPhase::kSelfBlockBackgroundOnly &&
       original_phase != PaintPhase::kSelfOutlineOnly &&
       // kOverlayOverflowControls is for the current object itself, so we don't
@@ -585,6 +589,17 @@
         !box_fragment_.GetLayoutObject()->IsBox()) {
       PaintObject(info, paint_offset);
     } else {
+      // Paint the caret before text when caret-shape is block as text insertion
+      // of block caret is a rectangle overlapping the visible text character.
+      // If the caret's node's fragment's containing block is this block, and
+      // the paint action is PaintPhaseForeground, then paint the caret.
+      if (original_phase == PaintPhase::kForeground &&
+          shape == CaretShape::kBlock) {
+        if (!recorder) [[likely]] {
+          DCHECK(!text_combine || !text_combine->NeedsAffineTransformInPaint());
+          PaintCaretsIfNeeded(paint_state, paint_info, paint_offset);
+        }
+      }
       ScopedBoxContentsPaintState contents_paint_state(
           paint_state, To<LayoutBox>(*box_fragment_.GetLayoutObject()));
       PaintObject(contents_paint_state.GetPaintInfo(),
@@ -592,9 +607,9 @@
     }
   }
 
-  // If the caret's node's fragment's containing block is this block, and
-  // the paint action is PaintPhaseForeground, then paint the caret.
-  if (original_phase == PaintPhase::kForeground) {
+  // Paint the caret when the shape is bar or underscore.
+  if (original_phase == PaintPhase::kForeground &&
+      shape != CaretShape::kBlock) {
     if (!recorder) [[likely]] {
       DCHECK(!text_combine || !text_combine->NeedsAffineTransformInPaint());
       PaintCaretsIfNeeded(paint_state, paint_info, paint_offset);
diff --git a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5 b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
index dfc54de..ac011b98 100644
--- a/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
+++ b/third_party/blink/renderer/core/style/computed_style_extra_fields.json5
@@ -1331,6 +1331,7 @@
       field_template: "monotonic_flag",
       field_group: "surround",
       default_value: "false",
+      custom_compare: true,
     },
     {
       name: "HasSiblingFunctions",
diff --git a/third_party/blink/renderer/core/svg/svg_element.cc b/third_party/blink/renderer/core/svg/svg_element.cc
index 52f7f28..5a6b9ebd 100644
--- a/third_party/blink/renderer/core/svg/svg_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_element.cc
@@ -721,7 +721,7 @@
 
   if (property) {
     SvgAttributeChanged({*property, params.name, params.reason});
-    InvalidateInstances();
+    SynchronizeAttributeInShadowInstances(params.name, params.new_value);
     return;
   }
 
@@ -740,7 +740,7 @@
       CssPropertyIdForSVGAttributeName(GetExecutionContext(), params.name);
   if (prop_id > CSSPropertyID::kInvalid) {
     UpdatePresentationAttributeStyle(prop_id, params.name, params.new_value);
-    InvalidateInstances();
+    SynchronizeAttributeInShadowInstances(params.name, params.new_value);
     return;
   }
 }
@@ -1202,4 +1202,19 @@
   return ownerSVGElement()->TimeContainer();
 }
 
+// TODO: When implementing <use> scoping rules this may need to be applied more
+// widely. (crbug.com/40550039)
+void SVGElement::SynchronizeAttributeInShadowInstances(
+    const QualifiedName& name,
+    const AtomicString& value) {
+  if (RuntimeEnabledFeatures::SvgUseInstancesAttributeSyncEnabled()) {
+    const HeapHashSet<WeakMember<SVGElement>>& set = InstancesForElement();
+    for (SVGElement* instance : set) {
+      instance->SetAttributeWithoutValidation(name, value);
+    }
+  } else {
+    InvalidateInstances();
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/svg/svg_element.h b/third_party/blink/renderer/core/svg/svg_element.h
index fb5126c..1f50bbd 100644
--- a/third_party/blink/renderer/core/svg/svg_element.h
+++ b/third_party/blink/renderer/core/svg/svg_element.h
@@ -279,6 +279,9 @@
 
   SMILTimeContainer* GetTimeContainer() const;
 
+  void SynchronizeAttributeInShadowInstances(const QualifiedName& name,
+                                             const AtomicString& value);
+
   Member<SVGElementRareData> svg_rare_data_;
   Member<SVGAnimatedString> class_name_;
 };
diff --git a/third_party/blink/renderer/core/svg/svg_use_element_test.cc b/third_party/blink/renderer/core/svg/svg_use_element_test.cc
index f489434..65d1d8f 100644
--- a/third_party/blink/renderer/core/svg/svg_use_element_test.cc
+++ b/third_party/blink/renderer/core/svg/svg_use_element_test.cc
@@ -126,9 +126,9 @@
   GetDocument().body()->setInnerHTML(R"HTML(
     <svg>
       <defs>
-        <rect id="r" width="100" height="100" fill="blue"/>
+        <g id="g"/>
       </defs>
-      <use id="target" href="#r"/>
+      <use id="target" href="#g"/>
     </svg>
   )HTML");
   UpdateAllLifecyclePhasesForTest();
@@ -139,8 +139,10 @@
   ASSERT_TRUE(target->InstanceRoot());
 
   GetDocument()
-      .getElementById(AtomicString("r"))
-      ->setAttribute(html_names::kWidthAttr, AtomicString("50"));
+      .getElementById(AtomicString("g"))
+      ->appendChild(GetDocument().createElementNS(
+          AtomicString("http://www.w3.org/2000/svg"), AtomicString("text"),
+          ASSERT_NO_EXCEPTION));
 
   ASSERT_FALSE(target->InstanceRoot());
 }
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
index 1e0da4e..6d80c21 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
@@ -293,7 +293,7 @@
       !host) {
     return;
   }
-  DCHECK(!host->ResourceProvider());
+  DCHECK(!host->ResourceProviderDEPRECATED());
 
   if (host->IsValidImageSize()) {
     if (dispatch_context_lost_event_timer_.IsActive()) {
@@ -793,9 +793,12 @@
   ResetInternal();
 }
 
-CanvasResourceProvider* BaseRenderingContext2D::PaintRenderingResultsToCanvas(
-    SourceDrawingBuffer) {
-  return Host()->ResourceProvider();
+scoped_refptr<StaticBitmapImage>
+BaseRenderingContext2D::PaintRenderingResultsToSnapshot(
+    SourceDrawingBuffer source_buffer,
+    FlushReason reason) {
+  CanvasResourceProvider* provider = Host()->ResourceProviderDEPRECATED();
+  return provider ? provider->Snapshot(reason) : nullptr;
 }
 
 void BaseRenderingContext2D::WillUseCurrentFont() const {
@@ -1501,11 +1504,12 @@
   gpu::SyncToken canvas_access_sync_token;
   bool performed_copy = false;
   scoped_refptr<gpu::ClientSharedImage> client_si =
-      host->ResourceProvider()->GetBackingClientSharedImageForExternalWrite(
-          &canvas_access_sync_token,
-          gpu::SHARED_IMAGE_USAGE_WEBGPU_READ |
-              gpu::SHARED_IMAGE_USAGE_WEBGPU_WRITE,
-          &performed_copy);
+      host->ResourceProviderDEPRECATED()
+          ->GetBackingClientSharedImageForExternalWrite(
+              &canvas_access_sync_token,
+              gpu::SHARED_IMAGE_USAGE_WEBGPU_READ |
+                  gpu::SHARED_IMAGE_USAGE_WEBGPU_WRITE,
+              &performed_copy);
   if (access_options->requireZeroCopy() && performed_copy) {
     exception_state.ThrowDOMException(
         DOMExceptionCode::kInvalidStateError,
@@ -1583,7 +1587,7 @@
   // If this canvas already has a resource provider, this means that drawing has
   // occurred after `transferToWebGPU`. We disallow transferring back in this
   // case, and raise an exception instead.
-  if (host->ResourceProvider()) {
+  if (host->ResourceProviderDEPRECATED()) {
     exception_state.ThrowDOMException(
         DOMExceptionCode::kInvalidStateError,
         "The canvas was touched after transferToGPUTexture.");
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h
index 50d75f5..48badf4 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h
@@ -224,8 +224,9 @@
   void PageVisibilityChanged() override {}
   void RestoreCanvasMatrixClipStack(cc::PaintCanvas* c) const final;
   void Reset() override;
-  CanvasResourceProvider* PaintRenderingResultsToCanvas(
-      SourceDrawingBuffer) final;
+  scoped_refptr<StaticBitmapImage> PaintRenderingResultsToSnapshot(
+      SourceDrawingBuffer source_buffer,
+      FlushReason reason) final;
 
   void SetTryRestoreContextIntervalForTesting(base::TimeDelta delay) {
     try_restore_context_interval_ = delay;
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
index 81e0985c..17abb22 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
@@ -158,7 +158,7 @@
 
   // CanvasRenderingContext implementation
   int AllocatedBufferCountPerPixel() override {
-    return (Host() && Host()->ResourceProvider()) ? 1 : 0;
+    return (Host() && Host()->ResourceProviderDEPRECATED()) ? 1 : 0;
   }
 
   int Width() const final;
diff --git a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.cc b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.cc
index 73673dd..0e2687a 100644
--- a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.cc
@@ -49,10 +49,11 @@
   image_layer_bridge_->Dispose();
 }
 
-CanvasResourceProvider*
-ImageBitmapRenderingContextBase::PaintRenderingResultsToCanvas(
-    SourceDrawingBuffer) {
-  return Host()->ResourceProvider();
+scoped_refptr<StaticBitmapImage>
+ImageBitmapRenderingContextBase::PaintRenderingResultsToSnapshot(
+    SourceDrawingBuffer source_buffer,
+    FlushReason reason) {
+  return GetImage(reason);
 }
 
 void ImageBitmapRenderingContextBase::Dispose() {
@@ -146,11 +147,11 @@
   }
   cc::PaintFlags paint_flags;
   paint_flags.setBlendMode(SkBlendMode::kSrc);
-  Host()->ResourceProvider()->Canvas().drawImage(
+  Host()->ResourceProviderDEPRECATED()->Canvas().drawImage(
       image->PaintImageForCurrentFrame(), 0, 0, SkSamplingOptions(),
       &paint_flags);
   scoped_refptr<CanvasResource> resource =
-      Host()->ResourceProvider()->ProduceCanvasResource(
+      Host()->ResourceProviderDEPRECATED()->ProduceCanvasResource(
           FlushReason::kNon2DCanvas);
   Host()->PushFrame(
       std::move(resource),
diff --git a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.h b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.h
index 495a319..bdbe827 100644
--- a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.h
+++ b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.h
@@ -63,8 +63,9 @@
 
   void Stop() override;
 
-  CanvasResourceProvider* PaintRenderingResultsToCanvas(
-      SourceDrawingBuffer) override;
+  scoped_refptr<StaticBitmapImage> PaintRenderingResultsToSnapshot(
+      SourceDrawingBuffer source_buffer,
+      FlushReason reason) override;
 
   bool IsPaintable() const final;
 
diff --git a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc
index 200078e..b92fc55 100644
--- a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc
@@ -105,15 +105,6 @@
       canvas->GetTopExecutionContext());
   is_valid_size_ = Host()->IsValidImageSize();
 
-  // Clear the background transparent or opaque.
-
-  // NOTE: At this point the canvas has no context installed yet and hence it is
-  // not possible to go through GetResourceProviderForCanvas2D() on it, which
-  // asserts that the context is present and is Canvas2D.
-  if (canvas->ResourceProvider() && canvas->ResourceProvider()->IsValid()) {
-    DidDraw(CanvasPerformanceMonitor::DrawType::kOther);
-  }
-
   ExecutionContext* execution_context = canvas->GetTopExecutionContext();
   if (auto* window = DynamicTo<LocalDOMWindow>(execution_context)) {
     if (window->GetFrame() && window->GetFrame()->GetSettings() &&
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index 91cc3d2..81b7632 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -845,8 +845,8 @@
   // Note: we commit only if (a) the paint operation succeeded and (b) it
   // actually updated the returned resource provider.
   bool resource_provider_was_updated = false;
-  auto* resource_provider = PaintRenderingResultsToCanvasInternal(
-      kBackBuffer, resource_provider_was_updated);
+  auto* resource_provider = PaintRenderingResultsToCanvas(
+      kBackBuffer, &resource_provider_was_updated);
   if (resource_provider && resource_provider_was_updated) {
     Host()->Commit(resource_provider->ProduceCanvasResource(FlushReason::kNone),
                    SkIRect::MakeWH(width, height));
@@ -1698,8 +1698,8 @@
   // Note: we push a frame only if (a) the paint operation succeeded and (b) it
   // actually updated the resource provider.
   bool resource_provider_was_updated = false;
-  auto* resource_provider = PaintRenderingResultsToCanvasInternal(
-      kBackBuffer, resource_provider_was_updated);
+  auto* resource_provider = PaintRenderingResultsToCanvas(
+      kBackBuffer, &resource_provider_was_updated);
   if (resource_provider && resource_provider_was_updated) {
     const int width = GetDrawingBuffer()->Size().width();
     const int height = GetDrawingBuffer()->Size().height();
@@ -1873,11 +1873,14 @@
     GetDrawingBuffer()->SetIsInHiddenPage(!Host()->IsPageVisible());
 }
 
-CanvasResourceProvider*
-WebGLRenderingContextBase::PaintRenderingResultsToCanvas(
-    SourceDrawingBuffer source_buffer) {
-  bool dont_care = false;
-  return PaintRenderingResultsToCanvasInternal(source_buffer, dont_care);
+scoped_refptr<StaticBitmapImage>
+WebGLRenderingContextBase::PaintRenderingResultsToSnapshot(
+    SourceDrawingBuffer source_buffer,
+    FlushReason reason) {
+  CanvasResourceProvider* provider =
+      PaintRenderingResultsToCanvas(source_buffer);
+
+  return provider ? provider->Snapshot(reason) : nullptr;
 }
 
 scoped_refptr<CanvasResource>
@@ -1898,12 +1901,14 @@
 }
 
 CanvasResourceProvider*
-WebGLRenderingContextBase::PaintRenderingResultsToCanvasInternal(
+WebGLRenderingContextBase::PaintRenderingResultsToCanvas(
     SourceDrawingBuffer source_buffer,
-    bool& resource_provider_was_updated) {
+    bool* resource_provider_was_updated /*=nullptr*/) {
   TRACE_EVENT0("blink",
                "WebGLRenderingContextBase::PaintRenderingResultsToCanvas");
-  resource_provider_was_updated = false;
+  if (resource_provider_was_updated != nullptr) {
+    *resource_provider_was_updated = false;
+  }
 
   if (isContextLost() || !GetDrawingBuffer()) {
     return Host()->GetResourceProviderForWebGL();
@@ -1943,7 +1948,9 @@
     resource_provider->ImportResource(
         GetDrawingBuffer()->ExportLowLatencyCanvasResource(
             resource_provider->CreateWeakPtr()));
-    resource_provider_was_updated = true;
+    if (resource_provider_was_updated != nullptr) {
+      *resource_provider_was_updated = true;
+    }
     return resource_provider;
   }
 
@@ -1958,8 +1965,11 @@
   if (!GetDrawingBuffer()->ResolveAndBindForReadAndDraw())
     return resource_provider;
 
-  resource_provider_was_updated = CopyRenderingResultsFromDrawingBuffer(
+  bool copy_succeeded = CopyRenderingResultsFromDrawingBuffer(
       Host()->GetResourceProviderForWebGL(), source_buffer);
+  if (resource_provider_was_updated != nullptr) {
+    *resource_provider_was_updated = copy_succeeded;
+  }
   return resource_provider;
 }
 
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
index 25adc01..c335997 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
@@ -713,8 +713,9 @@
   bool IsComposited() const override { return true; }
   bool UsingSwapChain() const override;
   void PageVisibilityChanged() override;
-  CanvasResourceProvider* PaintRenderingResultsToCanvas(
-      SourceDrawingBuffer) override;
+  scoped_refptr<StaticBitmapImage> PaintRenderingResultsToSnapshot(
+      SourceDrawingBuffer source_buffer,
+      FlushReason reason) override;
   void ClearMarkedCanvasDirty() override { marked_canvas_dirty_ = false; }
   scoped_refptr<CanvasResource> PaintRenderingResultsToResource(
       bool was_dirty,
@@ -1956,9 +1957,9 @@
                                 Platform::ContextType context_type,
                                 Platform::GraphicsInfo* graphics_info);
 
-  CanvasResourceProvider* PaintRenderingResultsToCanvasInternal(
+  CanvasResourceProvider* PaintRenderingResultsToCanvas(
       SourceDrawingBuffer source_buffer,
-      bool& resource_provider_was_updated);
+      bool* resource_provider_was_updated = nullptr);
   void TexImageHelperMediaVideoFrame(
       TexImageParams,
       WebGLTexture*,
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.cc
index 3ee4029c..461f71c 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.cc
@@ -3495,7 +3495,7 @@
   // Front and back buffers.
   int buffer_count = 2;
 
-  if (Host()->ResourceProvider()) {
+  if (Host()->ResourceProviderDEPRECATED()) {
     buffer_count++;
   }
 
@@ -3530,9 +3530,10 @@
   NOTIMPLEMENTED();
 }
 
-CanvasResourceProvider*
-WebGLRenderingContextWebGPUBase::PaintRenderingResultsToCanvas(
-    SourceDrawingBuffer) {
+scoped_refptr<StaticBitmapImage>
+WebGLRenderingContextWebGPUBase::PaintRenderingResultsToSnapshot(
+    SourceDrawingBuffer source_buffer,
+    FlushReason reason) {
   NOTIMPLEMENTED();
   return nullptr;
 }
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.h b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.h
index 8a5ed7001..83a7b86 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.h
@@ -1277,8 +1277,9 @@
   bool IsComposited() const override;
   bool IsPaintable() const override;
   void PageVisibilityChanged() override;
-  CanvasResourceProvider* PaintRenderingResultsToCanvas(
-      SourceDrawingBuffer) override;
+  scoped_refptr<StaticBitmapImage> PaintRenderingResultsToSnapshot(
+      SourceDrawingBuffer source_buffer,
+      FlushReason reason) override;
   bool CopyRenderingResultsToVideoFrame(
       WebGraphicsContext3DVideoFramePool*,
       SourceDrawingBuffer,
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
index db59def..2eb9c1e0 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.cc
@@ -191,11 +191,11 @@
 CanvasResourceProvider* GPUCanvasContext::PaintRenderingResultsToCanvas(
     SourceDrawingBuffer source_buffer) {
   if (!swap_buffers_) {
-    return Host()->ResourceProvider();
+    return Host()->GetResourceProviderForWebGPU();
   }
 
-  if (Host()->ResourceProvider() &&
-      Host()->ResourceProvider()->Size() != swap_buffers_->Size()) {
+  if (Host()->GetResourceProviderForWebGPU() &&
+      Host()->GetResourceProviderForWebGPU()->Size() != swap_buffers_->Size()) {
     Host()->DiscardResourceProvider();
   }
 
@@ -244,6 +244,16 @@
   return resource_provider;
 }
 
+scoped_refptr<StaticBitmapImage>
+GPUCanvasContext::PaintRenderingResultsToSnapshot(
+    SourceDrawingBuffer source_buffer,
+    FlushReason reason) {
+  CanvasResourceProvider* provider =
+      PaintRenderingResultsToCanvas(source_buffer);
+
+  return provider ? provider->Snapshot(reason) : nullptr;
+}
+
 bool GPUCanvasContext::CopyRenderingResultsToVideoFrame(
     WebGraphicsContext3DVideoFramePool* frame_pool,
     SourceDrawingBuffer src_buffer,
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h
index 3334442..7eeeb8a 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.h
@@ -68,8 +68,9 @@
   // Produces a snapshot of the current contents of the swap chain if possible
   // or else a snapshot of the most-recently presented contents.
   scoped_refptr<StaticBitmapImage> GetImage(FlushReason) final;
-  CanvasResourceProvider* PaintRenderingResultsToCanvas(
-      SourceDrawingBuffer) final;
+  scoped_refptr<StaticBitmapImage> PaintRenderingResultsToSnapshot(
+      SourceDrawingBuffer source_buffer,
+      FlushReason reason) override;
   bool CopyRenderingResultsToVideoFrame(
       WebGraphicsContext3DVideoFramePool* frame_pool,
       SourceDrawingBuffer src_buffer,
@@ -112,6 +113,7 @@
   bool IsGPUDeviceDestroyed() override;
 
  private:
+  CanvasResourceProvider* PaintRenderingResultsToCanvas(SourceDrawingBuffer);
   scoped_refptr<WebGPUMailboxTexture> GetFrontBufferMailboxTexture();
   void DetachSwapBuffers();
   void ReplaceDrawingBuffer(bool destroy_swap_buffers);
diff --git a/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler.cc b/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler.cc
index f635343..e07fc58 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler.cc
@@ -406,7 +406,8 @@
 
   hibernation_scheduled_ = false;
 
-  CanvasResourceProvider* provider = resource_host_->ResourceProvider();
+  CanvasResourceProvider* provider =
+      resource_host_->ResourceProviderDEPRECATED();
   if (!provider) {
     ReportHibernationEvent(
         HibernationEvent::kHibernationAbortedBecauseNoSurface);
diff --git a/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler_test.cc b/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler_test.cc
index 2d0fc34..648a11b 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler_test.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler_test.cc
@@ -87,10 +87,10 @@
   if (!page_visible) {
     // Trigger hibernation.
     scoped_refptr<StaticBitmapImage> snapshot =
-        host->ResourceProvider()->Snapshot(FlushReason::kHibernating);
+        host->ResourceProviderDEPRECATED()->Snapshot(FlushReason::kHibernating);
     hibernation_handler->SaveForHibernation(
         snapshot->PaintImageForCurrentFrame().GetSwSkImage(),
-        host->ResourceProvider()->ReleaseRecorder());
+        host->ResourceProviderDEPRECATED()->ReleaseRecorder());
     EXPECT_TRUE(hibernation_handler->IsHibernating());
   } else {
     // End hibernation.
@@ -231,7 +231,7 @@
 
   EXPECT_TRUE(host.GetRasterMode() == RasterMode::kGPU);
   EXPECT_FALSE(handler.IsHibernating());
-  EXPECT_TRUE(host.ResourceProvider()->IsValid());
+  EXPECT_TRUE(host.ResourceProviderDEPRECATED()->IsValid());
 }
 
 TEST_P(CanvasHibernationHandlerTest, ForegroundTooEarly) {
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_host.h b/third_party/blink/renderer/platform/graphics/canvas_resource_host.h
index 1962dea7..a112ecdd 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_host.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_host.h
@@ -63,7 +63,9 @@
 
   virtual bool LowLatencyEnabled() const { return false; }
 
-  CanvasResourceProvider* ResourceProvider() const {
+  // TODO(crbug.com/352263194): Transition all usages of this method to
+  // context-specific variants and eliminate the method.
+  CanvasResourceProvider* ResourceProviderDEPRECATED() const {
     return resource_provider_.get();
   }
 
diff --git a/third_party/blink/renderer/platform/graphics/test/fake_canvas_resource_host.h b/third_party/blink/renderer/platform/graphics/test/fake_canvas_resource_host.h
index d3be832..dee9234 100644
--- a/third_party/blink/renderer/platform/graphics/test/fake_canvas_resource_host.h
+++ b/third_party/blink/renderer/platform/graphics/test/fake_canvas_resource_host.h
@@ -37,8 +37,9 @@
   size_t GetMemoryUsage() const override { return 0; }
   CanvasResourceProvider* GetOrCreateCanvasResourceProviderForCanvas2D()
       override {
-    if (ResourceProvider())
-      return ResourceProvider();
+    if (ResourceProviderDEPRECATED()) {
+      return ResourceProviderDEPRECATED();
+    }
     constexpr auto kShouldInitialize =
         CanvasResourceProvider::ShouldInitialize::kCallClear;
     std::unique_ptr<CanvasResourceProvider> provider;
@@ -64,7 +65,7 @@
 
     ReplaceResourceProvider(std::move(provider));
 
-    return ResourceProvider();
+    return ResourceProviderDEPRECATED();
   }
 
   void SetPageVisible(bool visible) {
diff --git a/third_party/blink/renderer/platform/heap/heap_bind.h b/third_party/blink/renderer/platform/heap/heap_bind.h
index 27a16cc3..6c70d055 100644
--- a/third_party/blink/renderer/platform/heap/heap_bind.h
+++ b/third_party/blink/renderer/platform/heap/heap_bind.h
@@ -171,8 +171,8 @@
 
   template <typename Functor, typename... FreeArgs>
   auto Run(Functor&& functor, FreeArgs&&... free_args) {
-    if constexpr (base::is_instantiation<HeapCallback,
-                                         std::remove_cvref_t<Functor>>) {
+    if constexpr (base::is_instantiation<std::remove_cvref_t<Functor>,
+                                         HeapCallback>) {
       return std::forward<Functor>(functor).Run(
           std::get<index>(storage_).Unwrap()...,
           std::forward<FreeArgs>(free_args)...);
@@ -226,7 +226,7 @@
 template <typename R, typename C, typename... Args>
 struct FunctorTraitsForCallable<R (C::*)(Args...) const>
     : public FunctorTraits<R (*)(Args...)> {
-  static_assert(!base::is_instantiation<base::FunctionRef, C>,
+  static_assert(!base::is_instantiation<C, base::FunctionRef>,
                 "base::FunctionRef<> can't be bound");
   static_assert(std::is_empty_v<C>, "Capturing lambdas can't be bound");
 };
diff --git a/third_party/blink/renderer/platform/mojo/security_origin_mojom_traits.h b/third_party/blink/renderer/platform/mojo/security_origin_mojom_traits.h
index be38d4f..08b564b 100644
--- a/third_party/blink/renderer/platform/mojo/security_origin_mojom_traits.h
+++ b/third_party/blink/renderer/platform/mojo/security_origin_mojom_traits.h
@@ -11,7 +11,6 @@
 #include "mojo/public/cpp/base/unguessable_token_mojom_traits.h"
 #include "mojo/public/cpp/bindings/optional_as_pointer.h"
 #include "mojo/public/cpp/bindings/string_traits_wtf.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "url/mojom/origin.mojom-shared.h"
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 44bfcce..3fe20a2 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1828,12 +1828,6 @@
       public: true,
     },
     {
-      // Scale very large height and width of HTML Element
-      // to allow DnD.
-      name: "DnDScaleHeightAndWidthToMaxDimension",
-      status: "stable",
-    },
-    {
       name: "DocumentCookie",
     },
     {
@@ -4762,6 +4756,10 @@
       status: "stable",
     },
     {
+      name: "SvgUseInstancesAttributeSync",
+      status: "stable"
+    },
+    {
       name: "SynthesizedKeyboardEventsForAccessibilityActions",
       status: "experimental",
     },
diff --git a/third_party/blink/renderer/platform/wtf/text/ascii_fast_path.h b/third_party/blink/renderer/platform/wtf/text/ascii_fast_path.h
index c65d3841..fd36446 100644
--- a/third_party/blink/renderer/platform/wtf/text/ascii_fast_path.h
+++ b/third_party/blink/renderer/platform/wtf/text/ascii_fast_path.h
@@ -174,4 +174,12 @@
 
 }  // namespace WTF
 
+// TODO(crbug.com/422768753): Remove these `using` directives.
+namespace blink {
+using WTF::AlignToMachineWord;
+using WTF::IsAlignedToMachineWord;
+using WTF::IsAllASCII;
+using WTF::MachineWord;
+}  // namespace blink
+
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_ASCII_FAST_PATH_H_
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec.h b/third_party/blink/renderer/platform/wtf/text/text_codec.h
index 613d4e63..b579301 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec.h
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec.h
@@ -123,6 +123,13 @@
 
 }  // namespace WTF
 
+// TODO(crbug.com/422768753): Remove these `using` directives.
 using WTF::TextCodec;
+namespace blink {
+using WTF::EncodingNameRegistrar;
+using WTF::FlushBehavior;
+using WTF::TextCodecRegistrar;
+using WTF::UnencodableHandling;
+}  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_TEXT_CODEC_H_
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_ascii_fast_path.h b/third_party/blink/renderer/platform/wtf/text/text_codec_ascii_fast_path.h
index c6cb520b..3491a3c3 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_ascii_fast_path.h
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_ascii_fast_path.h
@@ -79,4 +79,9 @@
 
 }  // namespace WTF
 
+// TODO(crbug.com/422768753): Remove these `using` directives.
+namespace blink {
+using WTF::CopyASCIIMachineWord;
+}
+
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_TEXT_CODEC_ASCII_FAST_PATH_H_
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_latin1.cc b/third_party/blink/renderer/platform/wtf/text/text_codec_latin1.cc
index 8c6be1f..ea12e8a 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_latin1.cc
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_latin1.cc
@@ -37,7 +37,7 @@
 #include "third_party/blink/renderer/platform/wtf/text/text_codec_ascii_fast_path.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
-namespace WTF {
+namespace blink {
 
 static const UChar kTable[256] = {
     0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,  // 00-07
@@ -74,7 +74,8 @@
     0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF   // F8-FF
 };
 
-void TextCodecLatin1::RegisterEncodingNames(EncodingNameRegistrar registrar) {
+void TextCodecLatin1::RegisterEncodingNames(
+    WTF::EncodingNameRegistrar registrar) {
   // Taken from the alias table at https://encoding.spec.whatwg.org/
   registrar("windows-1252", "windows-1252");
   registrar("ANSI_X3.4-1968", "windows-1252");
@@ -96,12 +97,12 @@
 }
 
 static std::unique_ptr<TextCodec> NewStreamingTextDecoderWindowsLatin1(
-    const TextEncoding&,
+    const WTF::TextEncoding&,
     const void*) {
   return std::make_unique<TextCodecLatin1>();
 }
 
-void TextCodecLatin1::RegisterCodecs(TextCodecRegistrar registrar) {
+void TextCodecLatin1::RegisterCodecs(WTF::TextCodecRegistrar registrar) {
   registrar("windows-1252", NewStreamingTextDecoderWindowsLatin1, nullptr);
 
   // ASCII and Latin-1 both decode as Windows Latin-1 although they retain
@@ -111,7 +112,7 @@
 }
 
 String TextCodecLatin1::Decode(base::span<const uint8_t> bytes,
-                               FlushBehavior,
+                               WTF::FlushBehavior,
                                bool,
                                bool&) {
   if (bytes.empty()) {
@@ -212,8 +213,8 @@
 template <typename CharType>
 static std::string EncodeComplexWindowsLatin1(
     base::span<const CharType> char_data,
-    UnencodableHandling handling) {
-  DCHECK_NE(handling, kNoUnencodables);
+    WTF::UnencodableHandling handling) {
+  DCHECK_NE(handling, WTF::kNoUnencodables);
   const auto* characters = char_data.data();
   const wtf_size_t length = base::checked_cast<wtf_size_t>(char_data.size());
   wtf_size_t target_length = length;
@@ -259,7 +260,7 @@
 
 template <typename CharType>
 std::string TextCodecLatin1::EncodeCommon(base::span<const CharType> characters,
-                                          UnencodableHandling handling) {
+                                          WTF::UnencodableHandling handling) {
   std::string string(characters.size(), '\0');
 
   // Convert the string a fast way and simultaneously do an efficient check to
@@ -279,13 +280,13 @@
 }
 
 std::string TextCodecLatin1::Encode(base::span<const UChar> characters,
-                                    UnencodableHandling handling) {
+                                    WTF::UnencodableHandling handling) {
   return EncodeCommon(characters, handling);
 }
 
 std::string TextCodecLatin1::Encode(base::span<const LChar> characters,
-                                    UnencodableHandling handling) {
+                                    WTF::UnencodableHandling handling) {
   return EncodeCommon(characters, handling);
 }
 
-}  // namespace WTF
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_latin1.h b/third_party/blink/renderer/platform/wtf/text/text_codec_latin1.h
index 0598661..83f9deb 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_latin1.h
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_latin1.h
@@ -28,25 +28,28 @@
 
 #include "third_party/blink/renderer/platform/wtf/text/text_codec.h"
 
-namespace WTF {
+namespace blink {
 
 class TextCodecLatin1 final : public TextCodec {
  public:
-  static void RegisterEncodingNames(EncodingNameRegistrar);
-  static void RegisterCodecs(TextCodecRegistrar);
+  static void RegisterEncodingNames(WTF::EncodingNameRegistrar);
+  static void RegisterCodecs(WTF::TextCodecRegistrar);
 
  private:
   String Decode(base::span<const uint8_t> data,
-                FlushBehavior,
+                WTF::FlushBehavior,
                 bool stop_on_error,
                 bool& saw_error) override;
-  std::string Encode(base::span<const UChar>, UnencodableHandling) override;
-  std::string Encode(base::span<const LChar>, UnencodableHandling) override;
+  std::string Encode(base::span<const UChar>,
+                     WTF::UnencodableHandling) override;
+  std::string Encode(base::span<const LChar>,
+                     WTF::UnencodableHandling) override;
 
   template <typename CharType>
-  std::string EncodeCommon(base::span<const CharType>, UnencodableHandling);
+  std::string EncodeCommon(base::span<const CharType>,
+                           WTF::UnencodableHandling);
 };
 
-}  // namespace WTF
+}  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_TEXT_CODEC_LATIN1_H_
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_replacement.cc b/third_party/blink/renderer/platform/wtf/text/text_codec_replacement.cc
index a40484e..8919711 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_replacement.cc
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_replacement.cc
@@ -8,13 +8,13 @@
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
-namespace WTF {
+namespace blink {
 
 TextCodecReplacement::TextCodecReplacement()
     : replacement_error_returned_(false) {}
 
 void TextCodecReplacement::RegisterEncodingNames(
-    EncodingNameRegistrar registrar) {
+    WTF::EncodingNameRegistrar registrar) {
   // Taken from the alias table at·https://encoding.spec.whatwg.org/
   registrar("replacement", "replacement");
   registrar("csiso2022kr", "replacement");
@@ -25,17 +25,17 @@
 }
 
 static std::unique_ptr<TextCodec> NewStreamingTextDecoderReplacement(
-    const TextEncoding&,
+    const WTF::TextEncoding&,
     const void*) {
   return std::make_unique<TextCodecReplacement>();
 }
 
-void TextCodecReplacement::RegisterCodecs(TextCodecRegistrar registrar) {
+void TextCodecReplacement::RegisterCodecs(WTF::TextCodecRegistrar registrar) {
   registrar("replacement", NewStreamingTextDecoderReplacement, nullptr);
 }
 
 String TextCodecReplacement::Decode(base::span<const uint8_t> data,
-                                    FlushBehavior,
+                                    WTF::FlushBehavior,
                                     bool,
                                     bool& saw_error) {
   // https://encoding.spec.whatwg.org/#replacement-decoder
@@ -57,4 +57,4 @@
   return String();
 }
 
-}  // namespace WTF
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_replacement.h b/third_party/blink/renderer/platform/wtf/text/text_codec_replacement.h
index 2dc6421d..5c841a9 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_replacement.h
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_replacement.h
@@ -8,29 +8,29 @@
 #include "third_party/blink/renderer/platform/wtf/text/text_codec.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_codec_utf8.h"
 
-namespace WTF {
+namespace blink {
 
 // The "replacement" encoding exists to prevent attacks that abuse a mismatch
 // between encodings supported on the server and the client. The encoder is
 // the same as UTF-8; and for a non-empty input the decoder emits U+FFFD and
 // terminates. See: https://encoding.spec.whatwg.org/#replacement and
 // https://encoding.spec.whatwg.org/#output-encodings
-class TextCodecReplacement final : public TextCodecUTF8 {
+class TextCodecReplacement final : public TextCodecUtf8 {
  public:
   TextCodecReplacement();
 
-  static void RegisterEncodingNames(EncodingNameRegistrar);
-  static void RegisterCodecs(TextCodecRegistrar);
+  static void RegisterEncodingNames(WTF::EncodingNameRegistrar);
+  static void RegisterCodecs(WTF::TextCodecRegistrar);
 
  private:
   String Decode(base::span<const uint8_t> data,
-                FlushBehavior,
+                WTF::FlushBehavior,
                 bool stop_on_error,
                 bool& saw_error) override;
 
   bool replacement_error_returned_;
 };
 
-}  // namespace WTF
+}  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_TEXT_CODEC_REPLACEMENT_H_
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_utf16.cc b/third_party/blink/renderer/platform/wtf/text/text_codec_utf16.cc
index c93e8fd..b7d0838 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_utf16.cc
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_utf16.cc
@@ -35,9 +35,9 @@
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_uchar.h"
 
-namespace WTF {
+namespace blink {
 
-void TextCodecUTF16::RegisterEncodingNames(EncodingNameRegistrar registrar) {
+void TextCodecUtf16::RegisterEncodingNames(EncodingNameRegistrar registrar) {
   registrar("UTF-16LE", "UTF-16LE");
   registrar("UTF-16BE", "UTF-16BE");
 
@@ -51,24 +51,24 @@
   registrar("unicodeFFFE", "UTF-16BE");
 }
 
-static std::unique_ptr<TextCodec> NewStreamingTextDecoderUTF16LE(
-    const TextEncoding&,
+static std::unique_ptr<TextCodec> NewStreamingTextDecoderUtf16le(
+    const WTF::TextEncoding&,
     const void*) {
-  return std::make_unique<TextCodecUTF16>(true);
+  return std::make_unique<TextCodecUtf16>(true);
 }
 
-static std::unique_ptr<TextCodec> NewStreamingTextDecoderUTF16BE(
-    const TextEncoding&,
+static std::unique_ptr<TextCodec> NewStreamingTextDecoderUtf16be(
+    const WTF::TextEncoding&,
     const void*) {
-  return std::make_unique<TextCodecUTF16>(false);
+  return std::make_unique<TextCodecUtf16>(false);
 }
 
-void TextCodecUTF16::RegisterCodecs(TextCodecRegistrar registrar) {
-  registrar("UTF-16LE", NewStreamingTextDecoderUTF16LE, nullptr);
-  registrar("UTF-16BE", NewStreamingTextDecoderUTF16BE, nullptr);
+void TextCodecUtf16::RegisterCodecs(TextCodecRegistrar registrar) {
+  registrar("UTF-16LE", NewStreamingTextDecoderUtf16le, nullptr);
+  registrar("UTF-16BE", NewStreamingTextDecoderUtf16be, nullptr);
 }
 
-String TextCodecUTF16::Decode(base::span<const uint8_t> bytes,
+String TextCodecUtf16::Decode(base::span<const uint8_t> bytes,
                               FlushBehavior flush,
                               bool,
                               bool& saw_error) {
@@ -158,7 +158,7 @@
   return String::Adopt(buffer);
 }
 
-std::string TextCodecUTF16::Encode(base::span<const UChar> characters,
+std::string TextCodecUtf16::Encode(base::span<const UChar> characters,
                                    UnencodableHandling) {
   // We need to be sure we can double the length without overflowing.
   // Since the passed-in length is the length of an actual existing
@@ -187,7 +187,7 @@
   return result;
 }
 
-std::string TextCodecUTF16::Encode(base::span<const LChar> characters,
+std::string TextCodecUtf16::Encode(base::span<const LChar> characters,
                                    UnencodableHandling) {
   // In the LChar case, we do actually need to perform this check in release. :)
   CHECK_LE(characters.size(), std::numeric_limits<wtf_size_t>::max() / 2);
@@ -209,4 +209,4 @@
   return result;
 }
 
-}  // namespace WTF
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_utf16.h b/third_party/blink/renderer/platform/wtf/text/text_codec_utf16.h
index 4aa4c8a9..d29251b 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_utf16.h
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_utf16.h
@@ -28,14 +28,14 @@
 
 #include "third_party/blink/renderer/platform/wtf/text/text_codec.h"
 
-namespace WTF {
+namespace blink {
 
-class TextCodecUTF16 final : public TextCodec {
+class TextCodecUtf16 final : public TextCodec {
  public:
   static void RegisterEncodingNames(EncodingNameRegistrar);
   static void RegisterCodecs(TextCodecRegistrar);
 
-  TextCodecUTF16(bool little_endian) : little_endian_(little_endian) {}
+  TextCodecUtf16(bool little_endian) : little_endian_(little_endian) {}
 
   String Decode(base::span<const uint8_t> data,
                 FlushBehavior,
@@ -52,6 +52,6 @@
   UChar lead_surrogate_;
 };
 
-}  // namespace WTF
+}  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_TEXT_CODEC_UTF16_H_
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_utf8.cc b/third_party/blink/renderer/platform/wtf/text/text_codec_utf8.cc
index 8614a823..16462b8d 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_utf8.cc
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_utf8.cc
@@ -38,7 +38,7 @@
 #include "third_party/blink/renderer/platform/wtf/text/string_buffer.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_codec_ascii_fast_path.h"
 
-namespace WTF {
+namespace blink {
 
 // We'll use nonCharacter* constants to signal invalid utf-8.
 // The number in the name signals how many input bytes were invalid.
@@ -50,12 +50,12 @@
   return character >= kNonCharacter3 && character <= kNonCharacter1;
 }
 
-std::unique_ptr<TextCodec> TextCodecUTF8::Create(const TextEncoding&,
+std::unique_ptr<TextCodec> TextCodecUtf8::Create(const WTF::TextEncoding&,
                                                  const void*) {
-  return base::WrapUnique(new TextCodecUTF8());
+  return base::WrapUnique(new TextCodecUtf8());
 }
 
-void TextCodecUTF8::RegisterEncodingNames(EncodingNameRegistrar registrar) {
+void TextCodecUtf8::RegisterEncodingNames(EncodingNameRegistrar registrar) {
   registrar("UTF-8", "UTF-8");
 
   // Additional aliases that originally were present in the encoding
@@ -73,7 +73,7 @@
   registrar("unicode-1-1-utf-8", "UTF-8");
 }
 
-void TextCodecUTF8::RegisterCodecs(TextCodecRegistrar registrar) {
+void TextCodecUtf8::RegisterCodecs(TextCodecRegistrar registrar) {
   registrar("UTF-8", Create, nullptr);
 }
 
@@ -158,14 +158,14 @@
   return destination;
 }
 
-void TextCodecUTF8::ConsumePartialSequenceBytes(int num_bytes) {
+void TextCodecUtf8::ConsumePartialSequenceBytes(int num_bytes) {
   DCHECK_GE(partial_sequence_size_, num_bytes);
   partial_sequence_size_ -= num_bytes;
   memmove(partial_sequence_, partial_sequence_ + num_bytes,
           partial_sequence_size_);
 }
 
-void TextCodecUTF8::HandleError(int character,
+void TextCodecUtf8::HandleError(int character,
                                 UChar*& destination,
                                 bool stop_on_error,
                                 bool& saw_error) {
@@ -182,7 +182,7 @@
 }
 
 template <>
-bool TextCodecUTF8::HandlePartialSequence<LChar>(LChar*& destination,
+bool TextCodecUtf8::HandlePartialSequence<LChar>(LChar*& destination,
                                                  const uint8_t*& source,
                                                  const uint8_t* end,
                                                  bool flush,
@@ -240,7 +240,7 @@
 }
 
 template <>
-bool TextCodecUTF8::HandlePartialSequence<UChar>(UChar*& destination,
+bool TextCodecUtf8::HandlePartialSequence<UChar>(UChar*& destination,
                                                  const uint8_t*& source,
                                                  const uint8_t* end,
                                                  bool flush,
@@ -345,7 +345,7 @@
 };
 }  // namespace
 
-String TextCodecUTF8::Decode(base::span<const uint8_t> bytes,
+String TextCodecUtf8::Decode(base::span<const uint8_t> bytes,
                              FlushBehavior flush,
                              bool stop_on_error,
                              bool& saw_error) {
@@ -522,7 +522,7 @@
 }
 
 template <typename CharType>
-std::string TextCodecUTF8::EncodeCommon(base::span<const CharType> characters) {
+std::string TextCodecUtf8::EncodeCommon(base::span<const CharType> characters) {
   // The maximum number of UTF-8 bytes needed per UTF-16 code unit is 3.
   // BMP characters take only one UTF-16 code unit and can take up to 3 bytes
   // (3x).
@@ -549,7 +549,7 @@
 }
 
 template <typename CharType>
-TextCodec::EncodeIntoResult TextCodecUTF8::EncodeIntoCommon(
+TextCodec::EncodeIntoResult TextCodecUtf8::EncodeIntoCommon(
     base::span<const CharType> source,
     base::span<uint8_t> destination) {
   const auto* characters = source.data();
@@ -584,26 +584,26 @@
   return encode_into_result;
 }
 
-std::string TextCodecUTF8::Encode(base::span<const UChar> characters,
+std::string TextCodecUtf8::Encode(base::span<const UChar> characters,
                                   UnencodableHandling) {
   return EncodeCommon(characters);
 }
 
-std::string TextCodecUTF8::Encode(base::span<const LChar> characters,
+std::string TextCodecUtf8::Encode(base::span<const LChar> characters,
                                   UnencodableHandling) {
   return EncodeCommon(characters);
 }
 
-TextCodec::EncodeIntoResult TextCodecUTF8::EncodeInto(
+TextCodec::EncodeIntoResult TextCodecUtf8::EncodeInto(
     base::span<const UChar> characters,
     base::span<uint8_t> destination) {
   return EncodeIntoCommon(characters, destination);
 }
 
-TextCodec::EncodeIntoResult TextCodecUTF8::EncodeInto(
+TextCodec::EncodeIntoResult TextCodecUtf8::EncodeInto(
     base::span<const LChar> characters,
     base::span<uint8_t> destination) {
   return EncodeIntoCommon(characters, destination);
 }
 
-}  // namespace WTF
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_utf8.h b/third_party/blink/renderer/platform/wtf/text/text_codec_utf8.h
index de4c5910..1ea2317 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_utf8.h
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_utf8.h
@@ -31,18 +31,19 @@
 
 #include "third_party/blink/renderer/platform/wtf/text/text_codec.h"
 
-namespace WTF {
+namespace blink {
 
-class TextCodecUTF8 : public TextCodec {
+class TextCodecUtf8 : public TextCodec {
  public:
   static void RegisterEncodingNames(EncodingNameRegistrar);
   static void RegisterCodecs(TextCodecRegistrar);
 
  protected:
-  TextCodecUTF8() : partial_sequence_size_(0) {}
+  TextCodecUtf8() : partial_sequence_size_(0) {}
 
  private:
-  static std::unique_ptr<TextCodec> Create(const TextEncoding&, const void*);
+  static std::unique_ptr<TextCodec> Create(const WTF::TextEncoding&,
+                                           const void*);
 
   String Decode(base::span<const uint8_t> data,
                 FlushBehavior,
@@ -84,6 +85,6 @@
   uint8_t partial_sequence_[U8_MAX_LENGTH];
 };
 
-}  // namespace WTF
+}  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_TEXT_CODEC_UTF8_H_
diff --git a/third_party/blink/renderer/platform/wtf/text/text_encoding_registry.cc b/third_party/blink/renderer/platform/wtf/text/text_encoding_registry.cc
index 91150a6..7346b9929 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_encoding_registry.cc
+++ b/third_party/blink/renderer/platform/wtf/text/text_encoding_registry.cc
@@ -161,22 +161,22 @@
   g_text_codec_map = new TextCodecMap;
   g_text_encoding_name_map = new TextEncodingNameMap;
 
-  TextCodecLatin1::RegisterEncodingNames(AddToTextEncodingNameMap);
-  TextCodecLatin1::RegisterCodecs(AddToTextCodecMap);
+  blink::TextCodecLatin1::RegisterEncodingNames(AddToTextEncodingNameMap);
+  blink::TextCodecLatin1::RegisterCodecs(AddToTextCodecMap);
 
-  TextCodecUTF8::RegisterEncodingNames(AddToTextEncodingNameMap);
-  TextCodecUTF8::RegisterCodecs(AddToTextCodecMap);
+  blink::TextCodecUtf8::RegisterEncodingNames(AddToTextEncodingNameMap);
+  blink::TextCodecUtf8::RegisterCodecs(AddToTextCodecMap);
 
-  TextCodecUTF16::RegisterEncodingNames(AddToTextEncodingNameMap);
-  TextCodecUTF16::RegisterCodecs(AddToTextCodecMap);
+  blink::TextCodecUtf16::RegisterEncodingNames(AddToTextEncodingNameMap);
+  blink::TextCodecUtf16::RegisterCodecs(AddToTextCodecMap);
 
   TextCodecUserDefined::RegisterEncodingNames(AddToTextEncodingNameMap);
   TextCodecUserDefined::RegisterCodecs(AddToTextCodecMap);
 }
 
 static void ExtendTextCodecMaps() {
-  TextCodecReplacement::RegisterEncodingNames(AddToTextEncodingNameMap);
-  TextCodecReplacement::RegisterCodecs(AddToTextCodecMap);
+  blink::TextCodecReplacement::RegisterEncodingNames(AddToTextEncodingNameMap);
+  blink::TextCodecReplacement::RegisterCodecs(AddToTextCodecMap);
 
   TextCodecCJK::RegisterEncodingNames(AddToTextEncodingNameMap);
   TextCodecCJK::RegisterCodecs(AddToTextCodecMap);
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 39083e37..4637f50 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2764,7 +2764,7 @@
 
 # ====== New tests from wpt-importer added here ======
 crbug.com/424245323 [ Mac14 ] virtual/close-watcher/external/wpt/close-watcher/iframes/dialog-same-origin-ynn.html [ Skip Timeout ]
-crbug.com/424242611 [ Win11-arm64 ] external/wpt/orientation-sensor/RelativeOrientationSensor.https.html [ Pass Timeout ]
+crbug.com/424242611 [ Win11-arm64 ] external/wpt/orientation-sensor/RelativeOrientationSensor.https.html [ Failure Pass Timeout ]
 crbug.com/424229863 [ Android ] external/wpt/webdriver/tests/bidi/external/bluetooth/disable_simulation/context.py [ Failure ]
 crbug.com/424229863 [ Android ] external/wpt/webdriver/tests/bidi/external/bluetooth/disable_simulation/disable_simulation.py [ Failure ]
 crbug.com/424229863 [ Android ] external/wpt/webdriver/tests/bidi/external/bluetooth/simulate_gatt_connection_response/simulate_gatt_connection_response.py [ Failure ]
@@ -5220,6 +5220,7 @@
 crbug.com/1047293 [ Mac ] editing/pasteboard/pasteboard_with_unfocused_selection.html [ Failure Pass ]
 
 crbug.com/424416586 [ Mac ] inspector-protocol/overlay/overlay-resume-click-events.js [ Failure Pass Timeout ]
+crbug.com/424416586 [ Win ] inspector-protocol/overlay/overlay-resume-click-events.js [ Failure Pass Timeout ]
 
 # Mixed content autoupgrades make these tests not applicable, since they check for mixed content audio/video
 crbug.com/1025274 external/wpt/mixed-content/gen/top.meta/unset/audio-tag.https.html [ Failure ]
@@ -8526,7 +8527,7 @@
 b/40270061 http/tests/inspector-protocol/tracing/runtime-stats.js [ Crash Failure Pass Timeout ]
 
 #Loading bug triage 2024-05-16
-crbug.com/339833760 [ Win ] virtual/viewport-and-meta-enabled/http/tests/preload/meta-viewport-link-headers-imagesrcset.php [ Failure Pass ]
+crbug.com/339833760 [ Win ] virtual/viewport-and-meta-enabled/http/tests/preload/meta-viewport-link-headers-imagesrcset.php [ Failure Pass Timeout ]
 
 # Gardener 2024-05-29
 crbug.com/343473478 external/wpt/html/semantics/forms/the-input-element/click-user-gesture.html [ Failure Pass ]
@@ -9145,3 +9146,6 @@
 
 # Gardener 2025-06-12
 crbug.com/422636456 [ Mac ] http/tests/inspector-protocol/network/navigate-iframe-out2in.js [ Pass Timeout ]
+
+# Gardener 2025-06-13
+crbug.com/424644790 http/tests/inspector-protocol/tracing/soft-navigations.js [ Failure Pass ]
diff --git a/third_party/blink/web_tests/editing/caret/caret-shape-block-empty-element.html b/third_party/blink/web_tests/editing/caret/caret-shape-block-empty-element.html
new file mode 100644
index 0000000..96d8bd7
--- /dev/null
+++ b/third_party/blink/web_tests/editing/caret/caret-shape-block-empty-element.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>caret-shape block in an empty textarea</title>
+<link rel="help" href="https://drafts.csswg.org/css-ui/#caret-shape">
+<meta name="flags" content="interact">
+<meta name="assert" content="Test checks that caret-shape block can be set in an empty textarea">
+<style>
+  textarea {
+    font-size: 1em;
+    font-weight: bold;
+    width: 50em;
+    padding: 10px;
+    background: white;
+    color: blue;
+    caret-color: red;
+    caret-shape: block;
+  }
+</style>
+
+<body>
+  <p>Test passes if, when the empty text area below is focused for editing, the text insertion caret is a block.</p>
+  <p>Whether the caret flashes or how it flashes, are not part of the test.</p>
+  <textarea id="test"></textarea><br>
+  <script>
+    window.onload = function () {
+      document.getElementById("test").focus();
+    }
+  </script>
+</body>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/editing/caret/caret-shape-block.html b/third_party/blink/web_tests/editing/caret/caret-shape-block.html
new file mode 100644
index 0000000..eb5ae2e
--- /dev/null
+++ b/third_party/blink/web_tests/editing/caret/caret-shape-block.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>caret-shape block in a textarea</title>
+<link rel="help" href="https://drafts.csswg.org/css-ui/#caret-shape">
+<meta name="flags" content="interact">
+<meta name="assert" content="Test checks that caret-shape block can be set in a textarea">
+<style>
+  textarea {
+    font-size: 1em;
+    font-weight: bold;
+    width: 50em;
+    padding: 10px;
+    background: white;
+    color: blue;
+    caret-color: red;
+    caret-shape: block;
+  }
+</style>
+
+<body>
+  <p>Test passes if, when the text area below is focused for editing, the text insertion caret is a block.</p>
+  <p>Whether the caret flashes or how it flashes, are not part of the test.</p>
+  <textarea id="test">The text insertion caret should be a block over the following character.</textarea>
+  <script>
+    window.onload = function () {
+      document.getElementById("test").focus();
+    }
+  </script>
+</body>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/editing/caret/caret-shape-underscore-empty-element.html b/third_party/blink/web_tests/editing/caret/caret-shape-underscore-empty-element.html
new file mode 100644
index 0000000..42fc24a
--- /dev/null
+++ b/third_party/blink/web_tests/editing/caret/caret-shape-underscore-empty-element.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>caret-shape underscore in an empty textarea</title>
+<link rel="help" href="https://drafts.csswg.org/css-ui/#caret-shape">
+<meta name="flags" content="interact">
+<meta name="assert" content="Test checks that caret-shape underscore can be set in an empty textarea">
+<style>
+  textarea {
+    font-size: 1em;
+    font-weight: bold;
+    width: 50em;
+    padding: 10px;
+    background: white;
+    color: blue;
+    caret-color: red;
+    caret-shape: underscore;
+  }
+</style>
+
+<body>
+  <p>Test passes if, when the text area below is focused for editing, the text insertion caret is a underscore.</p>
+  <p>Whether the caret flashes or how it flashes, are not part of the test.</p>
+  <textarea id="test"></textarea><br>
+  <script>
+    window.onload = function () {
+      document.getElementById("test").focus();
+    }
+  </script>
+</body>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/editing/caret/caret-shape-underscore.html b/third_party/blink/web_tests/editing/caret/caret-shape-underscore.html
new file mode 100644
index 0000000..999f69f0
--- /dev/null
+++ b/third_party/blink/web_tests/editing/caret/caret-shape-underscore.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>caret-shape underscore in a textarea</title>
+<link rel="help" href="https://drafts.csswg.org/css-ui/#caret-shape">
+<meta name="flags" content="interact">
+<meta name="assert" content="Test checks that caret-shape underscore can be set in a textarea">
+<style>
+  textarea {
+    font-size: 1em;
+    font-weight: bold;
+    width: 50em;
+    padding: 10px;
+    background: white;
+    color: blue;
+    caret-color: red;
+    caret-shape: underscore;
+  }
+</style>
+
+<body>
+  <p>Test passes if, when the text area below is focused for editing, the text insertion caret is a underscore.</p>
+  <p>Whether the caret flashes or how it flashes, are not part of the test.</p>
+  <textarea id="test">The text insertion caret should be an underline of the following character.</textarea>
+  <script>
+    window.onload = function () {
+      document.getElementById("test").focus();
+    }
+  </script>
+</body>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchored-child-transition-with-selection.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchored-child-transition-with-selection.html
new file mode 100644
index 0000000..d18cb079
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchored-child-transition-with-selection.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>CSS Anchor Positioning Test: Transition on anchored element child with ::selection</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+  #container {
+    position: absolute;
+    right: anchor(right);
+    --i: 1px;
+  }
+  #content {
+    scale: 0;
+    transition: scale 1000s step-end;
+  }
+  #content.show { scale: 1; }
+  ::selection { color: var(--a); }
+  #container.foo {}
+</style>
+<div id="container">
+  <div id="content">FAIL</div>
+</div>
+<script>
+  test(() => {
+    content.offsetTop;
+    content.classList.toggle("show");
+    container.classList.toggle("foo");
+    assert_equals(getComputedStyle(content).scale, "0");
+  }, "Should transition scale property on anchored child");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/contextmenu-historical-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/contextmenu-historical-expected.txt
index 1066b42..f888bb59 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/contextmenu-historical-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/interactive-elements/contextmenu-historical-expected.txt
@@ -5,7 +5,5 @@
   assert_array_equals: lengths differ, expected array [] length 0, got object "[object NodeList]" length 3
 [FAIL] :disabled must not match menuitems
   assert_array_equals: lengths differ, expected array [] length 0, got object "[object NodeList]" length 1
-[FAIL] :default must not match menuitems
-  assert_array_equals: lengths differ, expected array [] length 0, got object "[object NodeList]" length 1
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/menu/tentative/checkable.html b/third_party/blink/web_tests/external/wpt/html/semantics/menu/tentative/checkable.html
new file mode 100644
index 0000000..d801fa1b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/menu/tentative/checkable.html
@@ -0,0 +1,209 @@
+<!DOCTYPE html>
+<html>
+<link rel=author href=mailto:dom@chromium.org>
+<link rel=help href=https://open-ui.org/components/menu.explainer>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<menubar>
+  <fieldset checkable=single>
+    <menuitem id=menubar-menuitem></menuitem>
+  </fieldset>
+</menubar>
+
+<menulist>
+  <menuitem id=menulist-menuitem-not-checkable></menuitem>
+  <fieldset checkable=single>
+    <menuitem id=menulist-menuitem-checkable></menuitem>
+  </fieldset>
+  <fieldset checkable=single>
+    <menuitem id=single1></menuitem>
+    <menuitem id=single2></menuitem>
+    <menuitem id=single3></menuitem>
+  </fieldset>
+  <fieldset checkable=multiple>
+    <menuitem id=multiple1></menuitem>
+    <menuitem id=multiple2></menuitem>
+    <menuitem id=multiple3></menuitem>
+  </fieldset>
+</menulist>
+
+<script>
+test(() => {
+  const mi = document.createElement('menuitem');
+  assert_false(mi.checked, "defaults to unchecked when detached");
+  assert_false(mi.matches(":checked"));
+  mi.checked = true;
+  assert_equals(mi.checked, false, "cannot be checked when detached");
+  assert_false(mi.matches(":checked"));
+
+  document.body.append(mi);
+
+  assert_equals(mi.checked, false, "defaults to unchecked when connected");
+  assert_false(mi.matches(":checked"));
+  mi.checked = true;
+  assert_equals(mi.checked, false,
+      "cannot be checked when not attached in a menulist");
+  assert_false(mi.matches(":checked"));
+
+  mi.remove();
+}, "menuitem is not checkable on its own");
+
+test(() => {
+  const mi = document.querySelector("#menubar-menuitem");
+  assert_equals(mi.checked, false, "menuitem in menubar is not checked");
+  assert_false(mi.matches(":checked"));
+  mi.checked = true;
+  assert_equals(mi.checked, false, "menuitem in menubar cannot be checked");
+  assert_false(mi.matches(":checked"));
+}, "menuitem in menubar is not checkable");
+
+test(() => {
+  const nonCheckable =
+      document.querySelector("#menulist-menuitem-not-checkable");
+  assert_equals(nonCheckable.checked, false,
+      "menuitem direct child of menulist is not checked");
+  assert_false(nonCheckable.matches(":checked"));
+  nonCheckable.checked = true;
+  assert_equals(nonCheckable.checked, false,
+      "menuitem direct child of menulist cannot be checked");
+  assert_false(nonCheckable.matches(":checked"));
+
+  const checkable = document.querySelector("#menulist-menuitem-checkable");
+  assert_equals(nonCheckable.checked, false,
+      "checkable menuitem is not checked");
+  assert_false(nonCheckable.matches(":checked"));
+  checkable.checked = true;
+  assert_equals(checkable.checked, true, "checkable menuitem is checked");
+  assert_true(checkable.matches(":checked"));
+}, "menuitem in menulist");
+
+test(() => {
+  assert_false(single1.checked, "single1 not checked");
+  assert_false(single1.matches(":checked"), "single1 not :checked");
+  assert_false(single2.checked, "single2 not checked");
+  assert_false(single2.matches(":checked"), "single2 not :checked");
+  assert_false(single3.checked, "single3 not checked");
+  assert_false(single3.matches(":checked"), "single3 not :checked");
+
+  single1.checked = true;
+  assert_true(single1.checked, "single1 IS checked [after single1 checked]");
+  assert_true(single1.matches(":checked"),
+      "single1 IS :checked [after single1 checked]");
+  assert_false(single2.checked, "single2 not checked [after single1 checked]");
+  assert_false(single2.matches(":checked"),
+      "single2 not :checked [after single1 checked]");
+  assert_false(single3.checked, "single3 not checked [after single1 checked]");
+  assert_false(single3.matches(":checked"),
+      "single3 not :checked [after single1 checked]");
+
+  single2.checked = true;
+  assert_false(single1.checked, "single1 not checked [after single2 checked]");
+  assert_false(single1.matches(":checked"),
+      "single1 not :checked [after single2 checked]");
+  assert_true(single2.checked, "single2 IS checked [after single1 checked]");
+  assert_true(single2.matches(":checked"),
+      "single2 IS :checked [after single2 checked]");
+  assert_false(single3.checked, "single3 not checked [after single2 checked]");
+  assert_false(single3.matches(":checked"),
+      "single3 not :checked [after single2 checked]");
+
+  single3.checked = true;
+  assert_false(single1.checked, "single1 not checked [after single3 checked]");
+  assert_false(single1.matches(":checked"),
+      "single1 not :checked [after single3 checked]");
+  assert_false(single2.checked, "single2 not checked [after single3 checked]");
+  assert_false(single2.matches(":checked"),
+      "single2 not :checked [after single3 checked]");
+  assert_true(single3.checked, "single3 IS checked [after single3 checked]");
+  assert_true(single3.matches(":checked"),
+      "single3 IS :checked [after single3 checked]");
+}, "checkable menuitem exclusivity");
+
+test(() => {
+  assert_false(multiple1.checked, "multiple1 not checked");
+  assert_false(multiple1.matches(":checked"), "multiple1 not :checked");
+  assert_false(multiple2.checked, "multiple2 not checked");
+  assert_false(multiple2.matches(":checked"), "multiple2 not :checked");
+  assert_false(multiple3.checked, "multiple3 not checked");
+  assert_false(multiple3.matches(":checked"), "multiple2 not :checked");
+
+  multiple1.checked = true;
+  assert_true(multiple1.checked, "multiple1 checked [after multiple1 checked]");
+  assert_true(multiple1.matches(":checked"),
+      "multiple1 IS :checked [after multiple1 checked]");
+  assert_false(multiple2.checked, "multiple2 not checked [after multiple1 checked]");
+  assert_false(multiple2.matches(":checked"),
+      "multiple2 not :checked [after multiple1 checked]");
+  assert_false(multiple3.checked, "multiple3 not checked [after multiple1 checked]");
+  assert_false(multiple3.matches(":checked"),
+      "multiple3 not :checked [after multiple1 checked]");
+
+  multiple2.checked = true;
+  assert_true(multiple1.checked, "multiple1 checked [after multiple2 checked]");
+  assert_true(multiple1.matches(":checked"),
+      "multiple1 IS :checked [after multiple2 checked]");
+  assert_true(multiple2.checked, "multiple2 checked [after multiple2 checked]");
+  assert_true(multiple2.matches(":checked"),
+      "multiple2 IS :checked [after multiple2 checked]");
+  assert_false(multiple3.checked, "multiple3 not checked [after multiple2 checked]");
+  assert_false(multiple3.matches(":checked"),
+      "multiple3 not :checked [after multiple2 checked]");
+
+  multiple3.checked = true;
+  assert_true(multiple1.checked, "multiple1 checked [after multiple3 checked]");
+  assert_true(multiple1.matches(":checked"),
+      "multiple1 IS :checked [after multiple3 checked]");
+  assert_true(multiple2.checked, "multiple2 checked [after multiple3 checked]");
+  assert_true(multiple2.matches(":checked"),
+      "multiple2 IS :checked [after multiple3 checked]");
+  assert_true(multiple3.checked, "multiple3 checked [after multiple3 checked]");
+  assert_true(multiple3.matches(":checked"),
+      "multiple3 IS checked [after multiple3 checked]");
+}, "checkable multiple");
+
+test(() => {
+  const menulist = document.createElement('menulist');
+  const fieldset = menulist.appendChild(document.createElement('fieldset'));
+  fieldset.setAttribute("checkable", "single");
+  const single1 = fieldset.appendChild(document.createElement('menuitem'));
+  const single2 = fieldset.appendChild(document.createElement('menuitem'));
+
+  single1.checked = true;
+  single2.checked = true;
+
+  assert_false(single1.checked, "single1 is unchecked");
+  assert_true(single2.checked, "single2 is checked");
+}, "checkable menuitem exclusivity when disconnected");
+
+test(() => {
+  const menulist = document.createElement('menulist');
+  const fieldset = menulist.appendChild(document.createElement('fieldset'));
+  fieldset.setAttribute("checkable", "single");
+  const single1 = fieldset.appendChild(document.createElement('menuitem'));
+
+  single1.checked = true;
+  assert_true(single1.checked, true);
+  fieldset.removeAttribute('checkable');
+  assert_false(single1.checked, false,
+      "menuitem gets unchecked after fieldset becomes uncheckable");
+  single1.checked = true;
+  assert_false(single1.checked,
+      "menuitem cannot become checked after fieldset becomes uncheckable");
+}, "when fieldset becomes uncheckable, so do its menuitems");
+
+test(() => {
+  const menulist = document.createElement('menulist');
+  const fieldset = menulist.appendChild(document.createElement('fieldset'));
+  fieldset.setAttribute("checkable", "multiple");
+  const single1 = fieldset.appendChild(document.createElement('menuitem'));
+  const single2 = fieldset.appendChild(document.createElement('menuitem'));
+
+  single1.checked = true;
+  single2.checked = true;
+  fieldset.setAttribute("checkable", "single");
+  assert_true(single1.checked, "first menuitem stays checked");
+  assert_false(single2.checked, "second menuitem becomes unchecked");
+}, "fieldset multiple => single; all but the first checked menuitem gets " +
+   "reset");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/menu/tentative/menubar-invoke-menulist.html b/third_party/blink/web_tests/external/wpt/html/semantics/menu/tentative/menubar-invoke-menulist.html
index 35740f45..3fe0caf 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/menu/tentative/menubar-invoke-menulist.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/menu/tentative/menubar-invoke-menulist.html
@@ -15,11 +15,18 @@
  <menuitem>Command 2</menuitem>
 </menulist>
 
+<menulist>
+  <fieldset checkable>
+    <menuitem id="checkable-menuitem">Show menu</menuitem>
+  </fieldset>
+</menulist>
+
 <script>
 const menubar = document.querySelector("menubar");
 const menubaritem = document.getElementById("menubaritem");
 const menulist = document.querySelector("menulist");
 const menulistitem = document.getElementById("menulistitem");
+const checkableMenuitem = document.getElementById("checkable-menuitem");
 
 test(() => {
  assert_equals(menubar.constructor, HTMLMenuBarElement);
@@ -36,31 +43,6 @@
 }, "Menu elements are HTML elements.");
 
 test(() => {
-  // `defaultChecked`.
-  assert_equals(menubaritem.defaultChecked, undefined,
-      "menuitem does not have a defaultChecked attribute");
-
-  // `checked` content & IDL attribute behavior.
-  // By default, attribute missing/null, which translates to the false IDL
-  // boolean state.
-  assert_equals(menubaritem.getAttribute('checked'), null);
-  assert_false(menubaritem.checked);
-
-  // The IDL attribute reads from the same state that the content attribute
-  // writes to.
-  menubaritem.setAttribute("checked", "true");
-  assert_true(menubaritem.checked);
-
-  // But the IDL attribute does not reflect [1] the content attribute value,
-  // which means when it is updated, the content attribute does not change.
-  //
-  // [1]: https://html.spec.whatwg.org/C#reflect
-  menubaritem.checked = false;
-  assert_false(menubaritem.checked);
-  menubaritem.setAttribute("checked", "true");
-}, "menuitem checked attribute");
-
-test(() => {
  menubaritem.setAttribute("command", "toggle-popover");
  menubaritem.setAttribute("commandfor", "more");
 
@@ -100,4 +82,23 @@
  assert_false(menulist.matches(':popover-open'),
     'The menulist should not open because the menuitem command is invalid');
 }, "Menuitem with invalid command/commandfor cannot invoke menulist popover.");
+
+test(() => {
+  checkableMenuitem.command = "show-menu";
+  checkableMenuitem.commandForElement = menulist;
+
+  checkableMenuitem.click();
+  assert_true(checkableMenuitem.checked,
+      "checkable menu item becomes checked");
+  assert_true(menulist.matches(":popover-open"),
+      "menulist matches :popover-open");
+
+  checkableMenuitem.setAttribute("command", "hide-menu");
+  checkableMenuitem.click();
+
+  assert_false(checkableMenuitem.checked,
+      "checkable menu item is still checked");
+  assert_false(menulist.matches(":popover-open"),
+      "menulist no longer matches :popover-open");
+}, "Checkable menuitems can still invoke menulist popovers");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/svg/struct/reftests/sync-svg-attributes-ref.svg b/third_party/blink/web_tests/external/wpt/svg/struct/reftests/sync-svg-attributes-ref.svg
new file mode 100644
index 0000000..f68db2a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/struct/reftests/sync-svg-attributes-ref.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+    <text y="20">The two texts should be on top of each other</text>
+    <text y="20" fill="blue">The two texts should be on top of each other</text>
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/svg/struct/reftests/sync-svg-attributes.svg b/third_party/blink/web_tests/external/wpt/svg/struct/reftests/sync-svg-attributes.svg
new file mode 100644
index 0000000..ef780dd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/struct/reftests/sync-svg-attributes.svg
@@ -0,0 +1,17 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml"
+     class="reftest-wait">
+  <metadata>
+    <title>SVG attributes gets synced properly on use shadow dom</title>
+    <h:link rel="match" href="sync-svg-attributes-ref.svg"/>
+  </metadata>
+  <g id="g">
+    <text y="100">The two texts should be on top of each other</text>
+  </g>
+  <use href="#g" fill="blue"/>
+  <script>
+    requestAnimationFrame(() => requestAnimationFrame(() => {
+      document.querySelector('#g > text').setAttribute('y', '20')
+      document.documentElement.classList.remove('reftest-wait');
+    }));
+  </script>
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/svg/struct/reftests/use-event-handler-no-loss-of-events-ref.html b/third_party/blink/web_tests/external/wpt/svg/struct/reftests/use-event-handler-no-loss-of-events-ref.html
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/struct/reftests/use-event-handler-no-loss-of-events-ref.html
diff --git a/third_party/blink/web_tests/external/wpt/svg/struct/reftests/use-event-handler-no-loss-of-events.html b/third_party/blink/web_tests/external/wpt/svg/struct/reftests/use-event-handler-no-loss-of-events.html
new file mode 100644
index 0000000..e56e320d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/struct/reftests/use-event-handler-no-loss-of-events.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html class="reftest-wait"></html>
+<meta charset="utf-8">
+<title>No loss of events when use instances copies event handlers</title>
+<link rel="author" title="Divyansh Mangal" href="mailto:dmangal@microsoft.com">
+<link rel="help" href="https://svgwg.org/svg2-draft/struct.html#UseEventHandling">
+<link rel="match" href="reference/green-100x100.html">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+
+<svg xmlns="http://www.w3.org/2000/svg">
+  <defs>
+    <rect id="target" width="100" height="100" onclick="click()" onmouseover="handleMouseOver()"/>
+  </defs>
+  <use id="use" href="#target"/>
+</svg>
+
+<script>
+  const use = document.getElementById("use");
+  function click() {
+    document.getElementById("target").setAttribute("fill", "green");
+  }
+
+  function handleMouseOver() {
+    document.getElementById("target").setAttribute("fill", "red");
+  }
+
+  requestAnimationFrame(() => requestAnimationFrame(() => {
+    new test_driver.Actions()
+        .pointerMove(50, 50, { origin: use })
+        .pointerDown()
+        .pointerUp()
+        .send()
+        .then(() =>  document.documentElement.classList.remove('reftest-wait'));
+    }));
+</script>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpReceiver-getParameters.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpReceiver-getParameters.html
index 14ec74b..a55f766 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpReceiver-getParameters.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpReceiver-getParameters.html
@@ -84,10 +84,16 @@
     callee.addTrack(track);
     var callerReceiver = caller.getTransceivers()[0].receiver;
     assert_equals(callerReceiver.getParameters().codecs.length, 0);
+    assert_equals(callerReceiver.getParameters().headerExtensions.length, 0,
+      "no caller header extensions before offer");
     const offer = await caller.createOffer();
     await caller.setLocalDescription(offer);
     await callee.setRemoteDescription(offer);
     var calleeReceiver = callee.getTransceivers()[0].receiver;
+    // Callee transceiver exists only after offer - population of parameters
+    // should only occur after answer.
+    assert_equals(calleeReceiver.getParameters().headerExtensions.length, 0,
+      "no callee header extensions before answer");
     assert_equals(calleeReceiver.getParameters().codecs.length, 0);
     const answer = await callee.createAnswer();
     await callee.setLocalDescription(answer);
@@ -96,6 +102,10 @@
     await caller.setRemoteDescription(answer);
     assert_greater_than(callerReceiver.getParameters().codecs.length, 0,
       "caller codecs after answer");
+    assert_greater_than(callerReceiver.getParameters().headerExtensions.length, 0,
+      "caller header extensions after O/A");
+    assert_greater_than(calleeReceiver.getParameters().headerExtensions.length, 0,
+      "callee header extensions after O/A");
   }, 'getParameters() surfaces codecs on two-way receiver at the right time');
 
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/websockets/stream/tentative/write.any.js b/third_party/blink/web_tests/external/wpt/websockets/stream/tentative/write.any.js
index 43af7da..7f859e12 100644
--- a/third_party/blink/web_tests/external/wpt/websockets/stream/tentative/write.any.js
+++ b/third_party/blink/web_tests/external/wpt/websockets/stream/tentative/write.any.js
@@ -94,3 +94,18 @@
   await promise_rejects_js(
       t, TypeError, writer.write(view), 'write() should reject');
 }, 'writing a view on a shared buffer should be rejected');
+
+promise_test(async () => {
+  let wss = new WebSocketStream(ECHOURL);
+  let { writable } = await wss.opened;
+  let writer = writable.getWriter();
+  wss = writable = null;
+  const promises = [];
+  for (let i = 0; i < 20; ++i) {
+    promises.push(writer.write(new Uint8Array(100000)));
+  }
+  writer = null;
+  for (let i = 0; i < 5; ++i) {
+    await garbageCollect();
+  }
+}, 'Garbage collecting a WebSocket stream doesn\'t crash while write promise is pending');
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/tracing/soft-navigations-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/tracing/soft-navigations-expected.txt
index 04be67f..2d46c10 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/tracing/soft-navigations-expected.txt
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/tracing/soft-navigations-expected.txt
@@ -1,14 +1,31 @@
 Tests trace events for soft navigations.
 
 PerformanceObserver supports "soft-navigation": true
-
-Waited for LCP element with id=click-target
 Recording started
 
-Got soft navigation performance entry: http://127.0.0.1:8000/greeting
-Tracing complete
+Waited for LCP element with id=click-target
 
-Got SoftNavigation event:
+Got soft navigation performance entry: http://127.0.0.1:8000/greeting
+
+Stopping tracing and analyzing events.
+Tracing complete
+-> LCP candidate event
+   ts: 1
+   frame: id_0
+   navigationId: id_1
+-> SoftNavigation event
+   interactionTimestamp: 2
+   ts: 3
+   frame: id_0
+   navigationId: id_2
+   initialURL: http://127.0.0.1:8000/greeting
+   mostRecentURL: http://127.0.0.1:8000/greeting
+-> LCP candidate event
+   ts: 4
+   frame: id_0
+   navigationId: id_2
+
+SoftNavigation event shape:
 Object: {
 	args: {
 		context: {
@@ -34,3 +51,26 @@
 	ts: number
 }
 
+LCP candidate event shape:
+Object: {
+	args: {
+		data: {
+			candidateIndex: number
+			isMainFrame: boolean
+			isOutermostMainFrame: boolean
+			navigationId: string
+			nodeId: number
+			size: number
+			type: string
+		}
+		frame: string
+	}
+	cat: string
+	name: string
+	ph: string
+	pid: number
+	s: string
+	tid: number
+	ts: number
+}
+
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/tracing/soft-navigations.js b/third_party/blink/web_tests/http/tests/inspector-protocol/tracing/soft-navigations.js
index d54f971..8513de2b 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/tracing/soft-navigations.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/tracing/soft-navigations.js
@@ -1,8 +1,6 @@
 (async function(/** @type {import('test_runner').TestRunner} */ testRunner) {
-  // Load test page and wait for the LCP element (it's also the click target).
-  const {page, session, dp} = await testRunner.startURL(
-      'http://127.0.0.1:8000/inspector-protocol/resources/soft-navigations.html',
-      'Tests trace events for soft navigations.');
+  const {session, dp} =
+      await testRunner.startBlank('Tests trace events for soft navigations.');
 
   // Check if the browser supports soft-navigation.
   testRunner.log(
@@ -10,6 +8,18 @@
       await session.evaluate(
           `PerformanceObserver.supportedEntryTypes.includes('soft-navigation')`));
 
+  // Start tracing and observe the devtools.timeline category.
+  const TracingHelper =
+      await testRunner.loadScript('../resources/tracing-test.js');
+  const tracingHelper = new TracingHelper(testRunner, session);
+  await tracingHelper.startTracing('devtools.timeline');
+
+  // Load test page and wait for the LCP element (it's also the click target).
+  const url =
+      'http://127.0.0.1:8000/inspector-protocol/resources/soft-navigations.html';
+  await dp.Page.navigate({url});
+
+
   const lcpElementId = await session.evaluateAsync(`new Promise(resolve => {
     new PerformanceObserver(list => {
       resolve(list.getEntries()[0].id);
@@ -42,12 +52,6 @@
     return {x: (rect.left + rect.width) / 2, y: (rect.top + rect.height) / 2};
   });
 
-  // Start tracing and observe the devtools.timeline category.
-  const TracingHelper =
-      await testRunner.loadScript('../resources/tracing-test.js');
-  const tracingHelper = new TracingHelper(testRunner, session);
-  await tracingHelper.startTracing('devtools.timeline');
-
   // The click which causes the soft navigation (via its click handler).
   userInteractionClick(clickTargetCenter);
 
@@ -58,16 +62,78 @@
       resolve(list.getEntries()[0].name);
     }).observe({type: 'soft-navigation', buffered: true});
   })`);
-  testRunner.log('\nGot soft navigation performance entry: ' + softNavigationName);
+  testRunner.log(
+      '\nGot soft navigation performance entry: ' + softNavigationName);
 
   // Stop tracing and log the SoftNavigation event.
-  await tracingHelper.stopTracing();
-  const Phase = TracingHelper.Phase;
-  const softNavigationEvent = tracingHelper.findEvent(
-      'SoftNavigationHeuristics_SoftNavigationDetected', Phase.INSTANT);
+  testRunner.log('\nStopping tracing and analyzing events.');
+  const unfilteredEvents = await tracingHelper.stopTracing();
 
-  testRunner.log('\nGot SoftNavigation event:');
-  tracingHelper.logEventShape(softNavigationEvent);
+  // Maps timestamps (monononically increasing double) to a counter.
+  class TimestampMapper {
+    constructor() {
+      this.time = 0;
+      this.counter = 0;
+    }
+
+    map(timestamp) {
+      if (this.time === timestamp) {
+        return this.counter;
+      }
+      if (this.time > timestamp) {
+        throw new Error('Timestamps not in chronological order');
+      }
+      this.time = timestamp;
+      this.counter++;
+      return this.counter;
+    }
+  }
+
+  // Maps actual IDs (e.g. navigationId) to logical IDs (e.g. 'id_0').
+  class IdMapper {
+    constructor() {
+      this.logicalIdByActualId = new Map();
+    }
+
+    map(id) {
+      let logical = this.logicalIdByActualId.get(id);
+      if (!logical) {
+        logical = 'id_' + this.logicalIdByActualId.size;
+        this.logicalIdByActualId.set(id, logical);
+      }
+      return logical;
+    }
+  }
+
+  const timestamps = new TimestampMapper();
+  const ids = new IdMapper();
+  const softNavs = [];
+  const lcpCandidates = [];
+  for (const event of unfilteredEvents) {
+    if (event.name === 'SoftNavigationHeuristics_SoftNavigationDetected') {
+      testRunner.log('-> SoftNavigation event');
+      testRunner.log('   interactionTimestamp: ' + timestamps.map(event.args.context.interactionTimestamp));
+      testRunner.log('   ts: ' + timestamps.map(event.ts));
+      testRunner.log('   frame: ' + ids.map(event.args.frame));
+      testRunner.log('   navigationId: ' + ids.map(event.args.navigationId));
+      testRunner.log('   initialURL: ' + event.args.context.initialURL)
+      testRunner.log('   mostRecentURL: ' + event.args.context.mostRecentURL)
+      softNavs.push(event);
+    } else if (event.name === 'largestContentfulPaint::Candidate') {
+      testRunner.log('-> LCP candidate event');
+      testRunner.log('   ts: ' + timestamps.map(event.ts));
+      testRunner.log('   frame: ' + ids.map(event.args.frame));
+      testRunner.log(
+          '   navigationId: ' + ids.map(event.args.data.navigationId));
+      lcpCandidates.push(event);
+    }
+  }
+
+  testRunner.log('\nSoftNavigation event shape:');
+  tracingHelper.logEventShape(softNavs[0]);
+
+  testRunner.log('\nLCP candidate event shape:');
+  tracingHelper.logEventShape(lcpCandidates[0]);
 
   testRunner.completeTest();
 })
diff --git a/third_party/blink/web_tests/platform/linux/editing/caret/caret-shape-block-empty-element-expected.png b/third_party/blink/web_tests/platform/linux/editing/caret/caret-shape-block-empty-element-expected.png
new file mode 100644
index 0000000..3afe5d6e
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/editing/caret/caret-shape-block-empty-element-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/editing/caret/caret-shape-block-expected.png b/third_party/blink/web_tests/platform/linux/editing/caret/caret-shape-block-expected.png
new file mode 100644
index 0000000..3683fc73
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/editing/caret/caret-shape-block-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/editing/caret/caret-shape-underscore-empty-element-expected.png b/third_party/blink/web_tests/platform/linux/editing/caret/caret-shape-underscore-empty-element-expected.png
new file mode 100644
index 0000000..94c4e31
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/editing/caret/caret-shape-underscore-empty-element-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/editing/caret/caret-shape-underscore-expected.png b/third_party/blink/web_tests/platform/linux/editing/caret/caret-shape-underscore-expected.png
new file mode 100644
index 0000000..b828908
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/editing/caret/caret-shape-underscore-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/editing/caret/caret-shape-block-empty-element-expected.png b/third_party/blink/web_tests/platform/mac/editing/caret/caret-shape-block-empty-element-expected.png
new file mode 100644
index 0000000..a41a7e58
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/editing/caret/caret-shape-block-empty-element-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/editing/caret/caret-shape-block-expected.png b/third_party/blink/web_tests/platform/mac/editing/caret/caret-shape-block-expected.png
new file mode 100644
index 0000000..76c7788
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/editing/caret/caret-shape-block-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/editing/caret/caret-shape-underscore-empty-element-expected.png b/third_party/blink/web_tests/platform/mac/editing/caret/caret-shape-underscore-empty-element-expected.png
new file mode 100644
index 0000000..521ec1ab
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/editing/caret/caret-shape-underscore-empty-element-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/editing/caret/caret-shape-underscore-expected.png b/third_party/blink/web_tests/platform/mac/editing/caret/caret-shape-underscore-expected.png
new file mode 100644
index 0000000..7ca2501
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac/editing/caret/caret-shape-underscore-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/editing/caret/caret-shape-block-empty-element-expected.png b/third_party/blink/web_tests/platform/win/editing/caret/caret-shape-block-empty-element-expected.png
new file mode 100644
index 0000000..0ac5c9d6
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/editing/caret/caret-shape-block-empty-element-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/editing/caret/caret-shape-block-expected.png b/third_party/blink/web_tests/platform/win/editing/caret/caret-shape-block-expected.png
new file mode 100644
index 0000000..fe00283
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/editing/caret/caret-shape-block-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/editing/caret/caret-shape-underscore-empty-element-expected.png b/third_party/blink/web_tests/platform/win/editing/caret/caret-shape-underscore-empty-element-expected.png
new file mode 100644
index 0000000..479f533
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/editing/caret/caret-shape-underscore-empty-element-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/editing/caret/caret-shape-underscore-expected.png b/third_party/blink/web_tests/platform/win/editing/caret/caret-shape-underscore-expected.png
new file mode 100644
index 0000000..ed77f87
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/editing/caret/caret-shape-underscore-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/orientation-sensor/RelativeOrientationSensor.https-expected.txt b/third_party/blink/web_tests/platform/win11-arm64/external/wpt/orientation-sensor/RelativeOrientationSensor.https-expected.txt
deleted file mode 100644
index 2b989e5..0000000
--- a/third_party/blink/web_tests/platform/win11-arm64/external/wpt/orientation-sensor/RelativeOrientationSensor.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Traceback (most recent call last):\n  File "C:\\b\\s\\w\\ir\\third_party\\wpt_tools\\wpt\\tools\\wptrunner\\wptrunner\\executors\\base.py", line 773, in process_action\n    action_handler = self.actions[action]\n                     ~~~~~~~~~~~~^^^^^^^^\nKeyError: 'bidi.permissions.set_permission'\n\nThe above exception was the direct cause of the following exception:\n\nTraceback (most recent call last):\n  File "C:\\b\\s\\w\\ir\\third_party\\wpt_tools\\wpt\\tools\\wptrunner\\wptrunner\\executors\\executorwebdriver.py", line 887, in run_func\n    self.result = True, self.func(self.protocol, self.url, self.timeout)\n                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "C:\\b\\s\\w\\ir\\third_party\\wpt_tools\\wpt\\tools\\wptrunner\\wptrunner\\executors\\executorwebdriver.py", line 1090, in do_testharness\n    raw_results = self.run_testdriver(protocol, url, timeout)\n                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "C:\\b\\s\\w\\ir\\third_party\\wpt_tools\\wpt\\tools\\wptrunner\\wptrunner\\executors\\executorwebdriver.py", line 1007, in run_testdriver\n    done, rv = handler(test_driver_message)\n               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File "C:\\b\\s\\w\\ir\\third_party\\wpt_tools\\wpt\\tools\\wptrunner\\wptrunner\\executors\\base.py", line 761, in __call__\n    return callback(url, payload)\n           ^^^^^^^^^^^^^^^^^^^^^^\n  File "C:\\b\\s\\w\\ir\\third_party\\wpt_tools\\wpt\\tools\\wptrunner\\wptrunner\\executors\\base.py", line 775, in process_action\n    raise ValueError(f"Unknown action {action}") from e\nValueError: Unknown action bidi.permissions.set_permission\n
-Harness: the test ran to completion.
-
diff --git a/content/test/data/back_forward_cache/shared_worker.js b/third_party/blink/web_tests/wpt_internal/shared-worker/back-forward-cache/resources/worker-empty.js
similarity index 100%
rename from content/test/data/back_forward_cache/shared_worker.js
rename to third_party/blink/web_tests/wpt_internal/shared-worker/back-forward-cache/resources/worker-empty.js
diff --git a/third_party/blink/web_tests/wpt_internal/shared-worker/back-forward-cache/shared-worker.window.js b/third_party/blink/web_tests/wpt_internal/shared-worker/back-forward-cache/shared-worker.window.js
new file mode 100644
index 0000000..6eea9e79
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/shared-worker/back-forward-cache/shared-worker.window.js
@@ -0,0 +1,27 @@
+// META: title=SharedWorker blocks bfcache.
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js
+// META: script=/html/browsers/browsing-the-web/remote-context-helper-tests/resources/test-helper.js
+// META: timeout=long
+
+'use strict';
+
+promise_test(async t => {
+  const rcHelper = new RemoteContextHelper();
+
+  const rc1 = await rcHelper.addWindow(
+      /*config=*/ {}, /*options=*/ {features: 'noopener'});
+
+  await rc1.executeScript(async () => {
+    window.foo = new SharedWorker(
+        '/wpt_internal/shared-worker/back-forward-cache/resources/worker-empty.js');
+  });
+  await assertBFCacheEligibility(rc1, /*shouldRestoreFromBfcache=*/ false);
+  await assertNotRestoredFromBFCache(
+      rc1,
+      ['sharedworker'],
+  );
+});
diff --git a/third_party/breakpad/BUILD.gn b/third_party/breakpad/BUILD.gn
index e2b55807..2f4e1ab0 100644
--- a/third_party/breakpad/BUILD.gn
+++ b/third_party/breakpad/BUILD.gn
@@ -205,10 +205,6 @@
       current_toolchain == default_system_allocator_toolchain) {
     # Contains the code shared by both {micro,mini}dump_stackwalk.
     static_library("stackwalk_common") {
-      # TODO(https://crbug.com/424364315): Disable modules build due to
-      # <stdint.h> include inside libdis namespace in disassembler_x86.h.
-      use_libcxx_modules = false
-
       # Binaries that use this library are not debugged frequently and
       # performance is vastly reduced without optimizations. So, force maximum
       # optimization to get the lowest runtimes in Chromium tests that use these
diff --git a/third_party/catapult b/third_party/catapult
index 1d50003..3936da5 160000
--- a/third_party/catapult
+++ b/third_party/catapult
@@ -1 +1 @@
-Subproject commit 1d50003d814d326a3e1f000d456b3eede5ab8fd5
+Subproject commit 3936da5884d45fc16ecbd3d939c4709fe3ebbd3e
diff --git a/third_party/cpuinfo/README.chromium b/third_party/cpuinfo/README.chromium
index 2e2ea93..f125548 100644
--- a/third_party/cpuinfo/README.chromium
+++ b/third_party/cpuinfo/README.chromium
@@ -1,8 +1,8 @@
 Name: cpuinfo
 Short Name: cpuinfo
 URL: https://github.com/pytorch/cpuinfo
-Version: 6c9eb84ba310f237cea13c478be50102e1128e9b
-Date: 2025-06-05
+Version: d7427551d6531037da216d20cd36feb19ed4905f
+Date: 2025-06-12
 License: BSD-2-Clause
 License File: src/LICENSE
 Security Critical: Yes
diff --git a/third_party/cpuinfo/src b/third_party/cpuinfo/src
index 6c9eb84..d742755 160000
--- a/third_party/cpuinfo/src
+++ b/third_party/cpuinfo/src
@@ -1 +1 @@
-Subproject commit 6c9eb84ba310f237cea13c478be50102e1128e9b
+Subproject commit d7427551d6531037da216d20cd36feb19ed4905f
diff --git a/third_party/crossbench b/third_party/crossbench
index e5f52e3..f153de5 160000
--- a/third_party/crossbench
+++ b/third_party/crossbench
@@ -1 +1 @@
-Subproject commit e5f52e392ef8fae9e4fd83e2d6af366999f28776
+Subproject commit f153de5d266c992e05a5f00db9b1f75440076f32
diff --git a/third_party/dawn b/third_party/dawn
index 8f0deff..31cf85d 160000
--- a/third_party/dawn
+++ b/third_party/dawn
@@ -1 +1 @@
-Subproject commit 8f0deff0d2fa43ec948531a7ae69ee02dd6485c1
+Subproject commit 31cf85d685b9ba4f3596ac21d484051f3196e43a
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index 1ad5f0b..3a4bfd6 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit 1ad5f0be793810c0b09958a976bda35724a20c6d
+Subproject commit 3a4bfd655bb875cee25ff21160dce79479f9f4fb
diff --git a/third_party/eigen3/README.chromium b/third_party/eigen3/README.chromium
index 48daa7f2..15b5e58 100644
--- a/third_party/eigen3/README.chromium
+++ b/third_party/eigen3/README.chromium
@@ -1,8 +1,8 @@
 Name: Eigen
 Short Name: eigen3
 URL: https://gitlab.com/libeigen/eigen
-Version: 21e89b930c6af56dbdaeea2a91d8b9d6fd2c208a
-Date: 2025-06-05
+Version: d0b490ee091629068e0c11953419eb089f9e6bb2
+Date: 2025-06-12
 License: MPL-2.0
 License File: LICENSE
 Security Critical: Yes
diff --git a/third_party/eigen3/src b/third_party/eigen3/src
index 21e89b9..d0b490e 160000
--- a/third_party/eigen3/src
+++ b/third_party/eigen3/src
@@ -1 +1 @@
-Subproject commit 21e89b930c6af56dbdaeea2a91d8b9d6fd2c208a
+Subproject commit d0b490ee091629068e0c11953419eb089f9e6bb2
diff --git a/third_party/googletest/src b/third_party/googletest/src
index fd15f51..1aeec48 160000
--- a/third_party/googletest/src
+++ b/third_party/googletest/src
@@ -1 +1 @@
-Subproject commit fd15f51d57f983c5f3f609bb39fd77f6dbdc391a
+Subproject commit 1aeec48a1dda87f179d76b5f4f30db91c9ab7239
diff --git a/third_party/libc++abi/src b/third_party/libc++abi/src
index 3a31ad5..e44c3c4 160000
--- a/third_party/libc++abi/src
+++ b/third_party/libc++abi/src
@@ -1 +1 @@
-Subproject commit 3a31ad538c40ba0eb41fbfd3ec583cdef340cf72
+Subproject commit e44c3c4560f1742744ef3f9fb4217a5f26ebca1b
diff --git a/third_party/perfetto b/third_party/perfetto
index fbed4ff..e93a2c7 160000
--- a/third_party/perfetto
+++ b/third_party/perfetto
@@ -1 +1 @@
-Subproject commit fbed4ffaccc0e754779134993ae8212091582aa9
+Subproject commit e93a2c7998dee72ddcacff7cf54d001051205ce4
diff --git a/third_party/rust/chromium_crates_io/Cargo.lock b/third_party/rust/chromium_crates_io/Cargo.lock
index 9bcca08..9f62894 100644
--- a/third_party/rust/chromium_crates_io/Cargo.lock
+++ b/third_party/rust/chromium_crates_io/Cargo.lock
@@ -130,7 +130,7 @@
 
 [[package]]
 name = "clap"
-version = "4.5.39"
+version = "4.5.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "clap_builder",
@@ -138,7 +138,7 @@
 
 [[package]]
 name = "clap_builder"
-version = "4.5.39"
+version = "4.5.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "anstyle",
@@ -346,7 +346,7 @@
 
 [[package]]
 name = "hashbrown"
-version = "0.15.3"
+version = "0.15.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -692,12 +692,12 @@
 
 [[package]]
 name = "memchr"
-version = "2.7.4"
+version = "2.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.8.8"
+version = "0.8.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "adler2",
@@ -823,7 +823,7 @@
 
 [[package]]
 name = "rustc-demangle"
-version = "0.1.24"
+version = "0.1.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -911,7 +911,7 @@
 
 [[package]]
 name = "smallvec"
-version = "1.15.0"
+version = "1.15.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -964,7 +964,7 @@
 
 [[package]]
 name = "syn"
-version = "2.0.101"
+version = "2.0.102"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "proc-macro2",
diff --git a/third_party/rust/chromium_crates_io/supply-chain/config.toml b/third_party/rust/chromium_crates_io/supply-chain/config.toml
index 9161d629..4420c67 100644
--- a/third_party/rust/chromium_crates_io/supply-chain/config.toml
+++ b/third_party/rust/chromium_crates_io/supply-chain/config.toml
@@ -80,10 +80,10 @@
 [policy."cfg-if:1.0.1"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
-[policy."clap:4.5.39"]
+[policy."clap:4.5.40"]
 criteria = ["crypto-safe", "safe-to-run"]
 
-[policy."clap_builder:4.5.39"]
+[policy."clap_builder:4.5.40"]
 criteria = ["crypto-safe", "safe-to-run"]
 
 [policy."clap_lex:0.7.5"]
@@ -155,7 +155,7 @@
 [policy."font-types:0.8.4"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
-[policy."hashbrown:0.15.3"]
+[policy."hashbrown:0.15.4"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
 [policy."heck:0.5.0"]
@@ -266,10 +266,10 @@
 [policy."log:0.4.27"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
-[policy."memchr:2.7.4"]
+[policy."memchr:2.7.5"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
-[policy."miniz_oxide:0.8.8"]
+[policy."miniz_oxide:0.8.9"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
 [policy."num-bigint:0.4.6"]
@@ -317,7 +317,7 @@
 [policy."rustc-demangle-capi:0.1.1"]
 criteria = ["crypto-safe", "safe-to-run"]
 
-[policy."rustc-demangle:0.1.24"]
+[policy."rustc-demangle:0.1.25"]
 criteria = ["crypto-safe", "safe-to-run"]
 
 [policy."rustversion:1.0.21"]
@@ -350,7 +350,7 @@
 [policy."small_ctor:0.1.2"]
 criteria = ["crypto-safe", "safe-to-run"]
 
-[policy."smallvec:1.15.0"]
+[policy."smallvec:1.15.1"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
 [policy."stable_deref_trait:1.2.0"]
@@ -374,7 +374,7 @@
 [policy."subtle:2.6.1"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
-[policy."syn:2.0.101"]
+[policy."syn:2.0.102"]
 criteria = ["crypto-safe", "safe-to-deploy", "ub-risk-2"]
 
 [policy."synstructure:0.13.2"]
diff --git a/third_party/rust/chromium_crates_io/vendor/clap-v4/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/clap-v4/.cargo_vcs_info.json
index e0a418a..0927238 100644
--- a/third_party/rust/chromium_crates_io/vendor/clap-v4/.cargo_vcs_info.json
+++ b/third_party/rust/chromium_crates_io/vendor/clap-v4/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
 {
   "git": {
-    "sha1": "8520a7acb57fdcc4a5171d6f8e37252ee8a16432"
+    "sha1": "3716f9f4289594b43abec42b2538efd1a90ff897"
   },
   "path_in_vcs": ""
 }
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/clap-v4/Cargo.lock b/third_party/rust/chromium_crates_io/vendor/clap-v4/Cargo.lock
index bde1423..e2f99c52 100644
--- a/third_party/rust/chromium_crates_io/vendor/clap-v4/Cargo.lock
+++ b/third_party/rust/chromium_crates_io/vendor/clap-v4/Cargo.lock
@@ -134,7 +134,7 @@
 
 [[package]]
 name = "clap"
-version = "4.5.39"
+version = "4.5.40"
 dependencies = [
  "automod",
  "clap-cargo",
@@ -159,9 +159,9 @@
 
 [[package]]
 name = "clap_builder"
-version = "4.5.39"
+version = "4.5.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51"
+checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
 dependencies = [
  "anstream",
  "anstyle",
@@ -175,9 +175,9 @@
 
 [[package]]
 name = "clap_derive"
-version = "4.5.32"
+version = "4.5.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
+checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
 dependencies = [
  "anstyle",
  "heck",
@@ -331,9 +331,9 @@
 
 [[package]]
 name = "jiff"
-version = "0.2.11"
+version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "27e77966151130221b079bcec80f1f34a9e414fa489d99152a201c07fd2182bc"
+checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93"
 dependencies = [
  "jiff-static",
  "jiff-tzdb-platform",
@@ -341,14 +341,14 @@
  "portable-atomic",
  "portable-atomic-util",
  "serde",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
 name = "jiff-static"
-version = "0.2.11"
+version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97265751f8a9a4228476f2fc17874a9e7e70e96b893368e42619880fe143b48a"
+checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -519,9 +519,9 @@
 
 [[package]]
 name = "rustversion"
-version = "1.0.20"
+version = "1.0.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
+checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
 
 [[package]]
 name = "ryu"
@@ -688,9 +688,9 @@
 
 [[package]]
 name = "trybuild"
-version = "1.0.104"
+version = "1.0.105"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ae08be68c056db96f0e6c6dd820727cca756ced9e1f4cc7fdd20e2a55e23898"
+checksum = "1c9bf9513a2f4aeef5fdac8677d7d349c79fdbcc03b9c86da6e9d254f1e43be2"
 dependencies = [
  "glob",
  "serde",
diff --git a/third_party/rust/chromium_crates_io/vendor/clap-v4/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/clap-v4/Cargo.toml
index 1ead04c0..625e39cf 100644
--- a/third_party/rust/chromium_crates_io/vendor/clap-v4/Cargo.toml
+++ b/third_party/rust/chromium_crates_io/vendor/clap-v4/Cargo.toml
@@ -13,7 +13,7 @@
 edition = "2021"
 rust-version = "1.74"
 name = "clap"
-version = "4.5.39"
+version = "4.5.40"
 build = false
 include = [
     "build.rs",
@@ -21,7 +21,6 @@
     "Cargo.toml",
     "LICENSE*",
     "README.md",
-    "benches/**/*",
     "examples/**/*",
 ]
 autolib = false
@@ -510,11 +509,11 @@
 required-features = ["derive"]
 
 [dependencies.clap_builder]
-version = "=4.5.39"
+version = "=4.5.40"
 default-features = false
 
 [dependencies.clap_derive]
-version = "=4.5.32"
+version = "=4.5.40"
 optional = true
 
 [dev-dependencies.automod]
@@ -588,7 +587,7 @@
 mem_forget = "warn"
 multiple_bound_locations = "allow"
 mutex_integer = "warn"
-needless_continue = "warn"
+needless_continue = "allow"
 needless_for_each = "warn"
 negative_feature_names = "warn"
 path_buf_push_overwrite = "warn"
@@ -597,6 +596,7 @@
 redundant_feature_names = "warn"
 ref_option_ref = "warn"
 rest_pat_in_fully_bound_structs = "warn"
+result_large_err = "allow"
 same_functions_in_if_condition = "warn"
 self_named_module_files = "warn"
 semicolon_if_nothing_returned = "warn"
@@ -609,6 +609,7 @@
 zero_sized_map_values = "warn"
 
 [lints.rust]
+unnameable_types = "allow"
 unreachable_pub = "warn"
 unsafe_op_in_unsafe_fn = "warn"
 unused_lifetimes = "warn"
@@ -623,5 +624,13 @@
 lto = true
 codegen-units = 1
 
+[profile.dev]
+panic = "abort"
+
+[profile.release]
+lto = true
+codegen-units = 1
+panic = "abort"
+
 [profile.test]
 opt-level = 1
diff --git a/third_party/rust/chromium_crates_io/vendor/clap-v4/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/clap-v4/Cargo.toml.orig
index 4d82ddc..8af48ee 100644
--- a/third_party/rust/chromium_crates_io/vendor/clap-v4/Cargo.toml.orig
+++ b/third_party/rust/chromium_crates_io/vendor/clap-v4/Cargo.toml.orig
@@ -21,12 +21,12 @@
   "Cargo.toml",
   "LICENSE*",
   "README.md",
-  "benches/**/*",
   "examples/**/*"
 ]
 
 [workspace.lints.rust]
 rust_2018_idioms = { level = "warn", priority = -1 }
+unnameable_types = "allow"
 unreachable_pub = "warn"
 unsafe_op_in_unsafe_fn = "warn"
 unused_lifetimes = "warn"
@@ -69,7 +69,7 @@
 macro_use_imports = "warn"
 mem_forget = "warn"
 mutex_integer = "warn"
-needless_continue = "warn"
+needless_continue = "allow"
 needless_for_each = "warn"
 negative_feature_names = "warn"
 path_buf_push_overwrite = "warn"
@@ -78,6 +78,7 @@
 redundant_feature_names = "warn"
 ref_option_ref = "warn"
 rest_pat_in_fully_bound_structs = "warn"
+result_large_err = "allow"
 same_functions_in_if_condition = "warn"
 self_named_module_files = "warn"
 semicolon_if_nothing_returned = "warn"
@@ -97,9 +98,18 @@
 assigning_clones = "allow"
 blocks_in_conditions = "allow"
 
+[profile.dev]
+panic = "abort"
+
+[profile.release]
+panic = "abort"
+codegen-units = 1
+lto = true
+# debug = "line-tables-only"  # requires Cargo 1.71
+
 [package]
 name = "clap"
-version = "4.5.39"
+version = "4.5.40"
 description = "A simple to use, efficient, and full-featured Command Line Argument Parser"
 categories = ["command-line-interface"]
 keywords = [
@@ -176,8 +186,8 @@
 bench = false
 
 [dependencies]
-clap_builder = { path = "./clap_builder", version = "=4.5.39", default-features = false }
-clap_derive = { path = "./clap_derive", version = "=4.5.32", optional = true }
+clap_builder = { path = "./clap_builder", version = "=4.5.40", default-features = false }
+clap_derive = { path = "./clap_derive", version = "=4.5.40", optional = true }
 
 [dev-dependencies]
 trybuild = "1.0.91"
diff --git a/third_party/rust/chromium_crates_io/vendor/clap-v4/src/_faq.rs b/third_party/rust/chromium_crates_io/vendor/clap-v4/src/_faq.rs
index 7ca5551..0265784 100644
--- a/third_party/rust/chromium_crates_io/vendor/clap-v4/src/_faq.rs
+++ b/third_party/rust/chromium_crates_io/vendor/clap-v4/src/_faq.rs
@@ -69,7 +69,7 @@
 //!
 //! There are also experiments with other APIs:
 //! - [fncmd](https://github.com/yuhr/fncmd): function attribute
-//! - [clap-serde](https://github.com/aobatact/clap-serde): create an `Command` from a deserializer
+//! - [clap-serde](https://github.com/aobatact/clap-serde): create a `Command` from a deserializer
 //!
 //! ### When should I use the builder vs derive APIs?
 //!
@@ -80,7 +80,7 @@
 //!
 //! The [Builder API][crate::_tutorial] is a lower-level API that someone might want to use for
 //! - Faster compile times if you aren't already using other procedural macros
-//! - More flexibility, e.g. you can look up an [arguments values][crate::ArgMatches::get_many],
+//! - More flexibility, e.g. you can look up the [argument's values][crate::ArgMatches::get_many],
 //!   their [ordering with other arguments][crate::ArgMatches::indices_of], and [what set
 //!   them][crate::ArgMatches::value_source].  The Derive API can only report values and not
 //!   indices of or other data.
diff --git a/third_party/rust/chromium_crates_io/vendor/clap-v4/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/clap-v4/src/lib.rs
index d4e54f9..ddaa548 100644
--- a/third_party/rust/chromium_crates_io/vendor/clap-v4/src/lib.rs
+++ b/third_party/rust/chromium_crates_io/vendor/clap-v4/src/lib.rs
@@ -11,7 +11,7 @@
 //! - [Cookbook][_cookbook]
 //! - [FAQ][_faq]
 //! - [Discussions](https://github.com/clap-rs/clap/discussions)
-//! - [CHANGELOG](https://github.com/clap-rs/clap/blob/v4.5.39/CHANGELOG.md) (includes major version migration
+//! - [CHANGELOG](https://github.com/clap-rs/clap/blob/v4.5.40/CHANGELOG.md) (includes major version migration
 //!   guides)
 //!
 //! ## Aspirations
@@ -100,3 +100,7 @@
 pub mod _features;
 #[cfg(feature = "unstable-doc")]
 pub mod _tutorial;
+
+#[doc = include_str!("../README.md")]
+#[cfg(doctest)]
+pub struct ReadmeDoctests;
diff --git a/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/.cargo_vcs_info.json
index 824b2f1..18166d2 100644
--- a/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/.cargo_vcs_info.json
+++ b/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
 {
   "git": {
-    "sha1": "8520a7acb57fdcc4a5171d6f8e37252ee8a16432"
+    "sha1": "3716f9f4289594b43abec42b2538efd1a90ff897"
   },
   "path_in_vcs": "clap_builder"
 }
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/Cargo.lock b/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/Cargo.lock
index 84525d544..40a5a76 100644
--- a/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/Cargo.lock
+++ b/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/Cargo.lock
@@ -101,7 +101,7 @@
 
 [[package]]
 name = "clap_builder"
-version = "4.5.39"
+version = "4.5.40"
 dependencies = [
  "anstream",
  "anstyle",
diff --git a/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/Cargo.toml
index b599ec8..dea03fe 100644
--- a/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/Cargo.toml
+++ b/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/Cargo.toml
@@ -13,7 +13,7 @@
 edition = "2021"
 rust-version = "1.74"
 name = "clap_builder"
-version = "4.5.39"
+version = "4.5.40"
 build = false
 include = [
     "build.rs",
@@ -21,7 +21,6 @@
     "Cargo.toml",
     "LICENSE*",
     "README.md",
-    "benches/**/*",
     "examples/**/*",
 ]
 autolib = false
@@ -187,7 +186,7 @@
 mem_forget = "warn"
 multiple_bound_locations = "allow"
 mutex_integer = "warn"
-needless_continue = "warn"
+needless_continue = "allow"
 needless_for_each = "warn"
 negative_feature_names = "warn"
 path_buf_push_overwrite = "warn"
@@ -196,6 +195,7 @@
 redundant_feature_names = "warn"
 ref_option_ref = "warn"
 rest_pat_in_fully_bound_structs = "warn"
+result_large_err = "allow"
 same_functions_in_if_condition = "warn"
 self_named_module_files = "warn"
 semicolon_if_nothing_returned = "warn"
@@ -208,6 +208,7 @@
 zero_sized_map_values = "warn"
 
 [lints.rust]
+unnameable_types = "allow"
 unreachable_pub = "warn"
 unsafe_op_in_unsafe_fn = "warn"
 unused_lifetimes = "warn"
diff --git a/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/Cargo.toml.orig
index 22bb846..2db96f25 100644
--- a/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/Cargo.toml.orig
+++ b/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "clap_builder"
-version = "4.5.39"
+version = "4.5.40"
 description = "A simple to use, efficient, and full-featured Command Line Argument Parser"
 categories = ["command-line-interface"]
 keywords = [
diff --git a/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/LICENSE-APACHE b/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/LICENSE-APACHE
index 261eeb9..8f71f43 100644
--- a/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/LICENSE-APACHE
+++ b/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/LICENSE-APACHE
@@ -178,7 +178,7 @@
    APPENDIX: How to apply the Apache License to your work.
 
       To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
+      boilerplate notice, with the fields enclosed by brackets "{}"
       replaced with your own identifying information. (Don't include
       the brackets!)  The text should be enclosed in the appropriate
       comment syntax for the file format. We also recommend that a
@@ -186,7 +186,7 @@
       same "printed page" as the copyright notice for easier
       identification within third-party archives.
 
-   Copyright [yyyy] [name of copyright owner]
+   Copyright {yyyy} {name of copyright owner}
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
@@ -199,3 +199,4 @@
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
+
diff --git a/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/LICENSE-MIT b/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/LICENSE-MIT
index 7b05b845..a2d0108 100644
--- a/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/LICENSE-MIT
+++ b/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/LICENSE-MIT
@@ -1,6 +1,4 @@
-The MIT License (MIT)
-
-Copyright (c) 2015-2022 Kevin B. Knapp and Clap Contributors
+Copyright (c) Individual contributors
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/README.md b/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/README.md
index bbe67eb..54da57f 100644
--- a/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/README.md
+++ b/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/README.md
@@ -10,15 +10,16 @@
 
 Licensed under either of
 
-- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or <https://www.apache.org/licenses/LICENSE-2.0>)
-- MIT license ([LICENSE-MIT](LICENSE-MIT) or <https://opensource.org/licenses/MIT>)
+* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
+* MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
 
 at your option.
 
 ### Contribution
 
-Unless you explicitly state otherwise, any contribution intentionally submitted
-for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
-dual licensed as above, without any additional terms or conditions.
+Unless you explicitly state otherwise, any contribution intentionally
+submitted for inclusion in the work by you, as defined in the Apache-2.0
+license, shall be dual-licensed as above, without any additional terms or
+conditions.
 
 See [CONTRIBUTING](CONTRIBUTING.md) for more details.
diff --git a/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/src/lib.rs
index 602c2fb..a0775bf 100644
--- a/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/src/lib.rs
+++ b/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/src/lib.rs
@@ -47,3 +47,7 @@
 
 const INTERNAL_ERROR_MSG: &str = "Fatal internal error. Please consider filing a bug \
                                   report at https://github.com/clap-rs/clap/issues";
+
+#[doc = include_str!("../README.md")]
+#[cfg(doctest)]
+pub struct ReadmeDoctests;
diff --git a/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/src/macros.rs b/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/src/macros.rs
index c03d3237..a15b6f3 100644
--- a/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/src/macros.rs
+++ b/third_party/rust/chromium_crates_io/vendor/clap_builder-v4/src/macros.rs
@@ -530,6 +530,14 @@
 /// [`Arg`]: crate::Arg
 #[macro_export]
 macro_rules! arg {
+    ( -$($tail:tt)+ ) => {{
+        let arg = $crate::Arg::default();
+        let arg = $crate::arg_impl! {
+            @arg (arg) -$($tail)+
+        };
+        debug_assert_ne!(arg.get_id(), "", "Without a value or long flag, the `name:` prefix is required");
+        arg
+    }};
     ( $name:ident: $($tail:tt)+ ) => {{
         let arg = $crate::Arg::new($crate::arg_impl! { @string $name });
         let arg = $crate::arg_impl! {
@@ -537,6 +545,13 @@
         };
         arg
     }};
+    ( $name:literal: $($tail:tt)+ ) => {{
+        let arg = $crate::Arg::new($crate::arg_impl! { @string $name });
+        let arg = $crate::arg_impl! {
+            @arg (arg) $($tail)+
+        };
+        arg
+    }};
     ( $($tail:tt)+ ) => {{
         let arg = $crate::Arg::default();
         let arg = $crate::arg_impl! {
diff --git a/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/.cargo_vcs_info.json
index ce60137..601ff49 100644
--- a/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/.cargo_vcs_info.json
+++ b/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
 {
   "git": {
-    "sha1": "631dfed6e9a4f0afd5de3f6799d02f2baa8e7050"
+    "sha1": "8ceeb4045f8a23752d0091cf4c6c8976c9e291b3"
   },
   "path_in_vcs": ""
 }
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/CHANGELOG.md b/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/CHANGELOG.md
index d34f654..98050ce 100644
--- a/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/CHANGELOG.md
+++ b/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/CHANGELOG.md
@@ -7,6 +7,12 @@
 
 ## [Unreleased]
 
+## [0.15.4](https://github.com/rust-lang/hashbrown/compare/v0.15.3...v0.15.4) - 2025-06-05
+
+### Changed
+
+- Removed optional dependency on compiler-builtins. This only affects building as part of `std`.
+
 ## [0.15.3](https://github.com/rust-lang/hashbrown/compare/v0.15.2...v0.15.3) - 2025-04-29
 
 ### Added
diff --git a/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/Cargo.lock b/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/Cargo.lock
index 521f5e5..ba3e9b6 100644
--- a/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/Cargo.lock
+++ b/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/Cargo.lock
@@ -10,15 +10,15 @@
 
 [[package]]
 name = "bitflags"
-version = "2.9.0"
+version = "2.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
+checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
 
 [[package]]
 name = "bumpalo"
-version = "3.17.0"
+version = "3.18.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
+checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
 dependencies = [
  "allocator-api2",
 ]
@@ -30,12 +30,6 @@
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
-name = "compiler_builtins"
-version = "0.1.156"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1ffbd2789fe5bb95b96a2e22cbe3128239dc46ff0374e0d38e9f102062d7055"
-
-[[package]]
 name = "crossbeam-deque"
 version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -92,9 +86,9 @@
 
 [[package]]
 name = "getrandom"
-version = "0.3.2"
+version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
+checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
 dependencies = [
  "cfg-if",
  "libc",
@@ -104,11 +98,10 @@
 
 [[package]]
 name = "hashbrown"
-version = "0.15.3"
+version = "0.15.4"
 dependencies = [
  "allocator-api2",
  "bumpalo",
- "compiler_builtins",
  "doc-comment",
  "equivalent",
  "fnv",
diff --git a/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/Cargo.toml
index 71574023..976f9d5 100644
--- a/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/Cargo.toml
+++ b/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/Cargo.toml
@@ -13,7 +13,7 @@
 edition = "2021"
 rust-version = "1.65.0"
 name = "hashbrown"
-version = "0.15.3"
+version = "0.15.4"
 authors = ["Amanieu d'Antras <amanieu@gmail.com>"]
 build = false
 exclude = [
@@ -64,7 +64,6 @@
 rustc-dep-of-std = [
     "nightly",
     "core",
-    "compiler_builtins",
     "alloc",
     "rustc-internal-api",
 ]
@@ -117,10 +116,6 @@
 optional = true
 default-features = false
 
-[dependencies.compiler_builtins]
-version = "0.1.2"
-optional = true
-
 [dependencies.core]
 version = "1.0.0"
 optional = true
diff --git a/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/Cargo.toml.orig
index 70a39010..5c165cf 100644
--- a/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/Cargo.toml.orig
+++ b/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "hashbrown"
-version = "0.15.3"
+version = "0.15.4"
 authors = ["Amanieu d'Antras <amanieu@gmail.com>"]
 description = "A Rust port of Google's SwissTable hash map"
 license = "MIT OR Apache-2.0"
@@ -22,7 +22,6 @@
 
 # When built as part of libstd
 core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" }
-compiler_builtins = { version = "0.1.2", optional = true }
 alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" }
 
 # Support for allocators that use allocator-api2
@@ -56,7 +55,6 @@
 rustc-dep-of-std = [
     "nightly",
     "core",
-    "compiler_builtins",
     "alloc",
     "rustc-internal-api",
 ]
diff --git a/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/src/map.rs b/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/src/map.rs
index 78c0a2e..0cffb9d 100644
--- a/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/src/map.rs
+++ b/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/src/map.rs
@@ -5058,6 +5058,10 @@
             Some(x) => *x = new,
         }
         assert_eq!(m.get(&5), Some(&new));
+        let mut hashmap: HashMap<i32, String> = HashMap::default();
+        let key = &1;
+        let result = hashmap.get_mut(key);
+        assert!(result.is_none());
     }
 
     #[test]
diff --git a/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/src/set.rs b/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/src/set.rs
index d56d7c4f..5c512b8 100644
--- a/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/src/set.rs
+++ b/third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/src/set.rs
@@ -2755,6 +2755,22 @@
     }
 
     #[test]
+    fn test_sub_assign() {
+        let mut a: HashSet<_> = vec![1, 2, 3, 4, 5].into_iter().collect();
+        let b: HashSet<_> = vec![4, 5, 6].into_iter().collect();
+
+        a -= &b;
+
+        let mut i = 0;
+        let expected = [1, 2, 3];
+        for x in &a {
+            assert!(expected.contains(x));
+            i += 1;
+        }
+        assert_eq!(i, expected.len());
+    }
+
+    #[test]
     fn test_union() {
         let mut a = HashSet::new();
         let mut b = HashSet::new();
diff --git a/third_party/rust/chromium_crates_io/vendor/memchr-v2/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/memchr-v2/.cargo_vcs_info.json
index 3926fa6..83d29d9 100644
--- a/third_party/rust/chromium_crates_io/vendor/memchr-v2/.cargo_vcs_info.json
+++ b/third_party/rust/chromium_crates_io/vendor/memchr-v2/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
 {
   "git": {
-    "sha1": "8ad339524d857a2dd9e7231b497ed92aa0f5c334"
+    "sha1": "3962118774ac511580c5b40fd14323e31629fa52"
   },
   "path_in_vcs": ""
 }
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/memchr-v2/Cargo.lock b/third_party/rust/chromium_crates_io/vendor/memchr-v2/Cargo.lock
new file mode 100644
index 0000000..f0c62ee4
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/memchr-v2/Cargo.lock
@@ -0,0 +1,80 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "getrandom"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.153"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
+
+[[package]]
+name = "log"
+version = "0.4.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+
+[[package]]
+name = "memchr"
+version = "2.7.5"
+dependencies = [
+ "log",
+ "quickcheck",
+ "rustc-std-workspace-core",
+]
+
+[[package]]
+name = "quickcheck"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6"
+dependencies = [
+ "rand",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rustc-std-workspace-core"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c"
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
diff --git a/third_party/rust/chromium_crates_io/vendor/memchr-v2/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/memchr-v2/Cargo.toml
index 3e5a1f4..e3195e98 100644
--- a/third_party/rust/chromium_crates_io/vendor/memchr-v2/Cargo.toml
+++ b/third_party/rust/chromium_crates_io/vendor/memchr-v2/Cargo.toml
@@ -13,7 +13,7 @@
 edition = "2021"
 rust-version = "1.61"
 name = "memchr"
-version = "2.7.4"
+version = "2.7.5"
 authors = [
     "Andrew Gallant <jamslam@gmail.com>",
     "bluss",
@@ -26,6 +26,7 @@
     "/scripts",
     "/tmp",
 ]
+autolib = false
 autobins = false
 autoexamples = false
 autotests = false
@@ -50,25 +51,20 @@
 [package.metadata.docs.rs]
 rustdoc-args = ["--generate-link-to-definition"]
 
-[profile.bench]
-debug = 2
-
-[profile.release]
-debug = 2
-
-[profile.test]
-opt-level = 3
-debug = 2
+[features]
+alloc = []
+default = ["std"]
+libc = []
+logging = ["dep:log"]
+rustc-dep-of-std = ["core"]
+std = ["alloc"]
+use_std = ["std"]
 
 [lib]
 name = "memchr"
 path = "src/lib.rs"
 bench = false
 
-[dependencies.compiler_builtins]
-version = "0.1.2"
-optional = true
-
 [dependencies.core]
 version = "1.0.0"
 optional = true
@@ -82,14 +78,12 @@
 version = "1.0.3"
 default-features = false
 
-[features]
-alloc = []
-default = ["std"]
-libc = []
-logging = ["dep:log"]
-rustc-dep-of-std = [
-    "core",
-    "compiler_builtins",
-]
-std = ["alloc"]
-use_std = ["std"]
+[profile.bench]
+debug = 2
+
+[profile.release]
+debug = 2
+
+[profile.test]
+opt-level = 3
+debug = 2
diff --git a/third_party/rust/chromium_crates_io/vendor/memchr-v2/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/memchr-v2/Cargo.toml.orig
index 2ef4f243..2318f9c 100644
--- a/third_party/rust/chromium_crates_io/vendor/memchr-v2/Cargo.toml.orig
+++ b/third_party/rust/chromium_crates_io/vendor/memchr-v2/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "memchr"
-version = "2.7.4"  #:version
+version = "2.7.5"  #:version
 authors = ["Andrew Gallant <jamslam@gmail.com>", "bluss"]
 description = """
 Provides extremely fast (uses SIMD on x86_64, aarch64 and wasm32) routines for
@@ -52,7 +52,7 @@
 
 # Internal feature, only used when building as part of libstd, not part of the
 # stable interface of this crate.
-rustc-dep-of-std = ['core', 'compiler_builtins']
+rustc-dep-of-std = ['core']
 
 [dependencies]
 # Only used when the `logging` feature is enabled (disabled by default).
@@ -60,7 +60,6 @@
 # Internal feature, only used when building as part of libstd, not part of the
 # stable interface of this crate.
 core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' }
-compiler_builtins = { version = '0.1.2', optional = true }
 
 [dev-dependencies]
 quickcheck = { version = "1.0.3", default-features = false }
diff --git a/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/arch/all/memchr.rs b/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/arch/all/memchr.rs
index 62fe2a33..7f327f8 100644
--- a/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/arch/all/memchr.rs
+++ b/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/arch/all/memchr.rs
@@ -13,7 +13,7 @@
 counting the number of times a single byte occurs in a haystack. This is
 useful, for example, for counting the number of lines in a haystack. This
 routine exists because it is usually faster, especially with a high match
-count, then using [`One::find`] repeatedly. ([`OneIter`] specializes its
+count, than using [`One::find`] repeatedly. ([`OneIter`] specializes its
 `Iterator::count` implementation to use this routine.)
 
 Only one, two and three bytes are supported because three bytes is about
@@ -456,7 +456,7 @@
         }
 
         // And now we start our search at a guaranteed aligned position.
-        // The first iteration of the loop below will overlap with the the
+        // The first iteration of the loop below will overlap with the
         // unaligned chunk above in cases where the search starts at an
         // unaligned offset, but that's okay as we're only here if that
         // above didn't find a match.
@@ -720,7 +720,7 @@
         }
 
         // And now we start our search at a guaranteed aligned position.
-        // The first iteration of the loop below will overlap with the the
+        // The first iteration of the loop below will overlap with the
         // unaligned chunk above in cases where the search starts at an
         // unaligned offset, but that's okay as we're only here if that
         // above didn't find a match.
diff --git a/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/arch/generic/memchr.rs b/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/arch/generic/memchr.rs
index 580b3cc1..de61fd81 100644
--- a/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/arch/generic/memchr.rs
+++ b/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/arch/generic/memchr.rs
@@ -12,7 +12,7 @@
 //
 // While the routine below is fairly long and perhaps intimidating, the basic
 // idea is actually very simple and can be expressed straight-forwardly in
-// pseudo code. The psuedo code below is written for 128 bit vectors, but the
+// pseudo code. The pseudo code below is written for 128 bit vectors, but the
 // actual code below works for anything that implements the Vector trait.
 //
 //     needle = (n1 << 15) | (n1 << 14) | ... | (n1 << 1) | n1
diff --git a/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/arch/x86_64/memchr.rs b/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/arch/x86_64/memchr.rs
index fcb1399..edb6d43 100644
--- a/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/arch/x86_64/memchr.rs
+++ b/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/arch/x86_64/memchr.rs
@@ -46,8 +46,8 @@
 ///
 /// # Safety
 ///
-/// Primarily callers must that `$fnty` is a correct function pointer type and
-/// not something else.
+/// Primarily callers must ensure that `$fnty` is a correct function pointer
+/// type and not something else.
 ///
 /// Callers must also ensure that `$memchrty::$memchrfind` corresponds to a
 /// routine that returns a valid function pointer when a match is found. That
diff --git a/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/arch/x86_64/sse2/memchr.rs b/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/arch/x86_64/sse2/memchr.rs
index c6f75df4..79572b8 100644
--- a/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/arch/x86_64/sse2/memchr.rs
+++ b/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/arch/x86_64/sse2/memchr.rs
@@ -10,7 +10,7 @@
 counting the number of times a single byte occurs in a haystack. This is
 useful, for example, for counting the number of lines in a haystack. This
 routine exists because it is usually faster, especially with a high match
-count, then using [`One::find`] repeatedly. ([`OneIter`] specializes its
+count, than using [`One::find`] repeatedly. ([`OneIter`] specializes its
 `Iterator::count` implementation to use this routine.)
 
 Only one, two and three bytes are supported because three bytes is about
diff --git a/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/tests/memchr/prop.rs b/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/tests/memchr/prop.rs
index b988260..949ef1f 100644
--- a/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/tests/memchr/prop.rs
+++ b/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/tests/memchr/prop.rs
@@ -1,9 +1,11 @@
+/// Defines a host of quickcheck tests for the given memchr searcher.
 #[cfg(miri)]
 #[macro_export]
 macro_rules! define_memchr_quickcheck {
     ($($tt:tt)*) => {};
 }
 
+/// Defines a host of quickcheck tests for the given memchr searcher.
 #[cfg(not(miri))]
 #[macro_export]
 macro_rules! define_memchr_quickcheck {
diff --git a/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/vector.rs b/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/vector.rs
index d86fbca..4379798 100644
--- a/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/vector.rs
+++ b/third_party/rust/chromium_crates_io/vendor/memchr-v2/src/vector.rs
@@ -78,7 +78,7 @@
 /// a slightly different representation. We could do extra work to unify the
 /// representations, but then would require additional costs in the hot path
 /// for `memchr` and `packedpair`. So instead, we abstraction over the specific
-/// representation with this trait an ddefine the operations we actually need.
+/// representation with this trait and define the operations we actually need.
 pub(crate) trait MoveMask: Copy + core::fmt::Debug {
     /// Return a mask that is all zeros except for the least significant `n`
     /// lanes in a corresponding vector.
@@ -344,7 +344,7 @@
 
         /// This is the only interesting implementation of this routine.
         /// Basically, instead of doing the "shift right narrow" dance, we use
-        /// adajacent folding max to determine whether there are any non-zero
+        /// adjacent folding max to determine whether there are any non-zero
         /// bytes in our mask. If there are, *then* we'll do the "shift right
         /// narrow" dance. In benchmarks, this does lead to slightly better
         /// throughput, but the win doesn't appear huge.
diff --git a/third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/.cargo_vcs_info.json
index fcf7470..5bffd83e 100644
--- a/third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/.cargo_vcs_info.json
+++ b/third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
 {
   "git": {
-    "sha1": "f177ab233c9e38cec03f7b35b9e642246c893312"
+    "sha1": "44e43c7786e379b2b1a7fde4aa0e63be719e583d"
   },
   "path_in_vcs": "miniz_oxide"
 }
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/Cargo.lock b/third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/Cargo.lock
index e94952c8..be78372 100644
--- a/third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/Cargo.lock
+++ b/third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/Cargo.lock
@@ -20,10 +20,9 @@
 
 [[package]]
 name = "miniz_oxide"
-version = "0.8.8"
+version = "0.8.9"
 dependencies = [
  "adler2",
- "compiler_builtins",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
  "serde",
diff --git a/third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/Cargo.toml
index 3883b54..4e6fb85 100644
--- a/third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/Cargo.toml
+++ b/third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/Cargo.toml
@@ -12,7 +12,7 @@
 [package]
 edition = "2021"
 name = "miniz_oxide"
-version = "0.8.8"
+version = "0.8.9"
 authors = [
     "Frommi <daniil.liferenko@gmail.com>",
     "oyvindln <oyvindln@users.noreply.github.com>",
@@ -49,7 +49,6 @@
 rustc-dep-of-std = [
     "core",
     "alloc",
-    "compiler_builtins",
     "adler2/rustc-dep-of-std",
 ]
 simd = ["simd-adler32"]
@@ -69,10 +68,6 @@
 optional = true
 package = "rustc-std-workspace-alloc"
 
-[dependencies.compiler_builtins]
-version = "0.1.2"
-optional = true
-
 [dependencies.core]
 version = "1.0.0"
 optional = true
diff --git a/third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/Cargo.toml.orig
index 7b271b7..3880267 100644
--- a/third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/Cargo.toml.orig
+++ b/third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/Cargo.toml.orig
@@ -1,7 +1,7 @@
 [package]
 name = "miniz_oxide"
 authors = ["Frommi <daniil.liferenko@gmail.com>", "oyvindln <oyvindln@users.noreply.github.com>", "Rich Geldreich richgel99@gmail.com"]
-version = "0.8.8"
+version = "0.8.9"
 license = "MIT OR Zlib OR Apache-2.0"
 readme = "Readme.md"
 keywords = ["zlib", "miniz", "deflate", "encoding"]
@@ -25,7 +25,6 @@
 # stable interface of this crate.
 core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' }
 alloc = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-alloc' }
-compiler_builtins = { version = '0.1.2', optional = true }
 
 
 [dev-dependencies]
@@ -45,7 +44,7 @@
 
 # Internal feature, only used when building as part of libstd, not part of the
 # stable interface of this crate.
-rustc-dep-of-std = ['core', 'alloc', 'compiler_builtins', 'adler2/rustc-dep-of-std']
+rustc-dep-of-std = ['core', 'alloc', 'adler2/rustc-dep-of-std']
 
 simd = ['simd-adler32']
 
diff --git a/third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/Readme.md b/third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/Readme.md
index a6c3e7f..cd7917d 100644
--- a/third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/Readme.md
+++ b/third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/Readme.md
@@ -15,6 +15,8 @@
 
 miniz_oxide 0.8.x currently requires at least Rust 1.56.0, though to leave some room for future internal improvements the minimum version might be raised in the future though it never be made incompatible with anything more recent than the last 4 rust versions and in all likelyhood not require anything even remotely that recent unless there is a very good reason for it.
 
+IMPORTANT! Versions prior to 0.8.4 have a [massive](https://github.com/Frommi/miniz_oxide/issues/163) regression in compression performance in versions of rust 1.81 and newer due to a upstream regression. If miniz_oxide is part of your dependencies, please update to the latest version to avoid performance regressions!
+
 miniz_oxide features no use of unsafe code.
 
 miniz_oxide can optionally be made to use a simd-accelerated version of adler32 via the [simd-adler32](https://crates.io/crates/simd-adler32) crate by enabling the 'simd' feature which will give a noticeable speedup on decoding, and a smaller speedup during encoding, if the data is encoded with a zlib header. Due to the increase in performance this is recommended, though not enabled by default for compatability reasons. Additionally, due to the use of simd intrinsics, the simd-adler32 has to use unsafe. (Due to limitations in the rust standard library simd-adler32 only has explicit SIMD implementations on stable rust for x86 platforms currently but this may change in the future.)
diff --git a/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/.cargo_vcs_info.json
index 50e007a..58916bd 100644
--- a/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/.cargo_vcs_info.json
+++ b/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
 {
   "git": {
-    "sha1": "d43f6d58562319e93a492ac8ceb3fe258beefaf4"
+    "sha1": "8e15996082029a8f5e577906b7464aa412660d91"
   },
   "path_in_vcs": ""
 }
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/.github/workflows/main.yml b/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/.github/workflows/main.yml
index 4397394..ff88825a 100644
--- a/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/.github/workflows/main.yml
+++ b/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/.github/workflows/main.yml
@@ -14,6 +14,7 @@
       run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }}
     - run: cargo build --all
     - run: cargo test --all
+    - run: cd crates/native-c && cargo test --all
     - run: cargo build --features std
 
   fuzz_targets:
diff --git a/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/Cargo.lock b/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/Cargo.lock
new file mode 100644
index 0000000..62033c4
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/Cargo.lock
@@ -0,0 +1,16 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.25"
+dependencies = [
+ "rustc-std-workspace-core",
+]
+
+[[package]]
+name = "rustc-std-workspace-core"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c"
diff --git a/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/Cargo.toml
index c4e53ab..33dfeef 100644
--- a/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/Cargo.toml
+++ b/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/Cargo.toml
@@ -11,9 +11,10 @@
 
 [package]
 name = "rustc-demangle"
-version = "0.1.24"
+version = "0.1.25"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
 build = false
+autolib = false
 autobins = false
 autoexamples = false
 autotests = false
@@ -34,25 +35,18 @@
     "docsrs",
 ]
 
-[profile.release]
-lto = true
+[features]
+compiler_builtins = []
+rustc-dep-of-std = ["core"]
+std = []
 
 [lib]
 name = "rustc_demangle"
 path = "src/lib.rs"
 
-[dependencies.compiler_builtins]
-version = "0.1.2"
-optional = true
-
 [dependencies.core]
 version = "1.0.0"
 optional = true
 package = "rustc-std-workspace-core"
 
-[features]
-rustc-dep-of-std = [
-    "core",
-    "compiler_builtins",
-]
-std = []
+[profile.release]
diff --git a/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/Cargo.toml.orig
index 197a0c4..968972d 100644
--- a/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/Cargo.toml.orig
+++ b/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "rustc-demangle"
-version = "0.1.24"
+version = "0.1.25"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
 license = "MIT/Apache-2.0"
 readme = "README.md"
@@ -16,14 +16,17 @@
 
 [dependencies]
 core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' }
-compiler_builtins = { version = '0.1.2', optional = true }
 
 [features]
-rustc-dep-of-std = ['core', 'compiler_builtins']
+rustc-dep-of-std = ['core']
 std = []
+# Deprecated: `compiler_builtins` used to be a dependency and was enabled by
+# some downstream users, but it is no longer needed. This feature should be
+# removed in a future release.
+compiler_builtins = []
 
 [profile.release]
-lto = true
+#lto = true
 
 [package.metadata.docs.rs]
 features = ["std"]
diff --git a/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/README.md b/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/README.md
index 0833e1e..62cb80b 100644
--- a/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/README.md
+++ b/third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/README.md
@@ -30,6 +30,15 @@
 platform). These objects implement the interface specified in
 `crates/capi/include/rustc_demangle.h`.
 
+If your build system does not support Rust, there is also a mostly-identical
+C version in the `crates/native-c` which you can use via copy-paste or as
+a git submodule. Read `crates/native-c/README.md` for more details. It is
+likely to be less supported than the Rust version, so it is better to use
+the Rust version if your build system supports it.
+
+Both the Rust and C versions don't require memory allocation or any other
+operating-system support.
+
 # License
 
 This project is licensed under either of
diff --git a/third_party/rust/chromium_crates_io/vendor/smallvec-v1/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/smallvec-v1/.cargo_vcs_info.json
index ca028c65..93189188 100644
--- a/third_party/rust/chromium_crates_io/vendor/smallvec-v1/.cargo_vcs_info.json
+++ b/third_party/rust/chromium_crates_io/vendor/smallvec-v1/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
 {
   "git": {
-    "sha1": "7c4d350f5ec284fd05807f1a182387889a62af24"
+    "sha1": "d0f47a3ea99296498ee940b5d99f59b403c498a2"
   },
   "path_in_vcs": ""
 }
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/smallvec-v1/Cargo.lock b/third_party/rust/chromium_crates_io/vendor/smallvec-v1/Cargo.lock
index e32500d..79606a4 100644
--- a/third_party/rust/chromium_crates_io/vendor/smallvec-v1/Cargo.lock
+++ b/third_party/rust/chromium_crates_io/vendor/smallvec-v1/Cargo.lock
@@ -13,9 +13,9 @@
 
 [[package]]
 name = "anyhow"
-version = "1.0.97"
+version = "1.0.98"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
+checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
 
 [[package]]
 name = "arbitrary"
@@ -84,9 +84,9 @@
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.94"
+version = "1.0.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
 dependencies = [
  "unicode-ident",
 ]
@@ -146,12 +146,12 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.100",
+ "syn 2.0.101",
 ]
 
 [[package]]
 name = "smallvec"
-version = "1.15.0"
+version = "1.15.1"
 dependencies = [
  "arbitrary",
  "bincode 1.3.3",
@@ -176,9 +176,9 @@
 
 [[package]]
 name = "syn"
-version = "2.0.100"
+version = "2.0.101"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
+checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
 dependencies = [
  "proc-macro2",
  "quote",
diff --git a/third_party/rust/chromium_crates_io/vendor/smallvec-v1/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/smallvec-v1/Cargo.toml
index b91d77a7..d9a4f3b2 100644
--- a/third_party/rust/chromium_crates_io/vendor/smallvec-v1/Cargo.toml
+++ b/third_party/rust/chromium_crates_io/vendor/smallvec-v1/Cargo.toml
@@ -12,7 +12,7 @@
 [package]
 edition = "2018"
 name = "smallvec"
-version = "1.15.0"
+version = "1.15.1"
 authors = ["The Servo Project Developers"]
 build = false
 autolib = false
diff --git a/third_party/rust/chromium_crates_io/vendor/smallvec-v1/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/smallvec-v1/Cargo.toml.orig
index a7fcfbe..81ea432 100644
--- a/third_party/rust/chromium_crates_io/vendor/smallvec-v1/Cargo.toml.orig
+++ b/third_party/rust/chromium_crates_io/vendor/smallvec-v1/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "smallvec"
-version = "1.15.0"
+version = "1.15.1"
 edition = "2018"
 authors = ["The Servo Project Developers"]
 license = "MIT OR Apache-2.0"
diff --git a/third_party/rust/chromium_crates_io/vendor/smallvec-v1/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/smallvec-v1/src/lib.rs
index 8689b75..3259774 100644
--- a/third_party/rust/chromium_crates_io/vendor/smallvec-v1/src/lib.rs
+++ b/third_party/rust/chromium_crates_io/vendor/smallvec-v1/src/lib.rs
@@ -184,18 +184,20 @@
 macro_rules! smallvec {
     // count helper: transform any expression into 1
     (@one $x:expr) => (1usize);
+    () => (
+        $crate::SmallVec::new()
+    );
     ($elem:expr; $n:expr) => ({
         $crate::SmallVec::from_elem($elem, $n)
     });
-    ($($x:expr),*$(,)*) => ({
-        let count = 0usize $(+ $crate::smallvec!(@one $x))*;
-        #[allow(unused_mut)]
+    ($($x:expr),+$(,)?) => ({
+        let count = 0usize $(+ $crate::smallvec!(@one $x))+;
         let mut vec = $crate::SmallVec::new();
         if count <= vec.inline_size() {
             $(vec.push($x);)*
             vec
         } else {
-            $crate::SmallVec::from_vec($crate::alloc::vec![$($x,)*])
+            $crate::SmallVec::from_vec($crate::alloc::vec![$($x,)+])
         }
     });
 }
diff --git a/third_party/rust/chromium_crates_io/vendor/syn-v2/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/syn-v2/.cargo_vcs_info.json
index a502693..26a2a29 100644
--- a/third_party/rust/chromium_crates_io/vendor/syn-v2/.cargo_vcs_info.json
+++ b/third_party/rust/chromium_crates_io/vendor/syn-v2/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
 {
   "git": {
-    "sha1": "58336a3fb49b63aae0ae2e708a69167543ff0e97"
+    "sha1": "b1cc55995dc2ff30ffdf10fc428f9df0bb85f28d"
   },
   "path_in_vcs": ""
 }
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/syn-v2/Cargo.lock b/third_party/rust/chromium_crates_io/vendor/syn-v2/Cargo.lock
index e8ac0ee..7d156136 100644
--- a/third_party/rust/chromium_crates_io/vendor/syn-v2/Cargo.lock
+++ b/third_party/rust/chromium_crates_io/vendor/syn-v2/Cargo.lock
@@ -13,9 +13,9 @@
 
 [[package]]
 name = "adler2"
-version = "2.0.0"
+version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
+checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
 
 [[package]]
 name = "anyhow"
@@ -43,14 +43,14 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.100",
+ "syn 2.0.101",
 ]
 
 [[package]]
 name = "backtrace"
-version = "0.3.74"
+version = "0.3.75"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
+checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
 dependencies = [
  "addr2line",
  "cfg-if",
@@ -58,7 +58,7 @@
  "miniz_oxide",
  "object",
  "rustc-demangle",
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
@@ -69,15 +69,15 @@
 
 [[package]]
 name = "bitflags"
-version = "2.9.0"
+version = "2.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
+checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
 
 [[package]]
 name = "bumpalo"
-version = "3.17.0"
+version = "3.18.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
+checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
 
 [[package]]
 name = "bytes"
@@ -87,18 +87,18 @@
 
 [[package]]
 name = "cc"
-version = "1.2.20"
+version = "1.2.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a"
+checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac"
 dependencies = [
  "shlex",
 ]
 
 [[package]]
 name = "cfg-if"
-version = "1.0.0"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
 
 [[package]]
 name = "console"
@@ -170,7 +170,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.100",
+ "syn 2.0.101",
 ]
 
 [[package]]
@@ -202,9 +202,9 @@
 
 [[package]]
 name = "errno"
-version = "0.3.11"
+version = "0.3.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
+checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
 dependencies = [
  "libc",
  "windows-sys 0.59.0",
@@ -230,9 +230,9 @@
 
 [[package]]
 name = "flate2"
-version = "1.1.1"
+version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
+checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
 dependencies = [
  "crc32fast",
  "miniz_oxide",
@@ -331,9 +331,9 @@
 
 [[package]]
 name = "getrandom"
-version = "0.3.2"
+version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
+checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
 dependencies = [
  "cfg-if",
  "libc",
@@ -349,9 +349,9 @@
 
 [[package]]
 name = "h2"
-version = "0.4.9"
+version = "0.4.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633"
+checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5"
 dependencies = [
  "atomic-waker",
  "bytes",
@@ -368,9 +368,9 @@
 
 [[package]]
 name = "hashbrown"
-version = "0.15.2"
+version = "0.15.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
 
 [[package]]
 name = "http"
@@ -434,11 +434,10 @@
 
 [[package]]
 name = "hyper-rustls"
-version = "0.27.5"
+version = "0.27.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2"
+checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
 dependencies = [
- "futures-util",
  "http",
  "hyper",
  "hyper-util",
@@ -467,41 +466,48 @@
 
 [[package]]
 name = "hyper-util"
-version = "0.1.11"
+version = "0.1.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2"
+checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb"
 dependencies = [
+ "base64",
  "bytes",
  "futures-channel",
+ "futures-core",
  "futures-util",
  "http",
  "http-body",
  "hyper",
+ "ipnet",
  "libc",
+ "percent-encoding",
  "pin-project-lite",
  "socket2",
+ "system-configuration",
  "tokio",
  "tower-service",
  "tracing",
+ "windows-registry",
 ]
 
 [[package]]
 name = "icu_collections"
-version = "1.5.0"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
+checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
 dependencies = [
  "displaydoc",
+ "potential_utf",
  "yoke",
  "zerofrom",
  "zerovec",
 ]
 
 [[package]]
-name = "icu_locid"
-version = "1.5.0"
+name = "icu_locale_core"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
+checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
 dependencies = [
  "displaydoc",
  "litemap",
@@ -511,30 +517,10 @@
 ]
 
 [[package]]
-name = "icu_locid_transform"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
-dependencies = [
- "displaydoc",
- "icu_locid",
- "icu_locid_transform_data",
- "icu_provider",
- "tinystr",
- "zerovec",
-]
-
-[[package]]
-name = "icu_locid_transform_data"
-version = "1.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d"
-
-[[package]]
 name = "icu_normalizer"
-version = "1.5.0"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
+checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
 dependencies = [
  "displaydoc",
  "icu_collections",
@@ -542,68 +528,55 @@
  "icu_properties",
  "icu_provider",
  "smallvec",
- "utf16_iter",
- "utf8_iter",
- "write16",
  "zerovec",
 ]
 
 [[package]]
 name = "icu_normalizer_data"
-version = "1.5.1"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7"
+checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
 
 [[package]]
 name = "icu_properties"
-version = "1.5.1"
+version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
+checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
 dependencies = [
  "displaydoc",
  "icu_collections",
- "icu_locid_transform",
+ "icu_locale_core",
  "icu_properties_data",
  "icu_provider",
- "tinystr",
+ "potential_utf",
+ "zerotrie",
  "zerovec",
 ]
 
 [[package]]
 name = "icu_properties_data"
-version = "1.5.1"
+version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2"
+checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
 
 [[package]]
 name = "icu_provider"
-version = "1.5.0"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
+checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
 dependencies = [
  "displaydoc",
- "icu_locid",
- "icu_provider_macros",
+ "icu_locale_core",
  "stable_deref_trait",
  "tinystr",
  "writeable",
  "yoke",
  "zerofrom",
+ "zerotrie",
  "zerovec",
 ]
 
 [[package]]
-name = "icu_provider_macros"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.100",
-]
-
-[[package]]
 name = "idna"
 version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -616,9 +589,9 @@
 
 [[package]]
 name = "idna_adapter"
-version = "1.2.0"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
+checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
 dependencies = [
  "icu_normalizer",
  "icu_properties",
@@ -636,9 +609,9 @@
 
 [[package]]
 name = "insta"
-version = "1.43.0"
+version = "1.43.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab2d11b2f17a45095b8c3603928ba29d7d918d7129d0d0641a36ba73cf07daa6"
+checksum = "154934ea70c58054b556dd430b99a98c2a7ff5309ac9891597e339b5c28f4371"
 dependencies = [
  "console",
  "once_cell",
@@ -652,6 +625,16 @@
 checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
 
 [[package]]
+name = "iri-string"
+version = "0.7.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2"
+dependencies = [
+ "memchr",
+ "serde",
+]
+
+[[package]]
 name = "itoa"
 version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -692,9 +675,9 @@
 
 [[package]]
 name = "litemap"
-version = "0.7.5"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856"
+checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
 
 [[package]]
 name = "log"
@@ -716,22 +699,22 @@
 
 [[package]]
 name = "miniz_oxide"
-version = "0.8.8"
+version = "0.8.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
+checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
 dependencies = [
  "adler2",
 ]
 
 [[package]]
 name = "mio"
-version = "1.0.3"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
+checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
 dependencies = [
  "libc",
  "wasi 0.11.0+wasi-snapshot-preview1",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -768,9 +751,9 @@
 
 [[package]]
 name = "openssl"
-version = "0.10.72"
+version = "0.10.73"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da"
+checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8"
 dependencies = [
  "bitflags",
  "cfg-if",
@@ -789,7 +772,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.100",
+ "syn 2.0.101",
 ]
 
 [[package]]
@@ -800,9 +783,9 @@
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.107"
+version = "0.9.109"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07"
+checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
 dependencies = [
  "cc",
  "libc",
@@ -835,6 +818,15 @@
 checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
 
 [[package]]
+name = "potential_utf"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585"
+dependencies = [
+ "zerovec",
+]
+
+[[package]]
 name = "proc-macro2"
 version = "1.0.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -880,9 +872,9 @@
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.11"
+version = "0.5.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3"
+checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
 dependencies = [
  "bitflags",
 ]
@@ -904,14 +896,14 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.100",
+ "syn 2.0.101",
 ]
 
 [[package]]
 name = "reqwest"
-version = "0.12.15"
+version = "0.12.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb"
+checksum = "a2f8e5513d63f2e5b386eb5106dc67eaf3f84e95258e210489136b8b92ad6119"
 dependencies = [
  "base64",
  "bytes",
@@ -935,21 +927,20 @@
  "once_cell",
  "percent-encoding",
  "pin-project-lite",
- "rustls-pemfile",
+ "rustls-pki-types",
  "serde",
  "serde_json",
  "serde_urlencoded",
  "sync_wrapper",
- "system-configuration",
  "tokio",
  "tokio-native-tls",
  "tower",
+ "tower-http",
  "tower-service",
  "url",
  "wasm-bindgen",
  "wasm-bindgen-futures",
  "web-sys",
- "windows-registry",
 ]
 
 [[package]]
@@ -968,15 +959,15 @@
 
 [[package]]
 name = "rustc-demangle"
-version = "0.1.24"
+version = "0.1.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
+checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
 
 [[package]]
 name = "rustix"
-version = "1.0.5"
+version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
+checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
 dependencies = [
  "bitflags",
  "errno",
@@ -987,9 +978,9 @@
 
 [[package]]
 name = "rustls"
-version = "0.23.26"
+version = "0.23.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0"
+checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321"
 dependencies = [
  "once_cell",
  "rustls-pki-types",
@@ -999,25 +990,19 @@
 ]
 
 [[package]]
-name = "rustls-pemfile"
-version = "2.2.0"
+name = "rustls-pki-types"
+version = "1.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
+checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79"
 dependencies = [
- "rustls-pki-types",
+ "zeroize",
 ]
 
 [[package]]
-name = "rustls-pki-types"
-version = "1.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c"
-
-[[package]]
 name = "rustls-webpki"
-version = "0.103.1"
+version = "0.103.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03"
+checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435"
 dependencies = [
  "ring",
  "rustls-pki-types",
@@ -1026,9 +1011,9 @@
 
 [[package]]
 name = "rustversion"
-version = "1.0.20"
+version = "1.0.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
+checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
 
 [[package]]
 name = "ryu"
@@ -1094,7 +1079,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.100",
+ "syn 2.0.101",
 ]
 
 [[package]]
@@ -1144,15 +1129,15 @@
 
 [[package]]
 name = "smallvec"
-version = "1.15.0"
+version = "1.15.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
 
 [[package]]
 name = "socket2"
-version = "0.5.9"
+version = "0.5.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef"
+checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
 dependencies = [
  "libc",
  "windows-sys 0.52.0",
@@ -1172,9 +1157,9 @@
 
 [[package]]
 name = "syn"
-version = "2.0.100"
+version = "2.0.101"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
+checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1183,7 +1168,7 @@
 
 [[package]]
 name = "syn"
-version = "2.0.101"
+version = "2.0.102"
 dependencies = [
  "anyhow",
  "automod",
@@ -1219,13 +1204,13 @@
 
 [[package]]
 name = "synstructure"
-version = "0.13.1"
+version = "0.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.100",
+ "syn 2.0.101",
 ]
 
 [[package]]
@@ -1262,12 +1247,12 @@
 
 [[package]]
 name = "tempfile"
-version = "3.19.1"
+version = "3.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf"
+checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
 dependencies = [
  "fastrand",
- "getrandom 0.3.2",
+ "getrandom 0.3.3",
  "once_cell",
  "rustix",
  "windows-sys 0.59.0",
@@ -1284,9 +1269,9 @@
 
 [[package]]
 name = "tinystr"
-version = "0.7.6"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
+checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
 dependencies = [
  "displaydoc",
  "zerovec",
@@ -1294,9 +1279,9 @@
 
 [[package]]
 name = "tokio"
-version = "1.44.2"
+version = "1.45.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
+checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
 dependencies = [
  "backtrace",
  "bytes",
@@ -1356,6 +1341,24 @@
 ]
 
 [[package]]
+name = "tower-http"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
+dependencies = [
+ "bitflags",
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "iri-string",
+ "pin-project-lite",
+ "tower",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
 name = "tower-layer"
 version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1379,9 +1382,9 @@
 
 [[package]]
 name = "tracing-core"
-version = "0.1.33"
+version = "0.1.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
+checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
 dependencies = [
  "once_cell",
 ]
@@ -1416,12 +1419,6 @@
 ]
 
 [[package]]
-name = "utf16_iter"
-version = "1.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
-
-[[package]]
 name = "utf8_iter"
 version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1489,7 +1486,7 @@
  "log",
  "proc-macro2",
  "quote",
- "syn 2.0.100",
+ "syn 2.0.101",
  "wasm-bindgen-shared",
 ]
 
@@ -1524,7 +1521,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.100",
+ "syn 2.0.101",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
@@ -1565,29 +1562,29 @@
 
 [[package]]
 name = "windows-registry"
-version = "0.4.0"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
+checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820"
 dependencies = [
+ "windows-link",
  "windows-result",
  "windows-strings",
- "windows-targets 0.53.0",
 ]
 
 [[package]]
 name = "windows-result"
-version = "0.3.2"
+version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
+checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
 dependencies = [
  "windows-link",
 ]
 
 [[package]]
 name = "windows-strings"
-version = "0.3.1"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
+checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
 dependencies = [
  "windows-link",
 ]
@@ -1598,7 +1595,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
@@ -1607,7 +1604,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
 dependencies = [
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
@@ -1616,30 +1613,14 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.6",
- "windows_aarch64_msvc 0.52.6",
- "windows_i686_gnu 0.52.6",
- "windows_i686_gnullvm 0.52.6",
- "windows_i686_msvc 0.52.6",
- "windows_x86_64_gnu 0.52.6",
- "windows_x86_64_gnullvm 0.52.6",
- "windows_x86_64_msvc 0.52.6",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b"
-dependencies = [
- "windows_aarch64_gnullvm 0.53.0",
- "windows_aarch64_msvc 0.53.0",
- "windows_i686_gnu 0.53.0",
- "windows_i686_gnullvm 0.53.0",
- "windows_i686_msvc 0.53.0",
- "windows_x86_64_gnu 0.53.0",
- "windows_x86_64_gnullvm 0.53.0",
- "windows_x86_64_msvc 0.53.0",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
 ]
 
 [[package]]
@@ -1649,96 +1630,48 @@
 checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 
 [[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
-
-[[package]]
 name = "windows_aarch64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
 [[package]]
-name = "windows_aarch64_msvc"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
-
-[[package]]
 name = "windows_i686_gnu"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
 
 [[package]]
-name = "windows_i686_gnu"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
-
-[[package]]
 name = "windows_i686_gnullvm"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 
 [[package]]
-name = "windows_i686_gnullvm"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
-
-[[package]]
 name = "windows_i686_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
 [[package]]
-name = "windows_i686_msvc"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
-
-[[package]]
 name = "windows_x86_64_gnu"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
 
 [[package]]
-name = "windows_x86_64_gnu"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
-
-[[package]]
 name = "windows_x86_64_gnullvm"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 
 [[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
-
-[[package]]
 name = "windows_x86_64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
-name = "windows_x86_64_msvc"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
-
-[[package]]
 name = "wit-bindgen-rt"
 version = "0.39.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1748,16 +1681,10 @@
 ]
 
 [[package]]
-name = "write16"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
-
-[[package]]
 name = "writeable"
-version = "0.5.5"
+version = "0.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
+checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
 
 [[package]]
 name = "xattr"
@@ -1771,9 +1698,9 @@
 
 [[package]]
 name = "yoke"
-version = "0.7.5"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
+checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
 dependencies = [
  "serde",
  "stable_deref_trait",
@@ -1783,13 +1710,13 @@
 
 [[package]]
 name = "yoke-derive"
-version = "0.7.5"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
+checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.100",
+ "syn 2.0.101",
  "synstructure",
 ]
 
@@ -1810,7 +1737,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.100",
+ "syn 2.0.101",
  "synstructure",
 ]
 
@@ -1821,10 +1748,21 @@
 checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
 
 [[package]]
-name = "zerovec"
-version = "0.10.4"
+name = "zerotrie"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
+checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+]
+
+[[package]]
+name = "zerovec"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428"
 dependencies = [
  "yoke",
  "zerofrom",
@@ -1833,11 +1771,11 @@
 
 [[package]]
 name = "zerovec-derive"
-version = "0.10.3"
+version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
+checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.100",
+ "syn 2.0.101",
 ]
diff --git a/third_party/rust/chromium_crates_io/vendor/syn-v2/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/syn-v2/Cargo.toml
index 3cd3ac5..d704b49e 100644
--- a/third_party/rust/chromium_crates_io/vendor/syn-v2/Cargo.toml
+++ b/third_party/rust/chromium_crates_io/vendor/syn-v2/Cargo.toml
@@ -13,7 +13,7 @@
 edition = "2021"
 rust-version = "1.61"
 name = "syn"
-version = "2.0.101"
+version = "2.0.102"
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 build = false
 include = [
diff --git a/third_party/rust/chromium_crates_io/vendor/syn-v2/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/syn-v2/Cargo.toml.orig
index cd1ad0c..218cd928 100644
--- a/third_party/rust/chromium_crates_io/vendor/syn-v2/Cargo.toml.orig
+++ b/third_party/rust/chromium_crates_io/vendor/syn-v2/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "syn"
-version = "2.0.101"
+version = "2.0.102"
 authors = ["David Tolnay <dtolnay@gmail.com>"]
 categories = ["development-tools::procedural-macro-helpers", "parser-implementations"]
 description = "Parser for Rust source code"
diff --git a/third_party/rust/chromium_crates_io/vendor/syn-v2/src/expr.rs b/third_party/rust/chromium_crates_io/vendor/syn-v2/src/expr.rs
index 07024e4..b59bc76 100644
--- a/third_party/rust/chromium_crates_io/vendor/syn-v2/src/expr.rs
+++ b/third_party/rust/chromium_crates_io/vendor/syn-v2/src/expr.rs
@@ -3218,7 +3218,6 @@
             Expr::Group(e) => e.to_tokens(tokens),
             #[cfg(feature = "full")]
             Expr::If(e) => e.to_tokens(tokens),
-            #[cfg(feature = "full")]
             Expr::Index(e) => print_expr_index(e, tokens, fixup),
             #[cfg(feature = "full")]
             Expr::Infer(e) => e.to_tokens(tokens),
@@ -3247,7 +3246,6 @@
             Expr::Try(e) => print_expr_try(e, tokens, fixup),
             #[cfg(feature = "full")]
             Expr::TryBlock(e) => e.to_tokens(tokens),
-            #[cfg(feature = "full")]
             Expr::Tuple(e) => e.to_tokens(tokens),
             Expr::Unary(e) => print_expr_unary(e, tokens, fixup),
             #[cfg(feature = "full")]
diff --git a/third_party/rust/chromium_crates_io/vendor/syn-v2/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/syn-v2/src/lib.rs
index 2726b56b..b2fe1f8c 100644
--- a/third_party/rust/chromium_crates_io/vendor/syn-v2/src/lib.rs
+++ b/third_party/rust/chromium_crates_io/vendor/syn-v2/src/lib.rs
@@ -249,7 +249,7 @@
 //!   dynamic library libproc_macro from rustc toolchain.
 
 // Syn types in rustdoc of other crates get linked to here.
-#![doc(html_root_url = "https://docs.rs/syn/2.0.101")]
+#![doc(html_root_url = "https://docs.rs/syn/2.0.102")]
 #![cfg_attr(docsrs, feature(doc_cfg))]
 #![deny(unsafe_op_in_unsafe_fn)]
 #![allow(non_camel_case_types)]
@@ -308,6 +308,7 @@
     clippy::used_underscore_binding,
     clippy::wildcard_imports,
 )]
+#![allow(unknown_lints, mismatched_lifetime_syntaxes)]
 
 extern crate self as syn;
 
diff --git a/third_party/rust/chromium_crates_io/vendor/syn-v2/src/stmt.rs b/third_party/rust/chromium_crates_io/vendor/syn-v2/src/stmt.rs
index 6261c7b..8ea0077f 100644
--- a/third_party/rust/chromium_crates_io/vendor/syn-v2/src/stmt.rs
+++ b/third_party/rust/chromium_crates_io/vendor/syn-v2/src/stmt.rs
@@ -38,7 +38,7 @@
 }
 
 ast_struct! {
-    /// A local `let` binding: `let x: u64 = s.parse()?`.
+    /// A local `let` binding: `let x: u64 = s.parse()?;`.
     #[cfg_attr(docsrs, doc(cfg(feature = "full")))]
     pub struct Local {
         pub attrs: Vec<Attribute>,
diff --git a/third_party/rust/chromium_crates_io/vendor/syn-v2/src/ty.rs b/third_party/rust/chromium_crates_io/vendor/syn-v2/src/ty.rs
index ff43ae5..69fd77a 100644
--- a/third_party/rust/chromium_crates_io/vendor/syn-v2/src/ty.rs
+++ b/third_party/rust/chromium_crates_io/vendor/syn-v2/src/ty.rs
@@ -572,14 +572,14 @@
             let dyn_span = dyn_token.span;
             let star_token: Option<Token![*]> = input.parse()?;
             let bounds = TypeTraitObject::parse_bounds(dyn_span, input, allow_plus)?;
-            return Ok(if star_token.is_some() {
+            Ok(if star_token.is_some() {
                 Type::Verbatim(verbatim::between(&begin, input))
             } else {
                 Type::TraitObject(TypeTraitObject {
                     dyn_token: Some(dyn_token),
                     bounds,
                 })
-            });
+            })
         } else if lookahead.peek(token::Bracket) {
             let content;
             let bracket_token = bracketed!(content in input);
diff --git a/third_party/rust/chromium_crates_io/vendor/syn-v2/tests/common/eq.rs b/third_party/rust/chromium_crates_io/vendor/syn-v2/tests/common/eq.rs
index 4009e06..f8059a6e 100644
--- a/third_party/rust/chromium_crates_io/vendor/syn-v2/tests/common/eq.rs
+++ b/third_party/rust/chromium_crates_io/vendor/syn-v2/tests/common/eq.rs
@@ -169,7 +169,6 @@
 use rustc_ast::ast::WherePredicateKind;
 use rustc_ast::ast::WhereRegionPredicate;
 use rustc_ast::ast::YieldKind;
-use rustc_ast::ptr::P;
 use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Lit, Token, TokenKind};
 use rustc_ast::tokenstream::{
     AttrTokenStream, AttrTokenTree, AttrsTarget, DelimSpacing, DelimSpan, LazyAttrTokenStream,
@@ -195,12 +194,6 @@
     }
 }
 
-impl<T: ?Sized + SpanlessEq> SpanlessEq for P<T> {
-    fn eq(&self, other: &Self) -> bool {
-        SpanlessEq::eq(&**self, &**other)
-    }
-}
-
 impl<T: ?Sized + SpanlessEq> SpanlessEq for Arc<T> {
     fn eq(&self, other: &Self) -> bool {
         SpanlessEq::eq(&**self, &**other)
@@ -623,7 +616,7 @@
 spanless_eq_enum!(Term; Ty(0) Const(0));
 spanless_eq_enum!(TokenTree; Token(0 1) Delimited(0 1 2 3));
 spanless_eq_enum!(TraitObjectSyntax; Dyn DynStar None);
-spanless_eq_enum!(TyPatKind; Range(0 1 2) Err(0));
+spanless_eq_enum!(TyPatKind; Range(0 1 2) Or(0) Err(0));
 spanless_eq_enum!(UintTy; Usize U8 U16 U32 U64 U128);
 spanless_eq_enum!(UnOp; Deref Not Neg);
 spanless_eq_enum!(UnsafeBinderCastKind; Wrap Unwrap);
diff --git a/third_party/rust/chromium_crates_io/vendor/syn-v2/tests/common/parse.rs b/third_party/rust/chromium_crates_io/vendor/syn-v2/tests/common/parse.rs
index cc724c4..03b30a3 100644
--- a/third_party/rust/chromium_crates_io/vendor/syn-v2/tests/common/parse.rs
+++ b/third_party/rust/chromium_crates_io/vendor/syn-v2/tests/common/parse.rs
@@ -6,12 +6,11 @@
 extern crate rustc_span;
 
 use rustc_ast::ast;
-use rustc_ast::ptr::P;
 use rustc_session::parse::ParseSess;
 use rustc_span::FileName;
 use std::panic;
 
-pub fn librustc_expr(input: &str) -> Option<P<ast::Expr>> {
+pub fn librustc_expr(input: &str) -> Option<Box<ast::Expr>> {
     match panic::catch_unwind(|| {
         let locale_resources = rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec();
         let sess = ParseSess::new(locale_resources);
diff --git a/third_party/rust/chromium_crates_io/vendor/syn-v2/tests/test_precedence.rs b/third_party/rust/chromium_crates_io/vendor/syn-v2/tests/test_precedence.rs
index 1d52022..9a7143a6 100644
--- a/third_party/rust/chromium_crates_io/vendor/syn-v2/tests/test_precedence.rs
+++ b/third_party/rust/chromium_crates_io/vendor/syn-v2/tests/test_precedence.rs
@@ -28,7 +28,8 @@
     clippy::match_wildcard_for_single_variants,
     clippy::needless_lifetimes,
     clippy::too_many_lines,
-    clippy::uninlined_format_args
+    clippy::uninlined_format_args,
+    clippy::unnecessary_box_returns
 )]
 
 extern crate rustc_ast;
@@ -43,10 +44,10 @@
 use crate::common::parse;
 use quote::ToTokens;
 use rustc_ast::ast;
-use rustc_ast::ptr::P;
 use rustc_ast_pretty::pprust;
 use rustc_span::edition::Edition;
 use std::fs;
+use std::mem;
 use std::path::Path;
 use std::process;
 use std::sync::atomic::{AtomicUsize, Ordering};
@@ -196,17 +197,17 @@
     (passed, failed)
 }
 
-fn librustc_parse_and_rewrite(input: &str) -> Option<P<ast::Expr>> {
+fn librustc_parse_and_rewrite(input: &str) -> Option<Box<ast::Expr>> {
     parse::librustc_expr(input).map(librustc_parenthesize)
 }
 
-fn librustc_parenthesize(mut librustc_expr: P<ast::Expr>) -> P<ast::Expr> {
+fn librustc_parenthesize(mut librustc_expr: Box<ast::Expr>) -> Box<ast::Expr> {
     use rustc_ast::ast::{
         AssocItem, AssocItemKind, Attribute, BinOpKind, Block, BoundConstness, Expr, ExprField,
         ExprKind, GenericArg, GenericBound, Local, LocalKind, Pat, PolyTraitRef, Stmt, StmtKind,
         StructExpr, StructRest, TraitBoundModifiers, Ty,
     };
-    use rustc_ast::mut_visit::{visit_clobber, walk_flat_map_assoc_item, MutVisitor};
+    use rustc_ast::mut_visit::{walk_flat_map_assoc_item, MutVisitor};
     use rustc_ast::visit::{AssocCtxt, BoundKind};
     use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
     use rustc_span::DUMMY_SP;
@@ -275,18 +276,21 @@
     }
 
     impl MutVisitor for FullyParenthesize {
-        fn visit_expr(&mut self, e: &mut P<Expr>) {
+        fn visit_expr(&mut self, e: &mut Box<Expr>) {
             noop_visit_expr(e, self);
             match e.kind {
                 ExprKind::Block(..) | ExprKind::If(..) | ExprKind::Let(..) => {}
                 ExprKind::Binary(..) if contains_let_chain(e) => {}
-                _ => visit_clobber(&mut **e, |inner| Expr {
-                    id: ast::DUMMY_NODE_ID,
-                    kind: ExprKind::Paren(P(inner)),
-                    span: DUMMY_SP,
-                    attrs: ThinVec::new(),
-                    tokens: None,
-                }),
+                _ => {
+                    let inner = mem::replace(e, Expr::dummy());
+                    **e = Expr {
+                        id: ast::DUMMY_NODE_ID,
+                        kind: ExprKind::Paren(inner),
+                        span: DUMMY_SP,
+                        attrs: ThinVec::new(),
+                        tokens: None,
+                    };
+                }
             }
         }
 
@@ -319,7 +323,7 @@
             }
         }
 
-        fn visit_block(&mut self, block: &mut P<Block>) {
+        fn visit_block(&mut self, block: &mut Block) {
             self.visit_id(&mut block.id);
             block
                 .stmts
@@ -327,7 +331,7 @@
             self.visit_span(&mut block.span);
         }
 
-        fn visit_local(&mut self, local: &mut P<Local>) {
+        fn visit_local(&mut self, local: &mut Local) {
             match &mut local.kind {
                 LocalKind::Decl => {}
                 LocalKind::Init(init) => {
@@ -342,9 +346,9 @@
 
         fn flat_map_assoc_item(
             &mut self,
-            item: P<AssocItem>,
+            item: Box<AssocItem>,
             ctxt: AssocCtxt,
-        ) -> SmallVec<[P<AssocItem>; 1]> {
+        ) -> SmallVec<[Box<AssocItem>; 1]> {
             match &item.kind {
                 AssocItemKind::Const(const_item)
                     if !const_item.generics.params.is_empty()
@@ -359,11 +363,11 @@
         // We don't want to look at expressions that might appear in patterns or
         // types yet. We'll look into comparing those in the future. For now
         // focus on expressions appearing in other places.
-        fn visit_pat(&mut self, pat: &mut P<Pat>) {
+        fn visit_pat(&mut self, pat: &mut Box<Pat>) {
             let _ = pat;
         }
 
-        fn visit_ty(&mut self, ty: &mut P<Ty>) {
+        fn visit_ty(&mut self, ty: &mut Box<Ty>) {
             let _ = ty;
         }
 
diff --git a/third_party/rust/chromium_crates_io/vendor/syn-v2/tests/test_round_trip.rs b/third_party/rust/chromium_crates_io/vendor/syn-v2/tests/test_round_trip.rs
index c649a55a..42869ed0 100644
--- a/third_party/rust/chromium_crates_io/vendor/syn-v2/tests/test_round_trip.rs
+++ b/third_party/rust/chromium_crates_io/vendor/syn-v2/tests/test_round_trip.rs
@@ -11,6 +11,7 @@
     clippy::needless_lifetimes,
     clippy::uninlined_format_args
 )]
+#![allow(mismatched_lifetime_syntaxes)]
 
 extern crate rustc_ast;
 extern crate rustc_ast_pretty;
diff --git a/third_party/rust/clap/v4/BUILD.gn b/third_party/rust/clap/v4/BUILD.gn
index cb77cdc..8a7b553 100644
--- a/third_party/rust/clap/v4/BUILD.gn
+++ b/third_party/rust/clap/v4/BUILD.gn
@@ -153,7 +153,7 @@
   edition = "2021"
   cargo_pkg_name = "clap"
   cargo_pkg_description = "A simple to use, efficient, and full-featured Command Line Argument Parser"
-  cargo_pkg_version = "4.5.39"
+  cargo_pkg_version = "4.5.40"
 
   allow_unsafe = false
 
diff --git a/third_party/rust/clap/v4/README.chromium b/third_party/rust/clap/v4/README.chromium
index 3b8b6d03..5b7acd5 100644
--- a/third_party/rust/clap/v4/README.chromium
+++ b/third_party/rust/clap/v4/README.chromium
@@ -1,7 +1,7 @@
 Name: clap
 URL: https://crates.io/crates/clap
-Version: 4.5.39
-Revision: 8520a7acb57fdcc4a5171d6f8e37252ee8a16432
+Version: 4.5.40
+Revision: 3716f9f4289594b43abec42b2538efd1a90ff897
 License: Apache-2.0
 License File: //third_party/rust/chromium_crates_io/vendor/clap-v4/LICENSE-APACHE
 Shipped: no
diff --git a/third_party/rust/clap_builder/v4/BUILD.gn b/third_party/rust/clap_builder/v4/BUILD.gn
index 82abefa4..21c9eb42 100644
--- a/third_party/rust/clap_builder/v4/BUILD.gn
+++ b/third_party/rust/clap_builder/v4/BUILD.gn
@@ -78,7 +78,7 @@
   edition = "2021"
   cargo_pkg_name = "clap_builder"
   cargo_pkg_description = "A simple to use, efficient, and full-featured Command Line Argument Parser"
-  cargo_pkg_version = "4.5.39"
+  cargo_pkg_version = "4.5.40"
 
   allow_unsafe = false
 
diff --git a/third_party/rust/clap_builder/v4/README.chromium b/third_party/rust/clap_builder/v4/README.chromium
index 08365f0..b19bb3f 100644
--- a/third_party/rust/clap_builder/v4/README.chromium
+++ b/third_party/rust/clap_builder/v4/README.chromium
@@ -1,7 +1,7 @@
 Name: clap_builder
 URL: https://crates.io/crates/clap_builder
-Version: 4.5.39
-Revision: 8520a7acb57fdcc4a5171d6f8e37252ee8a16432
+Version: 4.5.40
+Revision: 3716f9f4289594b43abec42b2538efd1a90ff897
 License: Apache-2.0
 License File: //third_party/rust/chromium_crates_io/vendor/clap_builder-v4/LICENSE-APACHE
 Shipped: no
diff --git a/third_party/rust/hashbrown/v0_15/BUILD.gn b/third_party/rust/hashbrown/v0_15/BUILD.gn
index 96f1f359..73a328a3 100644
--- a/third_party/rust/hashbrown/v0_15/BUILD.gn
+++ b/third_party/rust/hashbrown/v0_15/BUILD.gn
@@ -50,7 +50,7 @@
   cargo_pkg_authors = "Amanieu d'Antras <amanieu@gmail.com>"
   cargo_pkg_name = "hashbrown"
   cargo_pkg_description = "A Rust port of Google's SwissTable hash map"
-  cargo_pkg_version = "0.15.3"
+  cargo_pkg_version = "0.15.4"
 
   allow_unsafe = true
 
diff --git a/third_party/rust/hashbrown/v0_15/README.chromium b/third_party/rust/hashbrown/v0_15/README.chromium
index 22888dc5..5c55a75 100644
--- a/third_party/rust/hashbrown/v0_15/README.chromium
+++ b/third_party/rust/hashbrown/v0_15/README.chromium
@@ -1,7 +1,7 @@
 Name: hashbrown
 URL: https://crates.io/crates/hashbrown
-Version: 0.15.3
-Revision: 631dfed6e9a4f0afd5de3f6799d02f2baa8e7050
+Version: 0.15.4
+Revision: 8ceeb4045f8a23752d0091cf4c6c8976c9e291b3
 License: Apache-2.0
 License File: //third_party/rust/chromium_crates_io/vendor/hashbrown-v0_15/LICENSE-APACHE
 Shipped: yes
diff --git a/third_party/rust/memchr/v2/BUILD.gn b/third_party/rust/memchr/v2/BUILD.gn
index 64bb1abc..d879b81 100644
--- a/third_party/rust/memchr/v2/BUILD.gn
+++ b/third_party/rust/memchr/v2/BUILD.gn
@@ -68,7 +68,7 @@
   cargo_pkg_authors = "Andrew Gallant <jamslam@gmail.com>, bluss"
   cargo_pkg_name = "memchr"
   cargo_pkg_description = "Provides extremely fast (uses SIMD on x86_64, aarch64 and wasm32) routines for 1, 2 or 3 byte search and single substring search."
-  cargo_pkg_version = "2.7.4"
+  cargo_pkg_version = "2.7.5"
 
   allow_unsafe = true
 
diff --git a/third_party/rust/memchr/v2/README.chromium b/third_party/rust/memchr/v2/README.chromium
index 745c1a62..ce0e3c9 100644
--- a/third_party/rust/memchr/v2/README.chromium
+++ b/third_party/rust/memchr/v2/README.chromium
@@ -1,7 +1,7 @@
 Name: memchr
 URL: https://crates.io/crates/memchr
-Version: 2.7.4
-Revision: 8ad339524d857a2dd9e7231b497ed92aa0f5c334
+Version: 2.7.5
+Revision: 3962118774ac511580c5b40fd14323e31629fa52
 License: MIT
 License File: //third_party/rust/chromium_crates_io/vendor/memchr-v2/LICENSE-MIT
 Shipped: yes
diff --git a/third_party/rust/miniz_oxide/v0_8/BUILD.gn b/third_party/rust/miniz_oxide/v0_8/BUILD.gn
index c668cb6b..fff258f0 100644
--- a/third_party/rust/miniz_oxide/v0_8/BUILD.gn
+++ b/third_party/rust/miniz_oxide/v0_8/BUILD.gn
@@ -37,7 +37,7 @@
   cargo_pkg_authors = "Frommi <daniil.liferenko@gmail.com>, oyvindln <oyvindln@users.noreply.github.com>, Rich Geldreich richgel99@gmail.com"
   cargo_pkg_name = "miniz_oxide"
   cargo_pkg_description = "DEFLATE compression and decompression library rewritten in Rust based on miniz"
-  cargo_pkg_version = "0.8.8"
+  cargo_pkg_version = "0.8.9"
 
   allow_unsafe = false
 
diff --git a/third_party/rust/miniz_oxide/v0_8/README.chromium b/third_party/rust/miniz_oxide/v0_8/README.chromium
index 004a2a4c..b9d4db9 100644
--- a/third_party/rust/miniz_oxide/v0_8/README.chromium
+++ b/third_party/rust/miniz_oxide/v0_8/README.chromium
@@ -1,7 +1,7 @@
 Name: miniz_oxide
 URL: https://crates.io/crates/miniz_oxide
-Version: 0.8.8
-Revision: f177ab233c9e38cec03f7b35b9e642246c893312
+Version: 0.8.9
+Revision: 44e43c7786e379b2b1a7fde4aa0e63be719e583d
 License: Apache-2.0
 License File: //third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8/LICENSE-APACHE.md
 Shipped: yes
diff --git a/third_party/rust/rustc_demangle/v0_1/BUILD.gn b/third_party/rust/rustc_demangle/v0_1/BUILD.gn
index 8078e13..fc90a57 100644
--- a/third_party/rust/rustc_demangle/v0_1/BUILD.gn
+++ b/third_party/rust/rustc_demangle/v0_1/BUILD.gn
@@ -25,7 +25,7 @@
   cargo_pkg_authors = "Alex Crichton <alex@alexcrichton.com>"
   cargo_pkg_name = "rustc-demangle"
   cargo_pkg_description = "Rust compiler symbol demangling."
-  cargo_pkg_version = "0.1.24"
+  cargo_pkg_version = "0.1.25"
 
   allow_unsafe = false
 
diff --git a/third_party/rust/rustc_demangle/v0_1/README.chromium b/third_party/rust/rustc_demangle/v0_1/README.chromium
index 5df42967..106b15a 100644
--- a/third_party/rust/rustc_demangle/v0_1/README.chromium
+++ b/third_party/rust/rustc_demangle/v0_1/README.chromium
@@ -1,7 +1,7 @@
 Name: rustc-demangle
 URL: https://crates.io/crates/rustc-demangle
-Version: 0.1.24
-Revision: d43f6d58562319e93a492ac8ceb3fe258beefaf4
+Version: 0.1.25
+Revision: 8e15996082029a8f5e577906b7464aa412660d91
 License: Apache-2.0
 License File: //third_party/rust/chromium_crates_io/vendor/rustc-demangle-v0_1/LICENSE-APACHE
 Shipped: no
diff --git a/third_party/rust/smallvec/v1/BUILD.gn b/third_party/rust/smallvec/v1/BUILD.gn
index 3c1351a..906dd51 100644
--- a/third_party/rust/smallvec/v1/BUILD.gn
+++ b/third_party/rust/smallvec/v1/BUILD.gn
@@ -27,7 +27,7 @@
   cargo_pkg_authors = "The Servo Project Developers"
   cargo_pkg_name = "smallvec"
   cargo_pkg_description = "'Small vector' optimization: store up to a small number of items on the stack"
-  cargo_pkg_version = "1.15.0"
+  cargo_pkg_version = "1.15.1"
 
   allow_unsafe = true
 
diff --git a/third_party/rust/smallvec/v1/README.chromium b/third_party/rust/smallvec/v1/README.chromium
index 4c5b92f..08c487e 100644
--- a/third_party/rust/smallvec/v1/README.chromium
+++ b/third_party/rust/smallvec/v1/README.chromium
@@ -1,7 +1,7 @@
 Name: smallvec
 URL: https://crates.io/crates/smallvec
-Version: 1.15.0
-Revision: 7c4d350f5ec284fd05807f1a182387889a62af24
+Version: 1.15.1
+Revision: d0f47a3ea99296498ee940b5d99f59b403c498a2
 License: Apache-2.0
 License File: //third_party/rust/chromium_crates_io/vendor/smallvec-v1/LICENSE-APACHE
 Shipped: yes
diff --git a/third_party/rust/syn/v2/BUILD.gn b/third_party/rust/syn/v2/BUILD.gn
index 7e049a8..db797d8a 100644
--- a/third_party/rust/syn/v2/BUILD.gn
+++ b/third_party/rust/syn/v2/BUILD.gn
@@ -77,7 +77,7 @@
   cargo_pkg_authors = "David Tolnay <dtolnay@gmail.com>"
   cargo_pkg_name = "syn"
   cargo_pkg_description = "Parser for Rust source code"
-  cargo_pkg_version = "2.0.101"
+  cargo_pkg_version = "2.0.102"
 
   allow_unsafe = true
 
diff --git a/third_party/rust/syn/v2/README.chromium b/third_party/rust/syn/v2/README.chromium
index 9c6b49a..4177b6c 100644
--- a/third_party/rust/syn/v2/README.chromium
+++ b/third_party/rust/syn/v2/README.chromium
@@ -1,7 +1,7 @@
 Name: syn
 URL: https://crates.io/crates/syn
-Version: 2.0.101
-Revision: 58336a3fb49b63aae0ae2e708a69167543ff0e97
+Version: 2.0.102
+Revision: b1cc55995dc2ff30ffdf10fc428f9df0bb85f28d
 License: Apache-2.0
 License File: //third_party/rust/chromium_crates_io/vendor/syn-v2/LICENSE-APACHE
 Shipped: yes
diff --git a/third_party/search_engines_data/resources b/third_party/search_engines_data/resources
index b07b9e1..09fd22f 160000
--- a/third_party/search_engines_data/resources
+++ b/third_party/search_engines_data/resources
@@ -1 +1 @@
-Subproject commit b07b9e19ca1e2ee2bfeef7e45fc91faaa12c78ed
+Subproject commit 09fd22f3a4fb77ab03b7734e0c03ff7d7f97ef88
diff --git a/third_party/tflite/README.chromium b/third_party/tflite/README.chromium
index f3b72f67..c0c6e7c 100644
--- a/third_party/tflite/README.chromium
+++ b/third_party/tflite/README.chromium
@@ -1,8 +1,8 @@
 Name: TensorFlow Lite
 Short Name: tflite
 URL: https://github.com/tensorflow/tensorflow
-Version: 60fb9c76b41f0e4d6cfdd6b1bd2fabe443455306
-Date: 2025-06-05
+Version: 75530866a843d37eb98dfc75c2eb152634335949
+Date: 2025-06-12
 License: Caffe, Apache-2.0
 License File: LICENSE
 Security Critical: Yes
diff --git a/third_party/tflite/src b/third_party/tflite/src
index 60fb9c7..7553086 160000
--- a/third_party/tflite/src
+++ b/third_party/tflite/src
@@ -1 +1 @@
-Subproject commit 60fb9c76b41f0e4d6cfdd6b1bd2fabe443455306
+Subproject commit 75530866a843d37eb98dfc75c2eb152634335949
diff --git a/third_party/vulkan-deps b/third_party/vulkan-deps
index 636bbcf..222889e 160000
--- a/third_party/vulkan-deps
+++ b/third_party/vulkan-deps
@@ -1 +1 @@
-Subproject commit 636bbcfcf2bc3bd8f1d1408bf631ccfa5a359e6a
+Subproject commit 222889ea039509b86fa6dd90fcb6acf47e79cdb9
diff --git a/third_party/vulkan-validation-layers/src b/third_party/vulkan-validation-layers/src
index 24d7e90..6d6e6ec 160000
--- a/third_party/vulkan-validation-layers/src
+++ b/third_party/vulkan-validation-layers/src
@@ -1 +1 @@
-Subproject commit 24d7e9058718bb4f183a44c0fcf479cd886a03bd
+Subproject commit 6d6e6ec8e51cd219498359cbc48e4762d1a80616
diff --git a/third_party/webgpu-cts/src b/third_party/webgpu-cts/src
index 605c2fe..cb3be1a 160000
--- a/third_party/webgpu-cts/src
+++ b/third_party/webgpu-cts/src
@@ -1 +1 @@
-Subproject commit 605c2fec81e2227d91a019bb0d8dc6eb7554af44
+Subproject commit cb3be1a0c7f808d1cae46d4ca14a966777193e2e
diff --git a/third_party/xnnpack/BUILD.gn b/third_party/xnnpack/BUILD.gn
index af38305..41bf1a76 100644
--- a/third_party/xnnpack/BUILD.gn
+++ b/third_party/xnnpack/BUILD.gn
@@ -1856,6 +1856,7 @@
     "src/src/operator-delete.c",
     "src/src/operator-run.c",
     "src/src/operator-utils.c",
+    "src/src/pack-lh.cc",
     "src/src/params.c",
     "src/src/runtime.c",
     "src/src/sanitizers.c",
@@ -1899,6 +1900,7 @@
     "src/src/operator-delete.c",
     "src/src/operator-run.c",
     "src/src/operator-utils.c",
+    "src/src/pack-lh.cc",
     "src/src/params.c",
     "src/src/runtime.c",
     "src/src/sanitizers.c",
@@ -9629,6 +9631,7 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/f32-vapproxgelu/gen/f32-vapproxgelu-sse2-rational-12-10-div.c",
+      "src/src/f32-vapproxgelu/gen/f32-vapproxgelu-sse2fma-rational-12-10-div.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -9655,6 +9658,7 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/f32-vapproxgelu/gen/f32-vapproxgelu-sse2-rational-12-10-div.c",
+      "src/src/f32-vapproxgelu/gen/f32-vapproxgelu-sse2fma-rational-12-10-div.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -10957,6 +10961,7 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/f32-vcos/gen/f32-vcos-sse2-rational-5-4-div.c",
+      "src/src/f32-vcos/gen/f32-vcos-sse2fma-rational-5-4-div.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -10983,6 +10988,7 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/f32-vcos/gen/f32-vcos-sse2-rational-5-4-div.c",
+      "src/src/f32-vcos/gen/f32-vcos-sse2fma-rational-5-4-div.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -11495,6 +11501,7 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/f32-vexp/gen/f32-vexp-sse2-rational-3-2-div.c",
+      "src/src/f32-vexp/gen/f32-vexp-sse2fma-rational-3-2-div.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -11521,6 +11528,7 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/f32-vexp/gen/f32-vexp-sse2-rational-3-2-div.c",
+      "src/src/f32-vexp/gen/f32-vexp-sse2fma-rational-3-2-div.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -11764,6 +11772,7 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/f32-vgelu/gen/f32-vgelu-sse2-rational-12-10-div.c",
+      "src/src/f32-vgelu/gen/f32-vgelu-sse2fma-rational-12-10-div.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -11790,6 +11799,7 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/f32-vgelu/gen/f32-vgelu-sse2-rational-12-10-div.c",
+      "src/src/f32-vgelu/gen/f32-vgelu-sse2fma-rational-12-10-div.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -12033,6 +12043,7 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/f32-vhswish/gen/f32-vhswish-sse2.c",
+      "src/src/f32-vhswish/gen/f32-vhswish-sse2fma.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -12059,6 +12070,7 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/f32-vhswish/gen/f32-vhswish-sse2.c",
+      "src/src/f32-vhswish/gen/f32-vhswish-sse2fma.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -12300,6 +12312,7 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/f32-vlog/gen/f32-vlog-sse2-rational-3-3-div.c",
+      "src/src/f32-vlog/gen/f32-vlog-sse2fma-rational-3-3-div.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -12326,6 +12339,7 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/f32-vlog/gen/f32-vlog-sse2-rational-3-3-div.c",
+      "src/src/f32-vlog/gen/f32-vlog-sse2fma-rational-3-3-div.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -13183,6 +13197,7 @@
 
     sources = [
       "src/include/xnnpack.h",
+      "src/src/f32-vrsqrt/gen/f32-vrsqrt-sse2-rsqrt.c",
       "src/src/f32-vrsqrt/gen/f32-vrsqrt-sse2-sqrt.c",
     ]
 
@@ -13209,6 +13224,7 @@
 
     sources = [
       "src/include/xnnpack.h",
+      "src/src/f32-vrsqrt/gen/f32-vrsqrt-sse2-rsqrt.c",
       "src/src/f32-vrsqrt/gen/f32-vrsqrt-sse2-sqrt.c",
     ]
 
@@ -13779,6 +13795,7 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/f32-vsin/gen/f32-vsin-sse2-rational-5-4-div.c",
+      "src/src/f32-vsin/gen/f32-vsin-sse2fma-rational-5-4-div.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -13805,6 +13822,7 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/f32-vsin/gen/f32-vsin-sse2-rational-5-4-div.c",
+      "src/src/f32-vsin/gen/f32-vsin-sse2fma-rational-5-4-div.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -13992,6 +14010,7 @@
 
     sources = [
       "src/include/xnnpack.h",
+      "src/src/f32-vsqrt/gen/f32-vsqrt-sse2-rsqrt.c",
       "src/src/f32-vsqrt/gen/f32-vsqrt-sse2-sqrt.c",
     ]
 
@@ -14018,6 +14037,7 @@
 
     sources = [
       "src/include/xnnpack.h",
+      "src/src/f32-vsqrt/gen/f32-vsqrt-sse2-rsqrt.c",
       "src/src/f32-vsqrt/gen/f32-vsqrt-sse2-sqrt.c",
     ]
 
@@ -14262,6 +14282,7 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/f32-vtanh/gen/f32-vtanh-sse2-rational-9-8-div.c",
+      "src/src/f32-vtanh/gen/f32-vtanh-sse2fma-rational-9-8-div.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -14288,6 +14309,7 @@
     sources = [
       "src/include/xnnpack.h",
       "src/src/f32-vtanh/gen/f32-vtanh-sse2-rational-9-8-div.c",
+      "src/src/f32-vtanh/gen/f32-vtanh-sse2fma-rational-9-8-div.c",
     ]
 
     configs -= [ "//build/config/compiler:chromium_code" ]
@@ -33652,12 +33674,14 @@
 
     sources = [
       "src/include/xnnpack.h",
+      "src/src/f32-gemm/gen/f32-gemm-1x16-minmax-aarch64-neonfma-lane-ld128.c",
       "src/src/f32-gemm/gen/f32-gemm-1x4-minmax-scalar.c",
       "src/src/f32-gemm/gen/f32-gemm-1x4-relu-scalar.c",
       "src/src/f32-gemm/gen/f32-gemm-1x4-scalar.c",
       "src/src/f32-gemm/gen/f32-gemm-1x8-minmax-aarch64-neonfma-lane-ld128.c",
       "src/src/f32-gemm/gen/f32-gemm-1x8-minmax-neon-lane-ld64.c",
       "src/src/f32-gemm/gen/f32-gemm-1x8s4-minmax-neonfma.c",
+      "src/src/f32-gemm/gen/f32-gemm-4x16-minmax-aarch64-neonfma-lane-ld128.c",
       "src/src/f32-gemm/gen/f32-gemm-4x2-minmax-aarch64-neonfma-lane-ld64.c",
       "src/src/f32-gemm/gen/f32-gemm-4x2-minmax-neon-lane-ld64.c",
       "src/src/f32-gemm/gen/f32-gemm-4x2-minmax-scalar.c",
@@ -33691,12 +33715,14 @@
 
     sources = [
       "src/include/xnnpack.h",
+      "src/src/f32-gemm/gen/f32-gemm-1x16-minmax-aarch64-neonfma-lane-ld128.c",
       "src/src/f32-gemm/gen/f32-gemm-1x4-minmax-scalar.c",
       "src/src/f32-gemm/gen/f32-gemm-1x4-relu-scalar.c",
       "src/src/f32-gemm/gen/f32-gemm-1x4-scalar.c",
       "src/src/f32-gemm/gen/f32-gemm-1x8-minmax-aarch64-neonfma-lane-ld128.c",
       "src/src/f32-gemm/gen/f32-gemm-1x8-minmax-neon-lane-ld64.c",
       "src/src/f32-gemm/gen/f32-gemm-1x8s4-minmax-neonfma.c",
+      "src/src/f32-gemm/gen/f32-gemm-4x16-minmax-aarch64-neonfma-lane-ld128.c",
       "src/src/f32-gemm/gen/f32-gemm-4x2-minmax-aarch64-neonfma-lane-ld64.c",
       "src/src/f32-gemm/gen/f32-gemm-4x2-minmax-neon-lane-ld64.c",
       "src/src/f32-gemm/gen/f32-gemm-4x2-minmax-scalar.c",
@@ -33926,12 +33952,14 @@
 
     sources = [
       "src/include/xnnpack.h",
+      "src/src/f32-igemm/gen/f32-igemm-1x16-minmax-aarch64-neonfma-lane-ld128.c",
       "src/src/f32-igemm/gen/f32-igemm-1x4-minmax-scalar.c",
       "src/src/f32-igemm/gen/f32-igemm-1x4-relu-scalar.c",
       "src/src/f32-igemm/gen/f32-igemm-1x4-scalar.c",
       "src/src/f32-igemm/gen/f32-igemm-1x8-minmax-aarch64-neonfma-lane-ld128.c",
       "src/src/f32-igemm/gen/f32-igemm-1x8-minmax-neon-lane-ld64.c",
       "src/src/f32-igemm/gen/f32-igemm-1x8s4-minmax-neonfma.c",
+      "src/src/f32-igemm/gen/f32-igemm-4x16-minmax-aarch64-neonfma-lane-ld128.c",
       "src/src/f32-igemm/gen/f32-igemm-4x2-minmax-aarch64-neonfma-lane-ld64.c",
       "src/src/f32-igemm/gen/f32-igemm-4x2-minmax-neon-lane-ld64.c",
       "src/src/f32-igemm/gen/f32-igemm-4x2-minmax-scalar.c",
@@ -33965,12 +33993,14 @@
 
     sources = [
       "src/include/xnnpack.h",
+      "src/src/f32-igemm/gen/f32-igemm-1x16-minmax-aarch64-neonfma-lane-ld128.c",
       "src/src/f32-igemm/gen/f32-igemm-1x4-minmax-scalar.c",
       "src/src/f32-igemm/gen/f32-igemm-1x4-relu-scalar.c",
       "src/src/f32-igemm/gen/f32-igemm-1x4-scalar.c",
       "src/src/f32-igemm/gen/f32-igemm-1x8-minmax-aarch64-neonfma-lane-ld128.c",
       "src/src/f32-igemm/gen/f32-igemm-1x8-minmax-neon-lane-ld64.c",
       "src/src/f32-igemm/gen/f32-igemm-1x8s4-minmax-neonfma.c",
+      "src/src/f32-igemm/gen/f32-igemm-4x16-minmax-aarch64-neonfma-lane-ld128.c",
       "src/src/f32-igemm/gen/f32-igemm-4x2-minmax-aarch64-neonfma-lane-ld64.c",
       "src/src/f32-igemm/gen/f32-igemm-4x2-minmax-neon-lane-ld64.c",
       "src/src/f32-igemm/gen/f32-igemm-4x2-minmax-scalar.c",
@@ -41447,6 +41477,8 @@
 
     sources = [
       "src/include/xnnpack.h",
+      "src/src/x32-packw/gen/x32-packw-gio-neon-u2.c",
+      "src/src/x32-packw/gen/x32-packw-x16-gemm-goi-neon-ld4lane-u4-prfm.c",
       "src/src/x32-packw/gen/x32-packw-x2-gemm-gio-scalar.c",
       "src/src/x32-packw/gen/x32-packw-x2-gemm-goi-neon-ld2lane-u2-prfm.c",
       "src/src/x32-packw/gen/x32-packw-x2-gemm-goi-scalar-float-u4.c",
@@ -41478,6 +41510,8 @@
 
     sources = [
       "src/include/xnnpack.h",
+      "src/src/x32-packw/gen/x32-packw-gio-neon-u2.c",
+      "src/src/x32-packw/gen/x32-packw-x16-gemm-goi-neon-ld4lane-u4-prfm.c",
       "src/src/x32-packw/gen/x32-packw-x2-gemm-gio-scalar.c",
       "src/src/x32-packw/gen/x32-packw-x2-gemm-goi-neon-ld2lane-u2-prfm.c",
       "src/src/x32-packw/gen/x32-packw-x2-gemm-goi-scalar-float-u4.c",
diff --git a/third_party/xnnpack/README.chromium b/third_party/xnnpack/README.chromium
index 71017e3..34b7314 100644
--- a/third_party/xnnpack/README.chromium
+++ b/third_party/xnnpack/README.chromium
@@ -1,8 +1,8 @@
 Name: XNNPACK
 Short Name: xnnpack
 URL: https://github.com/google/xnnpack
-Version: 888719e9a4b11251d03ad2d6526da7f2e2b57308
-Date: 2025-06-05
+Version: a0a1bd4b3de97b356d7b106bf7fd3def6ad2103f
+Date: 2025-06-12
 License: BSD-3-Clause
 License File: src/LICENSE
 Security Critical: Yes
diff --git a/third_party/xnnpack/build_identifier.c b/third_party/xnnpack/build_identifier.c
index 069eb2a..b1ab887 100644
--- a/third_party/xnnpack/build_identifier.c
+++ b/third_party/xnnpack/build_identifier.c
@@ -310,6 +310,7 @@
 // - external/xnnpack+/src/f32-vapproxgelu/gen/f32-vapproxgelu-fma3-rational-12-10-div.c
 // - external/xnnpack+/src/f32-vapproxgelu/gen/f32-vapproxgelu-scalar-rational-12-10-div.c
 // - external/xnnpack+/src/f32-vapproxgelu/gen/f32-vapproxgelu-sse2-rational-12-10-div.c
+// - external/xnnpack+/src/f32-vapproxgelu/gen/f32-vapproxgelu-sse2fma-rational-12-10-div.c
 // - external/xnnpack+/src/f32-vbinary/gen/f32-vadd-avx-u16.c
 // - external/xnnpack+/src/f32-vbinary/gen/f32-vadd-avx512f-u32.c
 // - external/xnnpack+/src/f32-vbinary/gen/f32-vadd-scalar-u8.c
@@ -411,6 +412,7 @@
 // - external/xnnpack+/src/f32-vcos/gen/f32-vcos-fma3-rational-5-4-div.c
 // - external/xnnpack+/src/f32-vcos/gen/f32-vcos-scalar-rational-5-4-div.c
 // - external/xnnpack+/src/f32-vcos/gen/f32-vcos-sse2-rational-5-4-div.c
+// - external/xnnpack+/src/f32-vcos/gen/f32-vcos-sse2fma-rational-5-4-div.c
 // - external/xnnpack+/src/f32-velu/gen/f32-velu-avx-rr2-lut4-p4-perm-u32.c
 // - external/xnnpack+/src/f32-velu/gen/f32-velu-avx2-rr1-lut4-p4-perm-u32.c
 // - external/xnnpack+/src/f32-velu/gen/f32-velu-avx512f-rr1-p6-u64.c
@@ -421,21 +423,25 @@
 // - external/xnnpack+/src/f32-vexp/gen/f32-vexp-fma3-rational-3-2-div.c
 // - external/xnnpack+/src/f32-vexp/gen/f32-vexp-scalar-rational-3-2-div.c
 // - external/xnnpack+/src/f32-vexp/gen/f32-vexp-sse2-rational-3-2-div.c
+// - external/xnnpack+/src/f32-vexp/gen/f32-vexp-sse2fma-rational-3-2-div.c
 // - external/xnnpack+/src/f32-vgelu/gen/f32-vgelu-avx-rational-12-10-div.c
 // - external/xnnpack+/src/f32-vgelu/gen/f32-vgelu-avx512f-rational-12-10-div.c
 // - external/xnnpack+/src/f32-vgelu/gen/f32-vgelu-fma3-rational-12-10-div.c
 // - external/xnnpack+/src/f32-vgelu/gen/f32-vgelu-scalar-rational-12-10-div.c
 // - external/xnnpack+/src/f32-vgelu/gen/f32-vgelu-sse2-rational-12-10-div.c
+// - external/xnnpack+/src/f32-vgelu/gen/f32-vgelu-sse2fma-rational-12-10-div.c
 // - external/xnnpack+/src/f32-vhswish/gen/f32-vhswish-avx.c
 // - external/xnnpack+/src/f32-vhswish/gen/f32-vhswish-avx512f.c
 // - external/xnnpack+/src/f32-vhswish/gen/f32-vhswish-fma3.c
 // - external/xnnpack+/src/f32-vhswish/gen/f32-vhswish-scalar.c
 // - external/xnnpack+/src/f32-vhswish/gen/f32-vhswish-sse2.c
+// - external/xnnpack+/src/f32-vhswish/gen/f32-vhswish-sse2fma.c
 // - external/xnnpack+/src/f32-vlog/gen/f32-vlog-avx2-rational-3-3-div.c
 // - external/xnnpack+/src/f32-vlog/gen/f32-vlog-avx512f-rational-3-3-div.c
 // - external/xnnpack+/src/f32-vlog/gen/f32-vlog-fma3-rational-3-3-div.c
 // - external/xnnpack+/src/f32-vlog/gen/f32-vlog-scalar-rational-3-3-div.c
 // - external/xnnpack+/src/f32-vlog/gen/f32-vlog-sse2-rational-3-3-div.c
+// - external/xnnpack+/src/f32-vlog/gen/f32-vlog-sse2fma-rational-3-3-div.c
 // - external/xnnpack+/src/f32-vlrelu/gen/f32-vlrelu-avx-u16.c
 // - external/xnnpack+/src/f32-vlrelu/gen/f32-vlrelu-avx512f-u16.c
 // - external/xnnpack+/src/f32-vlrelu/gen/f32-vlrelu-scalar-u4.c
@@ -469,6 +475,7 @@
 // - external/xnnpack+/src/f32-vrsqrt/gen/f32-vrsqrt-avx512f-sqrt.c
 // - external/xnnpack+/src/f32-vrsqrt/gen/f32-vrsqrt-scalar-rsqrt-u1.c
 // - external/xnnpack+/src/f32-vrsqrt/gen/f32-vrsqrt-scalar-sqrt.c
+// - external/xnnpack+/src/f32-vrsqrt/gen/f32-vrsqrt-sse2-rsqrt.c
 // - external/xnnpack+/src/f32-vrsqrt/gen/f32-vrsqrt-sse2-sqrt.c
 // - external/xnnpack+/src/f32-vsigmoid/gen/f32-vsigmoid-avx-rr2-p5-nr2-u16.c
 // - external/xnnpack+/src/f32-vsigmoid/gen/f32-vsigmoid-avx2-rr1-p5-div-u16.c
@@ -481,16 +488,19 @@
 // - external/xnnpack+/src/f32-vsin/gen/f32-vsin-fma3-rational-5-4-div.c
 // - external/xnnpack+/src/f32-vsin/gen/f32-vsin-scalar-rational-5-4-div.c
 // - external/xnnpack+/src/f32-vsin/gen/f32-vsin-sse2-rational-5-4-div.c
+// - external/xnnpack+/src/f32-vsin/gen/f32-vsin-sse2fma-rational-5-4-div.c
 // - external/xnnpack+/src/f32-vsqrt/gen/f32-vsqrt-avx-rsqrt.c
 // - external/xnnpack+/src/f32-vsqrt/gen/f32-vsqrt-avx-sqrt.c
 // - external/xnnpack+/src/f32-vsqrt/gen/f32-vsqrt-avx512f-rsqrt.c
 // - external/xnnpack+/src/f32-vsqrt/gen/f32-vsqrt-scalar-sqrt.c
+// - external/xnnpack+/src/f32-vsqrt/gen/f32-vsqrt-sse2-rsqrt.c
 // - external/xnnpack+/src/f32-vsqrt/gen/f32-vsqrt-sse2-sqrt.c
 // - external/xnnpack+/src/f32-vtanh/gen/f32-vtanh-avx-rational-9-8-div.c
 // - external/xnnpack+/src/f32-vtanh/gen/f32-vtanh-avx512f-rational-9-8-div.c
 // - external/xnnpack+/src/f32-vtanh/gen/f32-vtanh-fma3-rational-9-8-div.c
 // - external/xnnpack+/src/f32-vtanh/gen/f32-vtanh-scalar-rational-9-8-div.c
 // - external/xnnpack+/src/f32-vtanh/gen/f32-vtanh-sse2-rational-9-8-div.c
+// - external/xnnpack+/src/f32-vtanh/gen/f32-vtanh-sse2fma-rational-9-8-div.c
 // - external/xnnpack+/src/f32-vunary/gen/f32-vabs-avx.c
 // - external/xnnpack+/src/f32-vunary/gen/f32-vabs-avx512f.c
 // - external/xnnpack+/src/f32-vunary/gen/f32-vabs-scalar.c
@@ -955,10 +965,10 @@
 #include <string.h>
 
 static const uint8_t xnn_build_identifier[] = {
-   12,  22, 222,  18, 189, 150, 218, 146,
-  154, 210,  20,  25,  31,  16, 206, 242,
-   49,  58,  83,   0,  18,  91, 126,  53,
-  116, 131,  35, 169, 153, 175, 107,  45
+   50, 189, 164,  87, 243,   2, 241, 123,
+   17,  16, 148,  99,  75,  57,  35,  27,
+  189,   7, 160,  95, 202, 124,  74, 192,
+   95, 180, 188,  47,  39,  30, 149, 161
 };
 
 size_t xnn_experimental_get_build_identifier_size() {
diff --git a/third_party/xnnpack/src b/third_party/xnnpack/src
index 888719e..a0a1bd4b 160000
--- a/third_party/xnnpack/src
+++ b/third_party/xnnpack/src
@@ -1 +1 @@
-Subproject commit 888719e9a4b11251d03ad2d6526da7f2e2b57308
+Subproject commit a0a1bd4b3de97b356d7b106bf7fd3def6ad2103f
diff --git a/tools/clang/spanify/Spanifier.cpp b/tools/clang/spanify/Spanifier.cpp
index e7b1e37..a7242e0 100644
--- a/tools/clang/spanify/Spanifier.cpp
+++ b/tools/clang/spanify/Spanifier.cpp
@@ -12,6 +12,7 @@
 #include <sstream>
 #include <string>
 #include <string_view>
+#include <variant>
 #include <vector>
 
 #include "RawPtrHelpers.h"
@@ -832,6 +833,59 @@
   assert(false && "Unexpected binaryOperation Node");
 }
 
+struct RangedReplacement {
+  clang::SourceRange range;
+  std::string text;
+};
+
+// Specifies an edit: `base::checked_cast<size_t>(...)`
+struct CheckedCastReplacement {
+  RangedReplacement opener;
+  RangedReplacement closer;
+};
+
+// There are three possible subspan expr replacements, respectively:
+// 1. No replacement (leave as is)
+// 2. Append a `u` to an integer literal.
+// 3. Wrap the expression in `base::checked_cast<size_t>(...)`.
+using SubspanExprReplacement =
+    std::variant<std::monostate, RangedReplacement, CheckedCastReplacement>;
+
+static SubspanExprReplacement GetSubspanExprReplacement(
+    const clang::Expr* expr,
+    const MatchFinder::MatchResult& result,
+    std::string_view key) {
+  clang::QualType type = expr->getType();
+  const clang::ASTContext& ast_context = *result.Context;
+
+  const uint64_t size_t_bits =
+      ast_context.getTypeSize(ast_context.getSizeType());
+  const bool is_unsigned_type =
+      type == ast_context.getCorrespondingUnsignedType(type);
+  if (is_unsigned_type && ast_context.getTypeSize(type) <= size_t_bits) {
+    return {};
+  }
+
+  const clang::SourceManager& source_manager = *result.SourceManager;
+  const clang::SourceRange range =
+      getExprRange(expr, source_manager, result.Context->getLangOpts());
+
+  if (const auto* integer_literal =
+          clang::dyn_cast<clang::IntegerLiteral>(expr)) {
+    assert(integer_literal->getValue().isNonNegative());
+    return RangedReplacement{.range = range.getEnd(), .text = "u"};
+  }
+
+  EmitReplacement(key, GetIncludeDirective(range, source_manager,
+                                           "base/numerics/safe_conversions.h"));
+  EmitReplacement(key, GetIncludeDirective(range, source_manager, "cstdint",
+                                           /*is_system_include_path=*/true));
+  return CheckedCastReplacement{
+      .opener = {.range = range.getBegin(),
+                 .text = "base::checked_cast<size_t>("},
+      .closer = {.range = range.getEnd(), .text = ")"}};
+}
+
 // When a binary operation and rhs expr appear inside a macro expansion,
 // this function produces an expression like:
 //     UNSAFE_TODO(MACRO(will_be_span.data()))
@@ -1088,35 +1142,29 @@
 void RewriteExprForSubspan(const clang::Expr* expr,
                            const MatchFinder::MatchResult& result,
                            std::string_view key) {
-  clang::QualType type = expr->getType();
-  const clang::ASTContext& ast_context = *result.Context;
-
-  // This logic isn't perfect: an unsigned type wider than `size_t`
-  // will pop us out of this function, but will fail the `strict_cast`
-  // imposed by `subspan()`.
-  if (type == ast_context.getCorrespondingUnsignedType(type)) {
+  const auto replacement = GetSubspanExprReplacement(expr, result, key);
+  if (const auto* u_suffix = std::get_if<RangedReplacement>(&replacement)) {
+    EmitReplacement(key,
+                    GetReplacementDirective(u_suffix->range, u_suffix->text,
+                                            *result.SourceManager));
     return;
   }
 
-  const clang::SourceManager& source_manager = *result.SourceManager;
-  const clang::SourceRange range =
-      getExprRange(expr, source_manager, result.Context->getLangOpts());
-
-  if (clang::dyn_cast<clang::IntegerLiteral>(expr)) {
-    EmitReplacement(
-        key, GetReplacementDirective(range.getEnd(), "u", source_manager));
+  if (const auto* checked_cast_replacement =
+          std::get_if<CheckedCastReplacement>(&replacement)) {
+    const auto& [opener, closer] = *checked_cast_replacement;
+    EmitReplacement(key, GetReplacementDirective(opener.range, opener.text,
+                                                 *result.SourceManager));
+    EmitReplacement(key, GetReplacementDirective(closer.range, closer.text,
+                                                 *result.SourceManager));
     return;
   }
 
-  EmitReplacement(key, GetReplacementDirective(range.getBegin(),
-                                               "base::checked_cast<size_t>(",
-                                               source_manager));
-  EmitReplacement(key,
-                  GetReplacementDirective(range.getEnd(), ")", source_manager));
-  EmitReplacement(key, GetIncludeDirective(range, source_manager,
-                                           "base/numerics/safe_conversions.h"));
-  EmitReplacement(key, GetIncludeDirective(range, source_manager, "cstdint",
-                                           /*is_system_include_path=*/true));
+  if (!std::get_if<std::monostate>(&replacement)) {
+    llvm::errs() << "Unexpected variant in `RewriteExprForSubspan()`.";
+    DumpMatchResult(result);
+    return;
+  }
 }
 
 // Handle the case where we match `&container[<offset>]` being used as a buffer.
@@ -1419,7 +1467,8 @@
 // Rewrite:
 //   `sizeof(c_array)`
 // Into:
-//  `std_array.size() * sizeof(element_size)`.
+//   `base::SpanificationSizeofForStdArray(std_array)`
+// Tests are in: array-tests-original.cc
 void RewriteArraySizeof(const MatchFinder::MatchResult& result) {
   clang::SourceManager& source_manager = *result.SourceManager;
 
@@ -1444,18 +1493,19 @@
     end_offset = name.getAsString().length();
   }
 
+  const std::string& key = GetRHS(result);
   const clang::SourceRange replacement_range = {
       sizeof_expr->getBeginLoc(),
       sizeof_expr->getEndLoc().getLocWithOffset(end_offset)};
-
-  // The outer-most parentheses are redundant for most cases. But it's
-  // necessary in cases like "x / sizeof(c_array)", which is unlikely though.
-  std::string replacement_text = llvm::formatv(
-      "({0}.size() * sizeof(decltype({0})::value_type))", array_decl_as_string);
-  std::string replacement_directive = GetReplacementDirective(
-      replacement_range, std::move(replacement_text), source_manager);
-
-  EmitReplacement(GetRHS(result), replacement_directive);
+  EmitReplacement(key,
+                  GetReplacementDirective(
+                      replacement_range,
+                      llvm::formatv("base::SpanificationSizeofForStdArray({0})",
+                                    array_decl_as_string),
+                      source_manager));
+  EmitReplacement(key,
+                  GetIncludeDirective(replacement_range, source_manager,
+                                      kBaseAutoSpanificationHelperIncludePath));
 }
 
 // Add `.data()` at the frontier of a span change. This is applied if the node
@@ -2682,14 +2732,15 @@
     // not. Investigate?
     const auto reinterpret_cast_wrapper = optionally(hasParent(
         cxxReinterpretCastExpr(
-            cxxReinterpretCastExpr(hasDestinationType(qualType(pointsTo(
+            hasDestinationType(qualType(pointsTo(
                 qualType(anyOf(qualType(asString("uint8_t"))
                                    .bind("reinterpret_cast_to_bytes"),
                                qualType(isAnyCharacter())
                                    .bind("reinterpret_cast_to_bytes"),
                                qualType(isInteger())
                                    .bind("reinterpret_cast_to_integral_type")))
-                    .bind("target_type"))))))
+                    .bind("target_type")))),
+            unless(raw_ptr_plugin::isInMacroLocation()))
             .bind("reinterpret_cast")));
 
     // Defines nodes that contain size information, these include:
diff --git a/tools/clang/spanify/tests/array-tests-expected.cc b/tools/clang/spanify/tests/array-tests-expected.cc
index 35f2aeda..e6a76f3f 100644
--- a/tools/clang/spanify/tests/array-tests-expected.cc
+++ b/tools/clang/spanify/tests/array-tests-expected.cc
@@ -7,6 +7,7 @@
 #include <cstring>
 #include <tuple>
 
+#include "base/containers/auto_spanification_helper.h"
 #include "base/containers/span.h"
 
 // No rewrite expected.
@@ -95,11 +96,11 @@
   std::ignore = buf[UnsafeIndex()];
 
   // Expected rewrite:
-  // std::ignore = (buf.size() * sizeof(decltype(buf)::value_type));
-  std::ignore = (buf.size() * sizeof(decltype(buf)::value_type));
+  // std::ignore = base::SpanificationSizeofForStdArray(buf);
+  std::ignore = base::SpanificationSizeofForStdArray(buf);
   // Expected rewrite:
-  // std::ignore = (buf.size() * sizeof(decltype(buf)::value_type));
-  std::ignore = (buf.size() * sizeof(decltype(buf)::value_type));
+  // std::ignore = base::SpanificationSizeofForStdArray(buf);
+  std::ignore = base::SpanificationSizeofForStdArray(buf);
   // Expected rewrite:
   // std::ignore = sizeof buf[0];
   std::ignore = sizeof buf[0];
diff --git a/tools/clang/spanify/tests/array-tests-original.cc b/tools/clang/spanify/tests/array-tests-original.cc
index fec0b01..cbad0979 100644
--- a/tools/clang/spanify/tests/array-tests-original.cc
+++ b/tools/clang/spanify/tests/array-tests-original.cc
@@ -92,10 +92,10 @@
   std::ignore = buf[UnsafeIndex()];
 
   // Expected rewrite:
-  // std::ignore = (buf.size() * sizeof(decltype(buf)::value_type));
+  // std::ignore = base::SpanificationSizeofForStdArray(buf);
   std::ignore = sizeof buf;
   // Expected rewrite:
-  // std::ignore = (buf.size() * sizeof(decltype(buf)::value_type));
+  // std::ignore = base::SpanificationSizeofForStdArray(buf);
   std::ignore = sizeof(buf);
   // Expected rewrite:
   // std::ignore = sizeof buf[0];
diff --git a/tools/clang/spanify/tests/span-frontier-macro-expected.cc b/tools/clang/spanify/tests/span-frontier-macro-expected.cc
index 111ed69..911b4c83 100644
--- a/tools/clang/spanify/tests/span-frontier-macro-expected.cc
+++ b/tools/clang/spanify/tests/span-frontier-macro-expected.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <tuple>
 #include <vector>
 
 // When a C++ MACRO references a variable that isn't passed as an argument to
@@ -35,33 +36,60 @@
 // No function body so that the argument type won't get spanified.
 void take_ptr1(int* arg);
 
-// A macro that expects a pointer as the argument.
+// Macros that expect a pointer as the argument.
+//
+// TODO: Since these macros are defined and used inside this translation unit
+// only, we may want to rewrite the macro definitions rather than adding
+// ".data()" call on the call sites.
 #define TAKE_PTR1(arg) (take_ptr1(arg))
+#define TAKE_PTR2(arg) (arg + 1)
+#define TAKE_PTR3_REINTERPRET_CAST(arg) (reinterpret_cast<unsigned char*>(arg))
+#define TAKE_PTR3_STATIC_CAST(arg) (static_cast<const int*>(arg))
+#define TAKE_PTR3_C_STYLE_CAST(arg) ((double*)(arg))
 
-void test_take_ptr1_macro() {
-  int array[3] = {1, 2, 3};
+void test_take_ptr_macro() {
+  int array[] = {1, 2, 3};
   // Expected rewrite:
   // base::span<int> buf = array;
   base::span<int> buf = array;
   buf[0] = 0;
+
   // Expected rewrite:
   // TAKE_PTR1(buf.data());
   TAKE_PTR1(buf.data());
-}
 
-// A macro that expects a pointer as the argument.
-#define TAKE_PTR2(arg) (arg + 1)
-
-void test_take_ptr2_macro() {
-  int array[3] = {1, 2, 3};
-  // Expected rewrite:
-  // base::span<int> buf = array;
-  base::span<int> buf = array;
-  buf[0] = 0;
   // Expected rewrite:
   // UNSAFE_TODO(TAKE_PTR2(buf.data()));
   UNSAFE_TODO(TAKE_PTR2(buf.data()));
-}
 
-// TODO(yukishiino): Support static_cast and C style cast.
-// #define TAKE_PTR3(arg) ((char*)(arg))
+  // Expected rewrite:
+  // unsigned char* p1 = TAKE_PTR3_REINTERPRET_CAST(buf.data());
+  unsigned char* p1 = TAKE_PTR3_REINTERPRET_CAST(buf.data());
+  // Expected rewrite:
+  // const int* p2 = TAKE_PTR3_STATIC_CAST(buf.data());
+  const int* p2 = TAKE_PTR3_STATIC_CAST(buf.data());
+  // Expected rewrite:
+  // double* p3 = TAKE_PTR3_C_STYLE_CAST(buf.data());
+  double* p3 = TAKE_PTR3_C_STYLE_CAST(buf.data());
+
+  // The following rewrites are not compilable. Just demonstrating the current
+  // behavior.
+  //
+  // Unexpected rewrite:
+  // base::span<unsigned char> s1 = TAKE_PTR3_REINTERPRET_CAST(buf);
+  base::span<unsigned char> s1 = TAKE_PTR3_REINTERPRET_CAST(buf);
+  std::ignore = s1[0];
+  // Unexpected rewrite:
+  // base::span<const int> s2 = TAKE_PTR3_STATIC_CAST(buf);
+  base::span<const int> s2 = TAKE_PTR3_STATIC_CAST(buf);
+  std::ignore = s2[0];
+  // Unexpected rewrite:
+  // base::span<double> s3 = TAKE_PTR3_C_STYLE_CAST(buf);
+  base::span<double> s3 = TAKE_PTR3_C_STYLE_CAST(buf);
+  std::ignore = s3[0];
+
+  // Just casting doesn't trigger rewriting.
+  TAKE_PTR3_REINTERPRET_CAST(buf);
+  TAKE_PTR3_STATIC_CAST(buf);
+  TAKE_PTR3_C_STYLE_CAST(buf);
+}
diff --git a/tools/clang/spanify/tests/span-frontier-macro-original.cc b/tools/clang/spanify/tests/span-frontier-macro-original.cc
index e76517d..b86aace 100644
--- a/tools/clang/spanify/tests/span-frontier-macro-original.cc
+++ b/tools/clang/spanify/tests/span-frontier-macro-original.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <tuple>
 #include <vector>
 
 // When a C++ MACRO references a variable that isn't passed as an argument to
@@ -33,33 +34,60 @@
 // No function body so that the argument type won't get spanified.
 void take_ptr1(int* arg);
 
-// A macro that expects a pointer as the argument.
+// Macros that expect a pointer as the argument.
+//
+// TODO: Since these macros are defined and used inside this translation unit
+// only, we may want to rewrite the macro definitions rather than adding
+// ".data()" call on the call sites.
 #define TAKE_PTR1(arg) (take_ptr1(arg))
+#define TAKE_PTR2(arg) (arg + 1)
+#define TAKE_PTR3_REINTERPRET_CAST(arg) (reinterpret_cast<unsigned char*>(arg))
+#define TAKE_PTR3_STATIC_CAST(arg) (static_cast<const int*>(arg))
+#define TAKE_PTR3_C_STYLE_CAST(arg) ((double*)(arg))
 
-void test_take_ptr1_macro() {
-  int array[3] = {1, 2, 3};
+void test_take_ptr_macro() {
+  int array[] = {1, 2, 3};
   // Expected rewrite:
   // base::span<int> buf = array;
   int* buf = array;
   buf[0] = 0;
+
   // Expected rewrite:
   // TAKE_PTR1(buf.data());
   TAKE_PTR1(buf);
-}
 
-// A macro that expects a pointer as the argument.
-#define TAKE_PTR2(arg) (arg + 1)
-
-void test_take_ptr2_macro() {
-  int array[3] = {1, 2, 3};
-  // Expected rewrite:
-  // base::span<int> buf = array;
-  int* buf = array;
-  buf[0] = 0;
   // Expected rewrite:
   // UNSAFE_TODO(TAKE_PTR2(buf.data()));
   TAKE_PTR2(buf);
-}
 
-// TODO(yukishiino): Support static_cast and C style cast.
-// #define TAKE_PTR3(arg) ((char*)(arg))
+  // Expected rewrite:
+  // unsigned char* p1 = TAKE_PTR3_REINTERPRET_CAST(buf.data());
+  unsigned char* p1 = TAKE_PTR3_REINTERPRET_CAST(buf);
+  // Expected rewrite:
+  // const int* p2 = TAKE_PTR3_STATIC_CAST(buf.data());
+  const int* p2 = TAKE_PTR3_STATIC_CAST(buf);
+  // Expected rewrite:
+  // double* p3 = TAKE_PTR3_C_STYLE_CAST(buf.data());
+  double* p3 = TAKE_PTR3_C_STYLE_CAST(buf);
+
+  // The following rewrites are not compilable. Just demonstrating the current
+  // behavior.
+  //
+  // Unexpected rewrite:
+  // base::span<unsigned char> s1 = TAKE_PTR3_REINTERPRET_CAST(buf);
+  unsigned char* s1 = TAKE_PTR3_REINTERPRET_CAST(buf);
+  std::ignore = s1[0];
+  // Unexpected rewrite:
+  // base::span<const int> s2 = TAKE_PTR3_STATIC_CAST(buf);
+  const int* s2 = TAKE_PTR3_STATIC_CAST(buf);
+  std::ignore = s2[0];
+  // Unexpected rewrite:
+  // base::span<double> s3 = TAKE_PTR3_C_STYLE_CAST(buf);
+  double* s3 = TAKE_PTR3_C_STYLE_CAST(buf);
+  std::ignore = s3[0];
+
+  // Just casting doesn't trigger rewriting.
+  TAKE_PTR3_REINTERPRET_CAST(buf);
+  TAKE_PTR3_STATIC_CAST(buf);
+  TAKE_PTR3_C_STYLE_CAST(buf);
+}
diff --git a/tools/clang/spanify/tests/temporary-unnamed-span-issue-408018846-expected.cc b/tools/clang/spanify/tests/temporary-unnamed-span-issue-408018846-expected.cc
index 0b75dea4..467572df 100644
--- a/tools/clang/spanify/tests/temporary-unnamed-span-issue-408018846-expected.cc
+++ b/tools/clang/spanify/tests/temporary-unnamed-span-issue-408018846-expected.cc
@@ -6,6 +6,7 @@
 #include <cstdint>
 #include <string_view>
 
+#include "base/containers/auto_spanification_helper.h"
 #include "base/containers/span.h"
 
 std::string_view ReturnOffsetIntoString(size_t offset) {
@@ -19,12 +20,8 @@
   // Expected rewrite:
   // return std::string_view(
   //     base::span<char>(non_const_buffer).subspan(offset).data(),
-  //     (non_const_buffer.size() *
-  //      sizeof(decltype(non_const_buffer)::value_type)) -
-  //         offset);
+  //     base::SpanificationSizeofForStdArray(non_const_buffer) - offset);
   return std::string_view(
       base::span<char>(non_const_buffer).subspan(offset).data(),
-      (non_const_buffer.size() *
-       sizeof(decltype(non_const_buffer)::value_type)) -
-          offset);
+      base::SpanificationSizeofForStdArray(non_const_buffer) - offset);
 }
diff --git a/tools/clang/spanify/tests/temporary-unnamed-span-issue-408018846-original.cc b/tools/clang/spanify/tests/temporary-unnamed-span-issue-408018846-original.cc
index c0231fb6..6efc062 100644
--- a/tools/clang/spanify/tests/temporary-unnamed-span-issue-408018846-original.cc
+++ b/tools/clang/spanify/tests/temporary-unnamed-span-issue-408018846-original.cc
@@ -16,9 +16,7 @@
   // Expected rewrite:
   // return std::string_view(
   //     base::span<char>(non_const_buffer).subspan(offset).data(),
-  //     (non_const_buffer.size() *
-  //      sizeof(decltype(non_const_buffer)::value_type)) -
-  //         offset);
+  //     base::SpanificationSizeofForStdArray(non_const_buffer) - offset);
   return std::string_view(non_const_buffer + offset,
                           sizeof(non_const_buffer) - offset);
 }
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index ef6ba4e..07048562 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -39431,6 +39431,44 @@
   </description>
 </action>
 
+<action name="Signin_BottomSheet_DefaultAccount_AddAccount">
+  <owner>arthurmilchior@chromium.org</owner>
+  <owner>chrome-signin-mobile-team@google.com</owner>
+  <description>
+    Recorded when the user taps on the Add Account button in the sign-in bottom
+    sheet. This can only occurs if all accounts were removed from the device
+    after the sign-in sheet was opened. Recorded for iOS only.
+  </description>
+</action>
+
+<action name="Signin_BottomSheet_DefaultAccount_IdentityButtonTapped">
+  <owner>arthurmilchior@chromium.org</owner>
+  <owner>chrome-signin-mobile-team@google.com</owner>
+  <description>
+    Recorded when the user taps on the button with the default identity in the
+    sign-in bottom sheet. That cause the identity chooser to be opened. Recorded
+    for iOS only.
+  </description>
+</action>
+
+<action name="Signin_BottomSheet_DefaultAccount_Signin">
+  <owner>arthurmilchior@chromium.org</owner>
+  <owner>chrome-signin-mobile-team@google.com</owner>
+  <description>
+    Recorded when the user taps on sign-in button in the sign-in bottom sheet.
+    Recorded for iOS only.
+  </description>
+</action>
+
+<action name="Signin_BottomSheet_DefaultAccount_Skip">
+  <owner>arthurmilchior@chromium.org</owner>
+  <owner>chrome-signin-mobile-team@google.com</owner>
+  <description>
+    Recorded when the user tap &quot;cancel&quot; or &quot;skip&quot; in the
+    sign-in bottom sheet. Recorded for iOS only.
+  </description>
+</action>
+
 <action name="Signin_BottomSheet_IdentityChooser_Closed">
   <owner>jlebel@chromium.org</owner>
   <owner>chrome-signin-mobile-team@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/ash/enums.xml b/tools/metrics/histograms/metadata/ash/enums.xml
index ebfbfa8..04f5018 100644
--- a/tools/metrics/histograms/metadata/ash/enums.xml
+++ b/tools/metrics/histograms/metadata/ash/enums.xml
@@ -2318,6 +2318,7 @@
   <int value="20" label="Select a window in Snap Group in partial Overview"/>
   <int value="21" label="Move a window in Snap Group to new coral desk"/>
   <int value="22" label="ToggleSnapGroup accelerator"/>
+  <int value="23" label="Moved to another display"/>
 </enum>
 
 <enum name="SpeechRecognitionEndState">
diff --git a/tools/metrics/histograms/metadata/glic/histograms.xml b/tools/metrics/histograms/metadata/glic/histograms.xml
index e94f4abc..85605a5c 100644
--- a/tools/metrics/histograms/metadata/glic/histograms.xml
+++ b/tools/metrics/histograms/metadata/glic/histograms.xml
@@ -77,7 +77,6 @@
     <variant name="GetOsMicrophonePermissionStatus"/>
     <variant name="GetUserProfileInfo"/>
     <variant name="GetZeroStateSuggestionsForFocusedTab"/>
-    <variant name="MaybeRefreshUserStatus"/>
     <variant name="OnRequestStarted"/>
     <variant name="OnResponseRated"/>
     <variant name="OnResponseStarted"/>
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml
index 9bde140..45671a06 100644
--- a/tools/metrics/histograms/metadata/net/histograms.xml
+++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -3209,7 +3209,7 @@
   </summary>
 </histogram>
 
-<histogram name="Net.HttpStreamPool.AttemptManagerAliveTime" units="ms"
+<histogram name="Net.HttpStreamPool.AttemptManagerAliveTime2" units="ms"
     expires_after="2025-12-02">
   <owner>bashi@chromium.org</owner>
   <owner>blink-network-stack@google.com</owner>
@@ -3236,7 +3236,7 @@
 </histogram>
 
 <histogram name="Net.HttpStreamPool.InitialAttemptState2"
-    enum="HttpStreamPoolInitialAttemptState" expires_after="2025-11-16">
+    enum="HttpStreamPoolInitialAttemptState" expires_after="2025-12-02">
   <owner>bashi@chromium.org</owner>
   <owner>blink-network-stack@google.com</owner>
   <summary>
@@ -3246,8 +3246,8 @@
   </summary>
 </histogram>
 
-<histogram name="Net.HttpStreamPool.JobCompleteTime2.{Result}" units="ms"
-    expires_after="2025-11-16">
+<histogram name="Net.HttpStreamPool.JobCompleteTime3.{Result}" units="ms"
+    expires_after="2025-12-02">
   <owner>bashi@chromium.org</owner>
   <owner>blink-network-stack@google.com</owner>
   <summary>
@@ -3323,7 +3323,7 @@
 
 <histogram
     name="Net.HttpStreamPool.TcpBasedAttemptCanceledInitialAttemptState.{Reason}"
-    enum="HttpStreamPoolInitialAttemptState" expires_after="2025-09-14">
+    enum="HttpStreamPoolInitialAttemptState" expires_after="2025-12-02">
   <owner>bashi@chromium.org</owner>
   <owner>blink-network-stack@google.com</owner>
   <summary>
@@ -3340,7 +3340,7 @@
   </token>
 </histogram>
 
-<histogram name="Net.HttpStreamPool.TcpBasedAttemptCanceledTime.{Reason}"
+<histogram name="Net.HttpStreamPool.TcpBasedAttemptCanceledTime2.{Reason}"
     units="ms" expires_after="2025-12-02">
   <owner>bashi@chromium.org</owner>
   <owner>blink-network-stack@google.com</owner>
@@ -3358,7 +3358,7 @@
 </histogram>
 
 <histogram name="Net.HttpStreamPool.TcpBasedAttemptCancelReason"
-    enum="StreamSocketCloseReason" expires_after="2025-09-14">
+    enum="StreamSocketCloseReason" expires_after="2025-12-02">
   <owner>bashi@chromium.org</owner>
   <owner>blink-network-stack@google.com</owner>
   <summary>
@@ -3368,7 +3368,7 @@
 </histogram>
 
 <histogram name="Net.HttpStreamPool.TcpBasedAttemptDelay" units="ms"
-    expires_after="2025-11-16">
+    expires_after="2025-12-02">
   <owner>bashi@chromium.org</owner>
   <owner>blink-network-stack@google.com</owner>
   <summary>
@@ -3377,7 +3377,7 @@
   </summary>
 </histogram>
 
-<histogram name="Net.HttpStreamPool.TcpBasedAttemptSSLConfigWaitTime"
+<histogram name="Net.HttpStreamPool.TcpBasedAttemptSSLConfigWaitTime2"
     units="ms" expires_after="2025-12-02">
   <owner>bashi@chromium.org</owner>
   <owner>blink-network-stack@google.com</owner>
@@ -3387,8 +3387,8 @@
   </summary>
 </histogram>
 
-<histogram name="Net.HttpStreamPool.TcpBasedAttemptTime.{Result}" units="ms"
-    expires_after="2025-09-14">
+<histogram name="Net.HttpStreamPool.TcpBasedAttemptTime2.{Result}" units="ms"
+    expires_after="2025-12-02">
   <owner>bashi@chromium.org</owner>
   <owner>blink-network-stack@google.com</owner>
   <summary>
diff --git a/tools/perf/core/bot_platforms.py b/tools/perf/core/bot_platforms.py
index 9d88b8f..34278c0 100644
--- a/tools/perf/core/bot_platforms.py
+++ b/tools/perf/core/bot_platforms.py
@@ -496,6 +496,14 @@
                           arguments=arguments)
 
 
+# Webview:
+def _crossbench_loading(estimated_runtime=60, arguments=None):
+  return CrossbenchConfig('loading.crossbench',
+                          'loading',
+                          estimated_runtime=estimated_runtime,
+                          arguments=arguments)
+
+
 _CROSSBENCH_JETSTREAM_SPEEDOMETER = frozenset([
     _crossbench_jetstream2(),
     _crossbench_speedometer3(),
@@ -547,6 +555,19 @@
     ]),
 ])
 
+_CROSSBENCH_WEBVIEW = frozenset([
+    _crossbench_loading(
+        estimated_runtime=750,
+        arguments=[
+            '--wpr=crossbench_android_loading_000.wprgo',
+            '--probe=chrome_histograms:{"baseline":false,"metrics":'
+            '{"Android.WebView.Startup.CreationTime.StartChromiumLocked":["mean"]}}',
+            '--repetitions=50',
+            '--stories=cnn',
+        ]
+    ),
+])
+
 _CHROME_HEALTH_BENCHMARK_CONFIGS_DESKTOP = PerfSuite(
     [_GetBenchmarkConfig('system_health.common_desktop')])
 
@@ -975,10 +996,12 @@
     pinpoint_only=True)
 ANDROID_PIXEL4_WEBVIEW = PerfPlatform(
     'android-pixel4_webview-perf', 'Android R',
-    _ANDROID_PIXEL4_WEBVIEW_BENCHMARK_CONFIGS, 23, 'android')
+    _ANDROID_PIXEL4_WEBVIEW_BENCHMARK_CONFIGS, 23, 'android',
+    crossbench=_CROSSBENCH_WEBVIEW)
 ANDROID_PIXEL4_WEBVIEW_PGO = PerfPlatform(
     'android-pixel4_webview-perf-pgo', 'Android R',
-    _ANDROID_PIXEL4_WEBVIEW_BENCHMARK_CONFIGS, 20, 'android')
+    _ANDROID_PIXEL4_WEBVIEW_BENCHMARK_CONFIGS, 20, 'android',
+    crossbench=_CROSSBENCH_WEBVIEW)
 ANDROID_PIXEL6 = PerfPlatform('android-pixel6-perf',
                               'Android U',
                               _ANDROID_PIXEL6_BENCHMARK_CONFIGS,
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 77cd92f..59f6929 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -6,7 +6,7 @@
         },
         "win": {
             "hash": "2f70d385ac25c97f50daeba79b32f7965fa0cedc",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/791bf363d18201eae5e636ba66d7d8b17472b769/trace_processor_shell.exe"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/fbed4ffaccc0e754779134993ae8212091582aa9/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "99f971ca131f6d11c73f4b918099d434bdd8093c",
@@ -22,7 +22,7 @@
         },
         "linux": {
             "hash": "b4977483ac603343f03adf009a6afb2c93736090",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/791bf363d18201eae5e636ba66d7d8b17472b769/trace_processor_shell"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/fbed4ffaccc0e754779134993ae8212091582aa9/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/perf/core/shard_maps/android-pixel4_webview-perf-pgo_map.json b/tools/perf/core/shard_maps/android-pixel4_webview-perf-pgo_map.json
index 98c4fb4a..a9b3166 100644
--- a/tools/perf/core/shard_maps/android-pixel4_webview-perf-pgo_map.json
+++ b/tools/perf/core/shard_maps/android-pixel4_webview-perf-pgo_map.json
@@ -8,7 +8,7 @@
                 "abridged": false
             },
             "blink_perf.bindings": {
-                "end": 42,
+                "end": 45,
                 "abridged": false
             },
             "speedometer2": {
@@ -22,11 +22,14 @@
     "1": {
         "benchmarks": {
             "blink_perf.bindings": {
-                "begin": 42,
+                "begin": 45,
                 "abridged": false
             },
             "blink_perf.css": {
-                "end": 71,
+                "abridged": false
+            },
+            "blink_perf.dom": {
+                "end": 1,
                 "abridged": false
             },
             "speedometer2": {
@@ -39,11 +42,8 @@
     },
     "2": {
         "benchmarks": {
-            "blink_perf.css": {
-                "begin": 71,
-                "abridged": false
-            },
             "blink_perf.dom": {
+                "begin": 1,
                 "abridged": false
             },
             "blink_perf.events": {
@@ -68,7 +68,7 @@
         "benchmarks": {
             "blink_perf.layout": {
                 "begin": 24,
-                "end": 102,
+                "end": 97,
                 "abridged": false
             },
             "speedometer2": {
@@ -82,7 +82,7 @@
     "4": {
         "benchmarks": {
             "blink_perf.layout": {
-                "begin": 102,
+                "begin": 97,
                 "abridged": false
             },
             "blink_perf.owp_storage": {
@@ -92,7 +92,7 @@
                 "abridged": false
             },
             "blink_perf.shadow_dom": {
-                "end": 23,
+                "end": 29,
                 "abridged": false
             },
             "speedometer2": {
@@ -106,7 +106,7 @@
     "5": {
         "benchmarks": {
             "blink_perf.shadow_dom": {
-                "begin": 23,
+                "begin": 29,
                 "abridged": false
             },
             "blink_perf.webaudio": {
@@ -134,6 +134,7 @@
                 "abridged": false
             },
             "rasterize_and_record_micro.top_25": {
+                "end": 3,
                 "abridged": false
             },
             "speedometer2": {
@@ -142,12 +143,27 @@
             "speedometer3": {
                 "abridged": false
             }
+        },
+        "crossbench": {
+            "loading": {
+                "display_name": "loading.crossbench",
+                "arguments": [
+                    "--wpr=crossbench_android_loading_000.wprgo",
+                    "--probe=chrome_histograms:{\"baseline\":false,\"metrics\":{\"Android.WebView.Startup.CreationTime.StartChromiumLocked\":[\"mean\"]}}",
+                    "--repetitions=50",
+                    "--stories=cnn"
+                ]
+            }
         }
     },
     "6": {
         "benchmarks": {
+            "rasterize_and_record_micro.top_25": {
+                "begin": 3,
+                "abridged": false
+            },
             "rendering.mobile": {
-                "end": 49,
+                "end": 42,
                 "abridged": false
             },
             "speedometer2": {
@@ -161,8 +177,8 @@
     "7": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 49,
-                "end": 98,
+                "begin": 42,
+                "end": 94,
                 "abridged": false
             },
             "speedometer2": {
@@ -176,8 +192,8 @@
     "8": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 98,
-                "end": 148,
+                "begin": 94,
+                "end": 152,
                 "abridged": false
             },
             "speedometer2": {
@@ -191,8 +207,8 @@
     "9": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 148,
-                "end": 198,
+                "begin": 152,
+                "end": 203,
                 "abridged": false
             },
             "speedometer2": {
@@ -206,8 +222,8 @@
     "10": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 198,
-                "end": 258,
+                "begin": 203,
+                "end": 262,
                 "abridged": false
             },
             "speedometer2": {
@@ -221,8 +237,8 @@
     "11": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 258,
-                "end": 318,
+                "begin": 262,
+                "end": 327,
                 "abridged": false
             },
             "speedometer2": {
@@ -236,8 +252,8 @@
     "12": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 318,
-                "end": 373,
+                "begin": 327,
+                "end": 378,
                 "abridged": false
             },
             "speedometer2": {
@@ -251,7 +267,7 @@
     "13": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 373,
+                "begin": 378,
                 "abridged": false
             },
             "rendering.mobile.notracing": {
@@ -279,7 +295,7 @@
                 "abridged": false
             },
             "system_health.common_mobile": {
-                "end": 19,
+                "end": 23,
                 "abridged": false
             }
         }
@@ -287,11 +303,11 @@
     "14": {
         "benchmarks": {
             "system_health.common_mobile": {
-                "begin": 19,
+                "begin": 23,
                 "abridged": false
             },
             "system_health.memory_mobile": {
-                "end": 2,
+                "end": 3,
                 "abridged": false
             },
             "speedometer2": {
@@ -305,8 +321,8 @@
     "15": {
         "benchmarks": {
             "system_health.memory_mobile": {
-                "begin": 2,
-                "end": 23,
+                "begin": 3,
+                "end": 24,
                 "abridged": false
             },
             "speedometer2": {
@@ -320,8 +336,8 @@
     "16": {
         "benchmarks": {
             "system_health.memory_mobile": {
-                "begin": 23,
-                "end": 43,
+                "begin": 24,
+                "end": 42,
                 "abridged": false
             },
             "speedometer2": {
@@ -335,8 +351,8 @@
     "17": {
         "benchmarks": {
             "system_health.memory_mobile": {
-                "begin": 43,
-                "end": 62,
+                "begin": 42,
+                "end": 60,
                 "abridged": false
             },
             "speedometer2": {
@@ -350,10 +366,7 @@
     "18": {
         "benchmarks": {
             "system_health.memory_mobile": {
-                "begin": 62,
-                "abridged": false
-            },
-            "system_health.webview_startup": {
+                "begin": 60,
                 "abridged": false
             },
             "speedometer2": {
@@ -366,6 +379,9 @@
     },
     "19": {
         "benchmarks": {
+            "system_health.webview_startup": {
+                "abridged": false
+            },
             "v8.browsing_mobile": {
                 "abridged": false
             },
@@ -384,30 +400,30 @@
         }
     },
     "extra_infos": {
-        "num_stories": 1112,
-        "predicted_min_shard_time": 2668.0,
-        "predicted_min_shard_index": 19,
-        "predicted_max_shard_time": 3149.0,
-        "predicted_max_shard_index": 18,
-        "shard #0": 2912.0,
-        "shard #1": 2904.0,
-        "shard #2": 2916.0,
-        "shard #3": 2897.0,
-        "shard #4": 2894.0,
-        "shard #5": 2906.0,
-        "shard #6": 2883.0,
-        "shard #7": 2913.0,
-        "shard #8": 2900.0,
-        "shard #9": 2893.0,
-        "shard #10": 2913.0,
-        "shard #11": 2881.0,
-        "shard #12": 2927.0,
-        "shard #13": 2919.0,
-        "shard #14": 2889.0,
-        "shard #15": 2834.0,
-        "shard #16": 2966.0,
-        "shard #17": 2918.0,
-        "shard #18": 3149.0,
-        "shard #19": 2668.0
+        "num_stories": 1114,
+        "predicted_min_shard_time": 2448.0,
+        "predicted_min_shard_index": 18,
+        "predicted_max_shard_time": 3660.0,
+        "predicted_max_shard_index": 19,
+        "shard #0": 3012.0,
+        "shard #1": 3029.0,
+        "shard #2": 3026.0,
+        "shard #3": 3030.0,
+        "shard #4": 3019.0,
+        "shard #5": 3001.0,
+        "shard #6": 3008.0,
+        "shard #7": 3018.0,
+        "shard #8": 3033.0,
+        "shard #9": 2980.0,
+        "shard #10": 3026.0,
+        "shard #11": 3006.0,
+        "shard #12": 3022.0,
+        "shard #13": 3036.0,
+        "shard #14": 2984.0,
+        "shard #15": 2970.0,
+        "shard #16": 2970.0,
+        "shard #17": 2991.0,
+        "shard #18": 2448.0,
+        "shard #19": 3660.0
     }
 }
diff --git a/tools/perf/core/shard_maps/android-pixel4_webview-perf_map.json b/tools/perf/core/shard_maps/android-pixel4_webview-perf_map.json
index c185bf9..0e5bb071 100644
--- a/tools/perf/core/shard_maps/android-pixel4_webview-perf_map.json
+++ b/tools/perf/core/shard_maps/android-pixel4_webview-perf_map.json
@@ -8,7 +8,7 @@
                 "abridged": false
             },
             "blink_perf.bindings": {
-                "end": 18,
+                "end": 41,
                 "abridged": false
             },
             "speedometer2": {
@@ -22,11 +22,11 @@
     "1": {
         "benchmarks": {
             "blink_perf.bindings": {
-                "begin": 18,
+                "begin": 41,
                 "abridged": false
             },
             "blink_perf.css": {
-                "end": 32,
+                "end": 61,
                 "abridged": false
             },
             "speedometer2": {
@@ -40,11 +40,17 @@
     "2": {
         "benchmarks": {
             "blink_perf.css": {
-                "begin": 32,
+                "begin": 61,
                 "abridged": false
             },
             "blink_perf.dom": {
-                "end": 11,
+                "abridged": false
+            },
+            "blink_perf.events": {
+                "abridged": false
+            },
+            "blink_perf.image_decoder": {
+                "end": 4,
                 "abridged": false
             },
             "speedometer2": {
@@ -57,18 +63,12 @@
     },
     "3": {
         "benchmarks": {
-            "blink_perf.dom": {
-                "begin": 11,
-                "abridged": false
-            },
-            "blink_perf.events": {
-                "abridged": false
-            },
             "blink_perf.image_decoder": {
+                "begin": 4,
                 "abridged": false
             },
             "blink_perf.layout": {
-                "end": 25,
+                "end": 59,
                 "abridged": false
             },
             "speedometer2": {
@@ -82,8 +82,11 @@
     "4": {
         "benchmarks": {
             "blink_perf.layout": {
-                "begin": 25,
-                "end": 101,
+                "begin": 59,
+                "abridged": false
+            },
+            "blink_perf.owp_storage": {
+                "end": 4,
                 "abridged": false
             },
             "speedometer2": {
@@ -96,18 +99,15 @@
     },
     "5": {
         "benchmarks": {
-            "blink_perf.layout": {
-                "begin": 101,
-                "abridged": false
-            },
             "blink_perf.owp_storage": {
+                "begin": 4,
                 "abridged": false
             },
             "blink_perf.parser": {
                 "abridged": false
             },
             "blink_perf.shadow_dom": {
-                "end": 29,
+                "end": 31,
                 "abridged": false
             },
             "speedometer2": {
@@ -121,7 +121,7 @@
     "6": {
         "benchmarks": {
             "blink_perf.shadow_dom": {
-                "begin": 29,
+                "begin": 31,
                 "abridged": false
             },
             "blink_perf.webaudio": {
@@ -142,6 +142,27 @@
             "dummy_benchmark.stable_benchmark_1": {
                 "abridged": false
             },
+            "speedometer2": {
+                "abridged": false
+            },
+            "speedometer3": {
+                "abridged": false
+            }
+        },
+        "crossbench": {
+            "loading": {
+                "display_name": "loading.crossbench",
+                "arguments": [
+                    "--wpr=crossbench_android_loading_000.wprgo",
+                    "--probe=chrome_histograms:{\"baseline\":false,\"metrics\":{\"Android.WebView.Startup.CreationTime.StartChromiumLocked\":[\"mean\"]}}",
+                    "--repetitions=50",
+                    "--stories=cnn"
+                ]
+            }
+        }
+    },
+    "7": {
+        "benchmarks": {
             "media.mobile": {
                 "abridged": false
             },
@@ -152,22 +173,7 @@
                 "abridged": false
             },
             "rendering.mobile": {
-                "end": 1,
-                "abridged": false
-            },
-            "speedometer2": {
-                "abridged": false
-            },
-            "speedometer3": {
-                "abridged": false
-            }
-        }
-    },
-    "7": {
-        "benchmarks": {
-            "rendering.mobile": {
-                "begin": 1,
-                "end": 57,
+                "end": 22,
                 "abridged": false
             },
             "speedometer2": {
@@ -181,8 +187,8 @@
     "8": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 57,
-                "end": 113,
+                "begin": 22,
+                "end": 67,
                 "abridged": false
             },
             "speedometer2": {
@@ -196,8 +202,8 @@
     "9": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 113,
-                "end": 159,
+                "begin": 67,
+                "end": 110,
                 "abridged": false
             },
             "speedometer2": {
@@ -211,8 +217,8 @@
     "10": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 159,
-                "end": 199,
+                "begin": 110,
+                "end": 160,
                 "abridged": false
             },
             "speedometer2": {
@@ -226,8 +232,8 @@
     "11": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 199,
-                "end": 249,
+                "begin": 160,
+                "end": 204,
                 "abridged": false
             },
             "speedometer2": {
@@ -241,8 +247,8 @@
     "12": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 249,
-                "end": 319,
+                "begin": 204,
+                "end": 265,
                 "abridged": false
             },
             "speedometer2": {
@@ -256,8 +262,8 @@
     "13": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 319,
-                "end": 356,
+                "begin": 265,
+                "end": 328,
                 "abridged": false
             },
             "speedometer2": {
@@ -271,13 +277,8 @@
     "14": {
         "benchmarks": {
             "rendering.mobile": {
-                "begin": 356,
-                "abridged": false
-            },
-            "rendering.mobile.notracing": {
-                "abridged": false
-            },
-            "speedometer": {
+                "begin": 328,
+                "end": 381,
                 "abridged": false
             },
             "speedometer2": {
@@ -290,6 +291,16 @@
     },
     "15": {
         "benchmarks": {
+            "rendering.mobile": {
+                "begin": 381,
+                "abridged": false
+            },
+            "rendering.mobile.notracing": {
+                "abridged": false
+            },
+            "speedometer": {
+                "abridged": false
+            },
             "speedometer-future": {
                 "abridged": false
             },
@@ -309,7 +320,7 @@
                 "abridged": false
             },
             "system_health.common_mobile": {
-                "end": 38,
+                "end": 19,
                 "abridged": false
             }
         }
@@ -317,11 +328,7 @@
     "16": {
         "benchmarks": {
             "system_health.common_mobile": {
-                "begin": 38,
-                "abridged": false
-            },
-            "system_health.memory_mobile": {
-                "end": 5,
+                "begin": 19,
                 "abridged": false
             },
             "speedometer2": {
@@ -335,8 +342,7 @@
     "17": {
         "benchmarks": {
             "system_health.memory_mobile": {
-                "begin": 5,
-                "end": 23,
+                "end": 19,
                 "abridged": false
             },
             "speedometer2": {
@@ -350,8 +356,8 @@
     "18": {
         "benchmarks": {
             "system_health.memory_mobile": {
-                "begin": 23,
-                "end": 37,
+                "begin": 19,
+                "end": 29,
                 "abridged": false
             },
             "speedometer2": {
@@ -365,8 +371,8 @@
     "19": {
         "benchmarks": {
             "system_health.memory_mobile": {
-                "begin": 37,
-                "end": 55,
+                "begin": 29,
+                "end": 47,
                 "abridged": false
             },
             "speedometer2": {
@@ -380,8 +386,8 @@
     "20": {
         "benchmarks": {
             "system_health.memory_mobile": {
-                "begin": 55,
-                "end": 72,
+                "begin": 47,
+                "end": 66,
                 "abridged": false
             }
         }
@@ -389,22 +395,17 @@
     "21": {
         "benchmarks": {
             "system_health.memory_mobile": {
-                "begin": 72,
+                "begin": 66,
                 "abridged": false
             },
             "system_health.webview_startup": {
                 "abridged": false
-            },
-            "v8.browsing_mobile": {
-                "end": 6,
-                "abridged": false
             }
         }
     },
     "22": {
         "benchmarks": {
             "v8.browsing_mobile": {
-                "begin": 6,
                 "abridged": false
             },
             "wasmpspdfkit": {
@@ -416,33 +417,33 @@
         }
     },
     "extra_infos": {
-        "num_stories": 1112,
-        "predicted_min_shard_time": 2024.0,
-        "predicted_min_shard_index": 21,
-        "predicted_max_shard_time": 2204.0,
-        "predicted_max_shard_index": 17,
-        "shard #0": 2108.0,
-        "shard #1": 2113.0,
-        "shard #2": 2122.0,
-        "shard #3": 2103.0,
-        "shard #4": 2114.0,
-        "shard #5": 2105.0,
-        "shard #6": 2105.0,
-        "shard #7": 2095.0,
-        "shard #8": 2125.0,
-        "shard #9": 2087.0,
-        "shard #10": 2114.0,
-        "shard #11": 2103.0,
-        "shard #12": 2109.0,
-        "shard #13": 2091.0,
-        "shard #14": 2114.0,
-        "shard #15": 2098.0,
-        "shard #16": 2129.0,
-        "shard #17": 2204.0,
-        "shard #18": 2099.0,
-        "shard #19": 2126.0,
-        "shard #20": 2154.0,
-        "shard #21": 2024.0,
-        "shard #22": 2083.0
+        "num_stories": 1114,
+        "predicted_min_shard_time": 1860.0,
+        "predicted_min_shard_index": 22,
+        "predicted_max_shard_time": 2460.0,
+        "predicted_max_shard_index": 21,
+        "shard #0": 2147.0,
+        "shard #1": 2145.0,
+        "shard #2": 2147.0,
+        "shard #3": 2144.0,
+        "shard #4": 2156.0,
+        "shard #5": 2138.0,
+        "shard #6": 2335.0,
+        "shard #7": 2105.0,
+        "shard #8": 2138.0,
+        "shard #9": 2147.0,
+        "shard #10": 2125.0,
+        "shard #11": 2130.0,
+        "shard #12": 2129.0,
+        "shard #13": 2134.0,
+        "shard #14": 2125.0,
+        "shard #15": 2141.0,
+        "shard #16": 2099.0,
+        "shard #17": 2152.0,
+        "shard #18": 2128.0,
+        "shard #19": 2116.0,
+        "shard #20": 2088.0,
+        "shard #21": 2460.0,
+        "shard #22": 1860.0
     }
 }
diff --git a/ui/base/interaction/interactive_test_definitions.h b/ui/base/interaction/interactive_test_definitions.h
index 27397b6..bfe64031 100644
--- a/ui/base/interaction/interactive_test_definitions.h
+++ b/ui/base/interaction/interactive_test_definitions.h
@@ -148,7 +148,7 @@
 
 // Checks that `T` is a reference wrapper around any type.
 template <typename T>
-concept IsReferenceWrapper = base::is_instantiation<std::reference_wrapper, T>;
+concept IsReferenceWrapper = base::is_instantiation<T, std::reference_wrapper>;
 
 // Helper to determine the type used to match a value. The default is to just
 // use the decayed value type.
@@ -197,7 +197,7 @@
 
 template <typename T>
 concept IsMatcher = IsGtestMatcher<T> || HasMatchAndExplain<T> ||
-                    base::is_instantiation<testing::PolymorphicMatcher, T>;
+                    base::is_instantiation<T, testing::PolymorphicMatcher>;
 
 // Accepts any function-like object that is compatible with
 // `InteractionSequence::StepCallback`.
diff --git a/v8 b/v8
index 32b330a..41aacdd 160000
--- a/v8
+++ b/v8
@@ -1 +1 @@
-Subproject commit 32b330ac8c50d47938a879343e450bd8bd8cd2e0
+Subproject commit 41aacdda71ed37cbaf84d7c138a0be8297d2fb85