diff --git a/DEPS b/DEPS
index 1280cad..0dbce8a2 100644
--- a/DEPS
+++ b/DEPS
@@ -273,7 +273,7 @@
   'screen_ai_windows_386': 'version:138.04',
 
   # siso CIPD package version.
-  'siso_version': 'git_revision:d704490133011610c402696584afedea80829dbd',
+  'siso_version': 'git_revision:7e7d85fc69f9084d2168385fb504b31e830dbfff',
 
   # download libaom test data
   'download_libaom_testdata': False,
@@ -303,7 +303,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.
-  'v8_revision': '77f35f055a1543f51099fcea9575f83304d60de5',
+  'v8_revision': 'ad9041e4d0f760e0c1c87d79a60b9ff1d2c77f96',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
@@ -375,7 +375,7 @@
   # 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': '885aeee863e05189c83fadb0c302d07518eb5500',
+  'crossbench_revision': '1de2eca3495784b797d977b40b7291a4a7cd06c1',
   # 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': 'fd0c28cbf06b695f677c525b6630f9f9e4a90eee',
+  'devtools_frontend_revision': '7ad25e25037043f7a75e7a838a651c110b918d48',
   # 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,7 +415,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '9fd4a731474f66c1ce5465f9b13919ad7487315d',
+  'dawn_revision': 'fd276573ab859ea73c18581c018a773e4e3b8902',
   # 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' + '@' +
-    '2dbc9aa95eddeb69a73546f3076874c682375331',
+    'e4201862b5cd95321ccc5abba80f47a502829743',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1680,7 +1680,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': '6X6Qqncm8SLOmqyM63uBJWfHB7X5An8CrBJbRmoOIG8C',
+          'version': 'Y-CbCN6v5_4a_FprX22MQBJmya6JbjaSA-BUTEYbBdoC',
       },
     ],
     'condition': 'checkout_android and non_git_source',
@@ -2878,16 +2878,16 @@
       'dep_type': 'cipd',
   },
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@9a8d0205ed06a556ff17d4097afc218c993ec260',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@3395378f6990e79066b5f1647f6f8ac5de07e26d',
   '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',
-  'src/third_party/spirv-tools/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Tools@e0bad2825dacf274578ec6d3c0e64e406d5e4fd7',
+  'src/third_party/spirv-tools/src': '{chromium_git}/external/github.com/KhronosGroup/SPIRV-Tools@dec28643ed15f68a2bc95650de25e0a7486b564c',
   'src/third_party/vulkan-headers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Headers@b39ab380a44b6c8df462c34e976ea9ce2d2c336b',
   'src/third_party/vulkan-loader/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Loader@22c0f133e6675f9313c12fb5e58337f8fa9b9195',
   'src/third_party/vulkan-tools/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Tools@d671923090e4dc74c0ebdb10c6e09fa0826e1fe9',
   'src/third_party/vulkan-utility-libraries/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-Utility-Libraries@54c9baf20802a13279e23fa4cb0528dd5cf16064',
-  'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@ce9b7e404fe1a312ff4c07961dc6f8a2fd925d44',
+  'src/third_party/vulkan-validation-layers/src': '{chromium_git}/external/github.com/KhronosGroup/Vulkan-ValidationLayers@3fa19fccc75171a6b607f95510c37739c606b809',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '56300b29fbfcc693ee6609ddad3fdd5b7a449a21',
@@ -2932,7 +2932,7 @@
     Var('chromium_git') + '/webpagereplay.git' + '@' + Var('webpagereplay_revision'),
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '74932424d457e2ad5e70c914b3cdd55bec759d6a',
+    Var('webrtc_git') + '/src.git' + '@' + '4c619d7b0f2020e1b54fc62aaafc24fc34af78f8',
 
   # Wuffs' canonical repository is at github.com/google/wuffs, but we use
   # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file.
@@ -4718,7 +4718,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        '59a93a5717e2d1a9e523d986e012bde44aa5faa2',
+        '3b581c6c47e23717766c2c1922d6c7111db6cb4c',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/WATCHLISTS b/WATCHLISTS
index 1aac9ba..6a2ad93 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -1075,6 +1075,12 @@
     'dbus': {
       'filepath': 'dbus/',
     },
+    'desktop_composebox': {
+      'filepath': '^chrome/browser/resources/new_tab_page/composebox/|'\
+                  '^chrome/browser/ui/webui/new_tab_page/composebox/|'\
+                  '^chrome/test/data/webui/new_tab_page/composebox/|'\
+                  '^components/omnibox/composebox/',
+    },
     'desktop_in_product_help': {
       'filepath': 'components/feature_engagement/|'\
                   'components/user_education/|'\
@@ -1086,6 +1092,23 @@
                   'chrome/browser/ui/webui/user_education_internals/|'\
                   'chrome/browser/ui/webui/whats_new/',
     },
+    'desktop_omnibox': {
+      'filepath': '^chrome/browser/ash/app_list/search/omnibox/|'\
+                  '^chrome/browser/autocomplete/|'\
+                  '^chrome/browser/resources/omnibox|'\
+                  '^chrome/browser/ui/location_bar/|'\
+                  '^chrome/browser/ui/omnibox/|'\
+                  '^chrome/browser/ui/views/location_bar/|'\
+                  '^chrome/browser/ui/views/omnibox/|'\
+                  '^chrome/browser/ui/webui/omnibox/|'\
+                  '^components/omnibox/|'\
+                  '^components/search_engines/'
+    },
+    'desktop_searchbox': {
+      'filepath': '^chrome/browser/ui/webui/searchbox/|'\
+                  '^chrome/test/data/webui/cr_components/searchbox/|'\
+                  '^ui/webui/resources/cr_components/searchbox/',
+    },
     'desktop_whats_new': {
       'filepath': 'chrome/browser/resources/whats_new/|'\
                   'chrome/browser/ui/webui/whats_new/',
@@ -1758,21 +1781,6 @@
                   '|chrome/browser/android/offline_pages/'\
                   '|chrome/android/java/src/org/chromium/chrome/browser/offlinepages/'
     },
-    'omnibox_desktop': {
-      'filepath': '^chrome/browser/ash/app_list/search/omnibox/|'\
-                  '^chrome/browser/autocomplete/|'\
-                  '^chrome/browser/resources/new_tab_page/realbox/|'\
-                  '^chrome/browser/resources/omnibox|'\
-                  '^chrome/browser/ui/location_bar/|'\
-                  '^chrome/browser/ui/omnibox/|'\
-                  '^chrome/browser/ui/views/location_bar/|'\
-                  '^chrome/browser/ui/views/omnibox/|'\
-                  '^chrome/browser/ui/webui/omnibox/|'\
-                  '^chrome/browser/ui/webui/realbox/|'\
-                  '^chrome/test/data/webui/new_tab_page/realbox/|'\
-                  '^components/omnibox/|'\
-                  '^components/search_engines/'
-    },
     'omnibox_ios': {
       'filepath': '^components/omnibox/|'\
                   '^components/search_engines/|'\
@@ -2915,8 +2923,12 @@
                    'pnevase@microsoft.com'],
     'data_decoder': ['mbarowsky+watch-data-decoder@chromium.org'],
     'dbus': ['hashimoto+watch@chromium.org'],
+    'desktop_composebox': ['omnibox-dev+watch@chromium.org'],
     'desktop_in_product_help': ['dfried+watch@chromium.org',
-                                'estalin+watch@chromium.org'],
+      'estalin+watch@chromium.org'],
+    'desktop_omnibox': ['jdonnelly+watch@chromium.org',
+                        'omnibox-dev+watch@chromium.org'],
+    'desktop_searchbox': ['omnibox-dev+watch@chromium.org'],
     'desktop_whats_new': ['mickeyburks+watch@chromium.org'],
     'device_bluetooth': ['mattreynolds+watch@chromium.org'],
     'device_bound_sessions': ['drubery+watch@chromium.org'],
@@ -3146,8 +3158,6 @@
     'offline_pages': ['chili+watch@chromium.org',
                       'dimich+watch@chromium.org',
                       'fgorski+watch@chromium.org'],
-    'omnibox_desktop': ['jdonnelly+watch@chromium.org',
-                        'mahmadi+watch@chromium.org'],
     'omnibox_ios': ['christianxu+watch@chromium.org'],
     'origin_trials': ['chasej+watch@chromium.org',
                       'iclelland+watch@chromium.org'],
diff --git a/build/config/ios/ios_sdk.gni b/build/config/ios/ios_sdk.gni
index 9a0ea63d..cab82e04 100644
--- a/build/config/ios/ios_sdk.gni
+++ b/build/config/ios/ios_sdk.gni
@@ -32,6 +32,10 @@
 
   # Set to true if building an app extension.
   ios_is_app_extension = false
+
+  # Set to `target_platform` to generate Xcode project with the
+  # corresponding platform SDK.
+  target_xcode_platform = target_platform
 }
 
 # Building XCTests requires copying XCTRunner.app which is part of the iOS
diff --git a/cc/tiles/picture_layer_tiling_set_unittest.cc b/cc/tiles/picture_layer_tiling_set_unittest.cc
index 71e0b9d6..af0e5adc 100644
--- a/cc/tiles/picture_layer_tiling_set_unittest.cc
+++ b/cc/tiles/picture_layer_tiling_set_unittest.cc
@@ -66,44 +66,10 @@
   PictureLayerTilingSet::TilingRange low_res_range(0, 0);
   PictureLayerTilingSet::TilingRange lower_than_low_res_range(0, 0);
   PictureLayerTiling* high_res_tiling;
-  PictureLayerTiling* low_res_tiling;
 
   scoped_refptr<FakeRasterSource> raster_source =
       FakeRasterSource::CreateFilled(layer_bounds);
 
-  std::unique_ptr<TestablePictureLayerTilingSet> set = CreateTilingSet(&client);
-  set->AddTiling(gfx::AxisTransform2d(2.0, gfx::Vector2dF()), raster_source);
-  high_res_tiling = set->AddTiling(gfx::AxisTransform2d(), raster_source);
-  high_res_tiling->set_resolution(HIGH_RESOLUTION);
-  set->AddTiling(gfx::AxisTransform2d(0.5, gfx::Vector2dF()), raster_source);
-  low_res_tiling = set->AddTiling(gfx::AxisTransform2d(0.25, gfx::Vector2dF()),
-                                  raster_source);
-  low_res_tiling->set_resolution(LOW_RESOLUTION);
-  set->AddTiling(gfx::AxisTransform2d(0.125, gfx::Vector2dF()), raster_source);
-
-  higher_than_high_res_range =
-      set->GetTilingRange(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
-  EXPECT_EQ(0u, higher_than_high_res_range.start);
-  EXPECT_EQ(1u, higher_than_high_res_range.end);
-
-  high_res_range = set->GetTilingRange(PictureLayerTilingSet::HIGH_RES);
-  EXPECT_EQ(1u, high_res_range.start);
-  EXPECT_EQ(2u, high_res_range.end);
-
-  between_high_and_low_res_range =
-      set->GetTilingRange(PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
-  EXPECT_EQ(2u, between_high_and_low_res_range.start);
-  EXPECT_EQ(3u, between_high_and_low_res_range.end);
-
-  low_res_range = set->GetTilingRange(PictureLayerTilingSet::LOW_RES);
-  EXPECT_EQ(3u, low_res_range.start);
-  EXPECT_EQ(4u, low_res_range.end);
-
-  lower_than_low_res_range =
-      set->GetTilingRange(PictureLayerTilingSet::LOWER_THAN_LOW_RES);
-  EXPECT_EQ(4u, lower_than_low_res_range.start);
-  EXPECT_EQ(5u, lower_than_low_res_range.end);
-
   std::unique_ptr<TestablePictureLayerTilingSet> set_without_low_res =
       CreateTilingSet(&client);
   set_without_low_res->AddTiling(gfx::AxisTransform2d(2.0, gfx::Vector2dF()),
@@ -139,40 +105,6 @@
       PictureLayerTilingSet::LOWER_THAN_LOW_RES);
   EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start);
 
-  std::unique_ptr<TestablePictureLayerTilingSet>
-      set_with_only_high_and_low_res = CreateTilingSet(&client);
-  high_res_tiling = set_with_only_high_and_low_res->AddTiling(
-      gfx::AxisTransform2d(), raster_source);
-  high_res_tiling->set_resolution(HIGH_RESOLUTION);
-  low_res_tiling = set_with_only_high_and_low_res->AddTiling(
-      gfx::AxisTransform2d(0.5, gfx::Vector2dF()), raster_source);
-  low_res_tiling->set_resolution(LOW_RESOLUTION);
-
-  higher_than_high_res_range = set_with_only_high_and_low_res->GetTilingRange(
-      PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
-  EXPECT_EQ(0u,
-            higher_than_high_res_range.end - higher_than_high_res_range.start);
-
-  high_res_range = set_with_only_high_and_low_res->GetTilingRange(
-      PictureLayerTilingSet::HIGH_RES);
-  EXPECT_EQ(0u, high_res_range.start);
-  EXPECT_EQ(1u, high_res_range.end);
-
-  between_high_and_low_res_range =
-      set_with_only_high_and_low_res->GetTilingRange(
-          PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
-  EXPECT_EQ(0u, between_high_and_low_res_range.end -
-                    between_high_and_low_res_range.start);
-
-  low_res_range = set_with_only_high_and_low_res->GetTilingRange(
-      PictureLayerTilingSet::LOW_RES);
-  EXPECT_EQ(1u, low_res_range.start);
-  EXPECT_EQ(2u, low_res_range.end);
-
-  lower_than_low_res_range = set_with_only_high_and_low_res->GetTilingRange(
-      PictureLayerTilingSet::LOWER_THAN_LOW_RES);
-  EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start);
-
   std::unique_ptr<TestablePictureLayerTilingSet> set_with_only_high_res =
       CreateTilingSet(&client);
   high_res_tiling =
diff --git a/cc/tiles/tile_manager_unittest.cc b/cc/tiles/tile_manager_unittest.cc
index 03f399e..c46677ea 100644
--- a/cc/tiles/tile_manager_unittest.cc
+++ b/cc/tiles/tile_manager_unittest.cc
@@ -585,81 +585,6 @@
   EXPECT_EQ(all_expected_tiles, all_actual_tiles);
 }
 
-TEST_F(TileManagerTilePriorityQueueTest,
-       RasterTilePriorityQueueHighLowTilings) {
-  const gfx::Size layer_bounds(1000, 1000);
-  const gfx::Size viewport(800, 800);
-  host_impl()->active_tree()->SetDeviceViewportRect(gfx::Rect(viewport));
-  SetupDefaultTrees(layer_bounds);
-
-  pending_layer()->tilings()->AddTiling(
-      gfx::AxisTransform2d(1.5f, gfx::Vector2dF()),
-      pending_layer()->raster_source());
-  active_layer()->tilings()->AddTiling(
-      gfx::AxisTransform2d(1.5f, gfx::Vector2dF()),
-      active_layer()->raster_source());
-  pending_layer()->tilings()->AddTiling(
-      gfx::AxisTransform2d(1.7f, gfx::Vector2dF()),
-      pending_layer()->raster_source());
-  active_layer()->tilings()->AddTiling(
-      gfx::AxisTransform2d(1.7f, gfx::Vector2dF()),
-      active_layer()->raster_source());
-
-  pending_layer()->tilings()->UpdateTilePriorities(gfx::Rect(viewport), 1.f,
-                                                   5.0, Occlusion(), true);
-  active_layer()->tilings()->UpdateTilePriorities(gfx::Rect(viewport), 1.f, 5.0,
-                                                  Occlusion(), true);
-
-  std::set<Tile*> all_expected_tiles;
-  for (size_t i = 0; i < pending_layer()->num_tilings(); ++i) {
-    PictureLayerTiling* tiling = pending_layer()->tilings()->tiling_at(i);
-    if (tiling->contents_scale_key() == 1.f) {
-      tiling->set_resolution(HIGH_RESOLUTION);
-      const auto& all_tiles = tiling->AllTilesForTesting();
-      all_expected_tiles.insert(all_tiles.begin(), all_tiles.end());
-    } else {
-      tiling->set_resolution(NON_IDEAL_RESOLUTION);
-    }
-  }
-
-  for (size_t i = 0; i < active_layer()->num_tilings(); ++i) {
-    PictureLayerTiling* tiling = active_layer()->tilings()->tiling_at(i);
-    if (tiling->contents_scale_key() == 1.5f) {
-      tiling->set_resolution(HIGH_RESOLUTION);
-      const auto& all_tiles = tiling->AllTilesForTesting();
-      all_expected_tiles.insert(all_tiles.begin(), all_tiles.end());
-    } else {
-      tiling->set_resolution(LOW_RESOLUTION);
-      // Low res tilings with a high res pending twin have to be processed
-      // because of possible activation tiles.
-      if (tiling->contents_scale_key() == 1.f) {
-        tiling->UpdateAndGetAllPrioritizedTilesForTesting();
-        const auto& all_tiles = tiling->AllTilesForTesting();
-        for (auto* tile : all_tiles)
-          EXPECT_TRUE(tile->required_for_activation());
-        all_expected_tiles.insert(all_tiles.begin(), all_tiles.end());
-      }
-    }
-  }
-
-  std::unique_ptr<RasterTilePriorityQueue> queue(host_impl()->BuildRasterQueue(
-      SAME_PRIORITY_FOR_BOTH_TREES, RasterTilePriorityQueue::Type::ALL));
-  EXPECT_FALSE(queue->IsEmpty());
-
-  size_t tile_count = 0;
-  std::set<Tile*> all_actual_tiles;
-  while (!queue->IsEmpty()) {
-    EXPECT_TRUE(queue->Top().tile());
-    all_actual_tiles.insert(queue->Top().tile());
-    ++tile_count;
-    queue->Pop();
-  }
-
-  EXPECT_EQ(tile_count, all_actual_tiles.size());
-  EXPECT_EQ(all_expected_tiles.size(), all_actual_tiles.size());
-  EXPECT_EQ(all_expected_tiles, all_actual_tiles);
-}
-
 TEST_F(TileManagerTilePriorityQueueTest, RasterTilePriorityQueueInvalidation) {
   const gfx::Size layer_bounds(1000, 1000);
   host_impl()->active_tree()->SetDeviceViewportRect(gfx::Rect(500, 500));
@@ -2090,89 +2015,74 @@
   TestSoftwareRasterBufferProvider raster_buffer_provider_;
 };
 
-TEST_F(PixelInspectTileManagerTest, LowResHasNoImage) {
+TEST_F(PixelInspectTileManagerTest, ImageDrawn) {
   gfx::Size size(10, 12);
-  auto resolutions =
-      std::to_array<TileResolution>({HIGH_RESOLUTION, LOW_RESOLUTION});
   host_impl()->CreatePendingTree();
 
-  for (size_t i = 0; i < std::size(resolutions); ++i) {
-    SCOPED_TRACE(resolutions[i]);
+  SCOPED_TRACE(HIGH_RESOLUTION);
 
-    // Make a RasterSource that will draw a blue bitmap image.
-    sk_sp<SkSurface> surface = SkSurfaces::Raster(
-        SkImageInfo::MakeN32Premul(size.width(), size.height()));
-    ASSERT_NE(surface, nullptr);
-    surface->getCanvas()->clear(SK_ColorBLUE);
-    sk_sp<SkImage> blue_image = surface->makeImageSnapshot();
+  // Make a RasterSource that will draw a blue bitmap image.
+  sk_sp<SkSurface> surface = SkSurfaces::Raster(
+      SkImageInfo::MakeN32Premul(size.width(), size.height()));
+  ASSERT_NE(surface, nullptr);
+  surface->getCanvas()->clear(SK_ColorBLUE);
+  sk_sp<SkImage> blue_image = surface->makeImageSnapshot();
 
-    FakeRecordingSource recording_source(size);
-    recording_source.SetBackgroundColor(SkColors::kTransparent);
-    recording_source.SetRequiresClear(true);
-    PaintFlags flags;
-    flags.setColor(SK_ColorGREEN);
-    recording_source.add_draw_rect_with_flags(gfx::Rect(size), flags);
-    recording_source.add_draw_image(std::move(blue_image), gfx::Point());
-    recording_source.Rerecord();
-    scoped_refptr<RasterSource> raster = recording_source.CreateRasterSource();
+  FakeRecordingSource recording_source(size);
+  recording_source.SetBackgroundColor(SkColors::kTransparent);
+  recording_source.SetRequiresClear(true);
+  PaintFlags flags;
+  flags.setColor(SK_ColorGREEN);
+  recording_source.add_draw_rect_with_flags(gfx::Rect(size), flags);
+  recording_source.add_draw_image(std::move(blue_image), gfx::Point());
+  recording_source.Rerecord();
+  scoped_refptr<RasterSource> raster = recording_source.CreateRasterSource();
 
-    std::unique_ptr<PictureLayerImpl> layer =
-        PictureLayerImpl::Create(host_impl()->pending_tree(), 1);
-    layer->SetBounds(size);
-    layer->SetRasterSourceForTesting(raster);
-    PictureLayerTilingSet* tiling_set = layer->picture_layer_tiling_set();
-    layer->set_contributes_to_drawn_render_surface(true);
+  std::unique_ptr<PictureLayerImpl> layer =
+      PictureLayerImpl::Create(host_impl()->pending_tree(), 1);
+  layer->SetBounds(size);
+  layer->SetRasterSourceForTesting(raster);
+  PictureLayerTilingSet* tiling_set = layer->picture_layer_tiling_set();
+  layer->set_contributes_to_drawn_render_surface(true);
 
-    auto* tiling = tiling_set->AddTiling(gfx::AxisTransform2d(), raster);
-    tiling->set_resolution(resolutions[i]);
-    tiling->CreateAllTilesForTesting(gfx::Rect(size));
+  auto* tiling = tiling_set->AddTiling(gfx::AxisTransform2d(), raster);
+  tiling->set_resolution(HIGH_RESOLUTION);
+  tiling->CreateAllTilesForTesting(gfx::Rect(size));
 
-    // SMOOTHNESS_TAKES_PRIORITY ensures that we will actually raster
-    // LOW_RESOLUTION tiles, otherwise they are skipped.
-    host_impl()->SetTreePriority(SMOOTHNESS_TAKES_PRIORITY);
+  // Call PrepareTiles and wait for it to complete.
+  auto* tile_manager = host_impl()->tile_manager();
+  base::RunLoop run_loop;
+  EXPECT_CALL(MockHostImpl(), NotifyAllTileTasksCompleted())
+      .WillOnce(testing::Invoke([&run_loop]() { run_loop.Quit(); }));
+  tile_manager->PrepareTiles(host_impl()->global_tile_state());
+  run_loop.Run();
+  tile_manager->PrepareToDraw();
 
-    // Call PrepareTiles and wait for it to complete.
-    auto* tile_manager = host_impl()->tile_manager();
-    base::RunLoop run_loop;
-    EXPECT_CALL(MockHostImpl(), NotifyAllTileTasksCompleted())
-        .WillOnce(testing::Invoke([&run_loop]() { run_loop.Quit(); }));
-    tile_manager->PrepareTiles(host_impl()->global_tile_state());
-    run_loop.Run();
-    tile_manager->PrepareToDraw();
+  Tile* tile = tiling->TileAt(0, 0);
+  // The tile in the tiling was rastered.
+  EXPECT_EQ(TileDrawInfo::RESOURCE_MODE, tile->draw_info().mode());
+  EXPECT_TRUE(tile->draw_info().IsReadyToDraw());
 
-    Tile* tile = tiling->TileAt(0, 0);
-    // The tile in the tiling was rastered.
-    EXPECT_EQ(TileDrawInfo::RESOURCE_MODE, tile->draw_info().mode());
-    EXPECT_TRUE(tile->draw_info().IsReadyToDraw());
+  gfx::Size resource_size = tile->draw_info().resource_size();
+  SkColorType ct = ToClosestSkColorType(
+      TestSoftwareRasterBufferProvider::kSharedImageFormat);
+  auto info = SkImageInfo::Make(resource_size.width(), resource_size.height(),
+                                ct, kPremul_SkAlphaType);
+  // CreateLayerTreeFrameSink() sets up a software compositing, so the
+  // tile resource will be a bitmap.
+  auto* backing = tile->draw_info().GetResource().backing();
+  SkBitmap bitmap;
+  auto mapping = backing->shared_image()->Map();
+  void* pixels = mapping->GetMemoryForPlane(0).data();
+  bitmap.installPixels(info, pixels, info.minRowBytes());
 
-    gfx::Size resource_size = tile->draw_info().resource_size();
-    SkColorType ct = ToClosestSkColorType(
-        TestSoftwareRasterBufferProvider::kSharedImageFormat);
-    auto info = SkImageInfo::Make(resource_size.width(), resource_size.height(),
-                                  ct, kPremul_SkAlphaType);
-    // CreateLayerTreeFrameSink() sets up a software compositing, so the
-    // tile resource will be a bitmap.
-    auto* backing = tile->draw_info().GetResource().backing();
-    SkBitmap bitmap;
-    auto mapping = backing->shared_image()->Map();
-    void* pixels = mapping->GetMemoryForPlane(0).data();
-    bitmap.installPixels(info, pixels, info.minRowBytes());
-
-    for (int x = 0; x < size.width(); ++x) {
-      for (int y = 0; y < size.height(); ++y) {
-        SCOPED_TRACE(y);
-        SCOPED_TRACE(x);
-        if (resolutions[i] == LOW_RESOLUTION) {
-          // Since it's low res, the bitmap was not drawn, and the background
-          // (green) is visible instead.
-          ASSERT_EQ(SK_ColorGREEN, bitmap.getColor(x, y));
-        } else {
-          EXPECT_EQ(HIGH_RESOLUTION, resolutions[i]);
-          // Since it's high res, the bitmap (blue) was drawn, and the
-          // background is not visible.
-          ASSERT_EQ(SK_ColorBLUE, bitmap.getColor(x, y));
-        }
-      }
+  for (int x = 0; x < size.width(); ++x) {
+    for (int y = 0; y < size.height(); ++y) {
+      SCOPED_TRACE(y);
+      SCOPED_TRACE(x);
+      // Since it's high res, the bitmap (blue) was drawn, and the
+      // background is not visible.
+      ASSERT_EQ(SK_ColorBLUE, bitmap.getColor(x, y));
     }
   }
 }
diff --git a/chrome/VERSION b/chrome/VERSION
index c175bdd..b3f28095 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=139
 MINOR=0
-BUILD=7242
+BUILD=7243
 PATCH=0
diff --git a/chrome/android/java/res/values/ids.xml b/chrome/android/java/res/values/ids.xml
index 3ef2ccf..5b98898 100644
--- a/chrome/android/java/res/values/ids.xml
+++ b/chrome/android/java/res/values/ids.xml
@@ -141,6 +141,7 @@
     <item type="id" name="downloads_menu_id" />
     <item type="id" name="all_bookmarks_menu_id" />
     <item type="id" name="recent_tabs_menu_id" />
+    <item type="id" name="extensions_menu_id" />
     <item type="id" name="page_zoom_id" />
     <item type="id" name="share_menu_id" />
     <item type="id" name="direct_share_menu_id" />
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 8a00493..768ffca9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -3397,6 +3397,17 @@
                 NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_RECENT_TABS_MANAGER);
             }
             RecordUserAction.record("MobileMenuRecentTabs");
+        } else if (id == R.id.extensions_menu_id) {
+            LoadUrlParams params =
+                    new LoadUrlParams(
+                            UrlConstants.CHROME_EXTENSIONS_URL, PageTransition.AUTO_TOPLEVEL);
+            if (currentTab == null) {
+                getTabCreator(getCurrentTabModel().isIncognito())
+                        .createNewTab(params, TabLaunchType.FROM_CHROME_UI, null);
+            } else {
+                currentTab.loadUrl(params);
+            }
+            RecordUserAction.record("MobileMenuExtensions");
         } else if (id == R.id.close_tab) {
             // TODO(crbug.com/375468032): use triggeringMotion to decide
             // TabClosureParams.allowUndo.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCapturePickerDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCapturePickerDialog.java
index 1b2b429..a6b52cdb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCapturePickerDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCapturePickerDialog.java
@@ -279,10 +279,6 @@
 
         mScreenButton.setOnClickListener(view -> startAndroidCapturePrompt());
 
-        // TODO(crbug.com/352187279): Show button once the entire screen sharing pipeline is
-        // working.
-        mScreenButton.setVisibility(View.GONE);
-
         mModalDialogManager.showDialog(mPropertyModel, ModalDialogManager.ModalDialogType.TAB);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java
index 375746a..84475ae 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java
@@ -57,6 +57,7 @@
 import org.chromium.chrome.browser.ui.appmenu.AppMenuDelegate;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuHandler;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuItemProperties;
+import org.chromium.chrome.browser.ui.extensions.ExtensionsBuildflags;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 import org.chromium.components.browser_ui.accessibility.PageZoomCoordinator;
 import org.chromium.components.dom_distiller.core.DomDistillerFeatures;
@@ -258,6 +259,9 @@
         // Recent Tabs
         if (shouldShowRecentTabsItem()) modelList.add(buildRecentTabsItem());
 
+        // Extensions
+        if (shouldShowExtensionsItem()) modelList.add(buildExtensionsItem());
+
         // Divider
         modelList.add(
                 new MVCListAdapter.ListItem(
@@ -585,6 +589,22 @@
                         shouldShowIconBeforeItem() ? R.drawable.devices_black_24dp : 0));
     }
 
+    private boolean shouldShowExtensionsItem() {
+        return ExtensionsBuildflags.ENABLE_DESKTOP_ANDROID_EXTENSIONS
+                && !ChromeFeatureList.isEnabled(
+                        ChromeFeatureList.BLOCK_INSTALLING_EXTENSIONS_ON_DESKTOP_ANDROID);
+    }
+
+    private MVCListAdapter.ListItem buildExtensionsItem() {
+        assert shouldShowExtensionsItem();
+        return new MVCListAdapter.ListItem(
+                AppMenuHandler.AppMenuItemType.STANDARD,
+                buildModelForStandardMenuItem(
+                        R.id.extensions_menu_id,
+                        R.string.menu_extensions,
+                        shouldShowIconBeforeItem() ? R.drawable.ic_extension_24dp : 0));
+    }
+
     private boolean shouldShowPageZoomItem(Tab currentTab) {
         return currentTab != null
                 && shouldShowWebContentsDependentMenuItem(currentTab)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index 69bc392a..f0e6c83 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -2272,10 +2272,6 @@
             mUpdateMenuItemHelper.registerObserver(mMenuStateObserver);
         }
 
-        if (mExtensionToolbarManager != null) {
-            mExtensionToolbarManager.initializeWithNative();
-        }
-
         mInitializedWithNative = true;
         mTabModelSelector.getCurrentTabModelSupplier().addObserver(mCurrentTabModelObserver);
         refreshSelectedTab(mActivityTabProvider.get());
diff --git a/chrome/android/junit/BUILD.gn b/chrome/android/junit/BUILD.gn
index 7cf5fdeb..b584d4cf 100644
--- a/chrome/android/junit/BUILD.gn
+++ b/chrome/android/junit/BUILD.gn
@@ -191,6 +191,7 @@
       "//chrome/browser/ui/android/desktop_windowing:java",
       "//chrome/browser/ui/android/edge_to_edge:java",
       "//chrome/browser/ui/android/ephemeraltab:java",
+      "//chrome/browser/ui/android/extensions:java",
       "//chrome/browser/ui/android/favicon:java",
       "//chrome/browser/ui/android/google_bottom_bar:java",
       "//chrome/browser/ui/android/google_bottom_bar:proto_java",
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java
index 8a05889..55cc1677 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java
@@ -105,6 +105,7 @@
 import org.chromium.chrome.browser.ui.appmenu.AppMenuDelegate;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuHandler;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuItemProperties;
+import org.chromium.chrome.browser.ui.extensions.ExtensionsBuildflags;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.ui.native_page.NativePage;
 import org.chromium.components.browser_ui.accessibility.PageZoomCoordinator;
@@ -145,6 +146,7 @@
 @RunWith(BaseRobolectricTestRunner.class)
 @DisableFeatures({
     ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_PAGE_SUMMARY,
+    ChromeFeatureList.BLOCK_INSTALLING_EXTENSIONS_ON_DESKTOP_ANDROID,
     ChromeFeatureList.NEW_TAB_PAGE_CUSTOMIZATION,
     DomDistillerFeatures.READER_MODE_IMPROVEMENTS
 })
@@ -477,22 +479,27 @@
         assertEquals(MenuGroup.PAGE_MENU, mTabbedAppMenuPropertiesDelegate.getMenuGroup());
         MVCListAdapter.ModelList modelList = mTabbedAppMenuPropertiesDelegate.getMenuItems();
 
-        Integer[] expectedItems = {
-            R.id.icon_row_menu_id,
-            R.id.new_tab_menu_id,
-            R.id.new_incognito_tab_menu_id,
-            R.id.divider_line_id,
-            R.id.open_history_menu_id,
-            R.id.quick_delete_menu_id,
-            R.id.quick_delete_divider_line_id,
-            R.id.downloads_menu_id,
-            R.id.all_bookmarks_menu_id,
-            R.id.recent_tabs_menu_id,
-            R.id.divider_line_id,
-            R.id.preferences_id,
-            R.id.help_id
-        };
-        assertMenuItemsAreEqual(modelList, expectedItems);
+        List<Integer> expectedItems =
+                new ArrayList<>(
+                        Arrays.asList(
+                                R.id.icon_row_menu_id,
+                                R.id.new_tab_menu_id,
+                                R.id.new_incognito_tab_menu_id,
+                                R.id.divider_line_id,
+                                R.id.open_history_menu_id,
+                                R.id.quick_delete_menu_id,
+                                R.id.quick_delete_divider_line_id,
+                                R.id.downloads_menu_id,
+                                R.id.all_bookmarks_menu_id,
+                                R.id.recent_tabs_menu_id,
+                                R.id.divider_line_id,
+                                R.id.preferences_id,
+                                R.id.help_id));
+
+        if (ExtensionsBuildflags.ENABLE_DESKTOP_ANDROID_EXTENSIONS) {
+            expectedItems.add(R.id.extensions_menu_id);
+        }
+        assertMenuItemsAreEqual(modelList, expectedItems.toArray(new Integer[0]));
     }
 
     @Test
@@ -510,26 +517,31 @@
         assertEquals(MenuGroup.PAGE_MENU, mTabbedAppMenuPropertiesDelegate.getMenuGroup());
         MVCListAdapter.ModelList modelList = mTabbedAppMenuPropertiesDelegate.getMenuItems();
 
-        Integer[] expectedItems = {
-            R.id.icon_row_menu_id,
-            R.id.new_tab_menu_id,
-            R.id.new_incognito_tab_menu_id,
-            R.id.divider_line_id,
-            R.id.open_history_menu_id,
-            R.id.quick_delete_menu_id,
-            R.id.quick_delete_divider_line_id,
-            R.id.downloads_menu_id,
-            R.id.all_bookmarks_menu_id,
-            R.id.recent_tabs_menu_id,
-            R.id.divider_line_id,
-            R.id.share_menu_id,
-            R.id.find_in_page_id,
-            R.id.open_with_id,
-            R.id.divider_line_id,
-            R.id.preferences_id,
-            R.id.help_id
-        };
-        assertMenuItemsAreEqual(modelList, expectedItems);
+        List<Integer> expectedItems =
+                new ArrayList<>(
+                        Arrays.asList(
+                                R.id.icon_row_menu_id,
+                                R.id.new_tab_menu_id,
+                                R.id.new_incognito_tab_menu_id,
+                                R.id.divider_line_id,
+                                R.id.open_history_menu_id,
+                                R.id.quick_delete_menu_id,
+                                R.id.quick_delete_divider_line_id,
+                                R.id.downloads_menu_id,
+                                R.id.all_bookmarks_menu_id,
+                                R.id.recent_tabs_menu_id,
+                                R.id.divider_line_id,
+                                R.id.share_menu_id,
+                                R.id.find_in_page_id,
+                                R.id.open_with_id,
+                                R.id.divider_line_id,
+                                R.id.preferences_id,
+                                R.id.help_id));
+
+        if (ExtensionsBuildflags.ENABLE_DESKTOP_ANDROID_EXTENSIONS) {
+            expectedItems.add(R.id.extensions_menu_id);
+        }
+        assertMenuItemsAreEqual(modelList, expectedItems.toArray(new Integer[0]));
     }
 
     @Test
@@ -571,6 +583,10 @@
         expectedTitles.add(R.string.menu_bookmarks);
         expectedItems.add(R.id.recent_tabs_menu_id);
         expectedTitles.add(R.string.menu_recent_tabs);
+        if (ExtensionsBuildflags.ENABLE_DESKTOP_ANDROID_EXTENSIONS) {
+            expectedItems.add(R.id.extensions_menu_id);
+            expectedTitles.add(R.string.menu_extensions);
+        }
         expectedItems.add(R.id.divider_line_id);
         expectedTitles.add(0);
         expectedItems.add(R.id.share_menu_id);
@@ -642,6 +658,10 @@
         expectedTitles.add(R.string.menu_bookmarks);
         expectedItems.add(R.id.recent_tabs_menu_id);
         expectedTitles.add(R.string.menu_recent_tabs);
+        if (ExtensionsBuildflags.ENABLE_DESKTOP_ANDROID_EXTENSIONS) {
+            expectedItems.add(R.id.extensions_menu_id);
+            expectedTitles.add(R.string.menu_extensions);
+        }
         expectedItems.add(R.id.divider_line_id);
         expectedTitles.add(0);
         expectedItems.add(R.id.share_menu_id);
@@ -691,29 +711,33 @@
         assertEquals(MenuGroup.PAGE_MENU, mTabbedAppMenuPropertiesDelegate.getMenuGroup());
         MVCListAdapter.ModelList modelList = mTabbedAppMenuPropertiesDelegate.getMenuItems();
 
-        Integer[] expectedItems = {
-            R.id.icon_row_menu_id,
-            R.id.new_tab_menu_id,
-            R.id.new_incognito_tab_menu_id,
-            R.id.divider_line_id,
-            R.id.open_history_menu_id,
-            R.id.quick_delete_menu_id,
-            R.id.quick_delete_divider_line_id,
-            R.id.downloads_menu_id,
-            R.id.all_bookmarks_menu_id,
-            R.id.recent_tabs_menu_id,
-            R.id.divider_line_id,
-            R.id.share_menu_id,
-            R.id.find_in_page_id,
-            R.id.translate_id,
-            R.id.universal_install,
-            // Request desktop site is hidden.
-            R.id.auto_dark_web_contents_id,
-            R.id.divider_line_id,
-            R.id.preferences_id,
-            R.id.help_id
-        };
-        assertMenuItemsAreEqual(modelList, expectedItems);
+        List<Integer> expectedItems =
+                new ArrayList<>(
+                        Arrays.asList(
+                                R.id.icon_row_menu_id,
+                                R.id.new_tab_menu_id,
+                                R.id.new_incognito_tab_menu_id,
+                                R.id.divider_line_id,
+                                R.id.open_history_menu_id,
+                                R.id.quick_delete_menu_id,
+                                R.id.quick_delete_divider_line_id,
+                                R.id.downloads_menu_id,
+                                R.id.all_bookmarks_menu_id,
+                                R.id.recent_tabs_menu_id,
+                                R.id.divider_line_id,
+                                R.id.share_menu_id,
+                                R.id.find_in_page_id,
+                                R.id.translate_id,
+                                R.id.universal_install,
+                                // Request desktop site is hidden.
+                                R.id.auto_dark_web_contents_id,
+                                R.id.divider_line_id,
+                                R.id.preferences_id,
+                                R.id.help_id));
+        if (ExtensionsBuildflags.ENABLE_DESKTOP_ANDROID_EXTENSIONS) {
+            expectedItems.add(R.id.extensions_menu_id);
+        }
+        assertMenuItemsAreEqual(modelList, expectedItems.toArray(new Integer[0]));
     }
 
     @Test
@@ -745,25 +769,29 @@
         assertEquals(MenuGroup.PAGE_MENU, mTabbedAppMenuPropertiesDelegate.getMenuGroup());
         MVCListAdapter.ModelList modelList = mTabbedAppMenuPropertiesDelegate.getMenuItems();
 
-        Integer[] expectedItems = {
-            R.id.update_menu_id,
-            R.id.new_tab_menu_id,
-            R.id.new_incognito_tab_menu_id,
-            R.id.open_history_menu_id,
-            R.id.quick_delete_menu_id,
-            R.id.downloads_menu_id,
-            R.id.all_bookmarks_menu_id,
-            R.id.recent_tabs_menu_id,
-            R.id.translate_id,
-            R.id.share_menu_id,
-            R.id.find_in_page_id,
-            R.id.universal_install,
-            R.id.reader_mode_prefs_id,
-            R.id.auto_dark_web_contents_id,
-            R.id.preferences_id,
-            R.id.help_id
-        };
-        assertMenuItemsHaveIcons(modelList, expectedItems);
+        List<Integer> expectedItems =
+                new ArrayList<>(
+                        Arrays.asList(
+                                R.id.update_menu_id,
+                                R.id.new_tab_menu_id,
+                                R.id.new_incognito_tab_menu_id,
+                                R.id.open_history_menu_id,
+                                R.id.quick_delete_menu_id,
+                                R.id.downloads_menu_id,
+                                R.id.all_bookmarks_menu_id,
+                                R.id.recent_tabs_menu_id,
+                                R.id.translate_id,
+                                R.id.share_menu_id,
+                                R.id.find_in_page_id,
+                                R.id.universal_install,
+                                R.id.reader_mode_prefs_id,
+                                R.id.auto_dark_web_contents_id,
+                                R.id.preferences_id,
+                                R.id.help_id));
+        if (ExtensionsBuildflags.ENABLE_DESKTOP_ANDROID_EXTENSIONS) {
+            expectedItems.add(R.id.extensions_menu_id);
+        }
+        assertMenuItemsHaveIcons(modelList, expectedItems.toArray(new Integer[0]));
     }
 
     @Test
@@ -880,6 +908,9 @@
         if (!BuildConfig.IS_DESKTOP_ANDROID) {
             expectedItems.add(R.id.request_desktop_site_id);
         }
+        if (ExtensionsBuildflags.ENABLE_DESKTOP_ANDROID_EXTENSIONS) {
+            expectedItems.add(R.id.extensions_menu_id);
+        }
 
         assertMenuItemsAreEqual(modelList, expectedItems.toArray(new Integer[0]));
 
@@ -955,6 +986,9 @@
         if (!BuildConfig.IS_DESKTOP_ANDROID) {
             expectedItems.add(R.id.request_desktop_site_id);
         }
+        if (ExtensionsBuildflags.ENABLE_DESKTOP_ANDROID_EXTENSIONS) {
+            expectedItems.add(R.id.extensions_menu_id);
+        }
 
         assertMenuItemsAreEqual(modelList, expectedItems.toArray(new Integer[0]));
     }
diff --git a/chrome/app/resources/generated_resources_lo.xtb b/chrome/app/resources/generated_resources_lo.xtb
index 8297d1b..d02577c4 100644
--- a/chrome/app/resources/generated_resources_lo.xtb
+++ b/chrome/app/resources/generated_resources_lo.xtb
@@ -2178,6 +2178,7 @@
 <translation id="24786041351753425">ເປີດການນຳໃຊ້ບໍລິການການກູ້ຄືນຂໍ້ມູນ.</translation>
 <translation id="2479541499757560845">ການຕັ້ງຄ່າແປ້ນພິມການຊ່ວຍເຂົ້າເຖິງ</translation>
 <translation id="2480868415629598489">ແກ້ໄຂຂໍ້ມູນທີ່ທ່ານສຳເນົາ ແລະ ວາງໃສ່</translation>
+<translation id="2480881140544300950">ໂປຣແກຣມຊອກຫາປັດຈຸບັນທີ່ຈັດການໜ້າແຖບໃໝ່ຂອງທ່ານ</translation>
 <translation id="2482878487686419369">ການແຈ້ງເຕືອນ</translation>
 <translation id="2482895651873876648">ຍ້າຍແຖບໄປໃສ່ກຸ່ມ <ph name="GROUP_NAME" /> - <ph name="GROUP_CONTENTS" /> ແລ້ວ</translation>
 <translation id="2483627560139625913">ຕັ້ງໂປຣແກຣມຊອກຫາໃນການຕັ້ງຄ່າໂປຣແກຣມທ່ອງເວັບ Chrome</translation>
@@ -5379,6 +5380,7 @@
 <translation id="4742970037960872810">ລຶບໄຮໄລ້ອອກ</translation>
 <translation id="4743260470722568160"><ph name="BEGIN_LINK" />ສຶກສາວິທີອັບເດດແອັບພລິເຄຊັນ<ph name="END_LINK" /></translation>
 <translation id="4743990041512863976">ອະນຸຍາດ – <ph name="PERMISSION_DETAILS" />. ເປີດ <ph name="LINK_BEGIN" />ສິດເຂົ້າເຖິງໄມໂຄຣໂຟນຂອງລະບົບ<ph name="LINK_END" />.</translation>
+<translation id="4744172369799559159">ທີມງານຈະກວດສອບໜ້າລະຫັດຜ່ານ ແລະ ຂໍ້ມູນທີ່ກ່ຽວຂ້ອງເພື່ອປັບປຸງຄຸນສົມບັດນີ້, ແຕ່ລະຫັດຜ່ານຂອງທ່ານຈະຖືກເຂົ້າລະຫັດໄວ້ ແລະ ຈະບໍ່ມີໃຜເບິ່ງເຫັນໄດ້.</translation>
 <translation id="4744260496658845719">ຄວາມສະຫວ່າງຂອງໄຟປຸ່ມແປ້ນພິມ</translation>
 <translation id="4744268813103118742">ເຂົ້າໄປເວັບໄຊ</translation>
 <translation id="4744571849207727284">Excel</translation>
@@ -6337,6 +6339,7 @@
 <translation id="5434065355175441495">ການໃສ່ລະຫັດ PKCS #1 RSA</translation>
 <translation id="5435274640623994081">ເປີດນຳໃຊ້ການບັນທຶກ earcon</translation>
 <translation id="5435779377906857208">ອະນຸຍາດໃຫ້ <ph name="HOST" /> ເຂົ້າເຖິງສະຖານທີ່ຂອງທ່ານທຸກເທື່ອ</translation>
+<translation id="5436211819997237281">ສ່ວນຂະຫຍາຍປັດຈຸບັນທີ່ຈັດການໜ້າແຖບໃໝ່ຂອງທ່ານ</translation>
 <translation id="5436492226391861498">ກໍາລັງລໍຖ້າຊ່ອງພຣັອກຊີ...</translation>
 <translation id="5436510242972373446">ຊອກຫາ <ph name="SITE_NAME" /> :</translation>
 <translation id="5438014818441491616">ຕອນນີ້ໜ້າຈໍ <ph name="WINDOW_SIDE" /> ກວ້າງ <ph name="WINDOW_SIZE_PERCENT" />, ແຖບ <ph name="PANE_SIDE" /> ກວ້າງ <ph name="PANE_SIZE_PERCENT" />.</translation>
@@ -9225,6 +9228,7 @@
 <translation id="7529411698175791732">ກວດເບິ່ງການເຊື່ອມຕໍ່ອິນເຕີເນັດຂອງທ່ານ. ຖ້າບັນຫາຍັງສືບຕໍ່, ກະລຸນາລອງອອກຈາກລະບົບແລ້ວເຂົ້າສູ່ລະບົບຄືນໃໝ່.</translation>
 <translation id="7529865045818406536">ເຄືອຂ່າຍທີ່ຕ້ອງການຈະຖືກໃຊ້ຫາກມີເຄືອຂ່າຍກ່ອນໜ້າທີ່ສາມາດໃຊ້ໄດ້ຫຼາຍກວ່າໜຶ່ງເຄືອຂ່າຍ</translation>
 <translation id="7530016656428373557">ອັດຕາປ່ອຍອອກມາເປັນວັດຕ໌</translation>
+<translation id="7530215951451994972">ສ້າງຮູບ</translation>
 <translation id="7531771599742723865">ມີການນຳໃຊ້ອຸປະກອນຢູ່</translation>
 <translation id="7531779363494549572">ໄປຫາການຕັ້ງຄ່າ &gt; ແອັບ ແລະ ການແຈ້ງເຕືອນ &gt; ການແຈ້ງເຕືອນ.</translation>
 <translation id="7532009420053991888"><ph name="LINUX_APP_NAME" /> ບໍ່ຕອບສະໜອງ. ເລືອກ "ບັງຄັບປິດ" ເພື່ອປິດແອັບ.</translation>
diff --git a/chrome/browser/ash/crosapi/structured_metrics_service_ash.cc b/chrome/browser/ash/crosapi/structured_metrics_service_ash.cc
deleted file mode 100644
index db6ddb0..0000000
--- a/chrome/browser/ash/crosapi/structured_metrics_service_ash.cc
+++ /dev/null
@@ -1,30 +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/structured_metrics_service_ash.h"
-
-#include "chromeos/crosapi/mojom/structured_metrics_service.mojom.h"
-#include "components/metrics/structured/event.h"
-#include "components/metrics/structured/recorder.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
-
-namespace crosapi {
-
-StructuredMetricsServiceAsh::StructuredMetricsServiceAsh() = default;
-StructuredMetricsServiceAsh::~StructuredMetricsServiceAsh() = default;
-
-void StructuredMetricsServiceAsh::BindReceiver(
-    mojo::PendingReceiver<mojom::StructuredMetricsService> receiver) {
-  receivers_.Add(this, std::move(receiver));
-}
-
-void StructuredMetricsServiceAsh::Record(
-    std::vector<::metrics::structured::Event> events) {
-  for (auto& event : events) {
-    metrics::structured::Recorder::GetInstance()->RecordEvent(std::move(event));
-  }
-}
-
-}  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/structured_metrics_service_ash.h b/chrome/browser/ash/crosapi/structured_metrics_service_ash.h
deleted file mode 100644
index 552a0c35..0000000
--- a/chrome/browser/ash/crosapi/structured_metrics_service_ash.h
+++ /dev/null
@@ -1,42 +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_STRUCTURED_METRICS_SERVICE_ASH_H_
-#define CHROME_BROWSER_ASH_CROSAPI_STRUCTURED_METRICS_SERVICE_ASH_H_
-
-#include "chromeos/crosapi/mojom/structured_metrics_service.mojom.h"
-#include "components/metrics/structured/event.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver_set.h"
-
-namespace crosapi {
-
-// Implements the StructuredMetricsService mojo interface to record events from
-// AshStructuredMetricsDelegate. Wrapper to validate and record structured
-// metrics. Lives on the UI thread. Although both AshStructuredMetricsDelegate
-// and StructuredMetricsServiceAsh live in the same Ash process, instantiating a
-// mojo pipe adds little overhead and provides lots of benefits out of the box
-// (ie message buffer).
-class StructuredMetricsServiceAsh final
-    : public mojom::StructuredMetricsService {
- public:
-  StructuredMetricsServiceAsh();
-  StructuredMetricsServiceAsh(const StructuredMetricsServiceAsh&) = delete;
-  StructuredMetricsServiceAsh& operator=(const StructuredMetricsServiceAsh&) =
-      delete;
-  ~StructuredMetricsServiceAsh() override;
-
-  void BindReceiver(
-      mojo::PendingReceiver<mojom::StructuredMetricsService> receiver);
-
-  // crosapi::mojom::StructuredMetricsService
-  void Record(std::vector<::metrics::structured::Event> events) override;
-
- private:
-  mojo::ReceiverSet<mojom::StructuredMetricsService> receivers_;
-};
-
-}  // namespace crosapi
-
-#endif  // CHROME_BROWSER_ASH_CROSAPI_STRUCTURED_METRICS_SERVICE_ASH_H_
diff --git a/chrome/browser/autofill_ai/chrome_autofill_ai_client.cc b/chrome/browser/autofill_ai/chrome_autofill_ai_client.cc
index f0f44726..f8e44a5 100644
--- a/chrome/browser/autofill_ai/chrome_autofill_ai_client.cc
+++ b/chrome/browser/autofill_ai/chrome_autofill_ai_client.cc
@@ -62,19 +62,3 @@
 autofill_ai::AutofillAiManager& ChromeAutofillAiClient::GetManager() {
   return prediction_improvements_manager_;
 }
-
-void ChromeAutofillAiClient::ShowSaveOrUpdateBubble(
-    autofill::EntityInstance new_entity,
-    std::optional<autofill::EntityInstance> old_entity,
-    EntitySaveOrUpdatePromptResultCallback prompt_acceptance_callback) {
-#if !BUILDFLAG(IS_ANDROID)
-  if (auto* controller =
-          autofill_ai::SaveOrUpdateAutofillAiDataController::GetOrCreate(
-              &*web_contents_, GetAutofillClient().GetAppLocale())) {
-    controller->ShowPrompt(std::move(new_entity), std::move(old_entity),
-                           std::move(prompt_acceptance_callback));
-    return;
-  }
-#endif  // !BUILDFLAG(IS_ANDROID)
-  std::move(prompt_acceptance_callback).Run(EntitySaveOrUpdatePromptResult());
-}
diff --git a/chrome/browser/autofill_ai/chrome_autofill_ai_client.h b/chrome/browser/autofill_ai/chrome_autofill_ai_client.h
index b42262d2..c484810 100644
--- a/chrome/browser/autofill_ai/chrome_autofill_ai_client.h
+++ b/chrome/browser/autofill_ai/chrome_autofill_ai_client.h
@@ -33,11 +33,6 @@
   // AutofillAiClient:
   autofill::ContentAutofillClient& GetAutofillClient() override;
   autofill_ai::AutofillAiManager& GetManager() override;
-  void ShowSaveOrUpdateBubble(
-      autofill::EntityInstance new_entity,
-      std::optional<autofill::EntityInstance> old_entity,
-      EntitySaveOrUpdatePromptResultCallback save_prompt_acceptance_callback)
-      override;
 
  private:
   explicit ChromeAutofillAiClient(content::WebContents* web_contents);
diff --git a/chrome/browser/chrome_browser_field_trials.cc b/chrome/browser/chrome_browser_field_trials.cc
index 33905e7..b71e4ce 100644
--- a/chrome/browser/chrome_browser_field_trials.cc
+++ b/chrome/browser/chrome_browser_field_trials.cc
@@ -141,6 +141,18 @@
   feature_overrides.EnableFeature(kAndroidMediaPicker);
   feature_overrides.EnableFeature(features::kUserMediaScreenCapturing);
 
+  // Enable desktop tab management features.
+  // TODO(crbug.com/422902880): Remove when tablet rollout is complete.
+  feature_overrides.EnableFeature(
+      base::features::kUseSharedRebindServiceConnection);
+  // TODO(crbug.com/422902940): Remove when tablet rollout is complete.
+  feature_overrides.EnableFeature(
+      base::features::kBackgroundNotPerceptibleBinding);
+  // TODO(crbug.com/422902625): Remove when rollout is complete to all form
+  // factors.
+  feature_overrides.EnableFeature(chrome::android::kProcessRankPolicyAndroid);
+  feature_overrides.EnableFeature(features::kGroupRebindingForGroupImportance);
+  feature_overrides.EnableFeature(chrome::android::kProtectedTabsAndroid);
 #endif  // BUILDFLAG(IS_DESKTOP_ANDROID)
   // Desktop-first features which are past incubation should either end up here,
   // or to a finch trial that enables it for all form factors.
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index f8cf92f..facdcce 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -323,6 +323,7 @@
 #include "content/public/browser/permission_descriptor_util.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
+#include "content/public/browser/service_worker_context.h"
 #include "content/public/browser/site_isolation_mode.h"
 #include "content/public/browser/site_isolation_policy.h"
 #include "content/public/browser/sms_fetcher.h"
@@ -340,6 +341,7 @@
 #include "content/public/common/content_descriptors.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/common/origin_util.h"
 #include "content/public/common/url_utils.h"
 #include "content/public/common/window_container_type.mojom-shared.h"
 #include "device/fido/features.h"
@@ -777,6 +779,11 @@
              "SkipPagehideInCommitForDSENavigation",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Warm up the ServiceWorker registration for DSE.
+BASE_FEATURE(kPrewarmServiceWorkerRegistrationForDSE,
+             "PrewarmServiceWorkerRegistrationForDSE",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 // A small ChromeBrowserMainExtraParts that invokes a callback when threads are
 // ready. Used to initialize ChromeContentBrowserClient data that needs the UI
 // thread.
@@ -3767,6 +3774,61 @@
   return !cookie_settings->ShouldBlockThirdPartyCookies();
 }
 
+void ChromeContentBrowserClient::PrewarmServiceWorkerRegistrationForDSE(
+    content::BrowserContext* browser_context,
+    content::ServiceWorkerContext& service_worker_context) {
+  TRACE_EVENT(
+      "ServiceWorker",
+      "ChromeContentBrowserClient::PrewarmServiceWorkerRegistrationForDSE");
+
+  if (ChromeContentBrowserClient::
+          PrewarmServiceWorkerRegistrationForDSECalledCountForTesting()) {
+    CHECK_IS_TEST();
+    ++(*ChromeContentBrowserClient::
+           PrewarmServiceWorkerRegistrationForDSECalledCountForTesting());
+  }
+
+  if (!base::FeatureList::IsEnabled(kPrewarmServiceWorkerRegistrationForDSE)) {
+    return;
+  }
+
+  Profile* profile = Profile::FromBrowserContext(browser_context);
+
+  if (!profile) {
+    return;
+  }
+
+  TemplateURLService* template_url_service =
+      TemplateURLServiceFactory::GetForProfile(profile);
+
+  if (!template_url_service) {
+    return;
+  }
+
+  GURL url =
+      template_url_service->GenerateSearchURLForDefaultSearchProvider(u"");
+
+  if (!content::OriginCanAccessServiceWorkers(url)) {
+    return;
+  }
+
+  const blink::StorageKey key =
+      blink::StorageKey::CreateFirstParty(url::Origin::Create(url));
+
+  if (!service_worker_context.MaybeHasRegistrationForStorageKey(key)) {
+    return;
+  }
+
+  service_worker_context.CheckHasServiceWorker(url, key, base::DoNothing());
+}
+
+// static
+std::optional<int>& ChromeContentBrowserClient::
+    PrewarmServiceWorkerRegistrationForDSECalledCountForTesting() {
+  static std::optional<int> call_count;
+  return call_count;
+}
+
 bool ChromeContentBrowserClient::CanSendSCTAuditingReport(
     content::BrowserContext* browser_context) {
   return SCTReportingService::CanSendSCTAuditingReport();
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index f54b754..cce71f1 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -457,6 +457,11 @@
   bool AreThirdPartyCookiesGenerallyAllowed(
       content::BrowserContext* browser_context,
       content::WebContents* web_contents) override;
+  void PrewarmServiceWorkerRegistrationForDSE(
+      content::BrowserContext* browser_context,
+      content::ServiceWorkerContext& service_worker_context) override;
+  static std::optional<int>&
+  PrewarmServiceWorkerRegistrationForDSECalledCountForTesting();
   bool CanSendSCTAuditingReport(
       content::BrowserContext* browser_context) override;
   void OnNewSCTAuditingReportSent(
diff --git a/chrome/browser/chrome_service_worker_browsertest.cc b/chrome/browser/chrome_service_worker_browsertest.cc
index 2263df9..d689ce58 100644
--- a/chrome/browser/chrome_service_worker_browsertest.cc
+++ b/chrome/browser/chrome_service_worker_browsertest.cc
@@ -24,6 +24,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
+#include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h"
 #include "chrome/browser/profiles/profile.h"
@@ -1590,4 +1591,27 @@
   EXPECT_FALSE(HasHeader(received_request(), "Cookie"));
 }
 
+class ChromeServiceWorkerPrewarmForDSETest : public InProcessBrowserTest {
+ public:
+  void SetUp() override {
+    ChromeContentBrowserClient::
+        PrewarmServiceWorkerRegistrationForDSECalledCountForTesting() = 0;
+    // The following step starts the browser, and prewarms the registration of
+    // ServiceWorker for DSE.
+    InProcessBrowserTest::SetUp();
+  }
+
+  void TearDown() override {
+    ChromeContentBrowserClient::
+        PrewarmServiceWorkerRegistrationForDSECalledCountForTesting() =
+            std::nullopt;
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(ChromeServiceWorkerPrewarmForDSETest, PrewarmIsCalled) {
+  EXPECT_GE(*ChromeContentBrowserClient::
+                PrewarmServiceWorkerRegistrationForDSECalledCountForTesting(),
+            1);
+}
+
 }  // namespace chrome_service_worker_browser_test
diff --git a/chrome/browser/devtools/devtools_browsertest.cc b/chrome/browser/devtools/devtools_browsertest.cc
index 2163522..ba244e4 100644
--- a/chrome/browser/devtools/devtools_browsertest.cc
+++ b/chrome/browser/devtools/devtools_browsertest.cc
@@ -1836,7 +1836,8 @@
 }
 
 // Disabled on Windows due to flakiness. http://crbug.com/183649
-#if BUILDFLAG(IS_WIN)
+// TODO(crbug.com/425268770): Flaky on Linux.
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
 #define MAYBE_TestDevToolsExtensionMessaging \
   DISABLED_TestDevToolsExtensionMessaging
 #else
diff --git a/chrome/browser/extensions/extension_management.cc b/chrome/browser/extensions/extension_management.cc
index 5496b03..7d55128c 100644
--- a/chrome/browser/extensions/extension_management.cc
+++ b/chrome/browser/extensions/extension_management.cc
@@ -171,14 +171,8 @@
                              update_url ? *update_url : std::string());
 }
 
-ManagedInstallationMode ExtensionManagement::GetInstallationMode(
-    const ExtensionId& extension_id,
-    const std::string& update_url) {
-// Block extensions for managed profiles on Desktop Android. This is
-// temporary until extensions are ready for dogfooding.
-// TODO(crbug.com/422307625): Remove this check once extensions are ready for
-// dogfooding.
-#if BUILDFLAG(IS_ANDROID)
+#if BUILDFLAG(ENABLE_DESKTOP_ANDROID_EXTENSIONS)
+bool ExtensionManagement::ExtensionsEnabledForDesktopAndroid() const {
   if (enterprise_util::IsBrowserManaged(profile_)) {
     // Disable extensions only for specific managed accounts.
     // This check keeps many tests from failing.
@@ -187,11 +181,26 @@
     if (base::Contains(user_name, "@")) {
       std::string domain = gaia::ExtractDomainName(user_name);
       if (domain == "google.com" || domain == "managedchrome.com") {
-        return ManagedInstallationMode::kRemoved;
+        return false;
       }
     }
   }
-#endif  // BUILDFLAG(IS_ANDROID)
+  return true;
+}
+#endif  // BUILDFLAG(ENABLE_DESKTOP_ANDROID_EXTENSIONS)
+
+ManagedInstallationMode ExtensionManagement::GetInstallationMode(
+    const ExtensionId& extension_id,
+    const std::string& update_url) {
+#if BUILDFLAG(ENABLE_DESKTOP_ANDROID_EXTENSIONS)
+  // Block extensions for managed profiles on Desktop Android. This is
+  // temporary until extensions are ready for dogfooding.
+  // TODO(crbug.com/422307625): Remove this check once extensions are ready for
+  // dogfooding.
+  if (!ExtensionsEnabledForDesktopAndroid()) {
+    return ManagedInstallationMode::kRemoved;
+  }
+#endif  // BUILDFLAG(ENABLE_DESKTOP_ANDROID_EXTENSIONS)
 
   // Check per-extension installation mode setting first.
   auto* setting = GetSettingsForId(extension_id);
diff --git a/chrome/browser/extensions/extension_management.h b/chrome/browser/extensions/extension_management.h
index caef9b2..81acab1 100644
--- a/chrome/browser/extensions/extension_management.h
+++ b/chrome/browser/extensions/extension_management.h
@@ -86,6 +86,14 @@
   // from the command line, or when loaded as an unpacked extension).
   bool BlocklistedByDefault() const;
 
+#if BUILDFLAG(ENABLE_DESKTOP_ANDROID_EXTENSIONS)
+  // Checks if extensions are enabled for Desktop Android for the current
+  // profile. This is temporary for until extensions are ready for dogfooding.
+  // TODO(crbug.com/422307625): Remove this check once extensions are ready for
+  // dogfooding.
+  bool ExtensionsEnabledForDesktopAndroid() const;
+#endif  // BUILDFLAG(ENABLE_DESKTOP_ANDROID_EXTENSIONS)
+
   // Returns installation mode for an extension.
   ManagedInstallationMode GetInstallationMode(const Extension* extension);
 
diff --git a/chrome/browser/extensions/load_error_reporter.cc b/chrome/browser/extensions/load_error_reporter.cc
index 8af69ff..bf5982f0 100644
--- a/chrome/browser/extensions/load_error_reporter.cc
+++ b/chrome/browser/extensions/load_error_reporter.cc
@@ -72,24 +72,7 @@
   LOG(WARNING) << "Extension error: " << message;
 
   if (enable_noisy_errors_ && be_noisy) {
-    // This dialog is synchronous to prevent a race condition during startup.
-    //
-    // In the asynchronous case, the sequence of events is:
-    // 1. A startup task to load an extension fails, and an asynchronous call
-    //    is made to show this parentless dialog.
-    // 2. The dialog's widget initializes, registering an accessibility observer
-    //    with `AXPlatform`. The async call then returns immediately, marking
-    //    the startup task as complete.
-    // 3. Because the startup task is finished and no windows are open, the
-    //    browser process begins its shutdown sequence.
-    // 4. During shutdown, `AXPlatform` is destroyed before the dialog is. Its
-    //    destructor's `CHECK` for no remaining observers fails because the
-    //    dialog's observer is still registered, causing a crash.
-    //
-    // By using a synchronous dialog, we block the startup task from completing
-    // until the user dismisses the alert, ensuring steps 3 and 4 cannot
-    // happen until after the dialog and its observers are gone.
-    chrome::ShowWarningMessageBoxSync(
+    chrome::ShowWarningMessageBoxAsync(
         gfx::NativeWindow(),
         l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_ERROR_ALERT_HEADING),
         message);
diff --git a/chrome/browser/preloading/search_preload/search_preload_browsertest.cc b/chrome/browser/preloading/search_preload/search_preload_browsertest.cc
index 609a682..b6415a5 100644
--- a/chrome/browser/preloading/search_preload/search_preload_browsertest.cc
+++ b/chrome/browser/preloading/search_preload/search_preload_browsertest.cc
@@ -36,6 +36,7 @@
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/navigation/preloading_headers.h"
 
 namespace {
 
@@ -55,6 +56,8 @@
 
 }  // namespace alternative_content
 
+constexpr static char kSearchTerms_502OnPrefetch[] = "502-on-prefetch";
+
 std::optional<net::HttpNoVarySearchData> ParseNoVarySearchData(std::string s) {
   auto headers =
       base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK\n");
@@ -252,20 +255,38 @@
 
   std::unique_ptr<net::test_server::HttpResponse> HandleSearchRequest(
       const net::test_server::HttpRequest& request) {
+    const bool is_prefetch =
+        request.headers.find(blink::kPurposeHeaderName) !=
+            request.headers.end() &&
+        request.headers.find(blink::kPurposeHeaderName)->second ==
+            blink::kSecPurposePrefetchHeaderValue;
+    CHECK_EQ(is_prefetch,
+             request.headers.find(blink::kSecPurposeHeaderName) !=
+                     request.headers.end() &&
+                 request.headers.find(blink::kSecPurposeHeaderName)->second ==
+                     blink::kSecPurposePrefetchPrerenderHeaderValue);
+
+    if (request.GetURL().spec().find(kSearchTerms_502OnPrefetch) !=
+            std::string::npos &&
+        is_prefetch) {
+      net::HttpStatusCode code = net::HTTP_BAD_GATEWAY;
+      std::string content = "<html><body>preeftch</body></html>";
+      base::StringPairs headers = {
+          {"Content-Length", base::NumberToString(content.length())},
+          {"Content-Type", "text/html"},
+          {"No-Vary-Search", R"(key-order, params, except=("q"))"},
+      };
+      return CreateDeferrableResponse(code, headers, content);
+    }
+
     net::HttpStatusCode code = net::HttpStatusCode::HTTP_OK;
-    std::string content = R"(
-      <html><body>
-      PRERENDER: HI PREFETCH! \o/
-      </body></html>
-    )";
+    std::string content = "<html><body>prefetch</body></html>";
     base::StringPairs headers = {
         {"Content-Length", base::NumberToString(content.length())},
         {"Content-Type", "text/html"},
         {"No-Vary-Search", R"(key-order, params, except=("q"))"},
     };
-    std::unique_ptr<net::test_server::HttpResponse> response =
-        CreateDeferrableResponse(code, headers, content);
-    return response;
+    return CreateDeferrableResponse(code, headers, content);
   }
 
   enum class PrefetchHint { kEnabled, kDisabled };
@@ -943,6 +964,123 @@
             ParseNoVarySearchData(R"(key-order, params, except=("q"))"));
 }
 
+// A pipeline is consumed by navigation.
+//
+// Note that this is for aligning the behavior of `SearchPrefetchService`. It
+// would be nice to discuss the ideal behavior.
+//
+// See also
+// https://docs.google.com/document/d/1NjxwlOEoBwpXojG13M85XtS8nH-S4uc0F6VOrlwIAXE/edit?pli=1&tab=t.0#heading=h.5qv0ome418fo
+IN_PROC_BROWSER_TEST_F(SearchPreloadBrowserTest,
+                       PipelineIsConsumedByNavigation) {
+  SetUpTemplateURLService();
+  SetUpSearchPreloadService({
+      .no_vary_search_data_cache = R"(key-order, params, except=("q"))",
+  });
+
+  ASSERT_TRUE(content::NavigateToURL(
+      &GetWebContents(), embedded_test_server()->GetURL("/empty.html")));
+
+  std::string original_query = "hello";
+  std::string search_terms = original_query;
+  SearchUrls urls = GetSearchUrls(search_terms);
+
+  {
+    content::test::TestPrefetchWatcher watcher;
+
+    ChangeAutocompleteResult(original_query, search_terms,
+                             PrefetchHint::kEnabled, PrerenderHint::kDisabled);
+
+    watcher.WaitUntilPrefetchResponseCompleted(std::nullopt,
+                                               urls.prefetch_on_suggest);
+  }
+
+  EXPECT_EQ(1, request_collector().CountByPath(urls.prefetch_on_suggest));
+  EXPECT_EQ(0, request_collector().CountByPath(urls.prerender));
+
+  // Navigate.
+  ASSERT_TRUE(content::NavigateToURL(&GetWebContents(), urls.navigation));
+
+  // Prefetch is used.
+  EXPECT_EQ(1, request_collector().CountByPath(urls.prefetch_on_suggest));
+  EXPECT_EQ(0, request_collector().CountByPath(urls.navigation));
+
+  // Prefetch was consumed by the navigation.
+  ASSERT_FALSE(GetSearchPreloadService().InvalidatePipelineForTesting(
+      GetWebContents(), urls.navigation));
+
+  // Navigate.
+  ASSERT_TRUE(content::NavigateToURL(&GetWebContents(), urls.navigation));
+
+  // Prefetch is not available.
+  EXPECT_EQ(1, request_collector().CountByPath(urls.prefetch_on_suggest));
+  EXPECT_EQ(1, request_collector().CountByPath(urls.navigation));
+}
+
+class SearchPreloadBrowserTest_ErrorBackoffDuration
+    : public SearchPreloadBrowserTestBase {
+  void InitFeatures(
+      base::test::ScopedFeatureList& scoped_feature_list) override {
+    scoped_feature_list.InitWithFeaturesAndParameters(
+        {
+            {
+                features::kPrefetchPrerenderIntegration,
+                {},
+            },
+            {
+                features::kDsePreload2,
+                {
+                    {"kDsePreload2ErrorBackoffDuration", "1000ms"},
+                    {"kDsePreload2DeviceMemoryThresholdMiB", "0"},
+                },
+            },
+        },
+        /*disabled_features=*/{});
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(
+    SearchPreloadBrowserTest_ErrorBackoffDuration,
+    PreloadsAreNotTriggeredCertainPeriodAfterPrefetchFailed) {
+  SetUpTemplateURLService();
+  SetUpSearchPreloadService({
+      .no_vary_search_data_cache = R"(key-order, params, except=("q"))",
+  });
+
+  ASSERT_TRUE(content::NavigateToURL(
+      &GetWebContents(), embedded_test_server()->GetURL("/empty.html")));
+
+  auto check = [&](std::string original_query,
+                   const bool is_triggered_expected) {
+    request_collector().Reset();
+
+    std::string search_terms = original_query;
+    SearchUrls urls = GetSearchUrls(search_terms);
+
+    {
+      content::test::TestPrefetchWatcher watcher;
+
+      ChangeAutocompleteResult(original_query, search_terms,
+                               PrefetchHint::kEnabled,
+                               PrerenderHint::kDisabled);
+
+      if (is_triggered_expected) {
+        watcher.WaitUntilPrefetchResponseCompleted(std::nullopt,
+                                                   urls.prefetch_on_suggest);
+      }
+    }
+
+    EXPECT_EQ(is_triggered_expected,
+              request_collector().CountByPath(urls.prefetch_on_suggest));
+    EXPECT_EQ(0, request_collector().CountByPath(urls.prerender));
+  };
+
+  check(kSearchTerms_502OnPrefetch, true);
+  check("two", false);
+  WaitForDuration(base::Milliseconds(1000));
+  check("three", true);
+}
+
 class SearchPreloadBrowserTest_DeviceMemoryThreshold
     : public SearchPreloadBrowserTestBase {
   void InitFeatures(
diff --git a/chrome/browser/preloading/search_preload/search_preload_features.cc b/chrome/browser/preloading/search_preload/search_preload_features.cc
index c7b0abd..7cce0e3 100644
--- a/chrome/browser/preloading/search_preload/search_preload_features.cc
+++ b/chrome/browser/preloading/search_preload/search_preload_features.cc
@@ -17,6 +17,9 @@
     &kDsePreload2, "kDsePreload2DeviceMemoryThresholdMiB",
     // 3 GiB = 3 * 2**10 * 2**20
     3072};
+const base::FeatureParam<base::TimeDelta> kDsePreload2ErrorBackoffDuration{
+    &kDsePreload2, "kDsePreload2ErrorBackoffDuration",
+    base::Milliseconds(60000)};
 const base::FeatureParam<size_t> kDsePreload2MaxPrefetch{
     &kDsePreload2, "kDsePreload2MaxPrefetch", 7};
 const base::FeatureParam<base::TimeDelta> kDsePreload2PrefetchTtl{
diff --git a/chrome/browser/preloading/search_preload/search_preload_features.h b/chrome/browser/preloading/search_preload/search_preload_features.h
index e8214d9..896b3b60 100644
--- a/chrome/browser/preloading/search_preload/search_preload_features.h
+++ b/chrome/browser/preloading/search_preload/search_preload_features.h
@@ -25,6 +25,9 @@
 
 // The feature is disabled if device memory is smaller than the threshold.
 extern const base::FeatureParam<size_t> kDsePreload2DeviceMemoryThresholdMiB;
+// Pause triggering preloads when on-suggest prefetch failed.
+extern const base::FeatureParam<base::TimeDelta>
+    kDsePreload2ErrorBackoffDuration;
 extern const base::FeatureParam<size_t> kDsePreload2MaxPrefetch;
 // Time to live (TTL) of prefetch.
 extern const base::FeatureParam<base::TimeDelta> kDsePreload2PrefetchTtl;
diff --git a/chrome/browser/preloading/search_preload/search_preload_pipeline.cc b/chrome/browser/preloading/search_preload/search_preload_pipeline.cc
index dbdc2de9..7e27979 100644
--- a/chrome/browser/preloading/search_preload/search_preload_pipeline.cc
+++ b/chrome/browser/preloading/search_preload/search_preload_pipeline.cc
@@ -52,7 +52,8 @@
     base::WeakPtr<SearchPreloadService> search_preload_service,
     const GURL& prefetch_url,
     content::PreloadingPredictor predictor,
-    const std::optional<net::HttpNoVarySearchData>& no_vary_search_hint) {
+    const std::optional<net::HttpNoVarySearchData>& no_vary_search_hint,
+    bool is_navigation_likely) {
   // Don't trigger prefetch if already triggered and is alive.
   //
   // TODO(crbug.com/394213503): Reconsider the behavior when prefetch is already
@@ -91,8 +92,14 @@
       /*holdback_status_override=*/std::nullopt,
       /*ttl=*/features::kDsePreload2PrefetchTtl.Get());
   CHECK(prefetch_handle_);
-  prefetch_handle_->SetOnPrefetchHeadReceived(base::BindRepeating(
+  prefetch_handle_->SetOnPrefetchHeadReceivedCallback(base::BindRepeating(
       &SearchPreloadService::OnPrefetchHeadReceived, search_preload_service));
+  if (!is_navigation_likely) {
+    prefetch_handle_->SetOnPrefetchCompletedOrFailedCallback(
+        base::BindRepeating(
+            &SearchPreloadService::OnOnSuggestPrefetchCompletedOrFailed,
+            search_preload_service));
+  }
 
   return true;
 }
diff --git a/chrome/browser/preloading/search_preload/search_preload_pipeline.h b/chrome/browser/preloading/search_preload/search_preload_pipeline.h
index 8ab1819..a792bec 100644
--- a/chrome/browser/preloading/search_preload/search_preload_pipeline.h
+++ b/chrome/browser/preloading/search_preload/search_preload_pipeline.h
@@ -39,7 +39,8 @@
       base::WeakPtr<SearchPreloadService> search_preload_service,
       const GURL& prefetch_url,
       content::PreloadingPredictor predictor,
-      const std::optional<net::HttpNoVarySearchData>& no_vary_search_hint);
+      const std::optional<net::HttpNoVarySearchData>& no_vary_search_hint,
+      bool is_navigation_likely);
   // Starts prerender if not triggered yet and prefetch is alive.
   void StartPrerender(content::WebContents& web_contents,
                       const GURL& prerernder_url,
diff --git a/chrome/browser/preloading/search_preload/search_preload_pipeline_manager.cc b/chrome/browser/preloading/search_preload/search_preload_pipeline_manager.cc
index 6c49e64..7ad6a30 100644
--- a/chrome/browser/preloading/search_preload/search_preload_pipeline_manager.cc
+++ b/chrome/browser/preloading/search_preload/search_preload_pipeline_manager.cc
@@ -16,6 +16,7 @@
 #include "components/omnibox/browser/base_search_provider.h"
 #include "components/omnibox/browser/omnibox.mojom-shared.h"
 #include "components/search_engines/template_url_service.h"
+#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/preloading_data.h"
 #include "content/public/browser/web_contents.h"
 
@@ -54,8 +55,8 @@
 
 SearchPreloadPipelineManager::SearchPreloadPipelineManager(
     content::WebContents* web_contents)
-    : content::WebContentsUserData<SearchPreloadPipelineManager>(
-          *web_contents) {
+    : content::WebContentsUserData<SearchPreloadPipelineManager>(*web_contents),
+      content::WebContentsObserver(web_contents) {
   auto* preloading_data =
       content::PreloadingData::GetOrCreateForWebContents(web_contents);
   SetIsNavigationInDomainCallback(preloading_data);
@@ -63,6 +64,33 @@
 
 SearchPreloadPipelineManager::~SearchPreloadPipelineManager() = default;
 
+void SearchPreloadPipelineManager::DidFinishNavigation(
+    content::NavigationHandle* navigation_handle) {
+  const bool is_primary_main_frame_navigation =
+      navigation_handle->HasCommitted() &&
+      navigation_handle->IsInPrimaryMainFrame() &&
+      !navigation_handle->IsSameDocument();
+  if (!is_primary_main_frame_navigation) {
+    return;
+  }
+
+  content::BrowserContext* browser_context =
+      GetWebContents().GetBrowserContext();
+  if (!browser_context) {
+    return;
+  }
+
+  // Invalidate a pipeline if it is likely used.
+  std::optional<GURL> maybe_canonical_url = GetCanonicalUrlForSearchPreload(
+      *browser_context, navigation_handle->GetURL());
+  if (!maybe_canonical_url.has_value()) {
+    return;
+  }
+  const GURL& canonical_url = maybe_canonical_url.value();
+
+  pipelines_.erase(canonical_url);
+}
+
 void SearchPreloadPipelineManager::ClearPreloads() {
   pipelines_.clear();
 }
@@ -169,7 +197,8 @@
                               /*is_navigation_likely=*/false);
   pipelines_[canonical_url]->StartPrefetch(
       GetWebContents(), search_preload_service, prefetch_url,
-      chrome_preloading_predictor::kDefaultSearchEngine, no_vary_search_hint);
+      chrome_preloading_predictor::kDefaultSearchEngine, no_vary_search_hint,
+      /*is_navigation_likely=*/false);
 
   // Trigger prerender without waiting prefetch.
   //
@@ -289,7 +318,8 @@
   pipelines_[canonical_url]->UpdateConfidence(GetWebContents(), 100);
   return pipelines_[canonical_url]->StartPrefetch(
       GetWebContents(), search_preload_service, prefetch_url, predictor,
-      no_vary_search_hint);
+      no_vary_search_hint,
+      /*is_navigation_likely=*/true);
 }
 
 bool SearchPreloadPipelineManager::InvalidatePipelineForTesting(
diff --git a/chrome/browser/preloading/search_preload/search_preload_pipeline_manager.h b/chrome/browser/preloading/search_preload/search_preload_pipeline_manager.h
index 05acdb6f..31af94816 100644
--- a/chrome/browser/preloading/search_preload/search_preload_pipeline_manager.h
+++ b/chrome/browser/preloading/search_preload/search_preload_pipeline_manager.h
@@ -8,6 +8,7 @@
 #include "base/containers/flat_map.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/preloading/search_preload/search_preload_pipeline.h"
+#include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
 #include "url/gurl.h"
 
@@ -30,7 +31,8 @@
 // - Manages preload pipelines per WebContents.
 // - Starts preloads in response to Omnibox events.
 class SearchPreloadPipelineManager
-    : public content::WebContentsUserData<SearchPreloadPipelineManager> {
+    : public content::WebContentsUserData<SearchPreloadPipelineManager>,
+      public content::WebContentsObserver {
  public:
   ~SearchPreloadPipelineManager() override;
 
@@ -46,6 +48,10 @@
     return weak_factory_.GetWeakPtr();
   }
 
+  // Implements `content::WebContentsObserver`
+  void DidFinishNavigation(
+      content::NavigationHandle* navigation_handle) override;
+
   // Clears all preloads.
   void ClearPreloads();
 
diff --git a/chrome/browser/preloading/search_preload/search_preload_service.cc b/chrome/browser/preloading/search_preload/search_preload_service.cc
index 12314c5e..1ddece1 100644
--- a/chrome/browser/preloading/search_preload/search_preload_service.cc
+++ b/chrome/browser/preloading/search_preload/search_preload_service.cc
@@ -115,6 +115,17 @@
   }
 }
 
+void SearchPreloadService::OnOnSuggestPrefetchCompletedOrFailed(
+    const network::URLLoaderCompletionStatus& completion_status,
+    const std::optional<int>& response_code) {
+  const bool is_2xx = response_code.has_value() &&
+                      (200 <= response_code && response_code < 300);
+  if (!is_2xx) {
+    pause_triggering_until_ = base::TimeTicks::Now() +
+                              features::kDsePreload2ErrorBackoffDuration.Get();
+  }
+}
+
 SearchPreloadPipelineManager&
 SearchPreloadService::GetOrCreatePipelineManagerWithLimit(
     content::WebContents& web_contents) {
@@ -146,6 +157,10 @@
     return;
   }
 
+  if (base::TimeTicks::Now() < pause_triggering_until_) {
+    return;
+  }
+
   GetOrCreatePipelineManagerWithLimit(*web_contents)
       .OnAutocompleteResultChanged(*profile_, GetWeakPtr(), result,
                                    no_vary_search_data_cache_);
@@ -160,6 +175,10 @@
     return false;
   }
 
+  if (base::TimeTicks::Now() < pause_triggering_until_) {
+    return false;
+  }
+
   return GetOrCreatePipelineManagerWithLimit(*web_contents)
       .OnNavigationLikely(*profile_, GetWeakPtr(), match, navigation_predictor,
                           no_vary_search_data_cache_);
diff --git a/chrome/browser/preloading/search_preload/search_preload_service.h b/chrome/browser/preloading/search_preload/search_preload_service.h
index c4f4115..1c5ffdfe 100644
--- a/chrome/browser/preloading/search_preload/search_preload_service.h
+++ b/chrome/browser/preloading/search_preload/search_preload_service.h
@@ -73,6 +73,9 @@
   void ClearPreloads();
 
   void OnPrefetchHeadReceived(const network::mojom::URLResponseHead& head);
+  void OnOnSuggestPrefetchCompletedOrFailed(
+      const network::URLLoaderCompletionStatus& completion_status,
+      const std::optional<int>& response_code);
 
   // Called when autocomplete is updated.
   void OnAutocompleteResultChanged(content::WebContents* web_contents,
@@ -112,6 +115,9 @@
   // prefetch.
   std::optional<net::HttpNoVarySearchData> no_vary_search_data_cache_;
 
+  // If prefetch on-suggest failed, pause triggering preloads until this time.
+  base::TimeTicks pause_triggering_until_;
+
   base::WeakPtrFactory<SearchPreloadService> weak_factory_{this};
 };
 
diff --git a/chrome/browser/sync/test/integration/single_client_secondary_account_sync_test.cc b/chrome/browser/sync/test/integration/single_client_secondary_account_sync_test.cc
index c95aebe7..5c4a281 100644
--- a/chrome/browser/sync/test/integration/single_client_secondary_account_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_secondary_account_sync_test.cc
@@ -58,38 +58,7 @@
   base::CallbackListSubscription test_signin_client_subscription_;
 };
 
-// The unconsented primary account isn't supported on ChromeOS.
-#if !BUILDFLAG(IS_CHROMEOS)
-IN_PROC_BROWSER_TEST_F(SingleClientSecondaryAccountSyncTest,
-                       StartsSyncTransportOnSignin) {
-  ASSERT_TRUE(SetupClients());
-
-  // Signing in (without granting sync consent or explicitly setting up Sync)
-  // should trigger starting the Sync machinery in standalone transport mode.
-  secondary_account_helper::SignInUnconsentedAccount(
-      profile(), &test_url_loader_factory_, "user@email.com");
-
-  EXPECT_TRUE(GetClient(0)->AwaitSyncTransportActive());
-
-  EXPECT_EQ(syncer::SyncService::TransportState::ACTIVE,
-            GetSyncService(0)->GetTransportState());
-
-  ASSERT_FALSE(GetSyncService(0)
-                   ->GetUserSettings()
-                   ->IsInitialSyncFeatureSetupComplete());
-
-  EXPECT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled());
-  EXPECT_FALSE(GetSyncService(0)->IsSyncFeatureActive());
-
-  // Make sure that only the allowed types got activated. Note that, depending
-  // on some other feature flags, not all of the allowed types are necessarily
-  // active, and that's okay.
-  syncer::DataTypeSet bad_types =
-      base::Difference(GetSyncService(0)->GetActiveDataTypes(),
-                       AllowedTypesInStandaloneTransportMode());
-  EXPECT_TRUE(bad_types.empty()) << syncer::DataTypeSetToDebugString(bad_types);
-}
-#else
+#if BUILDFLAG(IS_CHROMEOS)
 IN_PROC_BROWSER_TEST_F(SingleClientSecondaryAccountSyncTest,
                        DoesNotStartSyncTransportOnSignin) {
   ASSERT_TRUE(SetupClients());
@@ -102,7 +71,7 @@
   EXPECT_EQ(syncer::SyncService::TransportState::DISABLED,
             GetSyncService(0)->GetTransportState());
 }
-#endif  // !BUILDFLAG(IS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS)
 
 // ChromeOS doesn't support changes to the primary account after startup, so
 // this test doesn't apply.
diff --git a/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc b/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc
index 13f91cc..cb06b47 100644
--- a/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc
@@ -10,6 +10,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/test/integration/encryption_helper.h"
+#include "chrome/browser/sync/test/integration/secondary_account_helper.h"
 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
 #include "chrome/browser/sync/test/integration/sync_service_impl_harness.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
@@ -24,6 +25,8 @@
 #include "components/sync/test/nigori_test_utils.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/test_launcher.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
 
 #if BUILDFLAG(IS_CHROMEOS)
 #include "ash/constants/ash_features.h"
@@ -31,6 +34,18 @@
 
 namespace {
 
+using testing::ContainerEq;
+
+constexpr syncer::DataTypeSet kTypesGatedBehindHistoryOptIn{
+    syncer::COLLABORATION_GROUP,
+    syncer::HISTORY,
+    syncer::HISTORY_DELETE_DIRECTIVES,
+    syncer::SAVED_TAB_GROUP,
+    syncer::SHARED_TAB_GROUP_DATA,
+    syncer::SHARED_TAB_GROUP_ACCOUNT_DATA,
+    syncer::SESSIONS,
+    syncer::USER_EVENTS};
+
 #if !BUILDFLAG(IS_ANDROID)
 base::FilePath GetTestFilePathForCacheGuid() {
   base::FilePath user_data_path;
@@ -63,14 +78,34 @@
 };
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
-class SingleClientStandaloneTransportSyncTest : public SyncTest {
+class SingleClientStandaloneTransportSyncTest
+    : public SyncTest,
+      public testing::WithParamInterface<bool> {
  public:
-  SingleClientStandaloneTransportSyncTest() : SyncTest(SINGLE_CLIENT) {}
+  SingleClientStandaloneTransportSyncTest() : SyncTest(SINGLE_CLIENT) {
+    if (GetParam()) {
+      override_features_
+          .InitWithFeatures(/*enabled_features=*/
+                            {syncer::
+                                 kSyncEnableContactInfoDataTypeForCustomPassphraseUsers,
+                             syncer::kReplaceSyncPromosWithSignInPromos},
+                            /*disabled_features=*/{});
+    } else {
+      override_features_.InitWithFeatures(
+          /*enabled_features=*/{},
+          /*disabled_features=*/
+          {syncer::kSyncEnableContactInfoDataTypeForCustomPassphraseUsers,
+           syncer::kReplaceSyncPromosWithSignInPromos});
+    }
+  }
+
+ private:
+  base::test::ScopedFeatureList override_features_;
 };
 
 // On Chrome OS sync auto-starts on sign-in.
 #if !BUILDFLAG(IS_CHROMEOS)
-IN_PROC_BROWSER_TEST_F(SingleClientStandaloneTransportSyncTest,
+IN_PROC_BROWSER_TEST_P(SingleClientStandaloneTransportSyncTest,
                        StartsSyncTransportOnSignin) {
   ASSERT_TRUE(SetupClients());
 
@@ -94,20 +129,16 @@
 
   EXPECT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled());
   EXPECT_FALSE(GetSyncService(0)->IsSyncFeatureActive());
-
-  // Make sure that only the allowed types got activated. Note that, depending
-  // on some other feature flags, not all of the allowed types are necessarily
-  // active, and that's okay.
-  syncer::DataTypeSet bad_types =
-      base::Difference(GetSyncService(0)->GetActiveDataTypes(),
-                       AllowedTypesInStandaloneTransportMode());
-  EXPECT_TRUE(bad_types.empty()) << syncer::DataTypeSetToDebugString(bad_types);
 }
 #endif  // !BUILDFLAG(IS_CHROMEOS)
 
 #if !BUILDFLAG(IS_ANDROID)
-IN_PROC_BROWSER_TEST_F(SingleClientStandaloneTransportSyncTest,
+IN_PROC_BROWSER_TEST_P(SingleClientStandaloneTransportSyncTest,
                        SwitchesBetweenTransportAndFeature) {
+  const syncer::DataType kDataTypeExcludedInTransportMode = syncer::AUTOFILL;
+  CHECK(!AllowedTypesInStandaloneTransportMode().Has(
+      kDataTypeExcludedInTransportMode));
+
   ASSERT_TRUE(SetupClients());
 
   // Setup a primary account, but don't actually enable Sync-the-feature (so
@@ -119,10 +150,26 @@
             GetSyncService(0)->GetTransportState());
   ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureActive());
 
-  syncer::DataTypeSet bad_types =
-      base::Difference(GetSyncService(0)->GetActiveDataTypes(),
-                       AllowedTypesInStandaloneTransportMode());
-  EXPECT_TRUE(bad_types.empty()) << syncer::DataTypeSetToDebugString(bad_types);
+  syncer::DataTypeSet expected_types = Difference(
+      AllowedTypesInStandaloneTransportMode(), kTypesGatedBehindHistoryOptIn);
+
+  // Bookmarks and reading list require a separate opt in, unless
+  // `syncer::kReplaceSyncPromosWithSignInPromos` is enabled.
+  // TODO(crbug.com/424124636): This shouldn't be necessary if
+  // `kReplaceSyncPromosWithSignInPromos` is enabled.
+  expected_types.Remove(syncer::BOOKMARKS);
+  expected_types.Remove(syncer::READING_LIST);
+
+  // TODO(crbug.com/424124636): The types below should probably be excluded.
+  if (base::FeatureList::IsEnabled(
+          syncer::kReplaceSyncPromosWithSignInPromos)) {
+    expected_types.Put(syncer::PRODUCT_COMPARISON);
+    expected_types.Put(syncer::AUTOFILL_WALLET_METADATA);
+    expected_types.Put(syncer::AUTOFILL_WALLET_OFFER);
+  }
+
+  ASSERT_THAT(GetSyncService(0)->GetActiveDataTypes(),
+              ContainerEq(expected_types));
 
   // Turn Sync-the-feature on.
   ASSERT_TRUE(GetClient(0)->SetupSync());
@@ -132,18 +179,18 @@
   EXPECT_TRUE(GetSyncService(0)->IsSyncFeatureActive());
   // Make sure that some data type which is not allowed in transport-only mode
   // got activated.
-  ASSERT_FALSE(AllowedTypesInStandaloneTransportMode().Has(syncer::AUTOFILL));
   ASSERT_TRUE(GetSyncService(0)->GetUserSettings()->GetSelectedTypes().Has(
       syncer::UserSelectableType::kAutofill));
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::AUTOFILL));
+  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(
+      kDataTypeExcludedInTransportMode));
 }
-#endif  // BUILDFLAG(IS_ANDROID)
+#endif  // !BUILDFLAG(IS_ANDROID)
 
 // Tests the behavior of receiving a "Reset Sync" operation from the dashboard
 // while Sync-the-feature is active: On non-ChromeOS, this signs the user out,
 // so Sync will be fully disabled. On ChromeOS, there is no sign-out, so
 // Sync-the-transport will start.
-IN_PROC_BROWSER_TEST_F(SingleClientStandaloneTransportSyncTest,
+IN_PROC_BROWSER_TEST_P(SingleClientStandaloneTransportSyncTest,
                        HandlesResetFromDashboardWhenSyncActive) {
   ASSERT_TRUE(SetupClients());
 
@@ -173,6 +220,39 @@
   EXPECT_EQ(syncer::SyncService::TransportState::ACTIVE,
             GetSyncService(0)->GetTransportState());
   EXPECT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled());
+
+  // There are no immediate plans to launch additional types on ChromeOS, so the
+  // list is hardcoded here.
+  EXPECT_THAT(GetSyncService(0)->GetActiveDataTypes(),
+              ContainerEq(syncer::DataTypeSet{
+                  syncer::AUTOFILL_WALLET_CREDENTIAL,
+                  syncer::AUTOFILL_WALLET_DATA,
+                  syncer::AUTOFILL_WALLET_USAGE,
+                  syncer::DEVICE_INFO,
+                  syncer::NIGORI,
+                  syncer::USER_CONSENTS,
+                  syncer::SEND_TAB_TO_SELF,
+                  syncer::SECURITY_EVENTS,
+                  syncer::SHARING_MESSAGE,
+                  syncer::ARC_PACKAGE,
+                  syncer::OS_PREFERENCES,
+                  syncer::OS_PRIORITY_PREFERENCES,
+                  // TODO(crbug.com/424698545): This seems off: many of the
+                  // datatypes below should not start.
+                  syncer::APP_LIST,
+                  syncer::COLLABORATION_GROUP,
+                  syncer::CONTACT_INFO,
+                  syncer::EXTENSIONS,
+                  syncer::EXTENSION_SETTINGS,
+                  syncer::INCOMING_PASSWORD_SHARING_INVITATION,
+                  syncer::OUTGOING_PASSWORD_SHARING_INVITATION,
+                  syncer::PASSWORDS,
+                  syncer::PRODUCT_COMPARISON,
+                  syncer::SAVED_TAB_GROUP,
+                  syncer::SHARED_TAB_GROUP_DATA,
+                  syncer::SHARED_TAB_GROUP_ACCOUNT_DATA,
+                  syncer::WEBAUTHN_CREDENTIAL,
+              }));
 #else
   // On platforms other than Ash, the "Reset Sync" operation should revoke
   // the Sync consent. On Mobile, "Reset Sync" also clears the primary account.
@@ -189,7 +269,7 @@
 #if !BUILDFLAG(IS_ANDROID)
 // Regression test for crbug.com/955989 that verifies the cache GUID is not
 // reset upon restart of the browser, in standalone transport mode.
-IN_PROC_BROWSER_TEST_F(SingleClientStandaloneTransportSyncTest,
+IN_PROC_BROWSER_TEST_P(SingleClientStandaloneTransportSyncTest,
                        PRE_ReusesSameCacheGuid) {
   ASSERT_TRUE(SetupClients());
   ASSERT_TRUE(GetClient(0)->SignInPrimaryAccount());
@@ -220,7 +300,7 @@
   ASSERT_TRUE(base::WriteFile(GetTestFilePathForCacheGuid(), cache_guid));
 }
 
-IN_PROC_BROWSER_TEST_F(SingleClientStandaloneTransportSyncTest,
+IN_PROC_BROWSER_TEST_P(SingleClientStandaloneTransportSyncTest,
                        ReusesSameCacheGuid) {
   ASSERT_TRUE(SetupClients());
   ASSERT_FALSE(GetSyncService(0)->HasDisableReason(
@@ -255,40 +335,8 @@
 }
 #endif  // BUILDFLAG(IS_ANDROID)
 
-class SingleClientStandaloneTransportWithReplaceSyncWithSigninSyncTest
-    : public SingleClientStandaloneTransportSyncTest {
- public:
-  SingleClientStandaloneTransportWithReplaceSyncWithSigninSyncTest() {
-    override_features_.InitWithFeatures(
-        /*enabled_features=*/
-        {switches::kEnablePreferencesAccountStorage,
-         syncer::kSeparateLocalAndAccountSearchEngines,
-         syncer::kSyncEnableContactInfoDataTypeForCustomPassphraseUsers,
-         syncer::kReplaceSyncPromosWithSignInPromos,
-         syncer::kSyncAutofillWalletCredentialData},
-        /*disabled_features=*/{});
-  }
-  ~SingleClientStandaloneTransportWithReplaceSyncWithSigninSyncTest() override =
-      default;
-
-  bool WaitForPassphraseRequired() {
-    return PassphraseRequiredChecker(GetSyncService(0)).Wait();
-  }
-
-  bool WaitForPassphraseAccepted() {
-    return PassphraseAcceptedChecker(GetSyncService(0)).Wait();
-  }
-
- private:
-  base::test::ScopedFeatureList override_features_;
-};
-
-// This test is disabled on CrOS as the signed in, non-syncing state does not
-// exist.
-#if !BUILDFLAG(IS_CHROMEOS)
-IN_PROC_BROWSER_TEST_F(
-    SingleClientStandaloneTransportWithReplaceSyncWithSigninSyncTest,
-    DataTypesEnabledInTransportModeWithoutHistorySync) {
+IN_PROC_BROWSER_TEST_P(SingleClientStandaloneTransportSyncTest,
+                       DataTypesEnabledInTransportModeWithoutAdditionalOptIns) {
   ASSERT_TRUE(SetupClients());
   // Sign in, without turning on Sync-the-feature.
   ASSERT_TRUE(GetClient(0)->SignInPrimaryAccount());
@@ -299,79 +347,116 @@
   ASSERT_FALSE(GetSyncService(0)->GetUserSettings()->GetSelectedTypes().Has(
       syncer::UserSelectableType::kHistory));
 
-  // With `kReplaceSyncPromosWithSignInPromos` and by default (without opting
-  // into history), all the history-related should be disabled in transport
-  // mode.
-  EXPECT_FALSE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::HISTORY));
-  EXPECT_FALSE(GetSyncService(0)->GetActiveDataTypes().Has(
-      syncer::HISTORY_DELETE_DIRECTIVES));
-  EXPECT_FALSE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::SESSIONS));
-  EXPECT_FALSE(
-      GetSyncService(0)->GetActiveDataTypes().Has(syncer::USER_EVENTS));
+  // Make sure that only the allowed types got activated.
+  syncer::DataTypeSet expected_types = Difference(
+      AllowedTypesInStandaloneTransportMode(), kTypesGatedBehindHistoryOptIn);
 
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::PREFERENCES));
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(
-      syncer::PRIORITY_PREFERENCES));
+#if !BUILDFLAG(IS_ANDROID)
+  // Bookmarks and reading list require a separate opt in, unless
+  // `syncer::kReplaceSyncPromosWithSignInPromos` is enabled.
+  // TODO(crbug.com/424124636): This shouldn't be necessary if
+  // `kReplaceSyncPromosWithSignInPromos` is enabled.
+  expected_types.Remove(syncer::BOOKMARKS);
+  expected_types.Remove(syncer::READING_LIST);
+#endif  // !BUILDFLAG(IS_ANDROID)
 
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(
-      syncer::AUTOFILL_WALLET_CREDENTIAL));
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(
-      syncer::AUTOFILL_WALLET_DATA));
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(
-      syncer::AUTOFILL_WALLET_METADATA));
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(
-      syncer::AUTOFILL_WALLET_OFFER));
-  EXPECT_TRUE(
-      GetSyncService(0)->GetActiveDataTypes().Has(syncer::CONTACT_INFO));
+  EXPECT_THAT(GetSyncService(0)->GetActiveDataTypes(),
+              ContainerEq(expected_types));
 }
 
-IN_PROC_BROWSER_TEST_F(
-    SingleClientStandaloneTransportWithReplaceSyncWithSigninSyncTest,
-    DataTypesEnabledInTransportModeWithHistorySync) {
+IN_PROC_BROWSER_TEST_P(SingleClientStandaloneTransportSyncTest,
+                       DataTypesEnabledInTransportModeWithHistorySync) {
+  // Opting into history is only meaningful if
+  // `kReplaceSyncPromosWithSignInPromos` is enabled.
+  if (!GetParam()) {
+    GTEST_SKIP();
+  }
+
   ASSERT_TRUE(SetupClients());
   // Sign in, without turning on Sync-the-feature.
   ASSERT_TRUE(GetClient(0)->SignInPrimaryAccount());
+  ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive());
+  ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE,
+            GetSyncService(0)->GetTransportState());
   ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled());
+  ASSERT_FALSE(GetSyncService(0)->GetUserSettings()->GetSelectedTypes().Has(
+      syncer::UserSelectableType::kHistory));
 
   // Opt in to history and tabs.
   GetSyncService(0)->GetUserSettings()->SetSelectedType(
       syncer::UserSelectableType::kHistory, true);
   GetSyncService(0)->GetUserSettings()->SetSelectedType(
       syncer::UserSelectableType::kTabs, true);
+#if !BUILDFLAG(IS_ANDROID)
+  GetSyncService(0)->GetUserSettings()->SetSelectedType(
+      syncer::UserSelectableType::kSavedTabGroups, true);
+#endif  // !BUILDFLAG(IS_ANDROID)
 
   ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive());
   ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE,
             GetSyncService(0)->GetTransportState());
 
-  // With `kReplaceSyncPromosWithSignInPromos`, all the history-related types
-  // should be enabled in transport mode.
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::HISTORY));
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(
-      syncer::HISTORY_DELETE_DIRECTIVES));
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::SESSIONS));
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::USER_EVENTS));
+  // With the history opt in, all types that can run in transport mode should
+  // be active.
+  syncer::DataTypeSet expected_types = AllowedTypesInStandaloneTransportMode();
 
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::PREFERENCES));
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(
-      syncer::PRIORITY_PREFERENCES));
+#if !BUILDFLAG(IS_ANDROID)
+  // Bookmarks and reading list require a separate opt in, unless
+  // `syncer::kReplaceSyncPromosWithSignInPromos` is enabled.
+  // TODO(crbug.com/424124636): This shouldn't be necessary if
+  // `kReplaceSyncPromosWithSignInPromos` is enabled.
+  expected_types.Remove(syncer::BOOKMARKS);
+  expected_types.Remove(syncer::READING_LIST);
+#endif  // !BUILDFLAG(IS_ANDROID)
 
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(
-      syncer::AUTOFILL_WALLET_CREDENTIAL));
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(
-      syncer::AUTOFILL_WALLET_DATA));
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(
-      syncer::AUTOFILL_WALLET_METADATA));
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(
-      syncer::AUTOFILL_WALLET_OFFER));
-  EXPECT_TRUE(
-      GetSyncService(0)->GetActiveDataTypes().Has(syncer::CONTACT_INFO));
+  EXPECT_THAT(GetSyncService(0)->GetActiveDataTypes(),
+              ContainerEq(expected_types));
 }
-#endif  // !BUILDFLAG(IS_CHROMEOS)
+
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS)
+IN_PROC_BROWSER_TEST_P(SingleClientStandaloneTransportSyncTest,
+                       DataTypesEnabledForImplicitSignIn) {
+  ASSERT_TRUE(SetupClients());
+
+  // Signing in (without granting sync consent or explicitly setting up Sync)
+  // should trigger starting the Sync machinery in standalone transport mode.
+  secondary_account_helper::ImplicitSignInUnconsentedAccount(
+      GetProfile(0), &test_url_loader_factory_, "user@email.com");
+
+  ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive());
+  ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE,
+            GetSyncService(0)->GetTransportState());
+
+  // There are no immediate plans to launch additional types to implicitly
+  // signed in users, so the list is hardcoded here.
+  syncer::DataTypeSet expected_types{syncer::AUTOFILL_WALLET_CREDENTIAL,
+                                     syncer::AUTOFILL_WALLET_DATA,
+                                     syncer::AUTOFILL_WALLET_USAGE,
+                                     syncer::DEVICE_INFO,
+                                     syncer::NIGORI,
+                                     syncer::PRIORITY_PREFERENCES,
+                                     syncer::USER_CONSENTS,
+                                     syncer::SEND_TAB_TO_SELF,
+                                     syncer::SECURITY_EVENTS,
+                                     syncer::SHARING_MESSAGE};
+
+  // TODO(crbug.com/424124636): The types below should probably be excluded.
+  if (base::FeatureList::IsEnabled(
+          syncer::kReplaceSyncPromosWithSignInPromos)) {
+    expected_types.Put(syncer::PRODUCT_COMPARISON);
+    expected_types.Put(syncer::AUTOFILL_WALLET_METADATA);
+    expected_types.Put(syncer::AUTOFILL_WALLET_OFFER);
+  }
+
+  EXPECT_THAT(GetSyncService(0)->GetActiveDataTypes(),
+              ContainerEq(expected_types));
+}
+#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS)
 
 // TODO(crbug.com/40200835): Android currently doesn't support PRE_ tests.
 #if !BUILDFLAG(IS_ANDROID)
-IN_PROC_BROWSER_TEST_F(
-    SingleClientStandaloneTransportWithReplaceSyncWithSigninSyncTest,
+IN_PROC_BROWSER_TEST_P(
+    SingleClientStandaloneTransportSyncTest,
     PRE_DataTypesEnabledInTransportModeWithCustomPassphrase) {
   // There's a custom passphrase on the server.
   const syncer::KeyParamsForTesting kKeyParams =
@@ -382,63 +467,89 @@
   ASSERT_TRUE(SetupClients());
   // Sign in, without turning on Sync-the-feature.
   ASSERT_TRUE(GetClient(0)->SignInPrimaryAccount());
-  ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled());
-
-  // Opt in to history and tabs.
-  GetSyncService(0)->GetUserSettings()->SetSelectedType(
-      syncer::UserSelectableType::kHistory, true);
-  GetSyncService(0)->GetUserSettings()->SetSelectedType(
-      syncer::UserSelectableType::kTabs, true);
-  // Preferences are opted-into by default.
-  ASSERT_TRUE(GetSyncService(0)->GetUserSettings()->GetSelectedTypes().Has(
-      syncer::UserSelectableType::kPreferences));
-
-  ASSERT_TRUE(WaitForPassphraseRequired());
+  ASSERT_TRUE(PassphraseRequiredChecker(GetSyncService(0)).Wait());
   ASSERT_TRUE(GetSyncService(0)->GetUserSettings()->SetDecryptionPassphrase(
       kKeyParams.password));
-  ASSERT_TRUE(WaitForPassphraseAccepted());
+  ASSERT_TRUE(PassphraseAcceptedChecker(GetSyncService(0)).Wait());
 
   ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive());
   ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE,
             GetSyncService(0)->GetTransportState());
+  ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled());
 
-  // With a custom passphrase, the actual HISTORY types are not supported.
-  EXPECT_FALSE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::HISTORY));
-  EXPECT_FALSE(GetSyncService(0)->GetActiveDataTypes().Has(
-      syncer::HISTORY_DELETE_DIRECTIVES));
-  EXPECT_FALSE(
-      GetSyncService(0)->GetActiveDataTypes().Has(syncer::USER_EVENTS));
-  // But SESSIONS aka Open Tabs still works.
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::SESSIONS));
-
-  // With `kReplaceSyncPromosWithSignInPromos`, both PREFERENCES and
-  // PRIORITY_PREFERENCES should be enabled in transport mode.
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::PREFERENCES));
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(
-      syncer::PRIORITY_PREFERENCES));
+  // Make sure that only the allowed types got activated.
+  syncer::DataTypeSet expected_types = Difference(
+      AllowedTypesInStandaloneTransportMode(), kTypesGatedBehindHistoryOptIn);
 
   // CONTACT_INFO should be disabled by default for explicit-passphrase users.
-  EXPECT_FALSE(
-      GetSyncService(0)->GetActiveDataTypes().Has(syncer::CONTACT_INFO));
+  expected_types.Remove(syncer::CONTACT_INFO);
 
-  // Enabling kAutofill to enable CONTACT_INFO.
-  GetSyncService(0)->GetUserSettings()->SetSelectedType(
-      syncer::UserSelectableType::kAutofill, true);
+  // Bookmarks and reading list require a separate opt in, unless
+  // `syncer::kReplaceSyncPromosWithSignInPromos` is enabled.
+  // TODO(crbug.com/424124636): This shouldn't be necessary if
+  // `kReplaceSyncPromosWithSignInPromos` is enabled.
+  expected_types.Remove(syncer::BOOKMARKS);
+  expected_types.Remove(syncer::READING_LIST);
 
-  ASSERT_NE(syncer::SyncService::TransportState::ACTIVE,
-            GetSyncService(0)->GetTransportState());
-  ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive());
+  ASSERT_THAT(GetSyncService(0)->GetActiveDataTypes(),
+              ContainerEq(expected_types));
 
-  // CONTACT_INFO should be enabled.
-  EXPECT_TRUE(
-      GetSyncService(0)->GetActiveDataTypes().Has(syncer::CONTACT_INFO));
+  // Opting into history is only meaningful if
+  // `kReplaceSyncPromosWithSignInPromos` is enabled.
+  if (GetParam()) {
+    // Opt in to history and tabs.
+    GetSyncService(0)->GetUserSettings()->SetSelectedType(
+        syncer::UserSelectableType::kHistory, true);
+    GetSyncService(0)->GetUserSettings()->SetSelectedType(
+        syncer::UserSelectableType::kTabs, true);
+    GetSyncService(0)->GetUserSettings()->SetSelectedType(
+        syncer::UserSelectableType::kSavedTabGroups, true);
+
+    ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive());
+    ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE,
+              GetSyncService(0)->GetTransportState());
+
+    syncer::DataTypeSet expected_types_after_history_opt_in =
+        AllowedTypesInStandaloneTransportMode();
+
+    // CONTACT_INFO should remain disabled since it's gated by kAutofill.
+    expected_types_after_history_opt_in.Remove(syncer::CONTACT_INFO);
+
+    // With a custom passphrase, the actual HISTORY types are not supported.
+    expected_types_after_history_opt_in.Remove(syncer::HISTORY);
+    expected_types_after_history_opt_in.Remove(
+        syncer::HISTORY_DELETE_DIRECTIVES);
+    expected_types_after_history_opt_in.Remove(syncer::USER_EVENTS);
+
+    // But SESSIONS aka Open Tabs still works.
+    CHECK(expected_types_after_history_opt_in.Has(syncer::SESSIONS));
+
+#if !BUILDFLAG(IS_ANDROID)
+    // On desktop, bookmarks and reading list require a separate opt in.
+    // TODO(crbug.com/424124636): This shouldn't be necessary if
+    // `kReplaceSyncPromosWithSignInPromos` is enabled.
+    expected_types_after_history_opt_in.Remove(syncer::BOOKMARKS);
+    expected_types_after_history_opt_in.Remove(syncer::READING_LIST);
+#endif  // !BUILDFLAG(IS_ANDROID)
+
+    EXPECT_THAT(GetSyncService(0)->GetActiveDataTypes(),
+                ContainerEq(expected_types_after_history_opt_in));
+
+    // Enabling kAutofill to enable CONTACT_INFO.
+    GetSyncService(0)->GetUserSettings()->SetSelectedType(
+        syncer::UserSelectableType::kAutofill, true);
+    ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive());
+
+    // CONTACT_INFO should be enabled.
+    EXPECT_TRUE(
+        GetSyncService(0)->GetActiveDataTypes().Has(syncer::CONTACT_INFO));
+  }
 }
 
 // Tests that a custom passphrase user's opt-in to kAutofill (which happened in
 // the PRE_ test) survives a browser restart.
-IN_PROC_BROWSER_TEST_F(
-    SingleClientStandaloneTransportWithReplaceSyncWithSigninSyncTest,
-    DataTypesEnabledInTransportModeWithCustomPassphrase) {
+IN_PROC_BROWSER_TEST_P(SingleClientStandaloneTransportSyncTest,
+                       DataTypesEnabledInTransportModeWithCustomPassphrase) {
   ASSERT_TRUE(SetupClients());
 
   ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled());
@@ -446,152 +557,30 @@
   ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE,
             GetSyncService(0)->GetTransportState());
 
-  // CONTACT_INFO should be enabled after restarting.
-  EXPECT_TRUE(
-      GetSyncService(0)->GetActiveDataTypes().Has(syncer::CONTACT_INFO));
+  // CONTACT_INFO should be enabled after restarting, if and only if
+  // `kSyncEnableContactInfoDataTypeForCustomPassphraseUsers` is enabled.
+  EXPECT_EQ(GetSyncService(0)->GetActiveDataTypes().Has(syncer::CONTACT_INFO),
+            GetParam());
 }
 #endif  // BUILDFLAG(IS_ANDROID)
 
-class SingleClientStandaloneTransportWithoutReplaceSyncWithSigninSyncTest
-    : public SingleClientStandaloneTransportSyncTest {
- public:
-  SingleClientStandaloneTransportWithoutReplaceSyncWithSigninSyncTest() {
-#if BUILDFLAG(IS_ANDROID)
-    // On Android, PREFERENCES is active in transport mode only with
-    // `kReplaceSyncPromosWithSignInPromos` enabled.
-    override_features_.InitWithFeatures(
-        /*enabled_features=*/{switches::kEnablePreferencesAccountStorage},
-        /*disabled_features=*/{syncer::kReplaceSyncPromosWithSignInPromos});
+INSTANTIATE_TEST_SUITE_P(ReplaceSyncWithSignin,
+                         SingleClientStandaloneTransportSyncTest,
+#if BUILDFLAG(IS_CHROMEOS)
+                         // On ChromeOS, the behavior after enabling
+                         // `syncer::kReplaceSyncPromosWithSignInPromos` is
+                         // unspecified, so no need to test it.
+                         ::testing::Values(false));
+#elif BUILDFLAG(IS_ANDROID)
+                         // On Android, the feature has been enabled by
+                         // default for a long time. There is no need to
+                         // test the flag-disabled case.
+                         ::testing::Values(true));
 #else
-    // On Desktop, PREFERENCES, SEARCH_ENGINES and THEMES are active in
-    // transport mode irrespective of `kReplaceSyncPromosWithSignInPromos`.
-    // TODO(crbug.com/330677712): Merge this with the Android branch once
-    // `kReplaceSyncPromosWithSignInPromos` is removed.
-    override_features_.InitWithFeatures(
-        /*enabled_features=*/{switches::kEnablePreferencesAccountStorage,
-                              syncer::kSeparateLocalAndAccountSearchEngines,
-                              syncer::kSeparateLocalAndAccountThemes},
-        /*disabled_features=*/{syncer::kReplaceSyncPromosWithSignInPromos});
-#endif  // BUILDFLAG(IS_ANDROID)
-  }
-  ~SingleClientStandaloneTransportWithoutReplaceSyncWithSigninSyncTest()
-      override = default;
+                         ::testing::Bool());
+#endif
 
- private:
-  base::test::ScopedFeatureList override_features_;
-};
-
-#if BUILDFLAG(IS_ANDROID)
-
-IN_PROC_BROWSER_TEST_F(
-    SingleClientStandaloneTransportWithoutReplaceSyncWithSigninSyncTest,
-    DataTypesNotEnabledInTransportMode) {
-  ASSERT_TRUE(SetupClients());
-  // Sign in, without turning on Sync-the-feature.
-  ASSERT_TRUE(GetClient(0)->SignInPrimaryAccount());
-  ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled());
-
-  // Without `kReplaceSyncPromosWithSignInPromos`, neither History/Tabs nor
-  // Preferences are supported in transport mode, so they're reported as not
-  // selected even if the user explicitly tries to turn them on.
-  syncer::UserSelectableTypeSet types =
-      GetSyncService(0)->GetUserSettings()->GetRegisteredSelectableTypes();
-  ASSERT_TRUE(types.HasAll({syncer::UserSelectableType::kHistory,
-                            syncer::UserSelectableType::kTabs,
-                            syncer::UserSelectableType::kPreferences}));
-  GetSyncService(0)->GetUserSettings()->SetSelectedTypes(
-      /*sync_everything=*/true, types);
-  ASSERT_FALSE(GetSyncService(0)->GetUserSettings()->GetSelectedTypes().Has(
-      syncer::UserSelectableType::kHistory));
-  ASSERT_FALSE(GetSyncService(0)->GetUserSettings()->GetSelectedTypes().Has(
-      syncer::UserSelectableType::kTabs));
-  ASSERT_FALSE(GetSyncService(0)->GetUserSettings()->GetSelectedTypes().Has(
-      syncer::UserSelectableType::kPreferences));
-
-  ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive());
-  ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE,
-            GetSyncService(0)->GetTransportState());
-
-  // Without `kReplaceSyncPromosWithSignInPromos`, none of the history-related
-  // types should be active in transport mode (even if the user has opted in).
-  EXPECT_FALSE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::HISTORY));
-  EXPECT_FALSE(GetSyncService(0)->GetActiveDataTypes().Has(
-      syncer::HISTORY_DELETE_DIRECTIVES));
-  EXPECT_FALSE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::SESSIONS));
-  EXPECT_FALSE(
-      GetSyncService(0)->GetActiveDataTypes().Has(syncer::USER_EVENTS));
-
-  // Without `kReplaceSyncPromosWithSignInPromos`, PREFERENCES should not be
-  // active in transport mode (even if the user has opted in).
-  EXPECT_FALSE(
-      GetSyncService(0)->GetActiveDataTypes().Has(syncer::PREFERENCES));
-  // TODO(crbug.com/412602018): With
-  // `kSyncSupportAlwaysSyncingPriorityPreferences` enabled,
-  // PRIORITY_PREFERENCES are active in transport mode and decoupled from user
-  // toggle. Update or add new test to cover PRIORITY_PREFERENCES.
-}
-
-#else
-
-IN_PROC_BROWSER_TEST_F(
-    SingleClientStandaloneTransportWithoutReplaceSyncWithSigninSyncTest,
-    DataTypesNotEnabledInTransportMode) {
-  ASSERT_TRUE(SetupClients());
-  // Sign in, without turning on Sync-the-feature.
-  ASSERT_TRUE(GetClient(0)->SignInPrimaryAccount());
-  ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled());
-
-  // Without `kReplaceSyncPromosWithSignInPromos`, History/Tabs are not are
-  // supported in transport mode, so they're reported as not selected even if
-  // the user explicitly tries to turn them on.
-  syncer::UserSelectableTypeSet types =
-      GetSyncService(0)->GetUserSettings()->GetRegisteredSelectableTypes();
-  ASSERT_TRUE(types.HasAll({syncer::UserSelectableType::kHistory,
-                            syncer::UserSelectableType::kTabs,
-                            syncer::UserSelectableType::kPreferences}));
-  GetSyncService(0)->GetUserSettings()->SetSelectedTypes(
-      /*sync_everything=*/true, types);
-  ASSERT_FALSE(GetSyncService(0)->GetUserSettings()->GetSelectedTypes().Has(
-      syncer::UserSelectableType::kHistory));
-  ASSERT_FALSE(GetSyncService(0)->GetUserSettings()->GetSelectedTypes().Has(
-      syncer::UserSelectableType::kTabs));
-  // Preferences, Themes and Search Engines are supported in transport mode,
-  // provided the enabled feature flags, irrespective of
-  // `kReplaceSyncPromosWithSignInPromos`. So they're reported as selected even
-  // when the user explicitly turns them on.
-  ASSERT_TRUE(GetSyncService(0)->GetUserSettings()->GetSelectedTypes().HasAll(
-      {syncer::UserSelectableType::kPreferences,
-       syncer::UserSelectableType::kThemes}));
-
-  ASSERT_TRUE(GetClient(0)->AwaitSyncTransportActive());
-  ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE,
-            GetSyncService(0)->GetTransportState());
-
-  // Without `kReplaceSyncPromosWithSignInPromos`, none of the history-related
-  // types should be active in transport mode (even if the user has opted in).
-  EXPECT_FALSE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::HISTORY));
-  EXPECT_FALSE(GetSyncService(0)->GetActiveDataTypes().Has(
-      syncer::HISTORY_DELETE_DIRECTIVES));
-  EXPECT_FALSE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::SESSIONS));
-  EXPECT_FALSE(
-      GetSyncService(0)->GetActiveDataTypes().Has(syncer::USER_EVENTS));
-
-  // PREFERENCES, SEARCH_ENGINES and THEMES are active in transport mode
-  // irrespective of `kReplaceSyncPromosWithSignInPromos`, provided the
-  // enabled feature flags.
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::THEMES));
-  EXPECT_TRUE(
-      GetSyncService(0)->GetActiveDataTypes().Has(syncer::SEARCH_ENGINES));
-  EXPECT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has(syncer::PREFERENCES));
-  // TODO(crbug.com/412602018): With
-  // `kSyncSupportAlwaysSyncingPriorityPreferences` enabled,
-  // PRIORITY_PREFERENCES are active in transport mode and decoupled from user
-  // toggle. Update or add new test to cover PRIORITY_PREFERENCES.
-}
-
-#endif  // BUILDFLAG(IS_ANDROID)
-
-// SingleClientStandaloneTransportReplaceSyncWithSigninMigrationSyncTest is
+// ReplaceSyncWithSigninMigrationSyncTest is
 // disabled on CrOS as the signed in, non-syncing state does not exist.
 // TODO(crbug.com/40145099): Android currently doesn't support PRE_ tests and
 // all of these are.
@@ -602,10 +591,9 @@
 // This test intends to test the mobile migration behavior, but runs on desktop.
 // Desktop and mobile have different behaviors, and as a consequence is test is
 // only an approximation.
-class SingleClientStandaloneTransportReplaceSyncWithSigninMigrationSyncTest
-    : public SingleClientStandaloneTransportSyncTest {
+class ReplaceSyncWithSigninMigrationSyncTest : public SyncTest {
  public:
-  SingleClientStandaloneTransportReplaceSyncWithSigninMigrationSyncTest() {
+  ReplaceSyncWithSigninMigrationSyncTest() : SyncTest(SINGLE_CLIENT) {
     // Various features that are required for types to be supported in transport
     // mode are unconditionally enabled.
     default_features_.InitWithFeatures(
@@ -622,17 +610,15 @@
         {{syncer::kReplaceSyncPromosWithSignInPromos, !content::IsPreTest()},
          {switches::kEnablePreferencesAccountStorage, !content::IsPreTest()}});
   }
-  ~SingleClientStandaloneTransportReplaceSyncWithSigninMigrationSyncTest()
-      override = default;
+  ~ReplaceSyncWithSigninMigrationSyncTest() override = default;
 
  private:
   base::test::ScopedFeatureList default_features_;
   base::test::ScopedFeatureList sync_to_signin_feature_;
 };
 
-IN_PROC_BROWSER_TEST_F(
-    SingleClientStandaloneTransportReplaceSyncWithSigninMigrationSyncTest,
-    PRE_MigratesSignedInUser) {
+IN_PROC_BROWSER_TEST_F(ReplaceSyncWithSigninMigrationSyncTest,
+                       PRE_MigratesSignedInUser) {
   ASSERT_TRUE(SetupClients());
   // Sign in, without turning on Sync-the-feature.
   ASSERT_TRUE(GetClient(0)->SignInPrimaryAccount());
@@ -661,9 +647,8 @@
             GetSyncService(0)->GetTransportState());
 }
 
-IN_PROC_BROWSER_TEST_F(
-    SingleClientStandaloneTransportReplaceSyncWithSigninMigrationSyncTest,
-    MigratesSignedInUser) {
+IN_PROC_BROWSER_TEST_F(ReplaceSyncWithSigninMigrationSyncTest,
+                       MigratesSignedInUser) {
   ASSERT_TRUE(SetupClients());
 
   ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled());
@@ -687,9 +672,8 @@
       syncer::UserSelectableType::kPreferences));
 }
 
-IN_PROC_BROWSER_TEST_F(
-    SingleClientStandaloneTransportReplaceSyncWithSigninMigrationSyncTest,
-    PRE_MigratesSignedInCustomPassphraseUser) {
+IN_PROC_BROWSER_TEST_F(ReplaceSyncWithSigninMigrationSyncTest,
+                       PRE_MigratesSignedInCustomPassphraseUser) {
   ASSERT_TRUE(SetupClients());
   // Sign in, without turning on Sync-the-feature.
   ASSERT_TRUE(GetClient(0)->SignInPrimaryAccount());
@@ -714,9 +698,8 @@
       syncer::UserSelectableType::kPreferences));
 }
 
-IN_PROC_BROWSER_TEST_F(
-    SingleClientStandaloneTransportReplaceSyncWithSigninMigrationSyncTest,
-    MigratesSignedInCustomPassphraseUser) {
+IN_PROC_BROWSER_TEST_F(ReplaceSyncWithSigninMigrationSyncTest,
+                       MigratesSignedInCustomPassphraseUser) {
   ASSERT_TRUE(SetupClients());
 
   ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled());
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index 5744fb9c..c2eddc6c 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -58,6 +58,8 @@
 #include "chrome/common/chrome_switches.h"
 #include "components/bookmarks/test/bookmark_test_helpers.h"
 #include "components/browser_sync/browser_sync_switches.h"
+#include "components/commerce/core/commerce_feature_list.h"
+#include "components/data_sharing/public/features.h"
 #include "components/gcm_driver/fake_gcm_profile_service.h"
 #include "components/gcm_driver/gcm_profile_service.h"
 #include "components/gcm_driver/instance_id/instance_id.h"
@@ -65,6 +67,8 @@
 #include "components/gcm_driver/instance_id/instance_id_profile_service.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/os_crypt/sync/os_crypt_mocker.h"
+#include "components/password_manager/core/browser/password_manager_buildflags.h"
+#include "components/plus_addresses/features.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/signin/public/base/consent_level.h"
 #include "components/signin/public/base/signin_switches.h"
@@ -105,6 +109,7 @@
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
 #if BUILDFLAG(IS_ANDROID)
+#include "chrome/browser/password_manager/android/password_manager_util_bridge.h"
 #include "chrome/browser/sync/test/integration/sync_test_utils_android.h"
 #else  // BUILDFLAG(IS_ANDROID)
 #include "chrome/browser/ui/browser.h"
@@ -1075,12 +1080,19 @@
 syncer::DataTypeSet AllowedTypesInStandaloneTransportMode() {
   static_assert(55 == syncer::GetNumDataTypes(),
                 "Add new types below if they can run in transport mode");
+
+#if BUILDFLAG(IS_ANDROID)
+  // On Android, `kReplaceSyncPromosWithSignInPromos` has been enabled by
+  // default for a long time, so it is not expected to be exercised in tests.
+  CHECK(
+      base::FeatureList::IsEnabled(syncer::kReplaceSyncPromosWithSignInPromos));
+#endif  // BUILDFLAG(IS_ANDROID)
+
   // Only some types will run by default in transport mode (i.e. without their
   // own separate opt-in).
   syncer::DataTypeSet allowed_types = {syncer::AUTOFILL_WALLET_CREDENTIAL,
                                        syncer::AUTOFILL_WALLET_DATA,
                                        syncer::AUTOFILL_WALLET_USAGE,
-                                       syncer::CONTACT_INFO,
                                        syncer::DEVICE_INFO,
                                        syncer::SECURITY_EVENTS,
                                        syncer::SEND_TAB_TO_SELF,
@@ -1088,12 +1100,20 @@
                                        syncer::USER_CONSENTS};
   allowed_types.PutAll(syncer::ControlTypes());
 
-  allowed_types.Put(syncer::PLUS_ADDRESS);
-  allowed_types.Put(syncer::PLUS_ADDRESS_SETTING);
-  allowed_types.Put(syncer::PASSWORDS);
-  allowed_types.Put(syncer::WEBAUTHN_CREDENTIAL);
-  allowed_types.Put(syncer::INCOMING_PASSWORD_SHARING_INVITATION);
-  allowed_types.Put(syncer::OUTGOING_PASSWORD_SHARING_INVITATION);
+#if BUILDFLAG(IS_CHROMEOS)
+  // OS sync types run in transport mode.
+  allowed_types.PutAll({syncer::APP_LIST, syncer::ARC_PACKAGE,
+                        syncer::OS_PREFERENCES,
+                        syncer::OS_PRIORITY_PREFERENCES});
+
+  // Some of the feature-guarded logic in the #else branch below could make
+  // sense for ChromeOS too. However, since there are no immediate plans to
+  // roll them out on ChromeOS, they are excluded in this test to avoid
+  // accidental rollouts on ChromeOS transport mode (which is somewhat special,
+  // and reachable only in advanced scenarios such as the user having cleared
+  // data via sync dashboard).
+#else  // BUILDFLAG(IS_CHROMEOS)
+  allowed_types.Put(syncer::CONTACT_INFO);
 
   if (base::FeatureList::IsEnabled(
           switches::kEnablePreferencesAccountStorage)) {
@@ -1111,37 +1131,44 @@
           syncer::kReplaceSyncPromosWithSignInPromos)) {
     allowed_types.Put(syncer::AUTOFILL_WALLET_METADATA);
     allowed_types.Put(syncer::AUTOFILL_WALLET_OFFER);
-    allowed_types.Put(syncer::COLLABORATION_GROUP);
     allowed_types.Put(syncer::HISTORY);
     allowed_types.Put(syncer::HISTORY_DELETE_DIRECTIVES);
-    allowed_types.Put(syncer::PRODUCT_COMPARISON);
     allowed_types.Put(syncer::SAVED_TAB_GROUP);
     allowed_types.Put(syncer::SESSIONS);
-    allowed_types.Put(syncer::SHARED_TAB_GROUP_DATA);
     allowed_types.Put(syncer::USER_EVENTS);
+
+    if (data_sharing::features::IsDataSharingFunctionalityEnabled()) {
+      allowed_types.Put(syncer::SHARED_TAB_GROUP_DATA);
+      allowed_types.Put(syncer::COLLABORATION_GROUP);
+
+      if (base::FeatureList::IsEnabled(
+              syncer::kSyncSharedTabGroupAccountData)) {
+        allowed_types.Put(syncer::SHARED_TAB_GROUP_ACCOUNT_DATA);
+      }
+    }
+
+    if (base::FeatureList::IsEnabled(commerce::kProductSpecifications)) {
+      allowed_types.Put(syncer::PRODUCT_COMPARISON);
+    }
   }
   if (base::FeatureList::IsEnabled(syncer::kSyncAutofillLoyaltyCard)) {
     allowed_types.Put(syncer::AUTOFILL_VALUABLE);
   }
-  if (base::FeatureList::IsEnabled(syncer::kSyncSharedTabGroupAccountData)) {
-    allowed_types.Put(syncer::SHARED_TAB_GROUP_ACCOUNT_DATA);
+
+#if BUILDFLAG(IS_ANDROID) && !BUILDFLAG(USE_LOGIN_DATABASE_AS_BACKEND)
+  // On Android, PASSWORDS require that Google Play Services is present.
+  password_manager_android_util::PasswordManagerUtilBridge util_bridge;
+  if (util_bridge.IsInternalBackendPresent()) {
+    allowed_types.Put(syncer::PASSWORDS);
   }
+#else   // BUILDFLAG(IS_ANDROID) && !BUILDFLAG(USE_LOGIN_DATABASE_AS_BACKEND)
+  allowed_types.Put(syncer::PASSWORDS);
+#endif  // BUILDFLAG(IS_ANDROID) && !BUILDFLAG(USE_LOGIN_DATABASE_AS_BACKEND)
+
 #if BUILDFLAG(IS_ANDROID)
-  if (base::FeatureList::IsEnabled(syncer::kWebApkBackupAndRestoreBackend)) {
-    allowed_types.Put(syncer::WEB_APKS);
-  }
-#endif
-
-#if BUILDFLAG(IS_CHROMEOS)
-  // OS sync types run in transport mode.
-  allowed_types.PutAll({syncer::APP_LIST, syncer::ARC_PACKAGE,
-                        syncer::OS_PREFERENCES, syncer::OS_PRIORITY_PREFERENCES,
-                        syncer::PRINTERS,
-                        syncer::PRINTERS_AUTHORIZATION_SERVERS,
-                        syncer::WIFI_CONFIGURATIONS, syncer::WORKSPACE_DESK});
-#endif  // BUILDFLAG(IS_CHROMEOS)
-
-#if !BUILDFLAG(IS_ANDROID)
+  // TODO(crbug.com/420912307): Allow `syncer::WEB_APKS` if
+  // `syncer::kWebApkBackupAndRestoreBackend` is enabled.
+#else   // BUILDFLAG(IS_ANDROID)
   if (base::FeatureList::IsEnabled(syncer::kSeparateLocalAndAccountThemes)) {
     allowed_types.Put(syncer::THEMES);
   }
@@ -1150,7 +1177,21 @@
           syncer::kSeparateLocalAndAccountSearchEngines)) {
     allowed_types.Put(syncer::SEARCH_ENGINES);
   }
-#endif  // !BUILDFLAG(IS_ANDROID)
+
+  // These types are excluded on Android as they run outside Chrome.
+  allowed_types.Put(syncer::INCOMING_PASSWORD_SHARING_INVITATION);
+  allowed_types.Put(syncer::OUTGOING_PASSWORD_SHARING_INVITATION);
+  allowed_types.Put(syncer::WEBAUTHN_CREDENTIAL);
+#endif  // BUILDFLAG(IS_ANDROID)
+#endif  // BUILDFLAG(IS_CHROMEOS)
+
+  if (base::FeatureList::IsEnabled(
+          plus_addresses::features::kPlusAddressesEnabled) &&
+      !plus_addresses::features::kEnterprisePlusAddressServerUrl.Get()
+           .empty()) {
+    allowed_types.Put(syncer::PLUS_ADDRESS);
+    allowed_types.Put(syncer::PLUS_ADDRESS_SETTING);
+  }
 
   return allowed_types;
 }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 35bcb53..68ff0d1a 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1047,8 +1047,6 @@
       "passwords/bubble_controllers/move_to_account_store_bubble_controller.h",
       "passwords/bubble_controllers/password_bubble_controller_base.cc",
       "passwords/bubble_controllers/password_bubble_controller_base.h",
-      "passwords/bubble_controllers/password_change/password_change_credential_leak_bubble_controller.cc",
-      "passwords/bubble_controllers/password_change/password_change_credential_leak_bubble_controller.h",
       "passwords/bubble_controllers/password_change/successful_password_change_bubble_controller.cc",
       "passwords/bubble_controllers/password_change/successful_password_change_bubble_controller.h",
       "passwords/bubble_controllers/post_save_compromised_bubble_controller.cc",
@@ -4337,8 +4335,6 @@
       "views/passwords/password_auto_sign_in_view.h",
       "views/passwords/password_bubble_view_base.cc",
       "views/passwords/password_bubble_view_base.h",
-      "views/passwords/password_change/password_change_credential_leak_bubble_view.cc",
-      "views/passwords/password_change/password_change_credential_leak_bubble_view.h",
       "views/passwords/password_change/password_change_toast.cc",
       "views/passwords/password_change/password_change_toast.h",
       "views/passwords/password_change/successful_password_change_view.cc",
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 7aafe2f..c9ed87f 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -4422,6 +4422,9 @@
       <message name="IDS_MENU_RECENT_TABS" desc="Menu item for opening the 'Recent tabs' page that shows recently closed tabs and pages the user has opened on his/her other devices. [CHAR_LIMIT=27]">
         Recent tabs
       </message>
+      <message name="IDS_MENU_EXTENSIONS" desc="Menu item for opening the 'Extensions' page that allows the user to manage installed extensions. [CHAR_LIMIT=27]">
+        Extensions
+      </message>
       <message name="IDS_MENU_TINKER_TANK" desc="Menu item for opening the tinker tank bottom sheet. [CHAR_LIMIT=27]" translateable="false">
         Tinker tank
       </message>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_MENU_EXTENSIONS.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_MENU_EXTENSIONS.png.sha1
new file mode 100644
index 0000000..7c143e94
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_MENU_EXTENSIONS.png.sha1
@@ -0,0 +1 @@
+a1d39a56f032d53d0c50d4b1cb4e221f725cbb49
\ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_eu.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_eu.xtb
index a00351d..489f6c4 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_eu.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_eu.xtb
@@ -332,6 +332,7 @@
 <translation id="2524132927880411790">Joan Google aplikazioaren ahozko bilaketara</translation>
 <translation id="2527209463677295330">Orriko testu gehiago barne hartuz gero, agian emaitza hobeak ikusiko dituzu</translation>
 <translation id="2527779675047087889">Ezkutatu arbeleko edukia</translation>
+<translation id="2531209299761896527">Fitxak beste leiho batean irekitzeko, atximurkatu, eduki sakatuta eta arrastatu</translation>
 <translation id="2532336938189706096">Web-ikuspegia</translation>
 <translation id="253498598929009420">Webguneak pantailan agertzen dena ikusi ahal izango du</translation>
 <translation id="2535807170289627159">Fitxa guztiak</translation>
diff --git a/chrome/browser/ui/android/strings/translations/android_chrome_strings_lo.xtb b/chrome/browser/ui/android/strings/translations/android_chrome_strings_lo.xtb
index 84f2390..9c44dcf 100644
--- a/chrome/browser/ui/android/strings/translations/android_chrome_strings_lo.xtb
+++ b/chrome/browser/ui/android/strings/translations/android_chrome_strings_lo.xtb
@@ -341,6 +341,7 @@
 <translation id="2546283357679194313">ຄຸກກີ້ ແລະຂໍ້ມູນເວັບໄຊທ໌...</translation>
 <translation id="2547843573592965873">ການລັອກໂປຣໄຟລ໌ຂອງທ່ານຊ່ວຍຮັກສາຂໍ້ມູນຂອງທ່ານໃນລົດໃຫ້ປອດໄພ, ຮວມເຖິງລະຫັດຜ່ານ, ການຈ່າຍເງິນ ແລະ ອື່ນໆທີ່ບັນທຶກໄວ້ໃນບັນຊີ Google ຂອງທ່ານ.</translation>
 <translation id="254973855621628293">ບັນທຶກລະຫັດຜ່ານໃສ່ອຸປະກອນນີ້ແລ້ວ</translation>
+<translation id="2566471851103108967">{FILE_COUNT,plural, =1{ບລັອກການດາວໂຫຼດທີ່ເປັນອັນຕະລາຍແລ້ວ}other{ບລັອກການດາວໂຫຼດ # ລາຍການທີ່ເປັນອັນຕະລາຍແລ້ວ}}</translation>
 <translation id="2567385386134582609">ຮູບ</translation>
 <translation id="2569733278091928697">ທ່ານຈະສາມາດຈັດການການຄວບຄຸມມີເດຍ, ເຊດຊັນບໍ່ເປີດເຜີຍຕົວຕົນ, ການດາວໂຫຼດ ແລະ ອື່ນໆໄດ້ຢ່າງງ່າຍດາຍ</translation>
 <translation id="2571711316400087311">ສະເໜີສົ່ງໜ້າເປັນພາສາອື່ນໃຫ້ Google ແປພາສາ</translation>
@@ -750,6 +751,7 @@
 <translation id="4479972344484327217">ກຳລັງຕິດຕັ້ງ <ph name="MODULE" /> ສໍາລັບ Chrome…</translation>
 <translation id="4484496141267039529">ບໍ່ມີການເຊື່ອມຕໍ່. ກະລຸນາລອງໃໝ່ໃນພາຍຫຼັງ.</translation>
 <translation id="4487967297491345095">ທຸກຂໍ້ມູນແອັບຂອງ Chrome ຈະຖືກລຶບຢ່າງຖາວອນ. ນີ້ຮວມເອົາທຸກໄຟລ໌, ການຕັ້ງຄ່າ, ບັນຊີ, ຖານຂໍ້ມູນ ແລະ ອື່ນໆ.</translation>
+<translation id="4494315997125191493">ເລືອກຈັດການເພື່ອເບິ່ງໜ້າຈໍທັງໝົດ</translation>
 <translation id="4494806687727322324">ຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານເປີດການບັນທຶກລະຫັດຜ່ານ</translation>
 <translation id="4508528996305412043">ເມນູບັດຟີດເປີດຢູ່</translation>
 <translation id="4509741852167209430">ຂໍ້ມູນປະເພດທີ່ຈຳກັດຈະຖືກແບ່ງປັນລະຫວ່າງເວັບໄຊຕ່າງໆເພື່ອວັດແທກປະສິດທິພາບຂອງໂຄສະນາຂອງເຂົາເຈົ້າ, ເຊັ່ນ: ທ່ານມີການຊື້ເຄື່ອງຫຼັງຈາກເຂົ້າເວັບໄຊໃດໜຶ່ງຫຼືບໍ່</translation>
@@ -790,6 +792,7 @@
 <translation id="4668279686271488041">ຂໍ້ມູນການວັດແທກການໂຄສະນາຖືກລຶບຢ່າງເປັນປົກກະຕິຈາກອຸປະກອນຂອງທ່ານ</translation>
 <translation id="4668347365065281350">ຂໍ້ມູນທັງໝົດທີ່ເກັບໄວ້ໂດຍເວັບໄຊ, ຮວມທັງຄຸກກີ້ ແລະ ຂໍ້ມູນອື່ນທີ່ເກັບໄວ້ໃນເຄື່ອງ</translation>
 <translation id="4678082183394354975">ຮູບແບບສີສັນມືດສຳລັບເວັບໄຊແມ່ນຖືກເປີດໃຊ້ໃນ Chrome ແລ້ວ</translation>
+<translation id="4682306524980568490">ສາມາດສະແດງໄດ້ພຽງ <ph name="MAX_INSTANCE_COUNT" /> ໜ້າຈໍເທົ່ານັ້ນ</translation>
 <translation id="4684427112815847243">ຊິງຄ໌​ທຸກ​ຢ່າງ</translation>
 <translation id="4685741273709472646">ເລືອກຈາກລາຍຊື່ແບບເລື່ອນລົງ</translation>
 <translation id="4687718960473379118">ໂຄສະນາທີ່ເວັບໄຊແນະນຳ</translation>
diff --git a/chrome/browser/ui/android/toolbar/extension_actions_bridge.cc b/chrome/browser/ui/android/toolbar/extension_actions_bridge.cc
index 6ae831c25..b71a051 100644
--- a/chrome/browser/ui/android/toolbar/extension_actions_bridge.cc
+++ b/chrome/browser/ui/android/toolbar/extension_actions_bridge.cc
@@ -143,6 +143,13 @@
       runner->RunAction(extension, /*grant_tab_permissions=*/true));
 }
 
+jboolean ExtensionActionsBridge::ExtensionsEnabled(JNIEnv* env) {
+  extensions::ExtensionManagement* extension_management =
+      extensions::ExtensionManagementFactory::GetForBrowserContext(profile_);
+  return static_cast<jboolean>(
+      extension_management->ExtensionsEnabledForDesktopAndroid());
+}
+
 void ExtensionActionsBridge::OnToolbarActionAdded(
     const ToolbarActionsModel::ActionId& id) {
   Java_ExtensionActionsBridge_onActionAdded(AttachCurrentThread(), java_object_,
diff --git a/chrome/browser/ui/android/toolbar/extension_actions_bridge.h b/chrome/browser/ui/android/toolbar/extension_actions_bridge.h
index ca9d0564..8e02f53 100644
--- a/chrome/browser/ui/android/toolbar/extension_actions_bridge.h
+++ b/chrome/browser/ui/android/toolbar/extension_actions_bridge.h
@@ -40,6 +40,7 @@
   jint RunAction(JNIEnv* env,
                  const std::string& action_id,
                  const base::android::JavaParamRef<jobject>& web_contents_java);
+  jboolean ExtensionsEnabled(JNIEnv* env);
 
   // ToolbarActionsModel::Observer:
   void OnToolbarActionAdded(const ToolbarActionsModel::ActionId& id) override;
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionsBridge.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionsBridge.java
index 42dc3574..ae66b052 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionsBridge.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionsBridge.java
@@ -92,6 +92,15 @@
                 .runAction(mNativeExtensionActionsBridge, actionId, webContents);
     }
 
+    /**
+     * Returns whether the extensions are disabled on the profile for Desktop Android. This is
+     * temporary for until extensions are ready for dogfooding. TODO(crbug.com/422307625): Remove
+     * this check once extensions are ready for dogfooding.
+     */
+    public boolean extensionsEnabled() {
+        return ExtensionActionsBridgeJni.get().extensionsEnabled(mNativeExtensionActionsBridge);
+    }
+
     @CalledByNative
     @VisibleForTesting
     void onActionAdded(@JniType("std::string") String actionId) {
@@ -194,5 +203,7 @@
                 long nativeExtensionActionsBridge,
                 @JniType("std::string") String actionId,
                 WebContents webContents);
+
+        boolean extensionsEnabled(long nativeExtensionActionsBridge);
     }
 }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManager.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManager.java
index 48d05a42..69520795 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManager.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManager.java
@@ -52,7 +52,4 @@
                 themeColorProvider);
         return manager;
     }
-
-    /** Initialize the manager with the components that had native initialization dependencies. */
-    public void initializeWithNative();
 }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManagerImpl.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManagerImpl.java
index 7c9f5ca..decee3d 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManagerImpl.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarManagerImpl.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.toolbar.extensions;
 
 import android.content.Context;
-import android.view.View;
 import android.view.ViewStub;
 import android.widget.LinearLayout;
 
@@ -14,7 +13,6 @@
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
 import org.chromium.build.annotations.ServiceImpl;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.theme.ThemeColorProvider;
@@ -59,18 +57,7 @@
         mExtensionsMenuButton = container.findViewById(R.id.extensions_menu_button);
         mExtensionsMenuButtonCoordinator =
                 new ExtensionsMenuButtonCoordinator(
-                        context, mExtensionsMenuButton, themeColorProvider);
-    }
-
-    @Override
-    public void initializeWithNative() {
-        assert mExtensionsMenuButton != null;
-
-        mExtensionsMenuButton.setVisibility(
-                ChromeFeatureList.isEnabled(
-                                ChromeFeatureList.BLOCK_INSTALLING_EXTENSIONS_ON_DESKTOP_ANDROID)
-                        ? View.GONE
-                        : View.VISIBLE);
+                        context, mExtensionsMenuButton, themeColorProvider, profileSupplier);
     }
 
     @Override
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuButtonCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuButtonCoordinator.java
index 9c97bdc..d354eaf 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuButtonCoordinator.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuButtonCoordinator.java
@@ -10,9 +10,12 @@
 
 import androidx.core.widget.ImageViewCompat;
 
+import org.chromium.base.Callback;
 import org.chromium.base.lifetime.Destroyable;
+import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
+import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.theme.ThemeColorProvider;
 import org.chromium.chrome.browser.ui.theme.BrandedColorScheme;
 import org.chromium.ui.listmenu.ListMenuButton;
@@ -23,18 +26,46 @@
 
     private final ListMenuButton mExtensionsMenuButton;
     private final ThemeColorProvider mThemeColorProvider;
-    private final ThemeColorProvider.TintObserver mTintObserver;
+    private final ObservableSupplier<Profile> mProfileSupplier;
+
+    private final ThemeColorProvider.TintObserver mTintObserver = this::onTintChanged;
+    private final Callback<Profile> mProfileUpdatedCallback = this::onProfileUpdated;
+
+    @Nullable private Profile mProfile;
 
     public ExtensionsMenuButtonCoordinator(
             Context context,
             ListMenuButton extensionsMenuButton,
-            ThemeColorProvider themeColorProvider) {
+            ThemeColorProvider themeColorProvider,
+            ObservableSupplier<Profile> profileSupplier) {
         mExtensionsMenuButton = extensionsMenuButton;
         mExtensionsMenuButton.setOnClickListener(this::onClick);
+        mProfileSupplier = profileSupplier;
 
         mThemeColorProvider = themeColorProvider;
-        mTintObserver = this::onTintChanged;
         mThemeColorProvider.addTintObserver(mTintObserver);
+
+        mProfileSupplier.addObserver(mProfileUpdatedCallback);
+    }
+
+    private void onProfileUpdated(@Nullable Profile profile) {
+        if (profile == mProfile) {
+            return;
+        }
+
+        mProfile = profile;
+
+        // TODO(crbug.com/422307625): Remove this check once extensions are ready for
+        // dogfooding.
+        int visibility = View.GONE;
+        if (mProfile != null) {
+            ExtensionActionsBridge extensionActionsBridge = ExtensionActionsBridge.get(mProfile);
+            if (extensionActionsBridge != null && extensionActionsBridge.extensionsEnabled()) {
+                visibility = View.VISIBLE;
+            }
+        }
+
+        mExtensionsMenuButton.setVisibility(visibility);
     }
 
     void onClick(View view) {
@@ -54,5 +85,7 @@
     public void destroy() {
         mExtensionsMenuButton.setOnClickListener(null);
         mThemeColorProvider.removeTintObserver(mTintObserver);
+        mProfileSupplier.removeObserver(mProfileUpdatedCallback);
+        mProfile = null;
     }
 }
diff --git a/chrome/browser/ui/ash/quick_answers/quick_answers_controller_impl.cc b/chrome/browser/ui/ash/quick_answers/quick_answers_controller_impl.cc
index aa84946..7aa71ad 100644
--- a/chrome/browser/ui/ash/quick_answers/quick_answers_controller_impl.cc
+++ b/chrome/browser/ui/ash/quick_answers/quick_answers_controller_impl.cc
@@ -585,7 +585,7 @@
     return false;
   }
 
-  quick_answers_ui_controller_->CreateUserConsentView(anchor_bounds_,
+  quick_answers_ui_controller_->CreateUserConsentView(profile_, anchor_bounds_,
                                                       intent_type, intent_text);
 
   consent_ui_shown_ = GetTimeTicksNow();
diff --git a/chrome/browser/ui/ash/quick_answers/quick_answers_ui_controller.cc b/chrome/browser/ui/ash/quick_answers/quick_answers_ui_controller.cc
index c0bba2c..c5e5958 100644
--- a/chrome/browser/ui/ash/quick_answers/quick_answers_ui_controller.cc
+++ b/chrome/browser/ui/ash/quick_answers/quick_answers_ui_controller.cc
@@ -254,11 +254,12 @@
 }
 
 void QuickAnswersUiController::CreateUserConsentView(
+    Profile* profile,
     const gfx::Rect& anchor_bounds,
     quick_answers::IntentType intent_type,
     const std::u16string& intent_text) {
   CreateUserConsentViewInternal(
-      anchor_bounds, intent_type, intent_text,
+      profile, anchor_bounds, intent_type, intent_text,
       /*use_refreshed_design=*/
       chromeos::features::IsQuickAnswersMaterialNextUIEnabled());
 }
@@ -269,11 +270,12 @@
     const std::u16string& intent_text,
     bool use_refreshed_design) {
   CHECK_IS_TEST();
-  CreateUserConsentViewInternal(anchor_bounds, intent_type, intent_text,
-                                use_refreshed_design);
+  CreateUserConsentViewInternal(/*profile=*/nullptr, anchor_bounds, intent_type,
+                                intent_text, use_refreshed_design);
 }
 
 void QuickAnswersUiController::CreateUserConsentViewInternal(
+    Profile* profile,
     const gfx::Rect& anchor_bounds,
     quick_answers::IntentType intent_type,
     const std::u16string& intent_text,
@@ -284,13 +286,16 @@
   if (chromeos::features::IsMagicBoostRevampForQuickAnswersEnabled() &&
       QuickAnswersState::GetFeatureType() ==
           QuickAnswersState::FeatureType::kHmr) {
+    // Directing to the right settings toggle requires an active profile.
+    profile_ = profile;
     user_consent_view_.SetView(
         GetReadWriteCardsUiController().SetQuickAnswersUi(
             views::Builder<quick_answers::MagicBoostUserConsentView>(
                 std::make_unique<quick_answers::MagicBoostUserConsentView>(
-                    // TODO: crbug.com/414391121 - Populate the button label
-                    // with the correct text.
-                    intent_text, GetReadWriteCardsUiController()))
+                    intent_type, intent_text, GetReadWriteCardsUiController()))
+                .SetSettingsButtonPressed(base::BindRepeating(
+                    &QuickAnswersUiController::OnSettingsButtonPressed,
+                    base::Unretained(this)))
                 .Build()));
   } else {
     user_consent_view_.SetView(
diff --git a/chrome/browser/ui/ash/quick_answers/quick_answers_ui_controller.h b/chrome/browser/ui/ash/quick_answers/quick_answers_ui_controller.h
index 523dd2f..cf08f20 100644
--- a/chrome/browser/ui/ash/quick_answers/quick_answers_ui_controller.h
+++ b/chrome/browser/ui/ash/quick_answers/quick_answers_ui_controller.h
@@ -11,6 +11,7 @@
 #include "base/functional/callback_forward.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "chrome/browser/ui/ash/quick_answers/ui/magic_boost_user_consent_view.h"
 #include "chrome/browser/ui/ash/quick_answers/ui/quick_answers_view.h"
 #include "chrome/browser/ui/ash/quick_answers/ui/rich_answers_view.h"
 #include "chrome/browser/ui/ash/quick_answers/ui/user_consent_view.h"
@@ -96,7 +97,8 @@
   // feature vertically aligned to the anchor. Note that user consent is handled
   // by Quick Answers code only if `QuickAnswersState::FeatureType` is
   // `kQuickAnswers`.
-  void CreateUserConsentView(const gfx::Rect& anchor_bounds,
+  void CreateUserConsentView(Profile* profile,
+                             const gfx::Rect& anchor_bounds,
                              quick_answers::IntentType intent_type,
                              const std::u16string& intent_text);
   void CreateUserConsentViewForPixelTest(const gfx::Rect& anchor_bounds,
@@ -146,6 +148,10 @@
     return views::AsViewClass<quick_answers::UserConsentView>(
         user_consent_view_.view());
   }
+  quick_answers::MagicBoostUserConsentView* magic_boost_user_consent_view() {
+    return views::AsViewClass<quick_answers::MagicBoostUserConsentView>(
+        user_consent_view_.view());
+  }
   quick_answers::RichAnswersView* rich_answers_view() {
     return views::AsViewClass<quick_answers::RichAnswersView>(
         rich_answers_widget_->GetContentsView());
@@ -162,7 +168,8 @@
       const std::string& query,
       std::optional<quick_answers::Intent> intent,
       quick_answers::QuickAnswersView::Params params);
-  void CreateUserConsentViewInternal(const gfx::Rect& anchor_bounds,
+  void CreateUserConsentViewInternal(Profile* profile,
+                                     const gfx::Rect& anchor_bounds,
                                      quick_answers::IntentType intent_type,
                                      const std::u16string& intent_text,
                                      bool use_refreshed_design);
diff --git a/chrome/browser/ui/ash/quick_answers/ui/magic_boost_user_consent_view.cc b/chrome/browser/ui/ash/quick_answers/ui/magic_boost_user_consent_view.cc
index c58db4ec..1e9c343 100644
--- a/chrome/browser/ui/ash/quick_answers/ui/magic_boost_user_consent_view.cc
+++ b/chrome/browser/ui/ash/quick_answers/ui/magic_boost_user_consent_view.cc
@@ -74,13 +74,35 @@
 // Icon.
 constexpr gfx::Insets kIntentIconInsets = gfx::Insets(8);
 
+std::u16string GetChipLabel(IntentType intent_type,
+                            const std::u16string& intent_text) {
+  switch (intent_type) {
+    case IntentType::kUnit:
+      return l10n_util::GetStringFUTF16(
+          IDS_QUICK_ANSWERS_MAGIC_BOOST_USER_CONSENT_UNIT_CONVERSION_INTENT_LABEL_BUTTON,
+          intent_text);
+    case IntentType::kDictionary:
+      return l10n_util::GetStringFUTF16(
+          IDS_QUICK_ANSWERS_MAGIC_BOOST_USER_CONSENT_DEFINITION_INTENT_LABEL_BUTTON,
+          intent_text);
+    case IntentType::kTranslation:
+      return l10n_util::GetStringFUTF16(
+          IDS_QUICK_ANSWERS_MAGIC_BOOST_USER_CONSENT_TRANSLATION_INTENT_LABEL_BUTTON,
+          intent_text);
+    case IntentType::kUnknown:
+      NOTREACHED() << "No chip label for Unknown intent type";
+  }
+  NOTREACHED() << "Unknown enum";
+}
+
 }  // namespace
 
 // MagicBoostUserConsentView
 // -------------------------------------------------------------
 
 MagicBoostUserConsentView::MagicBoostUserConsentView(
-    const std::u16string& chip_label,
+    IntentType intent_type,
+    const std::u16string& intent_text,
     chromeos::ReadWriteCardsUiController& read_write_cards_ui_controller)
     : chromeos::ReadWriteCardsView(read_write_cards_ui_controller),
       focus_search_(
@@ -115,7 +137,8 @@
                           .AddChild(
                               views::Builder<views::LabelButton>()
                                   .CopyAddressTo(&intent_chip_)
-                                  .SetText(chip_label)
+                                  .SetText(
+                                      GetChipLabel(intent_type, intent_text))
                                   .SetProperty(views::kMarginsKey, kChipMargin)
                                   .SetLabelStyle(
                                       views::style::STYLE_BODY_4_EMPHASIS)
@@ -145,6 +168,7 @@
               views::Builder<views::ImageButton>()
                   .SetTooltipText(l10n_util::GetStringUTF16(
                       IDS_RICH_ANSWERS_VIEW_SETTINGS_BUTTON_A11Y_NAME_TEXT))
+                  .CopyAddressTo(&settings_button_)
                   .SetImageModel(
                       views::Button::ButtonState::STATE_NORMAL,
                       ui::ImageModel::FromVectorIcon(
@@ -188,6 +212,11 @@
   return focusable_views;
 }
 
+void MagicBoostUserConsentView::SetSettingsButtonPressed(
+    views::Button::PressedCallback callback) {
+  settings_button_->SetCallback(std::move(callback));
+}
+
 BEGIN_METADATA(MagicBoostUserConsentView)
 END_METADATA
 
diff --git a/chrome/browser/ui/ash/quick_answers/ui/magic_boost_user_consent_view.h b/chrome/browser/ui/ash/quick_answers/ui/magic_boost_user_consent_view.h
index 9cb09fb..4f387f2 100644
--- a/chrome/browser/ui/ash/quick_answers/ui/magic_boost_user_consent_view.h
+++ b/chrome/browser/ui/ash/quick_answers/ui/magic_boost_user_consent_view.h
@@ -13,8 +13,10 @@
 #include "chrome/browser/ui/ash/editor_menu/utils/focus_search.h"
 #include "chrome/browser/ui/ash/read_write_cards/read_write_cards_ui_controller.h"
 #include "chrome/browser/ui/ash/read_write_cards/read_write_cards_view.h"
+#include "chromeos/components/quick_answers/quick_answers_model.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/views/controls/button/button.h"
+#include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/layout/flex_layout_view.h"
 #include "ui/views/metadata/view_factory.h"
@@ -25,8 +27,6 @@
 class LabelButton;
 }  // namespace views
 
-class QuickAnswersUiController;
-
 namespace quick_answers {
 
 class MagicBoostUserConsentView : public chromeos::ReadWriteCardsView {
@@ -35,10 +35,11 @@
  public:
   static constexpr char kWidgetName[] = "MagicBoostUserConsentViewWidget";
 
-  // TODO: crbug.com/340628664 - remove `read_write_cards_ui_controller` arg
-  // once we stop extending `ReadWriteCardsView`.
-  explicit MagicBoostUserConsentView(
-      const std::u16string& chip_label,
+  // TODO(b/340628664): remove `read_write_cards_ui_controller` arg once we stop
+  // extending `ReadWriteCardsView`.
+  MagicBoostUserConsentView(
+      IntentType intent_type,
+      const std::u16string& intent_text,
       chromeos::ReadWriteCardsUiController& read_write_cards_ui_controller);
 
   // Disallow copy and assign.
@@ -53,20 +54,24 @@
   views::FocusTraversable* GetPaneFocusTraversable() override;
   void UpdateBoundsForQuickAnswers() override;
 
+  void SetSettingsButtonPressed(views::Button::PressedCallback callback);
+
   std::u16string chip_label_for_testing();
+  views::ImageButton* settings_button_for_testing() { return settings_button_; }
 
  private:
   // FocusSearch::GetFocusableViewsCallback to poll currently focusable views.
   std::vector<views::View*> GetFocusableViews();
 
-  base::WeakPtr<QuickAnswersUiController> controller_;
   chromeos::editor_menu::FocusSearch focus_search_;
   raw_ptr<views::LabelButton> intent_chip_ = nullptr;
+  raw_ptr<views::ImageButton> settings_button_ = nullptr;
 };
 
 BEGIN_VIEW_BUILDER(/* no export */,
                    MagicBoostUserConsentView,
                    chromeos::ReadWriteCardsView)
+VIEW_BUILDER_PROPERTY(views::Button::PressedCallback, SettingsButtonPressed)
 END_VIEW_BUILDER
 
 }  // namespace quick_answers
diff --git a/chrome/browser/ui/ash/quick_answers/ui/magic_boost_user_consent_view_unittest.cc b/chrome/browser/ui/ash/quick_answers/ui/magic_boost_user_consent_view_unittest.cc
index 6d1cbd00c..1f53556 100644
--- a/chrome/browser/ui/ash/quick_answers/ui/magic_boost_user_consent_view_unittest.cc
+++ b/chrome/browser/ui/ash/quick_answers/ui/magic_boost_user_consent_view_unittest.cc
@@ -4,20 +4,161 @@
 
 #include "chrome/browser/ui/ash/quick_answers/ui/magic_boost_user_consent_view.h"
 
+#include "base/test/scoped_feature_list.h"
+#include "chrome/browser/global_features.h"
+#include "chrome/browser/ui/ash/quick_answers/quick_answers_ui_controller.h"
+#include "chrome/browser/ui/ash/quick_answers/test/chrome_quick_answers_test_base.h"
 #include "chrome/browser/ui/ash/read_write_cards/read_write_cards_ui_controller.h"
+#include "chrome/browser/ui/settings_window_manager_chromeos.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile.h"
+#include "chromeos/components/quick_answers/test/fake_quick_answers_state.h"
+#include "chromeos/constants/chromeos_features.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/test/event_generator.h"
+#include "ui/views/controls/button/image_button.h"
 #include "ui/views/test/test_layout_provider.h"
 
 namespace quick_answers {
 
-TEST(MagicBoostUserConsentViewTest, ButtonTextLabel) {
-  views::test::TestLayoutProvider test_layout_provider;
-  chromeos::ReadWriteCardsUiController read_write_cards_ui_controller;
-  MagicBoostUserConsentView magic_boost_user_consent_view(
-      /*chip_label=*/u"testing label", read_write_cards_ui_controller);
+namespace {
 
-  EXPECT_EQ(u"testing label",
+constexpr gfx::Rect kDefaultAnchorBoundsInScreen =
+    gfx::Rect(gfx::Point(500, 250), gfx::Size(120, 140));
+
+class MockSettingsWindowManager : public chrome::SettingsWindowManager {
+ public:
+  MOCK_METHOD(void,
+              ShowChromePageForProfile,
+              (Profile * profile,
+               const GURL& gurl,
+               int64_t display_id,
+               apps::LaunchCallback callback),
+              (override));
+};
+
+}  // namespace
+
+class MagicBoostUserConsentViewTest : public ChromeQuickAnswersTestBase {
+ protected:
+  MagicBoostUserConsentViewTest() = default;
+  MagicBoostUserConsentViewTest(const MagicBoostUserConsentViewTest&) = delete;
+  MagicBoostUserConsentViewTest& operator=(
+      const MagicBoostUserConsentViewTest&) = delete;
+  ~MagicBoostUserConsentViewTest() override = default;
+
+  // ChromeQuickAnswersTestBase:
+  void SetUp() override {
+    ChromeQuickAnswersTestBase::SetUp();
+
+    feature_list_.InitWithFeatures(
+        {chromeos::features::kMagicBoostRevampForQuickAnswers}, {});
+  }
+
+  void TearDown() override {
+    fake_quick_answers_state_ = nullptr;
+
+    ChromeQuickAnswersTestBase::TearDown();
+  }
+
+  std::unique_ptr<QuickAnswersControllerImpl> CreateQuickAnswersControllerImpl(
+      chromeos::ReadWriteCardsUiController& read_write_cards_ui_controller)
+      override {
+    std::unique_ptr<FakeQuickAnswersState> fake_quick_answers_state =
+        std::make_unique<FakeQuickAnswersState>();
+    fake_quick_answers_state_ = fake_quick_answers_state.get();
+    fake_quick_answers_state_->OverrideFeatureType(
+        QuickAnswersState::FeatureType::kHmr);
+    return std::make_unique<QuickAnswersControllerImpl>(
+        TestingBrowserProcess::GetGlobal()
+            ->GetFeatures()
+            ->application_locale_storage(),
+        read_write_cards_ui_controller, std::move(fake_quick_answers_state));
+  }
+
+ public:
+  QuickAnswersControllerImpl* GetQuickAnswersController() {
+    return static_cast<QuickAnswersControllerImpl*>(
+        QuickAnswersController::Get());
+  }
+
+  QuickAnswersUiController* GetUiController() {
+    return GetQuickAnswersController()->quick_answers_ui_controller();
+  }
+
+  MagicBoostUserConsentView* GetMagicBoostUserConsentView() {
+    return views::AsViewClass<MagicBoostUserConsentView>(
+        GetUiController()->magic_boost_user_consent_view());
+  }
+
+  void CreateUserConsentView() {
+    GetQuickAnswersController()->SetVisibility(
+        QuickAnswersVisibility::kPending);
+    // Set up a companion menu before creating the QuickAnswersView.
+    CreateAndShowBasicMenu();
+    GetUiController()->GetReadWriteCardsUiController().SetContextMenuBounds(
+        kDefaultAnchorBoundsInScreen);
+
+    static_cast<QuickAnswersControllerImpl*>(QuickAnswersController::Get())
+        ->SetVisibility(QuickAnswersVisibility::kPending);
+    GetUiController()->CreateUserConsentView(
+        GetProfile(), kDefaultAnchorBoundsInScreen,
+        quick_answers::IntentType::kUnit, u"Text");
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+  chromeos::ReadWriteCardsUiController controller_;
+  raw_ptr<FakeQuickAnswersState> fake_quick_answers_state_ = nullptr;
+};
+
+TEST_F(MagicBoostUserConsentViewTest, TranslateButtonTextLabel) {
+  MagicBoostUserConsentView magic_boost_user_consent_view(
+      IntentType::kTranslation,
+      /*intent_text=*/u"testing label",
+      GetUiController()->GetReadWriteCardsUiController());
+
+  EXPECT_EQ(u"Translate \"testing label\"",
             magic_boost_user_consent_view.chip_label_for_testing());
 }
 
+TEST_F(MagicBoostUserConsentViewTest, DefineButtonTextLabel) {
+  MagicBoostUserConsentView magic_boost_user_consent_view(
+      IntentType::kDictionary,
+      /*intent_text=*/u"testing label",
+      GetUiController()->GetReadWriteCardsUiController());
+
+  EXPECT_EQ(u"Define \"testing label\"",
+            magic_boost_user_consent_view.chip_label_for_testing());
+}
+
+TEST_F(MagicBoostUserConsentViewTest, ConvertButtonTextLabel) {
+  MagicBoostUserConsentView magic_boost_user_consent_view(
+      IntentType::kUnit,
+      /*intent_text=*/u"testing label",
+      GetUiController()->GetReadWriteCardsUiController());
+
+  EXPECT_EQ(u"Convert \"testing label\"",
+            magic_boost_user_consent_view.chip_label_for_testing());
+}
+
+TEST_F(MagicBoostUserConsentViewTest, OpenSettings) {
+  MockSettingsWindowManager mock_settings_window_manager;
+  chrome::SettingsWindowManager::SetInstanceForTesting(
+      &mock_settings_window_manager);
+
+  CreateUserConsentView();
+
+  EXPECT_CALL(
+      mock_settings_window_manager,
+      ShowChromePageForProfile(testing::_, testing::_, testing::_, testing::_));
+
+  GetEventGenerator()->MoveMouseTo(GetMagicBoostUserConsentView()
+                                       ->settings_button_for_testing()
+                                       ->GetBoundsInScreen()
+                                       .CenterPoint());
+  GetEventGenerator()->ClickLeftButton();
+}
+
 }  // namespace quick_answers
diff --git a/chrome/browser/ui/autofill/autofill_ai/mock_save_or_update_ai_data_controller.h b/chrome/browser/ui/autofill/autofill_ai/mock_save_or_update_ai_data_controller.h
index b344fcb..72f284e 100644
--- a/chrome/browser/ui/autofill/autofill_ai/mock_save_or_update_ai_data_controller.h
+++ b/chrome/browser/ui/autofill/autofill_ai/mock_save_or_update_ai_data_controller.h
@@ -20,12 +20,13 @@
   MockSaveOrUpdateAutofillAiDataController();
   ~MockSaveOrUpdateAutofillAiDataController() override;
 
-  MOCK_METHOD(void,
-              ShowPrompt,
-              (autofill::EntityInstance,
-               std::optional<autofill::EntityInstance>,
-               AutofillAiClient::EntitySaveOrUpdatePromptResultCallback),
-              (override));
+  MOCK_METHOD(
+      void,
+      ShowPrompt,
+      (autofill::EntityInstance,
+       std::optional<autofill::EntityInstance>,
+       autofill::AutofillClient::EntitySaveOrUpdatePromptResultCallback),
+      (override));
   MOCK_METHOD(base::optional_ref<const autofill::EntityInstance>,
               GetAutofillAiData,
               (),
diff --git a/chrome/browser/ui/autofill/autofill_ai/save_or_update_autofill_ai_data_controller.h b/chrome/browser/ui/autofill/autofill_ai/save_or_update_autofill_ai_data_controller.h
index 1b07ad1..291caab 100644
--- a/chrome/browser/ui/autofill/autofill_ai/save_or_update_autofill_ai_data_controller.h
+++ b/chrome/browser/ui/autofill/autofill_ai/save_or_update_autofill_ai_data_controller.h
@@ -82,7 +82,7 @@
   virtual void ShowPrompt(
       autofill::EntityInstance new_entity,
       std::optional<autofill::EntityInstance> old_entity,
-      AutofillAiClient::EntitySaveOrUpdatePromptResultCallback
+      autofill::AutofillClient::EntitySaveOrUpdatePromptResultCallback
           save_prompt_acceptance_callback) = 0;
 
   // Called when the user accepts to save or update Autofill AI data.
diff --git a/chrome/browser/ui/autofill/autofill_ai/save_or_update_autofill_ai_data_controller_impl.cc b/chrome/browser/ui/autofill/autofill_ai/save_or_update_autofill_ai_data_controller_impl.cc
index 067e54a5..feec165 100644
--- a/chrome/browser/ui/autofill/autofill_ai/save_or_update_autofill_ai_data_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_ai/save_or_update_autofill_ai_data_controller_impl.cc
@@ -112,7 +112,7 @@
 void SaveOrUpdateAutofillAiDataControllerImpl::ShowPrompt(
     autofill::EntityInstance new_entity,
     std::optional<autofill::EntityInstance> old_entity,
-    AutofillAiClient::EntitySaveOrUpdatePromptResultCallback
+    autofill::AutofillClient::EntitySaveOrUpdatePromptResultCallback
         save_prompt_acceptance_callback) {
   // Don't show the bubble if it's already visible.
   if (bubble_view()) {
diff --git a/chrome/browser/ui/autofill/autofill_ai/save_or_update_autofill_ai_data_controller_impl.h b/chrome/browser/ui/autofill/autofill_ai/save_or_update_autofill_ai_data_controller_impl.h
index 40b00245..68c23539 100644
--- a/chrome/browser/ui/autofill/autofill_ai/save_or_update_autofill_ai_data_controller_impl.h
+++ b/chrome/browser/ui/autofill/autofill_ai/save_or_update_autofill_ai_data_controller_impl.h
@@ -43,10 +43,11 @@
   ~SaveOrUpdateAutofillAiDataControllerImpl() override;
 
   // SaveOrUpdateAutofillAiDataController:
-  void ShowPrompt(autofill::EntityInstance new_entity,
-                  std::optional<autofill::EntityInstance> old_entity,
-                  AutofillAiClient::EntitySaveOrUpdatePromptResultCallback
-                      save_prompt_acceptance_callback) override;
+  void ShowPrompt(
+      autofill::EntityInstance new_entity,
+      std::optional<autofill::EntityInstance> old_entity,
+      autofill::AutofillClient::EntitySaveOrUpdatePromptResultCallback
+          save_prompt_acceptance_callback) override;
   void OnSaveButtonClicked() override;
   base::optional_ref<const autofill::EntityInstance> GetAutofillAiData()
       const override;
@@ -87,7 +88,7 @@
 
   // Callback to notify the data provider about the user decision for the save
   // or update prompt.
-  AutofillAiClient::EntitySaveOrUpdatePromptResultCallback
+  autofill::AutofillClient::EntitySaveOrUpdatePromptResultCallback
       save_prompt_acceptance_callback_;
 
   base::WeakPtrFactory<SaveOrUpdateAutofillAiDataControllerImpl>
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index 98289ae..15ac269d 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -1201,4 +1201,20 @@
 #endif
 }
 
+void ChromeAutofillClient::ShowEntitySaveOrUpdateBubble(
+    EntityInstance new_entity,
+    std::optional<EntityInstance> old_entity,
+    EntitySaveOrUpdatePromptResultCallback prompt_acceptance_callback) {
+#if !BUILDFLAG(IS_ANDROID)
+  if (auto* controller =
+          autofill_ai::SaveOrUpdateAutofillAiDataController::GetOrCreate(
+              &*web_contents(), GetAppLocale())) {
+    controller->ShowPrompt(std::move(new_entity), std::move(old_entity),
+                           std::move(prompt_acceptance_callback));
+    return;
+  }
+#endif  // !BUILDFLAG(IS_ANDROID)
+  std::move(prompt_acceptance_callback).Run(EntitySaveOrUpdatePromptResult());
+}
+
 }  // namespace autofill
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h
index 4cffd1c..798daef 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.h
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -215,6 +215,11 @@
       plus_addresses::hats::SurveyType survey_type) final;
   optimization_guide::ModelQualityLogsUploaderService* GetMqlsUploadService()
       override;
+  void ShowEntitySaveOrUpdateBubble(
+      EntityInstance new_entity,
+      std::optional<EntityInstance> old_entity,
+      EntitySaveOrUpdatePromptResultCallback save_prompt_acceptance_callback)
+      override;
 
   // TODO(crbug.com/407666146): Create a test API.
   base::WeakPtr<AutofillSuggestionController>
diff --git a/chrome/browser/ui/passwords/bubble_controllers/password_change/password_change_credential_leak_bubble_controller.cc b/chrome/browser/ui/passwords/bubble_controllers/password_change/password_change_credential_leak_bubble_controller.cc
deleted file mode 100644
index ff8cba8d5..0000000
--- a/chrome/browser/ui/passwords/bubble_controllers/password_change/password_change_credential_leak_bubble_controller.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-// 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 "chrome/browser/ui/passwords/bubble_controllers/password_change/password_change_credential_leak_bubble_controller.h"
-
-#include <string>
-
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/signin/identity_manager_factory.h"
-#include "chrome/browser/sync/sync_service_factory.h"
-#include "chrome/browser/ui/passwords/passwords_leak_dialog_delegate.h"
-#include "chrome/browser/ui/passwords/passwords_model_delegate.h"
-#include "chrome/browser/ui/passwords/ui_utils.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/password_manager/core/browser/leak_detection_dialog_utils.h"
-#include "components/password_manager/core/browser/password_manager_metrics_util.h"
-#include "components/url_formatter/elide_url.h"
-
-namespace metrics_util = password_manager::metrics_util;
-
-PasswordChangeCredentialLeakBubbleController::
-    PasswordChangeCredentialLeakBubbleController(
-        base::WeakPtr<PasswordsModelDelegate> delegate)
-    : PasswordBubbleControllerBase(
-          delegate,
-          password_manager::metrics_util::UIDisplayDisposition::
-              PASSWORD_CHANGE_BUBBLE),
-      password_change_delegate_(
-          delegate_->GetPasswordChangeDelegate()->AsWeakPtr()) {}
-
-PasswordChangeCredentialLeakBubbleController::
-    ~PasswordChangeCredentialLeakBubbleController() {
-  OnBubbleClosing();
-}
-
-std::u16string PasswordChangeCredentialLeakBubbleController::GetTitle() const {
-  return l10n_util::GetStringUTF16(
-      IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_BUBBLE_TITLE);
-}
-
-void PasswordChangeCredentialLeakBubbleController::ReportInteractions() {
-  base::UmaHistogramEnumeration(
-      "PasswordManager.PasswordChange.LeakDetectionBubble", dismissal_reason_,
-      metrics_util::NUM_UI_RESPONSES);
-}
-
-std::u16string PasswordChangeCredentialLeakBubbleController::GetDisplayOrigin()
-    const {
-  return password_change_delegate_->GetDisplayOrigin();
-}
-
-void PasswordChangeCredentialLeakBubbleController::
-    NavigateToPasswordChangeSettings() {
-  dismissal_reason_ = metrics_util::CLICKED_ABOUT_PASSWORD_CHANGE;
-  delegate_->NavigateToPasswordChangeSettings();
-}
-
-std::u16string
-PasswordChangeCredentialLeakBubbleController::GetPrimaryAccountEmail() const {
-  Profile* profile = GetProfile();
-  return base::UTF8ToUTF16(GetDisplayableAccountName(
-      SyncServiceFactory::GetForProfile(profile),
-      IdentityManagerFactory::GetForProfile(profile)));
-}
-
-void PasswordChangeCredentialLeakBubbleController::ChangePassword() {
-  dismissal_reason_ = metrics_util::CLICKED_ACCEPT;
-  password_change_delegate_->StartPasswordChangeFlow();
-}
-
-void PasswordChangeCredentialLeakBubbleController::Cancel() {
-  dismissal_reason_ = metrics_util::CLICKED_CANCEL;
-  CHECK(password_change_delegate_);
-  password_change_delegate_->Stop();
-  delegate_->GetPasswordsLeakDialogDelegate()->OnLeakDialogHidden();
-}
diff --git a/chrome/browser/ui/passwords/bubble_controllers/password_change/password_change_credential_leak_bubble_controller.h b/chrome/browser/ui/passwords/bubble_controllers/password_change/password_change_credential_leak_bubble_controller.h
deleted file mode 100644
index 75dc016f..0000000
--- a/chrome/browser/ui/passwords/bubble_controllers/password_change/password_change_credential_leak_bubble_controller.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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 CHROME_BROWSER_UI_PASSWORDS_BUBBLE_CONTROLLERS_PASSWORD_CHANGE_PASSWORD_CHANGE_CREDENTIAL_LEAK_BUBBLE_CONTROLLER_H_
-#define CHROME_BROWSER_UI_PASSWORDS_BUBBLE_CONTROLLERS_PASSWORD_CHANGE_PASSWORD_CHANGE_CREDENTIAL_LEAK_BUBBLE_CONTROLLER_H_
-
-#include <string>
-
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/password_manager/password_change_delegate.h"
-#include "chrome/browser/ui/passwords/bubble_controllers/password_bubble_controller_base.h"
-#include "chrome/browser/ui/passwords/passwords_leak_dialog_delegate.h"
-#include "components/password_manager/core/browser/leak_detection_dialog_utils.h"
-
-// Controller for the credential leak bubble, which is only displayed when the
-// password change is supported.
-class PasswordChangeCredentialLeakBubbleController
-    : public PasswordBubbleControllerBase {
- public:
-  explicit PasswordChangeCredentialLeakBubbleController(
-      base::WeakPtr<PasswordsModelDelegate> delegate);
-
-  ~PasswordChangeCredentialLeakBubbleController() override;
-
-  // PasswordBubbleControllerBase methods:
-  std::u16string GetTitle() const override;
-  void ReportInteractions() override;
-
-  // Get the change password origin to be displayed in UI.
-  std::u16string GetDisplayOrigin() const;
-  std::u16string GetPrimaryAccountEmail() const;
-
-  void NavigateToPasswordChangeSettings();
-  void ChangePassword();
-  void Cancel();
-
- private:
-  base::WeakPtr<PasswordChangeDelegate> password_change_delegate_;
-  // Dismissal reason for a password bubble.
-  password_manager::metrics_util::UIDismissalReason dismissal_reason_ =
-      password_manager::metrics_util::NO_DIRECT_INTERACTION;
-};
-
-#endif  // CHROME_BROWSER_UI_PASSWORDS_BUBBLE_CONTROLLERS_PASSWORD_CHANGE_PASSWORD_CHANGE_CREDENTIAL_LEAK_BUBBLE_CONTROLLER_H_
diff --git a/chrome/browser/ui/passwords/bubble_controllers/password_change/password_change_credential_leak_bubble_controller_unittest.cc b/chrome/browser/ui/passwords/bubble_controllers/password_change/password_change_credential_leak_bubble_controller_unittest.cc
deleted file mode 100644
index 10df7d7f..0000000
--- a/chrome/browser/ui/passwords/bubble_controllers/password_change/password_change_credential_leak_bubble_controller_unittest.cc
+++ /dev/null
@@ -1,74 +0,0 @@
-// 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 "chrome/browser/ui/passwords/bubble_controllers/password_change/password_change_credential_leak_bubble_controller.h"
-
-#include <memory>
-
-#include "base/test/metrics/histogram_tester.h"
-#include "chrome/browser/password_manager/password_change_delegate_mock.h"
-#include "chrome/browser/ui/passwords/passwords_leak_dialog_delegate_mock.h"
-#include "chrome/browser/ui/passwords/passwords_model_delegate_mock.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::Return;
-namespace metrics_util = password_manager::metrics_util;
-
-class PasswordChangeCredentialLeakBubbleControllerTest
-    : public ::testing::Test {
- public:
-  void CreateController() {
-    EXPECT_CALL(mock_delegate_, OnBubbleShown());
-    ON_CALL(mock_delegate_, GetPasswordChangeDelegate)
-        .WillByDefault(Return(&password_change_delegate_));
-    ON_CALL(mock_delegate_, GetPasswordsLeakDialogDelegate)
-        .WillByDefault(Return(&passwords_leak_dialog_delegate_));
-    controller_ =
-        std::make_unique<PasswordChangeCredentialLeakBubbleController>(
-            mock_delegate_.AsWeakPtr());
-  }
-
- protected:
-  PasswordsModelDelegateMock mock_delegate_;
-  std::unique_ptr<PasswordChangeCredentialLeakBubbleController> controller_;
-  PasswordChangeDelegateMock password_change_delegate_;
-  PasswordsLeakDialogDelegateMock passwords_leak_dialog_delegate_;
-};
-
-TEST_F(PasswordChangeCredentialLeakBubbleControllerTest,
-       MetricsReportedForCancel) {
-  base::HistogramTester histogram_tester;
-  CreateController();
-
-  controller_->Cancel();
-  controller_.reset();
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.PasswordChange.LeakDetectionBubble",
-      metrics_util::CLICKED_CANCEL, 1);
-}
-
-TEST_F(PasswordChangeCredentialLeakBubbleControllerTest,
-       MetricsReportedForAccept) {
-  base::HistogramTester histogram_tester;
-  CreateController();
-
-  controller_->ChangePassword();
-  controller_.reset();
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.PasswordChange.LeakDetectionBubble",
-      metrics_util::CLICKED_ACCEPT, 1);
-}
-
-TEST_F(PasswordChangeCredentialLeakBubbleControllerTest,
-       MetricsReportedForAboutPasswordChange) {
-  base::HistogramTester histogram_tester;
-  CreateController();
-
-  controller_->NavigateToPasswordChangeSettings();
-  controller_.reset();
-  histogram_tester.ExpectUniqueSample(
-      "PasswordManager.PasswordChange.LeakDetectionBubble",
-      metrics_util::CLICKED_ABOUT_PASSWORD_CHANGE, 1);
-}
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
index 688401a..4fef9ed 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
@@ -58,7 +58,6 @@
 #include "chrome/browser/ui/user_education/browser_user_education_interface.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/passwords/manage_passwords_page_action_controller.h"
-#include "chrome/browser/ui/views/passwords/password_change/password_change_credential_leak_bubble_view.h"
 #include "chrome/browser/web_applications/web_app_utils.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/branded_strings.h"
diff --git a/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate_unittest.cc b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate_browsertest.cc
similarity index 76%
rename from chrome/browser/ui/toolbar/chrome_location_bar_model_delegate_unittest.cc
rename to chrome/browser/ui/toolbar/chrome_location_bar_model_delegate_browsertest.cc
index 4dd33d3..d8126423d 100644
--- a/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate_unittest.cc
+++ b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate_browsertest.cc
@@ -8,18 +8,17 @@
 
 #include "base/memory/raw_ptr.h"
 #include "base/test/scoped_feature_list.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/browser/signin/chrome_signin_client_factory.h"
-#include "chrome/browser/signin/chrome_signin_client_test_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/url_constants.h"
-#include "chrome/test/base/browser_with_test_window_test.h"
+#include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/search_test_utils.h"
-#include "chrome/test/base/testing_profile.h"
 #include "components/search_engines/template_url_service.h"
+#include "content/public/test/browser_test.h"
 
 // Concrete implementation of ChromeLocationBarModelDelegate.
 class TestChromeLocationBarModelDelegate
@@ -37,7 +36,6 @@
 
   // ChromeLocationBarModelDelegate:
   content::WebContents* GetActiveWebContents() const override {
-    browser_->tab_strip_model()->GetActiveWebContents();
     return browser_->tab_strip_model()->GetActiveWebContents();
   }
 
@@ -57,18 +55,22 @@
   net::CertStatus cert_status_ = 0;
 };
 
-class ChromeLocationBarModelDelegateTest : public BrowserWithTestWindowTest {
+class ChromeLocationBarModelDelegateTest : public InProcessBrowserTest {
  protected:
   ChromeLocationBarModelDelegateTest() = default;
 
-  void SetUp() override {
-    BrowserWithTestWindowTest::SetUp();
-
-    TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-        profile(),
+  void SetUpBrowserContextKeyedServices(
+      content::BrowserContext* context) override {
+    TemplateURLServiceFactory::GetInstance()->SetTestingFactory(
+        context,
         base::BindRepeating(&TemplateURLServiceFactory::BuildInstanceFor));
+  }
+
+  void SetUpOnMainThread() override {
+    InProcessBrowserTest::SetUpOnMainThread();
+
     TemplateURLService* template_url_service =
-        TemplateURLServiceFactory::GetForProfile(profile());
+        TemplateURLServiceFactory::GetForProfile(browser()->profile());
     search_test_utils::WaitForTemplateURLServiceToLoad(template_url_service);
 
     delegate_ = std::make_unique<TestChromeLocationBarModelDelegate>(browser());
@@ -76,7 +78,7 @@
 
   void SetSearchProvider(bool set_ntp_url) {
     TemplateURLService* template_url_service =
-        TemplateURLServiceFactory::GetForProfile(profile());
+        TemplateURLServiceFactory::GetForProfile(browser()->profile());
     TemplateURLData data;
     data.SetShortName(u"foo.com");
     data.SetURL("http://foo.com/url?bar={searchTerms}");
@@ -97,14 +99,6 @@
 
   TestChromeLocationBarModelDelegate* delegate() { return delegate_.get(); }
 
-  // BrowserWithTestWindowTest:
-  TestingProfile::TestingFactories GetTestingFactories() override {
-    return {TestingProfile::TestingFactory{
-        ChromeSigninClientFactory::GetInstance(),
-        base::BindRepeating(&BuildChromeSigninClientWithURLLoader,
-                            test_url_loader_factory())}};
-  }
-
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
   std::unique_ptr<TestChromeLocationBarModelDelegate> delegate_;
@@ -113,11 +107,11 @@
 // Tests whether ChromeLocationBarModelDelegate::IsNewTabPage and
 // ChromeLocationBarModelDelegate::IsNewTabPageURL return the expected results
 // for various NTP scenarios.
-TEST_F(ChromeLocationBarModelDelegateTest, IsNewTabPage) {
+IN_PROC_BROWSER_TEST_F(ChromeLocationBarModelDelegateTest, IsNewTabPage) {
   chrome::NewTab(browser());
   // New Tab URL with Google DSP resolves to the local or the WebUI NTP URL.
   GURL ntp_url(chrome::kChromeUINewTabPageURL);
-  EXPECT_EQ(ntp_url, search::GetNewTabPageURL(profile()));
+  EXPECT_EQ(ntp_url, search::GetNewTabPageURL(browser()->profile()));
 
   EXPECT_TRUE(delegate()->IsNewTabPage());
   EXPECT_TRUE(delegate()->IsNewTabPageURL(GetURL()));
@@ -127,7 +121,7 @@
   // New Tab URL with a user selected DSP without an NTP URL resolves to
   // chrome://new-tab-page-third-party/.
   EXPECT_EQ(GURL(chrome::kChromeUINewTabPageThirdPartyURL),
-            search::GetNewTabPageURL(profile()));
+            search::GetNewTabPageURL(browser()->profile()));
 
   EXPECT_FALSE(delegate()->IsNewTabPage());
   EXPECT_TRUE(delegate()->IsNewTabPageURL(GetURL()));
@@ -135,13 +129,15 @@
   SetSearchProvider(true);
   chrome::NewTab(browser());
   // New Tab URL with a user selected DSP resolves to the DSP's NTP URL.
-  EXPECT_EQ("https://foo.com/newtab", search::GetNewTabPageURL(profile()));
+  EXPECT_EQ("https://foo.com/newtab",
+            search::GetNewTabPageURL(browser()->profile()));
 
   EXPECT_FALSE(delegate()->IsNewTabPage());
   EXPECT_TRUE(delegate()->IsNewTabPageURL(GetURL()));
 }
 
-TEST_F(ChromeLocationBarModelDelegateTest, CertErrorPreventsElision) {
+IN_PROC_BROWSER_TEST_F(ChromeLocationBarModelDelegateTest,
+                       CertErrorPreventsElision) {
   EXPECT_FALSE(delegate()->ShouldPreventElision());
   delegate()->set_cert_status(net::CERT_STATUS_REVOKED);
   EXPECT_TRUE(delegate()->ShouldPreventElision());
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_browsertest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_browsertest.cc
index e9d8b04..58adc8d 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_browsertest.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_browsertest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/bookmarks/bookmark_test_helpers.h"
 #include "chrome/browser/browser_features.h"
 #include "chrome/browser/external_protocol/external_protocol_handler.h"
+#include "chrome/browser/preloading/bookmarkbar_preload/bookmarkbar_preload_pipeline_manager.h"
 #include "chrome/browser/preloading/chrome_preloading.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
@@ -434,6 +435,10 @@
     }
   }
 
+  content::test::PrerenderTestHelper& prerender_helper() {
+    return prerender_helper_;
+  }
+
  private:
   base::ScopedMockElapsedTimersForTest scoped_test_timer_;
   content::test::PrerenderTestHelper prerender_helper_;
@@ -733,6 +738,41 @@
       "Bookmarks.BookmarkBar.PrerenderNavigationToActivation", 1);
 }
 
+IN_PROC_BROWSER_TEST_F(PrerenderBookmarkBarOnHoverNavigationTest,
+                       DestroyedOnNavigatedAway) {
+  base::HistogramTester histogram_tester;
+
+  // Navigate to an initial page.
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(
+      browser(), https_test_server()->GetURL("/empty.html")));
+
+  GURL prerender_url = https_test_server()->GetURL("/simple.html?prerender");
+
+  BookmarkBarPreloadPipelineManager::CreateForWebContents(
+      GetActiveWebContents());
+  auto* bookmarkbar_preload_manager =
+      BookmarkBarPreloadPipelineManager::FromWebContents(
+          GetActiveWebContents());
+
+  bookmarkbar_preload_manager->StartPrerender(prerender_url);
+  content::test::PrerenderTestHelper::WaitForPrerenderLoadCompletion(
+      *GetActiveWebContents(), prerender_url);
+  content::FrameTreeNodeId host_id =
+      prerender_helper().GetHostForUrl(prerender_url);
+  ASSERT_TRUE(host_id);
+
+  // Navigate to a different page. This should cancel prerendering.
+  content::test::PrerenderHostObserver prerender_observer(
+      *GetActiveWebContents(), host_id);
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(
+      browser(), https_test_server()->GetURL("/simple.html?different")));
+  prerender_observer.WaitForDestroyed();
+
+  histogram_tester.ExpectUniqueSample(
+      "Prerender.Experimental.PrerenderHostFinalStatus.Embedder_BookmarkBar",
+      kFinalStatusTriggerDestroyed, 1);
+}
+
 // TODO(crbug.com/40285326): This fails with the field trial testing config.
 class PrerenderBookmarkBarOnHoverNavigationTestNoTestingConfig
     : public PrerenderBookmarkBarOnHoverNavigationTest {
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc
index d20b9d8..2f69761b 100644
--- a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc
+++ b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc
@@ -96,7 +96,7 @@
   // Keep top-chrome visible while a permission bubble is visible.
   auto* permission_manager =
       permissions::PermissionRequestManager::FromWebContents(contents);
-  if (permission_manager && permission_manager->IsRequestInProgress()) {
+  if (permission_manager && permission_manager->GetCurrentPrompt()) {
     return cc::BrowserControlsState::kShown;
   }
 
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc
index 23ffc60..b5f7f68 100644
--- a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc
+++ b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc
@@ -1363,9 +1363,7 @@
   CheckBrowserLayout(browser_view(), TopChromeShownState::kFullyShown);
 }
 
-// Sheriff 2022/04/18; flaky test crbug/1317068
-IN_PROC_BROWSER_TEST_F(TopControlsSlideControllerTest,
-                       DISABLED_TestPermissionBubble) {
+IN_PROC_BROWSER_TEST_F(TopControlsSlideControllerTest, TestPermissionBubble) {
   ToggleTabletMode();
   ASSERT_TRUE(GetTabletModeEnabled());
   EXPECT_TRUE(top_controls_slide_controller()->IsEnabled());
diff --git a/chrome/browser/ui/views/message_box_dialog.cc b/chrome/browser/ui/views/message_box_dialog.cc
index 163159d..491b16f 100644
--- a/chrome/browser/ui/views/message_box_dialog.cc
+++ b/chrome/browser/ui/views/message_box_dialog.cc
@@ -88,15 +88,6 @@
           },
           &run_loop, &result));
   run_loop.Run();
-
-  // After the dialog is closed, the Widget's destruction may post final
-  // cleanup tasks (e.g., to the compositor). Wait until these tasks are
-  // fully executed.
-  base::RunLoop flush_loop(base::RunLoop::Type::kNestableTasksAllowed);
-  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
-      FROM_HERE, flush_loop.QuitClosure());
-  flush_loop.Run();
-
   return result;
 }
 
diff --git a/chrome/browser/ui/views/passwords/password_change/password_change_credential_leak_bubble_view.cc b/chrome/browser/ui/views/passwords/password_change/password_change_credential_leak_bubble_view.cc
deleted file mode 100644
index e65d83ba..0000000
--- a/chrome/browser/ui/views/passwords/password_change/password_change_credential_leak_bubble_view.cc
+++ /dev/null
@@ -1,136 +0,0 @@
-// 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 "chrome/browser/ui/views/passwords/password_change/password_change_credential_leak_bubble_view.h"
-
-#include <memory>
-
-#include "base/functional/bind.h"
-#include "chrome/browser/ui/browser_actions.h"
-#include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/passwords/bubble_controllers/password_change/password_change_credential_leak_bubble_controller.h"
-#include "chrome/browser/ui/passwords/passwords_leak_dialog_delegate.h"
-#include "chrome/browser/ui/passwords/passwords_model_delegate.h"
-#include "chrome/browser/ui/ui_features.h"
-#include "chrome/browser/ui/views/chrome_layout_provider.h"
-#include "chrome/browser/ui/views/chrome_typography.h"
-#include "chrome/browser/ui/views/frame/browser_view.h"
-#include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
-#include "chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h"
-#include "chrome/browser/ui/views/page_action/page_action_icon_view.h"
-#include "chrome/browser/ui/views/passwords/views_utils.h"
-#include "chrome/grit/generated_resources.h"
-#include "chrome/grit/theme_resources.h"
-#include "components/password_manager/core/browser/leak_detection_dialog_utils.h"
-#include "content/public/browser/web_contents.h"
-#include "ui/base/metadata/metadata_impl_macros.h"
-#include "ui/gfx/text_constants.h"
-#include "ui/views/controls/styled_label.h"
-#include "ui/views/layout/flex_layout.h"
-#include "ui/views/vector_icons.h"
-
-using ClosedReason = views::Widget::ClosedReason;
-
-namespace {
-// Returns margins for a dialog.
-gfx::Insets GetDialogInsets() {
-  const auto* const layout_provider = ChromeLayoutProvider::Get();
-  gfx::Insets margins = layout_provider->GetInsetsMetric(views::INSETS_DIALOG);
-  margins.set_top(0);
-  return margins;
-}
-}  // namespace
-
-PasswordChangeCredentialLeakBubbleView::PasswordChangeCredentialLeakBubbleView(
-    content::WebContents* web_contents,
-    views::View* anchor_view)
-    : PasswordBubbleViewBase(web_contents,
-                             anchor_view,
-                             /*easily_dismissable=*/true),
-      controller_(PasswordsModelDelegateFromWebContents(web_contents)) {
-  set_fixed_width(views::LayoutProvider::Get()->GetDistanceMetric(
-      views::DISTANCE_MODAL_DIALOG_PREFERRED_WIDTH));
-  int spacing = ChromeLayoutProvider::Get()->GetDistanceMetric(
-      DISTANCE_RELATED_CONTROL_VERTICAL_SMALL);
-  auto* box_layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
-      views::BoxLayout::Orientation::kVertical));
-  box_layout->set_cross_axis_alignment(views::LayoutAlignment::kStretch);
-  box_layout->SetCollapseMarginsSpacing(true);
-  box_layout->set_between_child_spacing(spacing);
-  box_layout->set_inside_border_insets(GetDialogInsets());
-  // Set the margins to 0 such that the `root_view` fills the whole page bubble
-  // width.
-  set_margins(gfx::Insets());
-
-  AddChildView(views::Builder<views::StyledLabel>()
-                   .SetText(controller_.GetDisplayOrigin())
-                   .SetTextContext(views::style::CONTEXT_DIALOG_BODY_TEXT)
-                   .SetDefaultTextStyle(views::style::STYLE_PRIMARY)
-                   .Build());
-  AddChildView(CreateBodyText());
-
-  SetButtons(static_cast<int>(ui::mojom::DialogButton::kOk));
-  SetButtonLabel(ui::mojom::DialogButton::kOk,
-                 l10n_util::GetStringUTF16(
-                     IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_CHANGE_PASSWORD));
-  SetAcceptCallback(base::BindOnce(
-      &PasswordChangeCredentialLeakBubbleController::ChangePassword,
-      base::Unretained(&controller_)));
-  SetCloseCallback(base::BindRepeating(
-      [](PasswordChangeCredentialLeakBubbleView* view) {
-        ClosedReason reason = view->GetWidget()->closed_reason();
-        // Cancel the flow if the dialog is explicitly closed.
-        if (reason == ClosedReason::kCloseButtonClicked ||
-            reason == ClosedReason::kEscKeyPressed) {
-          // `controller_.Cancel()` may trigger Save/Update password prompt, so
-          // we need to hide this bubble earlier.
-          view->GetWidget()->Hide();
-          view->controller_.Cancel();
-        }
-      },
-      this));
-}
-
-PasswordChangeCredentialLeakBubbleView::
-    ~PasswordChangeCredentialLeakBubbleView() = default;
-
-std::unique_ptr<views::StyledLabel>
-PasswordChangeCredentialLeakBubbleView::CreateBodyText() {
-  base::RepeatingClosure navigate_to_settings =
-      base::BindRepeating(&PasswordChangeCredentialLeakBubbleController::
-                              NavigateToPasswordChangeSettings,
-                          base::Unretained(&controller_));
-  return CreateGooglePasswordManagerLabel(
-      /*text_message_id=*/
-      IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_LEAK_BUBBLE_DETAILS,
-      /*link_message_id=*/
-      IDS_PASSWORD_MANAGER_UI_PASSWORD_CHANGE_SETTINGS_LINK,
-      controller_.GetPrimaryAccountEmail(), navigate_to_settings,
-      views::style::CONTEXT_DIALOG_BODY_TEXT, views::style::STYLE_PRIMARY);
-}
-
-PasswordBubbleControllerBase*
-PasswordChangeCredentialLeakBubbleView::GetController() {
-  return &controller_;
-}
-
-const PasswordBubbleControllerBase*
-PasswordChangeCredentialLeakBubbleView::GetController() const {
-  return &controller_;
-}
-
-void PasswordChangeCredentialLeakBubbleView::OnWidgetInitialized() {
-  PasswordBubbleViewBase::OnWidgetInitialized();
-  GetOkButton()->SetImageModel(
-      views::Button::ButtonState::STATE_NORMAL,
-      ui::ImageModel::FromVectorIcon(views::kPasswordChangeIcon,
-                                     ui::kColorIconSecondary,
-                                     GetLayoutConstant(PAGE_INFO_ICON_SIZE)));
-  GetOkButton()->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  SetBubbleHeader(IDR_PASSWORD_CHANGE_WARNING,
-                  IDR_PASSWORD_CHANGE_WARNING_DARK);
-}
-
-BEGIN_METADATA(PasswordChangeCredentialLeakBubbleView)
-END_METADATA
diff --git a/chrome/browser/ui/views/passwords/password_change/password_change_credential_leak_bubble_view.h b/chrome/browser/ui/views/passwords/password_change/password_change_credential_leak_bubble_view.h
deleted file mode 100644
index 27d4a3d..0000000
--- a/chrome/browser/ui/views/passwords/password_change/password_change_credential_leak_bubble_view.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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 CHROME_BROWSER_UI_VIEWS_PASSWORDS_PASSWORD_CHANGE_PASSWORD_CHANGE_CREDENTIAL_LEAK_BUBBLE_VIEW_H_
-#define CHROME_BROWSER_UI_VIEWS_PASSWORDS_PASSWORD_CHANGE_PASSWORD_CHANGE_CREDENTIAL_LEAK_BUBBLE_VIEW_H_
-
-#include "chrome/browser/ui/passwords/bubble_controllers/password_change/password_change_credential_leak_bubble_controller.h"
-#include "chrome/browser/ui/passwords/passwords_leak_dialog_delegate.h"
-#include "chrome/browser/ui/views/passwords/password_bubble_view_base.h"
-#include "components/password_manager/core/browser/leak_detection_dialog_utils.h"
-#include "ui/views/controls/styled_label.h"
-
-class PasswordChangeCredentialLeakBubbleView : public PasswordBubbleViewBase {
-  METADATA_HEADER(PasswordChangeCredentialLeakBubbleView,
-                  PasswordBubbleViewBase)
-
- public:
-  PasswordChangeCredentialLeakBubbleView(content::WebContents* web_contents,
-                                         views::View* anchor_view);
-
- private:
-  ~PasswordChangeCredentialLeakBubbleView() override;
-
-  std::unique_ptr<views::StyledLabel> CreateBodyText();
-
-  // PasswordBubbleViewBase
-  PasswordBubbleControllerBase* GetController() override;
-  const PasswordBubbleControllerBase* GetController() const override;
-
-  // View:
-  void OnWidgetInitialized() override;
-
-  PasswordChangeCredentialLeakBubbleController controller_;
-};
-
-#endif  // CHROME_BROWSER_UI_VIEWS_PASSWORDS_PASSWORD_CHANGE_PASSWORD_CHANGE_CREDENTIAL_LEAK_BUBBLE_VIEW_H_
diff --git a/chrome/browser/ui/views/passwords/password_change/password_change_credential_leak_bubble_view_unittest.cc b/chrome/browser/ui/views/passwords/password_change/password_change_credential_leak_bubble_view_unittest.cc
deleted file mode 100644
index a142ced..0000000
--- a/chrome/browser/ui/views/passwords/password_change/password_change_credential_leak_bubble_view_unittest.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-// 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 "chrome/browser/ui/views/passwords/password_change/password_change_credential_leak_bubble_view.h"
-
-#include "chrome/browser/password_manager/password_change_delegate_mock.h"
-#include "chrome/browser/sync/sync_service_factory.h"
-#include "chrome/browser/ui/passwords/bubble_controllers/password_change/password_change_credential_leak_bubble_controller.h"
-#include "chrome/browser/ui/passwords/passwords_leak_dialog_delegate_mock.h"
-#include "chrome/browser/ui/views/passwords/password_bubble_view_test_base.h"
-#include "components/keyed_service/core/keyed_service.h"
-#include "components/password_manager/core/browser/leak_detection_dialog_utils.h"
-#include "components/signin/public/identity_manager/account_info.h"
-#include "components/sync/service/sync_service.h"
-#include "components/sync/test/test_sync_service.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/test/test_event.h"
-#include "ui/views/test/button_test_api.h"
-
-using testing::Invoke;
-using testing::Return;
-using ClosedReason = views::Widget::ClosedReason;
-
-namespace {
-const std::u16string kTestEmail = u"account@example.com";
-
-std::unique_ptr<KeyedService> BuildTestSyncService(
-    AccountInfo account_info,
-    content::BrowserContext* context) {
-  auto sync_service = std::make_unique<syncer::TestSyncService>();
-  sync_service->SetSignedIn(signin::ConsentLevel::kSync, account_info);
-  return sync_service;
-}
-}  // namespace
-
-class PasswordChangeCredentialLeakBubbleViewTest
-    : public PasswordBubbleViewTestBase {
- public:
-  PasswordChangeCredentialLeakBubbleViewTest() = default;
-  ~PasswordChangeCredentialLeakBubbleViewTest() override = default;
-
-  void SetUp() override {
-    PasswordBubbleViewTestBase::SetUp();
-    password_change_delegate_ = std::make_unique<PasswordChangeDelegateMock>();
-    ON_CALL(*password_change_delegate_, GetDisplayOrigin())
-        .WillByDefault(Return(u"example.com"));
-    ON_CALL(*model_delegate_mock(), GetPasswordChangeDelegate())
-        .WillByDefault(Return(password_change_delegate_.get()));
-    ON_CALL(*model_delegate_mock(), GetPasswordsLeakDialogDelegate())
-        .WillByDefault(Return(&passwords_leak_dialog_delegate_));
-    AccountInfo account_info = identity_test_env()->MakePrimaryAccountAvailable(
-        base::UTF16ToUTF8(kTestEmail), signin::ConsentLevel::kSignin);
-    SyncServiceFactory::GetInstance()->SetTestingFactory(
-        profile(),
-        base::BindRepeating(&BuildTestSyncService, std::move(account_info)));
-  }
-
-  void TearDown() override {
-    view_->GetWidget()->CloseWithReason(
-        views::Widget::ClosedReason::kCloseButtonClicked);
-    view_ = nullptr;
-    PasswordBubbleViewTestBase::TearDown();
-  }
-
-  void CreateAndShowView() {
-    CreateAnchorViewAndShow();
-
-    view_ = new PasswordChangeCredentialLeakBubbleView(web_contents(),
-                                                       anchor_view());
-    views::BubbleDialogDelegateView::CreateBubble(view_)->Show();
-  }
-
-  PasswordChangeCredentialLeakBubbleView* view() { return view_; }
-
-  PasswordChangeDelegateMock* password_change_delegate() {
-    return password_change_delegate_.get();
-  }
-
-  PasswordsLeakDialogDelegateMock* passwords_leak_dialog_delegate() {
-    return &passwords_leak_dialog_delegate_;
-  }
-
- private:
-  raw_ptr<PasswordChangeCredentialLeakBubbleView> view_;
-  std::unique_ptr<PasswordChangeDelegateMock> password_change_delegate_;
-  PasswordsLeakDialogDelegateMock passwords_leak_dialog_delegate_;
-};
-
-TEST_F(PasswordChangeCredentialLeakBubbleViewTest, ChangePasswordIsTriggered) {
-  CreateAndShowView();
-
-  EXPECT_CALL(*password_change_delegate(), StartPasswordChangeFlow);
-  EXPECT_CALL(*model_delegate_mock(), OnBubbleHidden);
-  views::test::ButtonTestApi(view()->GetOkButton())
-      .NotifyClick(ui::test::TestEvent());
-}
-
-TEST_F(PasswordChangeCredentialLeakBubbleViewTest,
-       PasswordChangeLinkIsTriggered) {
-  CreateAndShowView();
-
-  auto* controller = static_cast<PasswordChangeCredentialLeakBubbleController*>(
-      static_cast<PasswordBubbleViewBase*>(view())->GetController());
-  EXPECT_CALL(*model_delegate_mock(), NavigateToPasswordChangeSettings);
-  controller->NavigateToPasswordChangeSettings();
-}
-
-TEST_F(PasswordChangeCredentialLeakBubbleViewTest,
-       OnLeakDialogHiddenIsTriggeredOnClose) {
-  CreateAndShowView();
-
-  EXPECT_CALL(*passwords_leak_dialog_delegate(), OnLeakDialogHidden);
-  view()->GetWidget()->CloseWithReason(ClosedReason::kCloseButtonClicked);
-}
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 848a5ca..dd8dcb17 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
@@ -543,6 +543,13 @@
     return false;
   }
 
+  // Only preloads for regular profiles because WebContents::GetWebUI()
+  // may crash due to dangling RFH if navigation fails. See crbug.com/409389408.
+  // TODO(crbug.com/424551539): remove after fixing dangling RFH.
+  if (!Profile::FromBrowserContext(browser_context)->IsRegularProfile()) {
+    return false;
+  }
+
   // Don't preload if under heavy memory pressure.
   const auto* memory_monitor = base::MemoryPressureMonitor::Get();
   if (memory_monitor && memory_monitor->GetCurrentPressureLevel() >=
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index 3df86fa..df3cb591 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1750009617-bbfeebdfad78b22da897197df9e2c2884d7eca3d-f6ac3cb5a4c11c6645de8f6c2268c1194015d70f.profdata
+chrome-android32-main-1750053232-d5e827b0aae26bd92cef8256c29d0eec51b348e6-1e7bd3c1484bb4a9e8c3ff5e58bcfe93f4fe86ba.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index 89d189822..e7afea96 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1750015598-6439d4f9c5744cd57ff1dced75e3f34ff3ed5902-09516d32715f9bd80489f60c53c77b1021081774.profdata
+chrome-android64-main-1750059333-20e55cfa5577ef42522c4973ab6147afc1acf57c-2dde65da9b24ed2fcf986f8ce3ab6aaa5c0f0da5.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 48f40bd..61adb2c 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1750009617-6eb2c7fe91c4b06a5af3e2e13402bf081fe3de6f-f6ac3cb5a4c11c6645de8f6c2268c1194015d70f.profdata
+chrome-linux-main-1750053232-9965326834ecf9c33e3fb654f094cd1899a47b64-1e7bd3c1484bb4a9e8c3ff5e58bcfe93f4fe86ba.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 292d89f..63d0154f 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1750015598-0ff44c5aac07a439ed53c4c5fd045b028bab5526-09516d32715f9bd80489f60c53c77b1021081774.profdata
+chrome-mac-arm-main-1750060693-c2a26aec9aa22aefec7d6151373d8d8989dee0cb-8d8a660571fbfbc6989167053297f9d8f84aa315.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 094de419..d62823999 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1750009617-05adae8e20951b03b0ea348000c68b4285cafb40-f6ac3cb5a4c11c6645de8f6c2268c1194015d70f.profdata
+chrome-mac-main-1750053232-55f1879cb103295582b4ad7a15ac82753f013e00-1e7bd3c1484bb4a9e8c3ff5e58bcfe93f4fe86ba.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index 926728de..d8f0642 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1749967031-d1c7b5ce762613d774449d613e40ca3d704ac388-1ef2b77bb4414969924929ac44548cef351a11a7.profdata
+chrome-win-arm64-main-1750053232-33b168960ff3c97f61df406ebc8f69dec041a246-1e7bd3c1484bb4a9e8c3ff5e58bcfe93f4fe86ba.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index b50a3149..5c960237 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1749988628-4287abccd4efa8b9e34c1b13d84ee64289a1b8cf-8e8a0caa003533ccb469c4a67aef1241fe241952.profdata
+chrome-win32-main-1750042359-79ec791e4b9dafe825d5c07bec701a38be69f1b8-5175ec0ed798bc0e0853112f2aca712067e5c1d4.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 9f771456..d74227f 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1749999351-2255fb30d49c619811527c22d680e8d62ad24fda-76e12975326cf471fe76aeb19ca5ecdbffc1f9fc.profdata
+chrome-win64-main-1750042359-0e9d34015b69504bc6585da69dbbf7b3a25d22f9-5175ec0ed798bc0e0853112f2aca712067e5c1d4.profdata
diff --git a/chrome/installer/linux/BUILD.gn b/chrome/installer/linux/BUILD.gn
index 3a7cd8c..2aa4730 100644
--- a/chrome/installer/linux/BUILD.gn
+++ b/chrome/installer/linux/BUILD.gn
@@ -98,6 +98,7 @@
     "debian/deb_version.py",
     "debian/dist_package_versions.json",
     "debian/package_version_interval.py",
+    "//build/action_helpers.py",
     "//third_party/dpkg-shlibdeps/dpkg-shlibdeps.pl",
   ]
   outputs = [ "$root_out_dir/deb_{{source_name_part}}.deps" ]
@@ -135,7 +136,10 @@
   deps = [ ":installer_deps" ]
   script = "rpm/calculate_package_deps.py"
   sources = packaging_files_binaries
-  inputs = [ "rpm/dist_package_provides.json" ]
+  inputs = [
+    "rpm/dist_package_provides.json",
+    "//build/action_helpers.py",
+  ]
   outputs = [ "$root_out_dir/rpm_{{source_name_part}}.deps" ]
   args = [
     "{{source}}",
@@ -151,7 +155,10 @@
   deps = [ ":calculate_rpm_dependencies" ]
   script = "rpm/merge_package_deps.py"
   additional_deps = "rpm/additional_deps"
-  inputs = [ additional_deps ]
+  inputs = [
+    additional_deps,
+    "//build/action_helpers.py",
+  ]
   outputs = [ "$root_out_dir/rpm_common.deps" ]
   args = [
     "rpm_common.deps",
diff --git a/chrome/installer/linux/debian/calculate_package_deps.py b/chrome/installer/linux/debian/calculate_package_deps.py
index 8a8b294..d4bb857 100755
--- a/chrome/installer/linux/debian/calculate_package_deps.py
+++ b/chrome/installer/linux/debian/calculate_package_deps.py
@@ -119,7 +119,10 @@
             file=sys.stderr)
         ret_code = 1
 if ret_code == 0:
-  with open(dep_filename, 'w') as dep_file:
+  sys.path.append(os.path.join(script_dir, os.path.pardir, os.path.pardir,
+                               os.path.pardir, os.path.pardir, 'build'))
+  import action_helpers
+  with action_helpers.atomic_output(dep_filename, mode='w') as dep_file:
     lines = [interval_set.formatted() + '\n'
            for interval_set in interval_sets]
     dep_file.write(''.join(sorted(lines)))
diff --git a/chrome/installer/linux/rpm/calculate_package_deps.py b/chrome/installer/linux/rpm/calculate_package_deps.py
index c7c09851..9ed8e58 100755
--- a/chrome/installer/linux/rpm/calculate_package_deps.py
+++ b/chrome/installer/linux/rpm/calculate_package_deps.py
@@ -64,8 +64,11 @@
         ret_code = 1
         continue
 if ret_code == 0:
+  sys.path.append(os.path.join(script_dir, os.path.pardir, os.path.pardir,
+                               os.path.pardir, os.path.pardir, 'build'))
+  import action_helpers
   requires = requires.difference(remove_requires)
-  with open(dep_filename, 'w') as dep_file:
+  with action_helpers.atomic_output(dep_filename, mode='w') as dep_file:
     for requirement in sorted(list(requires)):
       dep_file.write(requirement + '\n')
 sys.exit(ret_code)
diff --git a/chrome/installer/linux/rpm/merge_package_deps.py b/chrome/installer/linux/rpm/merge_package_deps.py
index 282e8b4..5cfa026 100755
--- a/chrome/installer/linux/rpm/merge_package_deps.py
+++ b/chrome/installer/linux/rpm/merge_package_deps.py
@@ -3,8 +3,14 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import os
 import sys
 
+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])
@@ -24,5 +30,5 @@
       continue
     requires.add(line)
 
-with open(output_filename, 'w') as output_file:
+with action_helpers.atomic_output(output_filename, mode='w') as output_file:
   output_file.write(''.join(sorted(list(requires))))
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index da901b2..9b0778b8a 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3474,6 +3474,7 @@
       "../browser/ui/thumbnails/thumbnail_readiness_tracker_browsertest.cc",
       "../browser/ui/toolbar/cast/cast_contextual_menu_browsertest.cc",
       "../browser/ui/toolbar/cast/cast_toolbar_button_controller_browsertest.cc",
+      "../browser/ui/toolbar/chrome_location_bar_model_delegate_browsertest.cc",
       "../browser/ui/toolbar/pinned_toolbar/pinned_toolbar_actions_model_browsertest.cc",
       "../browser/ui/toolbar/toolbar_actions_model_browsertest.cc",
       "../browser/ui/unload_controller_browsertest.cc",
@@ -8002,7 +8003,6 @@
       "../browser/ui/passwords/bubble_controllers/common_saved_account_manager_bubble_controller_unittest.cc",
       "../browser/ui/passwords/bubble_controllers/manage_passwords_bubble_controller_unittest.cc",
       "../browser/ui/passwords/bubble_controllers/move_to_account_store_bubble_controller_unittest.cc",
-      "../browser/ui/passwords/bubble_controllers/password_change/password_change_credential_leak_bubble_controller_unittest.cc",
       "../browser/ui/passwords/bubble_controllers/password_change/successful_password_change_bubble_controller_unittest.cc",
       "../browser/ui/passwords/bubble_controllers/post_save_compromised_bubble_controller_unittest.cc",
       "../browser/ui/passwords/bubble_controllers/save_unsynced_credentials_locally_bubble_controller_unittest.cc",
@@ -8038,7 +8038,6 @@
       "../browser/ui/toolbar/app_menu_model_unittest.cc",
       "../browser/ui/toolbar/back_forward_menu_model_unittest.cc",
       "../browser/ui/toolbar/chrome_labs/chrome_labs_model_unittest.cc",
-      "../browser/ui/toolbar/chrome_location_bar_model_delegate_unittest.cc",
       "../browser/ui/toolbar/location_bar_model_unittest.cc",
       "../browser/ui/toolbar/toolbar_actions_model_unittest.cc",
       "../browser/ui/url_identity_unittest.cc",
@@ -8056,7 +8055,6 @@
       "../browser/ui/views/passwords/move_to_account_store_bubble_view_unittest.cc",
       "../browser/ui/views/passwords/password_bubble_view_test_base.cc",
       "../browser/ui/views/passwords/password_bubble_view_test_base.h",
-      "../browser/ui/views/passwords/password_change/password_change_credential_leak_bubble_view_unittest.cc",
       "../browser/ui/views/passwords/password_change/password_change_toast_unittest.cc",
       "../browser/ui/views/passwords/password_change/successful_password_change_view_unittest.cc",
       "../browser/ui/views/passwords/password_save_unsynced_credentials_locally_view_unittest.cc",
@@ -12211,10 +12209,13 @@
     "//components/bookmarks/browser:test_support",
     "//components/bookmarks/managed",
     "//components/browser_sync",
+    "//components/commerce/core:feature_list",
     "//components/favicon/core",
     "//components/invalidation/impl",
     "//components/invalidation/impl:test_support",
     "//components/os_crypt/sync:test_support",
+    "//components/password_manager/core/browser:password_manager_buildflags",
+    "//components/plus_addresses:features",
     "//components/saved_tab_groups/public",
     "//components/signin/public/identity_manager:test_support",
     "//components/sync",
@@ -12272,6 +12273,7 @@
       ":sync_integration_test_support_jni_headers",
       ":test_support_jni_headers",
       "//chrome/browser/android/webapk:webapk_sources",
+      "//chrome/browser/password_manager/android:utils",
       "//chrome/browser/ui/android/tab_model",
       "//components/saved_tab_groups/public:conversion_utils",
     ]
diff --git a/chrome/updater/updater.cc b/chrome/updater/updater.cc
index 47cb02a..86bfbc3 100644
--- a/chrome/updater/updater.cc
+++ b/chrome/updater/updater.cc
@@ -262,18 +262,6 @@
 #endif
 }
 
-constexpr const char* BuildArch() {
-#if defined(ARCH_CPU_ARM64)
-  return "64 bit (ARM)";
-#elif defined(ARCH_CPU_X86_64)
-  return "64 bit (x64)";
-#elif defined(ARCH_CPU_X86)
-  return "32 bit (x86)";
-#else
-#error CPU architecture is unknown.
-#endif
-}
-
 std::string OperatingSystemVersion() {
 #if BUILDFLAG(IS_WIN)
   const base::win::OSInfo::VersionNumber v =
@@ -326,7 +314,8 @@
   const UpdaterScope updater_scope = GetUpdaterScope();
   InitLogging(updater_scope);
   VLOG(1) << "Version: " << kUpdaterVersion << ", " << BuildFlavor() << ", "
-          << BuildArch() << ", command line: " << GetCommandLineString();
+          << base::SysInfo::ProcessCPUArchitecture()
+          << ", command line: " << GetCommandLineString();
   VLOG(1) << "OS version: " << OperatingSystemVersion()
           << ", System uptime (seconds): "
           << base::SysInfo::Uptime().InSeconds() << ", parent pid: "
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index a0e040a..eaf0bfd9 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-16320.0.0-1069610
\ No newline at end of file
+16320.0.0-1069621
\ No newline at end of file
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index aa513a8..2faaf3c2 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -258,6 +258,15 @@
       <message name="IDS_QUICK_ANSWERS_USER_CONSENT_TITLE_UNIT_CONVERSION_INTENT" desc="Title text of the dialog that opens up to seek user-consent for the Quick Answers feature when the supported intent is generated from the query.">
         Convert "<ph name="query">$1<ex>1kg</ex></ph>"
       </message>
+      <message name="IDS_QUICK_ANSWERS_MAGIC_BOOST_USER_CONSENT_DEFINITION_INTENT_LABEL_BUTTON" desc="Button label for Dictionary intent in the magic boost user consent view which leads to the magic boost disclaimer UI when clicked upon.">
+        Define "<ph name="query">$1<ex>unfathomable</ex></ph>"
+      </message>
+      <message name="IDS_QUICK_ANSWERS_MAGIC_BOOST_USER_CONSENT_TRANSLATION_INTENT_LABEL_BUTTON" desc="Button label for Translation intent in the magic boost user consent view which leads to the magic boost disclaimer UI when clicked upon.">
+        Translate "<ph name="query">$1<ex>信息</ex></ph>"
+      </message>
+      <message name="IDS_QUICK_ANSWERS_MAGIC_BOOST_USER_CONSENT_UNIT_CONVERSION_INTENT_LABEL_BUTTON" desc="Button label for Unit Conversion intent in the magic boost user consent view which leads to the magic boost disclaimer UI when clicked upon.">
+        Convert "<ph name="query">$1<ex>1kg</ex></ph>"
+      </message>
       <message name="IDS_QUICK_ANSWERS_USER_CONSENT_VIEW_TITLE_TEXT_WITH_INTENT" desc="Title text of the dialog that opens up to seek user-consent for the Quick Answers feature when supported intent is generated.">
         Get the <ph name="intent">$1<ex>definition</ex></ph> for "<ph name="query">$2<ex>unfathomable</ex></ph>" and more
       </message>
diff --git a/chromeos/chromeos_strings_grd/IDS_QUICK_ANSWERS_MAGIC_BOOST_USER_CONSENT_DEFINITION_INTENT_LABEL_BUTTON.png.sha1 b/chromeos/chromeos_strings_grd/IDS_QUICK_ANSWERS_MAGIC_BOOST_USER_CONSENT_DEFINITION_INTENT_LABEL_BUTTON.png.sha1
new file mode 100644
index 0000000..07de6f4a
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_QUICK_ANSWERS_MAGIC_BOOST_USER_CONSENT_DEFINITION_INTENT_LABEL_BUTTON.png.sha1
@@ -0,0 +1 @@
+6895d347beb0e7002c50898e1240a19373151665
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_QUICK_ANSWERS_MAGIC_BOOST_USER_CONSENT_TRANSLATION_INTENT_LABEL_BUTTON.png.sha1 b/chromeos/chromeos_strings_grd/IDS_QUICK_ANSWERS_MAGIC_BOOST_USER_CONSENT_TRANSLATION_INTENT_LABEL_BUTTON.png.sha1
new file mode 100644
index 0000000..865908f9
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_QUICK_ANSWERS_MAGIC_BOOST_USER_CONSENT_TRANSLATION_INTENT_LABEL_BUTTON.png.sha1
@@ -0,0 +1 @@
+98bac6ce039952cfba1e7ddde2d5f7066e591274
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_QUICK_ANSWERS_MAGIC_BOOST_USER_CONSENT_UNIT_CONVERSION_INTENT_LABEL_BUTTON.png.sha1 b/chromeos/chromeos_strings_grd/IDS_QUICK_ANSWERS_MAGIC_BOOST_USER_CONSENT_UNIT_CONVERSION_INTENT_LABEL_BUTTON.png.sha1
new file mode 100644
index 0000000..ea96441
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_QUICK_ANSWERS_MAGIC_BOOST_USER_CONSENT_UNIT_CONVERSION_INTENT_LABEL_BUTTON.png.sha1
@@ -0,0 +1 @@
+f8f891246e5003da6d250e562f3d3bd85eda261d
\ No newline at end of file
diff --git a/clank b/clank
index 2dbc9aa..e420186 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 2dbc9aa95eddeb69a73546f3076874c682375331
+Subproject commit e4201862b5cd95321ccc5abba80f47a502829743
diff --git a/components/autofill/content/renderer/BUILD.gn b/components/autofill/content/renderer/BUILD.gn
index 1e51b2a0c..009b765 100644
--- a/components/autofill/content/renderer/BUILD.gn
+++ b/components/autofill/content/renderer/BUILD.gn
@@ -144,4 +144,8 @@
     "//testing/gtest",
     "//third_party/blink/public:blink",
   ]
+
+  if (is_ios) {
+    deps += [ "//components/test:dom_label_test_bundle_data" ]
+  }
 }
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 8b8ba63..c3a502a 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -732,6 +732,7 @@
     "webdata/payments/payments_autofill_table.h",
     "webdata/payments/payments_sync_bridge_util.cc",
     "webdata/payments/payments_sync_bridge_util.h",
+    "webdata/payments/server_cvc.h",
     "webdata/valuables/valuable_data_type_controller.cc",
     "webdata/valuables/valuable_data_type_controller.h",
     "webdata/valuables/valuable_sync_bridge.cc",
diff --git a/components/autofill/core/browser/foundations/autofill_client.cc b/components/autofill/core/browser/foundations/autofill_client.cc
index 0881a03..7e05c8e 100644
--- a/components/autofill/core/browser/foundations/autofill_client.cc
+++ b/components/autofill/core/browser/foundations/autofill_client.cc
@@ -50,6 +50,31 @@
 AutofillClient::PopupOpenArgs& AutofillClient::PopupOpenArgs::operator=(
     AutofillClient::PopupOpenArgs&&) = default;
 
+AutofillClient::EntitySaveOrUpdatePromptResult::EntitySaveOrUpdatePromptResult(
+    bool did_user_decline,
+    std::optional<EntityInstance> entity)
+    : did_user_decline(did_user_decline), entity(std::move(entity)) {}
+
+AutofillClient::EntitySaveOrUpdatePromptResult::
+    EntitySaveOrUpdatePromptResult() = default;
+
+AutofillClient::EntitySaveOrUpdatePromptResult::EntitySaveOrUpdatePromptResult(
+    const AutofillClient::EntitySaveOrUpdatePromptResult&) = default;
+
+AutofillClient::EntitySaveOrUpdatePromptResult::EntitySaveOrUpdatePromptResult(
+    AutofillClient::EntitySaveOrUpdatePromptResult&&) = default;
+
+AutofillClient::EntitySaveOrUpdatePromptResult&
+AutofillClient::EntitySaveOrUpdatePromptResult::operator=(
+    const AutofillClient::EntitySaveOrUpdatePromptResult&) = default;
+
+AutofillClient::EntitySaveOrUpdatePromptResult&
+AutofillClient::EntitySaveOrUpdatePromptResult::operator=(
+    AutofillClient::EntitySaveOrUpdatePromptResult&&) = default;
+
+AutofillClient::EntitySaveOrUpdatePromptResult::
+    ~EntitySaveOrUpdatePromptResult() = default;
+
 version_info::Channel AutofillClient::GetChannel() const {
   return version_info::Channel::UNKNOWN;
 }
@@ -260,4 +285,9 @@
   return nullptr;
 }
 
+void AutofillClient::ShowEntitySaveOrUpdateBubble(
+    EntityInstance new_entity,
+    std::optional<EntityInstance> old_entity,
+    EntitySaveOrUpdatePromptResultCallback save_prompt_acceptance_callback) {}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/foundations/autofill_client.h b/components/autofill/core/browser/foundations/autofill_client.h
index 4e40f9e..4b97a3d 100644
--- a/components/autofill/core/browser/foundations/autofill_client.h
+++ b/components/autofill/core/browser/foundations/autofill_client.h
@@ -209,6 +209,28 @@
     ArrowPosition arrow_position;
   };
 
+  // Contains the result of a user interaction with the save/update AutofillAi
+  // prompt.
+  struct EntitySaveOrUpdatePromptResult final {
+    EntitySaveOrUpdatePromptResult();
+    EntitySaveOrUpdatePromptResult(bool did_user_decline,
+                                   std::optional<EntityInstance> entity);
+    EntitySaveOrUpdatePromptResult(const EntitySaveOrUpdatePromptResult&);
+    EntitySaveOrUpdatePromptResult(EntitySaveOrUpdatePromptResult&&);
+    EntitySaveOrUpdatePromptResult& operator=(
+        const EntitySaveOrUpdatePromptResult&);
+    EntitySaveOrUpdatePromptResult& operator=(EntitySaveOrUpdatePromptResult&&);
+    ~EntitySaveOrUpdatePromptResult();
+
+    // Whether the user explicitly declined the dialog.
+    bool did_user_decline = false;
+
+    // Non-empty iff the prompt was accepted.
+    std::optional<EntityInstance> entity;
+  };
+  using EntitySaveOrUpdatePromptResultCallback =
+      base::OnceCallback<void(EntitySaveOrUpdatePromptResult result)>;
+
   // Callback to run when the user makes a decision on whether to save the
   // profile. If the user edits the Autofill profile and then accepts edits, the
   // edited version of the profile should be passed as the second parameter. No
@@ -626,6 +648,14 @@
   // Returns the service used in order to log metrics into MQLS.
   virtual optimization_guide::ModelQualityLogsUploaderService*
   GetMqlsUploadService();
+
+  // Shows a bubble asking whether the user wants to save or update Autofill AI
+  // data. `old_entity` is present in the update cases. It is used to give users
+  // a better understanding of what was updated.
+  virtual void ShowEntitySaveOrUpdateBubble(
+      EntityInstance new_entity,
+      std::optional<EntityInstance> old_entity,
+      EntitySaveOrUpdatePromptResultCallback save_prompt_acceptance_callback);
 };
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/geo/country_data.cc b/components/autofill/core/browser/geo/country_data.cc
index aa14c53..7ae6a59 100644
--- a/components/autofill/core/browser/geo/country_data.cc
+++ b/components/autofill/core/browser/geo/country_data.cc
@@ -7,37 +7,29 @@
 #include <array>
 #include <utility>
 
+#include "base/containers/extend.h"
+#include "base/containers/fixed_flat_map.h"
+#include "base/containers/flat_map.h"
+#include "base/containers/to_vector.h"
 #include "base/memory/singleton.h"
+#include "base/strings/string_util.h"
 #include "components/strings/grit/components_strings.h"
 #include "third_party/icu/source/common/unicode/locid.h"
 
 namespace autofill {
 namespace {
 
-struct StaticCountryAddressImportRequirementsData {
-  char country_code[3];
-  RequiredFieldsForAddressImport address_import_field_requirements;
-};
-
-// Alias definitions record for CountryData requests.  A request for
-// |country_code_alias| is served with the |CountryData| for
-// |country_code_target|.
-struct StaticCountryCodeAliasData {
-  char country_code_alias[3];
-  char country_code_target[3];
-};
-
-// Alias definitions.
+// Alias definitions. A request for the key is served with the `CountryData` for
+// the target.
 constexpr auto kCountryCodeAliases =
-    std::to_array<StaticCountryCodeAliasData>({{"UK", "GB"}});
+    base::MakeFixedFlatMap<std::string_view, std::string_view>({{"UK", "GB"}});
 
-// Maps country codes to address import requirements. Keep this sorted
-// by country code.
+// Maps country codes to address import requirements.
 // This list is comprized of countries appearing in both
 // //third_party/icu/source/data/region/en.txt and
 // //third_party/libaddressinput/src/cpp/src/region_data_constants.cc.
 constexpr auto kCountryAddressImportRequirementsData =
-    std::to_array<StaticCountryAddressImportRequirementsData>(
+    base::MakeFixedFlatMap<std::string_view, RequiredFieldsForAddressImport>(
         {{"AC", ADDRESS_REQUIRES_LINE1_CITY},
          {"AD", ADDRESS_REQUIRES_LINE1},
          {"AE", ADDRESS_REQUIRES_LINE1_STATE},
@@ -292,52 +284,36 @@
          {"ZW", ADDRESS_REQUIRES_LINE1_CITY}});
 
 // GetCountryCodes and GetCountryData compute the data for CountryDataMap
-// based on |kCountryAddressImportRequirementsData|.
+// based on `kCountryAddressImportRequirementsData`.
 std::vector<std::string> GetCountryCodes() {
-  std::vector<std::string> country_codes;
-  country_codes.reserve(std::size(kCountryAddressImportRequirementsData));
-  for (const auto& static_data : kCountryAddressImportRequirementsData) {
-    country_codes.push_back(static_data.country_code);
-  }
-  return country_codes;
+  return base::ToVector(
+      kCountryAddressImportRequirementsData,
+      [](const auto& static_data) { return std::string(static_data.first); });
 }
 
-std::map<std::string, RequiredFieldsForAddressImport> GetCountryDataMap() {
-  std::map<std::string, RequiredFieldsForAddressImport> import_requirements;
-  // Add all the countries we have explicit data for.
-  for (const auto& static_data : kCountryAddressImportRequirementsData) {
-    import_requirements.insert(
-        import_requirements.end(),
-        std::make_pair(static_data.country_code,
-                       static_data.address_import_field_requirements));
-  }
-
-  // Add any other countries that ICU knows about, falling back to default data
-  // values.
+base::flat_map<std::string, RequiredFieldsForAddressImport>
+GetCountryDataMap() {
+  // Collect other countries that ICU knows about but for which we have no
+  // manually specified requirements.
+  std::vector<std::pair<std::string, RequiredFieldsForAddressImport>>
+      other_countries;
   // SAFETY: `icu::Locale::getISOCountries` returns a C-style array whose last
   // entry is a nullptr.
   for (const char* const* country_pointer = icu::Locale::getISOCountries();
        *country_pointer; UNSAFE_BUFFERS(++country_pointer)) {
-    std::string country_code = *country_pointer;
-    if (!import_requirements.count(country_code)) {
-      import_requirements.insert(std::make_pair(
-          std::move(country_code),
-          RequiredFieldsForAddressImport::ADDRESS_REQUIREMENTS_UNKNOWN));
+    if (!kCountryAddressImportRequirementsData.contains(*country_pointer)) {
+      other_countries.emplace_back(
+          *country_pointer,
+          RequiredFieldsForAddressImport::ADDRESS_REQUIREMENTS_UNKNOWN);
     }
   }
-  return import_requirements;
-}
 
-std::map<std::string, std::string> GetCountryCodeAliasMap() {
-  std::map<std::string, std::string> country_code_aliases;
-  // Create mappings for the aliases defined in |kCountryCodeAliases|.
-  for (const auto& static_alias_data : kCountryCodeAliases) {
-    // Insert the alias.
-    country_code_aliases.insert(
-        std::make_pair(std::string(static_alias_data.country_code_alias),
-                       std::string(static_alias_data.country_code_target)));
-  }
-  return country_code_aliases;
+  // Combine the other countries with those with explicit data.
+  other_countries.insert(other_countries.end(),
+                         kCountryAddressImportRequirementsData.begin(),
+                         kCountryAddressImportRequirementsData.end());
+  return base::MakeFlatMap<std::string, RequiredFieldsForAddressImport>(
+      std::move(other_countries));
 }
 
 }  // namespace
@@ -349,19 +325,18 @@
 
 CountryDataMap::CountryDataMap()
     : required_fields_for_address_import_map_(GetCountryDataMap()),
-      country_code_aliases_(GetCountryCodeAliasMap()),
       country_codes_(GetCountryCodes()) {}
 
 CountryDataMap::~CountryDataMap() = default;
 
 bool CountryDataMap::HasRequiredFieldsForAddressImport(
-    const std::string& country_code) const {
-  return required_fields_for_address_import_map_.count(country_code) > 0;
+    std::string_view country_code) const {
+  return required_fields_for_address_import_map_.contains(country_code);
 }
 
 RequiredFieldsForAddressImport
 CountryDataMap::GetRequiredFieldsForAddressImport(
-    const std::string& country_code) const {
+    std::string_view country_code) const {
   auto lookup = required_fields_for_address_import_map_.find(country_code);
   if (lookup != required_fields_for_address_import_map_.end())
     return lookup->second;
@@ -370,18 +345,18 @@
 }
 
 bool CountryDataMap::HasCountryCodeAlias(
-    const std::string& country_code_alias) const {
-  return country_code_aliases_.count(country_code_alias) > 0;
+    std::string_view country_code_alias) const {
+  return kCountryCodeAliases.contains(country_code_alias);
 }
 
-const std::string CountryDataMap::GetCountryCodeForAlias(
-    const std::string& country_code_alias) const {
-  auto lookup = country_code_aliases_.find(country_code_alias);
-  if (lookup != country_code_aliases_.end()) {
+std::string_view CountryDataMap::GetCountryCodeForAlias(
+    std::string_view country_code_alias) const {
+  auto lookup = kCountryCodeAliases.find(country_code_alias);
+  if (lookup != kCountryCodeAliases.end()) {
     DCHECK(HasRequiredFieldsForAddressImport(lookup->second));
     return lookup->second;
   }
-  return std::string();
+  return {};
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/geo/country_data.h b/components/autofill/core/browser/geo/country_data.h
index 8a30405f..e2a6cc9f 100644
--- a/components/autofill/core/browser/geo/country_data.h
+++ b/components/autofill/core/browser/geo/country_data.h
@@ -5,10 +5,11 @@
 #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_GEO_COUNTRY_DATA_H_
 #define COMPONENTS_AUTOFILL_CORE_BROWSER_GEO_COUNTRY_DATA_H_
 
-#include <map>
 #include <string>
 #include <vector>
 
+#include "base/containers/flat_map.h"
+
 namespace base {
 template <typename T>
 struct DefaultSingletonTraits;
@@ -62,22 +63,23 @@
   CountryDataMap(const CountryDataMap&) = delete;
   CountryDataMap& operator=(const CountryDataMap&) = delete;
 
-  // Returns true if a |CountryData| entry for the supplied |country_code|
+  // Returns true if a `CountryData` entry for the supplied `country_code`
   // exists.
-  bool HasRequiredFieldsForAddressImport(const std::string& country_code) const;
+  bool HasRequiredFieldsForAddressImport(std::string_view country_code) const;
 
-  // Returns true if there is a country code alias for |country_code|.
-  bool HasCountryCodeAlias(const std::string& country_code_alias) const;
+  // Returns true if there is a country code alias for `country_code`.
+  bool HasCountryCodeAlias(std::string_view country_code_alias) const;
 
-  // Returns the country code for a country code alias. If no alias definition
-  // is present return an empty string.
-  const std::string GetCountryCodeForAlias(
-      const std::string& country_code_alias) const;
+  // Returns the country code for a country code alias or an empty string if no
+  // alias definition is present.
+  std::string_view GetCountryCodeForAlias(
+      std::string_view country_code_alias) const;
 
-  // Lookup the |RequiredFieldForAddressImport| for the supplied |country_code|.
-  // If no entry exists, return requirements for the US as a best guess.
+  // Looks up the `RequiredFieldForAddressImport` for the supplied
+  // `country_code`. Returns requirements for the US as a best guess if no entry
+  // exists.
   RequiredFieldsForAddressImport GetRequiredFieldsForAddressImport(
-      const std::string& country_code) const;
+      std::string_view country_code) const;
 
   // Return a constant reference to a vector of all country codes.
   const std::vector<std::string>& country_codes() const {
@@ -89,9 +91,8 @@
   ~CountryDataMap();
   friend struct base::DefaultSingletonTraits<CountryDataMap>;
 
-  const std::map<std::string, RequiredFieldsForAddressImport>
+  const base::flat_map<std::string, RequiredFieldsForAddressImport>
       required_fields_for_address_import_map_;
-  const std::map<std::string, std::string> country_code_aliases_;
   const std::vector<std::string> country_codes_;
 };
 
diff --git a/components/autofill/core/browser/webdata/autofill_change.h b/components/autofill/core/browser/webdata/autofill_change.h
index 6a4d6fe..6cf57da6 100644
--- a/components/autofill/core/browser/webdata/autofill_change.h
+++ b/components/autofill/core/browser/webdata/autofill_change.h
@@ -16,7 +16,7 @@
 #include "components/autofill/core/browser/data_model/payments/credit_card.h"
 #include "components/autofill/core/browser/data_model/payments/iban.h"
 #include "components/autofill/core/browser/webdata/autocomplete/autocomplete_entry.h"
-#include "components/autofill/core/browser/webdata/payments/payments_autofill_table.h"
+#include "components/autofill/core/browser/webdata/payments/server_cvc.h"
 
 namespace autofill {
 
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
index 24a5042..04553d7 100644
--- a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
+++ b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
@@ -37,6 +37,7 @@
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h"
 #include "components/autofill/core/browser/webdata/payments/payments_autofill_table.h"
+#include "components/autofill/core/browser/webdata/payments/server_cvc.h"
 #include "components/autofill/core/browser/webdata/valuables/valuables_table.h"
 #include "components/autofill/core/common/autofill_clock.h"
 #include "components/autofill/core/common/dense_set.h"
diff --git a/components/autofill/core/browser/webdata/payments/autofill_wallet_credential_sync_bridge.cc b/components/autofill/core/browser/webdata/payments/autofill_wallet_credential_sync_bridge.cc
index 3c66c30d..c8d0768 100644
--- a/components/autofill/core/browser/webdata/payments/autofill_wallet_credential_sync_bridge.cc
+++ b/components/autofill/core/browser/webdata/payments/autofill_wallet_credential_sync_bridge.cc
@@ -14,6 +14,7 @@
 #include "components/autofill/core/browser/webdata/autofill_sync_metadata_table.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/browser/webdata/payments/payments_autofill_table.h"
 #include "components/autofill/core/browser/webdata/payments/payments_sync_bridge_util.h"
 #include "components/sync/base/data_type.h"
 #include "components/sync/base/deletion_origin.h"
diff --git a/components/autofill/core/browser/webdata/payments/autofill_wallet_sync_bridge.h b/components/autofill/core/browser/webdata/payments/autofill_wallet_sync_bridge.h
index 4369c38..fa46a8b 100644
--- a/components/autofill/core/browser/webdata/payments/autofill_wallet_sync_bridge.h
+++ b/components/autofill/core/browser/webdata/payments/autofill_wallet_sync_bridge.h
@@ -24,6 +24,7 @@
 class AutofillSyncMetadataTable;
 class AutofillWebDataBackend;
 class AutofillWebDataService;
+class BankAccount;
 class CreditCard;
 class Iban;
 struct CreditCardCloudTokenData;
diff --git a/components/autofill/core/browser/webdata/payments/payments_autofill_table.cc b/components/autofill/core/browser/webdata/payments/payments_autofill_table.cc
index 2b4e3e1..67e0335 100644
--- a/components/autofill/core/browser/webdata/payments/payments_autofill_table.cc
+++ b/components/autofill/core/browser/webdata/payments/payments_autofill_table.cc
@@ -48,6 +48,7 @@
 #include "components/autofill/core/browser/payments/payments_customer_data.h"
 #include "components/autofill/core/browser/webdata/autofill_change.h"
 #include "components/autofill/core/browser/webdata/autofill_table_utils.h"
+#include "components/autofill/core/browser/webdata/payments/server_cvc.h"
 #include "components/autofill/core/common/autofill_clock.h"
 #include "components/autofill/core/common/autofill_constants.h"
 #include "components/autofill/core/common/autofill_features.h"
diff --git a/components/autofill/core/browser/webdata/payments/payments_autofill_table.h b/components/autofill/core/browser/webdata/payments/payments_autofill_table.h
index 73bc6e0..89dd29f 100644
--- a/components/autofill/core/browser/webdata/payments/payments_autofill_table.h
+++ b/components/autofill/core/browser/webdata/payments/payments_autofill_table.h
@@ -7,14 +7,11 @@
 
 #include <stddef.h>
 
-#include <map>
 #include <memory>
 #include <optional>
 #include <string>
 #include <vector>
 
-#include "base/gtest_prod_util.h"
-#include "base/time/time.h"
 #include "components/autofill/core/browser/data_model/payments/credit_card_benefit.h"
 #include "components/sync/base/data_type.h"
 #include "components/sync/protocol/autofill_specifics.pb.h"
@@ -22,10 +19,6 @@
 
 class WebDatabase;
 
-namespace base {
-class Time;
-}
-
 namespace autofill {
 
 class AutofillOfferData;
@@ -35,19 +28,8 @@
 class Iban;
 struct PaymentsCustomerData;
 struct PaymentsMetadata;
+struct ServerCvc;
 class VirtualCardUsageData;
-// Helper struct to better group server cvc related variables for better
-// passing last_updated_timestamp, which is needed for sync bridge. Limited
-// scope in autofill table & sync bridge.
-struct ServerCvc {
-  bool operator==(const ServerCvc&) const = default;
-  // A server generated id to identify the corresponding credit card.
-  int64_t instrument_id;
-  // CVC value of the card.
-  std::u16string cvc;
-  // The timestamp of the most recent update to the data entry.
-  base::Time last_updated_timestamp;
-};
 
 // This class manages the various payments Autofill tables within the SQLite
 // database passed to the constructor. It expects the following schemas:
diff --git a/components/autofill/core/browser/webdata/payments/payments_sync_bridge_util.cc b/components/autofill/core/browser/webdata/payments/payments_sync_bridge_util.cc
index fd44f39..7f2bb419 100644
--- a/components/autofill/core/browser/webdata/payments/payments_sync_bridge_util.cc
+++ b/components/autofill/core/browser/webdata/payments/payments_sync_bridge_util.cc
@@ -27,6 +27,7 @@
 #include "components/autofill/core/browser/payments/constants.h"
 #include "components/autofill/core/browser/payments/payments_customer_data.h"
 #include "components/autofill/core/browser/webdata/payments/payments_autofill_table.h"
+#include "components/autofill/core/browser/webdata/payments/server_cvc.h"
 #include "components/autofill/core/common/autofill_payments_features.h"
 #include "components/autofill/core/common/autofill_util.h"
 #include "components/autofill/core/common/credit_card_network_identifiers.h"
diff --git a/components/autofill/core/browser/webdata/payments/server_cvc.h b/components/autofill/core/browser/webdata/payments/server_cvc.h
new file mode 100644
index 0000000..afbf2f24
--- /dev/null
+++ b/components/autofill/core/browser/webdata/payments/server_cvc.h
@@ -0,0 +1,32 @@
+// 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 COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_PAYMENTS_SERVER_CVC_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_PAYMENTS_SERVER_CVC_H_
+
+#include <stddef.h>
+
+#include <string>
+
+#include "base/time/time.h"
+
+namespace autofill {
+
+// Helper struct to better group server cvc related variables for better
+// passing last_updated_timestamp, which is needed for sync bridge. Limited
+// scope in autofill table & sync bridge.
+struct ServerCvc {
+  bool operator==(const ServerCvc&) const = default;
+
+  // A server generated id to identify the corresponding credit card.
+  int64_t instrument_id;
+  // CVC value of the card.
+  std::u16string cvc;
+  // The timestamp of the most recent update to the data entry.
+  base::Time last_updated_timestamp;
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_PAYMENTS_SERVER_CVC_H_
diff --git a/components/autofill_ai/core/browser/autofill_ai_client.cc b/components/autofill_ai/core/browser/autofill_ai_client.cc
index cd6e525..63e8e0db 100644
--- a/components/autofill_ai/core/browser/autofill_ai_client.cc
+++ b/components/autofill_ai/core/browser/autofill_ai_client.cc
@@ -11,32 +11,4 @@
 
 namespace autofill_ai {
 
-AutofillAiClient::EntitySaveOrUpdatePromptResult::
-    EntitySaveOrUpdatePromptResult(
-        bool did_user_decline,
-        std::optional<autofill::EntityInstance> entity)
-    : did_user_decline(did_user_decline), entity(std::move(entity)) {}
-
-AutofillAiClient::EntitySaveOrUpdatePromptResult::
-    EntitySaveOrUpdatePromptResult() = default;
-
-AutofillAiClient::EntitySaveOrUpdatePromptResult::
-    EntitySaveOrUpdatePromptResult(
-        const AutofillAiClient::EntitySaveOrUpdatePromptResult&) = default;
-
-AutofillAiClient::EntitySaveOrUpdatePromptResult::
-    EntitySaveOrUpdatePromptResult(
-        AutofillAiClient::EntitySaveOrUpdatePromptResult&&) = default;
-
-AutofillAiClient::EntitySaveOrUpdatePromptResult&
-AutofillAiClient::EntitySaveOrUpdatePromptResult::operator=(
-    const AutofillAiClient::EntitySaveOrUpdatePromptResult&) = default;
-
-AutofillAiClient::EntitySaveOrUpdatePromptResult&
-AutofillAiClient::EntitySaveOrUpdatePromptResult::operator=(
-    AutofillAiClient::EntitySaveOrUpdatePromptResult&&) = default;
-
-AutofillAiClient::EntitySaveOrUpdatePromptResult::
-    ~EntitySaveOrUpdatePromptResult() = default;
-
 }  // namespace autofill_ai
diff --git a/components/autofill_ai/core/browser/autofill_ai_client.h b/components/autofill_ai/core/browser/autofill_ai_client.h
index 72ad474..5067eae 100644
--- a/components/autofill_ai/core/browser/autofill_ai_client.h
+++ b/components/autofill_ai/core/browser/autofill_ai_client.h
@@ -28,29 +28,6 @@
 // Autofill in the settings while the client is alive.
 class AutofillAiClient {
  public:
-  // Contains the result of a user interaction with the save/update AutofillAi
-  // prompt.
-  struct EntitySaveOrUpdatePromptResult final {
-    EntitySaveOrUpdatePromptResult();
-    EntitySaveOrUpdatePromptResult(
-        bool did_user_decline,
-        std::optional<autofill::EntityInstance> entity);
-    EntitySaveOrUpdatePromptResult(const EntitySaveOrUpdatePromptResult&);
-    EntitySaveOrUpdatePromptResult(EntitySaveOrUpdatePromptResult&&);
-    EntitySaveOrUpdatePromptResult& operator=(
-        const EntitySaveOrUpdatePromptResult&);
-    EntitySaveOrUpdatePromptResult& operator=(EntitySaveOrUpdatePromptResult&&);
-    ~EntitySaveOrUpdatePromptResult();
-
-    // Whether the user explicitly declined the dialog.
-    bool did_user_decline = false;
-
-    // Non-empty iff the prompt was accepted.
-    std::optional<autofill::EntityInstance> entity;
-  };
-  using EntitySaveOrUpdatePromptResultCallback =
-      base::OnceCallback<void(EntitySaveOrUpdatePromptResult result)>;
-
   virtual ~AutofillAiClient() = default;
 
   // Returns the AutofillClient that is scoped to the same object (e.g., tab) as
@@ -64,15 +41,6 @@
   // Returns the `AutofillAiManager` associated with this
   // client.
   virtual AutofillAiManager& GetManager() = 0;
-
-  // Shows a bubble asking whether the user wants to save or update Autofill AI
-  // data. `old_entity` is present in the update cases. It is used to give users
-  // a better understanding of what was updated.
-  virtual void ShowSaveOrUpdateBubble(
-      autofill::EntityInstance new_entity,
-      std::optional<autofill::EntityInstance> old_entity,
-      EntitySaveOrUpdatePromptResultCallback
-          save_prompt_acceptance_callback) = 0;
 };
 
 }  // namespace autofill_ai
diff --git a/components/autofill_ai/core/browser/autofill_ai_manager.cc b/components/autofill_ai/core/browser/autofill_ai_manager.cc
index d436b26..c31912d 100644
--- a/components/autofill_ai/core/browser/autofill_ai_manager.cc
+++ b/components/autofill_ai/core/browser/autofill_ai_manager.cc
@@ -306,9 +306,9 @@
       auto prompt_result_callback =
           BindOnce(&AutofillAiManager::HandleSavePromptResult, GetWeakPtr(),
                    form.source_url(), entity);
-      client_->ShowSaveOrUpdateBubble(std::move(entity),
-                                      /*old_entity=*/std::nullopt,
-                                      std::move(prompt_result_callback));
+      client_->GetAutofillClient().ShowEntitySaveOrUpdateBubble(
+          std::move(entity),
+          /*old_entity=*/std::nullopt, std::move(prompt_result_callback));
       return true;
     }
     if (std::optional<std::pair<EntityInstance, EntityInstance>>
@@ -320,9 +320,9 @@
       auto prompt_result_callback =
           BindOnce(&AutofillAiManager::HandleUpdatePromptResult, GetWeakPtr(),
                    old_entity.guid());
-      client_->ShowSaveOrUpdateBubble(std::move(new_entity),
-                                      std::move(old_entity),
-                                      std::move(prompt_result_callback));
+      client_->GetAutofillClient().ShowEntitySaveOrUpdateBubble(
+          std::move(new_entity), std::move(old_entity),
+          std::move(prompt_result_callback));
       return true;
     }
   }
@@ -332,7 +332,7 @@
 void AutofillAiManager::HandleSavePromptResult(
     const GURL& form_url,
     const autofill::EntityInstance& entity,
-    AutofillAiClient::EntitySaveOrUpdatePromptResult result) {
+    autofill::AutofillClient::EntitySaveOrUpdatePromptResult result) {
   if (!result.entity) {
     if (result.did_user_decline) {
       AddStrikeForSaveAttempt(form_url, entity);
@@ -352,7 +352,7 @@
 
 void AutofillAiManager::HandleUpdatePromptResult(
     const base::Uuid& entity_uuid,
-    AutofillAiClient::EntitySaveOrUpdatePromptResult result) {
+    autofill::AutofillClient::EntitySaveOrUpdatePromptResult result) {
   if (!result.entity) {
     if (result.did_user_decline) {
       AddStrikeForUpdateAttempt(entity_uuid);
diff --git a/components/autofill_ai/core/browser/autofill_ai_manager.h b/components/autofill_ai/core/browser/autofill_ai_manager.h
index 893d860..4932eb6 100644
--- a/components/autofill_ai/core/browser/autofill_ai_manager.h
+++ b/components/autofill_ai/core/browser/autofill_ai_manager.h
@@ -91,12 +91,12 @@
   void HandleSavePromptResult(
       const GURL& form_url,
       const autofill::EntityInstance& entity,
-      AutofillAiClient::EntitySaveOrUpdatePromptResult result);
+      autofill::AutofillClient::EntitySaveOrUpdatePromptResult result);
   // Updates the `EntityDataManager` and the update strike database depending on
   // the prompt `result`.
   void HandleUpdatePromptResult(
       const base::Uuid& entity_uuid,
-      AutofillAiClient::EntitySaveOrUpdatePromptResult result);
+      autofill::AutofillClient::EntitySaveOrUpdatePromptResult result);
 
   autofill::LogManager* GetCurrentLogManager();
 
diff --git a/components/autofill_ai/core/browser/autofill_ai_manager_unittest.cc b/components/autofill_ai/core/browser/autofill_ai_manager_unittest.cc
index a787be9..74acaa4f 100644
--- a/components/autofill_ai/core/browser/autofill_ai_manager_unittest.cc
+++ b/components/autofill_ai/core/browser/autofill_ai_manager_unittest.cc
@@ -120,6 +120,22 @@
       std::move(license_plate), /*app_locale=*/"");
 }
 
+class MockAutofillClient : public autofill::TestAutofillClient {
+ public:
+  MockAutofillClient() = default;
+  MockAutofillClient(const MockAutofillClient&) = delete;
+  MockAutofillClient& operator=(const MockAutofillClient&) = delete;
+  ~MockAutofillClient() override = default;
+
+  MOCK_METHOD(
+      void,
+      ShowEntitySaveOrUpdateBubble,
+      (autofill::EntityInstance entity,
+       std::optional<autofill::EntityInstance> old_entity,
+       EntitySaveOrUpdatePromptResultCallback prompt_acceptance_callback),
+      (override));
+};
+
 class AutofillAiManagerTest : public testing::Test {
  public:
   AutofillAiManagerTest() {
@@ -181,7 +197,7 @@
     return edm().GetEntityInstances();
   }
 
-  autofill::TestAutofillClient& autofill_client() { return autofill_client_; }
+  MockAutofillClient& autofill_client() { return autofill_client_; }
   MockAutofillAiClient& client() { return client_; }
   autofill::EntityDataManager& edm() {
     return *autofill_client().GetEntityDataManager();
@@ -195,7 +211,7 @@
   autofill::test::AutofillUnitTestEnvironment autofill_test_env_;
   autofill::AutofillWebDataServiceTestHelper webdata_helper_{
       std::make_unique<autofill::EntityTable>()};
-  autofill::TestAutofillClient autofill_client_;
+  NiceMock<MockAutofillClient> autofill_client_;
   NiceMock<MockAutofillAiClient> client_;
   autofill::TestStrikeDatabase strike_database_;
   AutofillAiManager manager_{&client(), &strike_database_};
@@ -357,25 +373,28 @@
 // Tests that save prompts are only shown three times per url and entity type.
 TEST_F(AutofillAiManagerImportFormTest, StrikesForSavePromptsPerUrl) {
   constexpr char16_t kOtherPassportNumber[] = u"67867";
-  AutofillAiClient::EntitySaveOrUpdatePromptResult decline = {
+  autofill::AutofillClient::EntitySaveOrUpdatePromptResult decline = {
       /*did_user_decline=*/true, std::nullopt};
 
   MockFunction<void()> check;
   {
     InSequence s;
-    EXPECT_CALL(client(), ShowSaveOrUpdateBubble(
-                              PassportWithNumber(kDefaultPassportNumber), _, _))
+    EXPECT_CALL(autofill_client(),
+                ShowEntitySaveOrUpdateBubble(
+                    PassportWithNumber(kDefaultPassportNumber), _, _))
         .Times(2)
         .WillRepeatedly(RunOnceCallbackRepeatedly<2>(decline));
-    EXPECT_CALL(client(), ShowSaveOrUpdateBubble(
-                              PassportWithNumber(kOtherPassportNumber), _, _))
+    EXPECT_CALL(autofill_client(),
+                ShowEntitySaveOrUpdateBubble(
+                    PassportWithNumber(kOtherPassportNumber), _, _))
         .WillOnce(RunOnceCallback<2>(decline));
     EXPECT_CALL(check, Call);
-    EXPECT_CALL(client(), ShowSaveOrUpdateBubble(
-                              PassportWithNumber(kDefaultPassportNumber), _, _))
+    EXPECT_CALL(autofill_client(),
+                ShowEntitySaveOrUpdateBubble(
+                    PassportWithNumber(kDefaultPassportNumber), _, _))
         .WillOnce(RunOnceCallback<2>(decline));
-    EXPECT_CALL(client(),
-                ShowSaveOrUpdateBubble(
+    EXPECT_CALL(autofill_client(),
+                ShowEntitySaveOrUpdateBubble(
                     VehicleWithLicensePlate(kDefaultLicensePlate), _, _))
         .WillOnce(RunOnceCallback<2>(decline));
   }
@@ -404,25 +423,28 @@
 // this case, passport number).
 TEST_F(AutofillAiManagerImportFormTest, StrikesForSavePromptsPerAttribute) {
   constexpr char16_t kOtherPassportNumber[] = u"567435";
-  AutofillAiClient::EntitySaveOrUpdatePromptResult decline = {
+  autofill::AutofillClient::EntitySaveOrUpdatePromptResult decline = {
       /*did_user_decline=*/true, std::nullopt};
-  AutofillAiClient::EntitySaveOrUpdatePromptResult ignore = {
+  autofill::AutofillClient::EntitySaveOrUpdatePromptResult ignore = {
       /*did_user_decline=*/false, std::nullopt};
 
   MockFunction<void()> check;
   {
     InSequence s;
-    EXPECT_CALL(client(), ShowSaveOrUpdateBubble(
-                              PassportWithNumber(kDefaultPassportNumber), _, _))
+    EXPECT_CALL(autofill_client(),
+                ShowEntitySaveOrUpdateBubble(
+                    PassportWithNumber(kDefaultPassportNumber), _, _))
         .Times(2)
         .WillRepeatedly(RunOnceCallbackRepeatedly<2>(ignore));
-    EXPECT_CALL(client(), ShowSaveOrUpdateBubble(
-                              PassportWithNumber(kDefaultPassportNumber), _, _))
+    EXPECT_CALL(autofill_client(),
+                ShowEntitySaveOrUpdateBubble(
+                    PassportWithNumber(kDefaultPassportNumber), _, _))
         .Times(3)
         .WillRepeatedly(RunOnceCallbackRepeatedly<2>(decline));
     EXPECT_CALL(check, Call);
-    EXPECT_CALL(client(), ShowSaveOrUpdateBubble(
-                              PassportWithNumber(kOtherPassportNumber), _, _))
+    EXPECT_CALL(autofill_client(),
+                ShowEntitySaveOrUpdateBubble(
+                    PassportWithNumber(kOtherPassportNumber), _, _))
         .WillOnce(RunOnceCallback<2>(decline));
   }
 
@@ -454,40 +476,45 @@
   constexpr char16_t kOtherPassportNumber[] = u"67867";
   constexpr char16_t kOtherPassportNumber2[] = u"6785634567";
 
-  AutofillAiClient::EntitySaveOrUpdatePromptResult decline = {
+  autofill::AutofillClient::EntitySaveOrUpdatePromptResult decline = {
       /*did_user_decline=*/true, std::nullopt};
-  AutofillAiClient::EntitySaveOrUpdatePromptResult ignore = {
+  autofill::AutofillClient::EntitySaveOrUpdatePromptResult ignore = {
       /*did_user_decline=*/false, std::nullopt};
-  AutofillAiClient::EntitySaveOrUpdatePromptResult accept = {
+  autofill::AutofillClient::EntitySaveOrUpdatePromptResult accept = {
       /*did_user_decline=*/false,
       GetPassportEntityInstance({.number = kDefaultPassportNumber})};
 
   {
     InSequence s;
     // Accept the first prompt.
-    EXPECT_CALL(client(), ShowSaveOrUpdateBubble(
-                              PassportWithNumber(kDefaultPassportNumber), _, _))
+    EXPECT_CALL(autofill_client(),
+                ShowEntitySaveOrUpdateBubble(
+                    PassportWithNumber(kDefaultPassportNumber), _, _))
         .WillOnce(RunOnceCallback<2>(accept));
 
     // Accept the third prompt.
-    EXPECT_CALL(client(), ShowSaveOrUpdateBubble(
-                              PassportWithNumber(kOtherPassportNumber), _, _))
+    EXPECT_CALL(autofill_client(),
+                ShowEntitySaveOrUpdateBubble(
+                    PassportWithNumber(kOtherPassportNumber), _, _))
         .Times(2)
         .WillRepeatedly(RunOnceCallbackRepeatedly<2>(decline));
-    EXPECT_CALL(client(), ShowSaveOrUpdateBubble(
-                              PassportWithNumber(kOtherPassportNumber), _, _))
+    EXPECT_CALL(autofill_client(),
+                ShowEntitySaveOrUpdateBubble(
+                    PassportWithNumber(kOtherPassportNumber), _, _))
         .WillOnce(RunOnceCallback<2>(accept));
 
     // If the user just ignores the prompt, no strikes are recorded.
-    EXPECT_CALL(client(), ShowSaveOrUpdateBubble(
-                              PassportWithNumber(kOtherPassportNumber2), _, _))
+    EXPECT_CALL(autofill_client(),
+                ShowEntitySaveOrUpdateBubble(
+                    PassportWithNumber(kOtherPassportNumber2), _, _))
         .Times(2)
         .WillRepeatedly(RunOnceCallbackRepeatedly<2>(ignore));
 
     // Only three more prompts will be shown for the next update because the
     // user declines explicitly.
-    EXPECT_CALL(client(), ShowSaveOrUpdateBubble(
-                              PassportWithNumber(kOtherPassportNumber2), _, _))
+    EXPECT_CALL(autofill_client(),
+                ShowEntitySaveOrUpdateBubble(
+                    PassportWithNumber(kOtherPassportNumber2), _, _))
         .Times(3)
         .WillRepeatedly(RunOnceCallbackRepeatedly<2>(decline));
   }
@@ -526,9 +553,9 @@
   constexpr char16_t kOtherPassportNumber[] = u"56745";
   constexpr char16_t kOtherLicensePlate[] = u"MU-LJ-4500";
 
-  AutofillAiClient::EntitySaveOrUpdatePromptResult decline{
+  autofill::AutofillClient::EntitySaveOrUpdatePromptResult decline{
       /*did_user_interact=*/true, std::nullopt};
-  AutofillAiClient::EntitySaveOrUpdatePromptResult accept = {
+  autofill::AutofillClient::EntitySaveOrUpdatePromptResult accept = {
       /*did_user_decline=*/false,
       GetPassportEntityInstance({.number = kDefaultPassportNumber})};
   MockFunction<void()> check;
@@ -536,31 +563,34 @@
     InSequence s;
     // First, we expect to see two save attempts for a passport and two save
     // attempts for a vehicle.
-    EXPECT_CALL(client(), ShowSaveOrUpdateBubble(
-                              PassportWithNumber(kDefaultPassportNumber), _, _))
+    EXPECT_CALL(autofill_client(),
+                ShowEntitySaveOrUpdateBubble(
+                    PassportWithNumber(kDefaultPassportNumber), _, _))
         .Times(2)
         .WillRepeatedly(RunOnceCallbackRepeatedly<2>(decline));
-    EXPECT_CALL(client(),
-                ShowSaveOrUpdateBubble(
+    EXPECT_CALL(autofill_client(),
+                ShowEntitySaveOrUpdateBubble(
                     VehicleWithLicensePlate(kDefaultLicensePlate), _, _))
         .Times(2)
         .WillRepeatedly(RunOnceCallbackRepeatedly<2>(decline));
     EXPECT_CALL(check, Call);
 
     // We accept the next save prompt for a passport form.
-    EXPECT_CALL(client(), ShowSaveOrUpdateBubble(
-                              PassportWithNumber(kDefaultPassportNumber), _, _))
+    EXPECT_CALL(autofill_client(),
+                ShowEntitySaveOrUpdateBubble(
+                    PassportWithNumber(kDefaultPassportNumber), _, _))
         .WillOnce(RunOnceCallback<2>(accept));
 
     // We now only get one more vehicle save prompt (despite submitting a form
     // twice), but two more passport prompts because passport strikes were
     // reset.
-    EXPECT_CALL(client(),
-                ShowSaveOrUpdateBubble(
+    EXPECT_CALL(autofill_client(),
+                ShowEntitySaveOrUpdateBubble(
                     VehicleWithLicensePlate(kOtherLicensePlate), _, _))
         .WillOnce(RunOnceCallback<2>(decline));
-    EXPECT_CALL(client(), ShowSaveOrUpdateBubble(
-                              PassportWithNumber(kOtherPassportNumber), _, _))
+    EXPECT_CALL(autofill_client(),
+                ShowEntitySaveOrUpdateBubble(
+                    PassportWithNumber(kOtherPassportNumber), _, _))
         .Times(2)
         .WillRepeatedly(RunOnceCallbackRepeatedly<2>(decline));
   }
@@ -594,28 +624,31 @@
 // Tests that accepting a save prompt for an entity resets the strike counter
 // for the strike key attributes of that entity.
 TEST_F(AutofillAiManagerImportFormTest, AcceptingResetsStrikesPerAttribute) {
-  AutofillAiClient::EntitySaveOrUpdatePromptResult decline = {
+  autofill::AutofillClient::EntitySaveOrUpdatePromptResult decline = {
       /*did_user_decline=*/true, std::nullopt};
-  AutofillAiClient::EntitySaveOrUpdatePromptResult accept = {
+  autofill::AutofillClient::EntitySaveOrUpdatePromptResult accept = {
       /*did_user_decline=*/false,
       GetPassportEntityInstance({.number = kDefaultPassportNumber})};
   {
     InSequence s;
     // First, we expect to see two save attempts for a passport.
-    EXPECT_CALL(client(), ShowSaveOrUpdateBubble(
-                              PassportWithNumber(kDefaultPassportNumber), _, _))
+    EXPECT_CALL(autofill_client(),
+                ShowEntitySaveOrUpdateBubble(
+                    PassportWithNumber(kDefaultPassportNumber), _, _))
         .Times(2)
         .WillRepeatedly(RunOnceCallbackRepeatedly<2>(decline));
     // We accept the next save prompt for a passport form.
-    EXPECT_CALL(client(), ShowSaveOrUpdateBubble(
-                              PassportWithNumber(kDefaultPassportNumber), _, _))
+    EXPECT_CALL(autofill_client(),
+                ShowEntitySaveOrUpdateBubble(
+                    PassportWithNumber(kDefaultPassportNumber), _, _))
         .WillOnce(RunOnceCallback<2>(accept));
 
     // (User now deletes the passport.)
 
     // We now get more prompts for the same passport number again.
-    EXPECT_CALL(client(), ShowSaveOrUpdateBubble(
-                              PassportWithNumber(kDefaultPassportNumber), _, _))
+    EXPECT_CALL(autofill_client(),
+                ShowEntitySaveOrUpdateBubble(
+                    PassportWithNumber(kDefaultPassportNumber), _, _))
         .Times(2)
         .WillRepeatedly(RunOnceCallbackRepeatedly<2>(decline));
   }
@@ -648,8 +681,9 @@
 
   std::optional<EntityInstance> new_entity;
   std::optional<EntityInstance> old_entity;
-  AutofillAiClient::EntitySaveOrUpdatePromptResultCallback save_callback;
-  EXPECT_CALL(client(), ShowSaveOrUpdateBubble)
+  autofill::AutofillClient::EntitySaveOrUpdatePromptResultCallback
+      save_callback;
+  EXPECT_CALL(autofill_client(), ShowEntitySaveOrUpdateBubble)
       .WillOnce(DoAll(SaveArg<0>(&new_entity), SaveArg<1>(&old_entity),
                       MoveArg<2>(&save_callback)));
   EXPECT_TRUE(manager().OnFormSubmitted(*form, /*ukm_source_id=*/{}));
@@ -658,7 +692,7 @@
 
   // Accept the bubble.
   std::move(save_callback)
-      .Run(AutofillAiClient::EntitySaveOrUpdatePromptResult(
+      .Run(autofill::AutofillClient::EntitySaveOrUpdatePromptResult(
           /*did_user_decline=*/false, new_entity));
   // Tests that the expected entity was saved.
   base::span<const EntityInstance> saved_entities = GetEntityInstances();
@@ -684,14 +718,15 @@
   form->field(0)->set_value(u"Jon Doe");
   form->field(1)->set_value(u"1234321");
 
-  AutofillAiClient::EntitySaveOrUpdatePromptResultCallback save_callback;
-  EXPECT_CALL(client(), ShowSaveOrUpdateBubble)
+  autofill::AutofillClient::EntitySaveOrUpdatePromptResultCallback
+      save_callback;
+  EXPECT_CALL(autofill_client(), ShowEntitySaveOrUpdateBubble)
       .WillOnce(MoveArg<2>(&save_callback));
   EXPECT_TRUE(manager().OnFormSubmitted(*form, /*ukm_source_id=*/{}));
 
   // Decline the bubble.
   std::move(save_callback)
-      .Run(AutofillAiClient::EntitySaveOrUpdatePromptResult());
+      .Run(autofill::AutofillClient::EntitySaveOrUpdatePromptResult());
   // Tests that the no entity was saved.
   base::span<const EntityInstance> saved_entities = GetEntityInstances();
   EXPECT_EQ(saved_entities.size(), 0u);
@@ -705,7 +740,7 @@
   form->field(0)->set_value(u"Germany");
   form->field(1)->set_value(u"1234321");
 
-  EXPECT_CALL(client(), ShowSaveOrUpdateBubble).Times(0);
+  EXPECT_CALL(autofill_client(), ShowEntitySaveOrUpdateBubble).Times(0);
   EXPECT_FALSE(manager().OnFormSubmitted(*form, /*ukm_source_id=*/{}));
 
   // Tests that no entity was saved.
@@ -726,7 +761,7 @@
       entity, autofill::DRIVERS_LICENSE_NUMBER, /*app_locale=*/""));
   AddOrUpdateEntityInstance(entity);
 
-  EXPECT_CALL(client(), ShowSaveOrUpdateBubble).Times(0);
+  EXPECT_CALL(autofill_client(), ShowEntitySaveOrUpdateBubble).Times(0);
   EXPECT_FALSE(manager().OnFormSubmitted(*form, /*ukm_source_id=*/{}));
 
   // Tests that no entity was saved.
@@ -746,8 +781,9 @@
 
   std::optional<EntityInstance> entity;
   std::optional<EntityInstance> old_entity;
-  AutofillAiClient::EntitySaveOrUpdatePromptResultCallback save_callback;
-  EXPECT_CALL(client(), ShowSaveOrUpdateBubble)
+  autofill::AutofillClient::EntitySaveOrUpdatePromptResultCallback
+      save_callback;
+  EXPECT_CALL(autofill_client(), ShowEntitySaveOrUpdateBubble)
       .WillOnce(DoAll(SaveArg<0>(&entity), SaveArg<1>(&old_entity),
                       MoveArg<2>(&save_callback)));
 
@@ -757,7 +793,7 @@
 
   // Accept the bubble.
   std::move(save_callback)
-      .Run(AutofillAiClient::EntitySaveOrUpdatePromptResult(
+      .Run(autofill::AutofillClient::EntitySaveOrUpdatePromptResult(
           /*did_user_decline=*/false, entity));
   // Tests that the expected entity was saved.
   base::span<const EntityInstance> saved_entities = GetEntityInstances();
@@ -815,8 +851,9 @@
 
   std::optional<EntityInstance> entity;
   std::optional<EntityInstance> old_entity;
-  AutofillAiClient::EntitySaveOrUpdatePromptResultCallback save_callback;
-  EXPECT_CALL(client(), ShowSaveOrUpdateBubble)
+  autofill::AutofillClient::EntitySaveOrUpdatePromptResultCallback
+      save_callback;
+  EXPECT_CALL(autofill_client(), ShowEntitySaveOrUpdateBubble)
       .WillOnce(DoAll(SaveArg<0>(&entity), SaveArg<1>(&old_entity),
                       MoveArg<2>(&save_callback)));
   EXPECT_TRUE(manager().OnFormSubmitted(*form, /*ukm_source_id=*/{}));
@@ -826,7 +863,7 @@
 
   // Accept the bubble.
   std::move(save_callback)
-      .Run(AutofillAiClient::EntitySaveOrUpdatePromptResult(
+      .Run(autofill::AutofillClient::EntitySaveOrUpdatePromptResult(
           /*did_user_interact=*/true, entity));
   // Tests that the expected entity was updated.
   base::span<const EntityInstance> saved_entities = GetEntityInstances();
diff --git a/components/autofill_ai/core/browser/mock_autofill_ai_client.h b/components/autofill_ai/core/browser/mock_autofill_ai_client.h
index e3d98d3..9be3bd37 100644
--- a/components/autofill_ai/core/browser/mock_autofill_ai_client.h
+++ b/components/autofill_ai/core/browser/mock_autofill_ai_client.h
@@ -20,13 +20,6 @@
 
   MOCK_METHOD(autofill::AutofillClient&, GetAutofillClient, (), (override));
   MOCK_METHOD(AutofillAiManager&, GetManager, (), (override));
-  MOCK_METHOD(
-      void,
-      ShowSaveOrUpdateBubble,
-      (autofill::EntityInstance entity,
-       std::optional<autofill::EntityInstance> old_entity,
-       EntitySaveOrUpdatePromptResultCallback prompt_acceptance_callback),
-      (override));
 };
 
 }  // namespace autofill_ai
diff --git a/components/browser_ui/styles/android/BUILD.gn b/components/browser_ui/styles/android/BUILD.gn
index dcb5096..39a837865 100644
--- a/components/browser_ui/styles/android/BUILD.gn
+++ b/components/browser_ui/styles/android/BUILD.gn
@@ -191,6 +191,7 @@
     "java/res/drawable/ic_drive_document_24dp.xml",
     "java/res/drawable/ic_drive_file_24dp.xml",
     "java/res/drawable/ic_drive_image_24dp.xml",
+    "java/res/drawable/ic_extension_24dp.xml",
     "java/res/drawable/ic_eye_crossed.xml",
     "java/res/drawable/ic_fast_forward_white_24dp.xml",
     "java/res/drawable/ic_fast_rewind_white_24dp.xml",
diff --git a/components/browser_ui/styles/android/java/res/drawable/ic_extension_24dp.xml b/components/browser_ui/styles/android/java/res/drawable/ic_extension_24dp.xml
new file mode 100644
index 0000000..f08b267
--- /dev/null
+++ b/components/browser_ui/styles/android/java/res/drawable/ic_extension_24dp.xml
@@ -0,0 +1,16 @@
+<?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="24dp"
+    android:height="24dp"
+    android:viewportWidth="960"
+    android:viewportHeight="960">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M200,840Q167,840 143.5,816.5Q120,793 120,760L120,608Q168,608 204,577.5Q240,547 240,500Q240,453 204,422.5Q168,392 120,392L120,240Q120,207 143.5,183.5Q167,160 200,160L360,160Q360,118 389,89Q418,60 460,60Q502,60 531,89Q560,118 560,160L720,160Q753,160 776.5,183.5Q800,207 800,240L800,400Q842,400 871,429Q900,458 900,500Q900,542 871,571Q842,600 800,600L800,760Q800,793 776.5,816.5Q753,840 720,840L200,840ZM200,760L720,760L720,240L200,240L200,328Q254,348 287,395Q320,442 320,500Q320,557 287,604Q254,651 200,672L200,760ZM460,500L460,500L460,500Q460,500 460,500Q460,500 460,500Q460,500 460,500L460,500L460,500Z"/>
+</vector>
\ No newline at end of file
diff --git a/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc b/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc
index cf06f978..195b4285 100644
--- a/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc
+++ b/components/chromeos_camera/jpeg_encode_accelerator_unittest.cc
@@ -357,7 +357,8 @@
   scoped_refptr<media::VideoFrame> hw_out_frame_;
 
   // Used to create Gpu memory buffer for DMA-buf encoding tests.
-  std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager_;
+  std::unique_ptr<media::LocalGpuMemoryBufferManager>
+      gpu_memory_buffer_manager_;
 
   base::WeakPtrFactory<JpegClient> weak_factory_{this};
 };
diff --git a/components/enterprise/common/proto/BUILD.gn b/components/enterprise/common/proto/BUILD.gn
index f365b7d..f89d0f3 100644
--- a/components/enterprise/common/proto/BUILD.gn
+++ b/components/enterprise/common/proto/BUILD.gn
@@ -29,9 +29,6 @@
     "//components/safe_browsing/core/common/proto:csd_proto",
     "//components/safe_browsing/core/common/proto:csd_proto_extras",
   ]
-
-  # The fuzzable_proto_library rule above uses the full protobuf runtime.
-  protobuf_full_support = true
 }
 
 proto_library("dlp_policy_event_proto") {
diff --git a/components/input/android/input_receiver_data.cc b/components/input/android/input_receiver_data.cc
index 2c03b95..8544638 100644
--- a/components/input/android/input_receiver_data.cc
+++ b/components/input/android/input_receiver_data.cc
@@ -6,6 +6,8 @@
 
 #include <utility>
 
+#include "base/android/android_info.h"
+
 namespace input {
 
 InputReceiverData::InputReceiverData(
@@ -26,9 +28,9 @@
 
 InputReceiverData::~InputReceiverData() = default;
 
-void InputReceiverData::OnDestroyedCompositorFrameSink(
-    const viz::FrameSinkId& frame_sink_id) {
-  if (root_frame_sink_id() != frame_sink_id) {
+void InputReceiverData::OnDestroyedCompositorFrameSink() {
+  if (base::android::android_info::sdk_int() >=
+      base::android::android_info::SdkVersion::SDK_VERSION_BAKLAVA) {
     return;
   }
   pending_destruction_ = true;
diff --git a/components/input/android/input_receiver_data.h b/components/input/android/input_receiver_data.h
index 922921f..b93f225 100644
--- a/components/input/android/input_receiver_data.h
+++ b/components/input/android/input_receiver_data.h
@@ -31,7 +31,7 @@
 
   ~InputReceiverData();
 
-  void OnDestroyedCompositorFrameSink(const viz::FrameSinkId& frame_sink_id);
+  void OnDestroyedCompositorFrameSink();
 
   const viz::FrameSinkId& root_frame_sink_id() {
     return android_input_callback_->root_frame_sink_id();
diff --git a/components/input/android/scoped_input_receiver.cc b/components/input/android/scoped_input_receiver.cc
index 5cb2be6..5d5def8 100644
--- a/components/input/android/scoped_input_receiver.cc
+++ b/components/input/android/scoped_input_receiver.cc
@@ -4,6 +4,7 @@
 
 #include "components/input/android/scoped_input_receiver.h"
 
+#include "base/android/android_info.h"
 #include "base/android/android_input_receiver_compat.h"
 
 namespace input {
@@ -34,10 +35,12 @@
   if (a_input_receiver_ == nullptr) {
     return;
   }
-  // Not calling release due to AOSP crash on calling the API -
-  // b/368251173.
-  // base::AndroidInputReceiverCompat::GetInstance()
-  //   .AInputReceiver_releaseFn(a_input_receiver_);
+  if (base::android::android_info::sdk_int() >=
+      base::android::android_info::SdkVersion::SDK_VERSION_BAKLAVA) {
+    // Calling AInputReceiver_release on Android V, results in app crash.
+    base::AndroidInputReceiverCompat::GetInstance().AInputReceiver_releaseFn(
+        a_input_receiver_);
+  }
   a_input_receiver_ = nullptr;
 }
 
diff --git a/components/proto_extras/BUILD.gn b/components/proto_extras/BUILD.gn
index 8861c57..efdb310e 100644
--- a/components/proto_extras/BUILD.gn
+++ b/components/proto_extras/BUILD.gn
@@ -2,39 +2,27 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//testing/libfuzzer/fuzzer_test.gni")
-
 if (current_toolchain == host_toolchain) {
   executable("proto_extras_plugin") {
     sources = [ "proto_extras_plugin.cc" ]
     deps = [
       "//base",
-      "//third_party/protobuf:protoc_cpp",
       "//third_party/protobuf:protoc_lib",
+      "//third_party/protobuf:protoc_cpp",
     ]
   }
 }
 
-source_set("proto_extras_lib") {
+component("proto_extras_lib") {
   public = [ "proto_extras_lib.h" ]
+  sources = [
+    "proto_extras_lib.cc"
+  ]
   public_deps = [
     "//base",
     "//third_party/protobuf:protobuf_lite",
   ]
-}
-
-if (use_fuzzing_engine_with_lpm) {
-  # Component for protobuf_full support of our serialization, which is required
-  # by proto fuzzers.
-  source_set("protobuf_full_support") {
-    public = [ "protobuf_full_support.h" ]
-    sources = [ "protobuf_full_support.cc" ]
-    public_deps = [
-      ":proto_extras_lib",
-      "//base",
-      "//third_party/protobuf:protobuf_full",
-    ]
-  }
+  defines = [ "IS_PROTO_EXTRAS_IMPL" ]
 }
 
 source_set("unit_tests") {
diff --git a/components/proto_extras/proto_extras.gni b/components/proto_extras/proto_extras.gni
index 9e9c6ad..f1eba2b7 100644
--- a/components/proto_extras/proto_extras.gni
+++ b/components/proto_extras/proto_extras.gni
@@ -2,26 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-# Generate extra functionality for protobuf messages, including:
-# - Serialization to base::DictValue.
-# - Stream operator support for C++ printing.
-# - (future) equality operator support
-# - (future) gtest matchers.
-# This does not directly generate the protobuf bindings for any language, so
+# Generate serializers that turn a protobuf into a base::Value. This
+# does not directly generate the protobuf bindings for any language, so
 # callers must include the build target for C++ bindings in the deps.
 #
-# This is a wrapper around proto_library that adds the proto_extras plugin. It
-# is intended to be used in conjunction with proto_library, not on its own.
-#
-# The generated C++ code will be named <name>.extras.h and <name>.extras.cc.
-# The primary entry point is <name>.extras.h, which declares the generated
-# serialization and streaming operators.
-#
-# For cases where the message uses the full google::protobuf::Message type,
-# the protobuf_full_support option can be used to ensure the generated code
-# with the full protobuf library. Due to android build complications, this also
-# requires the `use_fuzzing_engine_with_lpm` build flag to be set.
-#
 # Caveats:
 # - Integer types in the proto that are not compatible with base::Value are
 #   serialized as strings (e.g. uint64_t).
@@ -35,28 +19,19 @@
 #     deps = [
 #       "mylib_proto_target"
 #     ]
-#     omit_to_value_serialization = true   # default is false
-#     omit_stream_operators = true         # default is false
+#     # Optional: Set to true to generate C++ stream operators (operator<<)
+#     # for the proto messages, which will print the message using
+#     # base::Value::DebugString().
+#     # Defaults to false.
+#     generate_stream_operators = true
 #   }
 
-import("//testing/libfuzzer/fuzzer_test.gni")
 import("//third_party/protobuf/proto_library.gni")
 
 template("proto_extras") {
-  _options = []
-  if (defined(invoker.omit_to_value_serialization) &&
-      invoker.omit_to_value_serialization) {
-    _options += [ "omit_to_value_serialization" ]
-  }
-  if (defined(invoker.omit_stream_operators) && invoker.omit_stream_operators) {
-    _options += [ "omit_stream_operators" ]
-  }
-
-  _protobuf_full_support = false
-  if (defined(invoker.protobuf_full_support) && invoker.protobuf_full_support &&
-      use_fuzzing_engine_with_lpm) {
-    _options += [ "protobuf_full_support" ]
-    _protobuf_full_support = true
+  _generate_stream_operators = false
+  if (defined(invoker.generate_stream_operators)) {
+    _generate_stream_operators = invoker.generate_stream_operators
   }
 
   proto_library("${target_name}") {
@@ -69,16 +44,16 @@
     }
 
     generator_plugin_label = "//components/proto_extras:proto_extras_plugin"
-    generator_plugin_suffix = ".extras"
+    generator_plugin_suffix = ".to_value"
     generate_cc = false
     generate_python = false
     link_public_deps = [ "//base" ]
-    link_deps = [ "//components/proto_extras:proto_extras_lib" ]
-    if (_protobuf_full_support) {
-      link_deps += [ "//components/proto_extras:protobuf_full_support" ]
-    }
-    if (_options != []) {
-      generator_plugin_options = string_join(",", _options)
+    link_deps = [
+      "//components/proto_extras:proto_extras_lib",
+    ]
+
+    if (_generate_stream_operators) {
+      generator_plugin_options = "generate_stream_operators"
     }
   }
 }
diff --git a/components/proto_extras/protobuf_full_support.cc b/components/proto_extras/proto_extras_lib.cc
similarity index 95%
rename from components/proto_extras/protobuf_full_support.cc
rename to components/proto_extras/proto_extras_lib.cc
index 31deed6d..11af1c9d 100644
--- a/components/proto_extras/protobuf_full_support.cc
+++ b/components/proto_extras/proto_extras_lib.cc
@@ -2,11 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/proto_extras/protobuf_full_support.h"
+#include "components/proto_extras/proto_extras_lib.h"
 
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
-#include "components/proto_extras/proto_extras_lib.h"
 #include "third_party/protobuf/src/google/protobuf/unknown_field_set.h"
 
 namespace proto_extras {
diff --git a/components/proto_extras/proto_extras_lib.h b/components/proto_extras/proto_extras_lib.h
index f14e7f77..7dd41e4 100644
--- a/components/proto_extras/proto_extras_lib.h
+++ b/components/proto_extras/proto_extras_lib.h
@@ -13,19 +13,39 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
+#include "third_party/protobuf/src/google/protobuf/message.h"
+#include "third_party/protobuf/src/google/protobuf/message_lite.h"
 
 namespace google::protobuf {
-class MessageLite;
+class UnknownFieldSet;
 }  // namespace google::protobuf
 
 namespace proto_extras {
 
-// Specialization for MessageLite protos, which always returns a std::string
-// for unknown fields.
-template <typename MessageType>
-  requires requires(MessageType message) {
-    { message.unknown_fields() } -> std::same_as<const std::string&>;
+COMPONENT_EXPORT(PROTO_EXTRAS) base::DictValue Serialize(
+    const google::protobuf::UnknownFieldSet& unknown_fields);
+
+// Specialization for Message protos, which use the UnknownFieldSet type
+// allowing for more readable serialization.
+template <typename MessageType,
+          typename std::enable_if_t<
+              std::is_base_of<google::protobuf::Message, MessageType>::value,
+              int> = 0>
+void SerializeUnknownFields(const MessageType& message, base::DictValue& dict) {
+  if (message.unknown_fields().empty()) {
+    return;
   }
+  dict.Set("unknown_fields", Serialize(message.unknown_fields()));
+}
+
+// Specialization for MessageLite protos. These types don't use the
+// UnknownFieldSet, and instead store all unknown fields in a string of bytes.
+template <
+    typename MessageType,
+    typename std::enable_if<
+        std::is_base_of<google::protobuf::MessageLite, MessageType>::value &&
+            !std::is_base_of<google::protobuf::Message, MessageType>::value,
+        int>::type = 0>
 void SerializeUnknownFields(const MessageType& message, base::DictValue& dict) {
   if (message.unknown_fields().empty()) {
     return;
diff --git a/components/proto_extras/proto_extras_plugin.cc b/components/proto_extras/proto_extras_plugin.cc
index ee2d2a5..77216be 100644
--- a/components/proto_extras/proto_extras_plugin.cc
+++ b/components/proto_extras/proto_extras_plugin.cc
@@ -2,21 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <string>
-
 #include "base/check.h"
 #include "base/containers/contains.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
-#include "base/notreached.h"
-#include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "third_party/abseil-cpp/absl/container/flat_hash_set.h"
 #include "third_party/protobuf/src/google/protobuf/compiler/code_generator.h"
-#include "third_party/protobuf/src/google/protobuf/compiler/cpp/helpers.h"
 #include "third_party/protobuf/src/google/protobuf/compiler/cpp/names.h"
+#include "third_party/protobuf/src/google/protobuf/compiler/cpp/helpers.h"
 #include "third_party/protobuf/src/google/protobuf/compiler/importer.h"
 #include "third_party/protobuf/src/google/protobuf/compiler/plugin.h"
 #include "third_party/protobuf/src/google/protobuf/descriptor.h"
@@ -31,123 +26,14 @@
 using google::protobuf::io::Printer;
 using google::protobuf::io::ZeroCopyOutputStream;
 
-struct ProtoExtrasGeneratorOptions {
-  bool generate_to_value_serialization;
+struct ToValueGeneratorOptions {
   bool generate_stream_operator;
-  bool protobuf_full_support;
 };
 
-void FieldToValueFunction(const FieldDescriptor& field, Printer* printer) {
-  using enum FieldDescriptor::Type;
-  auto conversion_function = [&]() -> std::string {
-    switch (field.type()) {
-      case TYPE_DOUBLE:
-      case TYPE_FLOAT:
-        return "static_cast<double>";
-      case TYPE_INT32:
-      case TYPE_INT64:
-      case TYPE_UINT64:
-      case TYPE_UINT32:
-      case TYPE_FIXED64:
-      case TYPE_FIXED32:
-      case TYPE_SFIXED64:
-      case TYPE_SFIXED32:
-      case TYPE_SINT64:
-      case TYPE_SINT32:
-        return "::proto_extras::ToNumericTypeForValue";
-      case TYPE_BOOL:
-        return "static_cast<bool>";
-      case TYPE_STRING:
-        return "static_cast<std::string>";
-      case TYPE_BYTES:
-        return "base::Base64Encode";
-      case TYPE_ENUM:
-        return base::StrCat(
-            {google::protobuf::compiler::cpp::QualifiedClassName(
-                 field.enum_type()),
-             "_Name"});
-      case TYPE_MESSAGE:
-      case TYPE_GROUP:
-        // The Serialize function for the message is in the namespace of the
-        // nested message itself.
-        return base::StrCat(
-            {google::protobuf::compiler::cpp::Namespace(field.message_type()),
-             "::Serialize"});
-    }
-    NOTREACHED();
-  };
-  printer->Print(conversion_function());
-}
-
-void CreateSerializationDefinitions(
-    const Descriptor& message,
-    Printer* printer,
-    const ProtoExtrasGeneratorOptions& options) {
-  printer->Emit(
-      {{"message_type", google::protobuf::compiler::cpp::ClassName(&message)},
-       {"serialize_fields",
-        [&]() {
-          for (int j = 0; j < message.field_count(); j++) {
-            const FieldDescriptor& field = *message.field(j);
-            std::string field_name(field.lowercase_name());
-
-            auto field_to_value = [&]() {
-              FieldToValueFunction(field, printer);
-            };
-            if (field.is_repeated()) {
-              printer->Emit({{"field_name", field_name},
-                             {"field_to_value", field_to_value}},
-                            R"(
-  if (!message.$field_name$().empty()) {
-    base::ListValue list;
-    for (const auto& value : message.$field_name$()) {
-      list.Append($field_to_value$(value));
-    }
-    dict.Set("$field_name$", std::move(list));
-  }
-)");
-            } else if (field.has_presence()) {
-              printer->Emit({{"field_name", field_name},
-                             {"field_to_value", field_to_value}},
-                            R"(
-  if (message.has_$field_name$()) {
-    dict.Set("$field_name$", $field_to_value$(message.$field_name$()));
-  }
-)");
-            } else if (field.type() == FieldDescriptor::Type::TYPE_STRING ||
-                       field.type() == FieldDescriptor::Type::TYPE_BYTES) {
-              printer->Emit({{"field_name", field_name},
-                             {"field_to_value", field_to_value}},
-                            R"(
-  if (!message.$field_name$().empty()) {
-    dict.Set("$field_name$", $field_to_value$(message.$field_name$()));
-  }
-)");
-            } else {
-              printer->Emit({{"field_name", field_name},
-                             {"field_to_value", field_to_value}},
-                            R"(
-  dict.Set("$field_name$", $field_to_value$(message.$field_name$()));
-)");
-            }
-          }
-        }}},
-      R"(
-base::DictValue Serialize(const $message_type$& message) {
-  base::DictValue dict;
-  if (!message.unknown_fields().empty()) {
-    ::proto_extras::SerializeUnknownFields(message, dict);
-  }
-  $serialize_fields$
-  return dict;
-}
-)");
-}
-
-class ProtoExtrasGenerator : public google::protobuf::compiler::CodeGenerator {
+class ToValueGenerator : public google::protobuf::compiler::CodeGenerator {
  public:
-  ProtoExtrasGenerator() = default;
-  ~ProtoExtrasGenerator() override = default;
+  ToValueGenerator() = default;
+  ~ToValueGenerator() override = default;
 
   bool Generate(const FileDescriptor* file,
                 const std::string& options,  // Options from build system
@@ -155,22 +41,11 @@
                 std::string* error) const override {
     CHECK(file);
 
-    ProtoExtrasGeneratorOptions generator_options{
-        .generate_to_value_serialization =
-            !base::Contains(options, "omit_to_value_serialization"),
-        .generate_stream_operator =
-            !base::Contains(options, "omit_stream_operators"),
-        .protobuf_full_support =
-            base::Contains(options, "protobuf_full_support"),
-    };
-    CHECK(generator_options.generate_to_value_serialization ||
-          generator_options.generate_stream_operator);
-
-    base::FilePath proto_file_path = base::FilePath::FromASCII(file->name());
+    base::FilePath base_file_path = ToValueFilePath(file->name());
     base::FilePath h_file_path =
-        proto_file_path.ReplaceExtension(FILE_PATH_LITERAL("extras.h"));
+        base_file_path.AddExtension(FILE_PATH_LITERAL("to_value.h"));
     base::FilePath cc_file_path =
-        proto_file_path.ReplaceExtension(FILE_PATH_LITERAL("extras.cc"));
+        base_file_path.AddExtension(FILE_PATH_LITERAL("to_value.cc"));
 
     const std::unique_ptr<ZeroCopyOutputStream> h_stream(
         context->Open(h_file_path.AsUTF8Unsafe()));
@@ -180,127 +55,102 @@
     Printer h_printer(h_stream.get(), Printer::Options{'$', nullptr});
     Printer cc_printer(cc_stream.get(), Printer::Options{'$', nullptr});
 
+    ToValueGeneratorOptions generator_options;
+    generator_options.generate_stream_operator =
+        base::Contains(options, "generate_stream_operators");
     std::string include_guard =
         base::ToUpperASCII(h_file_path.AsUTF8Unsafe()) + "_";
     CHECK(base::ReplaceChars(include_guard, ".-/\\", "_", &include_guard));
 
-    h_printer.Emit(
-        {
-            {"include_guard", include_guard},
-            {"proto_file_path", proto_file_path.AsUTF8Unsafe()},
-            {"includes",
-             [&] {
-               if (generator_options.generate_stream_operator) {
-                 h_printer.Print("#include <iosfwd>\n\n");
-               }
-               h_printer.Print(
-                   "#include \"$f$\"\n", "f",
-                   proto_file_path.ReplaceExtension(FILE_PATH_LITERAL("pb.h"))
-                       .AsUTF8Unsafe());
-             }},
-            {"function_declarations",
-             [&] {
-               google::protobuf::compiler::cpp::NamespaceOpener ns(
-                   google::protobuf::compiler::cpp::Namespace(file),
-                   &h_printer);
-               for (int i = 0; i < file->message_type_count(); i++) {
-                 PrintFunctionDeclarations(*file->message_type(i), &h_printer,
-                                           error, generator_options);
-               }
-             }},
-        },
-        R"(// Generated by the proto_to_extras plugin.  DO NOT EDIT!
-// source: $proto_file_path$
+    std::string kHeader =
+        "// Generated by the proto to value plugin.  DO NOT EDIT!\n\n";
+    h_printer.Print(kHeader);
+    h_printer.Print("#ifndef $g$\n#define $g$\n\n", "g", include_guard);
 
-#ifndef $include_guard$
-#define $include_guard$
-
-$includes$
-
-namespace base {
-class DictValue;
-}  // namespace base
-
-$function_declarations$
-
-#endif  // $include_guard$
-)");
-
-    // Determine the #includes for the implementation file.
-    absl::flat_hash_set<std::string> impl_system_inclues;
-    // Always have the header and pb.h for the message.
-    absl::flat_hash_set<std::string> impl_user_includes = {
-        h_file_path.AsUTF8Unsafe(),
-        proto_file_path.ReplaceExtension(FILE_PATH_LITERAL("pb.h"))
+    if (generator_options.generate_stream_operator) {
+      h_printer.Print("#include <iosfwd>\n\n");
+    }
+    std::vector<std::string> header_include_files = {
+        "base/values.h",
+        base_file_path.BaseName()
+            .AddExtension(FILE_PATH_LITERAL("pb.h"))
             .AsUTF8Unsafe(),
     };
+    for (const auto& include : header_include_files) {
+      h_printer.Print("#include \"$f$\"\n", "f", include);
+    }
+    h_printer.Print("\n");
+
+    {
+      google::protobuf::compiler::cpp::NamespaceOpener ns(
+          google::protobuf::compiler::cpp::Namespace(file), &h_printer);
+      for (int i = 0; i < file->message_type_count(); i++) {
+        if (!PrintFunctionDeclarations(*file->message_type(i), &h_printer,
+                                       error, generator_options)) {
+          return false;
+        }
+      }
+    }
+    h_printer.Print("\n#endif  // $g$\n", "g", include_guard);
+
+    cc_printer.Print(kHeader);
+    cc_printer.Print("\n");
     if (generator_options.generate_stream_operator) {
-      impl_system_inclues.insert("<ostream>");
+      cc_printer.Print("#include <ostream>\n\n");
     }
-    if (generator_options.generate_to_value_serialization) {
-      impl_user_includes.insert({"base/base64.h", "base/values.h",
-                                 "components/proto_extras/proto_extras_lib.h"});
-    }
+    std::vector<std::string> impl_include_files = {
+        "base/base64.h",
+        "base/values.h",
+        base_file_path.BaseName()
+            .AddExtension(FILE_PATH_LITERAL("pb.h"))
+            .AsUTF8Unsafe(),
+        h_file_path.AsUTF8Unsafe(),
+        "components/proto_extras/proto_extras_lib.h",
+    };
     for (int i = 0; i < file->dependency_count(); i++) {
-      base::FilePath dependency_proto_file_path =
-          base::FilePath::FromASCII(file->dependency(i)->name());
-      impl_user_includes.insert(
-          dependency_proto_file_path
-              .ReplaceExtension(FILE_PATH_LITERAL("extras.h"))
+      impl_include_files.push_back(
+          ToValueFilePath(file->dependency(i)->name())
+              .AddExtension(FILE_PATH_LITERAL("to_value.h"))
               .AsUTF8Unsafe());
     }
-    if (generator_options.protobuf_full_support) {
-      impl_user_includes.insert(
-          "components/proto_extras/protobuf_full_support.h");
+    for (const auto& include : impl_include_files) {
+      cc_printer.Print("#include \"$f$\"\n", "f", include);
     }
-    cc_printer.Emit(
-        {
-            {"proto_file_path", proto_file_path.AsUTF8Unsafe()},
-            {"includes",
-             [&] {
-               for (const auto& include : impl_system_inclues) {
-                 cc_printer.Print("#include $f$\n", "f", include);
-               }
-               for (const auto& include : impl_user_includes) {
-                 cc_printer.Print("#include \"$f$\"\n", "f", include);
-               }
-             }},
-            {"function_definitions",
-             [&] {
-               google::protobuf::compiler::cpp::NamespaceOpener ns(
-                   google::protobuf::compiler::cpp::Namespace(file),
-                   &cc_printer);
-               for (int i = 0; i < file->message_type_count(); i++) {
-                 PrintFunctionDefinitions(*file->message_type(i), &cc_printer,
-                                          error, generator_options);
-               }
-             }},
-        },
-        R"(// Generated by the proto_to_extras plugin.  DO NOT EDIT!
-// source: $proto_file_path$
+    cc_printer.Print("\n");
 
-$includes$
-
-$function_definitions$
-)");
+    {
+      google::protobuf::compiler::cpp::NamespaceOpener ns(
+          google::protobuf::compiler::cpp::Namespace(file), &cc_printer);
+      for (int i = 0; i < file->message_type_count(); i++) {
+        if (!PrintFunctionDefinition(*file->message_type(i), &cc_printer, error,
+                                     generator_options)) {
+          return false;
+        }
+      }
+    }
     return true;
   }
 
-  bool PrintFunctionDeclarations(
-      const Descriptor& message,
-      Printer* printer,
-      std::string* error,
-      const ProtoExtrasGeneratorOptions& options) const {
+ private:
+  base::FilePath ToValueFilePath(std::string_view file_name) const {
+#if BUILDFLAG(IS_WIN)
+    return base::FilePath(base::ASCIIToWide(file_name)).RemoveExtension();
+#else
+    return base::FilePath(file_name).RemoveExtension();
+#endif
+  }
+
+  bool PrintFunctionDeclarations(const Descriptor& message,
+                                 Printer* printer,
+                                 std::string* error,
+                                 const ToValueGeneratorOptions& options) const {
     std::string message_type =
         google::protobuf::compiler::cpp::ClassName(&message);
-    if (options.generate_to_value_serialization) {
-      printer->Print("base::DictValue Serialize(const $m$& message);\n", "m",
-                     message_type);
-    }
+    printer->Print("base::Value::Dict Serialize(const $m$& message);\n", "m",
+                   message_type);
     if (options.generate_stream_operator) {
       printer->Print(
-          "std::ostream& operator<<(std::ostream& out, const "
-          "$m$& message);\n",
+          "std::ostream& operator<<(std::ostream& out, const $m$& message);\n",
           "m", message_type);
     }
     for (int i = 0; i < message.nested_type_count(); i++) {
@@ -313,38 +163,134 @@
     return true;
   }
 
-  bool PrintFunctionDefinitions(
-      const Descriptor& message,
-      Printer* printer,
-      std::string* error,
-      const ProtoExtrasGeneratorOptions& options) const {
-    if (options.generate_to_value_serialization) {
-      CreateSerializationDefinitions(message, printer, options);
+  bool PrintFunctionDefinition(const Descriptor& message,
+                               Printer* printer,
+                               std::string* error,
+                               const ToValueGeneratorOptions& options) const {
+    std::string message_type =
+        google::protobuf::compiler::cpp::ClassName(&message);
+    printer->Print("base::Value::Dict Serialize(const $m$& message) {\n", "m",
+                   message_type);
+    printer->Indent();
+    printer->Print("base::Value::Dict dict;\n\n");
+    for (int j = 0; j < message.field_count(); j++) {
+      const FieldDescriptor* field = message.field(j);
+      std::string field_name(field->lowercase_name());
+      if (field->is_repeated()) {
+        printer->Print("if (!message.$f$().empty()) {\n", "f", field_name);
+        printer->Indent();
+        printer->Print("base::Value::List list;\n");
+        printer->Print("for (const auto& value : message.$f$()) {\n", "f",
+                       field_name);
+        printer->Indent();
+        printer->Print("list.Append(");
+        PrintFieldToValue(*field, printer);
+        printer->Print("(value));\n");
+        printer->Outdent();
+        printer->Print("}\n");
+        printer->Print("dict.Set(\"$f$\", std::move(list));\n", "f",
+                       field_name);
+        printer->Outdent();
+        printer->Print("}\n");
+      } else if (field->has_presence()) {
+        printer->Print("if (message.has_$f$()) {\n", "f", field_name);
+        printer->Indent();
+        printer->Print("dict.Set(\"$f$\", ", "f", field_name);
+        PrintFieldToValue(*field, printer);
+        printer->Print("(message.$f$()));\n", "f", field_name);
+        printer->Outdent();
+        printer->Print("}\n");
+      } else if (field->type() == FieldDescriptor::Type::TYPE_STRING ||
+                 field->type() == FieldDescriptor::Type::TYPE_BYTES) {
+        printer->Print("if (!message.$f$().empty()) {\n", "f", field_name);
+        printer->Indent();
+        printer->Print("dict.Set(\"$f$\", ", "f", field_name);
+        PrintFieldToValue(*field, printer);
+        printer->Print("(message.$f$()));\n", "f", field_name);
+        printer->Outdent();
+        printer->Print("}\n");
+      } else {
+        printer->Print("dict.Set(\"$f$\", ", "f", field_name);
+        PrintFieldToValue(*field, printer);
+        printer->Print("(message.$f$()));\n", "f", field_name);
+      }
     }
+    printer->Print("if (!message.unknown_fields().empty()) {\n");
+    printer->Indent();
+    printer->Print(
+        "::proto_extras::SerializeUnknownFields(message, dict);\n");
+    printer->Outdent();
+    printer->Print("}\n");
+    printer->Print("return dict;\n");
+    printer->Outdent();
+    printer->Print("}\n");
+
     if (options.generate_stream_operator) {
-      std::string message_type =
-          google::protobuf::compiler::cpp::ClassName(&message);
-      printer->Emit({{"message_type", message_type}},
-                    R"(
-std::ostream& operator<<(std::ostream& out, const $message_type$& message) {
-  return out << Serialize(message).DebugString();
-}
-)");
+      printer->Print(
+          "\nstd::ostream& operator<<(std::ostream& out, const $m$& message) "
+          "{\n",
+          "m", message_type);
+      printer->Indent();
+      printer->Print("return out << Serialize(message).DebugString();\n");
+      printer->Outdent();
+      printer->Print("}\n");
     }
 
     for (int i = 0; i < message.nested_type_count(); i++) {
-      if (!PrintFunctionDefinitions(*message.nested_type(i), printer, error,
-                                    options)) {
+      if (!PrintFunctionDefinition(*message.nested_type(i), printer, error,
+                                   options)) {
         return false;
       }
     }
 
     return true;
   }
+
+  void PrintFieldToValue(const FieldDescriptor& field, Printer* printer) const {
+    using enum FieldDescriptor::Type;
+    switch (field.type()) {
+      case TYPE_DOUBLE:
+      case TYPE_FLOAT:
+        printer->Print("static_cast<double>");
+        break;
+      case TYPE_INT32:
+      case TYPE_INT64:
+      case TYPE_UINT64:
+      case TYPE_UINT32:
+      case TYPE_FIXED64:
+      case TYPE_FIXED32:
+      case TYPE_SFIXED64:
+      case TYPE_SFIXED32:
+      case TYPE_SINT64:
+      case TYPE_SINT32:
+        printer->Print("::proto_extras::ToNumericTypeForValue");
+        break;
+      case TYPE_BOOL:
+        printer->Print("static_cast<bool>");
+        break;
+      case TYPE_STRING:
+        printer->Print("static_cast<std::string>");
+        break;
+      case TYPE_BYTES:
+        printer->Print("base::Base64Encode");
+        break;
+      case TYPE_ENUM:
+        printer->Print("$t$_Name", "t",
+                       google::protobuf::compiler::cpp::QualifiedClassName(
+                           field.enum_type()));
+        break;
+      case TYPE_MESSAGE:
+      case TYPE_GROUP:
+        printer->Print("$p$::Serialize", "p",
+                       google::protobuf::compiler::cpp::Namespace(field.message_type()));
+        break;
+    }
+  }
 };
+
 }  // namespace
 
 int main(int argc, char** argv) {
-  ProtoExtrasGenerator generator;
+  ToValueGenerator generator;
   return google::protobuf::compiler::PluginMain(argc, argv, &generator);
 }
diff --git a/components/proto_extras/proto_extras_unittest.cc b/components/proto_extras/proto_extras_unittest.cc
index bf7b00d..73a07f5 100644
--- a/components/proto_extras/proto_extras_unittest.cc
+++ b/components/proto_extras/proto_extras_unittest.cc
@@ -3,12 +3,12 @@
 // found in the LICENSE file.
 
 #include "base/test/values_test_util.h"
-#include "components/proto_extras/test_proto/test_proto.extras.h"
 #include "components/proto_extras/test_proto/test_proto.pb.h"
-#include "components/proto_extras/test_proto/test_proto_dependency.extras.h"
+#include "components/proto_extras/test_proto/test_proto.to_value.h"
 #include "components/proto_extras/test_proto/test_proto_dependency.pb.h"
-#include "components/proto_extras/test_proto2/test_proto2.extras.h"
+#include "components/proto_extras/test_proto/test_proto_dependency.to_value.h"
 #include "components/proto_extras/test_proto2/test_proto2.pb.h"
+#include "components/proto_extras/test_proto2/test_proto2.to_value.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace proto_extras {
diff --git a/components/proto_extras/protobuf_full_support.h b/components/proto_extras/protobuf_full_support.h
deleted file mode 100644
index ef668fc..0000000
--- a/components/proto_extras/protobuf_full_support.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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 COMPONENTS_PROTO_EXTRAS_PROTOBUF_FULL_SUPPORT_H_
-#define COMPONENTS_PROTO_EXTRAS_PROTOBUF_FULL_SUPPORT_H_
-
-#include "base/component_export.h"
-#include "base/values.h"
-#include "third_party/protobuf/src/google/protobuf/message.h"
-#include "third_party/protobuf/src/google/protobuf/unknown_field_set.h"
-
-namespace google::protobuf {
-class UnknownFieldSet;
-}  // namespace google::protobuf
-
-namespace proto_extras {
-
-base::DictValue Serialize(
-    const google::protobuf::UnknownFieldSet& unknown_fields);
-
-template <typename MessageType>
-  requires std::is_base_of_v<google::protobuf::Message, MessageType>
-void SerializeUnknownFields(const MessageType& message, base::DictValue& dict) {
-  if (message.unknown_fields().empty()) {
-    return;
-  }
-  dict.Set("unknown_fields", Serialize(message.unknown_fields()));
-}
-
-}  // namespace proto_extras
-
-#endif  // COMPONENTS_PROTO_EXTRAS_PROTOBUF_FULL_SUPPORT_H_
diff --git a/components/proto_extras/test_proto2/BUILD.gn b/components/proto_extras/test_proto2/BUILD.gn
index 0a65bdf..06d83310 100644
--- a/components/proto_extras/test_proto2/BUILD.gn
+++ b/components/proto_extras/test_proto2/BUILD.gn
@@ -14,4 +14,6 @@
   sources = [ "test_proto2.proto" ]
 
   deps = [ ":test_proto2" ]
+
+  generate_stream_operators = true
 }
diff --git a/components/safe_browsing/content/browser/web_ui/DEPS b/components/safe_browsing/content/browser/web_ui/DEPS
index c60c73f..a2e080da 100644
--- a/components/safe_browsing/content/browser/web_ui/DEPS
+++ b/components/safe_browsing/content/browser/web_ui/DEPS
@@ -1,6 +1,6 @@
 include_rules = [
   "+components/enterprise/common/proto/connectors.pb.h",
-  "+components/enterprise/common/proto/connectors.extras.h",
+  "+components/enterprise/common/proto/connectors.to_value.h",
   "+components/grit/safe_browsing_resources.h",
   "+components/grit/safe_browsing_resources_map.h",
   "+components/password_manager/core/browser/hash_password_manager.h",
diff --git a/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc b/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc
index a9302ab..dfc119a 100644
--- a/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc
+++ b/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc
@@ -36,11 +36,11 @@
 #include "components/safe_browsing/buildflags.h"
 #include "components/safe_browsing/core/browser/referrer_chain_provider.h"
 #include "components/safe_browsing/core/common/features.h"
-#include "components/safe_browsing/core/common/proto/csd.extras.h"
 #include "components/safe_browsing/core/common/proto/csd.pb.h"
-#include "components/safe_browsing/core/common/proto/realtimeapi.extras.h"
-#include "components/safe_browsing/core/common/proto/safebrowsingv5.extras.h"
+#include "components/safe_browsing/core/common/proto/csd.to_value.h"
+#include "components/safe_browsing/core/common/proto/realtimeapi.to_value.h"
 #include "components/safe_browsing/core/common/proto/safebrowsingv5.pb.h"
+#include "components/safe_browsing/core/common/proto/safebrowsingv5.to_value.h"
 #include "components/safe_browsing/core/common/safe_browsing_prefs.h"
 #include "components/safe_browsing/core/common/web_ui_constants.h"
 #include "components/strings/grit/components_strings.h"
@@ -58,8 +58,8 @@
 #endif
 
 #if BUILDFLAG(SAFE_BROWSING_DOWNLOAD_PROTECTION) && !BUILDFLAG(IS_ANDROID)
-#include "components/enterprise/common/proto/connectors.extras.h"
 #include "components/enterprise/common/proto/connectors.pb.h"
+#include "components/enterprise/common/proto/connectors.to_value.h"
 #endif
 
 using base::Time;
diff --git a/components/safe_browsing/core/common/proto/BUILD.gn b/components/safe_browsing/core/common/proto/BUILD.gn
index 377f7cb..a13eed7 100644
--- a/components/safe_browsing/core/common/proto/BUILD.gn
+++ b/components/safe_browsing/core/common/proto/BUILD.gn
@@ -24,9 +24,6 @@
 proto_extras("csd_proto_extras") {
   sources = [ "csd.proto" ]
   deps = [ ":csd_proto" ]
-
-  # The fuzzable_proto_library rule above uses the full protobuf runtime.
-  protobuf_full_support = true
 }
 
 proto_library("webui_proto") {
@@ -51,9 +48,6 @@
     "//components/enterprise/common/proto:connectors_proto",
     "//components/enterprise/common/proto:connectors_proto_extras",
   ]
-
-  # The fuzzable_proto_library rule above uses the full protobuf runtime.
-  protobuf_full_support = true
 }
 
 fuzzable_proto_library("client_model_proto") {
diff --git a/components/search_engines/search_engine_choice/search_engine_choice_service.cc b/components/search_engines/search_engine_choice/search_engine_choice_service.cc
index ebe4df0..e2c7d387 100644
--- a/components/search_engines/search_engine_choice/search_engine_choice_service.cc
+++ b/components/search_engines/search_engine_choice/search_engine_choice_service.cc
@@ -233,9 +233,22 @@
   base::Time::Exploded exploded;
   timestamp->LocalExplode(&exploded);
 
+  // For reporting purposes, we want to keep the date in the range [2022-01,
+  // 2050-12]. Dates that are before 2022 are reported as `1000-01`, and dates
+  // after 2050 are reported as `3000-01`.
+  int year = exploded.year;
+  int month = exploded.month;
+  if (exploded.year < 2022) {
+    year = 1000;
+    month = 1;
+  } else if (exploded.year > 2050) {
+    year = 3000;
+    month = 1;
+  }
+
   // Expected value space is 12 samples / year.
   base::UmaHistogramSparse(kSearchEngineChoiceCompletedOnMonthHistogram,
-                           exploded.year * 100 + exploded.month);
+                           year * 100 + month);
 }
 
 }  // namespace
@@ -545,7 +558,8 @@
             profile_prefs_.get(),
             SearchEngineChoiceWipeReason::kInvalidMetadataVersion);
         return;
-      case ChoiceCompletionMetadata::ParseError::kOther:
+      case ChoiceCompletionMetadata::ParseError::kMissingTimestamp:
+      case ChoiceCompletionMetadata::ParseError::kNullTimestamp:
         WipeSearchEngineChoicePrefs(
             profile_prefs_.get(),
             SearchEngineChoiceWipeReason::kInvalidMetadata);
diff --git a/components/search_engines/search_engine_choice/search_engine_choice_service_unittest.cc b/components/search_engines/search_engine_choice/search_engine_choice_service_unittest.cc
index 767d71a..fb83113 100644
--- a/components/search_engines/search_engine_choice/search_engine_choice_service_unittest.cc
+++ b/components/search_engines/search_engine_choice/search_engine_choice_service_unittest.cc
@@ -713,6 +713,46 @@
       kSearchEngineChoiceCompletedOnMonthHistogram, 202504, 1);
 }
 
+// Tests if choice screen completion date is recorded.
+TEST_F(SearchEngineChoiceServiceTest,
+       RecordsChoiceScreenCompletionDateBefore2022Histogram) {
+  base::HistogramTester histogram_tester;
+
+  // July 1993. What is specific about this timestamp (in windows epoch seconds)
+  // is that it is before 2022.
+  int64_t windows_epoch_timestamp = 12388103000;
+
+  pref_service()->SetString(
+      prefs::kDefaultSearchProviderChoiceScreenCompletionVersion, "1.0.0.0");
+  pref_service()->SetInt64(
+      prefs::kDefaultSearchProviderChoiceScreenCompletionTimestamp,
+      windows_epoch_timestamp);
+
+  search_engine_choice_service();
+  histogram_tester.ExpectUniqueSample(
+      kSearchEngineChoiceCompletedOnMonthHistogram, 100001, 1);
+}
+
+// Tests if choice screen completion date is recorded.
+TEST_F(SearchEngineChoiceServiceTest,
+       RecordsChoiceScreenCompletionDateAfter2050Histogram) {
+  base::HistogramTester histogram_tester;
+
+  // December 2056. What is specific about this timestamp (in windows epoch
+  // seconds) is that it is after 2050.
+  int64_t windows_epoch_timestamp = 14388103000;
+
+  pref_service()->SetString(
+      prefs::kDefaultSearchProviderChoiceScreenCompletionVersion, "1.0.0.0");
+  pref_service()->SetInt64(
+      prefs::kDefaultSearchProviderChoiceScreenCompletionTimestamp,
+      windows_epoch_timestamp);
+
+  search_engine_choice_service();
+  histogram_tester.ExpectUniqueSample(
+      kSearchEngineChoiceCompletedOnMonthHistogram, 300001, 1);
+}
+
 // Test that the user is not reprompted if the reprompt parameter is not a valid
 // JSON string.
 TEST_F(SearchEngineChoiceServiceTest, NoRepromptForSyntaxError) {
diff --git a/components/search_engines/search_engine_choice/search_engine_choice_utils.cc b/components/search_engines/search_engine_choice/search_engine_choice_utils.cc
index d7f89c6..8e149a90 100644
--- a/components/search_engines/search_engine_choice/search_engine_choice_utils.cc
+++ b/components/search_engines/search_engine_choice/search_engine_choice_utils.cc
@@ -112,8 +112,7 @@
     return std::nullopt;
   }
 
-  if (!parsed_country_id.has_value() ||
-      !parsed_search_engines) {
+  if (!parsed_country_id.has_value() || !parsed_search_engines) {
     return std::nullopt;
   }
 
@@ -123,9 +122,8 @@
         static_cast<SearchEngineType>(search_engine_type.GetInt()));
   }
 
-  return ChoiceScreenDisplayState(
-      search_engines, parsed_country_id.value(),
-      parsed_selected_engine_index);
+  return ChoiceScreenDisplayState(search_engines, parsed_country_id.value(),
+                                  parsed_selected_engine_index);
 }
 
 ChoiceScreenData::ChoiceScreenData(
@@ -226,8 +224,8 @@
       prefs::kDefaultSearchProviderPendingChoiceScreenDisplayState);
 
 #if BUILDFLAG(IS_IOS)
-    profile_prefs.ClearPref(
-        prefs::kDefaultSearchProviderChoiceScreenSkippedCount);
+  profile_prefs.ClearPref(
+      prefs::kDefaultSearchProviderChoiceScreenSkippedCount);
 #endif
 }
 
@@ -251,15 +249,19 @@
         ChoiceCompletionMetadata::ParseError::kInvalidVersion);
   }
 
-  // Note: Other error conditions don't have dedicated handling, so we log all
-  // of them as `kOther`.
+  if (!prefs.HasPrefPath(
+          prefs::kDefaultSearchProviderChoiceScreenCompletionTimestamp)) {
+    return base::unexpected(
+        ChoiceCompletionMetadata::ParseError::kMissingTimestamp);
+  }
 
   base::Time timestamp =
       base::Time::FromDeltaSinceWindowsEpoch(base::Seconds(prefs.GetInt64(
-          prefs::kDefaultSearchProviderChoiceScreenCompletionTimestamp)));
+        prefs::kDefaultSearchProviderChoiceScreenCompletionTimestamp)));
 
   if (timestamp.is_null()) {
-    return base::unexpected(ChoiceCompletionMetadata::ParseError::kOther);
+    return base::unexpected(
+        ChoiceCompletionMetadata::ParseError::kNullTimestamp);
   }
 
   return ChoiceCompletionMetadata{
diff --git a/components/search_engines/search_engine_choice/search_engine_choice_utils.h b/components/search_engines/search_engine_choice/search_engine_choice_utils.h
index d084ff5a..d931580f4 100644
--- a/components/search_engines/search_engine_choice/search_engine_choice_utils.h
+++ b/components/search_engines/search_engine_choice/search_engine_choice_utils.h
@@ -58,7 +58,7 @@
 inline constexpr char kSearchEngineChoiceRepromptSpecificCountryHistogram[] =
     "Search.ChoiceReprompt.SpecificCountry";
 inline constexpr char kSearchEngineChoiceCompletedOnMonthHistogram[] =
-    "Search.ChoiceCompletedOnMonth.OnProfileLoad";
+    "Search.ChoiceCompletedOnMonth.OnProfileLoad2";
 
 // These values are persisted to logs. Entries should not be renumbered and
 // numeric values should never be reused.
@@ -295,7 +295,8 @@
     kAbsent,
     kMissingVersion,
     kInvalidVersion,
-    kOther,
+    kMissingTimestamp,
+    kNullTimestamp,
   };
 
   base::Time timestamp;
diff --git a/components/strings/components_strings_eu.xtb b/components/strings/components_strings_eu.xtb
index 0e9f3545..0c84d3a 100644
--- a/components/strings/components_strings_eu.xtb
+++ b/components/strings/components_strings_eu.xtb
@@ -522,6 +522,7 @@
 <translation id="1863257867908022953">12. erretilua</translation>
 <translation id="1864927262126810325">Iturburua: <ph name="SOURCE_NAME" /></translation>
 <translation id="186539747722034544">Kable eta satelite bidezko hornitzaileak</translation>
+<translation id="1866757068250903512">Kontrolatu <ph name="READERNAME" /> izeneko autentifikazio-gailuak eta haiekin erabilitako txartel adimendunak</translation>
 <translation id="1870473978371099486">Klase pribatuak</translation>
 <translation id="1871208020102129563">Proxy-zerbitzari finkoak erabiltzeko konfiguratu da proxya, ez .pac scripteko URLak erabiltzeko.</translation>
 <translation id="1871284979644508959">Nahitaezko eremua</translation>
diff --git a/components/test/BUILD.gn b/components/test/BUILD.gn
index a84aef2..db5f9db2 100644
--- a/components/test/BUILD.gn
+++ b/components/test/BUILD.gn
@@ -71,6 +71,10 @@
     testonly = true
     filelist_name = "data/dom_distiller/unit_tests_bundle_data.filelist"
   }
+  bundle_data_from_filelist("dom_label_test_bundle_data") {
+    testonly = true
+    filelist_name = "data/autofill/label-doms/unit_tests_bundle_data.filelist"
+  }
   bundle_data_from_filelist("feed_test_bundle_data") {
     testonly = true
     filelist_name = "data/feed/unit_tests_bundle_data.filelist"
diff --git a/components/test/PRESUBMIT.py b/components/test/PRESUBMIT.py
index ddd2486a..051e97c 100644
--- a/components/test/PRESUBMIT.py
+++ b/components/test/PRESUBMIT.py
@@ -24,6 +24,9 @@
                 'data/dom_distiller/unit_tests_bundle_data')
         results += presubmit_support.CheckBundleData(
                 input_api, output_api,
+                'data/autofill/label-doms/unit_tests_bundle_data')
+        results += presubmit_support.CheckBundleData(
+                input_api, output_api,
                 'data/feed/unit_tests_bundle_data')
         results += presubmit_support.CheckBundleData(
                 input_api, output_api,
diff --git a/components/test/data/autofill/label-doms/unit_tests_bundle_data.filelist b/components/test/data/autofill/label-doms/unit_tests_bundle_data.filelist
new file mode 100644
index 0000000..dc58fe3
--- /dev/null
+++ b/components/test/data/autofill/label-doms/unit_tests_bundle_data.filelist
@@ -0,0 +1,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.
+# NOTE: this file is generated by build/ios/update_bundle_filelist.py
+#       If it requires updating, you should get a presubmit error with
+#       instructions on how to regenerate. Otherwise, do not edit.
+//components/test/data/autofill/label-doms/basic-test.html
+//components/test/data/autofill/label-doms/basic-test.json
diff --git a/components/test/data/autofill/label-doms/unit_tests_bundle_data.globlist b/components/test/data/autofill/label-doms/unit_tests_bundle_data.globlist
new file mode 100644
index 0000000..c4a55d975
--- /dev/null
+++ b/components/test/data/autofill/label-doms/unit_tests_bundle_data.globlist
@@ -0,0 +1,10 @@
+# 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.
+#
+# See build/ios/update_bundle_filelist.py for details on how .globlist
+# files are used to update their .filelist counterparts.
+
+//components/test/data/autofill/label-doms/**
+-//components/test/data/autofill/label-doms/*.filelist
+-//components/test/data/autofill/label-doms/*.globlist
diff --git a/components/viz/service/display/readback_pixeltest.cc b/components/viz/service/display/readback_pixeltest.cc
index 7fe6540c..ee7a639 100644
--- a/components/viz/service/display/readback_pixeltest.cc
+++ b/components/viz/service/display/readback_pixeltest.cc
@@ -1004,9 +1004,7 @@
 
   auto shared_image = sii->CreateSharedImage(
       {MultiPlaneFormat::kNV12, source_size, gfx::ColorSpace::CreateREC709(),
-       gpu::SHARED_IMAGE_USAGE_DISPLAY_READ |
-           gpu::SHARED_IMAGE_USAGE_RASTER_WRITE,
-       "TestLabels"},
+       gpu::SHARED_IMAGE_USAGE_DISPLAY_READ, "TestLabels"},
       gpu::kNullSurfaceHandle);
   CHECK(shared_image);
 
diff --git a/components/viz/service/input/input_manager.cc b/components/viz/service/input/input_manager.cc
index 011b34ef..131b037 100644
--- a/components/viz/service/input/input_manager.cc
+++ b/components/viz/service/input/input_manager.cc
@@ -56,6 +56,11 @@
       surface_handle, viz_input_token_java);
 }
 
+void DestroyReceiverData(
+    std::unique_ptr<input::InputReceiverData> receiver_data) {
+  receiver_data.reset();
+}
+
 #endif  // BUILDFLAG(IS_ANDROID)
 
 bool IsFrameMetadataAvailable(CompositorFrameSinkSupport* support) {
@@ -249,8 +254,14 @@
   TRACE_EVENT("viz", "InputManager::OnDestroyedCompositorFrameSink",
               "frame_sink_id", frame_sink_id);
 #if BUILDFLAG(IS_ANDROID)
-  if (receiver_data_) {
-    receiver_data_->OnDestroyedCompositorFrameSink(frame_sink_id);
+  if (receiver_data_ && receiver_data_->root_frame_sink_id() == frame_sink_id) {
+    receiver_data_->OnDestroyedCompositorFrameSink();
+    if (base::android::android_info::sdk_int() >=
+        base::android::android_info::SdkVersion::SDK_VERSION_BAKLAVA) {
+      base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
+          FROM_HERE,
+          base::BindOnce(&DestroyReceiverData, std::move(receiver_data_)));
+    }
   }
 #endif  // BUILDFLAG(IS_ANDROID)
 
diff --git a/components/viz/service/input/input_manager.h b/components/viz/service/input/input_manager.h
index 67061a7..7d8484e 100644
--- a/components/viz/service/input/input_manager.h
+++ b/components/viz/service/input/input_manager.h
@@ -23,6 +23,7 @@
 #include "mojo/public/cpp/bindings/associated_receiver_set.h"
 
 #if BUILDFLAG(IS_ANDROID)
+#include "base/android/android_info.h"
 #include "components/input/android/input_receiver_data.h"
 #include "components/viz/service/input/android_state_transfer_handler.h"
 #include "components/viz/service/input/render_input_router_support_android.h"
diff --git a/content/browser/indexed_db/BUILD.gn b/content/browser/indexed_db/BUILD.gn
index c01b146..214e23da 100644
--- a/content/browser/indexed_db/BUILD.gn
+++ b/content/browser/indexed_db/BUILD.gn
@@ -70,6 +70,10 @@
     "instance/lock_request_data.h",
     "instance/pending_connection.cc",
     "instance/pending_connection.h",
+    "instance/record.cc",
+    "instance/record.h",
+    "instance/sqlite/backing_store_cursor_impl.cc",
+    "instance/sqlite/backing_store_cursor_impl.h",
     "instance/sqlite/backing_store_database_impl.cc",
     "instance/sqlite/backing_store_database_impl.h",
     "instance/sqlite/backing_store_impl.cc",
@@ -78,6 +82,8 @@
     "instance/sqlite/backing_store_transaction_impl.h",
     "instance/sqlite/database_connection.cc",
     "instance/sqlite/database_connection.h",
+    "instance/sqlite/record_iterator.cc",
+    "instance/sqlite/record_iterator.h",
     "instance/transaction.cc",
     "instance/transaction.h",
     "list_set.h",
diff --git a/content/browser/indexed_db/indexed_db_leveldb_coding.cc b/content/browser/indexed_db/indexed_db_leveldb_coding.cc
index bb1ac2a2..cc2f1f4e 100644
--- a/content/browser/indexed_db/indexed_db_leveldb_coding.cc
+++ b/content/browser/indexed_db/indexed_db_leveldb_coding.cc
@@ -420,13 +420,14 @@
   return EncodeIDBKeyRecursively(value, into, 0);
 }
 
-void EncodeSortableIDBKey(const IndexedDBKey& value, std::string* into) {
+void EncodeSortableIDBKeyRecursively(const IndexedDBKey& value,
+                                     std::string* into) {
   size_t previous_size = into->size();
   switch (value.type()) {
     case blink::mojom::IDBKeyType::Array: {
       EncodeByte(kOrderedArrayTypeByte, into);
       for (const IndexedDBKey& key : value.array()) {
-        EncodeSortableIDBKey(key, into);
+        EncodeSortableIDBKeyRecursively(key, into);
       }
       EncodeByte(kSentinel, into);
       DCHECK_GT(into->size(), previous_size);
@@ -456,6 +457,12 @@
   }
 }
 
+std::string EncodeSortableIDBKey(const IndexedDBKey& value) {
+  std::string encoded;
+  EncodeSortableIDBKeyRecursively(value, &encoded);
+  return encoded;
+}
+
 #define COMPILE_ASSERT_MATCHING_VALUES(a, b)                          \
   static_assert(                                                      \
       static_cast<unsigned char>(a) == static_cast<unsigned char>(b), \
diff --git a/content/browser/indexed_db/indexed_db_leveldb_coding.h b/content/browser/indexed_db/indexed_db_leveldb_coding.h
index 4716a71b..829f37b 100644
--- a/content/browser/indexed_db/indexed_db_leveldb_coding.h
+++ b/content/browser/indexed_db/indexed_db_leveldb_coding.h
@@ -73,8 +73,8 @@
 // collation operation. Unlike `EncodeIDBKey`, which makes use of length bytes,
 // this operation re-encodes variable-length values in a way that supports
 // sentinels.
-CONTENT_EXPORT void EncodeSortableIDBKey(const blink::IndexedDBKey& value,
-                                         std::string* into);
+CONTENT_EXPORT std::string EncodeSortableIDBKey(
+    const blink::IndexedDBKey& value);
 CONTENT_EXPORT void EncodeIDBKeyPath(const blink::IndexedDBKeyPath& value,
                                      std::string* into);
 CONTENT_EXPORT void EncodeBlobJournal(const BlobJournalType& journal,
diff --git a/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc b/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc
index 7d4f3b2..9f3be06e 100644
--- a/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc
@@ -852,11 +852,9 @@
 
     EXPECT_TRUE(key_a.IsLessThan(key_b));
 
-    std::string encoded_a;
-    EncodeSortableIDBKey(key_a, &encoded_a);
+    std::string encoded_a = EncodeSortableIDBKey(key_a);
     EXPECT_TRUE(encoded_a.size());
-    std::string encoded_b;
-    EncodeSortableIDBKey(key_b, &encoded_b);
+    std::string encoded_b = EncodeSortableIDBKey(key_b);
     EXPECT_TRUE(encoded_b.size());
 
     auto sqlite_compare = [](const std::string& a, const std::string& b) {
@@ -876,8 +874,7 @@
   }
   // Also test decoding by treating all test cases as one massive array key.
   const IndexedDBKey all_keys_key(std::move(keys_vec));
-  std::string encoded;
-  EncodeSortableIDBKey(all_keys_key, &encoded);
+  std::string encoded = EncodeSortableIDBKey(all_keys_key);
   IndexedDBKey decoded_value = DecodeSortableIDBKey(encoded);
   ASSERT_TRUE(decoded_value.IsValid());
   EXPECT_TRUE(all_keys_key.Equals(decoded_value))
@@ -937,13 +934,11 @@
       SCOPED_TRACE(testing::Message()
                    << "Comparing " << value_a << " and " << value_b);
 
-      std::string encoded_a;
-      EncodeSortableIDBKey(
-          IndexedDBKey(value_a, blink::mojom::IDBKeyType::Number), &encoded_a);
+      std::string encoded_a = EncodeSortableIDBKey(
+          IndexedDBKey(value_a, blink::mojom::IDBKeyType::Number));
       EXPECT_TRUE(encoded_a.size());
-      std::string encoded_b;
-      EncodeSortableIDBKey(
-          IndexedDBKey(value_b, blink::mojom::IDBKeyType::Number), &encoded_b);
+      std::string encoded_b = EncodeSortableIDBKey(
+          IndexedDBKey(value_b, blink::mojom::IDBKeyType::Number));
       EXPECT_TRUE(encoded_b.size());
       EXPECT_EQ(encoded_a.size(), encoded_b.size());
 
@@ -964,8 +959,7 @@
 
   for (double value : values) {
     const IndexedDBKey key(value, blink::mojom::IDBKeyType::Number);
-    std::string encoded;
-    EncodeSortableIDBKey(key, &encoded);
+    std::string encoded = EncodeSortableIDBKey(key);
     IndexedDBKey decoded_value = DecodeSortableIDBKey(encoded);
     ASSERT_TRUE(decoded_value.IsValid());
     EXPECT_TRUE(key.Equals(decoded_value))
diff --git a/content/browser/indexed_db/instance/backing_store.h b/content/browser/indexed_db/instance/backing_store.h
index 8519190..cad6561 100644
--- a/content/browser/indexed_db/instance/backing_store.h
+++ b/content/browser/indexed_db/instance/backing_store.h
@@ -214,13 +214,12 @@
     // keys are valid, advances the cursor to the row for `key` or `key` and
     // `primary_key`. Returns true on success, or false if no eligible row was
     // found. Returns an error if there was a DB error.
+    virtual StatusOr<bool> Continue() = 0;
     virtual StatusOr<bool> Continue(const blink::IndexedDBKey& key,
                                     const blink::IndexedDBKey& primary_key) = 0;
     virtual StatusOr<bool> Advance(uint32_t count) = 0;
     // Clone may return a nullptr if cloning fails for any reason.
     virtual std::unique_ptr<Cursor> Clone() const = 0;
-
-    StatusOr<bool> Continue() { return Continue({}, {}); }
   };
 
   virtual ~BackingStore() = default;
diff --git a/content/browser/indexed_db/instance/leveldb/backing_store.cc b/content/browser/indexed_db/instance/leveldb/backing_store.cc
index bf102b3..d02ba75 100644
--- a/content/browser/indexed_db/instance/leveldb/backing_store.cc
+++ b/content/browser/indexed_db/instance/leveldb/backing_store.cc
@@ -3247,7 +3247,7 @@
 
 StatusOr<bool> BackingStore::Cursor::Advance(uint32_t count) {
   while (count--) {
-    StatusOr<bool> result = indexed_db::BackingStore::Cursor::Continue();
+    StatusOr<bool> result = Continue();
     if (!result.has_value()) {
       return base::unexpected(result.error());
     }
@@ -3259,6 +3259,10 @@
   return true;
 }
 
+StatusOr<bool> BackingStore::Cursor::Continue() {
+  return Continue({}, {});
+}
+
 StatusOr<bool> BackingStore::Cursor::Continue(const IndexedDBKey& key,
                                               const IndexedDBKey& primary_key) {
   return Continue(key, primary_key, SEEK);
diff --git a/content/browser/indexed_db/instance/leveldb/backing_store.h b/content/browser/indexed_db/instance/leveldb/backing_store.h
index 98ddfea..eef58b36 100644
--- a/content/browser/indexed_db/instance/leveldb/backing_store.h
+++ b/content/browser/indexed_db/instance/leveldb/backing_store.h
@@ -365,6 +365,7 @@
     const blink::IndexedDBKey& GetKey() const override;
     const blink::IndexedDBKey& GetPrimaryKey() const override;
     blink::IndexedDBKey TakeKey() && override;
+    StatusOr<bool> Continue() override;
     StatusOr<bool> Continue(const blink::IndexedDBKey& key,
                             const blink::IndexedDBKey& primary_key) override;
     StatusOr<bool> Advance(uint32_t count) override;
diff --git a/content/browser/indexed_db/instance/record.cc b/content/browser/indexed_db/instance/record.cc
new file mode 100644
index 0000000..409745a
--- /dev/null
+++ b/content/browser/indexed_db/instance/record.cc
@@ -0,0 +1,40 @@
+// 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 "content/browser/indexed_db/instance/record.h"
+
+#include <utility>
+
+#include "base/notreached.h"
+
+namespace content::indexed_db {
+
+ObjectStoreRecord::ObjectStoreRecord(blink::IndexedDBKey key,
+                                     IndexedDBValue value)
+    : key_(std::move(key)), value_(std::move(value)) {}
+
+ObjectStoreRecord::~ObjectStoreRecord() = default;
+
+blink::IndexedDBKey& ObjectStoreRecord::key() {
+  return key_;
+}
+
+blink::IndexedDBKey& ObjectStoreRecord::primary_key() {
+  return key_;
+}
+
+IndexedDBValue& ObjectStoreRecord::value() {
+  return value_;
+}
+
+ObjectStoreKeyOnlyRecord::ObjectStoreKeyOnlyRecord(blink::IndexedDBKey key)
+    : ObjectStoreRecord(std::move(key), /*value=*/{}) {}
+
+ObjectStoreKeyOnlyRecord::~ObjectStoreKeyOnlyRecord() = default;
+
+IndexedDBValue& ObjectStoreKeyOnlyRecord::value() {
+  NOTREACHED();
+}
+
+}  // namespace content::indexed_db
diff --git a/content/browser/indexed_db/instance/record.h b/content/browser/indexed_db/instance/record.h
new file mode 100644
index 0000000..6956401f
--- /dev/null
+++ b/content/browser/indexed_db/instance/record.h
@@ -0,0 +1,50 @@
+// 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 CONTENT_BROWSER_INDEXED_DB_INSTANCE_RECORD_H_
+#define CONTENT_BROWSER_INDEXED_DB_INSTANCE_RECORD_H_
+
+#include "content/browser/indexed_db/indexed_db_value.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
+
+namespace content::indexed_db {
+
+// Base class for an IndexedDB record.
+class Record {
+ public:
+  virtual ~Record() = default;
+
+  virtual blink::IndexedDBKey& key() = 0;
+  virtual blink::IndexedDBKey& primary_key() = 0;
+  virtual IndexedDBValue& value() = 0;
+};
+
+// An object store record has a key and value, with `primary_key()` being the
+// key itself.
+class ObjectStoreRecord : public Record {
+ public:
+  ObjectStoreRecord(blink::IndexedDBKey key, IndexedDBValue value);
+  ~ObjectStoreRecord() override;
+
+  blink::IndexedDBKey& key() override;
+  blink::IndexedDBKey& primary_key() override;
+  IndexedDBValue& value() override;
+
+ private:
+  blink::IndexedDBKey key_;
+  IndexedDBValue value_;
+};
+
+// It is an error to call `value()` on this type of record.
+class ObjectStoreKeyOnlyRecord : public ObjectStoreRecord {
+ public:
+  explicit ObjectStoreKeyOnlyRecord(blink::IndexedDBKey key);
+  ~ObjectStoreKeyOnlyRecord() override;
+
+  IndexedDBValue& value() override;
+};
+
+}  // namespace content::indexed_db
+
+#endif  // CONTENT_BROWSER_INDEXED_DB_INSTANCE_RECORD_H_
diff --git a/content/browser/indexed_db/instance/sqlite/backing_store_cursor_impl.cc b/content/browser/indexed_db/instance/sqlite/backing_store_cursor_impl.cc
new file mode 100644
index 0000000..b1bfda1c
--- /dev/null
+++ b/content/browser/indexed_db/instance/sqlite/backing_store_cursor_impl.cc
@@ -0,0 +1,69 @@
+// 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 "content/browser/indexed_db/instance/sqlite/backing_store_cursor_impl.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/types/expected.h"
+#include "content/browser/indexed_db/instance/record.h"
+#include "content/browser/indexed_db/instance/sqlite/record_iterator.h"
+#include "content/browser/indexed_db/status.h"
+
+namespace content::indexed_db::sqlite {
+
+content::indexed_db::sqlite::BackingStoreCursorImpl::BackingStoreCursorImpl(
+    std::unique_ptr<RecordIterator> iterator,
+    std::unique_ptr<Record> initial_record)
+    : iterator_(std::move(iterator)),
+      current_record_(std::move(initial_record)) {}
+
+BackingStoreCursorImpl::~BackingStoreCursorImpl() = default;
+
+const blink::IndexedDBKey& BackingStoreCursorImpl::GetKey() const {
+  return current_record_->key();
+}
+
+blink::IndexedDBKey BackingStoreCursorImpl::TakeKey() && {
+  return std::move(current_record_->key());
+}
+
+const blink::IndexedDBKey& BackingStoreCursorImpl::GetPrimaryKey() const {
+  return current_record_->primary_key();
+}
+
+IndexedDBValue& BackingStoreCursorImpl::GetValue() {
+  return current_record_->value();
+}
+
+std::unique_ptr<BackingStore::Cursor> BackingStoreCursorImpl::Clone() const {
+  // This is needed by `Cursor::PrefetchIterationOperation()`.
+  // TODO(crbug.com/419208481): Implement prefetch without using `Clone()`.
+  return nullptr;
+}
+
+StatusOr<bool> BackingStoreCursorImpl::Continue() {
+  return Advance(1);
+}
+
+StatusOr<bool> BackingStoreCursorImpl::Continue(
+    const blink::IndexedDBKey& key,
+    const blink::IndexedDBKey& primary_key) {
+  return iterator_->Iterate(key, primary_key)
+      .transform([this](std::unique_ptr<Record> new_record) {
+        current_record_ = std::move(new_record);
+        return current_record_ != nullptr;
+      });
+}
+
+StatusOr<bool> BackingStoreCursorImpl::Advance(uint32_t count) {
+  return iterator_->Iterate(count).transform(
+      [this](std::unique_ptr<Record> new_record) {
+        current_record_ = std::move(new_record);
+        return current_record_ != nullptr;
+      });
+}
+
+}  // namespace content::indexed_db::sqlite
diff --git a/content/browser/indexed_db/instance/sqlite/backing_store_cursor_impl.h b/content/browser/indexed_db/instance/sqlite/backing_store_cursor_impl.h
new file mode 100644
index 0000000..4f136e6
--- /dev/null
+++ b/content/browser/indexed_db/instance/sqlite/backing_store_cursor_impl.h
@@ -0,0 +1,46 @@
+// 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 CONTENT_BROWSER_INDEXED_DB_INSTANCE_SQLITE_BACKING_STORE_CURSOR_IMPL_H_
+#define CONTENT_BROWSER_INDEXED_DB_INSTANCE_SQLITE_BACKING_STORE_CURSOR_IMPL_H_
+
+#include <memory>
+
+#include "base/types/pass_key.h"
+#include "content/browser/indexed_db/instance/backing_store.h"
+
+namespace content::indexed_db {
+class Record;
+
+namespace sqlite {
+class RecordIterator;
+
+class BackingStoreCursorImpl : public BackingStore::Cursor {
+ public:
+  using PassKey = base::PassKey<BackingStoreCursorImpl>;
+
+  BackingStoreCursorImpl(std::unique_ptr<RecordIterator> iterator,
+                         std::unique_ptr<Record> initial_record);
+  ~BackingStoreCursorImpl() override;
+
+  // BackingStore::Cursor:
+  const blink::IndexedDBKey& GetKey() const override;
+  blink::IndexedDBKey TakeKey() && override;
+  const blink::IndexedDBKey& GetPrimaryKey() const override;
+  IndexedDBValue& GetValue() override;
+  std::unique_ptr<Cursor> Clone() const override;
+  StatusOr<bool> Continue() override;
+  StatusOr<bool> Continue(const blink::IndexedDBKey& key,
+                          const blink::IndexedDBKey& primary_key) override;
+  StatusOr<bool> Advance(uint32_t count) override;
+
+ private:
+  std::unique_ptr<RecordIterator> iterator_;
+  std::unique_ptr<Record> current_record_;
+};
+
+}  // namespace sqlite
+}  // namespace content::indexed_db
+
+#endif  // CONTENT_BROWSER_INDEXED_DB_INSTANCE_SQLITE_BACKING_STORE_CURSOR_IMPL_H_
diff --git a/content/browser/indexed_db/instance/sqlite/backing_store_transaction_impl.cc b/content/browser/indexed_db/instance/sqlite/backing_store_transaction_impl.cc
index fde8437f..9faf1f4 100644
--- a/content/browser/indexed_db/instance/sqlite/backing_store_transaction_impl.cc
+++ b/content/browser/indexed_db/instance/sqlite/backing_store_transaction_impl.cc
@@ -188,18 +188,18 @@
 BackingStoreTransactionImpl::OpenObjectStoreKeyCursor(
     int64_t object_store_id,
     const blink::IndexedDBKeyRange& key_range,
-    blink::mojom::IDBCursorDirection) {
-  NOTIMPLEMENTED();
-  return base::unexpected(Status::InvalidArgument("Not implemented"));
+    blink::mojom::IDBCursorDirection direction) {
+  return db_->OpenObjectStoreCursor(PassKey(), object_store_id, key_range,
+                                    direction, /*key_only=*/true);
 }
 
 StatusOr<std::unique_ptr<indexed_db::BackingStore::Cursor>>
 BackingStoreTransactionImpl::OpenObjectStoreCursor(
     int64_t object_store_id,
     const blink::IndexedDBKeyRange& key_range,
-    blink::mojom::IDBCursorDirection) {
-  NOTIMPLEMENTED();
-  return base::unexpected(Status::InvalidArgument("Not implemented"));
+    blink::mojom::IDBCursorDirection direction) {
+  return db_->OpenObjectStoreCursor(PassKey(), object_store_id, key_range,
+                                    direction, /*key_only=*/false);
 }
 
 StatusOr<std::unique_ptr<indexed_db::BackingStore::Cursor>>
diff --git a/content/browser/indexed_db/instance/sqlite/database_connection.cc b/content/browser/indexed_db/instance/sqlite/database_connection.cc
index effa745..11228b63f 100644
--- a/content/browser/indexed_db/instance/sqlite/database_connection.cc
+++ b/content/browser/indexed_db/instance/sqlite/database_connection.cc
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "base/check.h"
+#include "base/functional/callback.h"
 #include "base/memory/ptr_util.h"
 #include "base/notimplemented.h"
 #include "base/notreached.h"
@@ -18,7 +19,10 @@
 #include "base/types/expected.h"
 #include "content/browser/indexed_db/indexed_db_value.h"
 #include "content/browser/indexed_db/instance/backing_store.h"
+#include "content/browser/indexed_db/instance/record.h"
+#include "content/browser/indexed_db/instance/sqlite/backing_store_cursor_impl.h"
 #include "content/browser/indexed_db/instance/sqlite/backing_store_transaction_impl.h"
+#include "content/browser/indexed_db/instance/sqlite/record_iterator.h"
 #include "content/browser/indexed_db/status.h"
 #include "sql/database.h"
 #include "sql/meta_table.h"
@@ -170,6 +174,113 @@
   return metadata;
 }
 
+// Returns a `RecordIterator` and the initial `Record` for the range of object
+// store records determined by the parameters. Returns nullptrs if the range is
+// empty or an error if one occurs.
+StatusOr<std::pair<std::unique_ptr<RecordIterator>, std::unique_ptr<Record>>>
+CreateObjectStoreRecordIterator(sql::Database* db,
+                                int64_t object_store_id,
+                                const blink::IndexedDBKeyRange& key_range,
+                                bool ascending_order,
+                                bool key_only) {
+  std::vector<std::string_view> query_pieces{
+      "SELECT ", key_only ? "key" : "key, value",
+      " FROM records WHERE object_store_id = @object_store_id"};
+  if (key_range.lower().IsValid()) {
+    query_pieces.push_back(key_range.lower_open() ? " AND key > @lower"
+                                                  : " AND key >= @lower");
+  }
+  if (key_range.upper().IsValid()) {
+    query_pieces.push_back(key_range.upper_open() ? " AND key < @upper"
+                                                  : " AND key <= @upper");
+  }
+  if (ascending_order) {
+    query_pieces.push_back(
+        " AND (@is_first_seek = 1 OR key > @position)"
+        " AND (@target_key IS NULL OR key >= @target_key)"
+        " ORDER BY key ASC");
+  } else {
+    query_pieces.push_back(
+        " AND (@is_first_seek = 1 OR key < @position)"
+        " AND (@target_key IS NULL OR key <= @target_key)"
+        " ORDER BY key DESC");
+  }
+  // LIMIT is needed to use OFFSET. A negative LIMIT implies no limit on the
+  // number of rows returned:
+  // https://www.sqlite.org/lang_select.html#the_limit_clause.
+  query_pieces.push_back(" LIMIT -1 OFFSET @offset");
+
+  auto statement = std::make_unique<sql::Statement>(
+      db->GetReadonlyStatement(base::StrCat(query_pieces)));
+  int param_index = 0;
+  statement->BindInt64(param_index++, object_store_id);
+  if (key_range.lower().IsValid()) {
+    statement->BindBlob(param_index++, EncodeSortableIDBKey(key_range.lower()));
+  }
+  if (key_range.upper().IsValid()) {
+    statement->BindBlob(param_index++, EncodeSortableIDBKey(key_range.upper()));
+  }
+  int is_first_seek_index = param_index++;
+  int position_index = param_index++;
+  int target_key_index = param_index++;
+  int offset_index = param_index++;
+
+  RecordIterator::BindCallback bind_parameters = base::BindRepeating(
+      [](int is_first_seek_index, int position_index, int target_key_index,
+         int offset_index, sql::Statement& statement,
+         const std::string& position, const blink::IndexedDBKey& target_key,
+         const blink::IndexedDBKey& _, uint32_t offset) {
+        statement.BindBool(is_first_seek_index, false);
+        statement.BindBlob(position_index, position);
+        if (target_key.IsValid()) {
+          statement.BindBlob(target_key_index,
+                             EncodeSortableIDBKey(target_key));
+        } else {
+          statement.BindNull(target_key_index);
+        }
+        statement.BindInt64(offset_index, offset);
+      },
+      is_first_seek_index, position_index, target_key_index, offset_index);
+
+  RecordIterator::ReadCallback read_row = base::BindRepeating(
+      [](bool key_only, sql::Statement& statement)
+          -> StatusOr<RecordIterator::PositionAndRecord> {
+        std::string position;
+        TRANSIENT_CHECK(statement.ColumnBlobAsString(0, &position));
+        blink::IndexedDBKey key = DecodeSortableIDBKey(position);
+        if (key_only) {
+          return std::make_pair(
+              std::move(position),
+              std::make_unique<ObjectStoreKeyOnlyRecord>(std::move(key)));
+        }
+        IndexedDBValue value;
+        TRANSIENT_CHECK(statement.ColumnBlobAsVector(1, &value.bits));
+        return std::make_pair(std::move(position),
+                              std::make_unique<ObjectStoreRecord>(
+                                  std::move(key), std::move(value)));
+      },
+      key_only);
+
+  // Attempt to find the initial record in the range.
+  statement->BindBool(is_first_seek_index, true);
+  statement->BindNull(position_index);
+  statement->BindNull(target_key_index);
+  statement->BindInt(offset_index, 0);
+  if (!statement->Step()) {
+    TRANSIENT_CHECK(statement->Succeeded());
+    // Empty range.
+    return std::make_pair(nullptr, nullptr);
+  }
+  return read_row.Run(*statement)
+      .transform([&](RecordIterator::PositionAndRecord result) {
+        return std::make_pair(
+            std::make_unique<RecordIterator>(
+                std::move(statement), std::move(bind_parameters),
+                std::move(read_row), std::move(result.first)),
+            std::move(result.second));
+      });
+}
+
 }  // namespace
 
 // static
@@ -362,10 +473,8 @@
       db_->GetCachedStatement(SQL_FROM_HERE,
                               "SELECT row_id FROM records "
                               "WHERE object_store_id = ? AND key = ?"));
-  std::string encoded_key;
-  EncodeSortableIDBKey(key, &encoded_key);
   statement.BindInt64(0, object_store_id);
-  statement.BindBlob(1, std::move(encoded_key));
+  statement.BindBlob(1, EncodeSortableIDBKey(key));
   if (statement.Step()) {
     return BackingStore::RecordIdentifier{statement.ColumnInt64(0)};
   }
@@ -381,10 +490,8 @@
       db_->GetCachedStatement(SQL_FROM_HERE,
                               "SELECT value FROM records "
                               "WHERE object_store_id = ? AND key = ?"));
-  std::string encoded_key;
-  EncodeSortableIDBKey(key, &encoded_key);
   statement.BindInt64(0, object_store_id);
-  statement.BindBlob(1, std::move(encoded_key));
+  statement.BindBlob(1, EncodeSortableIDBKey(key));
   if (statement.Step()) {
     IndexedDBValue value;
     TRANSIENT_CHECK(statement.ColumnBlobAsVector(0, &value.bits));
@@ -404,9 +511,7 @@
       "INSERT OR REPLACE INTO records "
       "(object_store_id, key, value) VALUES (?, ?, ?)"));
   statement.BindInt64(0, object_store_id);
-  std::string encoded_key;
-  EncodeSortableIDBKey(key, &encoded_key);
-  statement.BindBlob(1, std::move(encoded_key));
+  statement.BindBlob(1, EncodeSortableIDBKey(key));
   statement.BindBlob(2, std::move(value.bits));
   TRANSIENT_CHECK(statement.Run());
   return BackingStore::RecordIdentifier{db_->GetLastInsertRowId()};
@@ -418,19 +523,13 @@
     blink::IndexedDBKeyRange key_range) {
   std::vector<std::string_view> query_pieces{
       "SELECT COUNT() FROM records WHERE object_store_id = ?"};
-  std::string lower_encoded;
-  std::string upper_encoded;
   if (key_range.lower().IsValid()) {
-    EncodeSortableIDBKey(key_range.lower(), &lower_encoded);
-    query_pieces.insert(
-        query_pieces.end(),
-        {" AND key ", key_range.lower_open() ? ">" : ">=", " ?"});
+    query_pieces.push_back(key_range.lower_open() ? " AND key > ?"
+                                                  : " AND key >= ?");
   }
   if (key_range.upper().IsValid()) {
-    EncodeSortableIDBKey(key_range.upper(), &upper_encoded);
-    query_pieces.insert(
-        query_pieces.end(),
-        {" AND key ", key_range.upper_open() ? "<" : "<=", " ?"});
+    query_pieces.push_back(key_range.upper_open() ? " AND key < ?"
+                                                  : " AND key <= ?");
   }
 
   // TODO(crbug.com/40253999): Evaluate performance benefit of using
@@ -439,14 +538,36 @@
       db_->GetReadonlyStatement(base::StrCat(query_pieces)));
   int param_index = 0;
   statement.BindInt64(param_index++, object_store_id);
-  if (!lower_encoded.empty()) {
-    statement.BindBlob(param_index++, lower_encoded);
+  if (key_range.lower().IsValid()) {
+    statement.BindBlob(param_index++, EncodeSortableIDBKey(key_range.lower()));
   }
-  if (!upper_encoded.empty()) {
-    statement.BindBlob(param_index++, upper_encoded);
+  if (key_range.upper().IsValid()) {
+    statement.BindBlob(param_index++, EncodeSortableIDBKey(key_range.upper()));
   }
   TRANSIENT_CHECK(statement.Step());
   return statement.ColumnInt(0);
 }
 
+StatusOr<std::unique_ptr<BackingStore::Cursor>>
+DatabaseConnection::OpenObjectStoreCursor(
+    base::PassKey<BackingStoreTransactionImpl>,
+    int64_t object_store_id,
+    const blink::IndexedDBKeyRange& key_range,
+    blink::mojom::IDBCursorDirection direction,
+    bool key_only) {
+  bool ascending_order =
+      (direction == blink::mojom::IDBCursorDirection::Next ||
+       direction == blink::mojom::IDBCursorDirection::NextNoDuplicate);
+  return CreateObjectStoreRecordIterator(db_.get(), object_store_id, key_range,
+                                         ascending_order, key_only)
+      .transform([](std::pair<std::unique_ptr<RecordIterator>,
+                              std::unique_ptr<Record>> result) {
+        return result.first
+                   ? std::make_unique<BackingStoreCursorImpl>(
+                         std::move(result.first), std::move(result.second))
+                   // Empty range.
+                   : nullptr;
+      });
+}
+
 }  // namespace content::indexed_db::sqlite
diff --git a/content/browser/indexed_db/instance/sqlite/database_connection.h b/content/browser/indexed_db/instance/sqlite/database_connection.h
index baab3d5..211e989 100644
--- a/content/browser/indexed_db/instance/sqlite/database_connection.h
+++ b/content/browser/indexed_db/instance/sqlite/database_connection.h
@@ -111,6 +111,13 @@
       int64_t object_store_id,
       blink::IndexedDBKeyRange key_range);
 
+  StatusOr<std::unique_ptr<BackingStore::Cursor>> OpenObjectStoreCursor(
+      base::PassKey<BackingStoreTransactionImpl>,
+      int64_t object_store_id,
+      const blink::IndexedDBKeyRange& key_range,
+      blink::mojom::IDBCursorDirection direction,
+      bool key_only);
+
  private:
   DatabaseConnection(std::unique_ptr<sql::Database> db,
                      std::unique_ptr<sql::MetaTable> meta_table,
diff --git a/content/browser/indexed_db/instance/sqlite/record_iterator.cc b/content/browser/indexed_db/instance/sqlite/record_iterator.cc
new file mode 100644
index 0000000..ea8c2ea
--- /dev/null
+++ b/content/browser/indexed_db/instance/sqlite/record_iterator.cc
@@ -0,0 +1,77 @@
+// 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 "content/browser/indexed_db/instance/sqlite/record_iterator.h"
+
+#include <memory>
+#include <optional>
+#include <string>
+#include <utility>
+
+#include "base/check.h"
+#include "base/functional/callback.h"
+#include "base/types/expected.h"
+#include "content/browser/indexed_db/instance/record.h"
+#include "content/browser/indexed_db/status.h"
+#include "sql/statement.h"
+#include "third_party/blink/public/common/indexeddb/indexeddb_key.h"
+
+// TODO(crbug.com/40253999): Remove after handling all error cases.
+#define TRANSIENT_CHECK(condition) CHECK(condition)
+
+namespace content::indexed_db::sqlite {
+
+RecordIterator::RecordIterator(std::unique_ptr<sql::Statement> statement,
+                               BindCallback bind_parameters,
+                               ReadCallback read_row,
+                               std::string initial_position)
+    : statement_(std::move(statement)),
+      bind_parameters_(std::move(bind_parameters)),
+      read_row_(std::move(read_row)),
+      current_position_(std::move(initial_position)) {}
+
+RecordIterator::~RecordIterator() = default;
+
+StatusOr<std::unique_ptr<Record>> RecordIterator::Iterate(
+    const blink::IndexedDBKey& key,
+    const blink::IndexedDBKey& primary_key) {
+  statement_->Reset(/*clear_bound_vars=*/false);
+  bind_parameters_.Run(*statement_, *current_position_, key, primary_key,
+                       /*offset=*/0);
+  if (!statement_->Step()) {
+    TRANSIENT_CHECK(statement_->Succeeded());
+    // End of range.
+    current_position_.reset();
+    return nullptr;
+  }
+  return read_row_.Run(*statement_).transform([this](PositionAndRecord result) {
+    current_position_ = std::move(result.first);
+    return std::move(result.second);
+  });
+}
+
+StatusOr<std::unique_ptr<Record>> RecordIterator::Iterate(uint32_t count) {
+  TRANSIENT_CHECK(count > 0);
+
+  // TODO(crbug.com/419208481): Implement a fast path where `statement_` is
+  // stepped without being reset when no record has changed in the range.
+  statement_->Reset(/*clear_bound_vars=*/false);
+
+  // Iterate count times => offset by (i.e., skip) [count - 1] rows.
+  bind_parameters_.Run(*statement_, *current_position_, /*key=*/{},
+                       /*primary_key=*/{},
+                       /*offset=*/count - 1);
+  if (!statement_->Step()) {
+    TRANSIENT_CHECK(statement_->Succeeded());
+    // End of range.
+    current_position_.reset();
+    return nullptr;
+  }
+  return read_row_.Run(*statement_).transform([this](PositionAndRecord result) {
+    current_position_ = std::move(result.first);
+    return std::move(result.second);
+  });
+}
+
+}  // namespace content::indexed_db::sqlite
diff --git a/content/browser/indexed_db/instance/sqlite/record_iterator.h b/content/browser/indexed_db/instance/sqlite/record_iterator.h
new file mode 100644
index 0000000..f0cf89e
--- /dev/null
+++ b/content/browser/indexed_db/instance/sqlite/record_iterator.h
@@ -0,0 +1,85 @@
+// 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 CONTENT_BROWSER_INDEXED_DB_INSTANCE_SQLITE_RECORD_ITERATOR_H_
+#define CONTENT_BROWSER_INDEXED_DB_INSTANCE_SQLITE_RECORD_ITERATOR_H_
+
+#include <memory>
+#include <optional>
+#include <string>
+#include <utility>
+
+#include "base/functional/callback.h"
+#include "content/browser/indexed_db/status.h"
+
+namespace blink {
+class IndexedDBKey;
+}  // namespace blink
+
+namespace sql {
+class Statement;
+}
+
+namespace content::indexed_db {
+class Record;
+
+namespace sqlite {
+
+// Iterates over a non-empty range of object store/index records, maintaining
+// the position in the range and emitting `Record`s.
+class RecordIterator {
+ public:
+  using PositionAndRecord = std::pair<std::string, std::unique_ptr<Record>>;
+  using BindCallback = base::RepeatingCallback<void(
+      sql::Statement& statement,
+      const std::string& position,
+      const blink::IndexedDBKey& target_key,
+      const blink::IndexedDBKey& target_primary_key,
+      uint32_t offset)>;
+  using ReadCallback = base::RepeatingCallback<StatusOr<PositionAndRecord>(
+      sql::Statement& statement)>;
+
+  RecordIterator(std::unique_ptr<sql::Statement> statement,
+                 BindCallback bind_parameters,
+                 ReadCallback read_row,
+                 std::string initial_position);
+
+  ~RecordIterator();
+
+  // Iterates from the current position until the target `key` and `primary_key`
+  // are reached. Use when at least one of these is valid.
+  StatusOr<std::unique_ptr<Record>> Iterate(
+      const blink::IndexedDBKey& key,
+      const blink::IndexedDBKey& primary_key);
+
+  // Iterates `count` times from the current position.
+  StatusOr<std::unique_ptr<Record>> Iterate(uint32_t count);
+
+ private:
+  // The parsed and bound statement that embeds the SQL query for this iterator.
+  // Because the records contained in the range can change between `Iterate()`
+  // calls, the query needs to be typically re-executed every time. The query
+  // itself is immutable for the duration of `this`, however, and contains a mix
+  // of fixed and variable bound parameters. To avoid re-parsing the query and
+  // rebinding the fixed parameters every time, hold on to the prepared
+  // statement and rebind only the variable parameters as needed.
+  std::unique_ptr<sql::Statement> statement_;
+
+  // Callback to bind variable parameters to the statement.
+  BindCallback bind_parameters_;
+
+  // Callback to read the position and `Record` corresponding to the current row
+  // of the statement.
+  ReadCallback read_row_;
+
+  // Opaque value tracking the position in the range. Typically, this is the
+  // encoded key from the current record. Null when and only when `this` has
+  // iterated past the end of its range.
+  std::optional<std::string> current_position_;
+};
+
+}  // namespace sqlite
+}  // namespace content::indexed_db
+
+#endif  // CONTENT_BROWSER_INDEXED_DB_INSTANCE_SQLITE_RECORD_ITERATOR_H_
diff --git a/content/browser/preloading/prefetch/prefetch_container.cc b/content/browser/preloading/prefetch/prefetch_container.cc
index fcf8bed..428135ba 100644
--- a/content/browser/preloading/prefetch/prefetch_container.cc
+++ b/content/browser/preloading/prefetch/prefetch_container.cc
@@ -1438,6 +1438,15 @@
     }
   }
 
+  std::optional<int> response_code = std::nullopt;
+  if (net_error == net::OK && GetNonRedirectHead() &&
+      GetNonRedirectHead()->headers) {
+    response_code = GetNonRedirectHead()->headers->response_code();
+  }
+  for (auto& observer : observers_) {
+    observer.OnPrefetchCompletedOrFailed(completion_status, response_code);
+  }
+
   if (GetPrefetchResponseCompletedCallbackForTesting()) {
     GetPrefetchResponseCompletedCallbackForTesting().Run(  // IN-TEST
         GetWeakPtr());
diff --git a/content/browser/preloading/prefetch/prefetch_container.h b/content/browser/preloading/prefetch/prefetch_container.h
index 7b2bd87..3b97186 100644
--- a/content/browser/preloading/prefetch/prefetch_container.h
+++ b/content/browser/preloading/prefetch/prefetch_container.h
@@ -248,6 +248,10 @@
     // successfully received or fetch requests including redirects failed.
     // Callers can check success/failure by `GetNonRedirectHead()`.
     virtual void OnDeterminedHead(PrefetchContainer& prefetch_container) = 0;
+    // Called when load of prefetch completed or failed.
+    virtual void OnPrefetchCompletedOrFailed(
+        const network::URLLoaderCompletionStatus& completion_status,
+        const std::optional<int>& response_code) = 0;
   };
 
   void OnWillBeDestroyed();
diff --git a/content/browser/preloading/prefetch/prefetch_handle_impl.cc b/content/browser/preloading/prefetch/prefetch_handle_impl.cc
index fc9ab138..b097c3e 100644
--- a/content/browser/preloading/prefetch/prefetch_handle_impl.cc
+++ b/content/browser/preloading/prefetch/prefetch_handle_impl.cc
@@ -11,17 +11,29 @@
 #include "content/browser/preloading/prefetch/prefetch_type.h"
 #include "content/public/browser/preloading_data.h"
 #include "content/public/browser/web_contents.h"
+#include "services/network/public/cpp/url_loader_completion_status.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
 
 namespace content {
 
-PrefetchContainerObserver::PrefetchContainerObserver(
-    base::RepeatingCallback<void(const network::mojom::URLResponseHead&)>
-        on_prefetch_head_received)
-    : on_prefetch_head_received_(std::move(on_prefetch_head_received)) {}
+PrefetchContainerObserver::PrefetchContainerObserver() = default;
 
 PrefetchContainerObserver::~PrefetchContainerObserver() = default;
 
+void PrefetchContainerObserver::SetOnPrefetchHeadReceivedCallback(
+    base::RepeatingCallback<void(const network::mojom::URLResponseHead&)>
+        on_prefetch_head_received) {
+  on_prefetch_head_received_ = std::move(on_prefetch_head_received);
+}
+
+void PrefetchContainerObserver::SetOnPrefetchCompletedOrFailedCallback(
+    base::RepeatingCallback<
+        void(const network::URLLoaderCompletionStatus& completion_status,
+             const std::optional<int>& response_code)>
+        on_prefetch_completed_or_failed) {
+  on_prefetch_completed_or_failed_ = std::move(on_prefetch_completed_or_failed);
+}
+
 void PrefetchContainerObserver::OnWillBeDestroyed(
     PrefetchContainer& prefetch_container) {}
 
@@ -31,15 +43,25 @@
 
 void PrefetchContainerObserver::OnDeterminedHead(
     PrefetchContainer& prefetch_container) {
-  // This condition will be used in a callback provided in the future.
-  // See
-  // https://chromium-review.googlesource.com/c/chromium/src/+/6615559/comment/3f439d19_8c9cf99a
-  //
-  // TODO(crbug.com/400761083): Use the callback.
-  if (prefetch_container.GetNonRedirectResponseReader() &&
-      prefetch_container.GetNonRedirectResponseReader()->load_state() ==
-          PrefetchResponseReader::LoadState::kResponseReceived) {
-    on_prefetch_head_received_.Run(*prefetch_container.GetNonRedirectHead());
+  if (on_prefetch_head_received_) {
+    // This condition will be used in a callback provided in the future.
+    // See
+    // https://chromium-review.googlesource.com/c/chromium/src/+/6615559/comment/3f439d19_8c9cf99a
+    //
+    // TODO(crbug.com/400761083): Use the callback.
+    if (prefetch_container.GetNonRedirectResponseReader() &&
+        prefetch_container.GetNonRedirectResponseReader()->load_state() ==
+            PrefetchResponseReader::LoadState::kResponseReceived) {
+      on_prefetch_head_received_.Run(*prefetch_container.GetNonRedirectHead());
+    }
+  }
+}
+
+void PrefetchContainerObserver::OnPrefetchCompletedOrFailed(
+    const network::URLLoaderCompletionStatus& completion_status,
+    const std::optional<int>& response_code) {
+  if (on_prefetch_completed_or_failed_) {
+    on_prefetch_completed_or_failed_.Run(completion_status, response_code);
   }
 }
 
@@ -47,9 +69,20 @@
     base::WeakPtr<PrefetchService> prefetch_service,
     base::WeakPtr<PrefetchContainer> prefetch_container)
     : prefetch_service_(std::move(prefetch_service)),
-      prefetch_container_(std::move(prefetch_container)) {}
+      prefetch_container_(std::move(prefetch_container)) {
+  CHECK(prefetch_service_);
+  // Note that `prefetch_container_` can be nullptr.
+
+  if (prefetch_container_) {
+    prefetch_container_->AddObserver(&prefetch_container_observer_);
+  }
+}
 
 PrefetchHandleImpl::~PrefetchHandleImpl() {
+  if (prefetch_container_) {
+    prefetch_container_->RemoveObserver(&prefetch_container_observer_);
+  }
+
   // Notify `PrefetchService` that the corresponding `PrefetchContainer` is no
   // longer needed. `PrefetchService` might release the container and its
   // corresponding resources by its decision with best-effort.
@@ -73,14 +106,20 @@
   }
 }
 
-void PrefetchHandleImpl::SetOnPrefetchHeadReceived(
+void PrefetchHandleImpl::SetOnPrefetchHeadReceivedCallback(
     base::RepeatingCallback<void(const network::mojom::URLResponseHead&)>
         on_prefetch_head_received) {
-  CHECK(!prefetch_container_observer_);
-
-  prefetch_container_observer_ = std::make_unique<PrefetchContainerObserver>(
+  prefetch_container_observer_.SetOnPrefetchHeadReceivedCallback(
       std::move(on_prefetch_head_received));
-  prefetch_container_->AddObserver(prefetch_container_observer_.get());
+}
+
+void PrefetchHandleImpl::SetOnPrefetchCompletedOrFailedCallback(
+    base::RepeatingCallback<
+        void(const network::URLLoaderCompletionStatus& completion_status,
+             const std::optional<int>& response_code)>
+        on_prefetch_completed_or_failed) {
+  prefetch_container_observer_.SetOnPrefetchCompletedOrFailedCallback(
+      std::move(on_prefetch_completed_or_failed));
 }
 
 bool PrefetchHandleImpl::IsAlive() const {
diff --git a/content/browser/preloading/prefetch/prefetch_handle_impl.h b/content/browser/preloading/prefetch/prefetch_handle_impl.h
index 63f0b4e6..ec04aff 100644
--- a/content/browser/preloading/prefetch/prefetch_handle_impl.h
+++ b/content/browser/preloading/prefetch/prefetch_handle_impl.h
@@ -21,9 +21,7 @@
 // TODO(crbug.com/400761083): Put it into `namespace prefetch_handle`.
 class PrefetchContainerObserver final : public PrefetchContainer::Observer {
  public:
-  explicit PrefetchContainerObserver(
-      base::RepeatingCallback<void(const network::mojom::URLResponseHead&)>
-          on_prefetch_head_received);
+  PrefetchContainerObserver();
   ~PrefetchContainerObserver() override;
 
   // Not movable nor copyable.
@@ -34,15 +32,31 @@
   PrefetchContainerObserver& operator=(const PrefetchContainerObserver&) =
       delete;
 
+  void SetOnPrefetchHeadReceivedCallback(
+      base::RepeatingCallback<void(const network::mojom::URLResponseHead&)>
+          on_prefetch_head_received);
+  void SetOnPrefetchCompletedOrFailedCallback(
+      base::RepeatingCallback<
+          void(const network::URLLoaderCompletionStatus& completion_status,
+               const std::optional<int>& response_code)>
+          on_prefetch_completed_or_failed);
+
   // Implements `PrefetchContainer::Observer`.
   void OnWillBeDestroyed(PrefetchContainer& prefetch_container) override;
   void OnGotInitialEligibility(PrefetchContainer& prefetch_container,
                                PreloadingEligibility eligibility) override;
   void OnDeterminedHead(PrefetchContainer& prefetch_container) override;
+  void OnPrefetchCompletedOrFailed(
+      const network::URLLoaderCompletionStatus& completion_status,
+      const std::optional<int>& response_code) override;
 
  private:
   base::RepeatingCallback<void(const network::mojom::URLResponseHead&)>
       on_prefetch_head_received_;
+  base::RepeatingCallback<void(
+      const network::URLLoaderCompletionStatus& completion_status,
+      const std::optional<int>& response_code)>
+      on_prefetch_completed_or_failed_;
 };
 
 class PrefetchHandleImpl final : public PrefetchHandle {
@@ -52,9 +66,14 @@
   ~PrefetchHandleImpl() override;
 
   // `PrefetchHandle` implementations
-  void SetOnPrefetchHeadReceived(
+  void SetOnPrefetchHeadReceivedCallback(
       base::RepeatingCallback<void(const network::mojom::URLResponseHead&)>
           on_prefetch_head_received) override;
+  void SetOnPrefetchCompletedOrFailedCallback(
+      base::RepeatingCallback<
+          void(const network::URLLoaderCompletionStatus& completion_status,
+               const std::optional<int>& response_code)>
+          on_prefetch_completed_or_failed) override;
   bool IsAlive() const override;
 
   // TODO(crbug.com/390329781): The following methods are tentative interface
@@ -70,7 +89,7 @@
  private:
   base::WeakPtr<PrefetchService> prefetch_service_;
   base::WeakPtr<PrefetchContainer> prefetch_container_;
-  std::unique_ptr<PrefetchContainerObserver> prefetch_container_observer_;
+  PrefetchContainerObserver prefetch_container_observer_;
   std::optional<PrefetchStatus> prefetch_status_on_release_started_prefetch_;
 };
 
diff --git a/content/browser/preloading/prefetch/prefetch_match_resolver.cc b/content/browser/preloading/prefetch/prefetch_match_resolver.cc
index 97eec695..5475f69 100644
--- a/content/browser/preloading/prefetch/prefetch_match_resolver.cc
+++ b/content/browser/preloading/prefetch/prefetch_match_resolver.cc
@@ -19,6 +19,7 @@
 #include "content/browser/preloading/prerender/prerender_host_registry.h"
 #include "content/browser/renderer_host/render_frame_host_delegate.h"
 #include "content/public/browser/navigation_handle_user_data.h"
+#include "services/network/public/cpp/url_loader_completion_status.h"
 
 namespace content {
 
@@ -338,6 +339,10 @@
   UnblockForMatch(prefetch_container.key());
 }
 
+void PrefetchMatchResolver::OnPrefetchCompletedOrFailed(
+    const network::URLLoaderCompletionStatus& completion_status,
+    const std::optional<int>& response_code) {}
+
 void PrefetchMatchResolver::OnTimeout(PrefetchContainer::Key prefetch_key) {
   // `timeout_timer` is alive, which implies `candidate` is alive.
   CHECK(candidates_.contains(prefetch_key));
diff --git a/content/browser/preloading/prefetch/prefetch_match_resolver.h b/content/browser/preloading/prefetch/prefetch_match_resolver.h
index 07b578e2..4ac11bae 100644
--- a/content/browser/preloading/prefetch/prefetch_match_resolver.h
+++ b/content/browser/preloading/prefetch/prefetch_match_resolver.h
@@ -47,6 +47,9 @@
   void OnGotInitialEligibility(PrefetchContainer& prefetch_container,
                                PreloadingEligibility eligibility) override;
   void OnDeterminedHead(PrefetchContainer& prefetch_container) override;
+  void OnPrefetchCompletedOrFailed(
+      const network::URLLoaderCompletionStatus& completion_status,
+      const std::optional<int>& response_code) override;
 
   // Finds prefetch that matches to a navigation and is servable.
   //
diff --git a/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc b/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
index 23b19cc..a5bc6f6 100644
--- a/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
+++ b/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
@@ -44,12 +44,12 @@
 #if BUILDFLAG(ENABLE_SCREEN_CAPTURE)
 #include "content/browser/media/capture/desktop_capture_device_uma_types.h"
 #include "content/browser/media/capture/web_contents_video_capture_device.h"
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
+#if !BUILDFLAG(IS_IOS)
 #if defined(USE_AURA)
 #include "content/browser/media/capture/aura_window_video_capture_device.h"
 #endif  // defined(USE_AURA)
 #include "content/browser/media/capture/desktop_capture_device.h"
-#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
+#endif  // !BUILDFLAG(IS_IOS)
 #if BUILDFLAG(IS_MAC)
 #include "content/browser/media/capture/desktop_capture_device_mac.h"
 #include "content/browser/media/capture/screen_capture_kit_device_utils_mac.h"
@@ -202,12 +202,11 @@
   if ((device_out = CreateDesktopCaptureDeviceMac(desktop_id))) {
     return kDesktopCaptureDeviceMac;
   }
-#endif  // BUILDFLAG(IS_MAC)
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
+#elif !BUILDFLAG(IS_IOS)
   if ((device_out = DesktopCaptureDevice::Create(desktop_id))) {
     return kLegacyDesktopCaptureDevice;
   }
-#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
+#endif  // !BUILDFLAG(IS_IOS)
   return kNoImplementation;
 }
 #endif  // BUILDFLAG(ENABLE_SCREEN_CAPTURE)
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
index 0287e30..32f3bf2 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -314,6 +314,9 @@
       quota_manager_proxy, special_storage_policy,
       std::move(non_network_pending_loader_factory_bundle_for_update_check),
       core_observer_list_.get(), core_sync_observer_list_.get(), this);
+
+  GetContentClient()->browser()->PrewarmServiceWorkerRegistrationForDSE(
+      browser_context, *this);
 }
 
 void ServiceWorkerContextWrapper::Shutdown() {
diff --git a/content/browser/webauth/authenticator_common_impl.cc b/content/browser/webauth/authenticator_common_impl.cc
index ef831a8..45e818b6 100644
--- a/content/browser/webauth/authenticator_common_impl.cc
+++ b/content/browser/webauth/authenticator_common_impl.cc
@@ -36,6 +36,7 @@
 #include "base/metrics/user_metrics_action.h"
 #include "base/notreached.h"
 #include "base/strings/string_view_util.h"
+#include "base/task/sequenced_task_runner.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "build/build_config.h"
@@ -972,10 +973,8 @@
       base::BindOnce(&AuthenticatorCommonImpl::OnCancelFromUI,
                      weak_factory_.GetWeakPtr()) /* cancel_callback */,
       base::BindOnce(
-          &AuthenticatorCommonImpl::CancelWithStatus,
-          weak_factory_.GetWeakPtr(),
-          blink::mojom::AuthenticatorStatus::
-              IMMEDIATE_NOT_FOUND) /* immediate_not_found_callback */,
+          &AuthenticatorCommonImpl::CancelRequestForImmediateMediation,
+          weak_factory_.GetWeakPtr()) /* immediate_not_found_callback */,
       base::BindRepeating(
           &AuthenticatorCommonImpl::StartGetAssertionRequest,
           weak_factory_.GetWeakPtr(),
@@ -2559,7 +2558,7 @@
 
 void AuthenticatorCommonImpl::OnImmediateTimeout() {
   base::UmaHistogramBoolean(kImmediateTimeoutWhileWaitingForUi, true);
-  CancelWithStatus(blink::mojom::AuthenticatorStatus::IMMEDIATE_NOT_FOUND);
+  CancelRequestForImmediateMediation();
 }
 
 void AuthenticatorCommonImpl::CancelImmediateTimeout() {
@@ -2571,6 +2570,24 @@
   req_state_->immediate_timer->Stop();
 }
 
+void AuthenticatorCommonImpl::CancelRequestForImmediateMediation() {
+  // Post a task to defer the cancellation, otherwise a reentrancy may occur.
+  // For example all authenticators may report no credentials; but the
+  // discoveries may still be active. See crbug.com/424491613 for an example.
+  base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](base::WeakPtr<AuthenticatorCommonImpl> auth_ptr) {
+            if (!auth_ptr) {
+              return;
+            }
+
+            auth_ptr->CancelWithStatus(
+                blink::mojom::AuthenticatorStatus::IMMEDIATE_NOT_FOUND);
+          },
+          weak_factory_.GetWeakPtr()));
+}
+
 void AuthenticatorCommonImpl::CancelWithStatus(
     blink::mojom::AuthenticatorStatus status) {
   // Callers may attempt to cancel whether there is a request or not.
diff --git a/content/browser/webauth/authenticator_common_impl.h b/content/browser/webauth/authenticator_common_impl.h
index 5528d7e..b5e848d 100644
--- a/content/browser/webauth/authenticator_common_impl.h
+++ b/content/browser/webauth/authenticator_common_impl.h
@@ -298,6 +298,10 @@
   // Cancels the immediate mediation timer when the UI is shown.
   void CancelImmediateTimeout();
 
+  // Cancels the current request if it's an immediate mediation and no immediate
+  // mediation UI was shown.
+  void CancelRequestForImmediateMediation();
+
   // Cancels the currently pending request (if any) with the supplied status.
   void CancelWithStatus(blink::mojom::AuthenticatorStatus status);
 
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/InputTransferHandler.java b/content/public/android/java/src/org/chromium/content_public/browser/InputTransferHandler.java
index 41ac46e..a3f22d55 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/InputTransferHandler.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/InputTransferHandler.java
@@ -64,11 +64,12 @@
         }
 
         // Browser InputTransfeToken might have changed. On Viz side we aren't destroying
-        // InputReceiver (due to platform bug: b/385124056) which was created with the initial
-        // Browser token. Attempt at transferring touch sequence using new Browser token and old Viz
-        // token would fail, so just early out here instead of making a binder call later.
+        // InputReceiver (due to platform bug: b/385124056 on Android V) which was created with the
+        // initial Browser token. Attempt at transferring touch sequence using new Browser token and
+        // old Viz token would fail, so just early out here instead of making a binder call later.
         assert sInitialBrowserToken != null;
-        if (sInitialBrowserToken != mBrowserToken.hashCode()) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.BAKLAVA
+                && sInitialBrowserToken != mBrowserToken.hashCode()) {
             return TransferInputToVizResult.BROWSER_TOKEN_CHANGED;
         }
 
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index fe00e15e..ae53bdb6 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -743,6 +743,10 @@
   return true;
 }
 
+void ContentBrowserClient::PrewarmServiceWorkerRegistrationForDSE(
+    BrowserContext* browser_context,
+    ServiceWorkerContext& service_worker_context) {}
+
 bool ContentBrowserClient::CanSendSCTAuditingReport(
     BrowserContext* browser_context) {
   return false;
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index f9db6c5..668c600 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -262,6 +262,7 @@
 class RenderProcessHost;
 class ResponsivenessCalculatorDelegate;
 class SerialDelegate;
+class ServiceWorkerContext;
 class SiteInstance;
 class SpeculationHostDelegate;
 class SpeechRecognitionManagerDelegate;
@@ -1285,6 +1286,12 @@
       content::BrowserContext* browser_context,
       content::WebContents* web_contents);
 
+  // Prewarms the ServiceWorker registration of the DefaultSearchEngine (DSE) by
+  // prefetching it from the database.
+  virtual void PrewarmServiceWorkerRegistrationForDSE(
+      BrowserContext* browser_context,
+      ServiceWorkerContext& service_worker_context);
+
   // Allows the embedder to implement policy for whether an SCT auditing report
   // should be sent.
   virtual bool CanSendSCTAuditingReport(BrowserContext* browser_context);
diff --git a/content/public/browser/desktop_capture.cc b/content/public/browser/desktop_capture.cc
index d208b6e86..6496f78f 100644
--- a/content/public/browser/desktop_capture.cc
+++ b/content/public/browser/desktop_capture.cc
@@ -15,6 +15,10 @@
 #include "content/browser/media/capture/desktop_capturer_ash.h"
 #endif
 
+#if BUILDFLAG(IS_ANDROID)
+#include "content/browser/media/capture/desktop_capturer_android.h"
+#endif
+
 #if defined(WEBRTC_USE_PIPEWIRE)
 #include "base/environment.h"
 #include "base/nix/xdg_util.h"
@@ -91,7 +95,12 @@
     return std::make_unique<DesktopCapturerAsh>();
   }
 #endif  // BUILDFLAG(IS_CHROMEOS)
+
+#if BUILDFLAG(IS_ANDROID)
+  return std::make_unique<DesktopCapturerAndroid>(options);
+#else
   return webrtc::DesktopCapturer::CreateScreenCapturer(options);
+#endif  // BUILDFLAG(IS_ANDROID)
 }
 
 std::unique_ptr<webrtc::DesktopCapturer> CreateWindowCapturer(
@@ -100,7 +109,11 @@
   options.set_allow_wgc_capturer_fallback(true);
 #endif  // defined(RTC_ENABLE_WIN_WGC)
 
+#if BUILDFLAG(IS_ANDROID)
+  return std::make_unique<DesktopCapturerAndroid>(options);
+#else
   return webrtc::DesktopCapturer::CreateWindowCapturer(options);
+#endif  // BUILDFLAG(IS_ANDROID)
 }
 
 bool CanUsePipeWire() {
diff --git a/content/public/browser/prefetch_handle.h b/content/public/browser/prefetch_handle.h
index 720f1d2..4af3f513 100644
--- a/content/public/browser/prefetch_handle.h
+++ b/content/public/browser/prefetch_handle.h
@@ -5,9 +5,15 @@
 #ifndef CONTENT_PUBLIC_BROWSER_PREFETCH_HANDLE_H_
 #define CONTENT_PUBLIC_BROWSER_PREFETCH_HANDLE_H_
 
+#include <optional>
+
 #include "base/functional/callback_forward.h"
 #include "services/network/public/mojom/url_response_head.mojom-forward.h"
 
+namespace network {
+struct URLLoaderCompletionStatus;
+}  // namespace network
+
 namespace content {
 
 // The interface to control prefetch resources associated with this.
@@ -25,11 +31,15 @@
   PrefetchHandle& operator=(PrefetchHandle&& other) = default;
 
   // Sets a callback called when non-redirect header is successfully received.
-  //
-  // Panics when called multiple times.
-  virtual void SetOnPrefetchHeadReceived(
+  virtual void SetOnPrefetchHeadReceivedCallback(
       base::RepeatingCallback<void(const network::mojom::URLResponseHead&)>
           on_prefetch_head_received) = 0;
+  // Sets a callback called when loading of prefetch failed.
+  virtual void SetOnPrefetchCompletedOrFailedCallback(
+      base::RepeatingCallback<
+          void(const network::URLLoaderCompletionStatus& completion_status,
+               const std::optional<int>& response_code)>
+          on_prefetch_completed_or_failed) = 0;
 
   // Returns true if the underlying `PrefetchContainer` is alive.
   virtual bool IsAlive() const = 0;
diff --git a/gin/OWNERS b/gin/OWNERS
index 0e039294..b053b89 100644
--- a/gin/OWNERS
+++ b/gin/OWNERS
@@ -7,8 +7,6 @@
 mlippautz@chromium.org
 
 # For adding JS/Wasm feature kill-switches.
-per-file gin_features.*=syg@chromium.org
-per-file v8_initializer.cc=syg@chromium.org
 
 # For ThreadIsolation related changes.
 per-file thread_isolation.*=sroettger@google.com
diff --git a/gpu/command_buffer/client/client_shared_image.cc b/gpu/command_buffer/client/client_shared_image.cc
index f3509f1..7df28daa 100644
--- a/gpu/command_buffer/client/client_shared_image.cc
+++ b/gpu/command_buffer/client/client_shared_image.cc
@@ -552,12 +552,6 @@
     InterfaceBase* raster_interface,
     const SyncToken& sync_token,
     bool readonly) {
-  SCOPED_CRASH_KEY_STRING32("ClientSharedImage", "DebugLabel", debug_label_);
-  SCOPED_CRASH_KEY_NUMBER("ClientSharedImage", "Usage", metadata_.usage);
-  DUMP_WILL_BE_CHECK(
-      metadata_.usage.Has(SHARED_IMAGE_USAGE_RASTER_READ) ||
-      metadata_.usage.Has(SHARED_IMAGE_USAGE_RASTER_WRITE) ||
-      metadata_.usage.Has(SHARED_IMAGE_USAGE_RASTER_COPY_SOURCE));
   return base::WrapUnique(
       new RasterScopedAccess(raster_interface, this, sync_token, readonly));
 }
@@ -798,17 +792,6 @@
   CHECK(raster_interface_);
   shared_image_->BeginAccess(readonly);
   raster_interface_->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
-  SCOPED_CRASH_KEY_STRING32("ClientSharedImage", "DebugLabel",
-                            shared_image_->debug_label());
-  SCOPED_CRASH_KEY_NUMBER("ClientSharedImage", "Usage", shared_image_->usage());
-  if (readonly) {
-    DUMP_WILL_BE_CHECK(
-        shared_image_->usage().Has(SHARED_IMAGE_USAGE_RASTER_READ) ||
-        shared_image_->usage().Has(SHARED_IMAGE_USAGE_RASTER_COPY_SOURCE));
-  } else {
-    DUMP_WILL_BE_CHECK(
-        shared_image_->usage().Has(SHARED_IMAGE_USAGE_RASTER_WRITE));
-  }
 }
 
 // static
diff --git a/gpu/command_buffer/service/shared_image/android_video_image_backing.cc b/gpu/command_buffer/service/shared_image/android_video_image_backing.cc
index e6f3c9a..c5dae54 100644
--- a/gpu/command_buffer/service/shared_image/android_video_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/android_video_image_backing.cc
@@ -42,11 +42,11 @@
           alpha_type,
           // This SI will be used to back a VideoFrame. As such, it
           // will potentially be sent to the display compositor and read by the
-          // GL interface for WebGL, and read by raster interface.
+          // GL interface for WebGL.
           // TODO: crbug.com/354856448 - add a parameter to the constructor that
           // allows to specify whether SCANOUT is needed.
           {SHARED_IMAGE_USAGE_DISPLAY_READ, SHARED_IMAGE_USAGE_GLES2_READ,
-           SHARED_IMAGE_USAGE_RASTER_READ, SHARED_IMAGE_USAGE_SCANOUT},
+           SHARED_IMAGE_USAGE_SCANOUT},
           std::move(debug_label),
           viz::SinglePlaneFormat::kRGBA_8888.EstimatedSizeInBytes(size),
           is_thread_safe,
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory.cc b/gpu/ipc/service/gpu_memory_buffer_factory.cc
index 59b2817..b01c0d0d 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory.cc
+++ b/gpu/ipc/service/gpu_memory_buffer_factory.cc
@@ -109,19 +109,4 @@
   return handle;
 }
 
-void GpuMemoryBufferFactory::CreateGpuMemoryBufferAsync(
-    gfx::GpuMemoryBufferId id,
-    const gfx::Size& size,
-    gfx::BufferFormat format,
-    gfx::BufferUsage usage,
-    int client_id,
-    SurfaceHandle surface_handle,
-    CreateGpuMemoryBufferAsyncCallback callback) {
-  // By default, we assume it's ok to allocate GMBs synchronously on the IO
-  // thread. However, subclasses can override this assumption.
-  std::move(callback).Run(
-      CreateGpuMemoryBuffer(id, size, /*framebuffer_size=*/size, format, usage,
-                            client_id, surface_handle));
-}
-
 }  // namespace gpu
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory.h b/gpu/ipc/service/gpu_memory_buffer_factory.h
index 6bfff24..8ad6128 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory.h
+++ b/gpu/ipc/service/gpu_memory_buffer_factory.h
@@ -71,20 +71,6 @@
       int client_id,
       SurfaceHandle surface_handle) = 0;
 
-  // Same as above, but returns the result asynchrounously. Safe to use on the
-  // IO thread. |callback| will be called on the same thread that calls this
-  // method, and it might be called on the same call stack.
-  using CreateGpuMemoryBufferAsyncCallback =
-      base::OnceCallback<void(gfx::GpuMemoryBufferHandle)>;
-  virtual void CreateGpuMemoryBufferAsync(
-      gfx::GpuMemoryBufferId id,
-      const gfx::Size& size,
-      gfx::BufferFormat format,
-      gfx::BufferUsage usage,
-      int client_id,
-      SurfaceHandle surface_handle,
-      CreateGpuMemoryBufferAsyncCallback callback);
-
   // Destroys GPU memory buffer identified by |id|. It can be called on any
   // thread.
   virtual void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc
index 9bc8abf..2737e335 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc
@@ -50,24 +50,6 @@
                                                client_id, std::move(pixmap));
 }
 
-void GpuMemoryBufferFactoryNativePixmap::CreateGpuMemoryBufferAsync(
-    gfx::GpuMemoryBufferId id,
-    const gfx::Size& size,
-    gfx::BufferFormat format,
-    gfx::BufferUsage usage,
-    int client_id,
-    SurfaceHandle surface_handle,
-    CreateGpuMemoryBufferAsyncCallback callback) {
-  ui::OzonePlatform::GetInstance()
-      ->GetSurfaceFactoryOzone()
-      ->CreateNativePixmapAsync(
-          surface_handle, GetVulkanDeviceQueue(), size, format, usage,
-          base::BindOnce(
-              &GpuMemoryBufferFactoryNativePixmap::OnNativePixmapCreated, id,
-              size, format, usage, client_id, std::move(callback),
-              weak_factory_.GetWeakPtr()));
-}
-
 void GpuMemoryBufferFactoryNativePixmap::DestroyGpuMemoryBuffer(
     gfx::GpuMemoryBufferId id,
     int client_id) {
@@ -92,24 +74,6 @@
   return nullptr;
 }
 
-// static
-void GpuMemoryBufferFactoryNativePixmap::OnNativePixmapCreated(
-    gfx::GpuMemoryBufferId id,
-    const gfx::Size& size,
-    gfx::BufferFormat format,
-    gfx::BufferUsage usage,
-    int client_id,
-    CreateGpuMemoryBufferAsyncCallback callback,
-    base::WeakPtr<GpuMemoryBufferFactoryNativePixmap> weak_ptr,
-    scoped_refptr<gfx::NativePixmap> pixmap) {
-  if (weak_ptr) {
-    std::move(callback).Run(weak_ptr->CreateGpuMemoryBufferFromNativePixmap(
-        id, size, format, usage, client_id, pixmap));
-  } else {
-    std::move(callback).Run(gfx::GpuMemoryBufferHandle());
-  }
-}
-
 gfx::GpuMemoryBufferHandle
 GpuMemoryBufferFactoryNativePixmap::CreateGpuMemoryBufferFromNativePixmap(
     gfx::GpuMemoryBufferId id,
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h
index 9e9d719..bcc77d5b 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h
@@ -43,14 +43,6 @@
       gfx::BufferUsage usage,
       int client_id,
       SurfaceHandle surface_handle) override;
-  void CreateGpuMemoryBufferAsync(
-      gfx::GpuMemoryBufferId id,
-      const gfx::Size& size,
-      gfx::BufferFormat format,
-      gfx::BufferUsage usage,
-      int client_id,
-      SurfaceHandle surface_handle,
-      CreateGpuMemoryBufferAsyncCallback callback) override;
   void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
                               int client_id) override;
   bool FillSharedMemoryRegionWithBufferContents(
@@ -64,16 +56,6 @@
                                              scoped_refptr<gfx::NativePixmap>,
                                              NativePixmapMapKeyHash>;
 
-  static void OnNativePixmapCreated(
-      gfx::GpuMemoryBufferId id,
-      const gfx::Size& size,
-      gfx::BufferFormat format,
-      gfx::BufferUsage usage,
-      int client_id,
-      CreateGpuMemoryBufferAsyncCallback callback,
-      base::WeakPtr<GpuMemoryBufferFactoryNativePixmap> weak_ptr,
-      scoped_refptr<gfx::NativePixmap> pixmap);
-
   gfx::GpuMemoryBufferHandle CreateGpuMemoryBufferFromNativePixmap(
       gfx::GpuMemoryBufferId id,
       const gfx::Size& size,
diff --git a/infra/config/generated/builders/ci/Win x64 Builder/targets/chromium.win.json b/infra/config/generated/builders/ci/Win x64 Builder/targets/chromium.win.json
index a4ad240..54a6feb 100644
--- a/infra/config/generated/builders/ci/Win x64 Builder/targets/chromium.win.json
+++ b/infra/config/generated/builders/ci/Win x64 Builder/targets/chromium.win.json
@@ -446,7 +446,7 @@
             "os": "Windows-10-19045"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 10
+          "shards": 11
         },
         "test": "content_browsertests",
         "test_id_prefix": "ninja://content/test:content_browsertests/"
diff --git a/infra/config/generated/builders/ci/Win10 Tests x64/targets/chromium.win.json b/infra/config/generated/builders/ci/Win10 Tests x64/targets/chromium.win.json
index 58626b42..6d193b8 100644
--- a/infra/config/generated/builders/ci/Win10 Tests x64/targets/chromium.win.json
+++ b/infra/config/generated/builders/ci/Win10 Tests x64/targets/chromium.win.json
@@ -422,7 +422,7 @@
             "os": "Windows-10-19045"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 10
+          "shards": 11
         },
         "test": "content_browsertests",
         "test_id_prefix": "ninja://content/test:content_browsertests/"
diff --git a/infra/config/generated/builders/ci/android-15-x64-rel/targets/chromium.android.json b/infra/config/generated/builders/ci/android-15-x64-rel/targets/chromium.android.json
index 1a8d8eb..f2a14e5 100644
--- a/infra/config/generated/builders/ci/android-15-x64-rel/targets/chromium.android.json
+++ b/infra/config/generated/builders/ci/android-15-x64-rel/targets/chromium.android.json
@@ -944,7 +944,7 @@
             }
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
+          "shards": 5
         },
         "test": "components_browsertests",
         "test_id_prefix": "ninja://components:components_browsertests/"
diff --git a/infra/config/generated/builders/ci/android-desktop-x64-compile-rel/targets/chromium.android.desktop.json b/infra/config/generated/builders/ci/android-desktop-x64-compile-rel/targets/chromium.android.desktop.json
index 722b6b0..7c48fb6f 100644
--- a/infra/config/generated/builders/ci/android-desktop-x64-compile-rel/targets/chromium.android.desktop.json
+++ b/infra/config/generated/builders/ci/android-desktop-x64-compile-rel/targets/chromium.android.desktop.json
@@ -51,7 +51,7 @@
             }
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 25
+          "shards": 22
         },
         "test": "android_browsertests",
         "test_id_prefix": "ninja://chrome/test:android_browsertests/"
diff --git a/infra/config/generated/builders/ci/android-desktop-x64-rel-15-tests/targets/chromium.android.desktop.json b/infra/config/generated/builders/ci/android-desktop-x64-rel-15-tests/targets/chromium.android.desktop.json
index 1f23b66b..12b32eb6 100644
--- a/infra/config/generated/builders/ci/android-desktop-x64-rel-15-tests/targets/chromium.android.desktop.json
+++ b/infra/config/generated/builders/ci/android-desktop-x64-rel-15-tests/targets/chromium.android.desktop.json
@@ -46,7 +46,7 @@
             }
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 25
+          "shards": 22
         },
         "test": "android_browsertests",
         "test_id_prefix": "ninja://chrome/test:android_browsertests/"
diff --git a/infra/config/generated/builders/ci/linux-chromeos-rel/targets/chromium.chromiumos.json b/infra/config/generated/builders/ci/linux-chromeos-rel/targets/chromium.chromiumos.json
index 087275a..8e2d143 100644
--- a/infra/config/generated/builders/ci/linux-chromeos-rel/targets/chromium.chromiumos.json
+++ b/infra/config/generated/builders/ci/linux-chromeos-rel/targets/chromium.chromiumos.json
@@ -296,7 +296,7 @@
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 187
+          "shards": 140
         },
         "test": "browser_tests",
         "test_id_prefix": "ninja://chrome/test:browser_tests/"
diff --git a/infra/config/generated/builders/try/android-15-x64-rel/targets/chromium.android.json b/infra/config/generated/builders/try/android-15-x64-rel/targets/chromium.android.json
index 1a8d8eb..f2a14e5 100644
--- a/infra/config/generated/builders/try/android-15-x64-rel/targets/chromium.android.json
+++ b/infra/config/generated/builders/try/android-15-x64-rel/targets/chromium.android.json
@@ -944,7 +944,7 @@
             }
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
+          "shards": 5
         },
         "test": "components_browsertests",
         "test_id_prefix": "ninja://components:components_browsertests/"
diff --git a/infra/config/generated/builders/try/android-desktop-15-x64-rel/targets/chromium.android.desktop.json b/infra/config/generated/builders/try/android-desktop-15-x64-rel/targets/chromium.android.desktop.json
index 722b6b0..7c48fb6f 100644
--- a/infra/config/generated/builders/try/android-desktop-15-x64-rel/targets/chromium.android.desktop.json
+++ b/infra/config/generated/builders/try/android-desktop-15-x64-rel/targets/chromium.android.desktop.json
@@ -51,7 +51,7 @@
             }
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 25
+          "shards": 22
         },
         "test": "android_browsertests",
         "test_id_prefix": "ninja://chrome/test:android_browsertests/"
diff --git a/infra/config/generated/builders/try/android-desktop-x64-rel/targets/chromium.android.desktop.json b/infra/config/generated/builders/try/android-desktop-x64-rel/targets/chromium.android.desktop.json
index 722b6b0..7c48fb6f 100644
--- a/infra/config/generated/builders/try/android-desktop-x64-rel/targets/chromium.android.desktop.json
+++ b/infra/config/generated/builders/try/android-desktop-x64-rel/targets/chromium.android.desktop.json
@@ -51,7 +51,7 @@
             }
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 25
+          "shards": 22
         },
         "test": "android_browsertests",
         "test_id_prefix": "ninja://chrome/test:android_browsertests/"
diff --git a/infra/config/generated/builders/try/android-x64-rel/targets/chromium.android.json b/infra/config/generated/builders/try/android-x64-rel/targets/chromium.android.json
index d6bf78a..529d9ceb 100644
--- a/infra/config/generated/builders/try/android-x64-rel/targets/chromium.android.json
+++ b/infra/config/generated/builders/try/android-x64-rel/targets/chromium.android.json
@@ -1001,7 +1001,7 @@
             }
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
+          "shards": 5
         },
         "test": "components_browsertests",
         "test_id_prefix": "ninja://components:components_browsertests/"
diff --git a/infra/config/generated/builders/try/linux-chromeos-rel/targets/chromium.chromiumos.json b/infra/config/generated/builders/try/linux-chromeos-rel/targets/chromium.chromiumos.json
index 087275a..8e2d143 100644
--- a/infra/config/generated/builders/try/linux-chromeos-rel/targets/chromium.chromiumos.json
+++ b/infra/config/generated/builders/try/linux-chromeos-rel/targets/chromium.chromiumos.json
@@ -296,7 +296,7 @@
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 187
+          "shards": 140
         },
         "test": "browser_tests",
         "test_id_prefix": "ninja://chrome/test:browser_tests/"
diff --git a/infra/config/generated/builders/try/win-rel/targets/chromium.win.json b/infra/config/generated/builders/try/win-rel/targets/chromium.win.json
index 50dd036..0944606 100644
--- a/infra/config/generated/builders/try/win-rel/targets/chromium.win.json
+++ b/infra/config/generated/builders/try/win-rel/targets/chromium.win.json
@@ -446,7 +446,7 @@
             "os": "Windows-10-19045"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 10
+          "shards": 11
         },
         "test": "content_browsertests",
         "test_id_prefix": "ninja://content/test:content_browsertests/"
diff --git a/infra/config/targets/autoshard_exceptions.json b/infra/config/targets/autoshard_exceptions.json
index da8ff4a..14280c6 100644
--- a/infra/config/targets/autoshard_exceptions.json
+++ b/infra/config/targets/autoshard_exceptions.json
@@ -16,7 +16,7 @@
                 "try_builder": "android-x64-rel"
             },
             "components_browsertests": {
-                "shards": 3,
+                "shards": 5,
                 "try_builder": "android-x64-rel"
             }
         },
@@ -46,7 +46,7 @@
     "chromium.android.desktop": {
         "android-desktop-x64-rel-15-tests": {
             "android_browsertests": {
-                "shards": 25,
+                "shards": 22,
                 "try_builder": "android-desktop-x64-rel"
             },
             "unit_tests": {
@@ -72,7 +72,7 @@
                 "try_builder": "linux-chromeos-rel"
             },
             "browser_tests": {
-                "shards": 187,
+                "shards": 140,
                 "try_builder": "linux-chromeos-rel"
             },
             "components_unittests": {
@@ -222,7 +222,7 @@
     "chromium.win": {
         "Win10 Tests x64": {
             "content_browsertests": {
-                "shards": 10,
+                "shards": 11,
                 "try_builder": "win-rel"
             },
             "headless_shell_wpt_tests": {
diff --git a/ios/chrome/app/strings/resources/ios_strings_eu.xtb b/ios/chrome/app/strings/resources/ios_strings_eu.xtb
index 50e56be8..5e8a4f7 100644
--- a/ios/chrome/app/strings/resources/ios_strings_eu.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_eu.xtb
@@ -1444,6 +1444,7 @@
 <translation id="6831043979455480757">Itzuli</translation>
 <translation id="6842136130964845393">Gordetako pasahitzak edonoiz atzitu ahal izango dituzula ziurtatzeko, egiaztatu zeu zarela</translation>
 <translation id="6851516051005285358">Eskatu ordenagailuetarako webgunea</translation>
+<translation id="6857446173140146664">Ezabatu atzeko planoa</translation>
 <translation id="6858718102216837409">Gehitu hizkuntza bat…</translation>
 <translation id="6858855187367714033">Eskaneatuta</translation>
 <translation id="6859944681507688231">QR kodea edo kreditu-txartela eskaneatzeko, gaitu kamera ezarpenetan.</translation>
diff --git a/ios/chrome/app/strings/resources/ios_strings_lo.xtb b/ios/chrome/app/strings/resources/ios_strings_lo.xtb
index ea3858a..4fa8820 100644
--- a/ios/chrome/app/strings/resources/ios_strings_lo.xtb
+++ b/ios/chrome/app/strings/resources/ios_strings_lo.xtb
@@ -545,6 +545,7 @@
 <translation id="3227137524299004712">ໄມໂຄຣໂຟນ</translation>
 <translation id="3235063766008841141">ປ້ອນໃນເວັບໄຊຫຼອກລວງແລະ ພົບເຫັນໃນການລະເມີດຂໍ້ມູນ</translation>
 <translation id="3235242129752692527">ແກ້ໄຂລາຍລະອຽດນັດໝາຍແລ້ວແຕະໃສ່ “ບັນທຶກ.“</translation>
+<translation id="323863549127671026">ແຖບ ແລະ ກຸ່ມແຖບທີ່ເປີດຢູ່ໃນປັດຈຸບັນ</translation>
 <translation id="3240426699337459095">ອັດ​ສຳ​ເນົາ​ລິ້ງ​ແລ້ວ</translation>
 <translation id="3244271242291266297">ດດ</translation>
 <translation id="3245429137663807393">ຫາກທ່ານແບ່ງປັນລາຍງານການນຳໃຊ້ Chrome ນຳ, ລາຍງານເຫຼົ່ານັ້ນຈະຮວມເອົາ URL ທີ່ທ່ານເຂົ້າໄວ້ພ້ອມ</translation>
diff --git a/ios/chrome/browser/incognito_reauth/ui_bundled/incognito_reauth_view.mm b/ios/chrome/browser/incognito_reauth/ui_bundled/incognito_reauth_view.mm
index 3be2155c..c9b34e8 100644
--- a/ios/chrome/browser/incognito_reauth/ui_bundled/incognito_reauth_view.mm
+++ b/ios/chrome/browser/incognito_reauth/ui_bundled/incognito_reauth_view.mm
@@ -49,20 +49,24 @@
 - (instancetype)init {
   self = [super init];
   if (self) {
-    // Increase blur intensity by layering some blur views to make
-    // content behind really not recognizeable.
-    for (int i = 0; i < 3; i++) {
-      UIBlurEffect* blurEffect =
-          [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
-      UIVisualEffectView* blurView =
-          [[UIVisualEffectView alloc] initWithEffect:blurEffect];
-      [self addSubview:blurView];
-      blurView.translatesAutoresizingMaskIntoConstraints = NO;
-      AddSameConstraints(self, blurView);
+    if (!IsIOSSoftLockEnabled()) {
+      // Increase blur intensity by layering some blur views to make
+      // content behind really not recognizeable.
+      for (int i = 0; i < 3; i++) {
+        UIBlurEffect* blurEffect =
+            [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
+        UIVisualEffectView* blurView =
+            [[UIVisualEffectView alloc] initWithEffect:blurEffect];
+        [self addSubview:blurView];
+        blurView.translatesAutoresizingMaskIntoConstraints = NO;
+        AddSameConstraints(self, blurView);
+      }
     }
 
-    UIBlurEffect* blurEffect =
-        [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
+    UIBlurEffect* blurEffect = [UIBlurEffect
+        effectWithStyle:IsIOSSoftLockEnabled()
+                            ? UIBlurEffectStyleSystemThickMaterialDark
+                            : UIBlurEffectStyleDark];
     UIVisualEffectView* blurBackgroundView =
         [[UIVisualEffectView alloc] initWithEffect:blurEffect];
     [self addSubview:blurBackgroundView];
@@ -314,13 +318,15 @@
     [button setTitle:l10n_util::GetNSString(
                          IDS_IOS_INCOGNITO_REAUTH_CLOSE_INCOGNITO_TABS)
             forState:UIControlStateNormal];
+    button.titleLabel.font =
+        [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
   } else {
     [button setTitle:l10n_util::GetNSString(
                          IDS_IOS_INCOGNITO_REAUTH_GO_TO_NORMAL_TABS)
             forState:UIControlStateNormal];
+    button.titleLabel.font =
+        [UIFont preferredFontForTextStyle:UIFontTextStyleTitle2];
   }
-  button.titleLabel.font =
-      [UIFont preferredFontForTextStyle:UIFontTextStyleTitle2];
   button.titleLabel.adjustsFontSizeToFitWidth = YES;
   button.titleLabel.adjustsFontForContentSizeCategory = YES;
   button.pointerInteractionEnabled = YES;
diff --git a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/toolbars/tab_grid_new_tab_button.mm b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/toolbars/tab_grid_new_tab_button.mm
index a1e0fd17..669ea0f 100644
--- a/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/toolbars/tab_grid_new_tab_button.mm
+++ b/ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/toolbars/tab_grid_new_tab_button.mm
@@ -76,6 +76,11 @@
   return self;
 }
 
+- (void)setEnabled:(BOOL)enabled {
+  [super setEnabled:enabled];
+  [self setSymbolPage:self.page];
+}
+
 #pragma mark - Public
 
 - (void)setPage:(TabGridPage)page {
@@ -90,8 +95,10 @@
     case TabGridPageIncognitoTabs:
       self.accessibilityLabel =
           l10n_util::GetNSString(IDS_IOS_TAB_GRID_CREATE_NEW_INCOGNITO_TAB);
-      _imageContainer.image = SymbolWithPalette(
-          _symbol, @[ UIColor.blackColor, UIColor.whiteColor ]);
+      _imageContainer.image = SymbolWithPalette(_symbol, @[
+        UIColor.blackColor,
+        self.enabled ? UIColor.whiteColor : UIColor.grayColor
+      ]);
       break;
     case TabGridPageRegularTabs:
       self.accessibilityLabel =
diff --git a/ios_internal b/ios_internal
index 59a93a5..3b581c6 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit 59a93a5717e2d1a9e523d986e012bde44aa5faa2
+Subproject commit 3b581c6c47e23717766c2c1922d6c7111db6cb4c
diff --git a/media/gpu/test/BUILD.gn b/media/gpu/test/BUILD.gn
index 9d1b2ed..4c8e745b 100644
--- a/media/gpu/test/BUILD.gn
+++ b/media/gpu/test/BUILD.gn
@@ -322,6 +322,7 @@
       "//base",
       "//build/config/linux/libdrm",
       "//gpu/command_buffer/client",
+      "//gpu/ipc/common:surface_handle_type",
       "//third_party/minigbm",
       "//ui/gfx:memory_buffer",
       "//ui/gfx/geometry",
diff --git a/media/gpu/test/local_gpu_memory_buffer_manager.h b/media/gpu/test/local_gpu_memory_buffer_manager.h
index 10a0900..18018b50 100644
--- a/media/gpu/test/local_gpu_memory_buffer_manager.h
+++ b/media/gpu/test/local_gpu_memory_buffer_manager.h
@@ -8,9 +8,11 @@
 #include <memory>
 
 #include "base/memory/raw_ptr.h"
-#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
+#include "base/synchronization/waitable_event.h"
+#include "gpu/ipc/common/surface_handle.h"
 #include "media/gpu/media_gpu_export.h"
 #include "ui/gfx/buffer_types.h"
+#include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/linux/scoped_gbm_device.h"
 
 namespace gfx {
@@ -25,8 +27,7 @@
 // gfx::GpuMemoryBufferManager which interacts with the DRM render node device
 // directly. The LocalGpuMemoryBufferManager is only for testing purposes and
 // should not be used in production.
-class MEDIA_GPU_EXPORT LocalGpuMemoryBufferManager
-    : public gpu::GpuMemoryBufferManager {
+class MEDIA_GPU_EXPORT LocalGpuMemoryBufferManager {
  public:
   LocalGpuMemoryBufferManager();
 
@@ -34,15 +35,14 @@
   LocalGpuMemoryBufferManager& operator=(const LocalGpuMemoryBufferManager&) =
       delete;
 
-  ~LocalGpuMemoryBufferManager() override;
+  ~LocalGpuMemoryBufferManager();
 
-  // gpu::GpuMemoryBufferManager implementation
   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::WaitableEvent* shutdown_event);
 
   // Imports a DmaBuf as a GpuMemoryBuffer to be able to map it. The
   // GBM_BO_USE_SW_READ_OFTEN usage is specified so that the user of the
diff --git a/media/renderers/paint_canvas_video_renderer_unittest.cc b/media/renderers/paint_canvas_video_renderer_unittest.cc
index f0f7029..cbeff707 100644
--- a/media/renderers/paint_canvas_video_renderer_unittest.cc
+++ b/media/renderers/paint_canvas_video_renderer_unittest.cc
@@ -952,11 +952,8 @@
   cc::SkiaPaintCanvas canvas(AllocBitmap(kWidth, kHeight));
 
   gfx::Size size(kWidth, kHeight);
-  // We try copying the contents of the source VideoFrame *into* the
-  // cached SI over the raster interface.
   scoped_refptr<gpu::ClientSharedImage> shared_image =
-      gpu::ClientSharedImage::CreateForTesting(
-          gpu::SHARED_IMAGE_USAGE_RASTER_READ);
+      gpu::ClientSharedImage::CreateForTesting();
   auto video_frame = VideoFrame::WrapSharedImage(
       PIXEL_FORMAT_NV12, shared_image, gpu::SyncToken(),
       base::BindOnce(MailboxHoldersReleased), size, gfx::Rect(size), size,
diff --git a/media/renderers/video_resource_updater_unittest.cc b/media/renderers/video_resource_updater_unittest.cc
index 0ec5f8b..ea4aea23 100644
--- a/media/renderers/video_resource_updater_unittest.cc
+++ b/media/renderers/video_resource_updater_unittest.cc
@@ -248,20 +248,12 @@
   scoped_refptr<VideoFrame> CreateTestHardwareVideoFrame(
       viz::SharedImageFormat si_format,
       VideoPixelFormat format,
-      unsigned target,
-      bool needs_raster_access) {
+      unsigned target) {
     const int kDimension = 10;
     gfx::Size size(kDimension, kDimension);
 
-    gpu::SharedImageMetadata metadata;
-    metadata.format = si_format;
-    metadata.color_space = gfx::ColorSpace::CreateSRGB();
-    metadata.surface_origin = kTopLeft_GrSurfaceOrigin;
-    metadata.alpha_type = kOpaque_SkAlphaType;
-    metadata.usage = needs_raster_access ? gpu::SHARED_IMAGE_USAGE_RASTER_READ
-                                         : gpu::SharedImageUsageSet();
     scoped_refptr<gpu::ClientSharedImage> shared_image =
-        gpu::ClientSharedImage::CreateForTesting(metadata, target);
+        gpu::ClientSharedImage::CreateForTesting(si_format, target);
     scoped_refptr<VideoFrame> video_frame = VideoFrame::WrapSharedImage(
         format, shared_image, kMailboxSyncToken,
         base::BindOnce(&VideoResourceUpdaterTest::SetReleaseSyncToken,
@@ -276,15 +268,14 @@
 
   scoped_refptr<VideoFrame> CreateTestRGBAHardwareVideoFrame() {
     return CreateTestHardwareVideoFrame(viz::SinglePlaneFormat::kRGBA_8888,
-                                        PIXEL_FORMAT_ARGB, GL_TEXTURE_2D,
-                                        /*needs_raster_access=*/false);
+                                        PIXEL_FORMAT_ARGB, GL_TEXTURE_2D);
   }
 
   scoped_refptr<VideoFrame> CreateTestStreamTextureHardwareVideoFrame(
       bool needs_copy) {
     scoped_refptr<VideoFrame> video_frame = CreateTestHardwareVideoFrame(
         viz::SinglePlaneFormat::kRGBA_8888, PIXEL_FORMAT_ARGB,
-        GL_TEXTURE_EXTERNAL_OES, /*needs_raster_access=*/needs_copy);
+        GL_TEXTURE_EXTERNAL_OES);
     video_frame->metadata().copy_required = needs_copy;
     return video_frame;
   }
@@ -293,7 +284,7 @@
   scoped_refptr<VideoFrame> CreateTestDCompSurfaceVideoFrame() {
     scoped_refptr<VideoFrame> video_frame = CreateTestHardwareVideoFrame(
         viz::SinglePlaneFormat::kRGBA_8888, PIXEL_FORMAT_ARGB,
-        GL_TEXTURE_EXTERNAL_OES, /*needs_raster_access=*/false);
+        GL_TEXTURE_EXTERNAL_OES);
     video_frame->metadata().dcomp_surface = true;
     return video_frame;
   }
@@ -728,9 +719,9 @@
 
 TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_SharedImageFormat) {
   std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
-  scoped_refptr<VideoFrame> video_frame = CreateTestHardwareVideoFrame(
-      viz::MultiPlaneFormat::kI420, PIXEL_FORMAT_I420, GL_TEXTURE_RECTANGLE_ARB,
-      /*needs_raster_access=*/false);
+  scoped_refptr<VideoFrame> video_frame =
+      CreateTestHardwareVideoFrame(viz::MultiPlaneFormat::kI420,
+                                   PIXEL_FORMAT_I420, GL_TEXTURE_RECTANGLE_ARB);
   VideoFrameExternalResource resource =
       updater->CreateExternalResourceFromVideoFrame(video_frame);
   EXPECT_EQ(VideoFrameResourceType::RGB, resource.type);
@@ -739,9 +730,9 @@
   EXPECT_EQ(resource.resource.synchronization_type,
             viz::TransferableResource::SynchronizationType::kSyncToken);
 
-  video_frame = CreateTestHardwareVideoFrame(
-      viz::MultiPlaneFormat::kI420, PIXEL_FORMAT_I420, GL_TEXTURE_RECTANGLE_ARB,
-      /*needs_raster_access=*/false);
+  video_frame =
+      CreateTestHardwareVideoFrame(viz::MultiPlaneFormat::kI420,
+                                   PIXEL_FORMAT_I420, GL_TEXTURE_RECTANGLE_ARB);
   video_frame->metadata().read_lock_fences_enabled = true;
 
   resource = updater->CreateExternalResourceFromVideoFrame(video_frame);
@@ -924,8 +915,7 @@
   std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
   EXPECT_EQ(0u, GetSharedImageCount());
   scoped_refptr<VideoFrame> video_frame = CreateTestHardwareVideoFrame(
-      viz::MultiPlaneFormat::kNV12, PIXEL_FORMAT_NV12, GL_TEXTURE_EXTERNAL_OES,
-      /*needs_raster_access=*/false);
+      viz::MultiPlaneFormat::kNV12, PIXEL_FORMAT_NV12, GL_TEXTURE_EXTERNAL_OES);
   VideoFrameExternalResource resource =
       updater->CreateExternalResourceFromVideoFrame(video_frame);
   EXPECT_EQ(VideoFrameResourceType::RGB, resource.type);
@@ -939,9 +929,9 @@
        CreateForHardwarePlanes_DualNV12_SharedImageFormat) {
   std::unique_ptr<VideoResourceUpdater> updater = CreateUpdaterForHardware();
   EXPECT_EQ(0u, GetSharedImageCount());
-  scoped_refptr<VideoFrame> video_frame = CreateTestHardwareVideoFrame(
-      viz::MultiPlaneFormat::kNV12, PIXEL_FORMAT_NV12, GL_TEXTURE_RECTANGLE_ARB,
-      /*needs_raster_access=*/false);
+  scoped_refptr<VideoFrame> video_frame =
+      CreateTestHardwareVideoFrame(viz::MultiPlaneFormat::kNV12,
+                                   PIXEL_FORMAT_NV12, GL_TEXTURE_RECTANGLE_ARB);
   VideoFrameExternalResource resource =
       updater->CreateExternalResourceFromVideoFrame(video_frame);
   // Setting to kSharedImageFormat, resource type should bo RGB.
@@ -952,8 +942,7 @@
   EXPECT_EQ(0u, GetSharedImageCount());
 
   video_frame = CreateTestHardwareVideoFrame(
-      viz::MultiPlaneFormat::kNV12, PIXEL_FORMAT_NV12, GL_TEXTURE_EXTERNAL_OES,
-      /*needs_raster_access=*/false);
+      viz::MultiPlaneFormat::kNV12, PIXEL_FORMAT_NV12, GL_TEXTURE_EXTERNAL_OES);
 
   resource = updater->CreateExternalResourceFromVideoFrame(video_frame);
   EXPECT_EQ(VideoFrameResourceType::RGB, resource.type);
@@ -976,7 +965,7 @@
   EXPECT_EQ(0u, GetSharedImageCount());
   scoped_refptr<VideoFrame> video_frame = CreateTestHardwareVideoFrame(
       viz::MultiPlaneFormat::kP010, PIXEL_FORMAT_P010LE,
-      GL_TEXTURE_EXTERNAL_OES, /*needs_raster_access=*/false);
+      GL_TEXTURE_EXTERNAL_OES);
   video_frame->set_color_space(kHDR10ColorSpace);
   video_frame->set_hdr_metadata(hdr_metadata);
 
diff --git a/net/cookies/canonical_cookie.h b/net/cookies/canonical_cookie.h
index 6b417ef..bb6e56a 100644
--- a/net/cookies/canonical_cookie.h
+++ b/net/cookies/canonical_cookie.h
@@ -5,6 +5,7 @@
 #ifndef NET_COOKIES_CANONICAL_COOKIE_H_
 #define NET_COOKIES_CANONICAL_COOKIE_H_
 
+#include <compare>
 #include <memory>
 #include <optional>
 #include <string>
@@ -246,14 +247,16 @@
       CookieSourceType source_type = CookieSourceType::kUnknown,
       CookieInclusionStatus* status = nullptr);
 
-  bool operator<(const CanonicalCookie& other) const {
+  friend auto operator<=>(const CanonicalCookie& left,
+                          const CanonicalCookie& right) {
     // Use the cookie properties that uniquely identify a cookie to determine
     // ordering.
-    return RefUniqueKey() < other.RefUniqueKey();
+    return left.RefUniqueKey() <=> right.RefUniqueKey();
   }
 
-  bool operator==(const CanonicalCookie& other) const {
-    return IsEquivalent(other);
+  friend bool operator==(const CanonicalCookie& left,
+                         const CanonicalCookie& right) {
+    return left.RefUniqueKey() == right.RefUniqueKey();
   }
 
   // See CookieBase for other accessors.
diff --git a/net/disk_cache/entry_unittest.cc b/net/disk_cache/entry_unittest.cc
index 78227ed1..f96ce7f 100644
--- a/net/disk_cache/entry_unittest.cc
+++ b/net/disk_cache/entry_unittest.cc
@@ -83,6 +83,7 @@
   void DoomedEntry(int stream_index);
   void BasicSparseIO();
   void HugeSparseIO();
+  void LargeOffsetSparseIO();
   void GetAvailableRangeTest();
   void CouldBeSparse();
   void UpdateSparseEntry();
@@ -1616,6 +1617,38 @@
   HugeSparseIO();
 }
 
+void DiskCacheEntryTest::LargeOffsetSparseIO() {
+  std::string key("the first key");
+  disk_cache::Entry* entry;
+  ASSERT_THAT(CreateEntry(key, &entry), IsOk());
+
+  // Write 4 MB so that we cover multiple entries.
+  static constexpr size_t kSize = 4 * 1024 * 1024;
+
+  auto buf_1 = CacheTestCreateAndFillBuffer(kSize, false);
+  auto buf_2 = base::MakeRefCounted<net::IOBufferWithSize>(kSize);
+
+  // Write sparse data from 4GB - 2MB to 4GB + 2MB.
+  constexpr int64_t offset = 4LL * 1024 * 1024 * 1024 - 2 * 1024 * 1024;
+
+  VerifySparseIO(entry, offset, buf_1.get(), kSize, buf_2.get());
+  entry->Close();
+
+  // Check it again.
+  ASSERT_THAT(OpenEntry(key, &entry), IsOk());
+  VerifyContentSparseIO(entry, offset, buf_1->span());
+  entry->Close();
+}
+
+// The test only works on SimpleCache now since other backend does not support
+// 2GB+ offset for 32 bits architecture.
+// TODO(crbug.com/391398191): Expand the test target to all cache backend.
+TEST_F(DiskCacheEntryTest, SimpleCacheLargeOffsetSparseIO) {
+  SetBackendToTest(BackendToTest::kSimple);
+  InitCache();
+  LargeOffsetSparseIO();
+}
+
 void DiskCacheEntryTest::GetAvailableRangeTest() {
   std::string key("the first key");
   disk_cache::Entry* entry;
@@ -1698,6 +1731,45 @@
   GetAvailableRangeTest();
 }
 
+// The test only works on SimpleCache now since other backend does not support
+// 2GB+ offset for 32 bits architecture.
+// TODO(crbug.com/391398191): Expand the test target to all cache backend.
+TEST_F(DiskCacheEntryTest, SimpleCacheGetAvailableRangeForLargeOffset) {
+  SetBackendToTest(BackendToTest::kSimple);
+  InitCache();
+
+  std::string key("the first key");
+  disk_cache::Entry* entry;
+  ASSERT_THAT(CreateEntry(key, &entry), IsOk());
+
+  // Write 4 MB so that we cover multiple entries.
+  static constexpr size_t kSize = 4 * 1024 * 1024;
+  auto buf = CacheTestCreateAndFillBuffer(kSize, false);
+
+  // Write sparse data from 4GB - 2MB to 4GB + 2MB.
+  constexpr int64_t offset = 4LL * 1024 * 1024 * 1024 - 2 * 1024 * 1024;
+
+  EXPECT_EQ(kSize, WriteSparseData(entry, offset, buf.get(), kSize));
+
+  TestRangeResultCompletionCallback cb;
+  RangeResult result =
+      cb.GetResult(entry->GetAvailableRange(offset, kSize * 2, cb.callback()));
+  EXPECT_EQ(net::OK, result.net_error);
+  EXPECT_EQ(kSize, result.available_len);
+  EXPECT_EQ(offset, result.start);
+
+  result = cb.GetResult(entry->GetAvailableRange(0, kSize, cb.callback()));
+  EXPECT_EQ(net::OK, result.net_error);
+  EXPECT_EQ(0, result.available_len);
+
+  result = cb.GetResult(
+      entry->GetAvailableRange(offset - kSize, kSize, cb.callback()));
+  EXPECT_EQ(net::OK, result.net_error);
+  EXPECT_EQ(0, result.available_len);
+
+  entry->Close();
+}
+
 TEST_F(DiskCacheEntryTest, GetAvailableRangeBlockFileDiscontinuous) {
   // crbug.com/791056 --- blockfile problem when there is a sub-KiB write before
   // a bunch of full 1KiB blocks, and a GetAvailableRange is issued to which
diff --git a/net/disk_cache/simple/simple_entry_format.h b/net/disk_cache/simple/simple_entry_format.h
index 4d4472d..01a7a35 100644
--- a/net/disk_cache/simple/simple_entry_format.h
+++ b/net/disk_cache/simple/simple_entry_format.h
@@ -87,8 +87,11 @@
   SimpleFileSparseRangeHeader();
 
   uint64_t sparse_range_magic_number = 0;
-  int64_t offset = 0;
-  int64_t length = 0;
+  uint64_t offset = 0;
+
+  // `length` must be size-fixed to avoid padding, so using uint64_t instead of
+  // size_t.
+  uint64_t length = 0;
   uint32_t data_crc32 = 0;
 
   // Avoid implicit padding so `std::has_unique_object_representations_v<>` will
diff --git a/net/disk_cache/simple/simple_entry_impl.cc b/net/disk_cache/simple/simple_entry_impl.cc
index 641141a..6acab98e 100644
--- a/net/disk_cache/simple/simple_entry_impl.cc
+++ b/net/disk_cache/simple/simple_entry_impl.cc
@@ -519,15 +519,16 @@
     return net::ERR_INVALID_ARGUMENT;
   }
 
-  // Truncate |buf_len| to make sure that |offset + buf_len| does not overflow.
+  // Truncate `buf_len` to make sure that `offset + buf_len` does not overflow.
   // This is OK since one can't write that far anyway.
-  // The result of std::min is guaranteed to fit into int since |buf_len| did.
-  buf_len = std::min(static_cast<int64_t>(buf_len),
-                     std::numeric_limits<int64_t>::max() - offset);
+  // The result of std::min is guaranteed to fit into size_t since `buf_len`
+  // did.
+  size_t length = std::min(static_cast<int64_t>(buf_len),
+                           std::numeric_limits<int64_t>::max() - offset);
 
   ScopedOperationRunner operation_runner(this);
   pending_operations_.push(SimpleEntryOperation::ReadSparseOperation(
-      this, offset, buf_len, buf, std::move(callback)));
+      this, static_cast<uint64_t>(offset), length, buf, std::move(callback)));
   return net::ERR_IO_PENDING;
 }
 
@@ -554,7 +555,8 @@
 
   ScopedOperationRunner operation_runner(this);
   pending_operations_.push(SimpleEntryOperation::WriteSparseOperation(
-      this, offset, buf_len, buf, std::move(callback)));
+      this, static_cast<uint64_t>(offset), static_cast<size_t>(buf_len), buf,
+      std::move(callback)));
   return net::ERR_IO_PENDING;
 }
 
@@ -565,15 +567,16 @@
   if (offset < 0 || len < 0)
     return RangeResult(net::ERR_INVALID_ARGUMENT);
 
-  // Truncate |len| to make sure that |offset + len| does not overflow.
+  // Truncate `buf_len` to make sure that `offset + buf_len` does not overflow.
   // This is OK since one can't write that far anyway.
-  // The result of std::min is guaranteed to fit into int since |len| did.
-  len = std::min(static_cast<int64_t>(len),
-                 std::numeric_limits<int64_t>::max() - offset);
+  // The result of std::min is guaranteed to fit into size_t since `buf_len`
+  // did.
+  size_t length = std::min(static_cast<int64_t>(len),
+                           std::numeric_limits<int64_t>::max() - offset);
 
   ScopedOperationRunner operation_runner(this);
   pending_operations_.push(SimpleEntryOperation::GetAvailableRangeOperation(
-      this, offset, len, std::move(callback)));
+      this, static_cast<uint64_t>(offset), length, std::move(callback)));
   return RangeResult(net::ERR_IO_PENDING);
 }
 
@@ -736,15 +739,17 @@
         break;
       case SimpleEntryOperation::TYPE_READ_SPARSE:
         ReadSparseDataInternal(operation.sparse_offset(), operation.buf(),
-                               operation.length(), operation.ReleaseCallback());
+                               operation.sparse_length(),
+                               operation.ReleaseCallback());
         break;
       case SimpleEntryOperation::TYPE_WRITE_SPARSE:
         WriteSparseDataInternal(operation.sparse_offset(), operation.buf(),
-                                operation.length(),
+                                operation.sparse_length(),
                                 operation.ReleaseCallback());
         break;
       case SimpleEntryOperation::TYPE_GET_AVAILABLE_RANGE:
-        GetAvailableRangeInternal(operation.sparse_offset(), operation.length(),
+        GetAvailableRangeInternal(operation.sparse_offset(),
+                                  operation.sparse_length(),
                                   operation.ReleaseRangeResultCalback());
         break;
       case SimpleEntryOperation::TYPE_DOOM:
diff --git a/net/disk_cache/simple/simple_entry_impl.h b/net/disk_cache/simple/simple_entry_impl.h
index e65ac2b..a345e63 100644
--- a/net/disk_cache/simple/simple_entry_impl.h
+++ b/net/disk_cache/simple/simple_entry_impl.h
@@ -383,7 +383,7 @@
   // TODO(clamy): Unify last_used_ with data in the index.
   base::Time last_used_;
   std::array<int32_t, kSimpleEntryStreamCount> data_size_;
-  int32_t sparse_data_size_ = 0;
+  uint64_t sparse_data_size_ = 0;
 
   // Number of times this object has been returned from Backend::OpenEntry() and
   // Backend::CreateEntry() without subsequent Entry::Close() calls. Used to
diff --git a/net/disk_cache/simple/simple_entry_operation.cc b/net/disk_cache/simple/simple_entry_operation.cc
index c0c23ae..497f3e3 100644
--- a/net/disk_cache/simple/simple_entry_operation.cc
+++ b/net/disk_cache/simple/simple_entry_operation.cc
@@ -22,7 +22,7 @@
     SimpleEntryImpl* entry,
     EntryResultState result_state,
     EntryResultCallback callback) {
-  SimpleEntryOperation op(entry, nullptr, CompletionOnceCallback(), 0, 0, 0,
+  SimpleEntryOperation op(entry, nullptr, CompletionOnceCallback(), 0, 0, 0, 0,
                           TYPE_OPEN, INDEX_NOEXIST, 0, false, false);
   op.entry_callback_ = std::move(callback);
   op.entry_result_state_ = result_state;
@@ -34,7 +34,7 @@
     SimpleEntryImpl* entry,
     EntryResultState result_state,
     EntryResultCallback callback) {
-  SimpleEntryOperation op(entry, nullptr, CompletionOnceCallback(), 0, 0, 0,
+  SimpleEntryOperation op(entry, nullptr, CompletionOnceCallback(), 0, 0, 0, 0,
                           TYPE_CREATE, INDEX_NOEXIST, 0, false, false);
   op.entry_callback_ = std::move(callback);
   op.entry_result_state_ = result_state;
@@ -47,7 +47,7 @@
     OpenEntryIndexEnum index_state,
     EntryResultState result_state,
     EntryResultCallback callback) {
-  SimpleEntryOperation op(entry, nullptr, CompletionOnceCallback(), 0, 0, 0,
+  SimpleEntryOperation op(entry, nullptr, CompletionOnceCallback(), 0, 0, 0, 0,
                           TYPE_OPEN_OR_CREATE, index_state, 0, false, false);
   op.entry_callback_ = std::move(callback);
   op.entry_result_state_ = result_state;
@@ -58,7 +58,7 @@
 SimpleEntryOperation SimpleEntryOperation::CloseOperation(
     SimpleEntryImpl* entry) {
   return SimpleEntryOperation(entry, nullptr, CompletionOnceCallback(), 0, 0, 0,
-                              TYPE_CLOSE, INDEX_NOEXIST, 0, false, false);
+                              0, TYPE_CLOSE, INDEX_NOEXIST, 0, false, false);
 }
 
 // static
@@ -70,7 +70,7 @@
     net::IOBuffer* buf,
     CompletionOnceCallback callback) {
   return SimpleEntryOperation(entry, buf, std::move(callback), offset, 0,
-                              length, TYPE_READ, INDEX_NOEXIST, index, false,
+                              length, 0, TYPE_READ, INDEX_NOEXIST, index, false,
                               false);
 }
 
@@ -85,43 +85,43 @@
     bool optimistic,
     CompletionOnceCallback callback) {
   return SimpleEntryOperation(entry, buf, std::move(callback), offset, 0,
-                              length, TYPE_WRITE, INDEX_NOEXIST, index,
+                              length, 0, TYPE_WRITE, INDEX_NOEXIST, index,
                               truncate, optimistic);
 }
 
 // static
 SimpleEntryOperation SimpleEntryOperation::ReadSparseOperation(
     SimpleEntryImpl* entry,
-    int64_t sparse_offset,
-    int length,
+    uint64_t sparse_offset,
+    size_t sparse_length,
     net::IOBuffer* buf,
     CompletionOnceCallback callback) {
   return SimpleEntryOperation(entry, buf, std::move(callback), 0, sparse_offset,
-                              length, TYPE_READ_SPARSE, INDEX_NOEXIST, 0, false,
-                              false);
+                              0, sparse_length, TYPE_READ_SPARSE, INDEX_NOEXIST,
+                              0, false, false);
 }
 
 // static
 SimpleEntryOperation SimpleEntryOperation::WriteSparseOperation(
     SimpleEntryImpl* entry,
-    int64_t sparse_offset,
-    int length,
+    uint64_t sparse_offset,
+    size_t sparse_length,
     net::IOBuffer* buf,
     CompletionOnceCallback callback) {
   return SimpleEntryOperation(entry, buf, std::move(callback), 0, sparse_offset,
-                              length, TYPE_WRITE_SPARSE, INDEX_NOEXIST, 0,
-                              false, false);
+                              0, sparse_length, TYPE_WRITE_SPARSE,
+                              INDEX_NOEXIST, 0, false, false);
 }
 
 // static
 SimpleEntryOperation SimpleEntryOperation::GetAvailableRangeOperation(
     SimpleEntryImpl* entry,
-    int64_t sparse_offset,
-    int length,
+    uint64_t sparse_offset,
+    size_t sparse_length,
     RangeResultCallback callback) {
-  SimpleEntryOperation op(entry, nullptr, CompletionOnceCallback(), 0,
-                          sparse_offset, length, TYPE_GET_AVAILABLE_RANGE,
-                          INDEX_NOEXIST, 0, false, false);
+  SimpleEntryOperation op(
+      entry, nullptr, CompletionOnceCallback(), 0, sparse_offset, 0,
+      sparse_length, TYPE_GET_AVAILABLE_RANGE, INDEX_NOEXIST, 0, false, false);
   op.range_callback_ = std::move(callback);
   return op;
 }
@@ -132,23 +132,25 @@
     net::CompletionOnceCallback callback) {
   net::IOBuffer* const buf = nullptr;
   const int offset = 0;
-  const int64_t sparse_offset = 0;
+  const uint64_t sparse_offset = 0;
   const int length = 0;
+  const size_t sparse_length = 0;
   const OpenEntryIndexEnum index_state = INDEX_NOEXIST;
   const int index = 0;
   const bool truncate = false;
   const bool optimistic = false;
   return SimpleEntryOperation(entry, buf, std::move(callback), offset,
-                              sparse_offset, length, TYPE_DOOM, index_state,
-                              index, truncate, optimistic);
+                              sparse_offset, length, sparse_length, TYPE_DOOM,
+                              index_state, index, truncate, optimistic);
 }
 
 SimpleEntryOperation::SimpleEntryOperation(SimpleEntryImpl* entry,
                                            net::IOBuffer* buf,
                                            net::CompletionOnceCallback callback,
                                            int offset,
-                                           int64_t sparse_offset,
+                                           uint64_t sparse_offset,
                                            int length,
+                                           size_t sparse_length,
                                            EntryOperationType type,
                                            OpenEntryIndexEnum index_state,
                                            int index,
@@ -160,6 +162,7 @@
       offset_(offset),
       sparse_offset_(sparse_offset),
       length_(length),
+      sparse_length_(sparse_length),
       type_(type),
       index_state_(index_state),
       index_(index),
diff --git a/net/disk_cache/simple/simple_entry_operation.h b/net/disk_cache/simple/simple_entry_operation.h
index 63ae3dac..0f034f7c 100644
--- a/net/disk_cache/simple/simple_entry_operation.h
+++ b/net/disk_cache/simple/simple_entry_operation.h
@@ -78,20 +78,20 @@
                                              CompletionOnceCallback callback);
   static SimpleEntryOperation ReadSparseOperation(
       SimpleEntryImpl* entry,
-      int64_t sparse_offset,
-      int length,
+      uint64_t sparse_offset,
+      size_t sparse_length,
       net::IOBuffer* buf,
       CompletionOnceCallback callback);
   static SimpleEntryOperation WriteSparseOperation(
       SimpleEntryImpl* entry,
-      int64_t sparse_offset,
-      int length,
+      uint64_t sparse_offset,
+      size_t sparse_length,
       net::IOBuffer* buf,
       CompletionOnceCallback callback);
   static SimpleEntryOperation GetAvailableRangeOperation(
       SimpleEntryImpl* entry,
-      int64_t sparse_offset,
-      int length,
+      uint64_t sparse_offset,
+      size_t sparse_length,
       RangeResultCallback callback);
   static SimpleEntryOperation DoomOperation(SimpleEntryImpl* entry,
                                             CompletionOnceCallback callback);
@@ -114,6 +114,7 @@
   int offset() const { return offset_; }
   int64_t sparse_offset() const { return sparse_offset_; }
   int length() const { return length_; }
+  size_t sparse_length() const { return sparse_length_; }
   net::IOBuffer* buf() { return buf_.get(); }
   bool truncate() const { return truncate_; }
   bool optimistic() const { return optimistic_; }
@@ -123,8 +124,9 @@
                        net::IOBuffer* buf,
                        CompletionOnceCallback callback,
                        int offset,
-                       int64_t sparse_offset,
+                       uint64_t sparse_offset,
                        int length,
+                       size_t sparse_length,
                        EntryOperationType type,
                        OpenEntryIndexEnum index_state,
                        int index,
@@ -144,6 +146,7 @@
   const int offset_;
   const int64_t sparse_offset_;
   const int length_;
+  const size_t sparse_length_;
 
   // Used in get available range operations.
   RangeResultCallback range_callback_;
diff --git a/net/disk_cache/simple/simple_synchronous_entry.cc b/net/disk_cache/simple/simple_synchronous_entry.cc
index 7b0b4c2..bf7db72 100644
--- a/net/disk_cache/simple/simple_synchronous_entry.cc
+++ b/net/disk_cache/simple/simple_synchronous_entry.cc
@@ -237,7 +237,7 @@
 SimpleEntryStat::SimpleEntryStat(
     base::Time last_used,
     const std::array<int32_t, kSimpleEntryStreamCount>& data_size,
-    const int32_t sparse_data_size)
+    const uint64_t sparse_data_size)
     : last_used_(last_used),
       data_size_(data_size),
       sparse_data_size_(sparse_data_size) {}
@@ -325,8 +325,8 @@
       doomed(doomed_p),
       request_update_crc(request_update_crc_p) {}
 
-SimpleSynchronousEntry::SparseRequest::SparseRequest(int64_t sparse_offset_p,
-                                                     int buf_len_p)
+SimpleSynchronousEntry::SparseRequest::SparseRequest(uint64_t sparse_offset_p,
+                                                     size_t buf_len_p)
     : sparse_offset(sparse_offset_p), buf_len(buf_len_p) {}
 
 // static
@@ -758,11 +758,10 @@
   DCHECK(initialized_);
   BackendFileOperations* file_operations = nullptr;
   ScopedFileOperationsBinding binding(this, &file_operations);
-  int64_t offset = in_entry_op.sparse_offset;
-  int buf_len = in_entry_op.buf_len;
+  uint64_t offset = in_entry_op.sparse_offset;
+  size_t buf_len = in_entry_op.buf_len;
 
   base::span<uint8_t> buf = out_buf->span();
-  int read_so_far = 0;
 
   if (!sparse_file_open() || !buf_len) {
     *out_result = 0;
@@ -777,6 +776,8 @@
     return;
   }
 
+  size_t read_so_far = 0;
+
   // Find the first sparse range at or after the requested offset.
   auto it = sparse_ranges_.lower_bound(offset);
 
@@ -784,20 +785,18 @@
     // Hop back one range and read the one overlapping with the start.
     --it;
     SparseRange* found_range = &it->second;
-    DCHECK_EQ(it->first, found_range->offset);
-    if (found_range->offset + found_range->length > offset) {
-      DCHECK_GE(found_range->length, 0);
-      DCHECK_LE(found_range->length, std::numeric_limits<int32_t>::max());
-      DCHECK_GE(offset - found_range->offset, 0);
-      DCHECK_LE(offset - found_range->offset,
-                std::numeric_limits<int32_t>::max());
-      int net_offset = static_cast<int>(offset - found_range->offset);
-      int range_len_after_offset =
-          static_cast<int>(found_range->length - net_offset);
-      DCHECK_GE(range_len_after_offset, 0);
+    CHECK_EQ(it->first, found_range->offset);
 
-      int len_to_read = std::min(buf_len, range_len_after_offset);
-      if (!ReadSparseRange(sparse_file.get(), found_range, net_offset,
+    CHECK(base::CheckAdd(found_range->offset, found_range->length).IsValid());
+    if (found_range->offset + found_range->length > offset) {
+      CHECK_LE(offset - found_range->offset,
+               std::numeric_limits<size_t>::max());
+      size_t offset_in_range =
+          base::checked_cast<size_t>(offset - found_range->offset);
+      size_t range_len_after_offset = found_range->length - offset_in_range;
+
+      size_t len_to_read = std::min(buf_len, range_len_after_offset);
+      if (!ReadSparseRange(sparse_file.get(), found_range, offset_in_range,
                            len_to_read, buf)) {
         DoomInternal(file_operations);
         *out_result = net::ERR_CACHE_READ_FAILURE;
@@ -810,25 +809,27 @@
 
   // Keep reading until the buffer is full or there is not another contiguous
   // range.
-  while (read_so_far < buf_len &&
-         it != sparse_ranges_.end() &&
+  while (read_so_far < buf_len && it != sparse_ranges_.end() &&
          it->second.offset == offset + read_so_far) {
     SparseRange* found_range = &it->second;
-    DCHECK_EQ(it->first, found_range->offset);
-    int range_len = base::saturated_cast<int>(found_range->length);
-    int len_to_read = std::min(buf_len - read_so_far, range_len);
-    if (!ReadSparseRange(
-            sparse_file.get(), found_range, 0, len_to_read,
-            buf.subspan(base::checked_cast<size_t>(read_so_far)))) {
+    CHECK_EQ(it->first, found_range->offset);
+    size_t range_len = found_range->length;
+    size_t len_to_read = std::min(buf_len - read_so_far, range_len);
+    if (!ReadSparseRange(sparse_file.get(), found_range, 0, len_to_read,
+                         buf.subspan(read_so_far))) {
       DoomInternal(file_operations);
       *out_result = net::ERR_CACHE_READ_FAILURE;
       return;
     }
+
     read_so_far += len_to_read;
+
     ++it;
   }
 
-  *out_result = read_so_far;
+  // The length to read is limited to each sparse data which is far smaller than
+  // int max.
+  *out_result = base::checked_cast<int>(read_so_far);
 }
 
 void SimpleSynchronousEntry::WriteSparseData(const SparseRequest& in_entry_op,
@@ -839,12 +840,10 @@
   DCHECK(initialized_);
   BackendFileOperations* file_operations = nullptr;
   ScopedFileOperationsBinding binding(this, &file_operations);
-  int64_t offset = in_entry_op.sparse_offset;
-  int buf_len = in_entry_op.buf_len;
+  uint64_t offset = in_entry_op.sparse_offset;
+  size_t buf_len = in_entry_op.buf_len;
 
   base::span<const uint8_t> buf = in_buf->span();
-  int written_so_far = 0;
-  int appended_so_far = 0;
 
   if (!sparse_file_open() && !CreateSparseFile(file_operations)) {
     DoomInternal(file_operations);
@@ -859,42 +858,42 @@
     return;
   }
 
-  int32_t sparse_data_size = out_entry_stat->sparse_data_size();
-  int32_t future_sparse_data_size;
+  uint64_t sparse_data_size = out_entry_stat->sparse_data_size();
+  uint64_t future_sparse_data_size;
   if (!base::CheckAdd(sparse_data_size, buf_len)
-           .AssignIfValid(&future_sparse_data_size) ||
-      future_sparse_data_size < 0) {
+           .AssignIfValid(&future_sparse_data_size)) {
     DoomInternal(file_operations);
     *out_result = net::ERR_CACHE_WRITE_FAILURE;
     return;
   }
   // This is a pessimistic estimate; it assumes the entire buffer is going to
   // be appended as a new range, not written over existing ranges.
-  if (static_cast<uint64_t>(future_sparse_data_size) > max_sparse_data_size) {
+  if (future_sparse_data_size > max_sparse_data_size) {
     DVLOG(1) << "Truncating sparse data file (" << sparse_data_size << " + "
              << buf_len << " > " << max_sparse_data_size << ")";
     TruncateSparseFile(sparse_file.get());
-    out_entry_stat->set_sparse_data_size(0);
+    out_entry_stat->set_sparse_data_size(0u);
   }
 
+  size_t written_so_far = 0;
+  size_t appended_so_far = 0;
+
   auto it = sparse_ranges_.lower_bound(offset);
 
   if (it != sparse_ranges_.begin()) {
     --it;
     SparseRange* found_range = &it->second;
-    if (found_range->offset + found_range->length > offset) {
-      DCHECK_GE(found_range->length, 0);
-      DCHECK_LE(found_range->length, std::numeric_limits<int32_t>::max());
-      DCHECK_GE(offset - found_range->offset, 0);
-      DCHECK_LE(offset - found_range->offset,
-                std::numeric_limits<int32_t>::max());
-      int net_offset = static_cast<int>(offset - found_range->offset);
-      int range_len_after_offset =
-          static_cast<int>(found_range->length - net_offset);
-      DCHECK_GE(range_len_after_offset, 0);
 
-      int len_to_write = std::min(buf_len, range_len_after_offset);
-      if (!WriteSparseRange(sparse_file.get(), found_range, net_offset,
+    CHECK(base::CheckAdd(found_range->offset, found_range->length).IsValid());
+    if (found_range->offset + found_range->length > offset) {
+      CHECK_LE(offset - found_range->offset,
+               std::numeric_limits<size_t>::max());
+      size_t offset_in_range =
+          static_cast<size_t>(offset - found_range->offset);
+      size_t range_len_after_offset = found_range->length - offset_in_range;
+
+      size_t len_to_write = std::min(buf_len, range_len_after_offset);
+      if (!WriteSparseRange(sparse_file.get(), found_range, offset_in_range,
                             len_to_write, buf)) {
         DoomInternal(file_operations);
         *out_result = net::ERR_CACHE_WRITE_FAILURE;
@@ -905,41 +904,40 @@
     ++it;
   }
 
-  while (written_so_far < buf_len &&
-         it != sparse_ranges_.end() &&
+  while (written_so_far < buf_len && it != sparse_ranges_.end() &&
          it->second.offset < offset + buf_len) {
     SparseRange* found_range = &it->second;
     if (offset + written_so_far < found_range->offset) {
-      int len_to_append =
-          static_cast<int>(found_range->offset - (offset + written_so_far));
-      if (!AppendSparseRange(
-              sparse_file.get(), offset + written_so_far, len_to_append,
-              buf.subspan(base::checked_cast<size_t>(written_so_far)))) {
+      size_t len_to_append =
+          static_cast<size_t>(found_range->offset - (offset + written_so_far));
+      if (!AppendSparseRange(sparse_file.get(), offset + written_so_far,
+                             len_to_append, buf.subspan(written_so_far))) {
         DoomInternal(file_operations);
         *out_result = net::ERR_CACHE_WRITE_FAILURE;
         return;
       }
+
       written_so_far += len_to_append;
       appended_so_far += len_to_append;
     }
-    int range_len = base::saturated_cast<int>(found_range->length);
-    int len_to_write = std::min(buf_len - written_so_far, range_len);
-    if (!WriteSparseRange(
-            sparse_file.get(), found_range, 0, len_to_write,
-            buf.subspan(base::checked_cast<size_t>(written_so_far)))) {
+
+    size_t len_to_write =
+        std::min(buf_len - written_so_far, found_range->length);
+    if (!WriteSparseRange(sparse_file.get(), found_range, 0, len_to_write,
+                          buf.subspan(written_so_far))) {
       DoomInternal(file_operations);
       *out_result = net::ERR_CACHE_WRITE_FAILURE;
       return;
     }
+
     written_so_far += len_to_write;
     ++it;
   }
 
   if (written_so_far < buf_len) {
-    int len_to_append = buf_len - written_so_far;
-    if (!AppendSparseRange(
-            sparse_file.get(), offset + written_so_far, len_to_append,
-            buf.subspan(base::checked_cast<size_t>(written_so_far)))) {
+    size_t len_to_append = buf_len - written_so_far;
+    if (!AppendSparseRange(sparse_file.get(), offset + written_so_far,
+                           len_to_append, buf.subspan(written_so_far))) {
       DoomInternal(file_operations);
       *out_result = net::ERR_CACHE_WRITE_FAILURE;
       return;
@@ -948,28 +946,32 @@
     appended_so_far += len_to_append;
   }
 
-  DCHECK_EQ(buf_len, written_so_far);
+  CHECK_EQ(buf_len, written_so_far);
 
   base::Time modification_time = Time::Now();
   out_entry_stat->set_last_used(modification_time);
-  int32_t old_sparse_data_size = out_entry_stat->sparse_data_size();
+  uint64_t old_sparse_data_size = out_entry_stat->sparse_data_size();
   out_entry_stat->set_sparse_data_size(old_sparse_data_size + appended_so_far);
-  *out_result = written_so_far;
+
+  // The length to read is limited to each sparse data which is far smaller than
+  // int max.
+  *out_result = base::checked_cast<int>(written_so_far);
 }
 
 void SimpleSynchronousEntry::GetAvailableRange(const SparseRequest& in_entry_op,
                                                RangeResult* out_result) {
   DCHECK(initialized_);
-  int64_t offset = in_entry_op.sparse_offset;
-  int len = in_entry_op.buf_len;
+  uint64_t offset = in_entry_op.sparse_offset;
+  size_t len = in_entry_op.buf_len;
 
   auto it = sparse_ranges_.lower_bound(offset);
 
-  int64_t start = offset;
-  int64_t avail_so_far = 0;
+  uint64_t start = offset;
+  uint64_t avail_so_far = 0;
 
-  if (it != sparse_ranges_.end() && it->second.offset < offset + len)
+  if (it != sparse_ranges_.end() && it->second.offset < offset + len) {
     start = it->second.offset;
+  }
 
   if ((it == sparse_ranges_.end() || it->second.offset > offset) &&
       it != sparse_ranges_.begin()) {
@@ -988,9 +990,13 @@
     ++it;
   }
 
-  int64_t len_from_start = len - (start - offset);
-  *out_result = RangeResult(
-      start, static_cast<int>(std::min(avail_so_far, len_from_start)));
+  // `range_len` must fit in size_t since it's guaranteed to be same or smaller
+  // than `len - (start - offset)` where `len` is within size_t range and
+  // `start` is same or larger than `offset`.
+  size_t range_len = base::checked_cast<size_t>(
+      std::min(avail_so_far, len - (start - offset)));
+
+  *out_result = RangeResult(start, range_len);
 }
 
 int SimpleSynchronousEntry::CheckEOFRecord(
@@ -1505,7 +1511,7 @@
     }
   }
 
-  int32_t sparse_data_size = 0;
+  uint64_t sparse_data_size = 0u;
   if (!OpenSparseFileIfExists(file_operations, &sparse_data_size)) {
     RecordSyncOpenResult(cache_type_, OPEN_ENTRY_SPARSE_OPEN_FAILED);
     return net::ERR_FAILED;
@@ -1839,7 +1845,7 @@
 
 bool SimpleSynchronousEntry::OpenSparseFileIfExists(
     BackendFileOperations* file_operations,
-    int32_t* out_sparse_data_size) {
+    uint64_t* out_sparse_data_size) {
   DCHECK(!sparse_file_open());
 
   FilePath filename =
@@ -1896,7 +1902,7 @@
 bool SimpleSynchronousEntry::TruncateSparseFile(base::File* sparse_file) {
   DCHECK(sparse_file_open());
 
-  int64_t header_and_key_length = sizeof(SimpleFileHeader) + key_->size();
+  uint64_t header_and_key_length = sizeof(SimpleFileHeader) + key_->size();
   if (!sparse_file->SetLength(header_and_key_length)) {
     DLOG(WARNING) << "Could not truncate sparse file";
     return false;
@@ -1933,8 +1939,8 @@
 }
 
 bool SimpleSynchronousEntry::ScanSparseFile(base::File* sparse_file,
-                                            int32_t* out_sparse_data_size) {
-  int64_t sparse_data_size = 0;
+                                            uint64_t* out_sparse_data_size) {
+  uint64_t sparse_data_size = 0;
 
   SimpleFileHeader header;
   if (!sparse_file->ReadAndCheck(0, base::byte_span_from_ref(header))) {
@@ -1954,7 +1960,7 @@
 
   sparse_ranges_.clear();
 
-  int64_t range_header_offset = sizeof(header) + key_->size();
+  uint64_t range_header_offset = sizeof(header) + key_->size();
   while (true) {
     SimpleFileSparseRangeHeader range_header;
     std::optional<size_t> range_header_read_result = sparse_file->Read(
@@ -1974,20 +1980,29 @@
       return false;
     }
 
+    if (range_header.length > std::numeric_limits<size_t>::max()) {
+      DLOG(WARNING) << "Too long sparse range length.";
+      return false;
+    }
+
+    if (!base::CheckAdd(range_header.offset, range_header.length).IsValid()) {
+      DLOG(WARNING) << "Too large sparse range tail.";
+      return false;
+    }
+
     SparseRange range;
     range.offset = range_header.offset;
-    range.length = range_header.length;
+    range.length = static_cast<size_t>(range_header.length);
     range.data_crc32 = range_header.data_crc32;
     range.file_offset = range_header_offset + sizeof(range_header);
     sparse_ranges_.emplace(range.offset, range);
 
     range_header_offset += sizeof(range_header) + range.length;
 
-    DCHECK_GE(sparse_data_size + range.length, sparse_data_size);
     sparse_data_size += range.length;
   }
 
-  *out_sparse_data_size = static_cast<int32_t>(sparse_data_size);
+  *out_sparse_data_size = sparse_data_size;
   sparse_tail_offset_ = range_header_offset;
 
   return true;
@@ -1995,23 +2010,23 @@
 
 bool SimpleSynchronousEntry::ReadSparseRange(base::File* sparse_file,
                                              const SparseRange* range,
-                                             size_t offset,
+                                             size_t offset_in_range,
                                              size_t len,
                                              base::span<uint8_t> buf) {
-  DCHECK(range);
-  DCHECK_LE(static_cast<int64_t>(offset), range->length);
-  DCHECK_LE(static_cast<int64_t>(offset + len), range->length);
+  CHECK(range);
+  CHECK_LE(offset_in_range, range->length);
+  CHECK_LE(offset_in_range + len, range->length);
 
-  bool bytes_read_ok = sparse_file->ReadAndCheck(
-      range->file_offset + offset, buf.first(base::checked_cast<size_t>(len)));
+  bool bytes_read_ok =
+      sparse_file->ReadAndCheck(range->file_offset + offset_in_range,
+                                buf.first(base::checked_cast<size_t>(len)));
   if (!bytes_read_ok) {
     DLOG(WARNING) << "Could not read sparse range.";
     return false;
   }
 
   // If we read the whole range and we have a crc32, check it.
-  if (offset == 0 && static_cast<int64_t>(len) == range->length &&
-      range->data_crc32 != 0) {
+  if (offset_in_range == 0 && len == range->length && range->data_crc32 != 0) {
     if (simple_util::Crc32(buf.first(len)) != range->data_crc32) {
       DLOG(WARNING) << "Sparse range crc32 mismatch.";
       return false;
@@ -2024,15 +2039,15 @@
 
 bool SimpleSynchronousEntry::WriteSparseRange(base::File* sparse_file,
                                               SparseRange* range,
-                                              size_t offset,
+                                              size_t offset_in_range,
                                               size_t len,
                                               base::span<const uint8_t> buf) {
-  DCHECK(range);
-  DCHECK_LE(static_cast<int64_t>(offset), range->length);
-  DCHECK_LE(static_cast<int64_t>(offset + len), range->length);
+  CHECK(range);
+  CHECK_LE(offset_in_range, range->length);
+  CHECK_LE(offset_in_range + len, range->length);
 
   uint32_t new_crc32 = 0;
-  if (offset == 0 && static_cast<int64_t>(len) == range->length) {
+  if (offset_in_range == 0 && len == range->length) {
     new_crc32 = simple_util::Crc32(buf.first(len));
   }
 
@@ -2053,8 +2068,8 @@
     }
   }
 
-  bool bytes_written_ok =
-      sparse_file->WriteAndCheck(range->file_offset + offset, buf.first(len));
+  bool bytes_written_ok = sparse_file->WriteAndCheck(
+      range->file_offset + offset_in_range, buf.first(len));
   if (!bytes_written_ok) {
     DLOG(WARNING) << "Could not write sparse range.";
     return false;
@@ -2064,10 +2079,9 @@
 }
 
 bool SimpleSynchronousEntry::AppendSparseRange(base::File* sparse_file,
-                                               int64_t offset,
+                                               uint64_t offset,
                                                size_t len,
                                                base::span<const uint8_t> buf) {
-  DCHECK_GE(offset, 0);
   DCHECK_NE(len, 0u);
 
   uint32_t data_crc32 = simple_util::Crc32(buf.first(len));
@@ -2091,7 +2105,7 @@
     DLOG(WARNING) << "Could not append sparse range data.";
     return false;
   }
-  int64_t data_file_offset = sparse_tail_offset_;
+  uint64_t data_file_offset = sparse_tail_offset_;
   sparse_tail_offset_ += *bytes_written;
 
   SparseRange range;
diff --git a/net/disk_cache/simple/simple_synchronous_entry.h b/net/disk_cache/simple/simple_synchronous_entry.h
index 578c165..db62f7b 100644
--- a/net/disk_cache/simple/simple_synchronous_entry.h
+++ b/net/disk_cache/simple/simple_synchronous_entry.h
@@ -61,7 +61,7 @@
  public:
   SimpleEntryStat(base::Time last_used,
                   const std::array<int32_t, kSimpleEntryStreamCount>& data_size,
-                  const int32_t sparse_data_size);
+                  const uint64_t sparse_data_size);
 
   int GetOffsetInFile(size_t key_length, int offset, int stream_index) const;
   int GetEOFOffsetInFile(size_t key_length, int stream_index) const;
@@ -76,15 +76,15 @@
     data_size_[stream_index] = data_size;
   }
 
-  int32_t sparse_data_size() const { return sparse_data_size_; }
-  void set_sparse_data_size(int32_t sparse_data_size) {
+  uint64_t sparse_data_size() const { return sparse_data_size_; }
+  void set_sparse_data_size(uint64_t sparse_data_size) {
     sparse_data_size_ = sparse_data_size;
   }
 
  private:
   base::Time last_used_;
   std::array<int32_t, kSimpleEntryStreamCount> data_size_;
-  int32_t sparse_data_size_;
+  uint64_t sparse_data_size_;
 };
 
 struct SimpleStreamPrefetchData {
@@ -176,10 +176,10 @@
   };
 
   struct SparseRequest {
-    SparseRequest(int64_t sparse_offset_p, int buf_len_p);
+    SparseRequest(uint64_t sparse_offset_p, size_t buf_len_p);
 
-    int64_t sparse_offset;
-    int buf_len;
+    uint64_t sparse_offset;
+    size_t buf_len;
   };
 
   NET_EXPORT_PRIVATE SimpleSynchronousEntry(
@@ -324,8 +324,8 @@
   };
 
   struct SparseRange {
-    int64_t offset;
-    int64_t length;
+    uint64_t offset;
+    size_t length;
     uint32_t data_crc32;
     int64_t file_offset;
 
@@ -426,7 +426,7 @@
 
   // Opens the sparse data file and scans it if it exists.
   bool OpenSparseFileIfExists(BackendFileOperations* file_operations,
-                              int32_t* out_sparse_data_size);
+                              uint64_t* out_sparse_data_size);
 
   // Creates and initializes the sparse data file.
   bool CreateSparseFile(BackendFileOperations* file_operations);
@@ -440,16 +440,16 @@
   // Removes all but the header of the sparse file.
   bool TruncateSparseFile(base::File* sparse_file);
 
-  // Scans the existing ranges in the sparse file. Populates |sparse_ranges_|
-  // and sets |*out_sparse_data_size| to the total size of all the ranges (not
+  // Scans the existing ranges in the sparse file. Populates `sparse_ranges_`
+  // and sets `*out_sparse_data_size` to the total size of all the ranges (not
   // including headers).
-  bool ScanSparseFile(base::File* sparse_file, int32_t* out_sparse_data_size);
+  bool ScanSparseFile(base::File* sparse_file, uint64_t* out_sparse_data_size);
 
   // Reads from a single sparse range. If asked to read the entire range, also
   // verifies the CRC32.
   bool ReadSparseRange(base::File* sparse_file,
                        const SparseRange* range,
-                       size_t offset,
+                       size_t offset_in_range,
                        size_t len,
                        base::span<uint8_t> buf);
 
@@ -457,13 +457,13 @@
   // range, also updates the CRC32; otherwise, invalidates it.
   bool WriteSparseRange(base::File* sparse_file,
                         SparseRange* range,
-                        size_t offset,
+                        size_t offset_in_range,
                         size_t len,
                         base::span<const uint8_t> buf);
 
   // Appends a new sparse range to the sparse data file.
   bool AppendSparseRange(base::File* sparse_file,
-                         int64_t offset,
+                         uint64_t offset,
                          size_t len,
                          base::span<const uint8_t> buf);
 
@@ -527,14 +527,14 @@
   // was created to store it.
   std::array<bool, kSimpleEntryNormalFileCount> empty_file_omitted_;
 
-  typedef std::map<int64_t, SparseRange> SparseRangeOffsetMap;
+  typedef std::map<uint64_t, SparseRange> SparseRangeOffsetMap;
   typedef SparseRangeOffsetMap::iterator SparseRangeIterator;
   SparseRangeOffsetMap sparse_ranges_;
   bool sparse_file_open_ = false;
 
   // Offset of the end of the sparse file (where the next sparse range will be
   // written).
-  int64_t sparse_tail_offset_;
+  uint64_t sparse_tail_offset_;
 };
 
 }  // namespace disk_cache
diff --git a/net/http/http_stream_pool_attempt_manager.cc b/net/http/http_stream_pool_attempt_manager.cc
index 5a0cfd6..cb2a57e 100644
--- a/net/http/http_stream_pool_attempt_manager.cc
+++ b/net/http/http_stream_pool_attempt_manager.cc
@@ -205,13 +205,14 @@
 }
 
 void HttpStreamPool::AttemptManager::RequestStream(Job* job) {
-  CHECK(availability_state_ == AvailabilityState::kAvailable);
+  // JobController should check idle streams before starting a request Job.
+  CHECK_EQ(group_->IdleStreamSocketCount(), 0u);
 
   TRACE_EVENT_INSTANT("net.stream", "AttemptManager::RequestStream", track_,
                       NetLogWithSourceToFlow(job->request_net_log()));
 
   net_log_.AddEvent(
-      NetLogEventType::HTTP_STREAM_POOL_ATTEMPT_MANAGER_START_JOB, [&] {
+      NetLogEventType::HTTP_STREAM_POOL_ATTEMPT_MANAGER_REQUEST_STREAM, [&] {
         base::Value::Dict dict;
         dict.Set("priority", job->priority());
         base::Value::List allowed_bad_certs_list;
@@ -235,40 +236,11 @@
       NetLogEventType::HTTP_STREAM_POOL_ATTEMPT_MANAGER_JOB_BOUND,
       net_log_.source());
 
-  if (job->respect_limits() == RespectLimits::kIgnore) {
-    limit_ignoring_jobs_.emplace(job);
-  }
-
-  if (!job->enable_ip_based_pooling()) {
-    ip_based_pooling_disabling_jobs_.emplace(job);
-  }
-
-  if (!job->enable_alternative_services()) {
-    alternative_service_disabling_jobs_.emplace(job);
-  }
-
-  // HttpStreamPool should check the existing QUIC/SPDY sessions and idle
-  // streams before calling this method.
-  DCHECK(!CanUseExistingQuicSession());
-  DCHECK(!HasAvailableSpdySession());
-  CHECK_EQ(group_->IdleStreamSocketCount(), 0u);
-
-  request_jobs_.Insert(job, job->priority());
-
-  MaybeChangeServiceEndpointRequestPriority();
-
-  if (base_ssl_config_.has_value()) {
-    base_ssl_config_->allowed_bad_certs = job->allowed_bad_certs();
-  }
-  quic_version_ = job->quic_version();
-
   StartInternal(job);
-
-  return;
 }
 
 void HttpStreamPool::AttemptManager::Preconnect(Job* job) {
-  CHECK(availability_state_ == AvailabilityState::kAvailable);
+  // JobController should check active streams before starting a preconnect Job.
   CHECK_LT(group_->ActiveStreamSocketCount(), job->num_streams());
 
   TRACE_EVENT_INSTANT("net.stream", "AttemptManager::Preconnect", track_,
@@ -287,14 +259,6 @@
       NetLogEventType::HTTP_STREAM_POOL_JOB_CONTROLLER_PRECONNECT_BOUND,
       net_log_.source());
 
-  // HttpStreamPool should check the existing QUIC/SPDY sessions before calling
-  // this method.
-  DCHECK(!CanUseExistingQuicSession());
-  DCHECK(!HasAvailableSpdySession());
-
-  preconnect_jobs_.emplace(job);
-  quic_version_ = job->quic_version();
-
   StartInternal(job);
 }
 
@@ -1027,6 +991,37 @@
 }
 
 void HttpStreamPool::AttemptManager::StartInternal(Job* job) {
+  CHECK(availability_state_ == AvailabilityState::kAvailable);
+
+  if (job->IsPreconnect()) {
+    preconnect_jobs_.emplace(job);
+  } else {
+    request_jobs_.Insert(job, job->priority());
+    if (base_ssl_config_.has_value()) {
+      base_ssl_config_->allowed_bad_certs = job->allowed_bad_certs();
+    }
+  }
+
+  if (job->respect_limits() == RespectLimits::kIgnore) {
+    limit_ignoring_jobs_.emplace(job);
+  }
+
+  if (!job->enable_ip_based_pooling()) {
+    ip_based_pooling_disabling_jobs_.emplace(job);
+  }
+
+  if (!job->enable_alternative_services()) {
+    alternative_service_disabling_jobs_.emplace(job);
+  }
+
+  quic_version_ = job->quic_version();
+
+  // JobController should check the existing QUIC/SPDY sessions before starting
+  // a Job.
+  DCHECK(!CanUseExistingQuicSession());
+  DCHECK(!HasAvailableSpdySession());
+
+  MaybeChangeServiceEndpointRequestPriority();
   RestrictAllowedProtocols(job->allowed_alpns());
   UpdateTcpBasedAttemptState();
 
@@ -1082,7 +1077,6 @@
   if (!CanUseQuic()) {
     // TODO(crbug.com/346835898): Use other error code?
     CancelQuicAttempt(ERR_ABORTED);
-    UpdateTcpBasedAttemptState();
   }
 }
 
diff --git a/net/log/net_log_event_type_list.h b/net/log/net_log_event_type_list.h
index df1896c..3ab717c 100644
--- a/net/log/net_log_event_type_list.h
+++ b/net/log/net_log_event_type_list.h
@@ -1506,7 +1506,7 @@
 //   }
 EVENT_TYPE(HTTP_STREAM_POOL_GROUP_HANDLE_CREATED)
 
-// Emitted when an HttpStreamPool::AttemptManager starts a stream. The event
+// Emitted when an HttpStreamPool::AttemptManager requests a stream. The event
 // parameters are:
 //   {
 //     "priority": <The priority of the erquest>,
@@ -1516,7 +1516,7 @@
 //     "quic_version": <The QUIC version to attempt>,
 //     "source_dependency": <The source identifier of the request>
 //   }
-EVENT_TYPE(HTTP_STREAM_POOL_ATTEMPT_MANAGER_START_JOB)
+EVENT_TYPE(HTTP_STREAM_POOL_ATTEMPT_MANAGER_REQUEST_STREAM)
 
 // Records on the caller's NetLog to indicate that an
 // HttpStreamPool::AttemptManager starts a Job.
diff --git a/services/webnn/tflite/graph_builder_tflite.cc b/services/webnn/tflite/graph_builder_tflite.cc
index 7b99abe..47f0cc2 100644
--- a/services/webnn/tflite/graph_builder_tflite.cc
+++ b/services/webnn/tflite/graph_builder_tflite.cc
@@ -1451,7 +1451,8 @@
 }
 
 std::optional<GraphBuilderTflite::TensorInfo>
-GraphBuilderTflite::CanFuseQuantizeAndGetOutput(const mojom::Clamp& clamp) {
+GraphBuilderTflite::CanFuseQuantizeAndGetOutput(const mojom::Clamp& clamp,
+                                                bool is_emulated) {
   if (!IsDequantizeOutput(clamp.input_operand_id)) {
     return std::nullopt;
   }
@@ -1476,6 +1477,17 @@
     return std::nullopt;
   }
 
+  // For emulated clamp, it is emulated with min and max operations, which
+  // requires the input and output to have the same scale and zero_point.
+  // https://ai.google.dev/edge/litert/models/quantization_spec#int8_quantized_operator_specifications
+  if (is_emulated) {
+    const mojom::QuantizeLinear& output_quantize =
+        GetQuantizeOp(next_op->first);
+    if (!IsSameScaleAndZeroPoint(input_dequantize, output_quantize)) {
+      return std::nullopt;
+    }
+  }
+
   return SerializeQuantizedOutput(*next_op);
 }
 
@@ -3485,25 +3497,61 @@
     TensorIndex output_tensor_index,
     base::span<const DataType> min_values,
     base::span<const DataType> max_values) -> OperatorOffset {
+  const std::array<int32_t, 1> min_values_dimensions = {
+      base::checked_cast<int32_t>(min_values.size())};
   const TensorIndex min_value_tensor_index =
-      SerializeTensorWithBuffer<DataType>(
-          /*buffer=*/min_values,
-          /*dimensions=*/std::array<int32_t, 1>{
-              base::checked_cast<int32_t>(min_values.size())});
+      SerializeTensorWithBuffer<DataType>(min_values, min_values_dimensions);
+
+  // If `input_tensor_info.quantize_params` is not null, it means the
+  // `min_values` and `max_values` should be quantized to the same data type
+  // with input to meet the requirements of QDQ fusion.
+  TensorIndex maybe_quantized_min_value_tensor_index = min_value_tensor_index;
+  if (!input_tensor_info.quantize_params.IsNull()) {
+    maybe_quantized_min_value_tensor_index = SerializeTemporaryTensor(
+        min_values_dimensions, input_tensor_info.data_type,
+        input_tensor_info.quantize_params);
+    const OperatorCodeIndex operator_code_index =
+        GetOperatorCodeIndex(::tflite::BuiltinOperator_QUANTIZE);
+    const std::array<TensorIndex, 1> quantize_inputs = {min_value_tensor_index};
+    const std::array<TensorIndex, 1> quantize_outputs = {
+        maybe_quantized_min_value_tensor_index};
+    operators_.emplace_back(::tflite::CreateOperator(
+        builder_, operator_code_index,
+        builder_.CreateVector<TensorIndex>(quantize_inputs),
+        builder_.CreateVector<TensorIndex>(quantize_outputs)));
+  }
+
   const TensorIndex output_tensor_index_of_max = SerializeTemporaryTensor(
-      input_tensor_info.dimensions, input_tensor_info.data_type);
+      input_tensor_info.dimensions, input_tensor_info.data_type,
+      input_tensor_info.quantize_params);
   operators_.emplace_back(SerializeBinaryOperation(
       ::tflite::BuiltinOperator_MAXIMUM, input_tensor_info.index,
-      min_value_tensor_index, output_tensor_index_of_max));
+      maybe_quantized_min_value_tensor_index, output_tensor_index_of_max));
 
+  const std::array<int32_t, 1> max_values_dimensions = {
+      base::checked_cast<int32_t>(max_values.size())};
   const TensorIndex max_value_tensor_index =
-      SerializeTensorWithBuffer<DataType>(
-          /*buffer=*/max_values,
-          /*dimensions=*/std::array<int32_t, 1>{
-              base::checked_cast<int32_t>(max_values.size())});
-  return SerializeBinaryOperation(::tflite::BuiltinOperator_MINIMUM,
-                                  output_tensor_index_of_max,
-                                  max_value_tensor_index, output_tensor_index);
+      SerializeTensorWithBuffer<DataType>(max_values, max_values_dimensions);
+
+  TensorIndex maybe_quantized_max_value_tensor_index = max_value_tensor_index;
+  if (!input_tensor_info.quantize_params.IsNull()) {
+    maybe_quantized_max_value_tensor_index = SerializeTemporaryTensor(
+        max_values_dimensions, input_tensor_info.data_type,
+        input_tensor_info.quantize_params);
+    const OperatorCodeIndex operator_code_index =
+        GetOperatorCodeIndex(::tflite::BuiltinOperator_QUANTIZE);
+    const std::array<TensorIndex, 1> quantize_inputs = {max_value_tensor_index};
+    const std::array<TensorIndex, 1> quantize_outputs = {
+        maybe_quantized_max_value_tensor_index};
+    operators_.emplace_back(::tflite::CreateOperator(
+        builder_, operator_code_index,
+        builder_.CreateVector<TensorIndex>(quantize_inputs),
+        builder_.CreateVector<TensorIndex>(quantize_outputs)));
+  }
+
+  return SerializeBinaryOperation(
+      ::tflite::BuiltinOperator_MINIMUM, output_tensor_index_of_max,
+      maybe_quantized_max_value_tensor_index, output_tensor_index);
 }
 
 auto GraphBuilderTflite::SerializeClamp(const mojom::Clamp& clamp)
@@ -3517,7 +3565,7 @@
       GetClampOperatorCode(min_value, max_value);
   const bool is_emulated = !operator_code.has_value();
   std::optional<TensorInfo> quantized_output =
-      is_emulated ? std::nullopt : CanFuseQuantizeAndGetOutput(clamp);
+      CanFuseQuantizeAndGetOutput(clamp, is_emulated);
   const bool fuse_dequantize = quantized_output.has_value();
   ASSIGN_OR_RETURN(const TensorInfo& input_tensor_info,
                    SerializeInputTensorInfo(
diff --git a/services/webnn/tflite/graph_builder_tflite.h b/services/webnn/tflite/graph_builder_tflite.h
index 8af8479..4852c34 100644
--- a/services/webnn/tflite/graph_builder_tflite.h
+++ b/services/webnn/tflite/graph_builder_tflite.h
@@ -733,7 +733,8 @@
   // op specific fusion criteria required by TFLite, if so we can remove the
   // preceding `dequantizeLinear` and subsequent `quantizeLinear`.
   std::optional<TensorInfo> CanFuseQuantizeAndGetOutput(
-      const mojom::Clamp& clamp);
+      const mojom::Clamp& clamp,
+      bool is_emulated);
   std::optional<TensorInfo> CanFuseQuantizeAndGetOutput(
       const mojom::Conv2d& conv2d,
       std::optional<OperandId> activation_output_operand_id);
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index d521566..11ffb311 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -18307,6 +18307,27 @@
             ]
         }
     ],
+    "PrewarmServiceWorkerRegistrationForDSE": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "chromeos_lacros",
+                "fuchsia",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "PrewarmServiceWorkerRegistrationForDSE"
+                    ]
+                }
+            ]
+        }
+    ],
     "PriceTrackingDesktopExpansionStudy": [
         {
             "platforms": [
diff --git a/third_party/androidx/BUILD.gn b/third_party/androidx/BUILD.gn
index 0cea3fb9..51137c0 100644
--- a/third_party/androidx/BUILD.gn
+++ b/third_party/androidx/BUILD.gn
@@ -1317,7 +1317,7 @@
 
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_android_aar_prebuilt("androidx_test_espresso_espresso_core_java") {
-    aar_path = "../androidx/cipd/libs/androidx_test_espresso_espresso_core/espresso-core-3.7.0-alpha03.aar"
+    aar_path = "../androidx/cipd/libs/androidx_test_espresso_espresso_core/espresso-core-3.7.0-alpha04.aar"
     info_path = "../androidx/committed/libs/androidx_test_espresso_espresso_core/androidx_test_espresso_espresso_core.info"
     enable_bytecode_checks = false
     testonly = true
@@ -3441,7 +3441,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_android_aar_prebuilt(
       "androidx_test_espresso_espresso_idling_resource_java") {
-    aar_path = "../androidx/cipd/libs/androidx_test_espresso_espresso_idling_resource/espresso-idling-resource-3.7.0-alpha03.aar"
+    aar_path = "../androidx/cipd/libs/androidx_test_espresso_espresso_idling_resource/espresso-idling-resource-3.7.0-alpha04.aar"
     info_path = "../androidx/committed/libs/androidx_test_espresso_espresso_idling_resource/androidx_test_espresso_espresso_idling_resource.info"
     enable_bytecode_checks = false
 
diff --git a/third_party/androidx/bill_of_materials.json b/third_party/androidx/bill_of_materials.json
index 8f5aed8..5df6aea 100644
--- a/third_party/androidx/bill_of_materials.json
+++ b/third_party/androidx/bill_of_materials.json
@@ -962,12 +962,12 @@
     {
         "name": "espresso-core",
         "group": "androidx.test.espresso",
-        "version": "3.7.0-alpha03"
+        "version": "3.7.0-alpha04"
     },
     {
         "name": "espresso-idling-resource",
         "group": "androidx.test.espresso",
-        "version": "3.7.0-alpha03"
+        "version": "3.7.0-alpha04"
     },
     {
         "name": "espresso-intents",
diff --git a/third_party/androidx/build.gradle b/third_party/androidx/build.gradle
index e5d80512..619f324 100644
--- a/third_party/androidx/build.gradle
+++ b/third_party/androidx/build.gradle
@@ -207,8 +207,8 @@
 versionCache['androidx.startup:startup-runtime'] = '1.2.0'
 versionCache['androidx.swiperefreshlayout:swiperefreshlayout'] = '1.2.0-SNAPSHOT'
 versionCache['androidx.test.espresso:espresso-contrib'] = '3.5.1'
-versionCache['androidx.test.espresso:espresso-core'] = '3.7.0-alpha03'
-versionCache['androidx.test.espresso:espresso-idling-resource'] = '3.7.0-alpha03'
+versionCache['androidx.test.espresso:espresso-core'] = '3.7.0-alpha04'
+versionCache['androidx.test.espresso:espresso-idling-resource'] = '3.7.0-alpha04'
 versionCache['androidx.test.espresso:espresso-intents'] = '3.5.1'
 versionCache['androidx.test.espresso:espresso-web'] = '3.5.1'
 versionCache['androidx.test.ext:junit'] = '1.3.0-alpha03'
@@ -307,7 +307,7 @@
     google()
     maven {
         // This URL is generated by the fetch_all_androidx.py script.
-        url 'https://androidx.dev/snapshots/builds/13647192/artifacts/repository'
+        url 'https://androidx.dev/snapshots/builds/13649072/artifacts/repository'
     }
     mavenCentral()
 }
diff --git a/third_party/androidx/committed/libs/androidx_test_espresso_espresso_core/README.chromium b/third_party/androidx/committed/libs/androidx_test_espresso_espresso_core/README.chromium
index fbefd82b..dc5e8f3 100644
--- a/third_party/androidx/committed/libs/androidx_test_espresso_espresso_core/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_test_espresso_espresso_core/README.chromium
@@ -1,7 +1,7 @@
 Name: AndroidX Test Library
 Short Name: espresso-core
 URL: https://developer.android.com/testing
-Version: 3.7.0-alpha03
+Version: 3.7.0-alpha04
 License: Apache-2.0
 License File: LICENSE
 CPEPrefix: unknown
diff --git a/third_party/androidx/committed/libs/androidx_test_espresso_espresso_idling_resource/README.chromium b/third_party/androidx/committed/libs/androidx_test_espresso_espresso_idling_resource/README.chromium
index 4a3762d..2544db8 100644
--- a/third_party/androidx/committed/libs/androidx_test_espresso_espresso_idling_resource/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_test_espresso_espresso_idling_resource/README.chromium
@@ -1,7 +1,7 @@
 Name: AndroidX Test Library
 Short Name: espresso-idling-resource
 URL: https://developer.android.com/testing
-Version: 3.7.0-alpha03
+Version: 3.7.0-alpha04
 License: Apache-2.0
 License File: LICENSE
 CPEPrefix: unknown
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_compile_hints_consumer.h b/third_party/blink/renderer/bindings/core/v8/v8_compile_hints_consumer.h
index 6f1dad53..36f3d015 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_compile_hints_consumer.h
+++ b/third_party/blink/renderer/bindings/core/v8/v8_compile_hints_consumer.h
@@ -43,7 +43,7 @@
 
    private:
     friend class V8CrowdsourcedCompileHintsConsumer;
-    WTF::BloomFilter<kBloomFilterKeySize> bloom_;
+    BloomFilter<kBloomFilterKeySize> bloom_;
   };
 
   class DataAndScriptNameHash {
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_compile_hints_producer.cc b/third_party/blink/renderer/bindings/core/v8/v8_compile_hints_producer.cc
index 88918c8..84355e5c 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_compile_hints_producer.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_compile_hints_producer.cc
@@ -192,7 +192,7 @@
   // containing 2 ^ 16 bits, which equals to 1024 64-bit ints.
   static_assert((1 << kBloomFilterKeySize) / (sizeof(int32_t) * 8) ==
                 kBloomFilterInt32Count);
-  WTF::BloomFilter<kBloomFilterKeySize> bloom;
+  BloomFilter<kBloomFilterKeySize> bloom;
 
   for (wtf_size_t script_ix = 0; script_ix < compile_hints_collectors_.size();
        ++script_ix) {
diff --git a/third_party/blink/renderer/core/css/check_pseudo_has_fast_reject_filter.h b/third_party/blink/renderer/core/css/check_pseudo_has_fast_reject_filter.h
index 09711c2..3e161bf 100644
--- a/third_party/blink/renderer/core/css/check_pseudo_has_fast_reject_filter.h
+++ b/third_party/blink/renderer/core/css/check_pseudo_has_fast_reject_filter.h
@@ -37,7 +37,7 @@
 // doesn't contain the hash for '.b'.
 class CORE_EXPORT CheckPseudoHasFastRejectFilter {
  public:
-  using FastRejectFilter = WTF::BloomFilter<12>;
+  using FastRejectFilter = BloomFilter<12>;
 
   CheckPseudoHasFastRejectFilter() = default;
   CheckPseudoHasFastRejectFilter(CheckPseudoHasFastRejectFilter&) = delete;
diff --git a/third_party/blink/renderer/core/css/invalidation/rule_invalidation_data.h b/third_party/blink/renderer/core/css/invalidation/rule_invalidation_data.h
index 0cf9b8b..7905f74 100644
--- a/third_party/blink/renderer/core/css/invalidation/rule_invalidation_data.h
+++ b/third_party/blink/renderer/core/css/invalidation/rule_invalidation_data.h
@@ -263,7 +263,7 @@
   // seems a bit narrow in practice.
   InvalidationSetMap class_invalidation_sets;
 
-  std::unique_ptr<WTF::BloomFilter<14>> names_with_self_invalidation;
+  std::unique_ptr<BloomFilter<14>> names_with_self_invalidation;
   static constexpr int kClassSalt = 13;
   static constexpr int kIdSalt = 29;
 
diff --git a/third_party/blink/renderer/core/css/invalidation/rule_invalidation_data_builder.cc b/third_party/blink/renderer/core/css/invalidation/rule_invalidation_data_builder.cc
index 7d69845..4efed3c 100644
--- a/third_party/blink/renderer/core/css/invalidation/rule_invalidation_data_builder.cc
+++ b/third_party/blink/renderer/core/css/invalidation/rule_invalidation_data_builder.cc
@@ -18,7 +18,7 @@
   if (other.names_with_self_invalidation) {
     if (rule_invalidation_data_.names_with_self_invalidation == nullptr) {
       rule_invalidation_data_.names_with_self_invalidation =
-          std::make_unique<WTF::BloomFilter<14>>();
+          std::make_unique<BloomFilter<14>>();
     }
     rule_invalidation_data_.names_with_self_invalidation->Merge(
         *other.names_with_self_invalidation);
diff --git a/third_party/blink/renderer/core/css/invalidation/rule_invalidation_data_visitor.cc b/third_party/blink/renderer/core/css/invalidation/rule_invalidation_data_visitor.cc
index 14173d50..a4a33069 100644
--- a/third_party/blink/renderer/core/css/invalidation/rule_invalidation_data_visitor.cc
+++ b/third_party/blink/renderer/core/css/invalidation/rule_invalidation_data_visitor.cc
@@ -1977,7 +1977,7 @@
         return false;
       } else {
         rule_invalidation_data_.names_with_self_invalidation =
-            std::make_unique<WTF::BloomFilter<14>>();
+            std::make_unique<BloomFilter<14>>();
       }
     }
     rule_invalidation_data_.names_with_self_invalidation->Add(value.Hash() *
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 0148e7b..de196c4 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
@@ -145,7 +145,7 @@
     CHECK(IsWebGPU());
     return ResourceProviderDEPRECATED();
   }
-  CanvasResourceProvider* GetResourceProviderForCanvas2D() const {
+  CanvasResourceProvider* GetResourceProviderForCanvas2D() const override {
     CHECK(IsRenderingContext2D());
     return ResourceProviderDEPRECATED();
   }
diff --git a/third_party/blink/renderer/core/layout/scroll_anchor.cc b/third_party/blink/renderer/core/layout/scroll_anchor.cc
index dd24101..38cae95 100644
--- a/third_party/blink/renderer/core/layout/scroll_anchor.cc
+++ b/third_party/blink/renderer/core/layout/scroll_anchor.cc
@@ -57,7 +57,7 @@
 }  // anonymous namespace
 
 // With 100 unique strings, a 2^12 slot table has a false positive rate of ~2%.
-using ClassnameFilter = WTF::BloomFilter<12>;
+using ClassnameFilter = BloomFilter<12>;
 using Corner = ScrollAnchor::Corner;
 
 SerializedAnchor::SerializedAnchor(const ScrollAnchorData& data,
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
index ee9412fd..88cd666 100644
--- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
+++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
@@ -536,24 +536,93 @@
 CanvasResourceProvider*
 OffscreenCanvas::GetOrCreateResourceProviderForImageBitmap() {
   CHECK(IsImageBitmapRenderingContext());
-  return GetOrCreateResourceProviderForCanvas2DOrImageBitmap();
-}
-
-CanvasResourceProvider*
-OffscreenCanvas::GetOrCreateResourceProviderForCanvas2D() {
-  CHECK(IsRenderingContext2D());
-  return GetOrCreateResourceProviderForCanvas2DOrImageBitmap();
-}
-
-CanvasResourceProvider*
-OffscreenCanvas::GetOrCreateResourceProviderForCanvas2DOrImageBitmap() {
-  CHECK(IsRenderingContext2D() || IsImageBitmapRenderingContext());
   if (!context_ ||
       (context_->isContextLost() && !context_->IsContextBeingRestored())) {
     return nullptr;
   }
 
-  if (CanvasResourceProvider* provider = ResourceProviderDEPRECATED()) {
+  if (CanvasResourceProvider* provider = GetResourceProviderForImageBitmap()) {
+    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
+      // canvas is notified of GPU context losses via the `NotifyGpuContextLost`
+      // callback and restoration happens in `TryRestoreContextEvent`. Both
+      // callbacks are executed in their own separate task. If the GPU context
+      // goes invalid in the middle of a render task, the canvas won't
+      // immediately know about it and canvas APIs will continue using the
+      // provider that is now invalid. We can early return here, trying to
+      // re-create the provider right away would just fail. We need to let
+      // `TryRestoreContextEvent` wait for the GPU process to up again.
+      return nullptr;
+    }
+    return provider;
+  }
+
+  if (!IsValidImageSize() && !Size().IsEmpty()) {
+    context_->LoseContext(CanvasRenderingContext::kInvalidCanvasSize);
+    return nullptr;
+  }
+
+  std::unique_ptr<CanvasResourceProvider> provider;
+  gfx::Size surface_size(width(), height());
+  const SkAlphaType alpha_type = GetRenderingContextAlphaType();
+  const viz::SharedImageFormat format = GetRenderingContextFormat();
+  const gfx::ColorSpace color_space = GetRenderingContextColorSpace();
+  if (SharedGpuContext::IsGpuCompositingEnabled()) {
+    provider = CanvasResourceProvider::CreateSharedImageProvider(
+        Size(), format, alpha_type, color_space,
+        CanvasResourceProvider::ShouldInitialize::kCallClear,
+        SharedGpuContext::ContextProviderWrapper(), RasterMode::kGPU,
+        gpu::SHARED_IMAGE_USAGE_DISPLAY_READ, this);
+  } else if (HasPlaceholderCanvas()) {
+    base::WeakPtr<CanvasResourceDispatcher> dispatcher_weakptr =
+        GetOrCreateResourceDispatcher()->GetWeakPtr();
+    provider =
+        CanvasResourceProvider::CreateSharedImageProviderForSoftwareCompositor(
+            Size(), format, alpha_type, color_space,
+            CanvasResourceProvider::ShouldInitialize::kCallClear,
+            SharedGpuContext::SharedImageInterfaceProvider(), this);
+  }
+
+  if (!provider) {
+    // Last resort fallback is to use the bitmap provider. Using this
+    // path is normal for software-rendered OffscreenCanvases that have no
+    // placeholder canvas. If there is a placeholder, its content will not be
+    // visible on screen, but at least readbacks will work. Failure to create
+    // another type of resource prover above is a sign that the graphics
+    // pipeline is in a bad state (e.g. gpu process crashed, out of memory)
+    provider = CanvasResourceProvider::CreateBitmapProvider(
+        Size(), format, alpha_type, color_space,
+        CanvasResourceProvider::ShouldInitialize::kCallClear, this);
+  }
+
+  ReplaceResourceProvider(std::move(provider));
+
+  if (GetResourceProviderForImageBitmap() &&
+      GetResourceProviderForImageBitmap()->IsValid()) {
+    // todo(crbug.com/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",
+        GetResourceProviderForImageBitmap()->IsAccelerated());
+    base::UmaHistogramEnumeration(
+        "Blink.Canvas.ResourceProviderType",
+        GetResourceProviderForImageBitmap()->GetType());
+    DidDraw();
+  }
+  return GetResourceProviderForImageBitmap();
+}
+
+CanvasResourceProvider*
+OffscreenCanvas::GetOrCreateResourceProviderForCanvas2D() {
+  CHECK(IsRenderingContext2D());
+  if (!context_ ||
+      (context_->isContextLost() && !context_->IsContextBeingRestored())) {
+    return nullptr;
+  }
+
+  if (CanvasResourceProvider* provider = GetResourceProviderForCanvas2D()) {
     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
@@ -579,18 +648,16 @@
   gfx::Size surface_size(width(), height());
   const bool can_use_gpu =
       SharedGpuContext::IsGpuCompositingEnabled() &&
-      (IsImageBitmapRenderingContext() ||
-       (RuntimeEnabledFeatures::Accelerated2dCanvasEnabled() &&
-        !(context_->CreationAttributes().will_read_frequently ==
-          CanvasContextCreationAttributesCore::WillReadFrequently::kTrue)));
+      RuntimeEnabledFeatures::Accelerated2dCanvasEnabled() &&
+      !(context_->CreationAttributes().will_read_frequently ==
+        CanvasContextCreationAttributesCore::WillReadFrequently::kTrue);
   const bool use_shared_image =
       can_use_gpu ||
       (HasPlaceholderCanvas() && SharedGpuContext::IsGpuCompositingEnabled());
   const bool use_scanout =
       use_shared_image && HasPlaceholderCanvas() &&
       SharedGpuContext::MaySupportImageChromium() &&
-      (IsRenderingContext2D() &&
-       RuntimeEnabledFeatures::Canvas2dImageChromiumEnabled());
+      RuntimeEnabledFeatures::Canvas2dImageChromiumEnabled();
 
   gpu::SharedImageUsageSet shared_image_usage_flags =
       gpu::SHARED_IMAGE_USAGE_DISPLAY_READ;
@@ -633,17 +700,19 @@
 
   ReplaceResourceProvider(std::move(provider));
 
-  if (ResourceProviderDEPRECATED() && ResourceProviderDEPRECATED()->IsValid()) {
+  if (GetResourceProviderForCanvas2D() &&
+      GetResourceProviderForCanvas2D()->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",
-                              ResourceProviderDEPRECATED()->IsAccelerated());
+    base::UmaHistogramBoolean(
+        "Blink.Canvas.ResourceProviderIsAccelerated",
+        GetResourceProviderForCanvas2D()->IsAccelerated());
     base::UmaHistogramEnumeration("Blink.Canvas.ResourceProviderType",
-                                  ResourceProviderDEPRECATED()->GetType());
+                                  GetResourceProviderForCanvas2D()->GetType());
     DidDraw();
   }
-  return ResourceProviderDEPRECATED();
+  return GetResourceProviderForCanvas2D();
 }
 
 void OffscreenCanvas::DidDraw(const SkIRect& rect) {
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h
index 0e5654b..d247312 100644
--- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h
+++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h
@@ -207,6 +207,11 @@
 
   void Trace(Visitor*) const override;
 
+  CanvasResourceProvider* GetResourceProviderForImageBitmap() {
+    CHECK(IsImageBitmapRenderingContext());
+    return ResourceProviderDEPRECATED();
+  }
+
   class ScopedInsideWorkerRAF {
     STACK_ALLOCATED();
 
@@ -261,7 +266,6 @@
   static ContextFactoryVector& RenderingContextFactories();
   static CanvasRenderingContextFactory* GetRenderingContextFactory(int);
 
-  CanvasResourceProvider* GetOrCreateResourceProviderForCanvas2DOrImageBitmap();
   void RecordIdentifiabilityMetric(const blink::IdentifiableSurface& surface,
                                    const IdentifiableToken& token) const;
 
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 6d80c21..c940fa8 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->ResourceProviderDEPRECATED());
+  DCHECK(!host->GetResourceProviderForCanvas2D());
 
   if (host->IsValidImageSize()) {
     if (dispatch_context_lost_event_timer_.IsActive()) {
@@ -797,7 +797,7 @@
 BaseRenderingContext2D::PaintRenderingResultsToSnapshot(
     SourceDrawingBuffer source_buffer,
     FlushReason reason) {
-  CanvasResourceProvider* provider = Host()->ResourceProviderDEPRECATED();
+  CanvasResourceProvider* provider = Host()->GetResourceProviderForCanvas2D();
   return provider ? provider->Snapshot(reason) : nullptr;
 }
 
@@ -1504,7 +1504,7 @@
   gpu::SyncToken canvas_access_sync_token;
   bool performed_copy = false;
   scoped_refptr<gpu::ClientSharedImage> client_si =
-      host->ResourceProviderDEPRECATED()
+      host->GetResourceProviderForCanvas2D()
           ->GetBackingClientSharedImageForExternalWrite(
               &canvas_access_sync_token,
               gpu::SHARED_IMAGE_USAGE_WEBGPU_READ |
@@ -1587,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->ResourceProviderDEPRECATED()) {
+  if (host->GetResourceProviderForCanvas2D()) {
     exception_state.ThrowDOMException(
         DOMExceptionCode::kInvalidStateError,
         "The canvas was touched after transferToGPUTexture.");
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 17abb22..ec26fc7 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()->ResourceProviderDEPRECATED()) ? 1 : 0;
+    return (Host() && Host()->GetResourceProviderForCanvas2D()) ? 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 0e2687a..153004ad 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
@@ -147,11 +147,12 @@
   }
   cc::PaintFlags paint_flags;
   paint_flags.setBlendMode(SkBlendMode::kSrc);
-  Host()->ResourceProviderDEPRECATED()->Canvas().drawImage(
+  OffscreenCanvas* canvas = static_cast<OffscreenCanvas*>(Host());
+  canvas->GetResourceProviderForImageBitmap()->Canvas().drawImage(
       image->PaintImageForCurrentFrame(), 0, 0, SkSamplingOptions(),
       &paint_flags);
   scoped_refptr<CanvasResource> resource =
-      Host()->ResourceProviderDEPRECATED()->ProduceCanvasResource(
+      canvas->GetResourceProviderForImageBitmap()->ProduceCanvasResource(
           FlushReason::kNon2DCanvas);
   Host()->PushFrame(
       std::move(resource),
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 461f71c..037a2bb0 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()->ResourceProviderDEPRECATED()) {
+  if (Host()->GetResourceProviderForWebGL()) {
     buffer_count++;
   }
 
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 92eca37..8e39d4f 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1811,7 +1811,6 @@
     "//services/viz/public/cpp/gpu",
     "//skia",
     "//skia:skcms",
-    "//third_party:freetype_buildflags",
     "//third_party:freetype_harfbuzz",
     "//third_party/abseil-cpp:absl",
     "//third_party/blink/public:image_resources",
diff --git a/third_party/blink/renderer/platform/fonts/simple_font_data.cc b/third_party/blink/renderer/platform/fonts/simple_font_data.cc
index 32030b9..b308719a 100644
--- a/third_party/blink/renderer/platform/fonts/simple_font_data.cc
+++ b/third_party/blink/renderer/platform/fonts/simple_font_data.cc
@@ -52,7 +52,6 @@
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
 #include "third_party/blink/renderer/platform/wtf/text/unicode.h"
-#include "third_party/freetype_buildflags.h"
 #include "third_party/skia/include/core/SkFont.h"
 #include "third_party/skia/include/core/SkFontMetrics.h"
 #include "third_party/skia/include/core/SkPath.h"
@@ -62,23 +61,14 @@
 #include "ui/gfx/geometry/skia_conversions.h"
 #include "v8/include/v8.h"
 
-#if !BUILDFLAG(USE_SYSTEM_FREETYPE) && BUILDFLAG(ENABLE_FREETYPE)
-#include "third_party/freetype/src/src/autofit/afws-decl.h"
-#endif
-
 namespace blink {
 
 constexpr float kSmallCapsFontSizeMultiplier = 0.7f;
 constexpr float kEmphasisMarkFontSizeMultiplier = 0.5f;
 
-#if !BUILDFLAG(USE_SYSTEM_FREETYPE) && BUILDFLAG(ENABLE_FREETYPE)
-constexpr int32_t kFontObjectsMemoryConsumption =
-    std::max(sizeof(AF_LatinMetricsRec), sizeof(AF_CJKMetricsRec));
-#else
 // sizeof(AF_LatinMetricsRec) = 2128
 // TODO(drott): Measure a new number for Fontations.
 constexpr int32_t kFontObjectsMemoryConsumption = 2128;
-#endif
 
 SimpleFontData::SimpleFontData(const FontPlatformData* platform_data,
                                const CustomFontData* custom_data,
diff --git a/third_party/blink/renderer/platform/fonts/web_font_typeface_factory.cc b/third_party/blink/renderer/platform/fonts/web_font_typeface_factory.cc
index c4dce0909..2588cc2 100644
--- a/third_party/blink/renderer/platform/fonts/web_font_typeface_factory.cc
+++ b/third_party/blink/renderer/platform/fonts/web_font_typeface_factory.cc
@@ -10,7 +10,6 @@
 #include "skia/ext/font_utils.h"
 #include "third_party/blink/renderer/platform/fonts/font_cache.h"
 #include "third_party/blink/renderer/platform/fonts/opentype/font_format_check.h"
-#include "third_party/freetype_buildflags.h"
 #include "third_party/skia/include/core/SkTypeface.h"
 #include "third_party/skia/include/ports/SkTypeface_fontations.h"
 
diff --git a/third_party/blink/renderer/platform/geometry/contoured_rect.cc b/third_party/blink/renderer/platform/geometry/contoured_rect.cc
index 920f7392..4ae7bac1 100644
--- a/third_party/blink/renderer/platform/geometry/contoured_rect.cc
+++ b/third_party/blink/renderer/platform/geometry/contoured_rect.cc
@@ -181,7 +181,7 @@
 // The resulting "aligned" corner has its coordinates and curvature adjusted
 // in such a way that it would have consistent thickness along its entire path.
 Corner ContouredRect::Corner::AlignedToOrigin(const Corner& origin) const {
-  if (origin.IsZero() || *this == origin) {
+  if (origin.IsEmpty() || *this == origin) {
     return *this;
   }
 
diff --git a/third_party/blink/renderer/platform/geometry/contoured_rect.h b/third_party/blink/renderer/platform/geometry/contoured_rect.h
index 4b1468f..91ef1ab 100644
--- a/third_party/blink/renderer/platform/geometry/contoured_rect.h
+++ b/third_party/blink/renderer/platform/geometry/contoured_rect.h
@@ -139,6 +139,9 @@
     }
     constexpr bool IsConcave() const { return curvature_ < 1; }
     constexpr bool IsZero() const { return Start() == End(); }
+    constexpr bool IsEmpty() const {
+      return v1().Length() == 0 || v2().Length() == 0;
+    }
     constexpr bool operator==(const Corner&) const = default;
 
     // Invert the curvature
diff --git a/third_party/blink/renderer/platform/geometry/path_builder.cc b/third_party/blink/renderer/platform/geometry/path_builder.cc
index 73bdfe8..1056b13 100644
--- a/third_party/blink/renderer/platform/geometry/path_builder.cc
+++ b/third_party/blink/renderer/platform/geometry/path_builder.cc
@@ -71,7 +71,7 @@
   // Start the path from the beginning of the curve.
   path.lineTo(gfx::PointFToSkPoint(corner.Start()));
 
-  if (corner.IsStraight()) {
+  if (corner.IsStraight() || corner.IsEmpty()) {
     // Straight or very close to it, draw two lines.
     path.lineTo(gfx::PointFToSkPoint(corner.Outer()));
     path.lineTo(gfx::PointFToSkPoint(corner.End()));
@@ -336,7 +336,7 @@
   ContouredRect origin_contoured_rect(origin_rect,
                                       contoured_rect.GetCornerCurvature());
 
-  if (!origin_rect.GetRadii().TopRight().IsZero()) {
+  if (!origin_rect.GetRadii().TopRight().IsEmpty()) {
     SkPath path;
     path.moveTo(infinite_rect.left(), infinite_rect.top());
     AddCurvedCorner(path, contoured_rect.TopRightCorner());
@@ -346,7 +346,7 @@
     op_builder.add(path, kIntersect_SkPathOp);
   }
 
-  if (!origin_rect.GetRadii().BottomRight().IsZero()) {
+  if (!origin_rect.GetRadii().BottomRight().IsEmpty()) {
     SkPath path;
     path.moveTo(infinite_rect.right(), infinite_rect.top());
     AddCurvedCorner(path, contoured_rect.BottomRightCorner());
@@ -356,7 +356,7 @@
     op_builder.add(path, kIntersect_SkPathOp);
   }
 
-  if (!origin_rect.GetRadii().BottomLeft().IsZero()) {
+  if (!origin_rect.GetRadii().BottomLeft().IsEmpty()) {
     SkPath path;
     path.moveTo(infinite_rect.right(), infinite_rect.bottom());
     AddCurvedCorner(path, contoured_rect.BottomLeftCorner());
@@ -366,7 +366,7 @@
     op_builder.add(path, kIntersect_SkPathOp);
   }
 
-  if (!origin_rect.GetRadii().TopLeft().IsZero()) {
+  if (!origin_rect.GetRadii().TopLeft().IsEmpty()) {
     SkPath path;
     path.moveTo(infinite_rect.left(), infinite_rect.bottom());
     AddCurvedCorner(path, contoured_rect.TopLeftCorner());
@@ -377,7 +377,8 @@
   }
 
   SkPath result;
-  CHECK(op_builder.resolve(&result));
+  CHECK(op_builder.resolve(&result))
+      << contoured_rect.ToString() << " " << origin_rect.ToString();
   builder_.addPath(result);
   current_path_.reset();
   return *this;
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 e07fc58..6f48a55 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_hibernation_handler.cc
@@ -407,7 +407,7 @@
   hibernation_scheduled_ = false;
 
   CanvasResourceProvider* provider =
-      resource_host_->ResourceProviderDEPRECATED();
+      resource_host_->GetResourceProviderForCanvas2D();
   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 648a11b3..f637bd7 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,11 @@
   if (!page_visible) {
     // Trigger hibernation.
     scoped_refptr<StaticBitmapImage> snapshot =
-        host->ResourceProviderDEPRECATED()->Snapshot(FlushReason::kHibernating);
+        host->GetResourceProviderForCanvas2D()->Snapshot(
+            FlushReason::kHibernating);
     hibernation_handler->SaveForHibernation(
         snapshot->PaintImageForCurrentFrame().GetSwSkImage(),
-        host->ResourceProviderDEPRECATED()->ReleaseRecorder());
+        host->GetResourceProviderForCanvas2D()->ReleaseRecorder());
     EXPECT_TRUE(hibernation_handler->IsHibernating());
   } else {
     // End hibernation.
@@ -231,7 +232,7 @@
 
   EXPECT_TRUE(host.GetRasterMode() == RasterMode::kGPU);
   EXPECT_FALSE(handler.IsHibernating());
-  EXPECT_TRUE(host.ResourceProviderDEPRECATED()->IsValid());
+  EXPECT_TRUE(host.GetResourceProviderForCanvas2D()->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 a112ecdd..5eb716f4 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_host.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_host.h
@@ -63,6 +63,8 @@
 
   virtual bool LowLatencyEnabled() const { return false; }
 
+  virtual CanvasResourceProvider* GetResourceProviderForCanvas2D() const = 0;
+
   // TODO(crbug.com/352263194): Transition all usages of this method to
   // context-specific variants and eliminate the method.
   CanvasResourceProvider* ResourceProviderDEPRECATED() const {
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc
index a2541f4e..f4e4d517 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc
@@ -157,13 +157,12 @@
   }
 
   // These SharedImages are read and written by WebGPU clients and can then be
-  // sent off to the display compositor. They can also be read over raster
-  // interface as part of video frame.
+  // sent off to the display compositor.
   gpu::SharedImageUsageSet usage =
       gpu::SHARED_IMAGE_USAGE_WEBGPU_READ |
       gpu::SHARED_IMAGE_USAGE_WEBGPU_WRITE |
       gpu::SHARED_IMAGE_USAGE_WEBGPU_SWAP_CHAIN_TEXTURE |
-      gpu::SHARED_IMAGE_USAGE_RASTER_READ | GetSharedImageUsagesForDisplay();
+      GetSharedImageUsagesForDisplay();
   if (usage_ & wgpu::TextureUsage::StorageBinding) {
     usage |= gpu::SHARED_IMAGE_USAGE_WEBGPU_STORAGE_TEXTURE;
   }
@@ -171,9 +170,10 @@
   wgpu::AdapterInfo adapter_info;
   device_.GetAdapter().GetInfo(&adapter_info);
   if (adapter_info.adapterType == wgpu::AdapterType::CPU) {
-    // When using the fallback adapter, service-side writes of the
+    // When using the fallback adapter, service-side reads and writes of the
     // SharedImage occur via Skia with copies from/to Dawn textures.
-    usage |= gpu::SHARED_IMAGE_USAGE_RASTER_WRITE;
+    usage |= gpu::SHARED_IMAGE_USAGE_RASTER_READ |
+             gpu::SHARED_IMAGE_USAGE_RASTER_WRITE;
   }
 
   gpu::ImageInfo info = {size,
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 dee9234..dcfbcb2 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
@@ -34,11 +34,16 @@
   void SetIsHibernating(bool is_hibernating) {
     is_hibernating_ = is_hibernating;
   }
+
+  CanvasResourceProvider* GetResourceProviderForCanvas2D() const override {
+    return ResourceProviderDEPRECATED();
+  }
+
   size_t GetMemoryUsage() const override { return 0; }
   CanvasResourceProvider* GetOrCreateCanvasResourceProviderForCanvas2D()
       override {
-    if (ResourceProviderDEPRECATED()) {
-      return ResourceProviderDEPRECATED();
+    if (GetResourceProviderForCanvas2D()) {
+      return GetResourceProviderForCanvas2D();
     }
     constexpr auto kShouldInitialize =
         CanvasResourceProvider::ShouldInitialize::kCallClear;
@@ -65,7 +70,7 @@
 
     ReplaceResourceProvider(std::move(provider));
 
-    return ResourceProviderDEPRECATED();
+    return GetResourceProviderForCanvas2D();
   }
 
   void SetPageVisible(bool visible) {
diff --git a/third_party/blink/renderer/platform/testing/video_frame_utils.cc b/third_party/blink/renderer/platform/testing/video_frame_utils.cc
index 8c7a81b..5775b14 100644
--- a/third_party/blink/renderer/platform/testing/video_frame_utils.cc
+++ b/third_party/blink/renderer/platform/testing/video_frame_utils.cc
@@ -45,8 +45,7 @@
                            << media::VideoPixelFormatToString(pixel_format)
                            << " has no corresponding gfx::BufferFormat";
       const auto si_usage = gpu::SHARED_IMAGE_USAGE_CPU_WRITE_ONLY |
-                            gpu::SHARED_IMAGE_USAGE_DISPLAY_READ |
-                            gpu::SHARED_IMAGE_USAGE_RASTER_READ;
+                            gpu::SHARED_IMAGE_USAGE_DISPLAY_READ;
       auto shared_image = test_sii->CreateSharedImage(
           {viz::GetSharedImageFormat(*buffer_format), coded_size,
            gfx::ColorSpace(), gpu::SharedImageUsageSet(si_usage),
diff --git a/third_party/blink/renderer/platform/wtf/bloom_filter.h b/third_party/blink/renderer/platform/wtf/bloom_filter.h
index 95d2d29..2b12c2e 100644
--- a/third_party/blink/renderer/platform/wtf/bloom_filter.h
+++ b/third_party/blink/renderer/platform/wtf/bloom_filter.h
@@ -36,7 +36,7 @@
 #include "base/dcheck_is_on.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
 
-namespace WTF {
+namespace blink {
 
 // Bloom filter with k=2. Uses 2^keyBits/8 bytes of memory.
 // False positive rate is approximately (1-e^(-2n/m))^2, where n is the number
@@ -140,6 +140,6 @@
   bit_array_[BitArrayIndex(key)] |= BitMask(key);
 }
 
-}  // namespace WTF
+}  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_BLOOM_FILTER_H_
diff --git a/third_party/blink/renderer/platform/wtf/bloom_filter_test.cc b/third_party/blink/renderer/platform/wtf/bloom_filter_test.cc
index 9c6d48a..f6171d7 100644
--- a/third_party/blink/renderer/platform/wtf/bloom_filter_test.cc
+++ b/third_party/blink/renderer/platform/wtf/bloom_filter_test.cc
@@ -7,7 +7,7 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace WTF {
+namespace blink {
 
 class BloomFilterTest : public ::testing::Test {
  protected:
@@ -108,4 +108,4 @@
   EXPECT_FALSE(filter.MayContain(charlie));
 }
 
-}  // namespace WTF
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/wtf/text/encoding_tables.cc b/third_party/blink/renderer/platform/wtf/text/encoding_tables.cc
index 7ee29a16..5bbd8bd 100644
--- a/third_party/blink/renderer/platform/wtf/text/encoding_tables.cc
+++ b/third_party/blink/renderer/platform/wtf/text/encoding_tables.cc
@@ -156,7 +156,7 @@
     size_t array_index = 0;
 
     UErrorCode error = U_ZERO_ERROR;
-    ICUConverterWrapper icu_converter;
+    blink::IcuConverterWrapper icu_converter;
     icu_converter.converter = ucnv_open("EUC-JP", &error);
     DCHECK(U_SUCCESS(error));
 
@@ -214,7 +214,7 @@
     size_t array_index = 0;
 
     UErrorCode error = U_ZERO_ERROR;
-    ICUConverterWrapper icu_converter;
+    blink::IcuConverterWrapper icu_converter;
     icu_converter.converter = ucnv_open("EUC-JP", &error);
     DCHECK(U_SUCCESS(error));
 
@@ -256,7 +256,7 @@
   std::call_once(flag, [] {
     array = new EucKrEncodeIndex;
     UErrorCode error = U_ZERO_ERROR;
-    ICUConverterWrapper icu_converter;
+    blink::IcuConverterWrapper icu_converter;
     icu_converter.converter = ucnv_open("windows-949", &error);
     DCHECK(U_SUCCESS(error));
     auto get_pair =
@@ -316,7 +316,7 @@
   std::call_once(flag, [] {
     array = new Gb18030EncodeTable;
     UErrorCode error = U_ZERO_ERROR;
-    ICUConverterWrapper icu_converter;
+    blink::IcuConverterWrapper icu_converter;
     icu_converter.converter = ucnv_open("gb18030", &error);
     DCHECK(U_SUCCESS(error));
     for (size_t pointer = 0; pointer < 23940; pointer++) {
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_icu.cc b/third_party/blink/renderer/platform/wtf/text/text_codec_icu.cc
index 67b9455..5cb77de9 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_icu.cc
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_icu.cc
@@ -46,22 +46,23 @@
 #include "third_party/blink/renderer/platform/wtf/text/text_codec_cjk.h"
 #include "third_party/blink/renderer/platform/wtf/threading.h"
 
-namespace WTF {
+namespace blink {
 
 const size_t kConversionBufferSize = 16384;
 
-ICUConverterWrapper::~ICUConverterWrapper() {
+IcuConverterWrapper::~IcuConverterWrapper() {
   if (converter)
     ucnv_close(converter);
 }
 
-static UConverter*& CachedConverterICU() {
-  return WtfThreading().CachedConverterICU().converter;
+static UConverter*& CachedConverterIcu() {
+  return WtfThreading().CachedConverterIcu().converter;
 }
 
-std::unique_ptr<TextCodec> TextCodecICU::Create(const TextEncoding& encoding,
-                                                const void*) {
-  return base::WrapUnique(new TextCodecICU(encoding));
+std::unique_ptr<TextCodec> TextCodecIcu::Create(
+    const WTF::TextEncoding& encoding,
+    const void*) {
+  return base::WrapUnique(new TextCodecIcu(encoding));
 }
 
 namespace {
@@ -81,7 +82,7 @@
 }
 }  // namespace
 
-void TextCodecICU::RegisterEncodingNames(EncodingNameRegistrar registrar) {
+void TextCodecIcu::RegisterEncodingNames(EncodingNameRegistrar registrar) {
   // We register Hebrew with logical ordering using a separate name.
   // Otherwise, this would share the same canonical name as the
   // visual ordering case, and then TextEncoding could not tell them
@@ -120,7 +121,7 @@
     }
 #endif
     // Avoid codecs supported by `TextCodecCJK`.
-    if (TextCodecCJK::IsSupported(standard_name)) {
+    if (WTF::TextCodecCJK::IsSupported(standard_name)) {
       continue;
     }
 
@@ -153,7 +154,7 @@
 
     // Avoid registering codecs registered by
     // `TextCodecCJK::RegisterEncodingNames`.
-    if (!TextCodecCJK::IsSupported(standard_name)) {
+    if (!WTF::TextCodecCJK::IsSupported(standard_name)) {
       registrar(standard_name, standard_name);
     }
 
@@ -270,7 +271,7 @@
 #endif
 }
 
-void TextCodecICU::RegisterCodecs(TextCodecRegistrar registrar) {
+void TextCodecIcu::RegisterCodecs(TextCodecRegistrar registrar) {
   // See comment above in registerEncodingNames.
   registrar("ISO-8859-8-I", Create, nullptr);
 
@@ -295,23 +296,23 @@
     }
 #endif
     // Avoid codecs supported by `TextCodecCJK`.
-    if (TextCodecCJK::IsSupported(standard_name)) {
+    if (WTF::TextCodecCJK::IsSupported(standard_name)) {
       continue;
     }
     registrar(standard_name, Create, nullptr);
   }
 }
 
-TextCodecICU::TextCodecICU(const TextEncoding& encoding)
+TextCodecIcu::TextCodecIcu(const WTF::TextEncoding& encoding)
     : encoding_(encoding) {}
 
-TextCodecICU::~TextCodecICU() {
-  ReleaseICUConverter();
+TextCodecIcu::~TextCodecIcu() {
+  ReleaseIcuConverter();
 }
 
-void TextCodecICU::ReleaseICUConverter() const {
+void TextCodecIcu::ReleaseIcuConverter() const {
   if (converter_icu_) {
-    UConverter*& cached_converter = CachedConverterICU();
+    UConverter*& cached_converter = CachedConverterIcu();
     if (cached_converter)
       ucnv_close(cached_converter);
     cached_converter = converter_icu_;
@@ -319,7 +320,7 @@
   }
 }
 
-void TextCodecICU::CreateICUConverter() const {
+void TextCodecIcu::CreateIcuConverter() const {
   DCHECK(!converter_icu_);
 
 #if defined(USING_SYSTEM_ICU)
@@ -330,11 +331,11 @@
 
   UErrorCode err;
 
-  UConverter*& cached_converter = CachedConverterICU();
+  UConverter*& cached_converter = CachedConverterIcu();
   if (cached_converter) {
     err = U_ZERO_ERROR;
     const char* cached_name = ucnv_getName(cached_converter, &err);
-    if (U_SUCCESS(err) && encoding_ == TextEncoding(cached_name)) {
+    if (U_SUCCESS(err) && encoding_ == WTF::TextEncoding(cached_name)) {
       converter_icu_ = cached_converter;
       cached_converter = nullptr;
       return;
@@ -349,7 +350,7 @@
     ucnv_setFallback(converter_icu_, true);
 }
 
-int TextCodecICU::DecodeToBuffer(UChar* target,
+int TextCodecIcu::DecodeToBuffer(UChar* target,
                                  UChar* target_limit,
                                  const char*& source,
                                  const char* source_limit,
@@ -396,13 +397,13 @@
   UConverterToUCallback saved_action_;
 };
 
-String TextCodecICU::Decode(base::span<const uint8_t> data,
+String TextCodecIcu::Decode(base::span<const uint8_t> data,
                             FlushBehavior flush,
                             bool stop_on_error,
                             bool& saw_error) {
   // Get a converter for the passed-in encoding.
   if (!converter_icu_) {
-    CreateICUConverter();
+    CreateIcuConverter();
     DCHECK(converter_icu_);
     if (!converter_icu_) {
       DLOG(ERROR)
@@ -511,7 +512,7 @@
                                   UErrorCode* err) {
   FormatEscapedEntityCallback(context, from_u_args, code_units, length,
                               code_point, reason, err,
-                              kEntitiesForUnencodables);
+                              UnencodableHandling::kEntitiesForUnencodables);
 }
 
 // Invalid character handler when writing escaped entities in CSS encoding for
@@ -524,9 +525,9 @@
                                      UChar32 code_point,
                                      UConverterCallbackReason reason,
                                      UErrorCode* err) {
-  FormatEscapedEntityCallback(context, from_u_args, code_units, length,
-                              code_point, reason, err,
-                              kCSSEncodedEntitiesForUnencodables);
+  FormatEscapedEntityCallback(
+      context, from_u_args, code_units, length, code_point, reason, err,
+      UnencodableHandling::kCSSEncodedEntitiesForUnencodables);
 }
 
 // Invalid character handler when writing escaped entities in HTML/XML encoding
@@ -539,9 +540,9 @@
                                      UChar32 code_point,
                                      UConverterCallbackReason reason,
                                      UErrorCode* err) {
-  FormatEscapedEntityCallback(context, from_u_args, code_units, length,
-                              code_point, reason, err,
-                              kURLEncodedEntitiesForUnencodables);
+  FormatEscapedEntityCallback(
+      context, from_u_args, code_units, length, code_point, reason, err,
+      UnencodableHandling::kURLEncodedEntitiesForUnencodables);
 }
 
 #if defined(USING_SYSTEM_ICU)
@@ -645,12 +646,12 @@
   STACK_ALLOCATED();
 
  public:
-  TextCodecInput(const TextEncoding& encoding,
+  TextCodecInput(const WTF::TextEncoding& encoding,
                  base::span<const UChar> characters)
       : begin_(characters.data()),
         end_(characters.data() + characters.size()) {}
 
-  TextCodecInput(const TextEncoding& encoding,
+  TextCodecInput(const WTF::TextEncoding& encoding,
                  base::span<const LChar> characters) {
     buffer_.ReserveInitialCapacity(
         base::checked_cast<wtf_size_t>(characters.size()));
@@ -668,7 +669,7 @@
   Vector<UChar> buffer_;
 };
 
-std::string TextCodecICU::EncodeInternal(const TextCodecInput& input,
+std::string TextCodecIcu::EncodeInternal(const TextCodecInput& input,
                                          UnencodableHandling handling) {
   const UChar* source = input.begin();
   const UChar* end = input.end();
@@ -676,7 +677,7 @@
   UErrorCode err = U_ZERO_ERROR;
 
   switch (handling) {
-    case kEntitiesForUnencodables:
+    case UnencodableHandling::kEntitiesForUnencodables:
 #if !defined(USING_SYSTEM_ICU)
       ucnv_setFromUCallBack(converter_icu_, NumericEntityCallback, nullptr,
                             nullptr, nullptr, &err);
@@ -687,7 +688,7 @@
           0, 0, &err);
 #endif
       break;
-    case kURLEncodedEntitiesForUnencodables:
+    case UnencodableHandling::kURLEncodedEntitiesForUnencodables:
 #if !defined(USING_SYSTEM_ICU)
       ucnv_setFromUCallBack(converter_icu_, UrlEscapedEntityCallback, nullptr,
                             nullptr, nullptr, &err);
@@ -698,7 +699,7 @@
                             0, 0, 0, &err);
 #endif
       break;
-    case kCSSEncodedEntitiesForUnencodables:
+    case UnencodableHandling::kCSSEncodedEntitiesForUnencodables:
 #if !defined(USING_SYSTEM_ICU)
       ucnv_setFromUCallBack(converter_icu_, CssEscapedEntityCallback, nullptr,
                             nullptr, nullptr, &err);
@@ -709,7 +710,7 @@
                             0, 0, 0, &err);
 #endif
       break;
-    case kNoUnencodables:
+    case UnencodableHandling::kNoUnencodables:
       DCHECK(encoding_ == UTF16BigEndianEncoding() ||
              encoding_ == UTF16LittleEndianEncoding() ||
              encoding_ == UTF8Encoding());
@@ -741,14 +742,14 @@
 }
 
 template <typename CharType>
-std::string TextCodecICU::EncodeCommon(base::span<const CharType> characters,
+std::string TextCodecIcu::EncodeCommon(base::span<const CharType> characters,
                                        UnencodableHandling handling) {
   if (characters.empty()) {
     return "";
   }
 
   if (!converter_icu_)
-    CreateICUConverter();
+    CreateIcuConverter();
   if (!converter_icu_)
     return std::string();
 
@@ -756,14 +757,14 @@
   return EncodeInternal(input, handling);
 }
 
-std::string TextCodecICU::Encode(base::span<const UChar> characters,
+std::string TextCodecIcu::Encode(base::span<const UChar> characters,
                                  UnencodableHandling handling) {
   return EncodeCommon(characters, handling);
 }
 
-std::string TextCodecICU::Encode(base::span<const LChar> characters,
+std::string TextCodecIcu::Encode(base::span<const LChar> characters,
                                  UnencodableHandling handling) {
   return EncodeCommon(characters, handling);
 }
 
-}  // namespace WTF
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_icu.h b/third_party/blink/renderer/platform/wtf/text/text_codec_icu.h
index 841f87bc..a68cdd0 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_icu.h
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_icu.h
@@ -33,22 +33,22 @@
 #include "third_party/blink/renderer/platform/wtf/text/text_codec.h"
 #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
 
-typedef struct UConverter UConverter;
+using UConverter = struct UConverter;
 
-namespace WTF {
+namespace blink {
 
 class TextCodecInput;
 
-class TextCodecICU final : public TextCodec {
+class TextCodecIcu final : public TextCodec {
  public:
   static void RegisterEncodingNames(EncodingNameRegistrar);
   static void RegisterCodecs(TextCodecRegistrar);
 
-  ~TextCodecICU() override;
+  ~TextCodecIcu() override;
 
  private:
-  TextCodecICU(const TextEncoding&);
-  WTF_EXPORT static std::unique_ptr<TextCodec> Create(const TextEncoding&,
+  explicit TextCodecIcu(const WTF::TextEncoding&);
+  WTF_EXPORT static std::unique_ptr<TextCodec> Create(const WTF::TextEncoding&,
                                                       const void*);
 
   String Decode(base::span<const uint8_t> data,
@@ -62,8 +62,8 @@
   std::string EncodeCommon(base::span<const CharType>, UnencodableHandling);
   std::string EncodeInternal(const TextCodecInput&, UnencodableHandling);
 
-  void CreateICUConverter() const;
-  void ReleaseICUConverter() const;
+  void CreateIcuConverter() const;
+  void ReleaseIcuConverter() const;
 
   int DecodeToBuffer(UChar* buffer,
                      UChar* buffer_limit,
@@ -73,27 +73,27 @@
                      bool flush,
                      UErrorCode&);
 
-  TextEncoding encoding_;
+  WTF::TextEncoding encoding_;
   mutable UConverter* converter_icu_ = nullptr;
 #if defined(USING_SYSTEM_ICU)
   mutable bool needs_gbk_fallbacks_ = false;
 #endif
 
-  FRIEND_TEST_ALL_PREFIXES(TextCodecICUTest, IgnorableCodePoint);
+  FRIEND_TEST_ALL_PREFIXES(TextCodecIcuTest, IgnorableCodePoint);
 };
 
-struct ICUConverterWrapper {
-  USING_FAST_MALLOC(ICUConverterWrapper);
+struct IcuConverterWrapper {
+  USING_FAST_MALLOC(IcuConverterWrapper);
 
  public:
-  ICUConverterWrapper() : converter(nullptr) {}
-  ICUConverterWrapper(const ICUConverterWrapper&) = delete;
-  ICUConverterWrapper& operator=(const ICUConverterWrapper&) = delete;
-  ~ICUConverterWrapper();
+  IcuConverterWrapper() : converter(nullptr) {}
+  IcuConverterWrapper(const IcuConverterWrapper&) = delete;
+  IcuConverterWrapper& operator=(const IcuConverterWrapper&) = delete;
+  ~IcuConverterWrapper();
 
   UConverter* converter;
 };
 
-}  // namespace WTF
+}  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_TEXT_CODEC_ICU_H_
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_icu_test.cc b/third_party/blink/renderer/platform/wtf/text/text_codec_icu_test.cc
index f81cd1f..9467baee 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_icu_test.cc
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_icu_test.cc
@@ -8,27 +8,28 @@
 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
-namespace WTF {
+namespace blink {
 
-TEST(TextCodecICUTest, IgnorableCodePoint) {
-  TextEncoding iso2022jp("iso-2022-jp");
-  std::unique_ptr<TextCodec> codec = TextCodecICU::Create(iso2022jp, nullptr);
+TEST(TextCodecIcuTest, IgnorableCodePoint) {
+  WTF::TextEncoding iso2022jp("iso-2022-jp");
+  std::unique_ptr<TextCodec> codec = TextCodecIcu::Create(iso2022jp, nullptr);
   Vector<UChar> source;
   source.push_back('a');
   source.push_back(kZeroWidthJoinerCharacter);
-  std::string encoded =
-      codec->Encode(base::span(source), kEntitiesForUnencodables);
+  std::string encoded = codec->Encode(
+      base::span(source), UnencodableHandling::kEntitiesForUnencodables);
   EXPECT_EQ("a&#8205;", encoded);
   const String source2(u"ABC~¤•★星🌟星★•¤~XYZ");
-  const std::string encoded2(
-      codec->Encode(source2.Span16(), kEntitiesForUnencodables));
+  const std::string encoded2(codec->Encode(
+      source2.Span16(), UnencodableHandling::kEntitiesForUnencodables));
   const String source3(u"ABC~&#164;&#8226;★星&#127775;星★&#8226;&#164;~XYZ");
-  const std::string encoded3(
-      codec->Encode(source3.Span16(), kEntitiesForUnencodables));
+  const std::string encoded3(codec->Encode(
+      source3.Span16(), UnencodableHandling::kEntitiesForUnencodables));
   EXPECT_EQ(encoded3, encoded2);
   EXPECT_EQ(
       "ABC~&#164;&#8226;\x1B$B!z@1\x1B(B&#127775;\x1B$B@1!z\x1B(B&#8226;&#164;~"
       "XYZ",
       encoded2);
 }
-}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_user_defined.cc b/third_party/blink/renderer/platform/wtf/text/text_codec_user_defined.cc
index f1488f51..1bdd38b 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_user_defined.cc
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_user_defined.cc
@@ -35,7 +35,7 @@
 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
-namespace WTF {
+namespace blink {
 
 void TextCodecUserDefined::RegisterEncodingNames(
     EncodingNameRegistrar registrar) {
@@ -43,7 +43,7 @@
 }
 
 static std::unique_ptr<TextCodec> NewStreamingTextDecoderUserDefined(
-    const TextEncoding&,
+    const WTF::TextEncoding&,
     const void*) {
   return std::make_unique<TextCodecUserDefined>();
 }
@@ -71,7 +71,7 @@
 static std::string EncodeComplexUserDefined(
     base::span<const CharType> char_data,
     UnencodableHandling handling) {
-  DCHECK_NE(handling, kNoUnencodables);
+  DCHECK_NE(handling, UnencodableHandling::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;
@@ -139,4 +139,4 @@
   return EncodeCommon(characters, handling);
 }
 
-}  // namespace WTF
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_user_defined.h b/third_party/blink/renderer/platform/wtf/text/text_codec_user_defined.h
index 551b03ad..3b93ec5 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_user_defined.h
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_user_defined.h
@@ -28,8 +28,9 @@
 
 #include "third_party/blink/renderer/platform/wtf/text/text_codec.h"
 
-namespace WTF {
+namespace blink {
 
+// https://encoding.spec.whatwg.org/#x-user-defined
 class TextCodecUserDefined final : public TextCodec {
  public:
   static void RegisterEncodingNames(EncodingNameRegistrar);
@@ -47,6 +48,6 @@
   std::string EncodeCommon(base::span<const CharType>, UnencodableHandling);
 };
 
-}  // namespace WTF
+}  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_TEXT_CODEC_USER_DEFINED_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 7346b9929..aa9dee4 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
@@ -170,8 +170,8 @@
   blink::TextCodecUtf16::RegisterEncodingNames(AddToTextEncodingNameMap);
   blink::TextCodecUtf16::RegisterCodecs(AddToTextCodecMap);
 
-  TextCodecUserDefined::RegisterEncodingNames(AddToTextEncodingNameMap);
-  TextCodecUserDefined::RegisterCodecs(AddToTextCodecMap);
+  blink::TextCodecUserDefined::RegisterEncodingNames(AddToTextEncodingNameMap);
+  blink::TextCodecUserDefined::RegisterCodecs(AddToTextCodecMap);
 }
 
 static void ExtendTextCodecMaps() {
@@ -181,8 +181,8 @@
   TextCodecCJK::RegisterEncodingNames(AddToTextEncodingNameMap);
   TextCodecCJK::RegisterCodecs(AddToTextCodecMap);
 
-  TextCodecICU::RegisterEncodingNames(AddToTextEncodingNameMap);
-  TextCodecICU::RegisterCodecs(AddToTextCodecMap);
+  blink::TextCodecIcu::RegisterEncodingNames(AddToTextEncodingNameMap);
+  blink::TextCodecIcu::RegisterCodecs(AddToTextCodecMap);
 }
 
 std::unique_ptr<TextCodec> NewTextCodec(const TextEncoding& encoding) {
diff --git a/third_party/blink/renderer/platform/wtf/threading.cc b/third_party/blink/renderer/platform/wtf/threading.cc
index 3a4c9d42..0391861 100644
--- a/third_party/blink/renderer/platform/wtf/threading.cc
+++ b/third_party/blink/renderer/platform/wtf/threading.cc
@@ -39,7 +39,7 @@
 ThreadSpecific<Threading>* Threading::static_data_;
 
 Threading::Threading()
-    : cached_converter_icu_(new ICUConverterWrapper),
+    : cached_converter_icu_(new blink::IcuConverterWrapper),
       thread_id_(CurrentThread()) {}
 
 Threading::~Threading() = default;
diff --git a/third_party/blink/renderer/platform/wtf/threading.h b/third_party/blink/renderer/platform/wtf/threading.h
index 302a200..7d8e84cb 100644
--- a/third_party/blink/renderer/platform/wtf/threading.h
+++ b/third_party/blink/renderer/platform/wtf/threading.h
@@ -41,6 +41,10 @@
 #include "third_party/blink/renderer/platform/wtf/type_traits.h"
 #include "third_party/blink/renderer/platform/wtf/wtf_export.h"
 
+namespace blink {
+struct IcuConverterWrapper;
+}
+
 namespace WTF {
 
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_WIN)
@@ -59,8 +63,6 @@
 WTF_EXPORT void SetIsBeforeThreadCreatedForTest();
 #endif
 
-struct ICUConverterWrapper;
-
 class WTF_EXPORT Threading {
   DISALLOW_NEW();
 
@@ -70,7 +72,9 @@
   Threading& operator=(const Threading&) = delete;
   ~Threading();
 
-  ICUConverterWrapper& CachedConverterICU() { return *cached_converter_icu_; }
+  blink::IcuConverterWrapper& CachedConverterIcu() {
+    return *cached_converter_icu_;
+  }
 
   base::PlatformThreadId ThreadId() const { return thread_id_; }
 
@@ -82,7 +86,7 @@
 #endif
 
  private:
-  std::unique_ptr<ICUConverterWrapper> cached_converter_icu_;
+  std::unique_ptr<blink::IcuConverterWrapper> cached_converter_icu_;
 
   base::PlatformThreadId thread_id_;
 
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 8d2a06c..36659968 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2763,6 +2763,28 @@
 crbug.com/413411328 external/wpt/css/css-values/urls/referrer-policy/unsafe-url/url-image-referrerpolicy-same-origin.sub.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/425041677 [ Mac ] external/wpt/svg/text/reftests/text-context-fill.svg [ Failure ]
+crbug.com/425041677 [ Win ] external/wpt/svg/text/reftests/text-context-fill.svg [ Failure ]
+crbug.com/425056982 [ Mac14 ] virtual/threaded-prefer-compositing/external/wpt/css/cssom-view/devicePixelRatio-undisplayed-iframe.tentative.html [ Crash ]
+crbug.com/425118323 [ Mac14 ] virtual/threaded-preload-scanner/external/wpt/html/semantics/scripting-1/the-script-element/async_001.htm [ Timeout ]
+crbug.com/425118323 [ Mac14 ] virtual/threaded-preload-scanner/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/002.html [ Timeout ]
+crbug.com/425118323 [ Mac14 ] virtual/threaded-preload-scanner/external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/008.html [ Crash ]
+crbug.com/425118323 [ Mac14 ] virtual/threaded-preload-scanner/external/wpt/html/semantics/scripting-1/the-script-element/json-module/charset-bom.any.worker.html [ Timeout ]
+crbug.com/425118323 [ Mac14 ] virtual/threaded-preload-scanner/external/wpt/html/semantics/scripting-1/the-script-element/json-module/cors-crossorigin-requests.html [ Timeout ]
+crbug.com/425118323 [ Mac14 ] virtual/threaded-preload-scanner/external/wpt/html/semantics/scripting-1/the-script-element/load-error-events-1.html [ Timeout ]
+crbug.com/425118323 [ Mac14 ] virtual/threaded-preload-scanner/external/wpt/html/semantics/scripting-1/the-script-element/load-error-events-3.html [ Timeout ]
+crbug.com/425118323 [ Mac14 ] virtual/threaded-preload-scanner/external/wpt/html/semantics/scripting-1/the-script-element/module/crossorigin.html [ Crash ]
+crbug.com/425118323 [ Mac14 ] virtual/threaded-preload-scanner/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url-workers.window.html [ Timeout ]
+crbug.com/425118323 [ Mac14 ] virtual/threaded-preload-scanner/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.worker.html [ Timeout ]
+crbug.com/425118323 [ Mac14 ] virtual/threaded-preload-scanner/external/wpt/html/semantics/scripting-1/the-script-element/module/import-meta/import-meta-resolve-importmap.html [ Timeout ]
+crbug.com/425145242 [ Mac14 ] virtual/unified-autoplay/external/wpt/feature-policy/feature-policy-frame-policy-allowed-for-some-override.https.sub.html [ Skip Timeout ]
+crbug.com/425145242 [ Mac14 ] virtual/unified-autoplay/external/wpt/feature-policy/reporting/payment-reporting.https.html [ Timeout ]
+crbug.com/425145242 [ Mac14 ] virtual/unified-autoplay/external/wpt/feature-policy/reporting/xr-reporting.https.html [ Timeout ]
+crbug.com/425041678 [ Mac14 ] virtual/unload-allowed/external/wpt/battery-status/no-leak-on-detached-use.https.html [ Timeout ]
+crbug.com/424597869 [ Mac14 ] virtual/unload-allowed/external/wpt/html/browsers/browsing-the-web/unloading-documents/003.html [ Timeout ]
+crbug.com/424597869 [ Mac14 ] virtual/unload-allowed/external/wpt/html/browsers/browsing-the-web/unloading-documents/unload/unload-main-frame-cross-origin.window.html [ Timeout ]
+crbug.com/425118323 [ Mac14 ] virtual/unload-allowed/external/wpt/html/infrastructure/urls/base-url/document-base-url-window-initiator-is-not-opener.https.window.html [ Timeout ]
+crbug.com/425056982 [ Mac14 ] virtual/wide-gamut/external/wpt/css/css-images/gradient/gradient-eval-001.html [ Timeout ]
 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 [ Failure Pass Timeout ]
 crbug.com/424229863 [ Android ] external/wpt/webdriver/tests/bidi/external/bluetooth/disable_simulation/context.py [ Failure ]
@@ -4939,7 +4961,6 @@
 crbug.com/845610 [ Win ] http/tests/inspector-protocol/target/target-browser-context.js [ Failure Pass ]
 
 # Sheriff 2018-06-07
-crbug.com/41393183 http/tests/devtools/editor/text-editor-enter-behaviour.js [ Failure Pass Timeout ]
 crbug.com/41392978 http/tests/devtools/elements/styles-4/stylesheet-source-url-comment.js [ Failure Pass Timeout ]
 
 # User Activation
@@ -5059,7 +5080,6 @@
 crbug.com/1021627 [ Mac ] fast/dom/rtl-scroll-to-leftmost-and-resize.html [ Failure Pass Timeout ]
 
 # Sheriff 2019-03-28
-crbug.com/41449570 http/tests/devtools/editor/text-editor-search-switch-editor.js [ Failure Pass ]
 crbug.com/41449571 http/tests/devtools/elements/styles-2/paste-property.js [ Crash Pass Timeout ]
 
 # Sheriff 2019-04-09
@@ -6496,6 +6516,7 @@
 
 # Virtual suite mostly fails while feature is in development.
 crbug.com/40253999 virtual/indexeddb_sqlite/* [ Skip Timeout ]
+
 crbug.com/40253999 virtual/indexeddb_sqlite/external/wpt/IndexedDB/abort-in-initial-upgradeneeded.any.html [ Pass ]
 crbug.com/40253999 virtual/indexeddb_sqlite/external/wpt/IndexedDB/abort-in-initial-upgradeneeded.any.serviceworker.html [ Pass ]
 crbug.com/40253999 virtual/indexeddb_sqlite/external/wpt/IndexedDB/abort-in-initial-upgradeneeded.any.sharedworker.html [ Pass ]
@@ -6505,6 +6526,23 @@
 crbug.com/40253999 virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbobjectstore_count.any.sharedworker.html [ Pass ]
 crbug.com/40253999 virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbobjectstore_count.any.worker.html [ Pass ]
 
+crbug.com/40253999 virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbcursor-direction-objectstore-keyrange.any.html [ Pass ]
+crbug.com/40253999 virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbcursor-direction-objectstore.any.html [ Pass ]
+crbug.com/40253999 virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbcursor_advance_objectstore.any.html [ Pass ]
+crbug.com/40253999 virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbcursor_continue_objectstore.any.html [ Pass ]
+crbug.com/40253999 virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbcursor_update_objectstore.any.html [ Pass ]
+crbug.com/40253999 virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbobjectstore_openCursor.any.html [ Pass ]
+crbug.com/40253999 virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbobjectstore_openKeyCursor.any.html [ Pass ]
+crbug.com/40253999 virtual/indexeddb_sqlite/external/wpt/IndexedDB/interleaved-cursors-large.any.html [ Pass ]
+crbug.com/40253999 virtual/indexeddb_sqlite/external/wpt/IndexedDB/interleaved-cursors-small.any.html [ Pass ]
+crbug.com/40253999 virtual/indexeddb_sqlite/external/wpt/IndexedDB/parallel-cursors-upgrade.any.html [ Pass ]
+
+crbug.com/40253999 virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbobjectstore-getAll-enforcerange.any.html [ Pass ]
+crbug.com/40253999 virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbobjectstore-getAllKeys-enforcerange.any.html [ Pass ]
+crbug.com/40253999 virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbobjectstore_getAll.any.html [ Pass ]
+crbug.com/40253999 virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbobjectstore_getAllKeys.any.html [ Pass ]
+crbug.com/40253999 virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbobjectstore_getAllRecords.tentative.any.html [ Pass ]
+
 # Sheriff 2022-08-06
 crbug.com/1350337 [ Linux ] external/wpt/web-locks/query-ordering.tentative.https.html [ Failure Pass ]
 
@@ -9141,3 +9179,6 @@
 
 # Gardener 2025-06-12
 crbug.com/422636456 [ Mac ] http/tests/inspector-protocol/network/navigate-iframe-out2in.js [ Pass Timeout ]
+
+# Gardener 2025-06-16
+crbug.com/424918655 [ Mac ] external/wpt/soft-navigation-heuristics/lcp/tentative/contracted-image.html [ Failure Pass ]
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index b255154..75a49e9f 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -7827,6 +7827,13 @@
           null,
           {}
          ]
+        ],
+        "offscreencanvas.transfercontrol.to.offscreen-crash.html": [
+         "949f49c1065cb949cc146d2246a0159c777cc272",
+         [
+          null,
+          {}
+         ]
         ]
        }
       },
@@ -317298,6 +317305,19 @@
         {}
        ]
       ],
+      "text-context-fill.svg": [
+       "0262deef3b2f7a69bfa825730bb74e0c19a6f38a",
+       [
+        null,
+        [
+         [
+          "/svg/text/reftests/text-context-fill-ref.svg",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "text-font-face-load-image.html": [
        "eb9a5fe4357373e3be74293c66f14f621a911405",
        [
@@ -431017,6 +431037,10 @@
        "3d3968fa4923436e760dd80b05af292a615cffcb",
        []
       ],
+      "text-context-fill-ref.svg": [
+       "a8fbd1964ee492b9ac54648c14419daeb45b4840",
+       []
+      ],
       "text-font-face-load-image-ref.html": [
        "5a668b313e5eced93cc0358d84a75a56f5b76e8c",
        []
@@ -709272,6 +709296,15 @@
       ]
      ]
     },
+    "canvas-click.html": [
+     "a058a621a0e2ed048954417a77deb15a887bd6e0",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
     "caret": {
      "empty-elements.html": [
       "328188c957bd738af419d54e4cd5c741cecc827f",
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-transition-attr.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-transition-attr.tentative.html
similarity index 94%
rename from third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-transition-attr.html
rename to third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-transition-attr.tentative.html
index 540ab89..824c75c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-transition-attr.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/anchor-transition-attr.tentative.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <title>CSS Anchor Positioning: Transition when the anchor attribute changes</title>
 <link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/">
-<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/9598">
+<link rel="help" href="https://github.com/whatwg/html/pull/9144">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <style>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-area-scroll-adjust.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-area-scroll-adjust.html
index 497b526f..128f23f9 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-area-scroll-adjust.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/position-area-scroll-adjust.html
@@ -9,11 +9,13 @@
     overflow: auto;
   }
   #anchor {
+    anchor-name: --a;
     background: green;
     width: 200px;
     height: 100px;
   }
   #anchored {
+    position-anchor: --a;
     position-area: bottom;
     margin: 0;
     padding: 0;
@@ -28,7 +30,7 @@
 <div id="scroller">
   <div class="filler"></div>
   <div id="anchor" popovertarget="anchored"></div>
-  <div id="anchored" anchor="anchor" popover></div>
+  <div id="anchored" popover></div>
   <div class="filler"></div>
   <div class="filler"></div>
 </div>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfercontrol.to.offscreen-crash.html b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfercontrol.to.offscreen-crash.html
new file mode 100644
index 0000000..949f49c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfercontrol.to.offscreen-crash.html
@@ -0,0 +1,7 @@
+<title>Transfer Canvas without Context</title>
+<canvas id="canvas"></canvas>
+
+<script>
+canvas.transferControlToOffscreen();
+canvas.toBlob(_ => {});
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/selection/canvas-click.html b/third_party/blink/web_tests/external/wpt/selection/canvas-click.html
new file mode 100644
index 0000000..a058a621a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/selection/canvas-click.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Clicking on a text-selectable canvas should not select it</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.com" title="Mozilla">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1969829">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<style>
+  :root { user-select: none }
+  canvas {
+    user-select: text;
+    outline: 2px solid hotpink;
+    background-color: green;
+    width: 200px;
+    height: 200px;
+  }
+</style>
+Clicking the green square should not select it.<br>
+<canvas></canvas>
+<script>
+promise_test(async function() {
+  await test_driver.click(document.querySelector("canvas"));
+  assert_true(getSelection().isCollapsed, "Clicking a canvas shouldn't generate a non-collapsed selection");
+});
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/svg/text/reftests/text-context-fill-ref.svg b/third_party/blink/web_tests/external/wpt/svg/text/reftests/text-context-fill-ref.svg
new file mode 100644
index 0000000..a8fbd196
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/text/reftests/text-context-fill-ref.svg
@@ -0,0 +1,15 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="150" height="100">
+  <style>
+    text {
+      font-family: Ahem;
+      font-size: 9px;
+    }
+  </style>
+  <defs>
+      <marker id="m" viewBox="0 0 25 10" refY="5" markerWidth="125" refX="10" markerHeight="50">
+          <text x="12" y="8" fill="green">XXX</text>
+      </marker>
+  </defs>
+  <line y2="30" x2="50" fill="green" marker-end="url(#m)" />
+  <line y2="30" x2="50" stroke="green" />
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/svg/text/reftests/text-context-fill.svg b/third_party/blink/web_tests/external/wpt/svg/text/reftests/text-context-fill.svg
new file mode 100644
index 0000000..0262dee
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/svg/text/reftests/text-context-fill.svg
@@ -0,0 +1,18 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml" width="150" height="100">
+  <title>text with context-fill</title>
+  <h:link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1969466"/>
+  <h:link rel="match" href="text-context-fill-ref.svg"/>
+  <h:link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+  <style>
+    text {
+      font-family: Ahem;
+      font-size: 9px;
+    }
+  </style>
+  <defs>
+      <marker id="m" viewBox="0 0 25 10" refY="5" markerWidth="125" refX="10" markerHeight="50">
+          <text x="12" y="8" fill="context-stroke">XXX</text>
+      </marker>
+  </defs>
+  <line y2="30" x2="50" stroke="green" marker-end="url(#m)" />
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/qdq_subgraph.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/qdq_subgraph.https.any.js
index b578270..b7bcdc0 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/qdq_subgraph.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/conformance_tests/qdq_subgraph.https.any.js
@@ -2931,6 +2931,82 @@
       }
     }
   },
+  {
+    'name': 'quantized clamp with emulation',
+    'graph': {
+      'inputs': {
+        'input': {
+          'data': [
+            8.413617134094238, 6.108623504638672, 3.549168109893799,
+            1.6811466217041016, -0.1988269537687301, -8.413617134094238,
+          ],
+          'descriptor': {shape: [2, 3], dataType: 'float32'},
+          'constant': false
+        },
+        'scale': {
+          'data': [0.343092918395996],
+          'descriptor': {shape: [1], dataType: 'float32'},
+          'constant': true
+        },
+        'zeroPoint': {
+          'data': [0],
+          'descriptor': {shape: [1], dataType: 'int8'},
+          'constant': true
+        },
+      },
+      'operators': [
+        {
+          'name': 'quantizeLinear',
+          'arguments': [
+            {'input': 'input'},
+            {'scale': 'scale', 'zeroPoint': 'zeroPoint'}
+          ],
+          'outputs': 'quantizedInput'
+        },
+        {
+          'name': 'dequantizeLinear',
+          'arguments': [
+            {'input': 'quantizedInput'},
+            {'scale': 'scale', 'zeroPoint': 'zeroPoint'}
+          ],
+          'outputs': 'dequantizedInput'
+        },
+        {
+          'name': 'clamp',
+          'arguments': [
+            {'input': 'dequantizedInput'},
+            {'options': {'minValue': -8, 'maxValue': 8}}
+          ],
+          'outputs': 'clampOutput'
+        },
+        {
+          'name': 'quantizeLinear',
+          'arguments': [
+            {'input': 'clampOutput'},
+            {'scale': 'scale', 'zeroPoint': 'zeroPoint'}
+          ],
+          'outputs': 'quantizedClampOutput'
+        },
+        {
+          'name': 'dequantizeLinear',
+          'arguments': [
+            {'input': 'quantizedClampOutput'},
+            {'scale': 'scale', 'zeroPoint': 'zeroPoint'}
+          ],
+          'outputs': 'output'
+        }
+      ],
+      'expectedOutputs': {
+        'output': {
+          'data': [
+            7.89113712310791, 6.17567253112793, 3.430929183959961,
+            1.7154645919799805, -0.3430929183959961, -7.89113712310791,
+          ],
+          'descriptor': {shape: [2, 3], dataType: 'float32'}
+        }
+      }
+    }
+  },
 ];
 
 if (navigator.ml) {
diff --git a/third_party/blink/web_tests/fast/borders/cornerShapeSingleRadius-expected.png b/third_party/blink/web_tests/fast/borders/cornerShapeSingleRadius-expected.png
new file mode 100644
index 0000000..76d075c
--- /dev/null
+++ b/third_party/blink/web_tests/fast/borders/cornerShapeSingleRadius-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/fast/borders/cornerShapeSingleRadius.html b/third_party/blink/web_tests/fast/borders/cornerShapeSingleRadius.html
new file mode 100644
index 0000000..cca4661
--- /dev/null
+++ b/third_party/blink/web_tests/fast/borders/cornerShapeSingleRadius.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<style>
+div {
+	width: 190px;
+	height: 190px;
+	box-sizing: border-box;
+	border-top-left-radius: 87px 0px;
+	border-top-right-radius: 0px 31px;
+	border-bottom-right-radius:  43px;
+	border-bottom-left-radius: 87px 1px;
+	border: 5px solid black;
+	corner-shape: scoop;
+	background-color: #0f0;
+}
+</style>
+<div></div>
diff --git a/third_party/blink/web_tests/flag-specific/enable-skia-graphite/external/wpt/soft-navigation-heuristics/lcp/tentative/contracted-image-expected.txt b/third_party/blink/web_tests/flag-specific/enable-skia-graphite/external/wpt/soft-navigation-heuristics/lcp/tentative/contracted-image-expected.txt
new file mode 100644
index 0000000..5b37deb
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/enable-skia-graphite/external/wpt/soft-navigation-heuristics/lcp/tentative/contracted-image-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+All subtests passed and are omitted for brevity.
+See https://chromium.googlesource.com/chromium/src/+/HEAD/docs/testing/writing_web_tests.md#Text-Test-Baselines for details.
+Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/http/tests/devtools/DIR_METADATA b/third_party/blink/web_tests/http/tests/devtools/DIR_METADATA
index 25fe1f0c..f6ff614 100644
--- a/third_party/blink/web_tests/http/tests/devtools/DIR_METADATA
+++ b/third_party/blink/web_tests/http/tests/devtools/DIR_METADATA
@@ -1,2 +1,4 @@
 team_email: "devtools-dev@chromium.org"
-
+buganizer_public: {
+  component_id: 1457055
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/devtools/console/DIR_METADATA b/third_party/blink/web_tests/http/tests/devtools/console/DIR_METADATA
new file mode 100644
index 0000000..070fa3c
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/console/DIR_METADATA
@@ -0,0 +1,4 @@
+team_email: "devtools-dev@chromium.org"
+buganizer_public: {
+  component_id: 1519297
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/devtools/domdebugger/DIR_METADATA b/third_party/blink/web_tests/http/tests/devtools/domdebugger/DIR_METADATA
new file mode 100644
index 0000000..7c82dcd
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/domdebugger/DIR_METADATA
@@ -0,0 +1,4 @@
+team_email: "devtools-dev@chromium.org"
+buganizer_public: {
+  component_id: 1457255
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/devtools/editor/resources/search-me.js b/third_party/blink/web_tests/http/tests/devtools/editor/resources/search-me.js
deleted file mode 100644
index c376ab0..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/editor/resources/search-me.js
+++ /dev/null
@@ -1,265 +0,0 @@
-function logMe()
-{
-    console.log(0);
-    console.log(1);
-    console.log(2);
-    console.log(3);
-    console.log(4);
-    console.log(5);
-    console.log(6);
-    console.log(7);
-    console.log(8);
-    console.log(9);
-    console.log(10);
-    console.log(11);
-    console.log(12);
-    console.log(13);
-    console.log(14);
-    console.log(15);
-    console.log(16);
-    console.log(17);
-    console.log(18);
-    console.log(19);
-    console.log(20);
-    console.log(21);
-    console.log(22);
-    console.log(23);
-    console.log(24);
-    console.log(25);
-    console.log(26);
-    console.log(27);
-    console.log(28);
-    console.log(29);
-    console.log(30);
-    console.log(31);
-    console.log(32);
-    console.log(33);
-    console.log(34);
-    console.log(35);
-    console.log(36);
-    console.log(37);
-    console.log(38);
-    console.log(39);
-    console.log(40);
-    console.log(41);
-    console.log(42);
-    console.log(43);
-    console.log(44);
-    console.log(45);
-    console.log(46);
-    console.log(47);
-    console.log(48);
-    console.log(49);
-    console.log(50);
-    console.log(51);
-    console.log(52);
-    console.log(53);
-    console.log(54);
-    console.log(55);
-    console.log(56);
-    console.log(57);
-    console.log(58);
-    console.log(59);
-    console.log(60);
-    console.log(61);
-    console.log(62);
-    console.log(63);
-    console.log(64);
-    console.log(65);
-    console.log(66);
-    console.log(67);
-    console.log(68);
-    console.log(69);
-    console.log(70);
-    console.log(71);
-    console.log(72);
-    console.log(73);
-    console.log(74);
-    console.log(75);
-    console.log(76);
-    console.log(77);
-    console.log(78);
-    console.log(79);
-    console.log(80);
-    console.log(81);
-    console.log(82);
-    console.log(83);
-    console.log(84);
-    console.log(85);
-    console.log(86);
-    console.log(87);
-    console.log(88);
-    console.log(89);
-    console.log(90);
-    console.log(91);
-    console.log(92);
-    console.log(93);
-    console.log(94);
-    console.log(95);
-    console.log(96);
-    console.log(97);
-    console.log(98);
-    console.log(99);
-    console.log(100);
-    console.log(101);
-    console.log(102);
-    console.log(103);
-    console.log(104);
-    console.log(105);
-    console.log(106);
-    console.log(107);
-    console.log(108);
-    console.log(109);
-    console.log(110);
-    console.log(111);
-    console.log(112);
-    console.log(113);
-    console.log(114);
-    console.log(115);
-    console.log(116);
-    console.log(117);
-    console.log(118);
-    console.log(119);
-    console.log(120);
-    console.log(121);
-    console.log(122);
-    console.log(123);
-    console.log(124);
-    console.log(125);
-    console.log(126);
-    console.log(127);
-    console.log(128);
-    console.log(129);
-    console.log(130);
-    console.log(131);
-    console.log(132);
-    console.log(133);
-    console.log(134);
-    console.log(135);
-    console.log(136);
-    console.log(137);
-    console.log(138);
-    console.log(139);
-    console.log(140);
-    console.log(141);
-    console.log(142);
-    console.log(143);
-    console.log(144);
-    console.log(145);
-    console.log(146);
-    console.log(147);
-    console.log(148);
-    console.log(149);
-    console.log(150);
-    console.log(151);
-    console.log(152);
-    console.log(153);
-    console.log(154);
-    console.log(155);
-    console.log(156);
-    console.log(157);
-    console.log(158);
-    console.log(159);
-    console.log(160);
-    console.log(161);
-    console.log(162);
-    console.log(163);
-    console.log(164);
-    console.log(165);
-    console.log(166);
-    console.log(167);
-    console.log(168);
-    console.log(169);
-    console.log(170);
-    console.log(171);
-    console.log(172);
-    console.log(173);
-    console.log(174);
-    console.log(175);
-    console.log(176);
-    console.log(177);
-    console.log(178);
-    console.log(179);
-    console.log(180);
-    console.log(181);
-    console.log(182);
-    console.log(183);
-    console.log(184);
-    console.log(185);
-    console.log(186);
-    console.log(187);
-    console.log(188);
-    console.log(189);
-    console.log(190);
-    console.log(191);
-    console.log(192);
-    console.log(193);
-    console.log(194);
-    console.log(195);
-    console.log(196);
-    console.log(197);
-    console.log(198);
-    console.log(199);
-
-    // FINDME
-
-    console.log(200);
-    console.log(201);
-    console.log(202);
-    console.log(203);
-    console.log(204);
-    console.log(205);
-    console.log(206);
-    console.log(207);
-    console.log(208);
-    console.log(209);
-    console.log(210);
-    console.log(211);
-    console.log(212);
-    console.log(213);
-    console.log(214);
-    console.log(215);
-    console.log(216);
-    console.log(217);
-    console.log(218);
-    console.log(219);
-    console.log(220);
-    console.log(221);
-    console.log(222);
-    console.log(223);
-    console.log(224);
-    console.log(225);
-    console.log(226);
-    console.log(227);
-    console.log(228);
-    console.log(229);
-    console.log(230);
-    console.log(231);
-    console.log(232);
-    console.log(233);
-    console.log(234);
-    console.log(235);
-    console.log(236);
-    console.log(237);
-    console.log(238);
-    console.log(239);
-    console.log(240);
-    console.log(241);
-    console.log(242);
-    console.log(243);
-    console.log(244);
-    console.log(245);
-    console.log(246);
-    console.log(247);
-    console.log(248);
-    console.log(249);
-    console.log(250);
-    console.log(251);
-    console.log(252);
-    console.log(253);
-    console.log(254);
-    console.log(255);
-    console.log(256);
-}
-
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/editor/text-editor-enter-behaviour-expected.txt b/third_party/blink/web_tests/http/tests/devtools/editor/text-editor-enter-behaviour-expected.txt
deleted file mode 100644
index c4ff696b..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/editor/text-editor-enter-behaviour-expected.txt
+++ /dev/null
@@ -1,158 +0,0 @@
-This test checks text editor enter behaviour.
-
-
-Running: testEnterInTheLineEnd
-function.testFunction()
-{
-....var.a.=.100;
-....|
-....var.b.=.200;
-....var.c.=.(a.+.b)./.2;
-....console.log(a);
-....console.log(b);
-....console.log(c);
-....if.(a.>.b).{
-........console.log(a);
-....}
-....return.c;
-}
-
-Running: testEnterAfterOpenCurlyBrace
-function.testFunction()
-{
-....|
-....var.a.=.100;
-....var.b.=.200;
-....var.c.=.(a.+.b)./.2;
-....console.log(a);
-....console.log(b);
-....console.log(c);
-....if.(a.>.b).{
-........console.log(a);
-....}
-....return.c;
-}
-
-Running: testEnterInTheMiddleOfLine
-function.testFunction()
-{
-....var.
-....|a.=.100;
-....var.b.=.200;
-....var.c.=.(a.+.b)./.2;
-....console.log(a);
-....console.log(b);
-....console.log(c);
-....if.(a.>.b).{
-........console.log(a);
-....}
-....return.c;
-}
-
-Running: testEnterInTheBeginningOfTheLine
-function.testFunction()
-{
-
-|....var.a.=.100;
-....var.b.=.200;
-....var.c.=.(a.+.b)./.2;
-....console.log(a);
-....console.log(b);
-....console.log(c);
-....if.(a.>.b).{
-........console.log(a);
-....}
-....return.c;
-}
-
-Running: testEnterWithTheSelection
-function.testFunction()
-{
-..
-..|var.a.=.100;
-....var.b.=.200;
-....var.c.=.(a.+.b)./.2;
-....console.log(a);
-....console.log(b);
-....console.log(c);
-....if.(a.>.b).{
-........console.log(a);
-....}
-....return.c;
-}
-
-Running: testEnterWithReversedSelection
-function.testFunction()
-{
-..
-..|var.a.=.100;
-....var.b.=.200;
-....var.c.=.(a.+.b)./.2;
-....console.log(a);
-....console.log(b);
-....console.log(c);
-....if.(a.>.b).{
-........console.log(a);
-....}
-....return.c;
-}
-
-Running: testEnterWithTheMultiLineSelection
-function.testFunction()
-{
-
-|if.(a.>.b).{
-........console.log(a);
-....}
-....return.c;
-}
-
-Running: testEnterWithFullLineSelection
-function.testFunction()
-{
-
-|....var.b.=.200;
-....var.c.=.(a.+.b)./.2;
-....console.log(a);
-....console.log(b);
-....console.log(c);
-....if.(a.>.b).{
-........console.log(a);
-....}
-....return.c;
-}
-
-Running: testEnterBeforeOpenBrace
-function.testFunction()
-{
-....var.a.=.100;
-....var.b.=.200;
-....var.c.=.(a.+.b)./.2;
-....console.log(a);
-....console.log(b);
-....console.log(c);
-
-|....if.(a.>.b).{
-........console.log(a);
-....}
-....return.c;
-}
-
-Running: testEnterMultiCursor
-function.testFunction()
-{
-....var.a.=.100;
-
-|....var.b.=.200;
-....var.c.=.(a.+.b)./.2;
-.
-.|...console.log(a);
-..
-..|..console.log(b);
-....console.log(c);
-....if.(a.>.b).{
-........console.log(a);
-....}
-....return.c;
-}
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/editor/text-editor-enter-behaviour.js b/third_party/blink/web_tests/http/tests/devtools/editor/text-editor-enter-behaviour.js
deleted file mode 100644
index e03263a..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/editor/text-editor-enter-behaviour.js
+++ /dev/null
@@ -1,116 +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.
-
-import {TestRunner} from 'test_runner';
-import {SourcesTestRunner} from 'sources_test_runner';
-
-import * as TextUtils from 'devtools/models/text_utils/text_utils.js';
-
-(async function() {
-  TestRunner.addResult(`This test checks text editor enter behaviour.\n`);
-  await TestRunner.showPanel('sources');
-  await TestRunner.evaluateInPagePromise(`
-      function codeSnippet() {
-          return document.getElementById("codeSnippet").textContent;
-      }
-  `);
-
-// clang-format off
-function testFunction()
-{
-    var a = 100;
-    var b = 200;
-    var c = (a + b) / 2;
-    console.log(a);
-    console.log(b);
-    console.log(c);
-    if (a > b) {
-        console.log(a);
-    }
-    return c;
-}
-// clang-format on
-
-  var textEditor = SourcesTestRunner.createTestEditor();
-  textEditor.setMimeType('text/javascript');
-  textEditor.setReadOnly(false);
-  textEditor.element.focus();
-
-  TestRunner.runTestSuite([
-    function testEnterInTheLineEnd(next) {
-      textEditor.setText(testFunction.toString());
-      var line = textEditor.line(2);
-      textEditor.setSelection(TextUtils.TextRange.TextRange.createFromLocation(2, line.length));
-      hitEnterDumpTextAndNext(next);
-    },
-
-    function testEnterAfterOpenCurlyBrace(next) {
-      textEditor.setText(testFunction.toString());
-      var line = textEditor.line(1);
-      textEditor.setSelection(TextUtils.TextRange.TextRange.createFromLocation(1, line.length));
-      hitEnterDumpTextAndNext(next);
-    },
-
-    function testEnterInTheMiddleOfLine(next) {
-      textEditor.setText(testFunction.toString());
-      var line = textEditor.line(2);
-      textEditor.setSelection(TextUtils.TextRange.TextRange.createFromLocation(2, line.length / 2));
-      hitEnterDumpTextAndNext(next);
-    },
-
-    function testEnterInTheBeginningOfTheLine(next) {
-      textEditor.setText(testFunction.toString());
-      textEditor.setSelection(TextUtils.TextRange.TextRange.createFromLocation(2, 0));
-      hitEnterDumpTextAndNext(next);
-    },
-
-    function testEnterWithTheSelection(next) {
-      textEditor.setText(testFunction.toString());
-      textEditor.setSelection(new TextUtils.TextRange.TextRange(2, 2, 2, 4));
-      hitEnterDumpTextAndNext(next);
-    },
-
-    function testEnterWithReversedSelection(next) {
-      textEditor.setText(testFunction.toString());
-      textEditor.setSelection(new TextUtils.TextRange.TextRange(2, 4, 2, 2));
-      hitEnterDumpTextAndNext(next);
-    },
-
-    function testEnterWithTheMultiLineSelection(next) {
-      textEditor.setText(testFunction.toString());
-      textEditor.setSelection(new TextUtils.TextRange.TextRange(2, 0, 8, 4));
-      hitEnterDumpTextAndNext(next);
-    },
-
-    function testEnterWithFullLineSelection(next) {
-      textEditor.setText(testFunction.toString());
-      textEditor.setSelection(new TextUtils.TextRange.TextRange(2, 0, 3, 0));
-      hitEnterDumpTextAndNext(next);
-    },
-
-    function testEnterBeforeOpenBrace(next) {
-      textEditor.setText(testFunction.toString());
-      textEditor.setSelection(new TextUtils.TextRange.TextRange(8, 0, 8, 0));
-      hitEnterDumpTextAndNext(next);
-    },
-
-    function testEnterMultiCursor(next) {
-      textEditor.setText(testFunction.toString());
-      SourcesTestRunner.setLineSelections(textEditor, [
-        {line: 3, column: 0},
-        {line: 5, column: 1},
-        {line: 6, column: 2},
-      ]);
-      hitEnterDumpTextAndNext(next);
-    }
-  ]);
-
-  function hitEnterDumpTextAndNext(next) {
-    SourcesTestRunner.fakeKeyEvent(textEditor, 'Enter', null, step2);
-    function step2() {
-      SourcesTestRunner.dumpTextWithSelection(textEditor, true);
-      next();
-    }
-  }
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/editor/text-editor-search-switch-editor-expected.txt b/third_party/blink/web_tests/http/tests/devtools/editor/text-editor-search-switch-editor-expected.txt
deleted file mode 100644
index fe7e1bb4..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/editor/text-editor-search-switch-editor-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-Tests that switching editor tabs after searching does not affect editor selection and viewport.
-
-Performing search...
-Recording editor viewport after searching...
-Recording editor viewport after switching tabs...
-Comparing viewports...
-  viewports match, SUCCESS
-Comparing selection ranges...
-  original selection range: {"startLine":203,"startColumn":7,"endLine":203,"endColumn":7}
-  current selection range: {"startLine":203,"startColumn":7,"endLine":203,"endColumn":7}
-
diff --git a/third_party/blink/web_tests/http/tests/devtools/editor/text-editor-search-switch-editor.js b/third_party/blink/web_tests/http/tests/devtools/editor/text-editor-search-switch-editor.js
deleted file mode 100644
index 1d3c3d11..0000000
--- a/third_party/blink/web_tests/http/tests/devtools/editor/text-editor-search-switch-editor.js
+++ /dev/null
@@ -1,64 +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.
-
-import {TestRunner} from 'test_runner';
-import {SourcesTestRunner} from 'sources_test_runner';
-
-import * as Sources from 'devtools/panels/sources/sources.js';
-
-(async function() {
-  TestRunner.addResult(
-      `Tests that switching editor tabs after searching does not affect editor selection and viewport.\n`);
-  await TestRunner.showPanel('sources');
-  await TestRunner.addScriptTag('../sources/debugger/resources/edit-me.js');
-  await TestRunner.addScriptTag('resources/search-me.js');
-
-  var textEditor;
-  var searchString = 'FINDME';
-  var searchableView = Sources.SourcesPanel.SourcesPanel.instance().searchableView();
-  var sourceFrame;
-  SourcesTestRunner.showScriptSource('search-me.js', didShowScriptSource);
-
-  function didShowScriptSource(shownSourceFrame) {
-    sourceFrame = shownSourceFrame;
-    textEditor = sourceFrame.textEditor;
-    // We are probably still updating the editor in current callstack, so postpone the test execution.
-    queueMicrotask(() => {
-      textEditorUpdated();
-    });
-  }
-
-  function textEditorUpdated(sourceFrame) {
-    searchableView.showSearchField();
-
-    TestRunner.addResult('Performing search...');
-    searchableView.searchInputElement.value = searchString;
-    searchableView.performSearch(true, true);
-    TestRunner.addResult('Recording editor viewport after searching...');
-
-    var originalViewport = {from: textEditor.firstVisibleLine(), to: textEditor.lastVisibleLine()};
-    var originalSelectionRange = textEditor.selection();
-
-    SourcesTestRunner.showScriptSource('edit-me.js', didShowAnotherSource);
-
-    function didShowAnotherSource(anotherSourceFrame) {
-      SourcesTestRunner.showScriptSource('search-me.js', didShowScriptSourceAgain);
-    }
-
-    function didShowScriptSourceAgain(sourceFrame) {
-      TestRunner.addResult('Recording editor viewport after switching tabs...');
-      var newViewport = {from: textEditor.firstVisibleLine(), to: textEditor.lastVisibleLine()};
-      var newSelectionRange = textEditor.selection();
-      TestRunner.addResult('Comparing viewports...');
-      if (originalViewport.from === newViewport.from && originalViewport.to === newViewport.to)
-        TestRunner.addResult('  viewports match, SUCCESS');
-      else
-        TestRunner.addResult('  viewports do not match, FAIL');
-      TestRunner.addResult('Comparing selection ranges...');
-      TestRunner.addResult('  original selection range: ' + originalSelectionRange.toString());
-      TestRunner.addResult('  current selection range: ' + newSelectionRange.toString());
-      TestRunner.completeTest();
-    }
-  }
-})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/DIR_METADATA b/third_party/blink/web_tests/http/tests/devtools/elements/DIR_METADATA
new file mode 100644
index 0000000..7c82dcd
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/DIR_METADATA
@@ -0,0 +1,4 @@
+team_email: "devtools-dev@chromium.org"
+buganizer_public: {
+  component_id: 1457255
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/devtools/network/DIR_METADATA b/third_party/blink/web_tests/http/tests/devtools/network/DIR_METADATA
new file mode 100644
index 0000000..2313cc64
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/network/DIR_METADATA
@@ -0,0 +1,4 @@
+team_email: "devtools-dev@chromium.org"
+buganizer_public: {
+  component_id: 1456921
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/devtools/sources/DIR_METADATA b/third_party/blink/web_tests/http/tests/devtools/sources/DIR_METADATA
new file mode 100644
index 0000000..edbe824f
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/sources/DIR_METADATA
@@ -0,0 +1,4 @@
+team_email: "devtools-dev@chromium.org"
+buganizer_public: {
+  component_id: 1456920
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/DIR_METADATA b/third_party/blink/web_tests/http/tests/inspector-protocol/DIR_METADATA
index 25fe1f0c..f6ff614 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/DIR_METADATA
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/DIR_METADATA
@@ -1,2 +1,4 @@
 team_email: "devtools-dev@chromium.org"
-
+buganizer_public: {
+  component_id: 1457055
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/animation/DIR_METADATA b/third_party/blink/web_tests/http/tests/inspector-protocol/animation/DIR_METADATA
new file mode 100644
index 0000000..a51c743
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/animation/DIR_METADATA
@@ -0,0 +1,4 @@
+team_email: "devtools-dev@chromium.org"
+buganizer_public: {
+  component_id: 1559716
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/console/DIR_METADATA b/third_party/blink/web_tests/http/tests/inspector-protocol/console/DIR_METADATA
new file mode 100644
index 0000000..070fa3c
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/console/DIR_METADATA
@@ -0,0 +1,4 @@
+team_email: "devtools-dev@chromium.org"
+buganizer_public: {
+  component_id: 1519297
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/css/DIR_METADATA b/third_party/blink/web_tests/http/tests/inspector-protocol/css/DIR_METADATA
new file mode 100644
index 0000000..7c82dcd
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/css/DIR_METADATA
@@ -0,0 +1,4 @@
+team_email: "devtools-dev@chromium.org"
+buganizer_public: {
+  component_id: 1457255
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/debugger/DIR_METADATA b/third_party/blink/web_tests/http/tests/inspector-protocol/debugger/DIR_METADATA
new file mode 100644
index 0000000..edbe824f
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/debugger/DIR_METADATA
@@ -0,0 +1,4 @@
+team_email: "devtools-dev@chromium.org"
+buganizer_public: {
+  component_id: 1456920
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/dom/DIR_METADATA b/third_party/blink/web_tests/http/tests/inspector-protocol/dom/DIR_METADATA
new file mode 100644
index 0000000..7c82dcd
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/dom/DIR_METADATA
@@ -0,0 +1,4 @@
+team_email: "devtools-dev@chromium.org"
+buganizer_public: {
+  component_id: 1457255
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/issues/DIR_METADATA b/third_party/blink/web_tests/http/tests/inspector-protocol/issues/DIR_METADATA
new file mode 100644
index 0000000..0d190be
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/issues/DIR_METADATA
@@ -0,0 +1,4 @@
+team_email: "devtools-dev@chromium.org"
+buganizer_public: {
+  component_id: 1519296
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/DIR_METADATA b/third_party/blink/web_tests/http/tests/inspector-protocol/network/DIR_METADATA
new file mode 100644
index 0000000..2313cc64
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/DIR_METADATA
@@ -0,0 +1,4 @@
+team_email: "devtools-dev@chromium.org"
+buganizer_public: {
+  component_id: 1456921
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/timeline/DIR_METADATA b/third_party/blink/web_tests/http/tests/inspector-protocol/timeline/DIR_METADATA
new file mode 100644
index 0000000..2937b2c
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/timeline/DIR_METADATA
@@ -0,0 +1,4 @@
+team_email: "devtools-dev@chromium.org"
+buganizer_public: {
+  component_id: 1457310
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/inspector-protocol/DIR_METADATA b/third_party/blink/web_tests/inspector-protocol/DIR_METADATA
index 25fe1f0c..f6ff614 100644
--- a/third_party/blink/web_tests/inspector-protocol/DIR_METADATA
+++ b/third_party/blink/web_tests/inspector-protocol/DIR_METADATA
@@ -1,2 +1,4 @@
 team_email: "devtools-dev@chromium.org"
-
+buganizer_public: {
+  component_id: 1457055
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/inspector-protocol/css/DIR_METADATA b/third_party/blink/web_tests/inspector-protocol/css/DIR_METADATA
new file mode 100644
index 0000000..7c82dcd
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/css/DIR_METADATA
@@ -0,0 +1,4 @@
+team_email: "devtools-dev@chromium.org"
+buganizer_public: {
+  component_id: 1457255
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/inspector-protocol/dom/DIR_METADATA b/third_party/blink/web_tests/inspector-protocol/dom/DIR_METADATA
new file mode 100644
index 0000000..7c82dcd
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/dom/DIR_METADATA
@@ -0,0 +1,4 @@
+team_email: "devtools-dev@chromium.org"
+buganizer_public: {
+  component_id: 1457255
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/inspector-protocol/performance-timeline/DIR_METADATA b/third_party/blink/web_tests/inspector-protocol/performance-timeline/DIR_METADATA
new file mode 100644
index 0000000..2937b2c
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/performance-timeline/DIR_METADATA
@@ -0,0 +1,4 @@
+team_email: "devtools-dev@chromium.org"
+buganizer_public: {
+  component_id: 1457310
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/inspector-protocol/timeline/DIR_METADATA b/third_party/blink/web_tests/inspector-protocol/timeline/DIR_METADATA
new file mode 100644
index 0000000..2937b2c
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/timeline/DIR_METADATA
@@ -0,0 +1,4 @@
+team_email: "devtools-dev@chromium.org"
+buganizer_public: {
+  component_id: 1457310
+}
\ No newline at end of file
diff --git a/third_party/blink/web_tests/platform/mac-mac13-arm64/external/wpt/soft-navigation-heuristics/lcp/tentative/contracted-image-expected.txt b/third_party/blink/web_tests/platform/mac-mac13-arm64/external/wpt/soft-navigation-heuristics/lcp/tentative/contracted-image-expected.txt
new file mode 100644
index 0000000..5b37deb
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac13-arm64/external/wpt/soft-navigation-heuristics/lcp/tentative/contracted-image-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+All subtests passed and are omitted for brevity.
+See https://chromium.googlesource.com/chromium/src/+/HEAD/docs/testing/writing_web_tests.md#Text-Test-Baselines for details.
+Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/platform/mac-mac14-arm64/external/wpt/soft-navigation-heuristics/lcp/tentative/contracted-image-expected.txt b/third_party/blink/web_tests/platform/mac-mac14-arm64/external/wpt/soft-navigation-heuristics/lcp/tentative/contracted-image-expected.txt
new file mode 100644
index 0000000..1534a4d
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac14-arm64/external/wpt/soft-navigation-heuristics/lcp/tentative/contracted-image-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] Largest Contentful Paint: |size| attribute is bounded by display size after soft navigation.
+  promise_test: Unhandled rejection with value: object "Error: 2 entries of type largest-contentful-paint with soft navigation observations never arrived"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbcursor_continue_objectstore.any-expected.txt b/third_party/blink/web_tests/virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbcursor_continue_objectstore.any-expected.txt
new file mode 100644
index 0000000..8118d60
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbcursor_continue_objectstore.any-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] Delete next element, and iterate to it
+  assert_unreached: unexpected db.error (AbortError) Reached unreachable code
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbobjectstore_getAll.any-expected.txt b/third_party/blink/web_tests/virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbobjectstore_getAll.any-expected.txt
new file mode 100644
index 0000000..5fcf71ca
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbobjectstore_getAll.any-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] Get all with large values
+  Cannot read properties of null (reading 'join')
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbobjectstore_getAllRecords.tentative.any-expected.txt b/third_party/blink/web_tests/virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbobjectstore_getAllRecords.tentative.any-expected.txt
new file mode 100644
index 0000000..afd207e9
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/indexeddb_sqlite/external/wpt/IndexedDB/idbobjectstore_getAllRecords.tentative.any-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] Get all records with large values
+  Cannot read properties of null (reading 'join')
+Harness: the test ran to completion.
+
diff --git a/third_party/crossbench b/third_party/crossbench
index 885aeee..1de2eca 160000
--- a/third_party/crossbench
+++ b/third_party/crossbench
@@ -1 +1 @@
-Subproject commit 885aeee863e05189c83fadb0c302d07518eb5500
+Subproject commit 1de2eca3495784b797d977b40b7291a4a7cd06c1
diff --git a/third_party/dawn b/third_party/dawn
index 9fd4a73..fd27657 160000
--- a/third_party/dawn
+++ b/third_party/dawn
@@ -1 +1 @@
-Subproject commit 9fd4a731474f66c1ce5465f9b13919ad7487315d
+Subproject commit fd276573ab859ea73c18581c018a773e4e3b8902
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index fd0c28c..7ad25e2 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit fd0c28cbf06b695f677c525b6630f9f9e4a90eee
+Subproject commit 7ad25e25037043f7a75e7a838a651c110b918d48
diff --git a/third_party/protobuf/BUILD.gn b/third_party/protobuf/BUILD.gn
index 19e90ba..3d6c4b70 100644
--- a/third_party/protobuf/BUILD.gn
+++ b/third_party/protobuf/BUILD.gn
@@ -142,10 +142,6 @@
 
       # The Cast Core gRPC generator tool.
       "//third_party/cast_core/public/src/build/chromium:cast_core_grpc_generator",
-
-      # The proto_extras plugin generates code that some of the above fuzzers
-      # use, and thus needs to know the full types.
-      "//components/proto_extras:protobuf_full_support",
     ]
   }
 
diff --git a/third_party/spirv-tools/src b/third_party/spirv-tools/src
index e0bad28..dec2864 160000
--- a/third_party/spirv-tools/src
+++ b/third_party/spirv-tools/src
@@ -1 +1 @@
-Subproject commit e0bad2825dacf274578ec6d3c0e64e406d5e4fd7
+Subproject commit dec28643ed15f68a2bc95650de25e0a7486b564c
diff --git a/third_party/vulkan-deps b/third_party/vulkan-deps
index 9a8d020..3395378 160000
--- a/third_party/vulkan-deps
+++ b/third_party/vulkan-deps
@@ -1 +1 @@
-Subproject commit 9a8d0205ed06a556ff17d4097afc218c993ec260
+Subproject commit 3395378f6990e79066b5f1647f6f8ac5de07e26d
diff --git a/third_party/vulkan-validation-layers/src b/third_party/vulkan-validation-layers/src
index ce9b7e4..3fa19fc 160000
--- a/third_party/vulkan-validation-layers/src
+++ b/third_party/vulkan-validation-layers/src
@@ -1 +1 @@
-Subproject commit ce9b7e404fe1a312ff4c07961dc6f8a2fd925d44
+Subproject commit 3fa19fccc75171a6b607f95510c37739c606b809
diff --git a/third_party/webrtc b/third_party/webrtc
index 7493242..4c619d7 160000
--- a/third_party/webrtc
+++ b/third_party/webrtc
@@ -1 +1 @@
-Subproject commit 74932424d457e2ad5e70c914b3cdd55bec759d6a
+Subproject commit 4c619d7b0f2020e1b54fc62aaafc24fc34af78f8
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 55d369d..e457ee8e 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -24426,6 +24426,12 @@
   <description>Please enter the description of the metric.</description>
 </action>
 
+<action name="MobileMenuExtensions">
+  <owner>massan@google.com</owner>
+  <owner>nya@chromium.org</owner>
+  <description>User pressed 'Extensions' in the app menu.</description>
+</action>
+
 <action name="MobileMenuFeedback">
   <owner>aurimas@chromium.org</owner>
   <description>User pressed 'Help and Feedback' in the app menu.</description>
diff --git a/tools/metrics/histograms/metadata/blink/histograms.xml b/tools/metrics/histograms/metadata/blink/histograms.xml
index 2e5a305..b063a87 100644
--- a/tools/metrics/histograms/metadata/blink/histograms.xml
+++ b/tools/metrics/histograms/metadata/blink/histograms.xml
@@ -1135,6 +1135,7 @@
     units="ms" expires_after="2025-10-26">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     Time between CommitNavigation to StartLoadingResponse in the renderer
     process. This is recorded on each new navigation for http or https URLs in
@@ -1147,6 +1148,7 @@
     units="ms" expires_after="2025-10-12">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     Time spent processing DocumentLoader::CreateParserPostCommit() in the
     renderer process. This is recorded on each new navigation for http or https
@@ -3109,6 +3111,7 @@
   <owner>
     src/third_party/blink/renderer/core/lcp_critical_path_predictor/OWNERS
   </owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     Measures the total elapsed time it takes to run SVGImage::DataChanged()
     while loading the outermost main frame document until finishing parsing.
@@ -3390,6 +3393,7 @@
   <owner>chikamune@chromium.org</owner>
   <owner>yyanagisawa@chromium.org</owner>
   <owner>kouhei@chromium.org</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     Record when the page's main frame starts preloading {SubresourceType}.
     Measures the duration between when the navigation starts, to when preloading
@@ -4981,6 +4985,7 @@
   <owner>paint-dev@chromium.org</owner>
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     Time spent updating a SVG image once all data is received.
 
diff --git a/tools/metrics/histograms/metadata/gpu/histograms.xml b/tools/metrics/histograms/metadata/gpu/histograms.xml
index dfa7eb0..2af07f7 100644
--- a/tools/metrics/histograms/metadata/gpu/histograms.xml
+++ b/tools/metrics/histograms/metadata/gpu/histograms.xml
@@ -825,6 +825,7 @@
   <owner>chikamune@chromium.org</owner>
   <owner>kouhei@chromium.org</owner>
   <owner>chrome-gpu-metric-alerts@chromium.org</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     Measures the time it takes to synchronously establish the GPU channel.
     Logged on the first run of a sync call to EstableGpuChannelSync is made.
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml
index d20b3f7b..24a263315 100644
--- a/tools/metrics/histograms/metadata/navigation/histograms.xml
+++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -785,6 +785,7 @@
     units="microseconds" expires_after="2025-11-16">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     Time spent processing RenderFrameImpl::CommitNavigationWithParams() in the
     renderer process. This is recorded on each WebFrameLoadType::kStandard
@@ -1192,6 +1193,7 @@
     units="microseconds" expires_after="2025-11-16">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     Time spent processing GetFrameHostForNavigation() in
     RenderFrameHostManager::DidCreateNavigationRequest() that can prepare a
@@ -1403,6 +1405,7 @@
   <owner>chikamune@chromium.org</owner>
   <owner>yyanagisawa@chromium.org</owner>
   <owner>kouhei@chromium.org</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     Record when (a) the navigation happened in MainFrame, (b) it was a new
     navigation, (c) it was not a session restore, (d) the URL was http or https,
@@ -1633,6 +1636,7 @@
     expires_after="2025-11-16">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     Milliseconds spent to process all the beforeunload events in JavaScript and
     waiting time for beforeunload dialog is closed if necessary. Recorded only
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml
index 298a0f6a..427d720 100644
--- a/tools/metrics/histograms/metadata/others/histograms.xml
+++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -6011,6 +6011,7 @@
     expires_after="2025-10-26">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     Measures the elapsed time it takes to read LCPPNavigationHint and attach it
     to NavigationHandle. Recorded on DidStartNavigatinon or
diff --git a/tools/metrics/histograms/metadata/page/histograms.xml b/tools/metrics/histograms/metadata/page/histograms.xml
index d946db71..ca29724 100644
--- a/tools/metrics/histograms/metadata/page/histograms.xml
+++ b/tools/metrics/histograms/metadata/page/histograms.xml
@@ -2609,6 +2609,7 @@
     expires_after="2025-10-12">
   <owner>chikamune@chromium.org</owner>
   <owner>loading-dev@chromium.org</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>{MetricName}, but recorded only for {Origin} navigations.</summary>
   <token key="Origin">
     <variant name="CrossOrigin" summary="cross-origin"/>
diff --git a/tools/metrics/histograms/metadata/search/OWNERS b/tools/metrics/histograms/metadata/search/OWNERS
index b4ab36a..3d0d35b 100644
--- a/tools/metrics/histograms/metadata/search/OWNERS
+++ b/tools/metrics/histograms/metadata/search/OWNERS
@@ -7,6 +7,7 @@
 
 # For search engine choice releated metrics only.
 alexilin@chromium.org
+ljjlee@google.com
 
 # For auxiliary search related metrics only.
 hanxi@chromium.org
diff --git a/tools/metrics/histograms/metadata/search/enums.xml b/tools/metrics/histograms/metadata/search/enums.xml
index 91272e5..272299f6 100644
--- a/tools/metrics/histograms/metadata/search/enums.xml
+++ b/tools/metrics/histograms/metadata/search/enums.xml
@@ -326,6 +326,7 @@
 
 <enum name="SearchEngineChoiceDate">
   <summary>Year-Month</summary>
+  <int value="100001" label="Before 2022"/>
   <int value="202201" label="2022-01"/>
   <int value="202202" label="2022-02"/>
   <int value="202203" label="2022-03"/>
@@ -386,6 +387,7 @@
   <int value="202610" label="2026-10"/>
   <int value="202611" label="2026-11"/>
   <int value="202612" label="2026-12"/>
+  <int value="300001" label="After 2050"/>
 </enum>
 
 <enum name="SearchEngineChoiceReprompt">
diff --git a/tools/metrics/histograms/metadata/search/histograms.xml b/tools/metrics/histograms/metadata/search/histograms.xml
index 3fcdc8f8..4b59380 100644
--- a/tools/metrics/histograms/metadata/search/histograms.xml
+++ b/tools/metrics/histograms/metadata/search/histograms.xml
@@ -325,11 +325,11 @@
   </summary>
 </histogram>
 
-<histogram name="Search.ChoiceCompletedOnMonth.OnProfileLoad"
+<histogram name="Search.ChoiceCompletedOnMonth.OnProfileLoad2"
     enum="SearchEngineChoiceDate" expires_after="2026-05-01">
-<!-- When bumping expiry date, also update the enum (making the enumeration in sync with existing values). Escalate when data count
-exceeds 100 entries:
-https://chromium.googlesource.com/chromium/src/tools/+/HEAD/metrics/histograms/README.md#sustainability -->
+<!-- When bumping expiry date, also update the enum (making the enumeration in
+sync with existing values). Escalate when data count exceeds 1000 entries:
+https://chromium.googlesource.com/chromium/src/tools/+/HEAD/metrics/histograms/README.md#When-To-Use-Sparse-Histograms -->
 
   <owner>dgn@google.com</owner>
   <owner>tju@google.com</owner>
@@ -339,6 +339,10 @@
     last engine choice timestamp formatted as YYYYMM integer. For convenience,
     the enum maps these to user readable `YYYY-MM` labels.
 
+    To avoid the histogram exceeding 1000 buckets (limit for sparse histograms),
+    the range is capped to [`2022-01`, `2050-12`], dates prior to 2022 being
+    recorded as `1000-01`, and dates after 2050 being recorded as `3000-01`.
+
     The value is serialized as a sparse histogram with integer values. Since
     each client can record the same value multiple times, it might be more
     interesting to look at unique clients.
diff --git a/tools/metrics/histograms/metadata/service/histograms.xml b/tools/metrics/histograms/metadata/service/histograms.xml
index b102b6e..eed2b10 100644
--- a/tools/metrics/histograms/metadata/service/histograms.xml
+++ b/tools/metrics/histograms/metadata/service/histograms.xml
@@ -586,6 +586,7 @@
     expires_after="2026-05-20">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     Execution time of FindRegistrationForClientUrl until continuation is called.
     The metric is not recorded during startup.
@@ -702,6 +703,7 @@
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     The time taken from (a) renderer process sends an IPC message to notify that
     a resource loading request needs to be fall back to network, to (b) browser
@@ -784,6 +786,7 @@
     units="ms" expires_after="2025-12-07">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     The time taken from (a) the start of finding service worker registration, to
     (b) reading response body is completed. Recorded when a fetch event handler
@@ -804,6 +807,7 @@
     units="ms" expires_after="2025-12-07">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     The time taken from (a) the start of finding service worker registration, to
     (b) browser process received the IPC. Recorded when no fetch event handler
@@ -824,6 +828,7 @@
     units="ms" expires_after="2025-12-07">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     The time taken from (a) the start of finding service worker registration, to
     (b) the start of a navigation request.
@@ -843,6 +848,7 @@
     units="ms" expires_after="2025-10-19">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     The time taken from (a) a resource loading request is routed to service
     worker path, to (b) a service worker is ready to handle the request.
@@ -910,6 +916,7 @@
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     The time taken from (a) response headers from service worker are received,
     to (b) reading response body is completed. Recorded when a fetch event
@@ -946,6 +953,7 @@
     units="ms" expires_after="2025-08-01">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     The time taken from (a) the start of a navigation request, to (b) reading
     response body is completed. Recorded when a fetch event handler handled the
@@ -966,6 +974,7 @@
     units="ms" expires_after="2025-08-01">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     The time taken from (a) the start of a navigation request, to (b) browser
     process received the IPC. Recorded when no fetch event handler provided a
@@ -987,6 +996,7 @@
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     The time taken from (a) the start of a navigation request, to (b) the
     request is forwarded to a service worker code path.
@@ -1007,6 +1017,7 @@
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     The time taken from (a) browser process sends an IPC message to dispatch a
     fetch event, to (b) a renderer process received the IPC message and is about
@@ -1220,6 +1231,7 @@
     units="ms" expires_after="2025-10-12">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     Execution time of FindRegistrationForClientUrl until continuation is called.
     It is recorded only once on browser startup.
@@ -1755,6 +1767,7 @@
     expires_after="2025-10-08">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     Execution time of ServiceWorkerStorage::FindForClientUrlInDB which is used
     by FindRegistrationForClientUrl.
@@ -1775,6 +1788,7 @@
     expires_after="2025-11-30">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     Execution time of ServiceWorkerStorage::ReadInitialDataFromDB which reads
     RegisteredStorageKey from a database.
@@ -1786,6 +1800,7 @@
     units="ms" expires_after="2025-12-07">
   <owner>chikamune@chromium.org</owner>
   <owner>chrome-worker@google.com</owner>
+  <improvement direction="LOWER_IS_BETTER"/>
   <summary>
     The cache creation time of service worker registration key on UI thread.
     Includes asynchronous call, thread hopping and the time of
diff --git a/v8 b/v8
index 77f35f0..ad9041e 160000
--- a/v8
+++ b/v8
@@ -1 +1 @@
-Subproject commit 77f35f055a1543f51099fcea9575f83304d60de5
+Subproject commit ad9041e4d0f760e0c1c87d79a60b9ff1d2c77f96