diff --git a/AUTHORS b/AUTHORS
index 2b97684b..818bb32c 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1061,6 +1061,7 @@
 Minggang Wang <minggang.wang@intel.com>
 Mingmin Xie <melvinxie@gmail.com>
 Mingming Xu <mingming1.xu@intel.com>
+Mingtao Zhou <mingtaoxt@gmail.com>
 Mingyue Ji <myandyji@gmail.com>
 Minjeong Kim <deoxyribonucleicacid150@gmail.com>
 Minjeong Lee <apenr1234@gmail.com>
diff --git a/DEPS b/DEPS
index 7c98e0d..41b2849 100644
--- a/DEPS
+++ b/DEPS
@@ -305,11 +305,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'src_internal_revision': 'ee7ed7723eb64518a8ca03d91fd4041e3a319574',
+  'src_internal_revision': '5b3a0932dc6e77ec5474737c28832c127f9eba80',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '2a9fe9cde3e8e2184db9c225b638dabc1debd5fa',
+  'skia_revision': '845ec125e94ce32aa235aeca99409dabf15f9f76',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -317,7 +317,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'e893313ccef7686c9f4c4444c9a605b0578b1534',
+  'angle_revision': 'fe30cd1a5fecfc2bb7581a742c15e0eb1fd77296',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -397,7 +397,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': 'e5b234e858cfd029bf8eafa13455f80f460643f2',
+  'devtools_frontend_revision': '2a744510a5faabae24e3c6d2ca34928f91392653',
   # 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.
@@ -1212,7 +1212,7 @@
       'packages': [
           {
               'package': 'chromium/chrome/android/orderfiles/arm64',
-              'version': '0zO7HtkBIb3zVMKfFnuZel8fcZRmCjiU7RU4a9GUIgYC',
+              'version': 'OG2xVTYyF5XeAkroHFyzHm7NayCDgU2lcr4x7HGNS2oC',
           },
       ],
       'condition': 'checkout_android',
@@ -1763,7 +1763,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 's12rOiGNzd60313qCbH7ZkS2V2gdqpFJOpp97EuPawUC',
+          'version': 'YC4HhXF5HZSHJivwdkTTUDHtKx_CuLz0IV2DwraDhBAC',
       },
     ],
     'condition': 'checkout_android and non_git_source',
@@ -2641,7 +2641,7 @@
     Var('pdfium_git') + '/pdfium.git' + '@' +  Var('pdfium_revision'),
 
   'src/third_party/perfetto':
-    Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + '313e4b6b9117daa3241863a5ce31c203c218164a',
+    Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + '55c592489062e1569fddcc59a4b9b5479a6b988f',
 
   'src/base/tracing/test/data': {
     'bucket': 'perfetto',
@@ -3012,7 +3012,7 @@
     Var('chromium_git') + '/webpagereplay.git' + '@' + Var('webpagereplay_revision'),
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'd7169bf89fc40930c49e083ec7969dfdd7650407',
+    Var('webrtc_git') + '/src.git' + '@' + '8d31c4add2eb4685afff353a35b705b089d5f21f',
 
   # 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.
@@ -3134,7 +3134,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/boca_receiver_app/app',
-        'version': 'XmR-MHAoVgK8NkVe5Wzmg6sF0rjD_0i8eerPGNn7uH4C',
+        'version': 'VDuf4Yr9R_yFPnNKg7CivrtnMZ-ICJAsxIK05AvzjcoC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -3200,7 +3200,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 'XtCUqIiftsKThLvaqajK4yJo2ezvnTl8rBqUTrvgUGUC',
+        'version': '7dZy2XxTgdbg3Fq1sWoWLlr6vOQaD6jfh6l6d6Yi7loC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/base/allocator/partition_allocator/src/partition_alloc/page_allocator_constants.h b/base/allocator/partition_allocator/src/partition_alloc/page_allocator_constants.h
index cbb3c78f..75311dc 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/page_allocator_constants.h
+++ b/base/allocator/partition_allocator/src/partition_alloc/page_allocator_constants.h
@@ -32,7 +32,8 @@
 
 #elif (PA_BUILDFLAG(IS_ANDROID) && PA_BUILDFLAG(PA_ARCH_CPU_64_BITS)) || \
     (PA_BUILDFLAG(IS_LINUX) && PA_BUILDFLAG(PA_ARCH_CPU_ARM64)) ||       \
-    (PA_BUILDFLAG(IS_LINUX) && PA_BUILDFLAG(PA_ARCH_CPU_PPC64))
+    (PA_BUILDFLAG(IS_LINUX) && PA_BUILDFLAG(PA_ARCH_CPU_PPC64)) ||       \
+    (PA_BUILDFLAG(IS_LINUX) && PA_BUILDFLAG(PA_ARCH_CPU_LOONGARCH64))
 // This should work for all POSIX (if needed), but currently all other
 // supported OS/architecture combinations use either hard-coded values
 // (such as x86) or have means to determine these values without needing
@@ -130,7 +131,7 @@
   // compiled for 64kB are likely to work on 4kB systems, 64kB is a good choice
   // here.
   return 16;  // 64kB
-#elif defined(_MIPS_ARCH_LOONGSON) || PA_BUILDFLAG(PA_ARCH_CPU_LOONGARCH64)
+#elif defined(_MIPS_ARCH_LOONGSON)
   return 14;  // 16kB
 #elif PA_BUILDFLAG(IS_APPLE) && PA_BUILDFLAG(PA_ARCH_CPU_64_BITS)
   return static_cast<size_t>(vm_page_shift);
@@ -140,7 +141,7 @@
   // compiled for 64kB are likely to work on 4kB systems, 64kB is a good choice
   // here.
   return 16;  // 64kB
-#elif defined(_MIPS_ARCH_LOONGSON) || PA_BUILDFLAG(PA_ARCH_CPU_LOONGARCH64)
+#elif defined(_MIPS_ARCH_LOONGSON)
   return 14;  // 16kB
 #elif PA_BUILDFLAG(IS_APPLE) && PA_BUILDFLAG(PA_ARCH_CPU_64_BITS)
   return static_cast<size_t>(vm_page_shift);
diff --git a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_constants.h b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_constants.h
index 0e8d54c..e941d16 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_constants.h
+++ b/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_constants.h
@@ -112,7 +112,7 @@
 PartitionPageShift() {
   return PageAllocationGranularityShift() + 2;
 }
-#elif defined(_MIPS_ARCH_LOONGSON) || PA_BUILDFLAG(PA_ARCH_CPU_LOONGARCH64)
+#elif defined(_MIPS_ARCH_LOONGSON)
 PA_ALWAYS_INLINE PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR size_t
 PartitionPageShift() {
   return 16;  // 64 KiB
diff --git a/cc/layers/tile_display_layer_impl_unittest.cc b/cc/layers/tile_display_layer_impl_unittest.cc
index 090c0f01..c9f27c4 100644
--- a/cc/layers/tile_display_layer_impl_unittest.cc
+++ b/cc/layers/tile_display_layer_impl_unittest.cc
@@ -504,4 +504,35 @@
   EXPECT_EQ(render_pass->quad_list.front()->resource_id, low_res_resource_id);
 }
 
+// Verifies that RemoveTiling correctly removes a tiling.
+TEST_F(TileDisplayLayerImplTest, RemoveTilingRemovesTiling) {
+  auto layer = std::make_unique<TileDisplayLayerImpl>(
+      CHECK_DEREF(host_impl()->active_tree()), /*id=*/42);
+  auto* raw_layer = layer.get();
+  host_impl()->active_tree()->AddLayer(std::move(layer));
+
+  // Add a tiling.
+  raw_layer->GetOrCreateTilingFromScaleKey(1.0);
+  ASSERT_NE(raw_layer->GetTilingForTesting(1.0), nullptr);
+
+  // Remove the tiling.
+  raw_layer->RemoveTiling(1.0);
+  EXPECT_EQ(raw_layer->GetTilingForTesting(1.0), nullptr);
+}
+
+// Verifies that calling RemoveTiling() for a tiling that doesn't exist doesn't
+// crash.
+TEST_F(TileDisplayLayerImplTest, RemoveTilingOnNonExistentTilingDoesNotCrash) {
+  auto layer = std::make_unique<TileDisplayLayerImpl>(
+      CHECK_DEREF(host_impl()->active_tree()), /*id=*/42);
+  auto* raw_layer = layer.get();
+  host_impl()->active_tree()->AddLayer(std::move(layer));
+
+  ASSERT_EQ(raw_layer->GetTilingForTesting(1.0), nullptr);
+
+  // This should not crash.
+  raw_layer->RemoveTiling(1.0);
+  EXPECT_EQ(raw_layer->GetTilingForTesting(1.0), nullptr);
+}
+
 }  // namespace cc
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
index fb790a87..f480339 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -277,8 +277,7 @@
                 MenuOrKeyboardActionController,
                 CompositorViewHolder.Initializer,
                 TabModelInitializer,
-                ThemeResourceWrapperProvider,
-                UmaActivityObserver.UmaSessionAwareActivity {
+                ThemeResourceWrapperProvider {
     public static final String UNFOLD_LATENCY_BEGIN_TIMESTAMP = "unfold_latency_begin_timestamp";
     public static final String IS_FROM_RECREATING = "is_from_recreating";
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaActivityObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaActivityObserver.java
index 7e5caa5..b37b6a3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaActivityObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaActivityObserver.java
@@ -4,12 +4,8 @@
 
 package org.chromium.chrome.browser.metrics;
 
-import android.app.Activity;
 import android.content.Context;
 
-import org.chromium.base.ActivityState;
-import org.chromium.base.ApplicationState;
-import org.chromium.base.ApplicationStatus;
 import org.chromium.build.annotations.Initializer;
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
@@ -35,43 +31,10 @@
     private TabModelSelector mLatestTabModelSelector;
     private AndroidPermissionDelegate mLatestAndroidPermissionDelegate;
 
-    /** Activities that implement this interface manage their own UMA Session starting/ending. */
-    public interface UmaSessionAwareActivity {}
-
-    private static ApplicationStatus.@Nullable ActivityStateListener sAppActivityListener;
-
-    static {
-        doStaticInit();
-    }
-
-    private static void doStaticInit() {
-        // Handles the case where we open a non-UMA aware activity like Bookmarks over CTA, and then
-        // the user hides the Bookmarks Activity (which should end the session).
-        sAppActivityListener =
-                new ApplicationStatus.ActivityStateListener() {
-                    @Override
-                    public void onActivityStateChange(Activity activity, int newState) {
-                        if (activity instanceof UmaSessionAwareActivity) return;
-                        if (newState != ActivityState.STOPPED
-                                && newState != ActivityState.DESTROYED) {
-                            return;
-                        }
-                        if (sActiveObserver == null) return;
-                        if (ApplicationStatus.getStateForApplication()
-                                == ApplicationState.HAS_RUNNING_ACTIVITIES) {
-                            return;
-                        }
-                        sActiveObserver.endUmaSessionInternal(false, true);
-                    }
-                };
-        ApplicationStatus.registerStateListenerForAllActivities(sAppActivityListener);
-    }
-
     public UmaActivityObserver(
             Context context,
             ActivityLifecycleDispatcher lifecycleDispatcher,
             @ActivityType int activityType) {
-        assert context instanceof UmaSessionAwareActivity;
         mUmaSessionStats = new UmaSessionStats(context);
         lifecycleDispatcher.register(this);
         mActivityType = activityType;
@@ -103,7 +66,7 @@
                     sActiveObserver = this;
                     return;
                 }
-                sActiveObserver.endUmaSessionInternal(false, false);
+                sActiveObserver.endUmaSessionInternal(false);
             }
             sActiveObserver = this;
 
@@ -138,15 +101,8 @@
      */
     public void endUmaSession() {
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.UMA_SESSION_CORRECTNESS_FIXES)) {
-            for (Activity activity : ApplicationStatus.getRunningActivities()) {
-                if (activity instanceof UmaSessionAwareActivity) continue;
-                if (ApplicationStatus.getStateForActivity(activity) == ActivityState.RESUMED) {
-                    // Don't end the session if an Activity like Settings/Bookmarks is still
-                    // visible.
-                    return;
-                }
-            }
-            endUmaSessionInternal(true, true);
+            sVisibleObservers.remove(this);
+            endUmaSessionInternal(true);
         } else {
             if (sActiveObserver == null) {
                 return;
@@ -158,12 +114,8 @@
         }
     }
 
-    private void endUmaSessionInternal(boolean startNextVisibleSession, boolean removeObserver) {
-        if (removeObserver) {
-            sVisibleObservers.remove(this);
-        }
+    private void endUmaSessionInternal(boolean startNextVisibleSession) {
         if (sActiveObserver != this) return;
-
         // Record session metrics.
         mUmaSessionStats.logAndEndSession();
         sActiveObserver = null;
@@ -185,7 +137,7 @@
     public void onDestroy() {
         if (sActiveObserver == null) return; // Ensures native library has been initialized.
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.UMA_SESSION_CORRECTNESS_FIXES)) {
-            endUmaSessionInternal(true, true);
+            endUmaSession();
         }
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
index 062cdbc..e186f36 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
@@ -91,10 +91,7 @@
 
 /** Queries the user's default search engine and shows autocomplete suggestions. */
 public class SearchActivity extends AsyncInitializationActivity
-        implements SnackbarManageable,
-                BackKeyBehaviorDelegate,
-                UrlFocusChangeListener,
-                UmaActivityObserver.UmaSessionAwareActivity {
+        implements SnackbarManageable, BackKeyBehaviorDelegate, UrlFocusChangeListener {
     // Shared with other org.chromium.chrome.browser.searchwidget classes.
     protected static final String TAG = "searchwidget";
 
diff --git a/chrome/android/javatests/BUILD.gn b/chrome/android/javatests/BUILD.gn
index a184537..a991108 100644
--- a/chrome/android/javatests/BUILD.gn
+++ b/chrome/android/javatests/BUILD.gn
@@ -843,7 +843,6 @@
     "src/org/chromium/chrome/browser/metrics/MainIntentBehaviorMetricsIntegrationTest.java",
     "src/org/chromium/chrome/browser/metrics/SessionMetricsTest.java",
     "src/org/chromium/chrome/browser/metrics/StartupLoadingMetricsTest.java",
-    "src/org/chromium/chrome/browser/metrics/UmaActivityObserverTest.java",
   ]
 
   deps = [ ":chrome_test_java_helper" ]
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/app/bookmarks/PartnerBookmarkTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/app/bookmarks/PartnerBookmarkTest.java
index 6e1f6c4..f25e405a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/app/bookmarks/PartnerBookmarkTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/app/bookmarks/PartnerBookmarkTest.java
@@ -169,9 +169,9 @@
         assertEquals(View.GONE, more2.getVisibility());
     }
 
-    // Disabled on android.emulator_12l_landscape - crbug.com/442769979.
     @Test
     @MediumTest
+    @DisabledTest(message = "https://crbug.com/443216305")
     public void testCannotSelectPartner() throws Exception {
         mBookmarkTestRule.openFolder(mBookmarkTestRule.getMobileFolder());
         View partner = mBookmarkManagerTestingDelegate.getBookmarkViewHolderByPosition(0).itemView;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/UmaActivityObserverTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/UmaActivityObserverTest.java
deleted file mode 100644
index 80408a7..0000000
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/UmaActivityObserverTest.java
+++ /dev/null
@@ -1,229 +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.
-
-package org.chromium.chrome.browser.metrics;
-
-import static org.mockito.ArgumentMatchers.anyLong;
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.net.Uri;
-
-import androidx.test.filters.LargeTest;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InOrder;
-import org.mockito.Mockito;
-import org.mockito.Spy;
-
-import org.chromium.base.ActivityState;
-import org.chromium.base.ApplicationStatus;
-import org.chromium.base.ThreadUtils;
-import org.chromium.base.test.transit.TravelException;
-import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.CriteriaHelper;
-import org.chromium.base.test.util.DoNotBatch;
-import org.chromium.base.test.util.Features.EnableFeatures;
-import org.chromium.base.test.util.Restriction;
-import org.chromium.chrome.browser.customtabs.CustomTabActivity;
-import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule;
-import org.chromium.chrome.browser.customtabs.CustomTabsIntentTestUtils;
-import org.chromium.chrome.browser.flags.ActivityType;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
-import org.chromium.chrome.browser.flags.ChromeSwitches;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.transit.ChromeTransitTestRules;
-import org.chromium.chrome.test.transit.FreshCtaTransitTestRule;
-import org.chromium.chrome.test.transit.page.WebPageStation;
-import org.chromium.chrome.test.transit.settings.SettingsStation;
-import org.chromium.ui.base.DeviceFormFactor;
-import org.chromium.ui.test.util.DeviceRestriction;
-
-/** Public Transit tests for the UmaActivityObserver. */
-@RunWith(ChromeJUnit4ClassRunner.class)
-@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-@DoNotBatch(reason = "Batching not yet supported in multi-window")
-// In phones, the New Window option in the app menu is only enabled when already in multi-window or
-// multi-display mode with Chrome not running in an adjacent window.
-@Restriction({DeviceFormFactor.TABLET_OR_DESKTOP, DeviceRestriction.RESTRICTION_TYPE_NON_AUTO})
-@EnableFeatures({ChromeFeatureList.UMA_SESSION_CORRECTNESS_FIXES})
-public class UmaActivityObserverTest {
-    @Rule
-    public FreshCtaTransitTestRule mCtaTestRule =
-            ChromeTransitTestRules.freshChromeTabbedActivityRule();
-
-    @Rule public CustomTabActivityTestRule mCctTestRule = new CustomTabActivityTestRule();
-
-    @Spy private UmaSessionStats.Natives mUmaSessionStatsJniSpy;
-    InOrder mInOrder;
-
-    @Before
-    public void setUp() {
-        mUmaSessionStatsJniSpy = Mockito.spy(UmaSessionStatsJni.get());
-        UmaSessionStatsJni.setInstanceForTesting(mUmaSessionStatsJniSpy);
-        mInOrder = Mockito.inOrder(mUmaSessionStatsJniSpy);
-        ThreadUtils.runOnUiThreadBlocking(
-                () -> {
-                    Assert.assertEquals(
-                            ActivityType.PRE_FIRST_TAB,
-                            UmaActivityObserver.getCurrentActivityType());
-                });
-    }
-
-    @Test
-    @LargeTest
-    public void testMultiWindowMetrics() throws Exception {
-        WebPageStation pageInFirstWindow = mCtaTestRule.startOnBlankPage();
-
-        ThreadUtils.runOnUiThreadBlocking(
-                () -> {
-                    Assert.assertEquals(
-                            ActivityType.TABBED, UmaActivityObserver.getCurrentActivityType());
-                });
-        mInOrder.verify(mUmaSessionStatsJniSpy, Mockito.times(1)).umaResumeSession(anyLong());
-        mInOrder.verify(mUmaSessionStatsJniSpy, Mockito.times(0)).umaEndSession(anyLong());
-
-        // Create second CTA window. This should be unnecessary but I cannot figure out how to
-        // convince Android to create an adjacent window for a new Activity. In any case, this
-        // is useful to ensure the session isn't restarted.
-        try {
-            pageInFirstWindow.openRegularTabAppMenu().openNewWindow();
-        } catch (TravelException e) {
-            // On android_32_google_apis_x64_foldable the screen size is too small for the search
-            // box to become fully visible with two windows. We don't care as we don't interact with
-            // it.
-            if (!e.getMessage().contains("id/search_box")) throw e;
-        }
-        ThreadUtils.runOnUiThreadBlocking(
-                () -> {
-                    Assert.assertEquals(
-                            ActivityType.TABBED, UmaActivityObserver.getCurrentActivityType());
-                });
-        mInOrder.verify(mUmaSessionStatsJniSpy, Mockito.times(0)).umaResumeSession(anyLong());
-        mInOrder.verify(mUmaSessionStatsJniSpy, Mockito.times(0)).umaEndSession(anyLong());
-
-        // Start a CCT over the second window.
-        Intent intent =
-                CustomTabsIntentTestUtils.createMinimalCustomTabIntent(
-                        mCtaTestRule.getActivity(),
-                        mCtaTestRule
-                                .getTestServer()
-                                .getURL("/chrome/test/data/android/about.html"));
-        intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.setComponent(new ComponentName(mCtaTestRule.getActivity(), CustomTabActivity.class));
-
-        mCctTestRule.startCustomTabActivityWithIntent(intent);
-        CriteriaHelper.pollUiThread(
-                () -> UmaActivityObserver.getCurrentActivityType() == ActivityType.CUSTOM_TAB);
-        mInOrder.verify(mUmaSessionStatsJniSpy, Mockito.times(1)).umaEndSession(anyLong());
-        mInOrder.verify(mUmaSessionStatsJniSpy, Mockito.times(1)).umaResumeSession(anyLong());
-        ThreadUtils.runOnUiThreadBlocking(
-                () -> {
-                    Assert.assertEquals(
-                            ActivityState.RESUMED,
-                            ApplicationStatus.getStateForActivity(mCtaTestRule.getActivity()));
-                    Assert.assertEquals(
-                            ActivityState.RESUMED,
-                            ApplicationStatus.getStateForActivity(mCctTestRule.getActivity()));
-                });
-
-        // Focus existing CTA in first window.
-        Intent intent2 = mCtaTestRule.getActivity().getIntent();
-        intent2.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
-        intent2.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
-        mCctTestRule.getActivity().startActivity(intent2);
-
-        CriteriaHelper.pollUiThread(
-                () -> UmaActivityObserver.getCurrentActivityType() == ActivityType.TABBED);
-        mInOrder.verify(mUmaSessionStatsJniSpy, Mockito.times(1)).umaEndSession(anyLong());
-        mInOrder.verify(mUmaSessionStatsJniSpy, Mockito.times(1)).umaResumeSession(anyLong());
-        ThreadUtils.runOnUiThreadBlocking(
-                () -> {
-                    Assert.assertEquals(
-                            ActivityState.RESUMED,
-                            ApplicationStatus.getStateForActivity(mCtaTestRule.getActivity()));
-                    Assert.assertEquals(
-                            ActivityState.RESUMED,
-                            ApplicationStatus.getStateForActivity(mCctTestRule.getActivity()));
-                });
-
-        // Close the CTA, resuming the CCT session.
-        mCtaTestRule.getActivity().finish();
-
-        CriteriaHelper.pollUiThread(
-                () -> UmaActivityObserver.getCurrentActivityType() == ActivityType.CUSTOM_TAB);
-        mInOrder.verify(mUmaSessionStatsJniSpy, Mockito.times(1)).umaEndSession(anyLong());
-        mInOrder.verify(mUmaSessionStatsJniSpy, Mockito.times(1)).umaResumeSession(anyLong());
-    }
-
-    @Test
-    @LargeTest
-    public void testSessionPreservedInSettings() throws Exception {
-        WebPageStation pageInFirstWindow = mCtaTestRule.startOnBlankPage();
-        ThreadUtils.runOnUiThreadBlocking(
-                () -> {
-                    Assert.assertEquals(
-                            ActivityType.TABBED, UmaActivityObserver.getCurrentActivityType());
-                });
-        mInOrder.verify(mUmaSessionStatsJniSpy, Mockito.times(1)).umaResumeSession(anyLong());
-        mInOrder.verify(mUmaSessionStatsJniSpy, Mockito.times(0)).umaEndSession(anyLong());
-
-        // Open settings, preserving the session.
-        SettingsStation settingsStation = pageInFirstWindow.openRegularTabAppMenu().openSettings();
-        ThreadUtils.runOnUiThreadBlocking(
-                () -> {
-                    Assert.assertEquals(
-                            ActivityType.TABBED, UmaActivityObserver.getCurrentActivityType());
-                });
-        mInOrder.verify(mUmaSessionStatsJniSpy, Mockito.times(0)).umaResumeSession(anyLong());
-        mInOrder.verify(mUmaSessionStatsJniSpy, Mockito.times(0)).umaEndSession(anyLong());
-
-        // Start dialer for result so we can close it.
-        int requestCode = 1234;
-        Intent dialerIntent = new Intent(Intent.ACTION_DIAL);
-        dialerIntent.setData(Uri.parse("tel:0123456789"));
-        try {
-            settingsStation.getActivity().startActivityForResult(dialerIntent, 1234);
-            CriteriaHelper.pollUiThread(
-                    () ->
-                            ApplicationStatus.getStateForActivity(settingsStation.getActivity())
-                                    == ActivityState.STOPPED);
-            mInOrder.verify(mUmaSessionStatsJniSpy, Mockito.times(0)).umaResumeSession(anyLong());
-            mInOrder.verify(mUmaSessionStatsJniSpy, Mockito.times(1)).umaEndSession(anyLong());
-        } finally {
-            // Close dialer.
-            settingsStation.getActivity().finishActivity(requestCode);
-        }
-
-        CriteriaHelper.pollUiThread(
-                () ->
-                        ApplicationStatus.getStateForActivity(settingsStation.getActivity())
-                                == ActivityState.RESUMED);
-
-        // Ideally we would re-start the session here, but this is complicated and enough of an edge
-        // case that it's not worth fixing for now.
-        mInOrder.verify(mUmaSessionStatsJniSpy, Mockito.times(0)).umaResumeSession(anyLong());
-        mInOrder.verify(mUmaSessionStatsJniSpy, Mockito.times(0)).umaEndSession(anyLong());
-
-        // Close settings and return to Tabbed activity.
-        settingsStation.getActivity().finish();
-        CriteriaHelper.pollUiThread(
-                () ->
-                        ApplicationStatus.getStateForActivity(mCtaTestRule.getActivity())
-                                == ActivityState.RESUMED);
-
-        ThreadUtils.runOnUiThreadBlocking(
-                () -> {
-                    Assert.assertEquals(
-                            ActivityType.TABBED, UmaActivityObserver.getCurrentActivityType());
-                });
-        mInOrder.verify(mUmaSessionStatsJniSpy, Mockito.times(1)).umaResumeSession(anyLong());
-        mInOrder.verify(mUmaSessionStatsJniSpy, Mockito.times(0)).umaEndSession(anyLong());
-    }
-}
diff --git a/chrome/android/modules/on_demand/javatests/src/org/chromium/chrome/browser/data_import/TargetServiceGrpcTest.java b/chrome/android/modules/on_demand/javatests/src/org/chromium/chrome/browser/data_import/TargetServiceGrpcTest.java
index ce4182b8..6a243dd 100644
--- a/chrome/android/modules/on_demand/javatests/src/org/chromium/chrome/browser/data_import/TargetServiceGrpcTest.java
+++ b/chrome/android/modules/on_demand/javatests/src/org/chromium/chrome/browser/data_import/TargetServiceGrpcTest.java
@@ -6,6 +6,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import static org.chromium.base.ThreadUtils.runOnUiThreadBlocking;
@@ -43,10 +44,8 @@
 import org.chromium.components.bookmarks.BookmarkId;
 import org.chromium.url.GURL;
 
-import java.io.FileOutputStream;
+import java.io.File;
 import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Paths;
 import java.util.List;
 import java.util.concurrent.TimeoutException;
 
@@ -121,47 +120,12 @@
     @Test
     @MediumTest
     public void testImportBookmarks_Basic() throws Exception {
-        String bookmarksFilePath =
-                UrlUtils.getTestFilePath("android/bookmarks/Valid_entries.html");
-        byte[] bookmarksContent = Files.readAllBytes(Paths.get(bookmarksFilePath));
+        String bookmarksFilePath = UrlUtils.getTestFilePath("android/bookmarks/Valid_entries.html");
+        ParcelFileDescriptor file =
+                ParcelFileDescriptor.open(
+                        new File(bookmarksFilePath), ParcelFileDescriptor.MODE_READ_ONLY);
 
-        ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
-        ParcelFileDescriptor readSide = pipe[0];
-
-        // The write side of the pipe will be closed automatically by the AutoCloseOutputStream.
-        try (FileOutputStream fos = new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1])) {
-            fos.write(bookmarksContent);
-        }
-
-        Metadata headers = new Metadata();
-        headers.put(
-                DataImporterServiceImpl.ParcelableMetadataInterceptor.PFD_METADATA_KEY, readSide);
-
-        BrowserFileMetadata fileMetadata =
-                BrowserFileMetadata.newBuilder()
-                        .setFileType(BrowserFileType.BROWSER_FILE_TYPE_BOOKMARKS)
-                        .build();
-        ImportItemRequest request =
-                ImportItemRequest.newBuilder()
-                        .setItemType(SystemAppApiItemType.SYSTEM_APP_API_ITEM_TYPE_BROWSER_DATA)
-                        .setSessionId(SESSION_ID)
-                        .setFileMetadata(
-                                Proto3Any.newBuilder().setValue(fileMetadata.toByteString()))
-                        .build();
-
-        TargetServiceGrpc.TargetServiceBlockingStub stubWithHeaders =
-                mStub.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(headers));
-        stubWithHeaders.importItem(request);
-
-        ImportItemsDoneRequest doneRequest =
-                ImportItemsDoneRequest.newBuilder()
-                        .setItemType(SystemAppApiItemType.SYSTEM_APP_API_ITEM_TYPE_BROWSER_DATA)
-                        .setSessionId(SESSION_ID)
-                        .setStatus(ImportItemsDoneRequest.CompleteStatus.COMPLETE_STATUS_SUCCESS)
-                        .build();
-        ImportItemsDoneResponse doneResponse = mStub.importItemsDone(doneRequest);
-        assertEquals(
-                /* amount of successful imported files */ 1, doneResponse.getSuccessItemCount());
+        importBrowserFile(file, BrowserFileType.BROWSER_FILE_TYPE_BOOKMARKS);
 
         final BookmarkModel bookmarkModel = waitForBookmarkModelLoaded();
         runOnUiThreadBlocking(
@@ -198,6 +162,78 @@
                 });
     }
 
+    @Test
+    @MediumTest
+    public void testImportReadingList() throws Exception {
+        String readinglistFilePath =
+                UrlUtils.getTestFilePath("android/bookmarks/Valid_reading_list_entry.html");
+        ParcelFileDescriptor file =
+                ParcelFileDescriptor.open(
+                        new File(readinglistFilePath), ParcelFileDescriptor.MODE_READ_ONLY);
+
+        importBrowserFile(file, BrowserFileType.BROWSER_FILE_TYPE_READING_LIST);
+
+        runOnUiThreadBlocking(
+                () -> ChromeBrowserInitializer.getInstance().handleSynchronousStartup());
+        final BookmarkModel bookmarkModel = waitForBookmarkModelLoaded();
+        runOnUiThreadBlocking(
+                () -> {
+                    BookmarkId readingListFolder =
+                            bookmarkModel.getLocalOrSyncableReadingListFolder();
+                    assertFalse(
+                            "Reading list should not be empty",
+                            bookmarkModel.getChildIds(readingListFolder).isEmpty());
+                    GURL url = new GURL("https://www.chromium.org/");
+                    assertTrue(
+                            "Reading list item should be present", bookmarkModel.isBookmarked(url));
+                    List<BookmarkId> bookmarkIds = bookmarkModel.searchBookmarks(url.getSpec(), 1);
+                    assertFalse("Bookmark ID list should not be empty", bookmarkIds.isEmpty());
+                    BookmarkId bookmarkId = bookmarkIds.get(0);
+                    assertEquals(
+                            "Reading list item title should match",
+                            "Chromium",
+                            bookmarkModel.getBookmarkById(bookmarkId).getTitle());
+                    assertEquals(
+                            "Item should be in reading list folder",
+                            readingListFolder,
+                            bookmarkModel.getBookmarkById(bookmarkId).getParentId());
+                });
+    }
+
+    private void importBrowserFile(ParcelFileDescriptor readSide, BrowserFileType fileType) {
+        Metadata headers = new Metadata();
+        headers.put(
+                DataImporterServiceImpl.ParcelableMetadataInterceptor.PFD_METADATA_KEY, readSide);
+
+        BrowserFileMetadata fileMetadata =
+                BrowserFileMetadata.newBuilder().setFileType(fileType).build();
+        ImportItemRequest request =
+                ImportItemRequest.newBuilder()
+                        .setItemType(SystemAppApiItemType.SYSTEM_APP_API_ITEM_TYPE_BROWSER_DATA)
+                        .setSessionId(SESSION_ID)
+                        .setFileMetadata(
+                                Proto3Any.newBuilder().setValue(fileMetadata.toByteString()))
+                        .build();
+
+        TargetServiceGrpc.TargetServiceBlockingStub stubWithHeaders =
+                mStub.withInterceptors(MetadataUtils.newAttachHeadersInterceptor(headers));
+        ImportItemResponse response = stubWithHeaders.importItem(request);
+        assertNotNull(response);
+        assertEquals(
+                ImportItemResponse.TransferError.TRANSFER_ERROR_UNSPECIFIED,
+                response.getTransferError());
+
+        ImportItemsDoneRequest doneRequest =
+                ImportItemsDoneRequest.newBuilder()
+                        .setItemType(SystemAppApiItemType.SYSTEM_APP_API_ITEM_TYPE_BROWSER_DATA)
+                        .setSessionId(SESSION_ID)
+                        .setStatus(ImportItemsDoneRequest.CompleteStatus.COMPLETE_STATUS_SUCCESS)
+                        .build();
+        ImportItemsDoneResponse doneResponse = mStub.importItemsDone(doneRequest);
+        assertEquals(
+                /* amount of successful imported files */ 1, doneResponse.getSuccessItemCount());
+    }
+
     /**
      * Waits until the bookmark model is loaded, i.e. until {@link
      * BookmarkModel#isBookmarkModelLoaded()} is true.
diff --git a/chrome/android/profiles/arm.newest.txt b/chrome/android/profiles/arm.newest.txt
index 643980f..936015f 100644
--- a/chrome/android/profiles/arm.newest.txt
+++ b/chrome/android/profiles/arm.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-142.0.7391.0_pre1509560_rc-r1-merged.afdo.bz2
+chromeos-chrome-arm-142.0.7394.0_pre1510892_rc-r2-merged.afdo.bz2
diff --git a/chrome/browser/accessibility/image_annotation_browsertest.cc b/chrome/browser/accessibility/image_annotation_browsertest.cc
index 72b3af2..c515127d 100644
--- a/chrome/browser/accessibility/image_annotation_browsertest.cc
+++ b/chrome/browser/accessibility/image_annotation_browsertest.cc
@@ -138,6 +138,26 @@
       return;
     }
 
+    processors_.emplace_back(std::move(image_processor));
+    processors_.back()->GetJpgImageData(base::BindOnce(
+        &FakeAnnotator::OnJpgImageDataReceived, base::Unretained(this),
+        std::move(image_id), std::move(description_language_tag),
+        std::move(callback)));
+  }
+
+  void OnJpgImageDataReceived(const std::string& image_id,
+                              const std::string& description_language_tag,
+                              AnnotateImageCallback callback,
+                              const std::vector<uint8_t>& image_bytes,
+                              const int32_t width,
+                              const int32_t height) {
+    if (image_bytes.empty()) {
+      std::move(callback).Run(
+          image_annotation::mojom::AnnotateImageResult::NewErrorCode(
+              image_annotation::mojom::AnnotateImageError::kFailure));
+      return;
+    }
+
     // Use the filename to create annotation strings. Check a map from filename
     // to desired label, otherwise just construct a string based on the
     // filename. Adds some trailing whitespace and punctuation to check that
@@ -173,6 +193,8 @@
 
  private:
   mojo::ReceiverSet<image_annotation::mojom::Annotator> receivers_;
+  std::vector<mojo::Remote<image_annotation::mojom::ImageProcessor>>
+      processors_;
   static bool return_ocr_results_;
   static bool return_label_results_;
   static std::map<std::string, std::string> custom_label_result_mapping_;
@@ -649,3 +671,34 @@
     snapshot = content::GetAccessibilityTreeSnapshot(web_contents);
   }
 }
+
+IN_PROC_BROWSER_TEST_F(ImageAnnotationBrowserTest, LazyLoadingImages) {
+  FakeAnnotator::SetReturnOcrResults(true);
+  FakeAnnotator::SetReturnLabelResults(true);
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(
+      browser(),
+      https_server_.GetURL("/accessibility/page_with_lazy_image.html")));
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  content::WaitForAccessibilityTreeToContainNodeWithName(
+      web_contents,
+      "Appears to say: green.png Annotation. Appears to be: green.png 'en' "
+      "Label");
+  EXPECT_EQ(1u, DescribeNodesWithAnnotations(
+                    content::GetAccessibilityTreeSnapshot(web_contents))
+                    .size());
+
+  base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+  base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
+      FROM_HERE, run_loop.QuitWhenIdleClosure(), base::Milliseconds(500));
+  run_loop.Run();
+  web_contents->ScrollToBottomOfDocument();
+
+  content::WaitForAccessibilityTreeToContainNodeWithName(
+      web_contents,
+      "Appears to say: red.png Annotation. Appears to be: red.png 'en' Label");
+  EXPECT_EQ(2u, DescribeNodesWithAnnotations(
+                    content::GetAccessibilityTreeSnapshot(web_contents))
+                    .size());
+}
diff --git a/chrome/browser/ash/exo/chrome_data_exchange_delegate_unittest.cc b/chrome/browser/ash/exo/chrome_data_exchange_delegate_unittest.cc
index 00939499..3e7f0aa 100644
--- a/chrome/browser/ash/exo/chrome_data_exchange_delegate_unittest.cc
+++ b/chrome/browser/ash/exo/chrome_data_exchange_delegate_unittest.cc
@@ -118,7 +118,8 @@
   arc_toplevel->SetProperty(chromeos::kAppTypeKey, chromeos::AppType::ARC_APP);
   ASSERT_TRUE(IsArcWindow(arc_toplevel));
   aura::Window* arc_window =
-      aura::test::CreateTestWindowWithBounds(gfx::Rect(), arc_toplevel);
+      aura::test::CreateTestWindow({.bounds = gfx::Rect()}, arc_toplevel)
+          .release();
   ASSERT_TRUE(IsArcWindow(arc_window->GetToplevelWindow()));
 
   // Crostini:
@@ -128,7 +129,8 @@
                                  chromeos::AppType::CROSTINI_APP);
   ASSERT_TRUE(crostini::IsCrostiniWindow(crostini_toplevel));
   aura::Window* crostini_window =
-      aura::test::CreateTestWindowWithBounds(gfx::Rect(), crostini_toplevel);
+      aura::test::CreateTestWindow({.bounds = gfx::Rect()}, crostini_toplevel)
+          .release();
   ASSERT_TRUE(crostini::IsCrostiniWindow(crostini_window->GetToplevelWindow()));
 
   // Plugin VM:
@@ -137,7 +139,8 @@
   exo::SetShellApplicationId(plugin_vm_toplevel, "org.chromium.plugin_vm_ui");
   ASSERT_TRUE(plugin_vm::IsPluginVmAppWindow(plugin_vm_toplevel));
   aura::Window* plugin_vm_window =
-      aura::test::CreateTestWindowWithBounds(gfx::Rect(), plugin_vm_toplevel);
+      aura::test::CreateTestWindow({.bounds = gfx::Rect()}, plugin_vm_toplevel)
+          .release();
   ASSERT_TRUE(
       plugin_vm::IsPluginVmAppWindow(plugin_vm_window->GetToplevelWindow()));
 
diff --git a/chrome/browser/ash/policy/status_collector/device_status_collector_unittest.cc b/chrome/browser/ash/policy/status_collector/device_status_collector_unittest.cc
index 57e81b6..1f2a1940 100644
--- a/chrome/browser/ash/policy/status_collector/device_status_collector_unittest.cc
+++ b/chrome/browser/ash/policy/status_collector/device_status_collector_unittest.cc
@@ -2,11 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifdef UNSAFE_BUFFERS_BUILD
-// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "chrome/browser/ash/policy/status_collector/device_status_collector.h"
 
 #include <stddef.h>
@@ -24,6 +19,7 @@
 #include "ash/constants/ash_features.h"
 #include "ash/constants/ash_pref_names.h"
 #include "base/check_deref.h"
+#include "base/containers/span.h"
 #include "base/environment.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -391,10 +387,10 @@
     test_clock_->SetNow(base::Time::Now().LocalMidnight() + kHour);
   }
 
-  void Simulate(ui::IdleState* states, int len) {
-    for (int i = 0; i < len; i++) {
+  void Simulate(base::span<const ui::IdleState> states) {
+    for (const auto& state : states) {
       test_clock_->Advance(DeviceStatusCollector::kIdlePollInterval);
-      ProcessIdleState(states[i]);
+      ProcessIdleState(state);
     }
   }
 
@@ -1261,8 +1257,8 @@
 
 TEST_F(DeviceStatusCollectorTest, AllIdle) {
   DisableDefaultSettings();
-  ui::IdleState test_states[] = {ui::IDLE_STATE_IDLE, ui::IDLE_STATE_IDLE,
-                                 ui::IDLE_STATE_IDLE};
+  const std::array<ui::IdleState, 3> test_states = {
+      ui::IDLE_STATE_IDLE, ui::IDLE_STATE_IDLE, ui::IDLE_STATE_IDLE};
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
       ash::kReportDeviceActivityTimes, true);
 
@@ -1272,14 +1268,13 @@
   EXPECT_EQ(0, GetActiveMilliseconds(device_status_));
 
   // Test reporting with a single idle sample.
-  status_collector_->Simulate(test_states, 1);
+  status_collector_->Simulate(base::span(test_states).first(1u));
   GetStatus();
   EXPECT_EQ(0, device_status_.active_periods_size());
   EXPECT_EQ(0, GetActiveMilliseconds(device_status_));
 
   // Test reporting with multiple consecutive idle samples.
-  status_collector_->Simulate(test_states,
-                              sizeof(test_states) / sizeof(ui::IdleState));
+  status_collector_->Simulate(test_states);
   GetStatus();
   EXPECT_EQ(0, device_status_.active_periods_size());
   EXPECT_EQ(0, GetActiveMilliseconds(device_status_));
@@ -1287,13 +1282,13 @@
 
 TEST_F(DeviceStatusCollectorTest, AllActive) {
   DisableDefaultSettings();
-  ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
-                                 ui::IDLE_STATE_ACTIVE};
+  const std::array<ui::IdleState, 3> test_states = {
+      ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE};
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
       ash::kReportDeviceActivityTimes, true);
 
   // Test a single active sample.
-  status_collector_->Simulate(test_states, 1);
+  status_collector_->Simulate(base::span(test_states).first(1u));
   GetStatus();
   EXPECT_EQ(1, device_status_.active_periods_size());
   EXPECT_EQ(1 * ActivePeriodMilliseconds(),
@@ -1301,8 +1296,7 @@
   device_status_.clear_active_periods();  // Clear the result protobuf.
 
   // Test multiple consecutive active samples.
-  status_collector_->Simulate(test_states,
-                              sizeof(test_states) / sizeof(ui::IdleState));
+  status_collector_->Simulate(test_states);
   GetStatus();
   EXPECT_EQ(1, device_status_.active_periods_size());
   EXPECT_EQ(4 * ActivePeriodMilliseconds(),
@@ -1311,15 +1305,14 @@
 
 TEST_F(DeviceStatusCollectorTest, MixedStates) {
   DisableDefaultSettings();
-  ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_IDLE,
-                                 ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
-                                 ui::IDLE_STATE_IDLE,   ui::IDLE_STATE_IDLE,
-                                 ui::IDLE_STATE_ACTIVE};
+  const std::array<ui::IdleState, 7> test_states = {
+      ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_IDLE, ui::IDLE_STATE_ACTIVE,
+      ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_IDLE, ui::IDLE_STATE_IDLE,
+      ui::IDLE_STATE_ACTIVE};
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
       ash::kReportDeviceActivityTimes, true);
 
-  status_collector_->Simulate(test_states,
-                              sizeof(test_states) / sizeof(ui::IdleState));
+  status_collector_->Simulate(test_states);
   GetStatus();
   EXPECT_EQ(4 * ActivePeriodMilliseconds(),
             GetActiveMilliseconds(device_status_));
@@ -1328,7 +1321,7 @@
 // For kiosks report total uptime instead of only active periods.
 TEST_F(DeviceStatusCollectorTest, MixedStatesForKiosk) {
   DisableDefaultSettings();
-  ui::IdleState test_states[] = {
+  const std::array<ui::IdleState, 6> test_states = {
       ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_IDLE, ui::IDLE_STATE_ACTIVE,
       ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_IDLE, ui::IDLE_STATE_IDLE,
   };
@@ -1336,8 +1329,7 @@
       ash::LoginState::LOGGED_IN_ACTIVE, ash::LoginState::LOGGED_IN_USER_KIOSK);
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
       ash::kReportDeviceActivityTimes, true);
-  status_collector_->Simulate(test_states,
-                              sizeof(test_states) / sizeof(ui::IdleState));
+  status_collector_->Simulate(test_states);
   GetStatus();
   EXPECT_EQ(6 * ActivePeriodMilliseconds(),
             GetActiveMilliseconds(device_status_));
@@ -1345,20 +1337,18 @@
 
 TEST_F(DeviceStatusCollectorTest, StateKeptInPref) {
   DisableDefaultSettings();
-  ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_IDLE,
-                                 ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
-                                 ui::IDLE_STATE_IDLE,   ui::IDLE_STATE_IDLE};
+  const std::array<ui::IdleState, 6> test_states = {
+      ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_IDLE, ui::IDLE_STATE_ACTIVE,
+      ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_IDLE, ui::IDLE_STATE_IDLE};
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
       ash::kReportDeviceActivityTimes, true);
-  status_collector_->Simulate(test_states,
-                              sizeof(test_states) / sizeof(ui::IdleState));
+  status_collector_->Simulate(test_states);
 
   // Process the list a second time after restarting the collector. It should be
   // able to count the active periods found by the original collector, because
   // the results are stored in a pref.
   RestartStatusCollector(CreateEmptyDeviceStatusCollectorOptions());
-  status_collector_->Simulate(test_states,
-                              sizeof(test_states) / sizeof(ui::IdleState));
+  status_collector_->Simulate(test_states);
 
   GetStatus();
   EXPECT_EQ(6 * ActivePeriodMilliseconds(),
@@ -1372,10 +1362,9 @@
   EXPECT_THAT(profile_pref_service_.GetDict(prefs::kUserActivityTimes),
               IsEmpty());
 
-  ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
-                                 ui::IDLE_STATE_ACTIVE};
-  status_collector_->Simulate(test_states,
-                              sizeof(test_states) / sizeof(ui::IdleState));
+  const std::array<ui::IdleState, 3> test_states = {
+      ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE};
+  status_collector_->Simulate(test_states);
   GetStatus();
   EXPECT_EQ(1, device_status_.active_periods_size());
   EXPECT_EQ(3 * ActivePeriodMilliseconds(),
@@ -1389,7 +1378,8 @@
 
 TEST_F(DeviceStatusCollectorTest, MaxStoredPeriods) {
   DisableDefaultSettings();
-  ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_IDLE};
+  const std::array<ui::IdleState, 2> test_states = {ui::IDLE_STATE_ACTIVE,
+                                                    ui::IDLE_STATE_IDLE};
   const int kMaxDays = 10;
 
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
@@ -1401,8 +1391,7 @@
 
   // Simulate 12 active periods.
   for (int i = 0; i < kMaxDays + 2; i++) {
-    status_collector_->Simulate(test_states,
-                                sizeof(test_states) / sizeof(ui::IdleState));
+    status_collector_->Simulate(test_states);
     // Advance the simulated clock by a day.
     test_clock_.Advance(base::Days(1));
   }
@@ -1413,8 +1402,7 @@
 
   // Simulate some future times.
   for (int i = 0; i < kMaxDays + 2; i++) {
-    status_collector_->Simulate(test_states,
-                                sizeof(test_states) / sizeof(ui::IdleState));
+    status_collector_->Simulate(test_states);
     // Advance the simulated clock by a day.
     test_clock_.Advance(base::Days(1));
   }
@@ -1422,7 +1410,7 @@
   test_clock_.Advance(-base::Days(20));
 
   // Collect one more data point to trigger pruning.
-  status_collector_->Simulate(test_states, 1);
+  status_collector_->Simulate(base::span(test_states).first(1u));
 
   // Check that we don't exceed the max number of periods.
   device_status_.clear_active_periods();
@@ -1432,10 +1420,9 @@
 
 TEST_F(DeviceStatusCollectorTest, ActivityTimesEnabledByDefault) {
   // Device activity times should be reported by default.
-  ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
-                                 ui::IDLE_STATE_ACTIVE};
-  status_collector_->Simulate(test_states,
-                              sizeof(test_states) / sizeof(ui::IdleState));
+  const std::array<ui::IdleState, 3> test_states = {
+      ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE};
+  status_collector_->Simulate(test_states);
   GetStatus();
   EXPECT_EQ(1, device_status_.active_periods_size());
   EXPECT_EQ(3 * ActivePeriodMilliseconds(),
@@ -1446,10 +1433,9 @@
   // Device activity times should not be reported while disabled.
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
       ash::kReportDeviceActivityTimes, false);
-  ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
-                                 ui::IDLE_STATE_ACTIVE};
-  status_collector_->Simulate(test_states,
-                              sizeof(test_states) / sizeof(ui::IdleState));
+  const std::array<ui::IdleState, 3> test_states = {
+      ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE};
+  status_collector_->Simulate(test_states);
   GetStatus();
   EXPECT_EQ(0, device_status_.active_periods_size());
   EXPECT_EQ(0, GetActiveMilliseconds(device_status_));
@@ -1457,14 +1443,14 @@
 
 TEST_F(DeviceStatusCollectorTest, ActivityCrossingMidnight) {
   DisableDefaultSettings();
-  ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE};
+  const std::array<ui::IdleState, 1> test_states = {ui::IDLE_STATE_ACTIVE};
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
       ash::kReportDeviceActivityTimes, true);
 
   // Set the baseline time to 20 seconds before midnight.
   test_clock_.SetNow(base::Time::Now().LocalMidnight() - base::Seconds(20));
 
-  status_collector_->Simulate(test_states, 1);
+  status_collector_->Simulate(test_states);
   GetStatus();
   ASSERT_EQ(2, device_status_.active_periods_size());
 
@@ -1487,7 +1473,7 @@
 
 TEST_F(DeviceStatusCollectorTest, ActivityTimesKeptUntilSubmittedSuccessfully) {
   DisableDefaultSettings();
-  ui::IdleState test_states[] = {
+  const std::array<ui::IdleState, 2> test_states = {
       ui::IDLE_STATE_ACTIVE,
       ui::IDLE_STATE_ACTIVE,
   };
@@ -1499,7 +1485,7 @@
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
       ash::kReportDeviceActivityTimes, true);
 
-  status_collector_->Simulate(test_states, 2);
+  status_collector_->Simulate(base::span(test_states).first(2u));
   GetStatus();
   EXPECT_EQ(2 * ActivePeriodMilliseconds(),
             GetActiveMilliseconds(device_status_));
@@ -1516,7 +1502,7 @@
 
   // After indicating a successful submit, the submitted status gets cleared,
   // and prior activity is no longer showing.
-  status_collector_->Simulate(test_states, 1);
+  status_collector_->Simulate(base::span(test_states).first(1u));
   status_collector_->OnSubmittedSuccessfully();
   GetStatus();
   EXPECT_EQ(0, GetActiveMilliseconds(device_status_));
@@ -1524,8 +1510,8 @@
 
 TEST_F(DeviceStatusCollectorTest, ActivityNoUser) {
   DisableDefaultSettings();
-  ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
-                                 ui::IDLE_STATE_ACTIVE};
+  const std::array<ui::IdleState, 3> test_states = {
+      ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE};
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
       ash::kReportDeviceActivityTimes, true);
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
@@ -1534,7 +1520,7 @@
   EXPECT_FALSE(status_collector_->IsReportingActivityTimes());
   EXPECT_FALSE(status_collector_->IsReportingUsers());
 
-  status_collector_->Simulate(test_states, 3);
+  status_collector_->Simulate(test_states);
   GetStatus();
   EXPECT_EQ(1, device_status_.active_periods_size());
   EXPECT_TRUE(device_status_.active_periods(0).user_email().empty());
@@ -1543,8 +1529,8 @@
 
 TEST_F(DeviceStatusCollectorTest, ActivityWithPublicSessionUser) {
   DisableDefaultSettings();
-  ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
-                                 ui::IDLE_STATE_ACTIVE};
+  const std::array<ui::IdleState, 3> test_states = {
+      ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE};
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
       ash::kReportDeviceActivityTimes, true);
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
@@ -1560,7 +1546,7 @@
   EXPECT_FALSE(status_collector_->IsReportingActivityTimes());
   EXPECT_FALSE(status_collector_->IsReportingUsers());
 
-  status_collector_->Simulate(test_states, 3);
+  status_collector_->Simulate(test_states);
   GetStatus();
   EXPECT_EQ(1, device_status_.active_periods_size());
   EXPECT_TRUE(device_status_.active_periods(0).user_email().empty());
@@ -1570,8 +1556,8 @@
 
 TEST_F(DeviceStatusCollectorTest, ActivityWithKioskUser) {
   DisableDefaultSettings();
-  ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
-                                 ui::IDLE_STATE_ACTIVE};
+  const std::array<ui::IdleState, 3> test_states = {
+      ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE};
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
       ash::kReportDeviceActivityTimes, true);
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
@@ -1587,7 +1573,7 @@
   EXPECT_FALSE(status_collector_->IsReportingActivityTimes());
   EXPECT_FALSE(status_collector_->IsReportingUsers());
 
-  status_collector_->Simulate(test_states, 3);
+  status_collector_->Simulate(test_states);
   GetStatus();
   EXPECT_EQ(1, device_status_.active_periods_size());
   EXPECT_TRUE(device_status_.active_periods(0).user_email().empty());
@@ -1597,8 +1583,8 @@
 
 TEST_F(DeviceStatusCollectorTest, ActivityWithIwaKioskUser) {
   DisableDefaultSettings();
-  ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
-                                 ui::IDLE_STATE_ACTIVE};
+  const std::array<ui::IdleState, 3> test_states = {
+      ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE};
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
       ash::kReportDeviceActivityTimes, true);
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
@@ -1614,7 +1600,7 @@
   EXPECT_FALSE(status_collector_->IsReportingActivityTimes());
   EXPECT_FALSE(status_collector_->IsReportingUsers());
 
-  status_collector_->Simulate(test_states, 3);
+  status_collector_->Simulate(test_states);
   GetStatus();
   EXPECT_EQ(1, device_status_.active_periods_size());
   EXPECT_TRUE(device_status_.active_periods(0).user_email().empty());
@@ -1624,8 +1610,8 @@
 
 TEST_F(DeviceStatusCollectorTest, ActivityWithAffiliatedUser) {
   DisableDefaultSettings();
-  ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
-                                 ui::IDLE_STATE_ACTIVE};
+  const std::array<ui::IdleState, 3> test_states = {
+      ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE};
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
       ash::kReportDeviceActivityTimes, true);
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
@@ -1640,7 +1626,7 @@
   EXPECT_TRUE(status_collector_->IsReportingActivityTimes());
   EXPECT_TRUE(status_collector_->IsReportingUsers());
 
-  status_collector_->Simulate(test_states, 3);
+  status_collector_->Simulate(test_states);
   GetStatus();
   EXPECT_EQ(1, device_status_.active_periods_size());
   EXPECT_EQ(account_id0.GetUserEmail(),
@@ -1655,7 +1641,7 @@
   EXPECT_TRUE(status_collector_->IsReportingActivityTimes());
   EXPECT_FALSE(status_collector_->IsReportingUsers());
 
-  status_collector_->Simulate(test_states, 3);
+  status_collector_->Simulate(test_states);
   GetStatus();
   EXPECT_EQ(1, device_status_.active_periods_size());
   EXPECT_TRUE(device_status_.active_periods(0).user_email().empty());
@@ -1664,8 +1650,8 @@
 
 TEST_F(DeviceStatusCollectorTest, ActivityWithNotAffiliatedUser) {
   DisableDefaultSettings();
-  ui::IdleState test_states[] = {ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE,
-                                 ui::IDLE_STATE_ACTIVE};
+  const std::array<ui::IdleState, 3> test_states = {
+      ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE, ui::IDLE_STATE_ACTIVE};
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
       ash::kReportDeviceActivityTimes, true);
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
@@ -1680,7 +1666,7 @@
   EXPECT_FALSE(status_collector_->IsReportingActivityTimes());
   EXPECT_FALSE(status_collector_->IsReportingUsers());
 
-  status_collector_->Simulate(test_states, 3);
+  status_collector_->Simulate(test_states);
   GetStatus();
   EXPECT_EQ(1, device_status_.active_periods_size());
   EXPECT_TRUE(device_status_.active_periods(0).user_email().empty());
@@ -1693,7 +1679,7 @@
   EXPECT_FALSE(status_collector_->IsReportingActivityTimes());
   EXPECT_FALSE(status_collector_->IsReportingUsers());
 
-  status_collector_->Simulate(test_states, 3);
+  status_collector_->Simulate(test_states);
   GetStatus();
   EXPECT_EQ(1, device_status_.active_periods_size());
   EXPECT_TRUE(device_status_.active_periods(0).user_email().empty());
@@ -2691,21 +2677,22 @@
   scoped_testing_cros_settings_.device_settings()->SetBoolean(
       ash::kReportOsUpdateStatus, true);
 
-  const char* kRequiredPlatformVersions[] = {"1234", "1234.0", "1234.0.0"};
+  const std::array<const char*, 3> kRequiredPlatformVersions = {
+      "1234", "1234.0", "1234.0.0"};
 
-  for (size_t i = 0; i < std::size(kRequiredPlatformVersions); ++i) {
+  for (const char* version : kRequiredPlatformVersions) {
     MockAutoLaunchKioskAppWithRequiredPlatformVersion(
-        fake_kiosk_device_local_account_, kRequiredPlatformVersions[i]);
+        fake_kiosk_device_local_account_, version);
 
     GetStatus();
     ASSERT_TRUE(device_status_.has_os_update_status())
-        << "Required platform version=" << kRequiredPlatformVersions[i];
+        << "Required platform version=" << version;
     EXPECT_EQ(em::OsUpdateStatus::OS_UP_TO_DATE,
               device_status_.os_update_status().update_status())
-        << "Required platform version=" << kRequiredPlatformVersions[i];
-    EXPECT_EQ(kRequiredPlatformVersions[i],
+        << "Required platform version=" << version;
+    EXPECT_EQ(version,
               device_status_.os_update_status().new_required_platform_version())
-        << "Required platform version=" << kRequiredPlatformVersions[i];
+        << "Required platform version=" << version;
   }
 }
 
@@ -2739,14 +2726,14 @@
   EXPECT_EQ(em::OsUpdateStatus::OS_IMAGE_DOWNLOAD_NOT_STARTED,
             device_status_.os_update_status().update_status());
 
-  const update_engine::Operation kUpdateEngineOps[] = {
+  const std::array<update_engine::Operation, 3> kUpdateEngineOps = {
       update_engine::Operation::DOWNLOADING,
       update_engine::Operation::VERIFYING,
       update_engine::Operation::FINALIZING,
   };
 
-  for (size_t i = 0; i < std::size(kUpdateEngineOps); ++i) {
-    update_status.set_current_operation(kUpdateEngineOps[i]);
+  for (const auto op : kUpdateEngineOps) {
+    update_status.set_current_operation(op);
     update_status.set_new_version("1235.1.2");
     update_engine_client_->PushLastStatus(update_status);
 
@@ -2788,14 +2775,14 @@
   ASSERT_FALSE(
       device_status_.os_update_status().has_new_required_platform_version());
 
-  const update_engine::Operation kUpdateEngineOps[] = {
+  const std::array<update_engine::Operation, 3> kUpdateEngineOps = {
       update_engine::Operation::DOWNLOADING,
       update_engine::Operation::VERIFYING,
       update_engine::Operation::FINALIZING,
   };
 
-  for (size_t i = 0; i < std::size(kUpdateEngineOps); ++i) {
-    update_status.set_current_operation(kUpdateEngineOps[i]);
+  for (const auto op : kUpdateEngineOps) {
+    update_status.set_current_operation(op);
     update_status.set_new_version("1235.1.2");
     update_engine_client_->PushLastStatus(update_status);
 
@@ -2844,12 +2831,12 @@
 
   // Check update multiple times, the timestamp stored in device status should
   // change accordingly.
-  const int64 kLastCheckedTimes[] = {10, 20, 30};
+  const std::array<int64_t, 3> kLastCheckedTimes = {10, 20, 30};
 
-  for (size_t i = 0; i < std::size(kLastCheckedTimes); ++i) {
+  for (const auto time : kLastCheckedTimes) {
     update_engine::StatusResult update_status;
     update_status.set_new_version(kDefaultPlatformVersion);
-    update_status.set_last_checked_time(kLastCheckedTimes[i]);
+    update_status.set_last_checked_time(time);
     update_engine_client_->PushLastStatus(update_status);
 
     GetStatus();
@@ -2858,7 +2845,7 @@
     // The timestamp precision in UpdateEngine is in seconds, but the
     // DeviceStatusCollector is in milliseconds. Therefore, the number should be
     // multiplied by 1000 before validation.
-    ASSERT_EQ(kLastCheckedTimes[i] * 1000,
+    ASSERT_EQ(time * 1000,
               device_status_.os_update_status().last_checked_timestamp());
   }
 }
@@ -3289,15 +3276,16 @@
   // Create a test uploads.log file. One |upload_time| is within last 24 hours,
   // the other is not.
   base::Time now = base::Time::Now();
-  base::Time timestamps[] = {now - base::Hours(22), now - base::Hours(24)};
+  std::array<base::Time, 2> timestamps = {now - base::Hours(22),
+                                          now - base::Hours(24)};
 
   std::stringstream stream;
-  for (int i = 0; i <= 1; ++i) {
+  for (const auto& timestamp : timestamps) {
     stream << "{";
-    stream << "\"upload_time\":\"" << timestamps[i].ToTimeT() << "\",";
+    stream << "\"upload_time\":\"" << timestamp.ToTimeT() << "\",";
     stream << "\"upload_id\":\"" << kTestUploadId << "\",";
     stream << "\"local_id\":\"" << kTestLocalID << "\",";
-    stream << "\"capture_time\":\"" << timestamps[i].ToTimeT() << "\",";
+    stream << "\"capture_time\":\"" << timestamp.ToTimeT() << "\",";
     stream << "\"state\":"
            << static_cast<int>(UploadList::UploadInfo::State::Uploaded) << ",";
     stream << "\"source\":\"" << kTestCauseKernel << "\"";
diff --git a/chrome/browser/autofill/android/save_update_address_profile_prompt_controller.cc b/chrome/browser/autofill/android/save_update_address_profile_prompt_controller.cc
index 0a8e19ab..eacd57d 100644
--- a/chrome/browser/autofill/android/save_update_address_profile_prompt_controller.cc
+++ b/chrome/browser/autofill/android/save_update_address_profile_prompt_controller.cc
@@ -124,9 +124,10 @@
   // Notify user that their address is saved only in Chrome and can be migrated
   // to their Google account.
   if (is_migration_to_account_) {
+    // TODO(crbug.com/40066949): Simplify once ConsentLevel::kSync is not used
+    // anymore, and thus IsSyncFeatureEnabledForAutofill() will always be false.
     return l10n_util::GetStringFUTF16(
-        personal_data_->address_data_manager()
-                .IsAutofillUserSelectableTypeEnabled()
+        personal_data_->address_data_manager().IsSyncFeatureEnabledForAutofill()
             ? IDS_AUTOFILL_SYNCABLE_PROFILE_MIGRATION_PROMPT_NOTICE
             : IDS_AUTOFILL_LOCAL_PROFILE_MIGRATION_PROMPT_NOTICE,
         base::UTF8ToUTF16(account->email));
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_util.cc b/chrome/browser/extensions/api/autofill_private/autofill_util.cc
index ee0e765..212d532 100644
--- a/chrome/browser/extensions/api/autofill_private/autofill_util.cc
+++ b/chrome/browser/extensions/api/autofill_private/autofill_util.cc
@@ -46,7 +46,6 @@
 #include "components/autofill/core/common/credit_card_network_identifiers.h"
 #include "components/prefs/pref_service.h"
 #include "components/strings/grit/components_strings.h"
-#include "components/sync/base/features.h"
 #include "components/sync/base/user_selectable_type.h"
 #include "components/variations/service/variations_service.h"
 #include "extensions/browser/extensions_browser_client.h"
@@ -356,13 +355,8 @@
 
   api::autofill_private::AccountInfo api_account;
   api_account.email = account->email;
-  // TODO(crbug.com/40066949): Remove `is_sync_enabled_for_autofill_profiles`
-  // from `AccountInfo` in favor of `is_autofill_sync_toggle_enabled` after
-  // Sync-the-feature users are migrated to ConsentLevel::kSignin.
   api_account.is_sync_enabled_for_autofill_profiles =
-      base::FeatureList::IsEnabled(syncer::kReplaceSyncPromosWithSignInPromos)
-          ? adm.IsAutofillUserSelectableTypeEnabled()
-          : adm.IsSyncFeatureEnabledForAutofill();
+      adm.IsSyncFeatureEnabledForAutofill();
   api_account.is_eligible_for_address_account_storage =
       adm.IsEligibleForAddressAccountStorage();
   api_account.is_autofill_sync_toggle_enabled =
diff --git a/chrome/browser/local_network_access/OWNERS b/chrome/browser/local_network_access/OWNERS
index c8542ff..930bd8f 100644
--- a/chrome/browser/local_network_access/OWNERS
+++ b/chrome/browser/local_network_access/OWNERS
@@ -1,5 +1 @@
-clamy@chromium.org
-cthomp@chromium.org
-estark@chromium.org
-hchao@chromium.org
-jdeblasio@chromium.org
+file://content/browser/security/local_network_access/OWNERS
diff --git a/chrome/browser/password_manager/android/credential_leak_controller_android.cc b/chrome/browser/password_manager/android/credential_leak_controller_android.cc
index 75ac004..b290cd7 100644
--- a/chrome/browser/password_manager/android/credential_leak_controller_android.cc
+++ b/chrome/browser/password_manager/android/credential_leak_controller_android.cc
@@ -8,7 +8,6 @@
 
 #include "base/android/jni_android.h"
 #include "chrome/browser/password_manager/android/password_checkup_launcher_helper.h"
-#include "chrome/browser/password_manager/android/password_manager_android_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/android/passwords/credential_leak_dialog_view_android.h"
 #include "components/password_manager/core/browser/features/password_features.h"
diff --git a/chrome/browser/password_manager/android/password_manager_settings_service_android_impl.cc b/chrome/browser/password_manager/android/password_manager_settings_service_android_impl.cc
index 0a8175eb..c6a2791 100644
--- a/chrome/browser/password_manager/android/password_manager_settings_service_android_impl.cc
+++ b/chrome/browser/password_manager/android/password_manager_settings_service_android_impl.cc
@@ -12,7 +12,6 @@
 #include "base/functional/bind.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/strings/strcat.h"
-#include "chrome/browser/password_manager/android/password_manager_android_util.h"
 #include "chrome/browser/password_manager/android/password_manager_lifecycle_helper_impl.h"
 #include "chrome/browser/password_manager/android/password_settings_updater_android_bridge_helper.h"
 #include "components/password_manager/core/browser/features/password_features.h"
diff --git a/chrome/browser/password_manager/android/password_settings_updater_android_dispatcher_bridge_impl.cc b/chrome/browser/password_manager/android/password_settings_updater_android_dispatcher_bridge_impl.cc
index 08b2708d..754e0981 100644
--- a/chrome/browser/password_manager/android/password_settings_updater_android_dispatcher_bridge_impl.cc
+++ b/chrome/browser/password_manager/android/password_settings_updater_android_dispatcher_bridge_impl.cc
@@ -8,7 +8,6 @@
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
-#include "chrome/browser/password_manager/android/password_manager_android_util.h"
 #include "chrome/browser/password_manager/android/password_settings_updater_android_dispatcher_bridge.h"
 #include "chrome/browser/password_manager/android/password_settings_updater_android_receiver_bridge.h"
 #include "components/password_manager/core/browser/password_manager_setting.h"
diff --git a/chrome/browser/password_manager/android/password_store_android_account_backend_unittest.cc b/chrome/browser/password_manager/android/password_store_android_account_backend_unittest.cc
index 2434fc90..2b3ab4f 100644
--- a/chrome/browser/password_manager/android/password_store_android_account_backend_unittest.cc
+++ b/chrome/browser/password_manager/android/password_store_android_account_backend_unittest.cc
@@ -21,7 +21,6 @@
 #include "chrome/browser/password_manager/android/fake_password_manager_lifecycle_helper.h"
 #include "chrome/browser/password_manager/android/mock_password_store_android_backend_bridge_helper.h"
 #include "chrome/browser/password_manager/android/mock_password_sync_controller_delegate_bridge.h"
-#include "chrome/browser/password_manager/android/password_manager_android_util.h"
 #include "chrome/browser/password_manager/android/password_manager_lifecycle_helper.h"
 #include "chrome/browser/password_manager/android/password_store_android_backend_api_error_codes.h"
 #include "chrome/browser/password_manager/android/password_store_android_backend_dispatcher_bridge.h"
diff --git a/chrome/browser/password_manager/android/password_store_android_backend_bridge_helper_impl.cc b/chrome/browser/password_manager/android/password_store_android_backend_bridge_helper_impl.cc
index 88225d3..6ecb1238 100644
--- a/chrome/browser/password_manager/android/password_store_android_backend_bridge_helper_impl.cc
+++ b/chrome/browser/password_manager/android/password_store_android_backend_bridge_helper_impl.cc
@@ -14,7 +14,6 @@
 #include "base/task/bind_post_task.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
-#include "chrome/browser/password_manager/android/password_manager_android_util.h"
 #include "chrome/browser/password_manager/android/password_store_android_backend_dispatcher_bridge.h"
 #include "chrome/browser/password_manager/android/password_store_android_backend_receiver_bridge.h"
 #include "components/password_manager/core/browser/password_form.h"
diff --git a/chrome/browser/password_manager/android/password_store_android_backend_dispatcher_bridge_impl.cc b/chrome/browser/password_manager/android/password_store_android_backend_dispatcher_bridge_impl.cc
index d46555a..a36b014 100644
--- a/chrome/browser/password_manager/android/password_store_android_backend_dispatcher_bridge_impl.cc
+++ b/chrome/browser/password_manager/android/password_store_android_backend_dispatcher_bridge_impl.cc
@@ -11,7 +11,6 @@
 #include "base/android/jni_android.h"
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
-#include "chrome/browser/password_manager/android/password_manager_android_util.h"
 #include "chrome/browser/password_manager/android/protos/list_passwords_result.pb.h"
 #include "chrome/browser/password_manager/android/protos/password_with_local_data.pb.h"
 #include "chrome/browser/password_manager/android/unified_password_manager_proto_utils.h"
diff --git a/chrome/browser/password_manager/android/password_sync_controller_delegate_bridge_impl.cc b/chrome/browser/password_manager/android/password_sync_controller_delegate_bridge_impl.cc
index 590917bd..15f59df 100644
--- a/chrome/browser/password_manager/android/password_sync_controller_delegate_bridge_impl.cc
+++ b/chrome/browser/password_manager/android/password_sync_controller_delegate_bridge_impl.cc
@@ -6,7 +6,6 @@
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
-#include "chrome/browser/password_manager/android/password_manager_android_util.h"
 #include "components/password_manager/core/browser/password_store/android_backend_error.h"
 #include "components/password_manager/core/common/password_manager_features.h"
 
diff --git a/chrome/browser/password_manager/android/save_update_password_message_delegate.cc b/chrome/browser/password_manager/android/save_update_password_message_delegate.cc
index 1288ddd0..cf1cada 100644
--- a/chrome/browser/password_manager/android/save_update_password_message_delegate.cc
+++ b/chrome/browser/password_manager/android/save_update_password_message_delegate.cc
@@ -15,7 +15,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/android/android_theme_resources.h"
 #include "chrome/browser/android/resource_mapper.h"
-#include "chrome/browser/password_manager/android/password_manager_android_util.h"
 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index e99698e..d801a81 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -155,7 +155,6 @@
 #include "chrome/browser/password_manager/android/one_time_passwords/android_sms_otp_backend_factory.h"
 #include "chrome/browser/password_manager/android/password_checkup_launcher_helper_impl.h"
 #include "chrome/browser/password_manager/android/password_generation_controller.h"
-#include "chrome/browser/password_manager/android/password_manager_android_util.h"
 #include "chrome/browser/password_manager/android/password_manager_error_message_helper_bridge_impl.h"
 #include "chrome/browser/password_manager/android/password_manager_launcher_android.h"
 #include "chrome/browser/password_manager/android/password_manager_ui_util_android.h"
diff --git a/chrome/browser/safe_browsing/android/password_reuse_controller_android.cc b/chrome/browser/safe_browsing/android/password_reuse_controller_android.cc
index 5e9559b..1158319 100644
--- a/chrome/browser/safe_browsing/android/password_reuse_controller_android.cc
+++ b/chrome/browser/safe_browsing/android/password_reuse_controller_android.cc
@@ -9,7 +9,6 @@
 
 #include "base/android/device_info.h"
 #include "base/functional/callback.h"
-#include "chrome/browser/password_manager/android/password_manager_android_util.h"
 #include "chrome/browser/ui/android/safe_browsing/password_reuse_dialog_view_android.h"
 #include "components/password_manager/core/browser/features/password_features.h"
 #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.cc b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
index 8061c06..9494837c 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
@@ -113,7 +113,6 @@
 
 #if BUILDFLAG(IS_ANDROID)
 #include "chrome/browser/password_manager/android/password_checkup_launcher_helper_impl.h"
-#include "chrome/browser/password_manager/android/password_manager_android_util.h"
 #include "chrome/browser/safe_browsing/android/password_reuse_controller_android.h"
 #include "chrome/browser/safe_browsing/android/safe_browsing_referring_app_bridge_android.h"
 #include "components/enterprise/connectors/core/features.h"
diff --git a/chrome/browser/signin/android/signin_manager_android.cc b/chrome/browser/signin/android/signin_manager_android.cc
index b2527e4..e8a67c6c 100644
--- a/chrome/browser/signin/android/signin_manager_android.cc
+++ b/chrome/browser/signin/android/signin_manager_android.cc
@@ -19,7 +19,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h"
 #include "chrome/browser/enterprise/util/managed_browser_utils.h"
-#include "chrome/browser/password_manager/android/password_manager_android_util.h"
 #include "chrome/browser/policy/cloud/user_policy_signin_service_factory.h"
 #include "chrome/browser/policy/cloud/user_policy_signin_service_mobile.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/sync/sync_service_factory.cc b/chrome/browser/sync/sync_service_factory.cc
index 0577da77..b2ec99d 100644
--- a/chrome/browser/sync/sync_service_factory.cc
+++ b/chrome/browser/sync/sync_service_factory.cc
@@ -31,7 +31,6 @@
 #include "chrome/browser/password_manager/password_receiver_service_factory.h"
 #include "chrome/browser/password_manager/profile_password_store_factory.h"
 #include "chrome/browser/plus_addresses/plus_address_setting_service_factory.h"
-#include "chrome/browser/power_bookmarks/power_bookmark_service_factory.h"
 #include "chrome/browser/prefs/pref_service_syncable_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_key.h"
@@ -235,8 +234,6 @@
       PlusAddressSettingServiceFactory::GetForBrowserContext(profile),
       WebDataServiceFactory::GetPlusAddressWebDataForProfile(
           profile, ServiceAccessType::IMPLICIT_ACCESS));
-  builder.SetPowerBookmarkService(
-      PowerBookmarkServiceFactory::GetForBrowserContext(profile));
   builder.SetPrefService(profile->GetPrefs());
   builder.SetPrefServiceSyncable(PrefServiceSyncableFromProfile(profile));
   builder.SetProductSpecificationsService(
@@ -538,7 +535,6 @@
   DependsOn(PlusAddressSettingServiceFactory::GetInstance());
   DependsOn(commerce::ProductSpecificationsServiceFactory::GetInstance());
   DependsOn(ProfilePasswordStoreFactory::GetInstance());
-  DependsOn(PowerBookmarkServiceFactory::GetInstance());
 
   DependsOn(SecurityEventRecorderFactory::GetInstance());
   DependsOn(SendTabToSelfSyncServiceFactory::GetInstance());
diff --git a/chrome/browser/sync/test/integration/BUILD.gn b/chrome/browser/sync/test/integration/BUILD.gn
index a932c756a..e5f42245 100644
--- a/chrome/browser/sync/test/integration/BUILD.gn
+++ b/chrome/browser/sync/test/integration/BUILD.gn
@@ -156,7 +156,6 @@
       "two_client_extensions_sync_test.cc",
       "two_client_history_sync_test.cc",
       "two_client_passwords_sync_test.cc",
-      "two_client_power_bookmarks_sync_test.cc",
       "two_client_preferences_sync_test.cc",
       "two_client_search_engines_sync_test.cc",
       "two_client_send_tab_to_self_sync_test.cc",
@@ -235,8 +234,6 @@
       "//components/favicon/core",
       "//components/history/content/browser",
       "//components/history/core/common",
-      "//components/power_bookmarks/common:test_support",
-      "//components/power_bookmarks/core",
       "//components/reading_list/core",
       "//components/saved_tab_groups/internal:tab_group_sync_bridge",
       "//components/search_engines",
@@ -433,7 +430,6 @@
     "//chrome/browser/favicon",
     "//chrome/test:test_support",
     "//components/autofill/content/browser",
-    "//components/power_bookmarks/core:features",
   ]
 
   deps = [
diff --git a/chrome/browser/sync/test/integration/DEPS b/chrome/browser/sync/test/integration/DEPS
index f3d63cbb..2d838960 100644
--- a/chrome/browser/sync/test/integration/DEPS
+++ b/chrome/browser/sync/test/integration/DEPS
@@ -3,18 +3,12 @@
 ]
 
 specific_include_rules = {
-  "local_sync_test\\.cc": [
-    "+components/power_bookmarks",
-  ],
   "single_client_nigori_sync_test\\.cc": [
     "+ash/multi_user/multi_user_window_manager_impl.h",
   ],
   "single_client_plus_address_sync_test\\.cc": [
     "+components/plus_addresses",
   ],
-  "two_client_power_bookmarks_sync_test\\.cc": [
-    "+components/power_bookmarks",
-  ],
   "two_client_web_apps_integration_test_base\\.h": [
     "+chrome/browser/ui/views",
   ],
diff --git a/chrome/browser/sync/test/integration/local_sync_test.cc b/chrome/browser/sync/test/integration/local_sync_test.cc
index 1900e42..863d4c5 100644
--- a/chrome/browser/sync/test/integration/local_sync_test.cc
+++ b/chrome/browser/sync/test/integration/local_sync_test.cc
@@ -19,7 +19,6 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/browser_sync/browser_sync_switches.h"
 #include "components/commerce/core/commerce_feature_list.h"
-#include "components/power_bookmarks/core/power_bookmark_features.h"
 #include "components/sync/base/command_line_switches.h"
 #include "components/sync/base/data_type.h"
 #include "components/sync/base/features.h"
@@ -116,10 +115,6 @@
       syncer::WEB_APPS,
       syncer::NIGORI};
 
-  if (base::FeatureList::IsEnabled(power_bookmarks::kPowerBookmarkBackend)) {
-    expected_active_data_types.Put(syncer::POWER_BOOKMARK);
-  }
-
   if (base::FeatureList::IsEnabled(syncer::kSyncAutofillWalletCredentialData)) {
     expected_active_data_types.Put(syncer::AUTOFILL_WALLET_CREDENTIAL);
   }
diff --git a/chrome/browser/sync/test/integration/two_client_power_bookmarks_sync_test.cc b/chrome/browser/sync/test/integration/two_client_power_bookmarks_sync_test.cc
deleted file mode 100644
index f0c4a61..0000000
--- a/chrome/browser/sync/test/integration/two_client_power_bookmarks_sync_test.cc
+++ /dev/null
@@ -1,286 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <vector>
-
-#include "base/scoped_multi_source_observation.h"
-#include "base/test/bind.h"
-#include "base/test/scoped_feature_list.h"
-#include "chrome/browser/power_bookmarks/power_bookmark_service_factory.h"
-#include "chrome/browser/sync/test/integration/contact_info_helper.h"
-#include "chrome/browser/sync/test/integration/status_change_checker.h"
-#include "chrome/browser/sync/test/integration/sync_test.h"
-#include "components/power_bookmarks/common/power.h"
-#include "components/power_bookmarks/common/power_bookmark_observer.h"
-#include "components/power_bookmarks/common/power_test_util.h"
-#include "components/power_bookmarks/core/power_bookmark_features.h"
-#include "components/power_bookmarks/core/power_bookmark_service.h"
-#include "components/sync/base/features.h"
-#include "components/sync/test/fake_server_http_post_provider.h"
-#include "content/public/test/browser_test.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-using ::testing::ContainerEq;
-
-std::string PowerToString(const power_bookmarks::Power& power) {
-  sync_pb::PowerBookmarkSpecifics specifics;
-  power.ToPowerBookmarkSpecifics(&specifics);
-  return specifics.SerializeAsString();
-}
-
-std::vector<std::string> GetPowersForURLAsString(
-    GURL url,
-    power_bookmarks::PowerBookmarkService* service) {
-  base::RunLoop run_loop;
-  std::vector<std::string> result;
-  service->GetPowersForURL(
-      url, sync_pb::PowerBookmarkSpecifics::POWER_TYPE_MOCK,
-      base::BindOnce(
-          [](base::RunLoop* run_loop, std::vector<std::string>* result,
-             std::vector<std::unique_ptr<power_bookmarks::Power>> powers) {
-            for (auto& power : powers) {
-              result->push_back(PowerToString(*power));
-            }
-            run_loop->Quit();
-          },
-          &run_loop, &result));
-  run_loop.Run();
-  return result;
-}
-
-// Helper class to wait until the two services match for the given `url`.
-class PowerBookmarkChecker : public StatusChangeChecker,
-                             public power_bookmarks::PowerBookmarkObserver {
- public:
-  PowerBookmarkChecker(power_bookmarks::PowerBookmarkService* service0,
-                       power_bookmarks::PowerBookmarkService* service1,
-                       GURL url)
-      : service0_(service0), service1_(service1), url_(url) {
-    power_bookmark_service_obs_.AddObservation(service0_);
-    power_bookmark_service_obs_.AddObservation(service1_);
-  }
-
-  // StatusChangeChecker implementation.
-  bool IsExitConditionSatisfied(std::ostream* os) override {
-    testing::StringMatchResultListener result_listener;
-    bool matches =
-        ExplainMatchResult(testing::UnorderedElementsAreArray(service0_data_),
-                           service1_data_, &result_listener);
-    *os << result_listener.str();
-    return matches;
-  }
-
-  // power_bookmarks::PowerBookmarkObserver implementation.
-  void OnPowersChanged() override {
-    service0_data_ = GetPowersForURLAsString(url_, service0_);
-    service1_data_ = GetPowersForURLAsString(url_, service1_);
-
-    CheckExitCondition();
-  }
-
- private:
-  const raw_ptr<power_bookmarks::PowerBookmarkService> service0_;
-  const raw_ptr<power_bookmarks::PowerBookmarkService> service1_;
-  const GURL url_;
-
-  base::ScopedMultiSourceObservation<power_bookmarks::PowerBookmarkService,
-                                     power_bookmarks::PowerBookmarkObserver>
-      power_bookmark_service_obs_{this};
-  std::vector<std::string> service0_data_;
-  std::vector<std::string> service1_data_;
-};
-
-class TwoClientPowerBookmarksSyncTest : public SyncTest {
- public:
-  const GURL kGoogleURL = GURL("https://google.com");
-  TwoClientPowerBookmarksSyncTest() : SyncTest(TWO_CLIENT) {
-    features_.InitWithFeatures(
-        /*enabled_features=*/{power_bookmarks::kPowerBookmarkBackend},
-        /*disabled_features=*/{});
-  }
-
-  void SetupServices() {
-    service0_ = GetSyncService(0);
-    service1_ = GetSyncService(1);
-  }
-
- protected:
-  raw_ptr<power_bookmarks::PowerBookmarkService, AcrossTasksDanglingUntriaged>
-      service0_;
-  raw_ptr<power_bookmarks::PowerBookmarkService, AcrossTasksDanglingUntriaged>
-      service1_;
-
- private:
-  power_bookmarks::PowerBookmarkService* GetSyncService(int index) {
-    return PowerBookmarkServiceFactory::GetForBrowserContext(GetProfile(index));
-  }
-
-  base::test::ScopedFeatureList features_;
-};
-
-bool CreatePower(std::unique_ptr<power_bookmarks::Power> power,
-                 power_bookmarks::PowerBookmarkService* service) {
-  base::RunLoop run_loop;
-  bool result = false;
-  service->CreatePower(std::move(power),
-                       base::BindLambdaForTesting([&](bool success) {
-                         result = success;
-                         run_loop.Quit();
-                       }));
-  run_loop.Run();
-  return result;
-}
-
-bool UpdatePower(std::unique_ptr<power_bookmarks::Power> power,
-                 power_bookmarks::PowerBookmarkService* service) {
-  base::RunLoop run_loop;
-  bool result = false;
-  service->UpdatePower(std::move(power),
-                       base::BindLambdaForTesting([&](bool success) {
-                         result = success;
-                         run_loop.Quit();
-                       }));
-  run_loop.Run();
-  return result;
-}
-
-bool DeletePower(base::Uuid guid,
-                 power_bookmarks::PowerBookmarkService* service) {
-  base::RunLoop run_loop;
-  bool result = false;
-  service->DeletePower(guid, base::BindLambdaForTesting([&](bool success) {
-                         result = success;
-                         run_loop.Quit();
-                       }));
-  run_loop.Run();
-  return result;
-}
-
-bool DeletePowersForURL(GURL url,
-                        power_bookmarks::PowerBookmarkService* service) {
-  base::RunLoop run_loop;
-  bool result = false;
-  service->DeletePowersForURL(url,
-                              sync_pb::PowerBookmarkSpecifics::POWER_TYPE_MOCK,
-                              base::BindLambdaForTesting([&](bool success) {
-                                result = success;
-                                run_loop.Quit();
-                              }));
-  run_loop.Run();
-  return result;
-}
-void VerifyPowersForURL(GURL url,
-                        power_bookmarks::PowerBookmarkService* service0,
-                        power_bookmarks::PowerBookmarkService* service1) {
-  EXPECT_THAT(GetPowersForURLAsString(url, service0),
-              ContainerEq(GetPowersForURLAsString(url, service1)));
-}
-
-// TODO(crbug.com/40285326): This fails with the field trial testing config.
-class TwoClientPowerBookmarksSyncTestNoTestingConfig
-    : public TwoClientPowerBookmarksSyncTest {
- public:
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    TwoClientPowerBookmarksSyncTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitch("disable-field-trial-config");
-  }
-};
-
-IN_PROC_BROWSER_TEST_F(TwoClientPowerBookmarksSyncTestNoTestingConfig,
-                       AddOnePower) {
-  ASSERT_TRUE(SetupSync());
-  SetupServices();
-
-  // service0 adds a new power.
-  auto power1 = power_bookmarks::MakePower(
-      kGoogleURL, sync_pb::PowerBookmarkSpecifics::POWER_TYPE_MOCK);
-  EXPECT_TRUE(CreatePower(power1->Clone(), service0_));
-  EXPECT_TRUE(PowerBookmarkChecker(service0_, service1_, kGoogleURL).Wait());
-}
-
-IN_PROC_BROWSER_TEST_F(TwoClientPowerBookmarksSyncTest,
-                       // TODO(crbug.com/40901832): Re-enable this test.
-                       DISABLED_UpdateOnePower) {
-  ASSERT_TRUE(SetupSync());
-  SetupServices();
-
-  // service0 adds a new power.
-  auto power1 = power_bookmarks::MakePower(
-      kGoogleURL, sync_pb::PowerBookmarkSpecifics::POWER_TYPE_MOCK);
-  base::Time now = base::Time::Now();
-  power1->set_time_modified(now);
-  EXPECT_TRUE(CreatePower(power1->Clone(), service0_));
-  EXPECT_TRUE(PowerBookmarkChecker(service0_, service1_, kGoogleURL).Wait());
-  VerifyPowersForURL(kGoogleURL, service0_, service1_);
-
-  // service1 updates an existing power.
-  power1->set_time_modified(now + base::Seconds(1));
-  EXPECT_TRUE(UpdatePower(std::move(power1), service1_));
-  EXPECT_TRUE(PowerBookmarkChecker(service0_, service1_, kGoogleURL).Wait());
-  VerifyPowersForURL(kGoogleURL, service0_, service1_);
-}
-
-IN_PROC_BROWSER_TEST_F(TwoClientPowerBookmarksSyncTest, DeleteOnePower) {
-  ASSERT_TRUE(SetupSync());
-  SetupServices();
-
-  // service0 adds a new power.
-  auto power1 = power_bookmarks::MakePower(
-      kGoogleURL, sync_pb::PowerBookmarkSpecifics::POWER_TYPE_MOCK);
-  auto guid = power1->guid();
-  EXPECT_TRUE(CreatePower(power1->Clone(), service0_));
-  EXPECT_TRUE(PowerBookmarkChecker(service0_, service1_, kGoogleURL).Wait());
-
-  // service0 deletes a power.
-  EXPECT_TRUE(DeletePower(guid, service0_));
-  EXPECT_TRUE(PowerBookmarkChecker(service0_, service1_, kGoogleURL).Wait());
-}
-
-IN_PROC_BROWSER_TEST_F(TwoClientPowerBookmarksSyncTestNoTestingConfig,
-                       AddMultiplePowers) {
-  ASSERT_TRUE(SetupSync());
-  SetupServices();
-
-  // service0 adds a power.
-  base::RunLoop run_loop1;
-  auto power1 = power_bookmarks::MakePower(
-      kGoogleURL, sync_pb::PowerBookmarkSpecifics::POWER_TYPE_MOCK);
-  EXPECT_TRUE(CreatePower(std::move(power1), service0_));
-  EXPECT_TRUE(PowerBookmarkChecker(service0_, service1_, kGoogleURL).Wait());
-
-  // service0 adds another power.
-  base::RunLoop run_loop3;
-  auto power2 = power_bookmarks::MakePower(
-      kGoogleURL, sync_pb::PowerBookmarkSpecifics::POWER_TYPE_MOCK);
-  EXPECT_TRUE(CreatePower(std::move(power2), service0_));
-  EXPECT_TRUE(PowerBookmarkChecker(service0_, service1_, kGoogleURL).Wait());
-}
-
-IN_PROC_BROWSER_TEST_F(TwoClientPowerBookmarksSyncTest, DeletePowersForURL) {
-  ASSERT_TRUE(SetupSync());
-  SetupServices();
-
-  // service0 adds a power.
-  base::RunLoop run_loop1;
-  auto power1 = power_bookmarks::MakePower(
-      kGoogleURL, sync_pb::PowerBookmarkSpecifics::POWER_TYPE_MOCK);
-  EXPECT_TRUE(CreatePower(std::move(power1), service0_));
-  EXPECT_TRUE(PowerBookmarkChecker(service0_, service1_, kGoogleURL).Wait());
-
-  // service0 adds another power.
-  base::RunLoop run_loop3;
-  auto power2 = power_bookmarks::MakePower(
-      kGoogleURL, sync_pb::PowerBookmarkSpecifics::POWER_TYPE_MOCK);
-  EXPECT_TRUE(CreatePower(std::move(power2), service0_));
-  EXPECT_TRUE(PowerBookmarkChecker(service0_, service1_, kGoogleURL).Wait());
-
-  // service0 deletes powers for URL.
-  EXPECT_TRUE(DeletePowersForURL(kGoogleURL, service0_));
-  EXPECT_TRUE(PowerBookmarkChecker(service0_, service1_, kGoogleURL).Wait());
-}
-
-}  // namespace
diff --git a/chrome/browser/ui/autofill/BUILD.gn b/chrome/browser/ui/autofill/BUILD.gn
index 5ec8611..79770363 100644
--- a/chrome/browser/ui/autofill/BUILD.gn
+++ b/chrome/browser/ui/autofill/BUILD.gn
@@ -22,8 +22,6 @@
     "autofill_suggestion_controller.h",
     "autofill_suggestion_controller_utils.h",
     "bubble_controller_base.h",
-    "bubble_manager.h",
-    "bubble_manager_impl.h",
     "chrome_autofill_client.h",
     "next_idle_barrier.h",
     "popup_controller_common.h",
@@ -84,6 +82,8 @@
       "autofill_field_promo_controller_impl.h",
       "autofill_field_promo_view.h",
       "autofill_popup_controller_impl.h",
+      "bubble_manager.h",
+      "bubble_manager_impl.h",
       "delete_address_profile_dialog_controller.h",
       "delete_address_profile_dialog_controller_impl.h",
       "delete_address_profile_dialog_view.h",
@@ -124,8 +124,6 @@
     "autofill_popup_hide_helper.cc",
     "autofill_suggestion_controller.cc",
     "autofill_suggestion_controller_utils.cc",
-    "bubble_manager.cc",
-    "bubble_manager_impl.cc",
     "chrome_autofill_client.cc",
     "next_idle_barrier.cc",
     "popup_controller_common.cc",
@@ -199,6 +197,8 @@
       "autofill_context_menu_manager.cc",
       "autofill_field_promo_controller_impl.cc",
       "autofill_popup_controller_impl.cc",
+      "bubble_manager.cc",
+      "bubble_manager_impl.cc",
       "delete_address_profile_dialog_controller_impl.cc",
       "edit_address_profile_dialog_controller_impl.cc",
       "save_address_bubble_controller.cc",
@@ -239,7 +239,6 @@
   sources = [
     "autofill_client_provider_unittest.cc",
     "autofill_suggestion_controller_unittest.cc",
-    "bubble_manager_impl_unittest.cc",
     "chrome_autofill_client_unittest.cc",
   ]
 
@@ -313,6 +312,7 @@
       "address_editor_controller_unittest.cc",
       "autofill_field_promo_controller_impl_unittest.cc",
       "autofill_popup_controller_impl_unittest.cc",
+      "bubble_manager_impl_unittest.cc",
       "save_address_bubble_controller_unittest.cc",
       "update_address_bubble_controller_unittest.cc",
     ]
diff --git a/chrome/browser/ui/autofill/address_bubbles_controller.cc b/chrome/browser/ui/autofill/address_bubbles_controller.cc
index 0845c3f..9f0dff7 100644
--- a/chrome/browser/ui/autofill/address_bubbles_controller.cc
+++ b/chrome/browser/ui/autofill/address_bubbles_controller.cc
@@ -162,7 +162,7 @@
   if (decision == AutofillClient::AddressPromptUserDecision::kEditDeclined) {
     // Reopen this bubble if the user canceled editing.
     shown_by_user_gesture_ = false;
-    ShowBubble();
+    QueueOrShowBubble(/*force_show=*/true);
     return;
   }
   if (address_profile_save_prompt_callback_) {
@@ -196,7 +196,7 @@
     return;
   }
   shown_by_user_gesture_ = true;
-  ShowBubble();
+  QueueOrShowBubble(/*force_show=*/true);
 }
 
 bool AddressBubblesController::IsBubbleActive() const {
diff --git a/chrome/browser/ui/autofill/address_bubbles_controller_interactive_uitest.cc b/chrome/browser/ui/autofill/address_bubbles_controller_interactive_uitest.cc
index 5d8c527..67f68cc 100644
--- a/chrome/browser/ui/autofill/address_bubbles_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/autofill/address_bubbles_controller_interactive_uitest.cc
@@ -293,6 +293,9 @@
           AutofillClient::AddressPromptUserDecision::kAccepted));
 }
 
+// TODO(crbug.com/356845298): Add a test for combining the `kAccountNameEmail`
+// profile with one of the `kAccountHome`/`kAccountWork` profiles.
+
 INSTANTIATE_TEST_SUITE_P(AllAutofillAddressStates,
                          SaveAddressProfileTest,
                          ::testing::Bool(),
diff --git a/chrome/browser/ui/autofill/autofill_bubble_controller_base.cc b/chrome/browser/ui/autofill/autofill_bubble_controller_base.cc
index 505c6d3..12c097b 100644
--- a/chrome/browser/ui/autofill/autofill_bubble_controller_base.cc
+++ b/chrome/browser/ui/autofill/autofill_bubble_controller_base.cc
@@ -61,12 +61,14 @@
   if (IsShowingBubble()) {
     bubble_view_->Hide();
     bubble_view_ = nullptr;
+#if !BUILDFLAG(IS_ANDROID)
     if (base::FeatureList::IsEnabled(
             features::kAutofillShowBubblesBasedOnPriorities)) {
       if (auto* manager = BubbleManager::GetForWebContents(web_contents())) {
         manager->OnBubbleHiddenByController(*this);
       }
     }
+#endif  // !BUILDFLAG(IS_ANDROID)
   }
 }
 
diff --git a/chrome/browser/ui/autofill/bubble_manager.cc b/chrome/browser/ui/autofill/bubble_manager.cc
index e5da61ab2..4cb69c68 100644
--- a/chrome/browser/ui/autofill/bubble_manager.cc
+++ b/chrome/browser/ui/autofill/bubble_manager.cc
@@ -25,7 +25,7 @@
   CHECK(base::FeatureList::IsEnabled(
       autofill::features::kAutofillShowBubblesBasedOnPriorities));
   tabs::TabInterface* const tab_interface =
-      tabs::TabInterface::GetFromContents(web_contents);
+      tabs::TabInterface::MaybeGetFromContents(web_contents);
   if (!tab_interface) {
     return nullptr;
   }
diff --git a/chrome/browser/ui/autofill/delete_address_profile_dialog_controller_impl.cc b/chrome/browser/ui/autofill/delete_address_profile_dialog_controller_impl.cc
index e79533b..4e51e29 100644
--- a/chrome/browser/ui/autofill/delete_address_profile_dialog_controller_impl.cc
+++ b/chrome/browser/ui/autofill/delete_address_profile_dialog_controller_impl.cc
@@ -15,7 +15,6 @@
 #include "components/autofill/core/browser/data_manager/personal_data_manager.h"
 #include "components/signin/public/identity_manager/account_info.h"
 #include "components/strings/grit/components_strings.h"
-#include "components/sync/base/features.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_user_data.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -81,13 +80,10 @@
 
   PersonalDataManager* pdm = PersonalDataManagerFactory::GetForBrowserContext(
       web_contents_->GetBrowserContext());
-  const bool is_syncing =
-      base::FeatureList::IsEnabled(syncer::kReplaceSyncPromosWithSignInPromos)
-          ? pdm->address_data_manager().IsAutofillUserSelectableTypeEnabled()
-          : pdm->address_data_manager().IsSyncFeatureEnabledForAutofill();
   return l10n_util::GetStringUTF16(
-      is_syncing ? IDS_AUTOFILL_DELETE_SYNC_ADDRESS_RECORD_TYPE_NOTICE
-                 : IDS_AUTOFILL_DELETE_LOCAL_ADDRESS_RECORD_TYPE_NOTICE);
+      pdm->address_data_manager().IsSyncFeatureEnabledForAutofill()
+          ? IDS_AUTOFILL_DELETE_SYNC_ADDRESS_RECORD_TYPE_NOTICE
+          : IDS_AUTOFILL_DELETE_LOCAL_ADDRESS_RECORD_TYPE_NOTICE);
 }
 
 void DeleteAddressProfileDialogControllerImpl::OnAccepted() {
diff --git a/chrome/browser/ui/autofill/payments/iban_bubble_controller_impl.cc b/chrome/browser/ui/autofill/payments/iban_bubble_controller_impl.cc
index f12926b..f9762bd 100644
--- a/chrome/browser/ui/autofill/payments/iban_bubble_controller_impl.cc
+++ b/chrome/browser/ui/autofill/payments/iban_bubble_controller_impl.cc
@@ -125,7 +125,7 @@
     CHECK(current_bubble_type_ == IbanBubbleType::kManageSavedIban ||
           current_bubble_type_ == IbanBubbleType::kUploadInProgress);
   }
-  ShowBubble();
+  QueueOrShowBubble(/*force_show=*/true);
 }
 
 void IbanBubbleControllerImpl::ShowConfirmationBubbleView(
diff --git a/chrome/browser/ui/autofill/payments/offer_notification_bubble_controller_impl.cc b/chrome/browser/ui/autofill/payments/offer_notification_bubble_controller_impl.cc
index bf9bc458..4fcb0a67 100644
--- a/chrome/browser/ui/autofill/payments/offer_notification_bubble_controller_impl.cc
+++ b/chrome/browser/ui/autofill/payments/offer_notification_bubble_controller_impl.cc
@@ -179,7 +179,7 @@
 
   is_user_gesture_ = true;
 
-  ShowBubble();
+  QueueOrShowBubble(/*force_show=*/true);
 }
 
 void OfferNotificationBubbleControllerImpl::DismissNotification() {
diff --git a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_interactive_uitest.cc b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_interactive_uitest.cc
index 6057104..d9bc522 100644
--- a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_interactive_uitest.cc
+++ b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_interactive_uitest.cc
@@ -9,11 +9,13 @@
 #include "base/memory/raw_ptr.h"
 #include "base/test/with_feature_override.h"
 #include "base/values.h"
+#include "chrome/browser/ui/autofill/autofill_bubble_base.h"
 #include "chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.h"
 #include "chrome/browser/ui/autofill/payments/save_card_ui.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
+#include "chrome/browser/ui/views/autofill/payments/save_card_bubble_views.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/interactive_test_utils.h"
@@ -24,6 +26,7 @@
 #include "components/autofill/core/common/autofill_features.h"
 #include "content/public/test/browser_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/views/test/widget_test.h"
 
 namespace autofill {
 
@@ -201,18 +204,26 @@
 
 // Tests that opening a new tab will hide the save card bubble.
 IN_PROC_BROWSER_TEST_P(SaveCardBubbleControllerImplTest, NewTabHidesDialog) {
-  if (GetParam()) {
-    // TODO(crbug.com/432429605): Investigate.
-    GTEST_SKIP() << "The test is flaky.";
-  }
   ShowUi("LocalSave");
-  EXPECT_NE(nullptr, controller()->GetPaymentBubbleView());
+  AutofillBubbleBase* bubble_base = controller()->GetPaymentBubbleView();
+  ASSERT_NE(nullptr, bubble_base);
+
+  SaveCardBubbleViews* bubble_view =
+      static_cast<SaveCardBubbleViews*>(bubble_base);
+
+  // Create a waiter that will return once the bubble's widget is destroyed.
+  views::test::WidgetDestroyedWaiter waiter(bubble_view->GetWidget());
+
   // Open a new tab page in the foreground.
   ui_test_utils::NavigateToURLWithDisposition(
       browser(), GURL(chrome::kChromeUINewTabURL),
       WindowOpenDisposition::NEW_FOREGROUND_TAB,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB |
           ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
+
+  // Wait until the bubble is actually gone.
+  waiter.Wait();
+
   EXPECT_EQ(nullptr, controller()->GetPaymentBubbleView());
 }
 
diff --git a/chrome/browser/ui/autofill/payments/virtual_card_enroll_bubble_controller_impl.cc b/chrome/browser/ui/autofill/payments/virtual_card_enroll_bubble_controller_impl.cc
index bbe213b0..3c17c8b 100644
--- a/chrome/browser/ui/autofill/payments/virtual_card_enroll_bubble_controller_impl.cc
+++ b/chrome/browser/ui/autofill/payments/virtual_card_enroll_bubble_controller_impl.cc
@@ -87,7 +87,7 @@
   }
 
   is_user_gesture_ = true;
-  ShowBubble();
+  QueueOrShowBubble(/*force_show=*/true);
 }
 
 void VirtualCardEnrollBubbleControllerImpl::ShowConfirmationBubbleView(
diff --git a/chrome/browser/ui/autofill/save_address_bubble_controller.cc b/chrome/browser/ui/autofill/save_address_bubble_controller.cc
index b7b71a70..eca34dc 100644
--- a/chrome/browser/ui/autofill/save_address_bubble_controller.cc
+++ b/chrome/browser/ui/autofill/save_address_bubble_controller.cc
@@ -25,7 +25,6 @@
 #include "components/autofill/core/browser/ui/addresses/autofill_address_util.h"
 #include "components/signin/public/identity_manager/account_info.h"
 #include "components/strings/grit/components_strings.h"
-#include "components/sync/base/features.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/image_model.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -56,6 +55,9 @@
         return IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_TITLE;
       case autofill::AutofillClient::SaveAddressBubbleType::kMigrateToAccount:
         return IDS_AUTOFILL_ACCOUNT_MIGRATE_ADDRESS_PROMPT_TITLE;
+      case autofill::AutofillClient::SaveAddressBubbleType::
+          kHomeWorkNameEmailMerge:
+        return IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_NAME_EMAIL_HOME_WORK_MERGE_PROMPT_TITLE;
     }
   }());
 }
@@ -96,11 +98,7 @@
         GetPrimaryAccountInfoFromBrowserContext(
             web_contents()->GetBrowserContext());
 
-    const bool is_syncing =
-        base::FeatureList::IsEnabled(syncer::kReplaceSyncPromosWithSignInPromos)
-            ? pdm.address_data_manager().IsAutofillUserSelectableTypeEnabled()
-            : pdm.address_data_manager().IsSyncFeatureEnabledForAutofill();
-    int string_id = is_syncing
+    int string_id = pdm.address_data_manager().IsSyncFeatureEnabledForAutofill()
                         ? IDS_AUTOFILL_SYNCABLE_PROFILE_MIGRATION_PROMPT_NOTICE
                         : IDS_AUTOFILL_LOCAL_PROFILE_MIGRATION_PROMPT_NOTICE;
 
@@ -170,6 +168,22 @@
         return IDS_AUTOFILL_EDIT_ADDRESS_DIALOG_OK_BUTTON_LABEL_SAVE;
       case autofill::AutofillClient::SaveAddressBubbleType::kMigrateToAccount:
         return IDS_AUTOFILL_MIGRATE_ADDRESS_DIALOG_OK_BUTTON_LABEL_SAVE;
+      case autofill::AutofillClient::SaveAddressBubbleType::
+          kHomeWorkNameEmailMerge:
+        return IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_NAME_EMAIL_HOME_WORK_MERGE_OK_BUTTON_LABEL;
+    }
+  }());
+}
+
+std::u16string SaveAddressBubbleController::GetNegativeButtonLabel() const {
+  return l10n_util::GetStringUTF16([this] {
+    switch (save_address_bubble_type_) {
+      case AutofillClient::SaveAddressBubbleType::kSave:
+      case autofill::AutofillClient::SaveAddressBubbleType::kMigrateToAccount:
+        return IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_CANCEL_BUTTON_LABEL;
+      case autofill::AutofillClient::SaveAddressBubbleType::
+          kHomeWorkNameEmailMerge:
+        return IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_NAME_EMAIL_HOME_WORK_MERGE_CANCEL_BUTTON_LABEL;
     }
   }());
 }
diff --git a/chrome/browser/ui/autofill/save_address_bubble_controller.h b/chrome/browser/ui/autofill/save_address_bubble_controller.h
index 7729243..7ea4bd7 100644
--- a/chrome/browser/ui/autofill/save_address_bubble_controller.h
+++ b/chrome/browser/ui/autofill/save_address_bubble_controller.h
@@ -45,6 +45,7 @@
   virtual std::u16string GetProfileEmail() const;
   virtual std::u16string GetProfilePhone() const;
   virtual std::u16string GetOkButtonLabel() const;
+  std::u16string GetNegativeButtonLabel() const;
   const AutofillProfile& GetAutofillProfile() const { return address_profile_; }
 
   // The value returned by the cancel button callback depends on whether
diff --git a/chrome/browser/ui/autofill/save_address_bubble_controller_unittest.cc b/chrome/browser/ui/autofill/save_address_bubble_controller_unittest.cc
index fb9a3576..f0787151 100644
--- a/chrome/browser/ui/autofill/save_address_bubble_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/save_address_bubble_controller_unittest.cc
@@ -16,9 +16,11 @@
 #include "chrome/browser/ui/autofill/chrome_autofill_client.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/application_locale_storage/application_locale_storage.h"
+#include "components/autofill/core/browser/data_model/addresses/autofill_profile.h"
 #include "components/autofill/core/browser/data_model/addresses/autofill_profile_test_api.h"
 #include "components/autofill/core/browser/foundations/autofill_client.h"
 #include "components/autofill/core/browser/test_utils/autofill_test_utils.h"
+#include "components/autofill/core/browser/test_utils/test_profiles.h"
 #include "components/autofill/core/browser/ui/addresses/autofill_address_util.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_contents.h"
@@ -186,5 +188,46 @@
   EXPECT_TRUE(controller->GetFooterMessage().empty());
 }
 
+TEST_F(SaveAddressBubbleControllerTest, CombiningAccountsTypes) {
+  const AutofillProfile merged_profile = test::SupersetProfileOf(
+      {test::AccountNameEmailProfile(),
+       test::OnlyAddressProfile(AutofillProfile::RecordType::kAccountHome)},
+      app_locale(), AutofillProfile::RecordType::kAccount);
+  std::unique_ptr<SaveAddressBubbleController> controller = CreateController(
+      merged_profile,
+      AutofillClient::SaveAddressBubbleType::kHomeWorkNameEmailMerge);
+
+  EXPECT_EQ(
+      controller->GetWindowTitle(),
+      l10n_util::GetStringUTF16(
+          IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_NAME_EMAIL_HOME_WORK_MERGE_PROMPT_TITLE));
+  EXPECT_EQ(
+      controller->GetOkButtonLabel(),
+      l10n_util::GetStringUTF16(
+          IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_NAME_EMAIL_HOME_WORK_MERGE_OK_BUTTON_LABEL));
+  EXPECT_EQ(
+      controller->GetNegativeButtonLabel(),
+      l10n_util::GetStringUTF16(
+          IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_NAME_EMAIL_HOME_WORK_MERGE_CANCEL_BUTTON_LABEL));
+  EXPECT_EQ(controller->GetFooterMessage(),
+            l10n_util::GetStringFUTF16(
+                IDS_AUTOFILL_SAVE_IN_ACCOUNT_PROMPT_ADDRESS_SOURCE_NOTICE,
+                base::UTF8ToUTF16(GetPrimaryAccountInfoFromBrowserContext(
+                                      web_contents()->GetBrowserContext())
+                                      ->email)));
+  EXPECT_NE(controller->GetHeaderImages(), std::nullopt);
+  EXPECT_TRUE(controller->GetBodyText().empty());
+
+  EXPECT_EQ(controller->GetAddressSummary(),
+            GetEnvelopeStyleAddress(merged_profile, app_locale(),
+                                    /*include_recipient=*/true,
+                                    /*include_country=*/true));
+  EXPECT_EQ(controller->GetProfileEmail(),
+            merged_profile.GetInfo(EMAIL_ADDRESS, app_locale()));
+
+  EXPECT_EQ(controller->GetCancelCallbackValue(),
+            AutofillClient::AddressPromptUserDecision::kDeclined);
+}
+
 }  // namespace
 }  // namespace autofill
diff --git a/chrome/browser/ui/color/material_chrome_color_mixer.cc b/chrome/browser/ui/color/material_chrome_color_mixer.cc
index fc6e9126..f0e430f 100644
--- a/chrome/browser/ui/color/material_chrome_color_mixer.cc
+++ b/chrome/browser/ui/color/material_chrome_color_mixer.cc
@@ -36,12 +36,9 @@
   mixer[kColorAppMenuHighlightSeverityMedium] = {kColorAppMenuHighlightDefault};
   mixer[kColorAppMenuHighlightSeverityHigh] = {kColorAppMenuHighlightDefault};
 
-  if (base::FeatureList::IsEnabled(
-          features::kEnableAppMenuButtonColorsForDefaultAvatarButtonStates)) {
-    mixer[kColorAvatarButtonHighlightDefaultForeground] = {
-        kColorAppMenuExpandedForegroundDefault};
-    mixer[kColorAvatarButtonHighlightDefault] = {kColorAppMenuHighlightDefault};
-  }
+  mixer[kColorAvatarButtonHighlightDefaultForeground] = {
+      kColorAppMenuExpandedForegroundDefault};
+  mixer[kColorAvatarButtonHighlightDefault] = {kColorAppMenuHighlightDefault};
 
   mixer[kColorAvatarButtonHighlightManagementForeground] = {
       kColorAvatarButtonHighlightDefaultForeground};
@@ -281,12 +278,6 @@
       ui::kColorSysOnTonalContainer};
   mixer[kColorAppMenuChipInkDropHover] = {ui::kColorSysStateHoverOnSubtle};
   mixer[kColorAppMenuChipInkDropRipple] = {ui::kColorSysStateRipplePrimary};
-  if (!base::FeatureList::IsEnabled(
-          features::kEnableAppMenuButtonColorsForDefaultAvatarButtonStates)) {
-    mixer[kColorAvatarButtonHighlightDefault] = {ui::kColorSysTonalContainer};
-    mixer[kColorAvatarButtonHighlightDefaultForeground] = {
-        ui::kColorSysOnTonalContainer};
-  }
   mixer[kColorAvatarButtonHighlightSyncPaused] = {
       kColorAvatarButtonHighlightDefault};
   mixer[kColorAvatarButtonHighlightSigninPaused] = {
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
index 4098e3c..4341c2d 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
@@ -1279,7 +1279,6 @@
     PasswordBubbleViewBase::CloseCurrentBubble();
     // This will detach any existing bubble so OnBubbleHidden() isn't called.
     weak_ptr_factory_.InvalidateWeakPtrs();
-    passwords_action_item->SetIsShowingBubble(true);
     PasswordBubbleViewBase::ShowBubble(
         web_contents(), LocationBarBubbleDelegateView::AUTOMATIC);
     // If the bubble appeared then the status is updated in OnBubbleShown().
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc
index 96b5572..ca148364 100644
--- a/chrome/browser/ui/ui_features.cc
+++ b/chrome/browser/ui/ui_features.cc
@@ -454,10 +454,6 @@
              "ManagedProfileRequiredInterstitial",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
-BASE_FEATURE(kEnableAppMenuButtonColorsForDefaultAvatarButtonStates,
-             "EnableAppMenuButtonColorsForDefaultAvatarButtonStates",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 // Enables a web-based tab strip. See https://crbug.com/989131. Note this
 // feature only works when the ENABLE_WEBUI_TAB_STRIP buildflag is enabled.
 BASE_FEATURE(kWebUITabStrip,
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h
index c9ed380..baec751 100644
--- a/chrome/browser/ui/ui_features.h
+++ b/chrome/browser/ui/ui_features.h
@@ -311,10 +311,6 @@
 BASE_DECLARE_FEATURE(kEnterpriseManagementDisclaimerUsesCustomLabel);
 BASE_DECLARE_FEATURE(kManagedProfileRequiredInterstitial);
 
-// Enables using the same colors used for the default app menu button for the
-// avatar button states using default colors.
-BASE_DECLARE_FEATURE(kEnableAppMenuButtonColorsForDefaultAvatarButtonStates);
-
 BASE_DECLARE_FEATURE(kWebUITabStrip);
 
 // Controls whether the context menu is shown on a touch press or a touch
diff --git a/chrome/browser/ui/views/autofill/save_address_profile_view.cc b/chrome/browser/ui/views/autofill/save_address_profile_view.cc
index 33c2622..a029a29 100644
--- a/chrome/browser/ui/views/autofill/save_address_profile_view.cc
+++ b/chrome/browser/ui/views/autofill/save_address_profile_view.cc
@@ -135,9 +135,7 @@
   SetTitle(controller_->GetWindowTitle());
   SetButtonLabel(ui::mojom::DialogButton::kOk, controller_->GetOkButtonLabel());
   SetButtonLabel(ui::mojom::DialogButton::kCancel,
-                 l10n_util::GetStringUTF16(
-                     IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_CANCEL_BUTTON_LABEL));
-
+                 controller_->GetNegativeButtonLabel());
   SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::Orientation::kVertical, gfx::Insets(),
       views::LayoutProvider::Get()->GetDistanceMetric(
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
index e48bf44..d771c499 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -2112,7 +2112,7 @@
   overflow_button_->SetImageModel(
       views::Button::STATE_DISABLED,
       ui::GetDefaultDisabledIconFromImageModel(overflow_button_icon,
-                                               GetColorProvider()));
+                                               color_provider));
 
   // Redraw the background.
   SchedulePaint();
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc b/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc
index 4c107cba..85cd708c 100644
--- a/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc
+++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc
@@ -351,11 +351,7 @@
 }
 
 bool AvatarToolbarButton::ShouldBlendHighlightColor() const {
-  if (base::FeatureList::IsEnabled(
-          features::kEnableAppMenuButtonColorsForDefaultAvatarButtonStates)) {
-    return false;
-  }
-  return GetWidget() && GetWidget()->GetCustomTheme();
+  return false;
 }
 
 base::ScopedClosureRunner AvatarToolbarButton::SetExplicitButtonState(
@@ -615,30 +611,10 @@
 }
 
 SkColor AvatarToolbarButton::GetForegroundColor(ButtonState state) const {
-  if (base::FeatureList::IsEnabled(
-          features::kEnableAppMenuButtonColorsForDefaultAvatarButtonStates)) {
-    if (IsLabelPresentAndVisible()) {
-      return GetHighlightTextColor().value_or(GetColorProvider()->GetColor(
-          kColorAvatarButtonHighlightDefaultForeground));
-    }
-  } else {
-    const bool has_custom_theme =
-        this->GetWidget() && this->GetWidget()->GetCustomTheme();
-
-    // If there is a custom theme use the `ToolbarButton` version of
-    // `GetForegroundColor()` This is to avoid creating new colorIds for icons
-    // for all the different states. With chrome refresh and without any custom
-    // theme, the color would be same as the label color.
-    if (!has_custom_theme && IsLabelPresentAndVisible()) {
-      const std::optional<SkColor> foreground_color = GetHighlightTextColor();
-      const auto* const color_provider = GetColorProvider();
-      return foreground_color.has_value()
-                 ? foreground_color.value()
-                 : color_provider->GetColor(
-                       kColorAvatarButtonHighlightDefaultForeground);
-    }
+  if (IsLabelPresentAndVisible()) {
+    return GetHighlightTextColor().value_or(GetColorProvider()->GetColor(
+        kColorAvatarButtonHighlightDefaultForeground));
   }
-
   return ToolbarButton::GetForegroundColor(state);
 }
 
diff --git a/chrome/browser/ui/webui/signin/history_sync_optin_helper.cc b/chrome/browser/ui/webui/signin/history_sync_optin_helper.cc
index 226e634..d60008b7 100644
--- a/chrome/browser/ui/webui/signin/history_sync_optin_helper.cc
+++ b/chrome/browser/ui/webui/signin/history_sync_optin_helper.cc
@@ -21,8 +21,8 @@
 #include "chrome/browser/ui/webui/signin/managed_user_profile_notice_ui.h"
 #include "chrome/browser/ui/webui/signin/turn_sync_on_helper_policy_fetch_tracker.h"
 #include "components/signin/public/base/signin_switches.h"
-#include "components/signin/public/identity_manager/account_capability_fetcher.h"
 #include "components/signin/public/identity_manager/account_info.h"
+#include "components/signin/public/identity_manager/account_state_fetcher.h"
 #include "components/signin/public/identity_manager/account_managed_status_finder.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/signin/public/identity_manager/tribool.h"
@@ -142,25 +142,25 @@
     : profile_(profile),
       account_info_(account_info),
       delegate_(delegate),
-      is_managed_capability_fetcher_(std::make_unique<AccountCapabilityFetcher>(
-          identity_manager,
-          account_info,
-          /*get_capability_state_callback=*/
-          base::BindRepeating(
-              &HistorySyncOptinHelper::AccountIsManagedCapability,
-              base::Unretained(this)),
-          /*on_capability_fetched_callback=*/
-          base::BindOnce(
-              &HistorySyncOptinHelper::ResumeShowHistorySyncOptinScreenFlow,
-              base::Unretained(this)))) {
+      account_state_fetcher_(
+          std::make_unique<AccountStateFetcher>(
+              identity_manager,
+              account_info,
+              /*get_account_state_callback=*/
+              base::BindRepeating(&HistorySyncOptinHelper::AccountIsManaged,
+                                  base::Unretained(this)),
+              /*on_account_info_fetched_callback=*/
+              base::BindOnce(&HistorySyncOptinHelper::
+                                 ResumeShowHistorySyncOptinScreenFlow,
+                             base::Unretained(this)))) {
   CHECK(base::FeatureList::IsEnabled(switches::kEnableHistorySyncOptin));
   CHECK(delegate);
 }
 
-HistorySyncOptinHelper::~HistorySyncOptinHelper() {}
+HistorySyncOptinHelper::~HistorySyncOptinHelper() = default;
 
 void HistorySyncOptinHelper::StartHistorySyncOptinFlow() {
-  is_managed_capability_fetcher_->FetchCapability();
+  account_state_fetcher_->FetchAccountInfo();
 }
 
 void HistorySyncOptinHelper::MaybeShowAccountManagementScreen(
@@ -265,7 +265,7 @@
   }
 }
 
-signin::Tribool HistorySyncOptinHelper::AccountIsManagedCapability(
+signin::Tribool HistorySyncOptinHelper::AccountIsManaged(
     const AccountInfo& account_info) {
   if (!account_info.IsEmpty()) {
     return account_info.IsManaged();
diff --git a/chrome/browser/ui/webui/signin/history_sync_optin_helper.h b/chrome/browser/ui/webui/signin/history_sync_optin_helper.h
index 5c47a9f2..23d5d8e 100644
--- a/chrome/browser/ui/webui/signin/history_sync_optin_helper.h
+++ b/chrome/browser/ui/webui/signin/history_sync_optin_helper.h
@@ -17,7 +17,7 @@
 #include "components/signin/public/identity_manager/account_info.h"
 #include "components/signin/public/identity_manager/tribool.h"
 
-class AccountCapabilityFetcher;
+class AccountStateFetcher;
 class Profile;
 class TurnSyncOnHelperPolicyFetchTracker;
 
@@ -113,8 +113,8 @@
 
   void StartHistorySyncOptinFlow();
 
-  AccountCapabilityFetcher* GetAccountCapabilityFetcherForTesting() {
-    return is_managed_capability_fetcher_.get();
+  AccountStateFetcher* GetAccountStateFetcherForTesting() {
+    return account_state_fetcher_.get();
   }
 
   SyncServiceStartupStateObserver*
@@ -134,14 +134,12 @@
   // screen.
   void OnAccountManagementScreenClosed(signin::SigninChoice result);
 
-  signin::Tribool AccountIsManagedCapability(const AccountInfo& account_info);
+  signin::Tribool AccountIsManaged(const AccountInfo& account_info);
 
   raw_ptr<Profile> profile_;
   const AccountInfo account_info_;
   raw_ptr<Delegate> delegate_;
-  // TODO(crbug.com/434964019): Rename this class and instances as they do not
-  // track capabilities anymore.
-  std::unique_ptr<AccountCapabilityFetcher> is_managed_capability_fetcher_;
+  std::unique_ptr<AccountStateFetcher> account_state_fetcher_;
 
   std::unique_ptr<SyncServiceStartupStateObserver> sync_startup_state_observer_;
   std::unique_ptr<HistorySyncOptinPolicyHelper> policy_helper_;
diff --git a/chrome/browser/ui/webui/signin/history_sync_optin_helper_browsertest.cc b/chrome/browser/ui/webui/signin/history_sync_optin_helper_browsertest.cc
index d8333da..c0f9001 100644
--- a/chrome/browser/ui/webui/signin/history_sync_optin_helper_browsertest.cc
+++ b/chrome/browser/ui/webui/signin/history_sync_optin_helper_browsertest.cc
@@ -27,8 +27,7 @@
 #include "components/policy/core/common/mock_policy_service.h"
 #include "components/policy/core/common/policy_service.h"
 #include "components/signin/public/base/signin_switches.h"
-#include "components/signin/public/identity_manager/account_capabilities_test_mutator.h"
-#include "components/signin/public/identity_manager/account_capability_fetcher.h"
+#include "components/signin/public/identity_manager/account_state_fetcher.h"
 #include "components/signin/public/identity_manager/identity_test_environment.h"
 #include "components/signin/public/identity_manager/signin_constants.h"
 #include "components/signin/public/identity_manager/tribool.h"
@@ -73,13 +72,9 @@
   }
 
   // Updates the fields relating to the account management.
-  void UpdateManagedUserCapabilities(AccountInfo& account_info,
-                                     bool is_managed) {
+  void UpdateAccountManagementInfo(AccountInfo& account_info, bool is_managed) {
     account_info.hosted_domain =
         is_managed ? "example.com" : signin::constants::kNoHostedDomainFound;
-    AccountCapabilitiesTestMutator mutator(&account_info.capabilities);
-    mutator.set_is_subject_to_account_level_enterprise_policies(is_managed);
-
     CHECK(account_info.IsValid());
     identity_test_env()->UpdateAccountInfoForAccount(account_info);
   }
@@ -115,7 +110,7 @@
 
 IN_PROC_BROWSER_TEST_F(
     HistorySyncOptinHelperBrowserTest,
-    TriggersHistorySyncScreenWhenCapabilityFetchedForConsumerAccount) {
+    TriggersHistorySyncScreenWhenAccountInfoFetchedForConsumerAccount) {
   AccountInfo account_info = MakeAccountInfoAvailable();
   MockHistorySyncOptinHelperDelegate delegate;
 
@@ -126,12 +121,12 @@
       &delegate);
   history_sync_optin_helper.StartHistorySyncOptinFlow();
 
-  // This triggers the flopw that reaches the delegate's
+  // This triggers the flow that reaches the delegate's
   // `ShowHistorySyncOptinScreen`.
-  UpdateManagedUserCapabilities(account_info, /*is_managed=*/false);
+  UpdateAccountManagementInfo(account_info, /*is_managed=*/false);
 
   // Subsequent updates should have no impact.
-  UpdateManagedUserCapabilities(account_info, /*is_managed=*/false);
+  UpdateAccountManagementInfo(account_info, /*is_managed=*/false);
 }
 
 IN_PROC_BROWSER_TEST_F(
@@ -157,11 +152,11 @@
 
   // This triggers the flow that reaches the delegate's
   // `ShowAccountManagementScreen`.
-  UpdateManagedUserCapabilities(account_info, /*is_managed=*/true);
+  UpdateAccountManagementInfo(account_info, /*is_managed=*/true);
   run_loop.Run();
 
   // Subsequent updates should have no impact on the flow.
-  UpdateManagedUserCapabilities(account_info, /*is_managed=*/true);
+  UpdateAccountManagementInfo(account_info, /*is_managed=*/true);
 }
 
 IN_PROC_BROWSER_TEST_F(
@@ -188,16 +183,17 @@
 
   // This triggers the flow that reaches the delegate's
   // `ShowAccountManagementScreen`.
-  UpdateManagedUserCapabilities(account_info, /*is_managed=*/true);
+  UpdateAccountManagementInfo(account_info, /*is_managed=*/true);
   run_loop.Run();
 
   // Subsequent updates should have no impact on the flow.
-  UpdateManagedUserCapabilities(account_info, /*is_managed=*/true);
+  UpdateAccountManagementInfo(account_info, /*is_managed=*/true);
+
 }
 
 IN_PROC_BROWSER_TEST_F(
     HistorySyncOptinHelperBrowserTest,
-    TriggersHistorySyncScreenWhenCapabilityFetchingTimesOut) {
+    TriggersHistorySyncScreenWhenAccountInfoFetchingTimesOut) {
   AccountInfo account_info = MakeAccountInfoAvailable();
   MockHistorySyncOptinHelperDelegate delegate;
 
@@ -210,11 +206,11 @@
   testing::Mock::VerifyAndClearExpectations(&delegate);
 
   EXPECT_CALL(delegate, ShowHistorySyncOptinScreen).Times(1);
-  history_sync_optin_helper.GetAccountCapabilityFetcherForTesting()
+  history_sync_optin_helper.GetAccountStateFetcherForTesting()
       ->EnforceTimeoutReachedForTesting();
 
-  // After the timeout is reached, capability updates should have no impact.
-  UpdateManagedUserCapabilities(account_info, /*is_managed=*/true);
+  // After the timeout is reached, account info updates should have no impact.
+  UpdateAccountManagementInfo(account_info, /*is_managed=*/true);
 }
 
 IN_PROC_BROWSER_TEST_F(HistorySyncOptinHelperBrowserTest,
@@ -224,7 +220,7 @@
       syncer::SyncService::TransportState::INITIALIZING);
 
   AccountInfo account_info = MakeAccountInfoAvailable();
-  UpdateManagedUserCapabilities(account_info, /*is_managed=*/false);
+  UpdateAccountManagementInfo(account_info, /*is_managed=*/false);
   MockHistorySyncOptinHelperDelegate delegate;
 
   HistorySyncOptinHelper history_sync_optin_helper(
@@ -253,7 +249,7 @@
   GetTestSyncService()->SetAllowedByEnterprisePolicy(false);
 
   AccountInfo account_info = MakeAccountInfoAvailable();
-  UpdateManagedUserCapabilities(account_info, /*is_managed=*/false);
+  UpdateAccountManagementInfo(account_info, /*is_managed=*/false);
   MockHistorySyncOptinHelperDelegate delegate;
 
   EXPECT_CALL(delegate, ShowHistorySyncOptinScreen).Times(0);
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index 34dc15a9..fa72310 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1757043039-4d675340696881c942eb9a6e8a9c5c971675e876-b0cf5b741cc5a090be8cd305f2bf79b325d00e11.profdata
+chrome-android64-main-1757056825-7365af6de451bfae61f9feedebb33096e13e4b61-3c0e69a6b174ecc818878661c484832be6ced999.profdata
diff --git a/chrome/build/android-desktop-x64.pgo.txt b/chrome/build/android-desktop-x64.pgo.txt
index dc20833f..68d4aaf3 100644
--- a/chrome/build/android-desktop-x64.pgo.txt
+++ b/chrome/build/android-desktop-x64.pgo.txt
@@ -1 +1 @@
-chrome-android-desktop-x64-main-1757030166-bb7bb71b05595fa399f768add14dca25eb122afc-c78541b0a6e2d1bf8507bf96eb5353fe182f32e4.profdata
+chrome-android-desktop-x64-main-1757051972-3e7ae86352ddf7cd199a38055f947281e5ee2919-e68792d4fddce29c7940fa84c482b19b3693dfcf.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index b7b7f06..f205ab2 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1757030166-76ffb00448a6d14d2f30152ebad0de28961e4185-c78541b0a6e2d1bf8507bf96eb5353fe182f32e4.profdata
+chrome-mac-main-1757051972-fe027bb3f56eeda0249d3e394b1b8a04f995a47f-e68792d4fddce29c7940fa84c482b19b3693dfcf.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 6c478228d..2a62582 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1757030166-cc56838c8ab4e0607cc9943e1dcdedca62198d4c-c78541b0a6e2d1bf8507bf96eb5353fe182f32e4.profdata
+chrome-win32-main-1757051972-1a19d8a65bdbea6024b36be237f7e4f91ad538eb-e68792d4fddce29c7940fa84c482b19b3693dfcf.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 9aac958..3183432 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1757030166-69050754091825cdb598ef786f1ed4c634010f1b-c78541b0a6e2d1bf8507bf96eb5353fe182f32e4.profdata
+chrome-win64-main-1757041177-7e09cde8210417f0e4766b41802afcd61cca0340-d79ad90592249a53a847b0abcd617183034ecbd5.profdata
diff --git a/chrome/gpu/browser_exposed_gpu_interfaces.cc b/chrome/gpu/browser_exposed_gpu_interfaces.cc
index 1778daa..ac93923 100644
--- a/chrome/gpu/browser_exposed_gpu_interfaces.cc
+++ b/chrome/gpu/browser_exposed_gpu_interfaces.cc
@@ -61,7 +61,7 @@
   mojo::MakeSelfOwnedReceiver(
       std::make_unique<arc::GpuArcVideoEncodeAccelerator>(
           gpu::ArcSharedImageInterface::Create(
-              gpu_service->gpu_channel_manager()),
+              gpu_service->gpu_channel_manager(), gpu_service->main_runner()),
           gpu_preferences, gpu_workarounds),
       std::move(receiver));
 }
diff --git a/chrome/test/data/accessibility/page_with_lazy_image.html b/chrome/test/data/accessibility/page_with_lazy_image.html
new file mode 100644
index 0000000..acc9412
--- /dev/null
+++ b/chrome/test/data/accessibility/page_with_lazy_image.html
@@ -0,0 +1,7 @@
+<html>
+  <body>
+  <img src="green.png">
+  <div id="box" style="height: 4000px"></div>
+  <img loading="lazy" style="height:16px; width:16px" src="red.png">
+  </body>
+</html>
diff --git a/chrome/test/data/android/bookmarks/Valid_reading_list_entry.html b/chrome/test/data/android/bookmarks/Valid_reading_list_entry.html
new file mode 100644
index 0000000..a920244
--- /dev/null
+++ b/chrome/test/data/android/bookmarks/Valid_reading_list_entry.html
@@ -0,0 +1,6 @@
+<!DOCTYPE NETSCAPE-Bookmark-file-1>
+<TITLE>Reading List</TITLE>
+<H1>Reading List</H1>
+<DL><p>
+    <DT><A HREF="https://www.chromium.org/">Chromium</A>
+</DL><p>
\ No newline at end of file
diff --git a/chrome/test/data/webui/extensions/extensions_browsertest.cc b/chrome/test/data/webui/extensions/extensions_browsertest.cc
index 08bb89f8c..b9c8f1d 100644
--- a/chrome/test/data/webui/extensions/extensions_browsertest.cc
+++ b/chrome/test/data/webui/extensions/extensions_browsertest.cc
@@ -570,8 +570,6 @@
   RunTestCase("ItemListVisibility");
 }
 
-// TODO(crbug.com/439447730): Enable on desktop android.
-#if BUILDFLAG(ENABLE_EXTENSIONS)
 IN_PROC_BROWSER_TEST_F(
     CrExtensionsManagerTestWithMultipleExtensionTypesInstalled,
     SplitItems) {
@@ -620,7 +618,6 @@
   InstallPrerequisites();
   RunTestCase("ShowUnsupportedDeveloperExtensionDisabledToast");
 }
-#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 
 class CrExtensionsManagerTestWithIdQueryParam
     : public ExtensionSettingsTestBase {
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index be723ed..4a9d96b 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-16408.0.0-1071485
\ No newline at end of file
+16408.0.0-1071498
\ No newline at end of file
diff --git a/chromeos/ash/components/emoji/gif_tenor_api_fetcher.cc b/chromeos/ash/components/emoji/gif_tenor_api_fetcher.cc
index 30b3c63..f7c6e24 100644
--- a/chromeos/ash/components/emoji/gif_tenor_api_fetcher.cc
+++ b/chromeos/ash/components/emoji/gif_tenor_api_fetcher.cc
@@ -13,11 +13,13 @@
 
 #include "base/check_deref.h"
 #include "base/functional/bind.h"
+#include "base/json/json_reader.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "base/types/expected.h"
+#include "base/types/optional_ref.h"
 #include "base/values.h"
 #include "base/version_info/channel.h"
 #include "chromeos/ash/components/channel/channel_info.h"
@@ -114,19 +116,13 @@
 }
 
 const base::Value::List* FindList(
-    data_decoder::DataDecoder::ValueOrError& result,
-    const std::string& key) {
+    base::optional_ref<const base::Value::Dict> result,
+    std::string_view key) {
   if (!result.has_value()) {
     return nullptr;
   }
 
-  const auto* response = result->GetIfDict();
-  if (!response) {
-    return nullptr;
-  }
-
-  const auto* list = response->FindList(key);
-  return list ? list : nullptr;
+  return result->FindList(key);
 }
 
 std::vector<tenor::mojom::GifResponsePtr> ParseGifs(
@@ -251,7 +247,7 @@
 }
 
 base::expected<std::vector<std::string>, GifTenorApiFetcher::Error>
-ParseCategoriesResponse(data_decoder::DataDecoder::ValueOrError result) {
+ParseCategoriesResponse(base::optional_ref<const base::Value::Dict> result) {
   const auto* tags = FindList(result, "tags");
   if (!tags) {
     return base::unexpected(GifTenorApiFetcher::Error::kHttpError);
@@ -277,19 +273,19 @@
 
 base::expected<tenor::mojom::PaginatedGifResponsesPtr,
                GifTenorApiFetcher::Error>
-ParsePaginatedGifsResponse(data_decoder::DataDecoder::ValueOrError result) {
+ParsePaginatedGifsResponse(base::optional_ref<const base::Value::Dict> result) {
   const auto* gifs = FindList(result, "results");
   if (!gifs) {
     return base::unexpected(GifTenorApiFetcher::Error::kHttpError);
   }
-  const auto* next = result->GetDict().FindString("next");
+  const auto* next = result->FindString("next");
   return base::ok(tenor::mojom::PaginatedGifResponses::New(next ? *next : "",
                                                            ParseGifs(gifs)));
 }
 
 base::expected<std::vector<tenor::mojom::GifResponsePtr>,
                GifTenorApiFetcher::Error>
-ParseGifsResponse(data_decoder::DataDecoder::ValueOrError result) {
+ParseGifsResponse(base::optional_ref<const base::Value::Dict> result) {
   const auto* gifs = FindList(result, "results");
   if (!gifs) {
     return base::unexpected(GifTenorApiFetcher::Error::kHttpError);
@@ -321,40 +317,39 @@
     GifTenorApiFetcher::GetCategoriesCallback callback,
     std::unique_ptr<EndpointFetcher> endpoint_fetcher,
     std::unique_ptr<EndpointResponse> response) {
-  if (response->http_status_code == net::HTTP_OK) {
-    data_decoder::DataDecoder::ParseJsonIsolated(
-        response->response,
-        base::BindOnce(ParseCategoriesResponse).Then(std::move(callback)));
+  if (response->http_status_code != net::HTTP_OK) {
+    std::move(callback).Run(base::unexpected(GetError(std::move(response))));
     return;
   }
-  std::move(callback).Run(base::unexpected(GetError(std::move(response))));
+
+  std::move(callback).Run(ParseCategoriesResponse(
+      base::JSONReader::ReadDict(response->response, base::JSON_PARSE_RFC)));
 }
 
-// `endpoint_fetcher` may be null.
 void TenorGifsApiResponseHandler(
     GifTenorApiFetcher::TenorGifsApiCallback callback,
     std::unique_ptr<EndpointFetcher> endpoint_fetcher,
     std::unique_ptr<EndpointResponse> response) {
-  if (response->http_status_code == net::HTTP_OK) {
-    data_decoder::DataDecoder::ParseJsonIsolated(
-        response->response,
-        base::BindOnce(ParsePaginatedGifsResponse).Then(std::move(callback)));
+  if (response->http_status_code != net::HTTP_OK) {
+    std::move(callback).Run(base::unexpected(GetError(std::move(response))));
     return;
   }
-  std::move(callback).Run(base::unexpected(GetError(std::move(response))));
+
+  std::move(callback).Run(ParsePaginatedGifsResponse(
+      base::JSONReader::ReadDict(response->response, base::JSON_PARSE_RFC)));
 }
 
 void FetchGifsByIdsResponseHandler(
     GifTenorApiFetcher::GetGifsByIdsCallback callback,
     std::unique_ptr<EndpointFetcher> endpoint_fetcher,
     std::unique_ptr<EndpointResponse> response) {
-  if (response->http_status_code == net::HTTP_OK) {
-    data_decoder::DataDecoder::ParseJsonIsolated(
-        response->response,
-        base::BindOnce(ParseGifsResponse).Then(std::move(callback)));
+  if (response->http_status_code != net::HTTP_OK) {
+    std::move(callback).Run(base::unexpected(GetError(std::move(response))));
     return;
   }
-  std::move(callback).Run(base::unexpected(GetError(std::move(response))));
+
+  std::move(callback).Run(ParseGifsResponse(
+      base::JSONReader::ReadDict(response->response, base::JSON_PARSE_RFC)));
 }
 
 }  // namespace
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index f9fdfe9..4fd0ce5e 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -320,6 +320,8 @@
     "form_processing/name_processing_util.h",
     "form_processing/optimization_guide_proto_util.cc",
     "form_processing/optimization_guide_proto_util.h",
+    "form_qualifiers.cc",
+    "form_qualifiers.h",
     "form_structure.cc",
     "form_structure.h",
     "form_structure_rationalization_engine.cc",
@@ -1455,6 +1457,7 @@
     "form_processing/label_processing_util_unittest.cc",
     "form_processing/name_processing_util_unittest.cc",
     "form_processing/optimization_guide_proto_util_unittest.cc",
+    "form_qualifiers_unittest.cc",
     "form_structure_rationalization_engine_unittest.cc",
     "form_structure_rationalizer_unittest.cc",
     "form_structure_sectioning_util_unittest.cc",
diff --git a/components/autofill/core/browser/crowdsourcing/votes_uploader.cc b/components/autofill/core/browser/crowdsourcing/votes_uploader.cc
index 780836fb..b2e3034 100644
--- a/components/autofill/core/browser/crowdsourcing/votes_uploader.cc
+++ b/components/autofill/core/browser/crowdsourcing/votes_uploader.cc
@@ -20,6 +20,7 @@
 #include "components/autofill/core/browser/data_model/addresses/autofill_profile.h"
 #include "components/autofill/core/browser/data_model/payments/credit_card.h"
 #include "components/autofill/core/browser/form_import/form_data_importer.h"
+#include "components/autofill/core/browser/form_qualifiers.h"
 #include "components/autofill/core/browser/form_structure.h"
 #include "components/autofill/core/browser/foundations/autofill_client.h"
 #include "components/autofill/core/browser/metrics/autofill_metrics.h"
@@ -200,7 +201,7 @@
   // is available to use as a baseline.
   std::vector<const AutofillProfile*> profiles =
       client_->GetPersonalDataManager().address_data_manager().GetProfiles();
-  if (observed_submission && form->IsAutofillable()) {
+  if (observed_submission && IsAutofillable(*form)) {
     AutofillMetrics::LogNumberOfProfilesAtAutofillableFormSubmission(
         profiles.size());
   }
@@ -233,7 +234,7 @@
   }
 
   FormStructure::FormAssociations form_associations;
-  if (form->IsAutofillable()) {
+  if (IsAutofillable(*form)) {
     form_associations = client_->GetFormDataImporter()->GetFormAssociations(
         form->form_signature());
   }
@@ -398,21 +399,21 @@
 
   // If the form is submitted, we don't need to send pending votes from blur
   // (un-focus) events.
-  if (submitted_form->ShouldRunHeuristics() ||
-      submitted_form->ShouldRunHeuristicsForSingleFields() ||
-      submitted_form->ShouldBeQueried()) {
+  if (ShouldRunHeuristics(*submitted_form) ||
+      ShouldRunHeuristicsForSingleFields(*submitted_form) ||
+      ShouldBeQueried(*submitted_form)) {
     autofill_metrics::LogQualityMetrics(
         *submitted_form, submitted_form->form_parsed_timestamp(),
         initial_interaction_timestamp, submission_timestamp,
         client_->GetFormInteractionsUkmLogger(), ukm_source_id,
         observed_submission);
   }
-  if (!submitted_form->ShouldBeUploaded()) {
+  if (!ShouldBeUploaded(*submitted_form)) {
     return;
   }
   if (autofill_metrics::ShouldRecordUkm() &&
-      submitted_form->ShouldUploadUkm(
-          /*require_classified_field=*/true)) {
+      ShouldUploadUkm(*submitted_form,
+                      /*require_classified_field=*/true)) {
     AutofillMetrics::LogAutofillFieldInfoAfterSubmission(
         client_->GetUkmRecorder(), ukm_source_id, *submitted_form,
         submission_timestamp);
diff --git a/components/autofill/core/browser/data_manager/addresses/address_data_manager.cc b/components/autofill/core/browser/data_manager/addresses/address_data_manager.cc
index 80074cc..7b30e04 100644
--- a/components/autofill/core/browser/data_manager/addresses/address_data_manager.cc
+++ b/components/autofill/core/browser/data_manager/addresses/address_data_manager.cc
@@ -608,6 +608,11 @@
 }
 
 bool AddressDataManager::IsAutofillSyncToggleAvailable() const {
+  if (base::FeatureList::IsEnabled(
+          syncer::kReplaceSyncPromosWithSignInPromos)) {
+    return false;
+  }
+
   if (!pref_service_->GetBoolean(::prefs::kExplicitBrowserSignin)) {
     return false;
   }
diff --git a/components/autofill/core/browser/data_manager/addresses/address_data_manager_unittest.cc b/components/autofill/core/browser/data_manager/addresses/address_data_manager_unittest.cc
index 6fec4c3..859e1b90 100644
--- a/components/autofill/core/browser/data_manager/addresses/address_data_manager_unittest.cc
+++ b/components/autofill/core/browser/data_manager/addresses/address_data_manager_unittest.cc
@@ -33,6 +33,7 @@
 #include "components/signin/public/identity_manager/account_info.h"
 #include "components/signin/public/identity_manager/identity_test_environment.h"
 #include "components/strike_database/test_inmemory_strike_database.h"
+#include "components/sync/base/features.h"
 #include "components/sync/service/sync_user_settings.h"
 #include "components/sync/test/test_sync_service.h"
 #include "components/webdata/common/web_database_service.h"
@@ -1221,12 +1222,18 @@
       /*hosted_domain=*/"", "Full Name", "Given Name", "en-US",
       /*picture_url=*/"");
 
-  prefs_->SetBoolean(::prefs::kExplicitBrowserSignin, true);
-  EXPECT_TRUE(address_data_manager().IsAutofillSyncToggleAvailable());
 
   prefs_->SetBoolean(::prefs::kExplicitBrowserSignin, false);
   EXPECT_FALSE(address_data_manager().IsAutofillSyncToggleAvailable());
 }
+
+TEST_F(AddressDataManagerTest, AutofillSyncToggleNotAvailableWithSigninPromos) {
+  base::test::ScopedFeatureList feature_list{
+      syncer::kReplaceSyncPromosWithSignInPromos};
+
+  prefs_->SetBoolean(::prefs::kExplicitBrowserSignin, true);
+  EXPECT_FALSE(address_data_manager().IsAutofillSyncToggleAvailable());
+}
 #endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
 
 // Tests that any `kAccountNameEmail` is created on construction of
diff --git a/components/autofill/core/browser/form_import/addresses/address_profile_save_manager.cc b/components/autofill/core/browser/form_import/addresses/address_profile_save_manager.cc
index 6b695b4..0b6b6ef3 100644
--- a/components/autofill/core/browser/form_import/addresses/address_profile_save_manager.cc
+++ b/components/autofill/core/browser/form_import/addresses/address_profile_save_manager.cc
@@ -48,11 +48,12 @@
     case AutofillProfileImportType::kConfirmableMergeAndSilentUpdate:
     case AutofillProfileImportType::kNameEmailSuperset:
     case AutofillProfileImportType::kHomeAndWorkSuperset:
-    case AutofillProfileImportType::kHomeWorkNameEmailMerge:
       return AutofillClient::SaveAddressBubbleType::kSave;
     case AutofillProfileImportType::kProfileMigration:
     case AutofillProfileImportType::kProfileMigrationAndSilentUpdate:
       return AutofillClient::SaveAddressBubbleType::kMigrateToAccount;
+    case AutofillProfileImportType::kHomeWorkNameEmailMerge:
+      return AutofillClient::SaveAddressBubbleType::kHomeWorkNameEmailMerge;
     // Those import types do not cause save/update/migrate/merge bubble to be
     // displayed.
     case AutofillProfileImportType::kDuplicateImport:
diff --git a/components/autofill/core/browser/form_parsing/determine_regex_types.cc b/components/autofill/core/browser/form_parsing/determine_regex_types.cc
index 90039ef84..efee0e6 100644
--- a/components/autofill/core/browser/form_parsing/determine_regex_types.cc
+++ b/components/autofill/core/browser/form_parsing/determine_regex_types.cc
@@ -12,6 +12,7 @@
 #include "components/autofill/core/browser/country_type.h"
 #include "components/autofill/core/browser/form_parsing/field_candidates.h"
 #include "components/autofill/core/browser/form_parsing/form_field_parser.h"
+#include "components/autofill/core/browser/form_qualifiers.h"
 #include "components/autofill/core/browser/form_structure.h"
 #include "components/autofill/core/browser/form_structure_rationalizer.h"
 #include "components/autofill/core/browser/form_structure_sectioning_util.h"
@@ -36,10 +37,10 @@
   FieldCandidatesMap field_type_map;
 
   auto form_field_data_vector = base::ToVector(form.fields(), &ToPointer);
-  if (form.ShouldRunHeuristics()) {
+  if (ShouldRunHeuristics(form)) {
     FormFieldParser::ParseFormFields(context, form_field_data_vector,
                                      field_type_map);
-  } else if (form.ShouldRunHeuristicsForSingleFields()) {
+  } else if (ShouldRunHeuristicsForSingleFields(form)) {
     FormFieldParser::ParseSingleFields(context, form_field_data_vector,
                                        field_type_map);
     FormFieldParser::ParseStandaloneCVCFields(context, form_field_data_vector,
diff --git a/components/autofill/core/browser/form_qualifiers.cc b/components/autofill/core/browser/form_qualifiers.cc
new file mode 100644
index 0000000..59c533b
--- /dev/null
+++ b/components/autofill/core/browser/form_qualifiers.cc
@@ -0,0 +1,300 @@
+// 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 "components/autofill/core/browser/form_qualifiers.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/form_structure.h"
+#include "components/autofill/core/browser/logging/log_manager.h"
+#include "components/autofill/core/common/autofill_internals/log_message.h"
+#include "components/autofill/core/common/autofill_internals/logging_scope.h"
+#include "components/autofill/core/common/autofill_regex_constants.h"
+#include "components/autofill/core/common/autofill_regexes.h"
+#include "components/autofill/core/common/autofill_util.h"
+#include "components/autofill/core/common/form_data.h"
+#include "components/autofill/core/common/form_field_data.h"
+#include "third_party/abseil-cpp/absl/functional/overload.h"
+
+namespace autofill {
+
+namespace internal {
+
+namespace {
+
+// Returns true if the scheme given by |url| is one for which autofill is
+// allowed to activate. By default this only returns true for HTTP and HTTPS.
+bool HasAllowedScheme(const GURL& url) {
+  return url.SchemeIsHTTPOrHTTPS();
+}
+
+template <typename T>
+concept IsForm = std::same_as<T, FormStructure> || std::same_as<T, FormData>;
+
+const GURL& url(const FormData& form) {
+  return form.url();
+}
+const GURL& url(const FormStructure& form) {
+  return form.source_url();
+}
+
+const GURL& action(const FormData& form) {
+  return form.action();
+}
+const GURL& action(const FormStructure& form) {
+  return form.target_url();
+}
+
+const std::vector<FormFieldData>& fields(const FormData& form) {
+  return form.fields();
+}
+const std::vector<std::unique_ptr<AutofillField>>& fields(
+    const FormStructure& form) {
+  return form.fields();
+}
+
+// A field is active if it contributes to the form signature and it is are
+// included in queries to the Autofill server.
+auto is_active = absl::Overload{
+    [](const FormFieldData& field) {
+      return !IsCheckable(field.check_status());
+    },
+    [](const std::unique_ptr<AutofillField>& field) {
+      return !IsCheckable(field->check_status());
+    },
+};
+
+auto has_autocomplete = absl::Overload{
+    [](const FormFieldData& field) {
+      return field.parsed_autocomplete().has_value();
+    },
+    [](const std::unique_ptr<AutofillField>& field) {
+      return field->parsed_autocomplete().has_value();
+    },
+};
+
+auto is_password_field = absl::Overload{
+    [](const FormFieldData& field) {
+      return field.form_control_type() == FormControlType::kInputPassword;
+    },
+    [](const std::unique_ptr<AutofillField>& field) {
+      return field->form_control_type() == FormControlType::kInputPassword;
+    },
+};
+
+auto is_select_element = absl::Overload{
+    [](const FormFieldData& field) { return field.IsSelectElement(); },
+    [](const std::unique_ptr<AutofillField>& field) {
+      return field->IsSelectElement();
+    },
+};
+
+// Returns true if at least `num` fields satisfy `p`.
+// This is useful if `num` is significantly smaller than `fields.size()` because
+// it may avoid iterating over all of `fields`. It's equivalent to
+// `std::range::count_if(fields, [](auto& f) { p(*f); }) >= num`.
+template <typename T, typename Predicate>
+  requires IsForm<T>
+bool AtLeastNumFieldsSatisfy(const T& form, size_t num, Predicate p) {
+  for (auto& field : fields(form)) {
+    if (num == 0) {
+      break;
+    }
+    if constexpr (std::same_as<T, FormStructure>) {
+      if (std::invoke(p, *field)) {
+        --num;
+      }
+    } else {
+      if (std::invoke(p, field)) {
+        --num;
+      }
+    }
+  }
+  return num == 0;
+}
+
+template <typename T>
+  requires IsForm<T>
+bool ShouldBeParsed(const T& form,
+                    ShouldBeParsedParams params,
+                    LogManager* log_manager) {
+  // Exclude URLs not on the web via HTTP(S).
+  if (!HasAllowedScheme(url(form))) {
+    LOG_AF(log_manager) << LoggingScope::kAbortParsing
+                        << LogMessage::kAbortParsingNotAllowedScheme << form;
+    return false;
+  }
+
+  if (!AtLeastNumFieldsSatisfy(form, params.min_required_fields, is_active) &&
+      (!AtLeastNumFieldsSatisfy(
+           form, params.required_fields_for_forms_with_only_password_fields,
+           is_active) ||
+       !std::ranges::all_of(fields(form), is_password_field)) &&
+      std::ranges::none_of(fields(form), has_autocomplete)) {
+    LOG_AF(log_manager) << LoggingScope::kAbortParsing
+                        << LogMessage::kAbortParsingNotEnoughFields
+                        << std::ranges::count_if(fields(form), is_active)
+                        << form;
+    return false;
+  }
+
+  // Rule out search forms.
+  if (MatchesRegex<kUrlSearchActionRe>(
+          base::UTF8ToUTF16(action(form).path_piece()))) {
+    LOG_AF(log_manager) << LoggingScope::kAbortParsing
+                        << LogMessage::kAbortParsingUrlMatchesSearchRegex
+                        << form;
+    return false;
+  }
+
+  bool has_text_field =
+      std::ranges::any_of(fields(form), std::not_fn(is_select_element));
+  if (!has_text_field) {
+    LOG_AF(log_manager) << LoggingScope::kAbortParsing
+                        << LogMessage::kAbortParsingFormHasNoTextfield << form;
+  }
+  return has_text_field;
+}
+
+template <typename T>
+  requires IsForm<T>
+bool ShouldRunHeuristics(const T& form) {
+  return AtLeastNumFieldsSatisfy(form, kMinRequiredFieldsForHeuristics,
+                                 is_active) &&
+         HasAllowedScheme(url(form));
+}
+
+template <typename T>
+  requires IsForm<T>
+bool ShouldRunHeuristicsForSingleFields(const T& form) {
+  return AtLeastNumFieldsSatisfy(form, 1, is_active) &&
+         HasAllowedScheme(url(form));
+}
+
+bool ShouldBeQueried(const FormStructure& form) {
+  return (AtLeastNumFieldsSatisfy(form, kMinRequiredFieldsForQuery,
+                                  is_active) ||
+          std::ranges::any_of(fields(form), is_password_field)) &&
+         ShouldBeParsed(form, {}, nullptr);
+}
+
+bool ShouldBeUploaded(const FormStructure& form) {
+  return AtLeastNumFieldsSatisfy(form, kMinRequiredFieldsForUpload,
+                                 is_active) &&
+         ShouldBeParsed(form, {}, nullptr);
+}
+
+bool ShouldUploadUkm(const FormStructure& form, bool require_classified_field) {
+  if (!ShouldBeParsed(form, {}, nullptr)) {
+    return false;
+  }
+
+  auto is_focusable_text_field =
+      [](const std::unique_ptr<AutofillField>& field) {
+        return field->IsTextInputElement() && field->IsFocusable();
+      };
+
+  // Return true if the field is a visible text input field which has predicted
+  // types from heuristics or the server.
+  auto is_focusable_predicted_text_field =
+      [](const std::unique_ptr<AutofillField>& field) {
+        return field->IsTextInputElement() && field->IsFocusable() &&
+               ((field->server_type() != NO_SERVER_DATA &&
+                 field->server_type() != UNKNOWN_TYPE) ||
+                field->heuristic_type() != UNKNOWN_TYPE ||
+                field->html_type() != HtmlFieldType::kUnspecified);
+      };
+
+  size_t num_text_fields = std::ranges::count_if(
+      fields(form), require_classified_field ? is_focusable_predicted_text_field
+                                             : is_focusable_text_field);
+  if (num_text_fields == 0) {
+    return false;
+  }
+
+  // If the form contains a single text field and this contains the string
+  // "search" in its name/id/placeholder, the function return false and the form
+  // is not recorded into UKM. The form is considered a search box.
+  if (num_text_fields == 1) {
+    auto it = std::ranges::find_if(fields(form),
+                                   require_classified_field
+                                       ? is_focusable_predicted_text_field
+                                       : is_focusable_text_field);
+    if (base::ToLowerASCII((*it)->placeholder()).find(u"search") !=
+            std::string::npos ||
+        base::ToLowerASCII((*it)->name()).find(u"search") !=
+            std::string::npos ||
+        base::ToLowerASCII((*it)->label()).find(u"search") !=
+            std::string::npos ||
+        base::ToLowerASCII((*it)->aria_label()).find(u"search") !=
+            std::string::npos) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+}  // namespace
+
+}  // namespace internal
+
+bool ShouldBeParsed(const FormData& form, LogManager* log_manager) {
+  return internal::ShouldBeParsed(form, {}, log_manager);
+}
+
+bool ShouldBeParsed(const FormStructure& form, LogManager* log_manager) {
+  return internal::ShouldBeParsed(form, {}, log_manager);
+}
+
+bool ShouldRunHeuristics(const FormData& form) {
+  return internal::ShouldRunHeuristics(form);
+}
+
+bool ShouldRunHeuristics(const FormStructure& form) {
+  return internal::ShouldRunHeuristics(form);
+}
+
+bool ShouldRunHeuristicsForSingleFields(const FormData& form) {
+  return internal::ShouldRunHeuristicsForSingleFields(form);
+}
+
+bool ShouldRunHeuristicsForSingleFields(const FormStructure& form) {
+  return internal::ShouldRunHeuristicsForSingleFields(form);
+}
+
+bool ShouldBeQueried(const FormStructure& form) {
+  return internal::ShouldBeQueried(form);
+}
+
+bool ShouldBeUploaded(const FormStructure& form) {
+  return internal::ShouldBeUploaded(form);
+}
+
+bool ShouldUploadUkm(const FormStructure& form, bool require_classified_field) {
+  return internal::ShouldUploadUkm(form, require_classified_field);
+}
+
+bool IsAutofillable(const FormStructure& form) {
+  static constexpr size_t kMinRequiredFields =
+      std::min({kMinRequiredFieldsForHeuristics, kMinRequiredFieldsForQuery,
+                kMinRequiredFieldsForUpload});
+  return internal::AtLeastNumFieldsSatisfy(form, kMinRequiredFields,
+                                           &AutofillField::IsFieldFillable) &&
+         internal::ShouldBeParsed(form, {}, nullptr);
+}
+
+bool ShouldBeParsedForTest(const FormData& form,  // IN-TEST
+                           ShouldBeParsedParams params,
+                           LogManager* log_manager) {
+  return internal::ShouldBeParsed(form, params, log_manager);
+}
+
+bool ShouldBeParsedForTest(const FormStructure& form,  // IN-TEST
+                           ShouldBeParsedParams params,
+                           LogManager* log_manager) {
+  return internal::ShouldBeParsed(form, params, log_manager);
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/form_qualifiers.h b/components/autofill/core/browser/form_qualifiers.h
new file mode 100644
index 0000000..0ff9808
--- /dev/null
+++ b/components/autofill/core/browser/form_qualifiers.h
@@ -0,0 +1,90 @@
+// 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_FORM_QUALIFIERS_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_QUALIFIERS_H_
+
+#include <algorithm>
+#include <cstddef>
+
+#include "components/autofill/core/common/autofill_constants.h"
+
+namespace autofill {
+
+// This file contains several functions that test properties of FormData and
+// FormStructure.
+//
+// Since some functions exist for both FormData and FormStructure and their,
+// this file contains both implementations. Otherwise, we'd have to maintain
+// equivalent implementations in both classes.
+//
+// TODO(crbug.com/40232021): Simplify this redundancy when FormData and
+// FormStructure have a formal relationship (like composition or inheritance).
+
+class FormData;
+class FormStructure;
+class LogManager;
+
+// Returns true if this form matches the structural requirements for Autofill.
+[[nodiscard]] bool ShouldBeParsed(const FormData& form,
+                                  LogManager* log_manager);
+[[nodiscard]] bool ShouldBeParsed(const FormStructure& form,
+                                  LogManager* log_manager);
+
+// Returns true if heuristic autofill type detection should be attempted for
+// this form.
+[[nodiscard]] bool ShouldRunHeuristics(const FormData& form);
+[[nodiscard]] bool ShouldRunHeuristics(const FormStructure& form);
+
+// Returns true if autofill's heuristic field type detection should be attempted
+// for this form given that `kMinRequiredFieldsForHeuristics` is not met.
+[[nodiscard]] bool ShouldRunHeuristicsForSingleFields(const FormData& form);
+[[nodiscard]] bool ShouldRunHeuristicsForSingleFields(
+    const FormStructure& form);
+
+// Returns true if we should query the crowd-sourcing server to determine this
+// form's field types. If the form includes author-specified types, this will
+// return false unless there are password fields in the form. If there are no
+// password fields the assumption is that the author has expressed their intent
+// and crowdsourced data should not be used to override this. Password fields
+// are different because there is no way to specify password generation
+// directly.
+[[nodiscard]] bool ShouldBeQueried(const FormStructure& form);
+
+// Returns true if we should upload Autofill votes for this form to the
+// crowd-sourcing server. It is not applied for Password Manager votes.
+[[nodiscard]] bool ShouldBeUploaded(const FormStructure& form);
+
+// Returns whether the form is considered parseable and meets a couple of other
+// requirements which makes uploading UKM data worthwhile. For example, the form
+// should not be a search form, the forms should have at least one focusable
+// input field with a type from heuristics or the server.
+[[nodiscard]] bool ShouldUploadUkm(const FormStructure& form,
+                                   bool require_classified_field);
+
+// Runs a quick heuristic to rule out forms that are obviously not
+// autofillable, like google/yahoo/msn search, etc.
+[[nodiscard]] bool IsAutofillable(const FormStructure& form);
+
+// Production code only uses the default parameters.
+// Exposed publicly for testing. Production code only uses the default values.
+struct ShouldBeParsedParams {
+  size_t min_required_fields =
+      std::min({kMinRequiredFieldsForHeuristics, kMinRequiredFieldsForQuery,
+                kMinRequiredFieldsForUpload});
+  size_t required_fields_for_forms_with_only_password_fields =
+      kRequiredFieldsForFormsWithOnlyPasswordFields;
+};
+
+// Variants of ShouldBeParsed() that additionally take ShouldBeParsedParams.
+[[nodiscard]] bool ShouldBeParsedForTest(const FormData& form,  // IN-TEST
+                                         ShouldBeParsedParams params,
+                                         LogManager* log_manager);
+[[nodiscard]] bool ShouldBeParsedForTest(const FormStructure& form,  // IN-TEST
+                                         ShouldBeParsedParams params,
+                                         LogManager* log_manager);
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_FORM_QUALIFIERS_H_
diff --git a/components/autofill/core/browser/form_qualifiers_unittest.cc b/components/autofill/core/browser/form_qualifiers_unittest.cc
new file mode 100644
index 0000000..8901d6b9
--- /dev/null
+++ b/components/autofill/core/browser/form_qualifiers_unittest.cc
@@ -0,0 +1,366 @@
+// 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 "components/autofill/core/browser/form_qualifiers.h"
+
+#include "components/autofill/core/browser/form_parsing/determine_regex_types.h"
+#include "components/autofill/core/browser/form_structure.h"
+#include "components/autofill/core/browser/form_structure_test_api.h"
+#include "components/autofill/core/common/autofill_test_utils.h"
+#include "components/autofill/core/common/form_data.h"
+#include "components/autofill/core/common/form_data_test_api.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace autofill {
+namespace {
+
+class FormStructureShouldTest : public testing::Test {
+ public:
+  static bool ShouldBeParsed(const FormStructure& form,
+                             ShouldBeParsedParams params = {}) {
+    const bool r = ShouldBeParsedForTest(form, params, nullptr);
+    CHECK_EQ(r, ShouldBeParsedForTest(form.ToFormData(), params, nullptr))
+        << "ShouldBeParsed(FormStructure) and ShouldBeParsed(FormData) must be "
+           "equivalent";
+    return r;
+  }
+
+  static bool ShouldRunHeuristics(const FormStructure& form) {
+    const bool r = autofill::ShouldRunHeuristics(form);
+    CHECK_EQ(r, autofill::ShouldRunHeuristics(form.ToFormData()))
+        << "ShouldRunHeuristics(FormStructure) and "
+           "ShouldRunHeuristics(FormData) must be equivalent";
+    return r;
+  }
+
+  static bool FormIsAutofillable(const FormData& form) {
+    const RegexPredictions regex_predictions = DetermineRegexTypes(
+        GeoIpCountryCode(""), LanguageCode(""), form, nullptr);
+    FormStructure form_structure(form);
+    regex_predictions.ApplyTo(form_structure.fields());
+    form_structure.RationalizeAndAssignSections(GeoIpCountryCode(""),
+                                                LanguageCode(""), nullptr);
+    return IsAutofillable(form_structure);
+  }
+
+ private:
+  test::AutofillUnitTestEnvironment autofill_test_environment_;
+};
+
+class FormShouldBeParsedTest : public FormStructureShouldTest {
+ public:
+  FormShouldBeParsedTest() {
+    form_.set_url(GURL("http://www.foo.com/"));
+    form_structure_ = std::make_unique<FormStructure>(form_);
+  }
+
+  ~FormShouldBeParsedTest() override = default;
+
+  void SetAction(GURL action) {
+    form_.set_action(action);
+    form_structure_ = nullptr;
+  }
+
+  void AddField(FormFieldData field) {
+    field.set_renderer_id(test::MakeFieldRendererId());
+    test_api(form_).Append(std::move(field));
+    form_structure_ = nullptr;
+  }
+
+  void AddTextField() {
+    FormFieldData field;
+    field.set_form_control_type(FormControlType::kInputText);
+    AddField(field);
+  }
+
+  FormStructure& form_structure() {
+    if (!form_structure_) {
+      form_structure_ = std::make_unique<FormStructure>(form_);
+    }
+    return *form_structure_.get();
+  }
+
+ private:
+  FormData form_;
+  std::unique_ptr<FormStructure> form_structure_;
+};
+
+// Empty forms should not be parsed.
+TEST_F(FormShouldBeParsedTest, FalseIfNoFields) {
+  EXPECT_FALSE(ShouldBeParsed(form_structure()));
+  EXPECT_FALSE(ShouldBeParsed(form_structure(), {.min_required_fields = 1}));
+}
+
+// Forms with only checkable fields should not be parsed.
+TEST_F(FormShouldBeParsedTest, IgnoresCheckableFields) {
+  // Start with a single checkable field.
+  {
+    FormFieldData field;
+    field.set_check_status(FormFieldData::CheckStatus::kCheckableButUnchecked);
+    field.set_form_control_type(FormControlType::kInputRadio);
+    AddField(field);
+  }
+  EXPECT_FALSE(ShouldBeParsed(form_structure()));
+  EXPECT_FALSE(ShouldBeParsed(form_structure(), {.min_required_fields = 1}));
+
+  // Add a second checkable field.
+  {
+    FormFieldData field;
+    field.set_check_status(FormFieldData::CheckStatus::kCheckableButUnchecked);
+    field.set_form_control_type(FormControlType::kInputCheckbox);
+    AddField(field);
+  }
+  EXPECT_FALSE(ShouldBeParsed(form_structure()));
+  EXPECT_FALSE(ShouldBeParsed(form_structure(), {.min_required_fields = 1}));
+
+  // Add one text field.
+  AddTextField();
+  EXPECT_TRUE(ShouldBeParsed(form_structure()));
+  EXPECT_TRUE(ShouldBeParsed(form_structure(), {.min_required_fields = 1}));
+}
+
+// Forms with at least one text field should be parsed.
+TEST_F(FormShouldBeParsedTest, TrueIfOneTextField) {
+  AddTextField();
+  EXPECT_TRUE(ShouldBeParsed(form_structure()));
+  EXPECT_TRUE(ShouldBeParsed(form_structure(), {.min_required_fields = 1}));
+  EXPECT_FALSE(ShouldBeParsed(form_structure(), {.min_required_fields = 2}));
+
+  AddTextField();
+  EXPECT_TRUE(ShouldBeParsed(form_structure()));
+  EXPECT_TRUE(ShouldBeParsed(form_structure(), {.min_required_fields = 1}));
+  EXPECT_TRUE(ShouldBeParsed(form_structure(), {.min_required_fields = 2}));
+}
+
+// Forms that have only select fields should not be parsed.
+TEST_F(FormShouldBeParsedTest, FalseIfOnlySelectField) {
+  {
+    FormFieldData field;
+    field.set_form_control_type(FormControlType::kSelectOne);
+    AddField(field);
+  }
+  EXPECT_FALSE(ShouldBeParsed(form_structure()));
+  EXPECT_FALSE(ShouldBeParsed(form_structure(), {.min_required_fields = 1}));
+
+  AddTextField();
+  EXPECT_TRUE(ShouldBeParsed(form_structure()));
+  EXPECT_TRUE(ShouldBeParsed(form_structure(), {.min_required_fields = 2}));
+}
+
+// Form whose action is a search URL should not be parsed.
+TEST_F(FormShouldBeParsedTest, FalseIfSearchURL) {
+  AddTextField();
+  EXPECT_TRUE(ShouldBeParsed(form_structure()));
+  EXPECT_TRUE(ShouldBeParsed(form_structure(), {.min_required_fields = 1}));
+  EXPECT_FALSE(ShouldBeParsed(form_structure(), {.min_required_fields = 2}));
+
+  // The target cannot include http(s)://*/search...
+  SetAction(GURL("http://google.com/search?q=hello"));
+  EXPECT_FALSE(ShouldBeParsed(form_structure()));
+  EXPECT_FALSE(ShouldBeParsed(form_structure(), {.min_required_fields = 1}));
+
+  // But search can be in the URL.
+  SetAction(GURL("http://search.com/?q=hello"));
+  EXPECT_TRUE(ShouldBeParsed(form_structure()));
+  EXPECT_TRUE(ShouldBeParsed(form_structure(), {.min_required_fields = 1}));
+}
+
+// Forms with two password fields and no other fields should be parsed.
+TEST_F(FormShouldBeParsedTest, TrueIfOnlyPasswordFields) {
+  {
+    FormFieldData field;
+    field.set_form_control_type(FormControlType::kInputPassword);
+    AddField(field);
+  }
+  EXPECT_TRUE(ShouldBeParsed(form_structure()));
+  EXPECT_TRUE(ShouldBeParsed(
+      form_structure(),
+      {.min_required_fields = 2,
+       .required_fields_for_forms_with_only_password_fields = 1}));
+  EXPECT_FALSE(ShouldBeParsed(
+      form_structure(),
+      {.min_required_fields = 2,
+       .required_fields_for_forms_with_only_password_fields = 2}));
+
+  {
+    FormFieldData field;
+    field.set_form_control_type(FormControlType::kInputPassword);
+    AddField(field);
+  }
+  EXPECT_TRUE(ShouldBeParsed(form_structure()));
+  EXPECT_TRUE(ShouldBeParsed(
+      form_structure(),
+      {.min_required_fields = 2,
+       .required_fields_for_forms_with_only_password_fields = 1}));
+  EXPECT_TRUE(ShouldBeParsed(
+      form_structure(),
+      {.min_required_fields = 2,
+       .required_fields_for_forms_with_only_password_fields = 2}));
+}
+
+// Forms with at least one field with an autocomplete attribute should be
+// parsed.
+TEST_F(FormShouldBeParsedTest, TrueIfOneFieldHasAutocomplete) {
+  AddTextField();
+  EXPECT_TRUE(ShouldBeParsed(form_structure()));
+  EXPECT_FALSE(ShouldBeParsed(form_structure(), {.min_required_fields = 2}));
+  EXPECT_FALSE(ShouldBeParsed(form_structure(), {.min_required_fields = 2}));
+
+  {
+    FormFieldData field;
+    field.set_parsed_autocomplete(AutocompleteParsingResult{
+        .section = "my-billing-section", .field_type = HtmlFieldType::kName});
+    field.set_form_control_type(FormControlType::kInputText);
+    AddField(field);
+  }
+  EXPECT_TRUE(ShouldBeParsed(form_structure()));
+  EXPECT_TRUE(ShouldBeParsed(form_structure(), {.min_required_fields = 2}));
+  EXPECT_TRUE(ShouldBeParsed(form_structure(), {.min_required_fields = 2}));
+}
+
+TEST_F(FormStructureShouldTest, ShouldBeParsed_BadScheme) {
+  std::unique_ptr<FormStructure> form_structure;
+  FormData form;
+  form.set_fields(
+      {test::CreateTestFormField("Name", "name", "",
+                                 FormControlType::kInputText, "name"),
+       test::CreateTestFormField("Email", "email", "",
+                                 FormControlType::kInputText, "email"),
+       test::CreateTestFormField("Address", "address", "",
+                                 FormControlType::kInputText,
+                                 "address-line1")});
+
+  // Baseline, HTTP should work.
+  form.set_url(GURL("http://wwww.foo.com/myform"));
+  form_structure = std::make_unique<FormStructure>(form);
+  EXPECT_TRUE(ShouldBeParsed(*form_structure));
+  EXPECT_TRUE(ShouldRunHeuristics(*form_structure));
+  EXPECT_TRUE(ShouldBeQueried(*form_structure));
+  EXPECT_TRUE(ShouldBeUploaded(*form_structure));
+
+  // Baseline, HTTPS should work.
+  form.set_url(GURL("https://wwww.foo.com/myform"));
+  form_structure = std::make_unique<FormStructure>(form);
+  EXPECT_TRUE(ShouldBeParsed(*form_structure));
+  EXPECT_TRUE(ShouldRunHeuristics(*form_structure));
+  EXPECT_TRUE(ShouldBeQueried(*form_structure));
+  EXPECT_TRUE(ShouldBeUploaded(*form_structure));
+
+  // Chrome internal urls shouldn't be parsed.
+  form.set_url(GURL("chrome://settings"));
+  form_structure = std::make_unique<FormStructure>(form);
+  EXPECT_FALSE(ShouldBeParsed(*form_structure));
+  EXPECT_FALSE(ShouldRunHeuristics(*form_structure));
+  EXPECT_FALSE(ShouldBeQueried(*form_structure));
+  EXPECT_FALSE(ShouldBeUploaded(*form_structure));
+
+  // FTP urls shouldn't be parsed.
+  form.set_url(GURL("ftp://ftp.foo.com/form.html"));
+  form_structure = std::make_unique<FormStructure>(form);
+  EXPECT_FALSE(ShouldBeParsed(*form_structure));
+  EXPECT_FALSE(ShouldRunHeuristics(*form_structure));
+  EXPECT_FALSE(ShouldBeQueried(*form_structure));
+  EXPECT_FALSE(ShouldBeUploaded(*form_structure));
+
+  // Blob urls shouldn't be parsed.
+  form.set_url(GURL("blob://blob.foo.com/form.html"));
+  form_structure = std::make_unique<FormStructure>(form);
+  EXPECT_FALSE(ShouldBeParsed(*form_structure));
+  EXPECT_FALSE(ShouldRunHeuristics(*form_structure));
+  EXPECT_FALSE(ShouldBeQueried(*form_structure));
+  EXPECT_FALSE(ShouldBeUploaded(*form_structure));
+
+  // About urls shouldn't be parsed.
+  form.set_url(GURL("about://about.foo.com/form.html"));
+  form_structure = std::make_unique<FormStructure>(form);
+  EXPECT_FALSE(ShouldBeParsed(*form_structure));
+  EXPECT_FALSE(ShouldRunHeuristics(*form_structure));
+  EXPECT_FALSE(ShouldBeQueried(*form_structure));
+  EXPECT_FALSE(ShouldBeUploaded(*form_structure));
+}
+
+// Tests that ShouldBeParsed returns true for a form containing less than three
+// fields if at least one has an autocomplete attribute.
+TEST_F(FormStructureShouldTest, ShouldBeParsed_TwoFields_HasAutocomplete) {
+  std::unique_ptr<FormStructure> form_structure;
+  FormData form;
+  form.set_url(GURL("http://www.foo.com/"));
+  form.set_fields({test::CreateTestFormField(
+                       "Name", "name", "", FormControlType::kInputText, "name"),
+                   test::CreateTestFormField("Address", "Address", "",
+                                             FormControlType::kSelectOne, "")});
+  form_structure = std::make_unique<FormStructure>(form);
+  EXPECT_TRUE(ShouldBeParsed(*form_structure));
+}
+
+TEST_F(FormStructureShouldTest, IsAutofillable) {
+  FormData form;
+  form.set_url(GURL("http://www.foo.com/"));
+  FormFieldData field;
+
+  // Start with a username field. It should be picked up by the password but
+  // not by autofill.
+  field.set_label(u"username");
+  field.set_name(u"username");
+  field.set_form_control_type(FormControlType::kInputText);
+  field.set_renderer_id(test::MakeFieldRendererId());
+  test_api(form).Append(field);
+
+  // With min required fields enabled.
+  EXPECT_FALSE(FormIsAutofillable(form));
+
+  // Add a password field. The form should be picked up by the password but
+  // not by autofill.
+  field.set_label(u"password");
+  field.set_name(u"password");
+  field.set_form_control_type(FormControlType::kInputPassword);
+  field.set_renderer_id(test::MakeFieldRendererId());
+  test_api(form).Append(field);
+
+  EXPECT_FALSE(FormIsAutofillable(form));
+
+  // Add an auto-fillable fields. With just one auto-fillable field, this should
+  // be picked up by autofill only if there is no minimum field enforcement.
+  field.set_label(u"Full Name");
+  field.set_name(u"fullname");
+  field.set_form_control_type(FormControlType::kInputText);
+  field.set_renderer_id(test::MakeFieldRendererId());
+  test_api(form).Append(field);
+
+  EXPECT_FALSE(FormIsAutofillable(form));
+
+  // Add an auto-fillable fields. With just one auto-fillable field, this should
+  // be picked up by autofill only if there is no minimum field enforcement.
+  field.set_label(u"Address Line 1");
+  field.set_name(u"address1");
+  field.set_form_control_type(FormControlType::kInputText);
+  field.set_renderer_id(test::MakeFieldRendererId());
+  test_api(form).Append(field);
+
+  EXPECT_FALSE(FormIsAutofillable(form));
+
+  // We now have three auto-fillable fields. It's always autofillable.
+  field.set_label(u"Email");
+  field.set_name(u"email");
+  field.set_form_control_type(FormControlType::kInputEmail);
+  field.set_renderer_id(test::MakeFieldRendererId());
+  test_api(form).Append(field);
+
+  EXPECT_TRUE(FormIsAutofillable(form));
+
+  // The target cannot include http(s)://*/search...
+  form.set_action(GURL("http://google.com/search?q=hello"));
+
+  EXPECT_FALSE(FormIsAutofillable(form));
+
+  // But search can be in the URL.
+  form.set_action(GURL("http://search.com/?q=hello"));
+
+  EXPECT_TRUE(FormIsAutofillable(form));
+}
+
+}  // namespace
+}  // namespace autofill
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index fe58ad0..58a09b4 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -89,12 +89,6 @@
 
 namespace {
 
-// Returns true if the scheme given by |url| is one for which autofill is
-// allowed to activate. By default this only returns true for HTTP and HTTPS.
-bool HasAllowedScheme(const GURL& url) {
-  return url.SchemeIsHTTPOrHTTPS();
-}
-
 raw_ptr<const FormFieldData> to_form_field_data(
     const std::unique_ptr<AutofillField>& field) {
   return field.get();
@@ -129,36 +123,6 @@
   return value ? "Yes" : "No";
 }
 
-bool has_autocomplete(const std::unique_ptr<AutofillField>& field) {
-  return field->parsed_autocomplete().has_value();
-}
-
-bool is_password_field(const std::unique_ptr<AutofillField>& field) {
-  return field->form_control_type() == FormControlType::kInputPassword;
-}
-
-// A field is active if it contributes to the form signature and it is are
-// included in queries to the Autofill server.
-bool is_active(const FormFieldData& field) {
-  return !IsCheckable(field.check_status());
-}
-
-// Returns true if at least `num` fields satisfy `p`.
-// This is useful if `num` is significantly smaller than `fields.size()` because
-// it may avoid iterating over all of `fields`. It's equivalent to
-// `std::range::count_if(fields, [](auto& f) { p(*f); }) >= num`.
-template <typename Predicate>
-bool AtLeastNumSatisfy(base::span<const std::unique_ptr<AutofillField>> fields,
-                       size_t num,
-                       Predicate p) {
-  for (auto it = fields.begin(); it != fields.end() && num > 0; ++it) {
-    if (std::invoke(p, **it)) {
-      --num;
-    }
-  }
-  return num == 0;
-}
-
 }  // namespace
 
 FormStructure::FormStructure(const FormData& form)
@@ -384,15 +348,6 @@
   return base::NumberToString(form_signature().value());
 }
 
-bool FormStructure::IsAutofillable() const {
-  size_t min_required_fields =
-      std::min({kMinRequiredFieldsForHeuristics, kMinRequiredFieldsForQuery,
-                kMinRequiredFieldsForUpload});
-  return AtLeastNumSatisfy(fields_, min_required_fields,
-                           &AutofillField::IsFieldFillable) &&
-         ShouldBeParsed();
-}
-
 bool FormStructure::IsCompleteCreditCardForm(
     CreditCardFormCompleteness credit_card_form_completeness) const {
   FieldTypeSet all_cc_types = FieldTypeSet(fields_, [](const auto& field) {
@@ -420,123 +375,6 @@
   }
 }
 
-bool FormStructure::ShouldBeParsed(ShouldBeParsedParams params,
-                                   LogManager* log_manager) const {
-  // Exclude URLs not on the web via HTTP(S).
-  if (!HasAllowedScheme(source_url_)) {
-    LOG_AF(log_manager) << LoggingScope::kAbortParsing
-                        << LogMessage::kAbortParsingNotAllowedScheme << *this;
-    return false;
-  }
-
-  if (!AtLeastNumSatisfy(fields(), params.min_required_fields, is_active) &&
-      (!AtLeastNumSatisfy(
-           fields(), params.required_fields_for_forms_with_only_password_fields,
-           is_active) ||
-       !std::ranges::all_of(fields_, is_password_field)) &&
-      std::ranges::none_of(fields_, has_autocomplete)) {
-    LOG_AF(log_manager) << LoggingScope::kAbortParsing
-                        << LogMessage::kAbortParsingNotEnoughFields
-                        << std::ranges::count_if(fields_,
-                                                 [](const auto& field) {
-                                                   return is_active(*field);
-                                                 })
-                        << *this;
-    return false;
-  }
-
-  // Rule out search forms.
-  if (MatchesRegex<kUrlSearchActionRe>(
-          base::UTF8ToUTF16(target_url_.path_piece()))) {
-    LOG_AF(log_manager) << LoggingScope::kAbortParsing
-                        << LogMessage::kAbortParsingUrlMatchesSearchRegex
-                        << *this;
-    return false;
-  }
-
-  bool has_text_field = std::ranges::any_of(
-      *this, [](const auto& field) { return !field->IsSelectElement(); });
-  if (!has_text_field) {
-    LOG_AF(log_manager) << LoggingScope::kAbortParsing
-                        << LogMessage::kAbortParsingFormHasNoTextfield << *this;
-  }
-  return has_text_field;
-}
-
-bool FormStructure::ShouldRunHeuristics() const {
-  // Must be identical to FormData::ShouldRunHeuristics()!
-  return AtLeastNumSatisfy(fields(), kMinRequiredFieldsForHeuristics,
-                           is_active) &&
-         HasAllowedScheme(source_url_);
-}
-
-bool FormStructure::ShouldRunHeuristicsForSingleFields() const {
-  // Must be identical to FormData::ShouldRunHeuristicsForSingleFields()!
-  return AtLeastNumSatisfy(fields(), 1, is_active) &&
-         HasAllowedScheme(source_url_);
-}
-
-bool FormStructure::ShouldBeQueried() const {
-  return (AtLeastNumSatisfy(fields(), kMinRequiredFieldsForQuery, is_active) ||
-          std::ranges::any_of(fields_, is_password_field)) &&
-         ShouldBeParsed();
-}
-
-bool FormStructure::ShouldBeUploaded() const {
-  return AtLeastNumSatisfy(fields(), kMinRequiredFieldsForUpload, is_active) &&
-         ShouldBeParsed();
-}
-
-bool FormStructure::ShouldUploadUkm(bool require_classified_field) const {
-  if (!ShouldBeParsed()) {
-    return false;
-  }
-
-  auto is_focusable_text_field =
-      [](const std::unique_ptr<AutofillField>& field) {
-        return field->IsTextInputElement() && field->IsFocusable();
-      };
-
-  // Return true if the field is a visible text input field which has predicted
-  // types from heuristics or the server.
-  auto is_focusable_predicted_text_field =
-      [](const std::unique_ptr<AutofillField>& field) {
-        return field->IsTextInputElement() && field->IsFocusable() &&
-               ((field->server_type() != NO_SERVER_DATA &&
-                 field->server_type() != UNKNOWN_TYPE) ||
-                field->heuristic_type() != UNKNOWN_TYPE ||
-                field->html_type() != HtmlFieldType::kUnspecified);
-      };
-
-  size_t num_text_fields = std::ranges::count_if(
-      fields(), require_classified_field ? is_focusable_predicted_text_field
-                                         : is_focusable_text_field);
-  if (num_text_fields == 0) {
-    return false;
-  }
-
-  // If the form contains a single text field and this contains the string
-  // "search" in its name/id/placeholder, the function return false and the form
-  // is not recorded into UKM. The form is considered a search box.
-  if (num_text_fields == 1) {
-    auto it = std::ranges::find_if(
-        fields(), require_classified_field ? is_focusable_predicted_text_field
-                                           : is_focusable_text_field);
-    if (base::ToLowerASCII((*it)->placeholder()).find(u"search") !=
-            std::string::npos ||
-        base::ToLowerASCII((*it)->name()).find(u"search") !=
-            std::string::npos ||
-        base::ToLowerASCII((*it)->label()).find(u"search") !=
-            std::string::npos ||
-        base::ToLowerASCII((*it)->aria_label()).find(u"search") !=
-            std::string::npos) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
 void FormStructure::RetrieveFromCache(const FormStructure& cached_form,
                                       RetrieveFromCacheReason reason) {
   // Build a table to lookup AutofillFields by their FieldGlobalId.
diff --git a/components/autofill/core/browser/form_structure.h b/components/autofill/core/browser/form_structure.h
index 2f2a5eb..255681f 100644
--- a/components/autofill/core/browser/form_structure.h
+++ b/components/autofill/core/browser/form_structure.h
@@ -91,10 +91,6 @@
   // Return the form signature as string.
   std::string FormSignatureAsStr() const;
 
-  // Runs a quick heuristic to rule out forms that are obviously not
-  // auto-fillable, like google/yahoo/msn search, etc.
-  bool IsAutofillable() const;
-
   // This enum defines two different states of completeness for a credit card
   // form, each used for a distinct purpose to check if the required credit card
   // fields exist.
@@ -114,39 +110,6 @@
   bool IsCompleteCreditCardForm(
       CreditCardFormCompleteness credit_card_form_completeness) const;
 
-  // Returns true if this form matches the structural requirements for Autofill.
-  [[nodiscard]] bool ShouldBeParsed(LogManager* log_manager = nullptr) const {
-    return ShouldBeParsed({}, log_manager);
-  }
-
-  // Returns true if heuristic autofill type detection should be attempted for
-  // this form.
-  bool ShouldRunHeuristics() const;
-
-  // Returns true if autofill's heuristic field type detection should be
-  // attempted for this form given that |kMinRequiredFieldsForHeuristics| is not
-  // met.
-  bool ShouldRunHeuristicsForSingleFields() const;
-
-  // Returns true if we should query the crowd-sourcing server to determine this
-  // form's field types. If the form includes author-specified types, this will
-  // return false unless there are password fields in the form. If there are no
-  // password fields the assumption is that the author has expressed their
-  // intent and crowdsourced data should not be used to override this. Password
-  // fields are different because there is no way to specify password generation
-  // directly.
-  bool ShouldBeQueried() const;
-
-  // Returns true if we should upload Autofill votes for this form to the
-  // crowd-sourcing server. It is not applied for Password Manager votes.
-  bool ShouldBeUploaded() const;
-
-  // Returns whether the form is considered parseable and meets a couple of
-  // other requirements which makes uploading UKM data worthwhile. E.g. the
-  // form should not be a search form, the forms should have at least one
-  // focusable input field with a type from heuristics or the server.
-  bool ShouldUploadUkm(bool require_classified_field) const;
-
   // This enum defines the behavior of RetrieveFromCache, which needs to adapt
   // to the reason for retrieving data from the cache.
   enum class RetrieveFromCacheReason {
@@ -356,22 +319,9 @@
   // `parsed_autocomplete` member.
   void SetFieldTypesFromAutocompleteAttribute();
 
-  // Production code only uses the default parameters.
-  // Unit tests also test other parameters.
-  struct ShouldBeParsedParams {
-    size_t min_required_fields =
-        std::min({kMinRequiredFieldsForHeuristics, kMinRequiredFieldsForQuery,
-                  kMinRequiredFieldsForUpload});
-    size_t required_fields_for_forms_with_only_password_fields =
-        kRequiredFieldsForFormsWithOnlyPasswordFields;
-  };
-
   FormStructure(FormSignature form_signature,
                 const std::vector<FieldSignature>& field_signatures);
 
-  [[nodiscard]] bool ShouldBeParsed(ShouldBeParsedParams params,
-                                    LogManager* log_manager = nullptr) const;
-
   // Extracts the parseable field name by removing a common affix.
   void ExtractParseableFieldNames();
 
diff --git a/components/autofill/core/browser/form_structure_fuzzer.cc b/components/autofill/core/browser/form_structure_fuzzer.cc
index 8f1e68c0..642457eca 100644
--- a/components/autofill/core/browser/form_structure_fuzzer.cc
+++ b/components/autofill/core/browser/form_structure_fuzzer.cc
@@ -18,6 +18,7 @@
 #include "base/path_service.h"
 #include "components/autofill/core/browser/country_type.h"
 #include "components/autofill/core/browser/form_parsing/determine_regex_types.h"
+#include "components/autofill/core/browser/form_qualifiers.h"
 #include "components/autofill/core/common/form_data.h"
 #include "components/autofill/core/common/form_data_fuzzed_producer.h"
 #include "components/autofill/core/common/form_field_data.h"
@@ -81,17 +82,14 @@
   form_structure.RationalizeAndAssignSections(
       GenerateGeoIpCountryCode(data_provider), LanguageCode(""),
       /*log_manager=*/nullptr);
-  std::ignore = form_structure.IsAutofillable();
+  std::ignore = IsAutofillable(form_structure);
   std::ignore = form_structure.IsCompleteCreditCardForm(
       FormStructure::CreditCardFormCompleteness::kCompleteCreditCardForm);
-  std::ignore = form_structure.ShouldBeParsed();
-  std::ignore = form_structure.ToFormData().ShouldRunHeuristics();
-  std::ignore = form_structure.ShouldRunHeuristics();
-  std::ignore =
-      form_structure.ToFormData().ShouldRunHeuristicsForSingleFields();
-  std::ignore = form_structure.ShouldRunHeuristicsForSingleFields();
-  std::ignore = form_structure.ShouldBeQueried();
-  std::ignore = form_structure.ShouldBeUploaded();
+  std::ignore = ShouldBeParsed(form_structure, /*log_manager=*/nullptr);
+  std::ignore = ShouldRunHeuristics(form_structure);
+  std::ignore = ShouldRunHeuristicsForSingleFields(form_structure);
+  std::ignore = ShouldBeQueried(form_structure);
+  std::ignore = ShouldBeUploaded(form_structure);
   return 0;
 }
 
diff --git a/components/autofill/core/browser/form_structure_test_api.h b/components/autofill/core/browser/form_structure_test_api.h
index 2694fed..4976b8b 100644
--- a/components/autofill/core/browser/form_structure_test_api.h
+++ b/components/autofill/core/browser/form_structure_test_api.h
@@ -19,8 +19,6 @@
 // Exposes some testing operations for FormStructure.
 class FormStructureTestApi {
  public:
-  using ShouldBeParsedParams = FormStructure::ShouldBeParsedParams;
-
   explicit FormStructureTestApi(FormStructure& form_structure)
       : form_structure_(form_structure) {}
 
@@ -35,11 +33,6 @@
     return *form_structure_->fields_.back();
   }
 
-  [[nodiscard]] bool ShouldBeParsed(ShouldBeParsedParams params = {},
-                                    LogManager* log_manager = nullptr) {
-    return form_structure_->ShouldBeParsed(params, log_manager);
-  }
-
   // Set the heuristic and server types for each field. The `heuristic_types`
   // and `server_types` vectors must be aligned with the indices of the fields
   // in the form. For each field in `heuristic_types` there must be exactly one
diff --git a/components/autofill/core/browser/form_structure_unittest.cc b/components/autofill/core/browser/form_structure_unittest.cc
index 55a633c..b9bf5e77 100644
--- a/components/autofill/core/browser/form_structure_unittest.cc
+++ b/components/autofill/core/browser/form_structure_unittest.cc
@@ -20,7 +20,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
 #include "base/unguessable_token.h"
 #include "build/build_config.h"
 #include "components/autofill/core/browser/autofill_field.h"
@@ -30,6 +29,7 @@
 #include "components/autofill/core/browser/form_parsing/determine_regex_types.h"
 #include "components/autofill/core/browser/form_parsing/form_field_parser.h"
 #include "components/autofill/core/browser/form_parsing/regex_patterns.h"
+#include "components/autofill/core/browser/form_qualifiers.h"
 #include "components/autofill/core/browser/form_structure_test_api.h"
 #include "components/autofill/core/browser/heuristic_source.h"
 #include "components/autofill/core/browser/proto/api_v1.pb.h"
@@ -79,20 +79,7 @@
     return base::NumberToString(StrToHash64Bit(str));
   }
 
- protected:
-  bool FormIsAutofillable(const FormData& form) {
-    FormStructure form_structure(form);
-    const RegexPredictions regex_predictions =
-        DetermineRegexTypes(GeoIpCountryCode(""), LanguageCode(""),
-                            form_structure.ToFormData(), nullptr);
-    regex_predictions.ApplyTo(form_structure.fields());
-    form_structure.RationalizeAndAssignSections(GeoIpCountryCode(""),
-                                                LanguageCode(""), nullptr);
-    return form_structure.IsAutofillable();
-  }
-
  private:
-  base::test::ScopedFeatureList scoped_feature_list_;
   test::AutofillUnitTestEnvironment autofill_test_environment_;
 };
 
@@ -174,346 +161,6 @@
   EXPECT_EQ(form.full_url(), form_structure.full_source_url());
 }
 
-TEST_F(FormStructureTestImpl, IsAutofillable) {
-  FormData form;
-  form.set_url(GURL("http://www.foo.com/"));
-  FormFieldData field;
-
-  // Start with a username field. It should be picked up by the password but
-  // not by autofill.
-  field.set_label(u"username");
-  field.set_name(u"username");
-  field.set_form_control_type(FormControlType::kInputText);
-  field.set_renderer_id(test::MakeFieldRendererId());
-  test_api(form).Append(field);
-
-  // With min required fields enabled.
-  EXPECT_FALSE(FormIsAutofillable(form));
-
-  // Add a password field. The form should be picked up by the password but
-  // not by autofill.
-  field.set_label(u"password");
-  field.set_name(u"password");
-  field.set_form_control_type(FormControlType::kInputPassword);
-  field.set_renderer_id(test::MakeFieldRendererId());
-  test_api(form).Append(field);
-
-  EXPECT_FALSE(FormIsAutofillable(form));
-
-  // Add an auto-fillable fields. With just one auto-fillable field, this should
-  // be picked up by autofill only if there is no minimum field enforcement.
-  field.set_label(u"Full Name");
-  field.set_name(u"fullname");
-  field.set_form_control_type(FormControlType::kInputText);
-  field.set_renderer_id(test::MakeFieldRendererId());
-  test_api(form).Append(field);
-
-  EXPECT_FALSE(FormIsAutofillable(form));
-
-  // Add an auto-fillable fields. With just one auto-fillable field, this should
-  // be picked up by autofill only if there is no minimum field enforcement.
-  field.set_label(u"Address Line 1");
-  field.set_name(u"address1");
-  field.set_form_control_type(FormControlType::kInputText);
-  field.set_renderer_id(test::MakeFieldRendererId());
-  test_api(form).Append(field);
-
-  EXPECT_FALSE(FormIsAutofillable(form));
-
-  // We now have three auto-fillable fields. It's always autofillable.
-  field.set_label(u"Email");
-  field.set_name(u"email");
-  field.set_form_control_type(FormControlType::kInputEmail);
-  field.set_renderer_id(test::MakeFieldRendererId());
-  test_api(form).Append(field);
-
-  EXPECT_TRUE(FormIsAutofillable(form));
-
-  // The target cannot include http(s)://*/search...
-  form.set_action(GURL("http://google.com/search?q=hello"));
-
-  EXPECT_FALSE(FormIsAutofillable(form));
-
-  // But search can be in the URL.
-  form.set_action(GURL("http://search.com/?q=hello"));
-
-  EXPECT_TRUE(FormIsAutofillable(form));
-}
-
-class FormStructureTestImpl_ShouldBeParsed_Test : public FormStructureTestImpl {
- public:
-  FormStructureTestImpl_ShouldBeParsed_Test() {
-    form_.set_url(GURL("http://www.foo.com/"));
-    form_structure_ = std::make_unique<FormStructure>(form_);
-  }
-
-  ~FormStructureTestImpl_ShouldBeParsed_Test() override = default;
-
-  void SetAction(GURL action) {
-    form_.set_action(action);
-    form_structure_ = nullptr;
-  }
-
-  void AddField(FormFieldData field) {
-    field.set_renderer_id(test::MakeFieldRendererId());
-    test_api(form_).Append(std::move(field));
-    form_structure_ = nullptr;
-  }
-
-  void AddTextField() {
-    FormFieldData field;
-    field.set_form_control_type(FormControlType::kInputText);
-    AddField(field);
-  }
-
-  FormStructure& form_structure() {
-    if (!form_structure_) {
-      form_structure_ = std::make_unique<FormStructure>(form_);
-    }
-    return *form_structure_.get();
-  }
-
- private:
-  FormData form_;
-  std::unique_ptr<FormStructure> form_structure_;
-};
-
-// Empty forms should not be parsed.
-TEST_F(FormStructureTestImpl_ShouldBeParsed_Test, FalseIfNoFields) {
-  EXPECT_FALSE(test_api(form_structure()).ShouldBeParsed());
-  EXPECT_FALSE(
-      test_api(form_structure()).ShouldBeParsed({.min_required_fields = 1}));
-}
-
-// Forms with only checkable fields should not be parsed.
-TEST_F(FormStructureTestImpl_ShouldBeParsed_Test, IgnoresCheckableFields) {
-  // Start with a single checkable field.
-  {
-    FormFieldData field;
-    field.set_check_status(FormFieldData::CheckStatus::kCheckableButUnchecked);
-    field.set_form_control_type(FormControlType::kInputRadio);
-    AddField(field);
-  }
-  EXPECT_FALSE(test_api(form_structure()).ShouldBeParsed());
-  EXPECT_FALSE(
-      test_api(form_structure()).ShouldBeParsed({.min_required_fields = 1}));
-
-  // Add a second checkable field.
-  {
-    FormFieldData field;
-    field.set_check_status(FormFieldData::CheckStatus::kCheckableButUnchecked);
-    field.set_form_control_type(FormControlType::kInputCheckbox);
-    AddField(field);
-  }
-  EXPECT_FALSE(test_api(form_structure()).ShouldBeParsed());
-  EXPECT_FALSE(
-      test_api(form_structure()).ShouldBeParsed({.min_required_fields = 1}));
-
-  // Add one text field.
-  AddTextField();
-  EXPECT_TRUE(test_api(form_structure()).ShouldBeParsed());
-  EXPECT_TRUE(
-      test_api(form_structure()).ShouldBeParsed({.min_required_fields = 1}));
-}
-
-// Forms with at least one text field should be parsed.
-TEST_F(FormStructureTestImpl_ShouldBeParsed_Test, TrueIfOneTextField) {
-  AddTextField();
-  EXPECT_TRUE(test_api(form_structure()).ShouldBeParsed());
-  EXPECT_TRUE(
-      test_api(form_structure()).ShouldBeParsed({.min_required_fields = 1}));
-  EXPECT_FALSE(
-      test_api(form_structure()).ShouldBeParsed({.min_required_fields = 2}));
-
-  AddTextField();
-  EXPECT_TRUE(test_api(form_structure()).ShouldBeParsed());
-  EXPECT_TRUE(
-      test_api(form_structure()).ShouldBeParsed({.min_required_fields = 1}));
-  EXPECT_TRUE(
-      test_api(form_structure()).ShouldBeParsed({.min_required_fields = 2}));
-}
-
-// Forms that have only select fields should not be parsed.
-TEST_F(FormStructureTestImpl_ShouldBeParsed_Test, FalseIfOnlySelectField) {
-  {
-    FormFieldData field;
-    field.set_form_control_type(FormControlType::kSelectOne);
-    AddField(field);
-  }
-  EXPECT_FALSE(test_api(form_structure()).ShouldBeParsed());
-  EXPECT_FALSE(
-      test_api(form_structure()).ShouldBeParsed({.min_required_fields = 1}));
-
-  AddTextField();
-  EXPECT_TRUE(test_api(form_structure()).ShouldBeParsed());
-  EXPECT_TRUE(
-      test_api(form_structure()).ShouldBeParsed({.min_required_fields = 2}));
-}
-
-// Form whose action is a search URL should not be parsed.
-TEST_F(FormStructureTestImpl_ShouldBeParsed_Test, FalseIfSearchURL) {
-  AddTextField();
-  EXPECT_TRUE(test_api(form_structure()).ShouldBeParsed());
-  EXPECT_TRUE(
-      test_api(form_structure()).ShouldBeParsed({.min_required_fields = 1}));
-  EXPECT_FALSE(
-      test_api(form_structure()).ShouldBeParsed({.min_required_fields = 2}));
-
-  // The target cannot include http(s)://*/search...
-  SetAction(GURL("http://google.com/search?q=hello"));
-  EXPECT_FALSE(test_api(form_structure()).ShouldBeParsed());
-  EXPECT_FALSE(
-      test_api(form_structure()).ShouldBeParsed({.min_required_fields = 1}));
-
-  // But search can be in the URL.
-  SetAction(GURL("http://search.com/?q=hello"));
-  EXPECT_TRUE(test_api(form_structure()).ShouldBeParsed());
-  EXPECT_TRUE(
-      test_api(form_structure()).ShouldBeParsed({.min_required_fields = 1}));
-}
-
-// Forms with two password fields and no other fields should be parsed.
-TEST_F(FormStructureTestImpl_ShouldBeParsed_Test, TrueIfOnlyPasswordFields) {
-  {
-    FormFieldData field;
-    field.set_form_control_type(FormControlType::kInputPassword);
-    AddField(field);
-  }
-  EXPECT_TRUE(test_api(form_structure()).ShouldBeParsed());
-  EXPECT_TRUE(
-      test_api(form_structure())
-          .ShouldBeParsed(
-              {.min_required_fields = 2,
-               .required_fields_for_forms_with_only_password_fields = 1}));
-  EXPECT_FALSE(
-      test_api(form_structure())
-          .ShouldBeParsed(
-              {.min_required_fields = 2,
-               .required_fields_for_forms_with_only_password_fields = 2}));
-
-  {
-    FormFieldData field;
-    field.set_form_control_type(FormControlType::kInputPassword);
-    AddField(field);
-  }
-  EXPECT_TRUE(test_api(form_structure()).ShouldBeParsed());
-  EXPECT_TRUE(
-      test_api(form_structure())
-          .ShouldBeParsed(
-              {.min_required_fields = 2,
-               .required_fields_for_forms_with_only_password_fields = 1}));
-  EXPECT_TRUE(
-      test_api(form_structure())
-          .ShouldBeParsed(
-              {.min_required_fields = 2,
-               .required_fields_for_forms_with_only_password_fields = 2}));
-}
-
-// Forms with at least one field with an autocomplete attribute should be
-// parsed.
-TEST_F(FormStructureTestImpl_ShouldBeParsed_Test,
-       TrueIfOneFieldHasAutocomplete) {
-  AddTextField();
-  EXPECT_TRUE(test_api(form_structure()).ShouldBeParsed());
-  EXPECT_FALSE(
-      test_api(form_structure()).ShouldBeParsed({.min_required_fields = 2}));
-  EXPECT_FALSE(
-      test_api(form_structure()).ShouldBeParsed({.min_required_fields = 2}));
-
-  {
-    FormFieldData field;
-    field.set_parsed_autocomplete(AutocompleteParsingResult{
-        .section = "my-billing-section", .field_type = HtmlFieldType::kName});
-    field.set_form_control_type(FormControlType::kInputText);
-    AddField(field);
-  }
-  EXPECT_TRUE(test_api(form_structure()).ShouldBeParsed());
-  EXPECT_TRUE(
-      test_api(form_structure()).ShouldBeParsed({.min_required_fields = 2}));
-  EXPECT_TRUE(
-      test_api(form_structure()).ShouldBeParsed({.min_required_fields = 2}));
-}
-
-TEST_F(FormStructureTestImpl, ShouldBeParsed_BadScheme) {
-  std::unique_ptr<FormStructure> form_structure;
-  FormData form;
-  form.set_fields(
-      {CreateTestFormField("Name", "name", "", FormControlType::kInputText,
-                           "name"),
-       CreateTestFormField("Email", "email", "", FormControlType::kInputText,
-                           "email"),
-       CreateTestFormField("Address", "address", "",
-                           FormControlType::kInputText, "address-line1")});
-
-  // Baseline, HTTP should work.
-  form.set_url(GURL("http://wwww.foo.com/myform"));
-  form_structure = std::make_unique<FormStructure>(form);
-  EXPECT_TRUE(form_structure->ShouldBeParsed());
-  EXPECT_TRUE(form_structure->ToFormData().ShouldRunHeuristics());
-  EXPECT_TRUE(form_structure->ShouldRunHeuristics());
-  EXPECT_TRUE(form_structure->ShouldBeQueried());
-  EXPECT_TRUE(form_structure->ShouldBeUploaded());
-
-  // Baseline, HTTPS should work.
-  form.set_url(GURL("https://wwww.foo.com/myform"));
-  form_structure = std::make_unique<FormStructure>(form);
-  EXPECT_TRUE(form_structure->ShouldBeParsed());
-  EXPECT_TRUE(form_structure->ToFormData().ShouldRunHeuristics());
-  EXPECT_TRUE(form_structure->ShouldRunHeuristics());
-  EXPECT_TRUE(form_structure->ShouldBeQueried());
-  EXPECT_TRUE(form_structure->ShouldBeUploaded());
-
-  // Chrome internal urls shouldn't be parsed.
-  form.set_url(GURL("chrome://settings"));
-  form_structure = std::make_unique<FormStructure>(form);
-  EXPECT_FALSE(form_structure->ShouldBeParsed());
-  EXPECT_FALSE(form_structure->ToFormData().ShouldRunHeuristics());
-  EXPECT_FALSE(form_structure->ShouldRunHeuristics());
-  EXPECT_FALSE(form_structure->ShouldBeQueried());
-  EXPECT_FALSE(form_structure->ShouldBeUploaded());
-
-  // FTP urls shouldn't be parsed.
-  form.set_url(GURL("ftp://ftp.foo.com/form.html"));
-  form_structure = std::make_unique<FormStructure>(form);
-  EXPECT_FALSE(form_structure->ShouldBeParsed());
-  EXPECT_FALSE(form_structure->ToFormData().ShouldRunHeuristics());
-  EXPECT_FALSE(form_structure->ShouldRunHeuristics());
-  EXPECT_FALSE(form_structure->ShouldBeQueried());
-  EXPECT_FALSE(form_structure->ShouldBeUploaded());
-
-  // Blob urls shouldn't be parsed.
-  form.set_url(GURL("blob://blob.foo.com/form.html"));
-  form_structure = std::make_unique<FormStructure>(form);
-  EXPECT_FALSE(form_structure->ShouldBeParsed());
-  EXPECT_FALSE(form_structure->ToFormData().ShouldRunHeuristics());
-  EXPECT_FALSE(form_structure->ShouldRunHeuristics());
-  EXPECT_FALSE(form_structure->ShouldBeQueried());
-  EXPECT_FALSE(form_structure->ShouldBeUploaded());
-
-  // About urls shouldn't be parsed.
-  form.set_url(GURL("about://about.foo.com/form.html"));
-  form_structure = std::make_unique<FormStructure>(form);
-  EXPECT_FALSE(form_structure->ShouldBeParsed());
-  EXPECT_FALSE(form_structure->ToFormData().ShouldRunHeuristics());
-  EXPECT_FALSE(form_structure->ShouldRunHeuristics());
-  EXPECT_FALSE(form_structure->ShouldBeQueried());
-  EXPECT_FALSE(form_structure->ShouldBeUploaded());
-}
-
-// Tests that ShouldBeParsed returns true for a form containing less than three
-// fields if at least one has an autocomplete attribute.
-TEST_F(FormStructureTestImpl, ShouldBeParsed_TwoFields_HasAutocomplete) {
-  std::unique_ptr<FormStructure> form_structure;
-  FormData form;
-  form.set_url(GURL("http://www.foo.com/"));
-  form.set_fields({CreateTestFormField("Name", "name", "",
-                                       FormControlType::kInputText, "name"),
-                   CreateTestFormField("Address", "Address", "",
-                                       FormControlType::kSelectOne, "")});
-  form_structure = std::make_unique<FormStructure>(form);
-  EXPECT_TRUE(form_structure->ShouldBeParsed());
-}
-
 // Tests that ShouldBeParsed returns true for a form containing less than three
 // fields if at least one has an autocomplete attribute.
 TEST_F(FormStructureTestImpl, DetermineHeuristicTypes_AutocompleteFalse) {
@@ -878,10 +525,9 @@
   field.set_renderer_id(test::MakeFieldRendererId());
   test_api(form).Append(field);
 
-  EXPECT_FALSE(FormStructure(form).ShouldRunHeuristics());
-  EXPECT_FALSE(form.ShouldRunHeuristics());
+  EXPECT_FALSE(ShouldRunHeuristics(FormStructure(form)));
 
-  EXPECT_TRUE(FormStructure(form).ShouldBeQueried());
+  EXPECT_TRUE(ShouldBeQueried(FormStructure(form)));
 
   // Default configuration.
   {
@@ -898,7 +544,7 @@
     EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(1)->heuristic_type());
     EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->server_type());
     EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->server_type());
-    EXPECT_FALSE(form_structure.IsAutofillable());
+    EXPECT_FALSE(IsAutofillable(form_structure));
   }
 }
 
@@ -915,9 +561,8 @@
                            FormControlType::kInputText, "given-name"),
        CreateTestFormField("Last Name", "lastname", "",
                            FormControlType::kInputText, "")});
-  EXPECT_FALSE(FormStructure(form).ShouldRunHeuristics());
-  EXPECT_FALSE(form.ShouldRunHeuristics());
-  EXPECT_TRUE(FormStructure(form).ShouldBeQueried());
+  EXPECT_FALSE(ShouldRunHeuristics(FormStructure(form)));
+  EXPECT_TRUE(ShouldBeQueried(FormStructure(form)));
 
   // As a side effect of parsing small forms, if any of the heuristics, query,
   // or upload minimums are disabled, we'll autofill fields with an
@@ -938,7 +583,7 @@
     EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->server_type());
     EXPECT_THAT(form_structure.field(0)->Type().GetTypes(),
                 ElementsAre(NAME_FIRST));
-    EXPECT_TRUE(form_structure.IsAutofillable());
+    EXPECT_TRUE(IsAutofillable(form_structure));
   }
 }
 
@@ -956,8 +601,8 @@
   field.set_renderer_id(test::MakeFieldRendererId());
   test_api(form).Append(field);
 
-  EXPECT_TRUE(FormStructure(form).ShouldRunHeuristicsForSingleFields());
-  EXPECT_TRUE(form.ShouldRunHeuristicsForSingleFields());
+  EXPECT_TRUE(ShouldRunHeuristicsForSingleFields(FormStructure(form)));
+  EXPECT_TRUE(ShouldRunHeuristicsForSingleFields(form));
 
   // Default configuration.
   {
@@ -972,7 +617,7 @@
     ASSERT_EQ(1U, AutofillCount(form_structure));
     EXPECT_EQ(MERCHANT_PROMO_CODE, form_structure.field(0)->heuristic_type());
     EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->server_type());
-    EXPECT_TRUE(form_structure.IsAutofillable());
+    EXPECT_TRUE(IsAutofillable(form_structure));
   }
 }
 
@@ -1002,8 +647,8 @@
       std::ranges::any_of(form_structure.fields(), [](const auto& field) {
         return field->form_control_type() == FormControlType::kInputPassword;
       }));
-  EXPECT_TRUE(form_structure.ShouldBeQueried());
-  EXPECT_TRUE(form_structure.ShouldBeUploaded());
+  EXPECT_TRUE(ShouldBeQueried(form_structure));
+  EXPECT_TRUE(ShouldBeUploaded(form_structure));
 }
 
 // Verify that we can correctly process a degenerate section listed in the
@@ -1146,7 +791,7 @@
   regex_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
-  EXPECT_TRUE(form_structure->IsAutofillable());
+  EXPECT_TRUE(IsAutofillable(*form_structure));
   ASSERT_EQ(10U, form_structure->field_count());
   ASSERT_EQ(9U, AutofillCount(*form_structure));
 
@@ -1225,7 +870,7 @@
   regex_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
-  EXPECT_TRUE(form_structure->IsAutofillable());
+  EXPECT_TRUE(IsAutofillable(*form_structure));
   ASSERT_EQ(7U, form_structure->field_count());
   ASSERT_EQ(6U, AutofillCount(*form_structure));
 
@@ -1304,7 +949,7 @@
   regex_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
-  EXPECT_TRUE(form_structure->IsAutofillable());
+  EXPECT_TRUE(IsAutofillable(*form_structure));
   ASSERT_EQ(8U, form_structure->field_count());
   ASSERT_EQ(7U, AutofillCount(*form_structure));
 
@@ -1373,7 +1018,7 @@
   regex_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
-  EXPECT_TRUE(form_structure->IsAutofillable());
+  EXPECT_TRUE(IsAutofillable(*form_structure));
   ASSERT_EQ(6U, form_structure->field_count());
   ASSERT_EQ(5U, AutofillCount(*form_structure));
 
@@ -1446,7 +1091,7 @@
   regex_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
-  EXPECT_TRUE(form_structure->IsAutofillable());
+  EXPECT_TRUE(IsAutofillable(*form_structure));
   ASSERT_EQ(7U, form_structure->field_count());
   ASSERT_EQ(5U, AutofillCount(*form_structure));
 
@@ -1503,7 +1148,7 @@
   regex_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
-  EXPECT_TRUE(form_structure->IsAutofillable());
+  EXPECT_TRUE(IsAutofillable(*form_structure));
   ASSERT_EQ(4U, form_structure->field_count());
   ASSERT_EQ(4U, AutofillCount(*form_structure));
 
@@ -1606,7 +1251,7 @@
   regex_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
-  EXPECT_TRUE(form_structure->IsAutofillable());
+  EXPECT_TRUE(IsAutofillable(*form_structure));
   ASSERT_EQ(4U, form_structure->field_count());
   EXPECT_EQ(4U, AutofillCount(*form_structure));
 
@@ -1653,7 +1298,7 @@
   regex_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
-  EXPECT_TRUE(form_structure->IsAutofillable());
+  EXPECT_TRUE(IsAutofillable(*form_structure));
   ASSERT_EQ(3U, form_structure->field_count());
   ASSERT_EQ(3U, AutofillCount(*form_structure));
 
@@ -1695,7 +1340,7 @@
   regex_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
-  EXPECT_TRUE(form_structure->IsAutofillable());
+  EXPECT_TRUE(IsAutofillable(*form_structure));
   ASSERT_EQ(3U, form_structure->field_count());
   ASSERT_EQ(3U, AutofillCount(*form_structure));
 
@@ -1778,7 +1423,7 @@
   regex_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
-  EXPECT_TRUE(form_structure->IsAutofillable());
+  EXPECT_TRUE(IsAutofillable(*form_structure));
   ASSERT_EQ(11U, form_structure->field_count());
   ASSERT_EQ(11U, AutofillCount(*form_structure));
 
@@ -1837,7 +1482,7 @@
   regex_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
-  EXPECT_TRUE(form_structure->IsAutofillable());
+  EXPECT_TRUE(IsAutofillable(*form_structure));
   ASSERT_EQ(4U, form_structure->field_count());
   ASSERT_EQ(4U, AutofillCount(*form_structure));
 
@@ -1889,7 +1534,7 @@
   regex_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
-  EXPECT_TRUE(form_structure->IsAutofillable());
+  EXPECT_TRUE(IsAutofillable(*form_structure));
 
   // Expect the correct number of fields.
   ASSERT_EQ(5U, form_structure->field_count());
@@ -1955,7 +1600,7 @@
   regex_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
-  EXPECT_TRUE(form_structure->IsAutofillable());
+  EXPECT_TRUE(IsAutofillable(*form_structure));
 
   // Expect the correct number of fields.
   ASSERT_EQ(6U, form_structure->field_count());
@@ -2025,7 +1670,7 @@
   regex_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
-  EXPECT_TRUE(form_structure->IsAutofillable());
+  EXPECT_TRUE(IsAutofillable(*form_structure));
 
   // Expect the correct number of fields.
   ASSERT_EQ(6U, form_structure->field_count());
@@ -2295,7 +1940,7 @@
   field.set_renderer_id(test::MakeFieldRendererId());
   test_api(form).Append(field);
 
-  EXPECT_FALSE(FormStructure(form).ShouldBeUploaded());
+  EXPECT_FALSE(ShouldBeUploaded(FormStructure(form)));
 }
 
 
@@ -2505,10 +2150,10 @@
 
   // The form has too few fields; it should not run heuristics, falling back to
   // the single field parsing.
-  EXPECT_FALSE(FormStructure(form).ShouldRunHeuristics());
-  EXPECT_FALSE(form.ShouldRunHeuristics());
-  EXPECT_TRUE(FormStructure(form).ShouldRunHeuristicsForSingleFields());
-  EXPECT_TRUE(form.ShouldRunHeuristicsForSingleFields());
+  EXPECT_FALSE(ShouldRunHeuristics(FormStructure(form)));
+  EXPECT_FALSE(ShouldRunHeuristics(form));
+  EXPECT_TRUE(ShouldRunHeuristicsForSingleFields(FormStructure(form)));
+  EXPECT_TRUE(ShouldRunHeuristicsForSingleFields(form));
 
   {
     FormStructure form_structure(form);
@@ -2521,7 +2166,7 @@
     ASSERT_EQ(1U, form_structure.field_count());
     ASSERT_EQ(1U, AutofillCount(form_structure));
     EXPECT_EQ(EMAIL_ADDRESS, form_structure.field(0)->heuristic_type());
-    EXPECT_TRUE(form_structure.IsAutofillable());
+    EXPECT_TRUE(IsAutofillable(form_structure));
   }
 }
 
@@ -2533,10 +2178,10 @@
 
   // The form has too few fields; it should not run heuristics, falling back to
   // the single field parsing.
-  EXPECT_FALSE(FormStructure(form).ShouldRunHeuristics());
-  EXPECT_FALSE(form.ShouldRunHeuristics());
-  EXPECT_TRUE(FormStructure(form).ShouldRunHeuristicsForSingleFields());
-  EXPECT_TRUE(form.ShouldRunHeuristicsForSingleFields());
+  EXPECT_FALSE(ShouldRunHeuristics(FormStructure(form)));
+  EXPECT_FALSE(ShouldRunHeuristics(form));
+  EXPECT_TRUE(ShouldRunHeuristicsForSingleFields(FormStructure(form)));
+  EXPECT_TRUE(ShouldRunHeuristicsForSingleFields(form));
 
   {
     FormStructure form_structure(form);
@@ -2550,7 +2195,7 @@
     ASSERT_EQ(1U, AutofillCount(form_structure));
     EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(0)->heuristic_type());
     EXPECT_EQ(EMAIL_ADDRESS, form_structure.field(1)->heuristic_type());
-    EXPECT_TRUE(form_structure.IsAutofillable());
+    EXPECT_TRUE(IsAutofillable(form_structure));
   }
 }
 
@@ -2563,10 +2208,10 @@
 
   // The form has too few fields; it should not run heuristics, falling back to
   // the single field parsing.
-  EXPECT_FALSE(FormStructure(form).ShouldRunHeuristics());
-  EXPECT_FALSE(form.ShouldRunHeuristics());
-  EXPECT_TRUE(FormStructure(form).ShouldRunHeuristicsForSingleFields());
-  EXPECT_TRUE(form.ShouldRunHeuristicsForSingleFields());
+  EXPECT_FALSE(ShouldRunHeuristics(FormStructure(form)));
+  EXPECT_FALSE(ShouldRunHeuristics(form));
+  EXPECT_TRUE(ShouldRunHeuristicsForSingleFields(FormStructure(form)));
+  EXPECT_TRUE(ShouldRunHeuristicsForSingleFields(form));
 
   {
     FormStructure form_structure(form);
@@ -2580,7 +2225,7 @@
     ASSERT_EQ(1U, AutofillCount(form_structure));
     EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(0)->heuristic_type());
     EXPECT_EQ(EMAIL_ADDRESS, form_structure.field(1)->heuristic_type());
-    EXPECT_TRUE(form_structure.IsAutofillable());
+    EXPECT_TRUE(IsAutofillable(form_structure));
   }
 }
 
@@ -2593,10 +2238,10 @@
 
   // The form has too few fields; it should not run heuristics, falling back to
   // the single field parsing.
-  EXPECT_FALSE(FormStructure(form).ShouldRunHeuristics());
-  EXPECT_FALSE(form.ShouldRunHeuristics());
-  EXPECT_TRUE(FormStructure(form).ShouldRunHeuristicsForSingleFields());
-  EXPECT_TRUE(form.ShouldRunHeuristicsForSingleFields());
+  EXPECT_FALSE(ShouldRunHeuristics(FormStructure(form)));
+  EXPECT_FALSE(ShouldRunHeuristics(form));
+  EXPECT_TRUE(ShouldRunHeuristicsForSingleFields(FormStructure(form)));
+  EXPECT_TRUE(ShouldRunHeuristicsForSingleFields(form));
   {
     FormStructure form_structure(form);
     const RegexPredictions regex_predictions =
@@ -2610,7 +2255,7 @@
     // it should be autofillable when the feature is enabled.
     ASSERT_EQ(1U, AutofillCount(form_structure));
     EXPECT_EQ(EMAIL_ADDRESS, form_structure.field(0)->heuristic_type());
-    EXPECT_TRUE(form_structure.IsAutofillable());
+    EXPECT_TRUE(IsAutofillable(form_structure));
   }
 }
 
@@ -2665,7 +2310,7 @@
   regex_predictions.ApplyTo(form_structure->fields());
   form_structure->RationalizeAndAssignSections(GeoIpCountryCode(""),
                                                LanguageCode(""), nullptr);
-  EXPECT_TRUE(form_structure->IsAutofillable());
+  EXPECT_TRUE(IsAutofillable(*form_structure));
   ASSERT_EQ(5U, form_structure->field_count());
   ASSERT_EQ(5U, AutofillCount(*form_structure));
 
diff --git a/components/autofill/core/browser/foundations/autofill_client.h b/components/autofill/core/browser/foundations/autofill_client.h
index cabc7033..d3d151a 100644
--- a/components/autofill/core/browser/foundations/autofill_client.h
+++ b/components/autofill/core/browser/foundations/autofill_client.h
@@ -249,9 +249,15 @@
 
   // Specifies the type of the address save prompt.
   enum class SaveAddressBubbleType {
+    // The standard "Save address" bubble.
     kSave = 0,
+    // An altered save bubble, that offers migrating a profile to the Google
+    // Account.
     kMigrateToAccount = 1,
-    kMaxValue = kMigrateToAccount
+    // A bubble offering to merge the `kAccountNameEmail` and
+    // `kAccountHome/kAccountName` profiles into a single profile.
+    kHomeWorkNameEmailMerge = 2,
+    kMaxValue = kHomeWorkNameEmailMerge
   };
 
   // Callback to run when the user makes a decision on whether to save the
diff --git a/components/autofill/core/browser/foundations/autofill_manager.cc b/components/autofill/core/browser/foundations/autofill_manager.cc
index be004f7..14f43027 100644
--- a/components/autofill/core/browser/foundations/autofill_manager.cc
+++ b/components/autofill/core/browser/foundations/autofill_manager.cc
@@ -22,6 +22,7 @@
 #include "components/autofill/core/browser/crowdsourcing/autofill_crowdsourcing_encoding.h"
 #include "components/autofill/core/browser/data_model/payments/credit_card.h"
 #include "components/autofill/core/browser/form_parsing/determine_regex_types.h"
+#include "components/autofill/core/browser/form_qualifiers.h"
 #include "components/autofill/core/browser/form_structure.h"
 #include "components/autofill/core/browser/form_structure_sectioning_util.h"
 #include "components/autofill/core/browser/logging/log_manager.h"
@@ -301,7 +302,7 @@
 
     // Configure the query encoding for this form and add it to the appropriate
     // collection of forms: queryable vs non-queryable.
-    if (form_structure.ShouldBeQueried()) {
+    if (ShouldBeQueried(form_structure)) {
       queryable_forms.push_back(&form_structure);
     }
 
@@ -588,7 +589,7 @@
     }
 
     auto form_structure = std::make_unique<FormStructure>(form_data);
-    if (!form_structure->ShouldBeParsed(log_manager())) {
+    if (!ShouldBeParsed(*form_structure, log_manager())) {
       LogCurrentFieldTypes(*form_structure);
       continue;
     }
@@ -622,14 +623,6 @@
     parsed_forms.push_back(form_data);
   }
 
-  // Remove duplicates by their FormGlobalId. Otherwise, after moving the forms
-  // into `form_structures_`, duplicates may be destroyed and we'd end up with
-  // dangling pointers.
-  std::ranges::sort(form_structures, {}, &FormStructure::global_id);
-  auto repeated =
-      std::ranges::unique(form_structures, {}, &FormStructure::global_id);
-  form_structures.erase(repeated.begin(), repeated.end());
-
   ParseFormsAsyncCommon(
       std::move(form_structures),
       base::BindOnce(
@@ -655,7 +648,7 @@
   }
 
   auto form_structure = std::make_unique<FormStructure>(form_data);
-  if (!form_structure->ShouldBeParsed(log_manager())) {
+  if (!ShouldBeParsed(*form_structure, log_manager())) {
     LogCurrentFieldTypes(*form_structure);
     // For Autocomplete, events need to be handled even for forms that cannot be
     // parsed.
diff --git a/components/autofill/core/browser/foundations/browser_autofill_manager.cc b/components/autofill/core/browser/foundations/browser_autofill_manager.cc
index cf4bb61..bf76f23 100644
--- a/components/autofill/core/browser/foundations/browser_autofill_manager.cc
+++ b/components/autofill/core/browser/foundations/browser_autofill_manager.cc
@@ -91,6 +91,7 @@
 #include "components/autofill/core/browser/filling/form_filler.h"
 #include "components/autofill/core/browser/filling/payments/field_filling_payments_util.h"
 #include "components/autofill/core/browser/form_import/form_data_importer.h"
+#include "components/autofill/core/browser/form_qualifiers.h"
 #include "components/autofill/core/browser/form_structure.h"
 #include "components/autofill/core/browser/foundations/autofill_client.h"
 #include "components/autofill/core/browser/geo/phone_number_i18n.h"
@@ -1115,7 +1116,9 @@
 
   // Don't send suggestions or track forms that should not be parsed.
   const bool got_autofillable_form =
-      form_structure && form_structure->ShouldBeParsed() && autofill_field;
+      form_structure &&
+      ShouldBeParsed(*form_structure, /*log_manager=*/nullptr) &&
+      autofill_field;
 
   if (!ShouldShowSuggestionsForAutocompleteUnrecognizedFields(trigger_source) &&
       got_autofillable_form &&
@@ -2653,7 +2656,7 @@
 
 bool BrowserAutofillManager::ShouldUploadForm(const FormStructure& form) {
   return client().IsAutofillEnabled() && !client().IsOffTheRecord() &&
-         form.ShouldBeUploaded();
+         ShouldBeUploaded(form);
 }
 
 void BrowserAutofillManager::
@@ -3450,7 +3453,7 @@
   // effort.
   bool should_upload_ukm =
       autofill_metrics::ShouldRecordUkm() &&
-      form_structure.ShouldUploadUkm(/*require_classified_field=*/true);
+      ShouldUploadUkm(form_structure, /*require_classified_field=*/true);
 
   for (const auto& autofill_field : form_structure) {
     if (should_upload_ukm) {
@@ -3483,8 +3486,8 @@
 
   if (base::FeatureList::IsEnabled(features::kAutofillUKMExperimentalFields) &&
       !metrics_->form_submitted_timestamp.is_null() &&
-      form_structure.ShouldUploadUkm(
-          /*require_classified_field=*/false)) {
+      ShouldUploadUkm(form_structure,
+                      /*require_classified_field=*/false)) {
     client()
         .GetFormInteractionsUkmLogger()
         .LogAutofillFormWithExperimentalFieldsCountAtFormRemove(
diff --git a/components/autofill/core/browser/metrics/form_events/form_event_logger_base.cc b/components/autofill/core/browser/metrics/form_events/form_event_logger_base.cc
index 7af37a2..db8d9c8 100644
--- a/components/autofill/core/browser/metrics/form_events/form_event_logger_base.cc
+++ b/components/autofill/core/browser/metrics/form_events/form_event_logger_base.cc
@@ -17,6 +17,7 @@
 #include "base/time/time.h"
 #include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/field_type_utils.h"
+#include "components/autofill/core/browser/form_qualifiers.h"
 #include "components/autofill/core/browser/form_structure.h"
 #include "components/autofill/core/browser/foundations/autofill_client.h"
 #include "components/autofill/core/browser/foundations/autofill_driver.h"
@@ -53,8 +54,7 @@
   // applicable  must not run heuristics normally (i.e., their field count is
   // below `kMinRequiredFieldsForHeuristics`), but must be eligible for single
   // field form heuristics.
-  if (form.ShouldRunHeuristics() ||
-      !form.ShouldRunHeuristicsForSingleFields()) {
+  if (ShouldRunHeuristics(form) || !ShouldRunHeuristicsForSingleFields(form)) {
     return false;
   }
   // Having met the prerequisites, now determine if there's a field whose
@@ -257,7 +257,7 @@
   }
 
   // Log UKM metrics for only autofillable form events.
-  if (form.IsAutofillable()) {
+  if (IsAutofillable(form)) {
     client().GetFormInteractionsUkmLogger().LogFormEvent(
         driver().GetPageUkmSourceId(), event, GetFormTypesForLogging(form),
         form.form_parsed_timestamp());
diff --git a/components/autofill/core/browser/suggestions/addresses/address_suggestion_generator.cc b/components/autofill/core/browser/suggestions/addresses/address_suggestion_generator.cc
index 7e8a1d39..ccf3b8f 100644
--- a/components/autofill/core/browser/suggestions/addresses/address_suggestion_generator.cc
+++ b/components/autofill/core/browser/suggestions/addresses/address_suggestion_generator.cc
@@ -74,6 +74,14 @@
   std::u16string text;
 };
 
+// Used to hold the relevant data for address on typing suggestions between
+// fetching and generating phases of the suggestion generation.
+struct AddressOnTypingSuggestionData {
+  std::u16string suggestion_text;
+  FieldType type;
+  std::string guid;
+};
+
 Suggestion CreateUndoOrClearFormSuggestion() {
 #if BUILDFLAG(IS_IOS)
   std::u16string value =
@@ -622,10 +630,7 @@
              : SuggestionType::kAddressEntry;
 }
 
-}  // namespace
-
-// TODO(crbug.com/409962888): Handle address suggestions on typing.
-std::vector<Suggestion> GetSuggestionsOnTypingForProfile(
+std::vector<AddressOnTypingSuggestionData> GetAddressOnTypingSuggestionData(
     const AddressDataManager& address_data_manager,
     const std::u16string& field_contents) {
   // Get the profiles to suggest, which are already sorted by relevance.
@@ -674,8 +679,8 @@
   static constexpr FieldTypeSet kTypesWithLessRequiredMatchingCharacters = {
       ADDRESS_HOME_ZIP};
 
-  std::vector<Suggestion> suggestions;
   std::set<std::u16string> suggestions_text;
+  std::vector<AddressOnTypingSuggestionData> suggestion_data;
   // The number of profiles that data will be derived from when generating
   // suggestions.
   static constexpr size_t kMaxNumberProfilesToUse = 2;
@@ -728,15 +733,31 @@
       // `ADDRESS_HOME_LINE1` and
       // `ADDRESS_HOME_STREET_ADDRESS` hold the same data.
       if (!suggestions_text.contains(suggestion_text)) {
-        suggestions.emplace_back(suggestion_text,
-                                 SuggestionType::kAddressEntryOnTyping);
-        suggestions.back().field_by_field_filling_type_used = type;
-        suggestions.back().payload = Suggestion::AutofillProfilePayload(
-            Suggestion::Guid(profile->guid()));
+        suggestion_data.push_back({suggestion_text, type, profile->guid()});
         suggestions_text.insert(suggestion_text);
       }
     }
   }
+
+  return suggestion_data;
+}
+
+}  // namespace
+
+// TODO(crbug.com/409962888): Handle address suggestions on typing.
+std::vector<Suggestion> GetSuggestionsOnTypingForProfile(
+    const AddressDataManager& address_data_manager,
+    const std::u16string& field_contents) {
+  std::vector<Suggestion> suggestions;
+
+  for (const AddressOnTypingSuggestionData& data :
+       GetAddressOnTypingSuggestionData(address_data_manager, field_contents)) {
+    suggestions.emplace_back(data.suggestion_text,
+                             SuggestionType::kAddressEntryOnTyping);
+    suggestions.back().field_by_field_filling_type_used = data.type;
+    suggestions.back().payload =
+        Suggestion::AutofillProfilePayload(Suggestion::Guid(data.guid));
+  }
   if (suggestions.size() > 0) {
     // TODO(crbug.com/381994105): Consider adding undo.
     std::ranges::move(GetAddressFooterSuggestions(/*is_autofilled=*/false),
diff --git a/components/autofill/core/browser/test_utils/autofill_form_test_utils.cc b/components/autofill/core/browser/test_utils/autofill_form_test_utils.cc
index a593410..f214c22 100644
--- a/components/autofill/core/browser/test_utils/autofill_form_test_utils.cc
+++ b/components/autofill/core/browser/test_utils/autofill_form_test_utils.cc
@@ -7,6 +7,7 @@
 #include "base/containers/to_vector.h"
 #include "components/autofill/core/browser/country_type.h"
 #include "components/autofill/core/browser/form_parsing/determine_regex_types.h"
+#include "components/autofill/core/browser/form_qualifiers.h"
 #include "components/autofill/core/browser/form_structure.h"
 #include "components/autofill/core/browser/test_utils/autofill_test_utils.h"
 #include "components/autofill/core/common/autocomplete_parsing_util.h"
@@ -234,16 +235,16 @@
     }
 
     if (test_case.form_flags.is_autofillable) {
-      EXPECT_TRUE(form_structure->IsAutofillable());
+      EXPECT_TRUE(IsAutofillable(*form_structure));
     }
     if (test_case.form_flags.should_be_parsed) {
-      EXPECT_TRUE(form_structure->ShouldBeParsed());
+      EXPECT_TRUE(ShouldBeParsed(*form_structure, /*log_manager=*/nullptr));
     }
     if (test_case.form_flags.should_be_queried) {
-      EXPECT_TRUE(form_structure->ShouldBeQueried());
+      EXPECT_TRUE(ShouldBeQueried(*form_structure));
     }
     if (test_case.form_flags.should_be_uploaded) {
-      EXPECT_TRUE(form_structure->ShouldBeUploaded());
+      EXPECT_TRUE(ShouldBeUploaded(*form_structure));
     }
     if (test_case.form_flags.has_author_specified_types) {
       EXPECT_TRUE(
diff --git a/components/autofill/core/browser/webdata/valuables/valuable_sync_bridge.cc b/components/autofill/core/browser/webdata/valuables/valuable_sync_bridge.cc
index 3c21107..2a307d30 100644
--- a/components/autofill/core/browser/webdata/valuables/valuable_sync_bridge.cc
+++ b/components/autofill/core/browser/webdata/valuables/valuable_sync_bridge.cc
@@ -57,19 +57,11 @@
 }
 
 bool IsSyncWalletFlightReservationsEnabled() {
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
   return base::FeatureList::IsEnabled(syncer::kSyncWalletFlightReservations);
-#else
-  return false;
-#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 }
 
 bool IsSyncWalletVehicleRegistrationsEnabled() {
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
   return base::FeatureList::IsEnabled(syncer::kSyncWalletVehicleRegistrations);
-#else
-  return false;
-#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 }
 
 }  // namespace
diff --git a/components/autofill/core/browser/webdata/valuables/valuable_sync_bridge_unittest.cc b/components/autofill/core/browser/webdata/valuables/valuable_sync_bridge_unittest.cc
index c05a221..7983da8 100644
--- a/components/autofill/core/browser/webdata/valuables/valuable_sync_bridge_unittest.cc
+++ b/components/autofill/core/browser/webdata/valuables/valuable_sync_bridge_unittest.cc
@@ -103,14 +103,9 @@
  public:
   // Creates the `bridge()` and mocks its `ValuablesTable`.
   void SetUp() override {
-    std::vector<base::test::FeatureRef> enabled_features = {
-        syncer::kSyncMoveValuablesToProfileDb
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-        ,
-        syncer::kSyncWalletVehicleRegistrations
-#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-    };
-    feature_list_.InitWithFeatures(enabled_features, /*disabled_features=*/{});
+    feature_list_.InitWithFeatures({syncer::kSyncMoveValuablesToProfileDb,
+                                    syncer::kSyncWalletVehicleRegistrations},
+                                   /*disabled_features=*/{});
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     db_.AddTable(&valuables_table_);
     db_.AddTable(&sync_metadata_table_);
@@ -495,7 +490,6 @@
               UnorderedElementsAre(local_vehicle));
 }
 
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 // Tests that `GetAllDataForDebugging()` returns all vehicle registrations.
 TEST_F(ValuableSyncBridgeTest, GetAllDataForDebuggingForVehicleRegistrations) {
   EntityInstance local_vehicle = GetLocalVehicleEntityInstance(
@@ -562,6 +556,5 @@
   EXPECT_THAT(GetAllEntityInstancesFromTable(),
               UnorderedElementsAre(local_vehicle, new_wallet_vehicle));
 }
-#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 
 }  // namespace autofill
diff --git a/components/autofill/core/common/form_data.cc b/components/autofill/core/common/form_data.cc
index df4c00c2..0bcd270 100644
--- a/components/autofill/core/common/form_data.cc
+++ b/components/autofill/core/common/form_data.cc
@@ -75,34 +75,6 @@
            << " FormData from pickle.";
 }
 
-// Returns true if the scheme given by |url| is one for which autofill is
-// allowed to activate. By default this only returns true for HTTP and HTTPS.
-bool HasAllowedScheme(const GURL& url) {
-  return url.SchemeIsHTTPOrHTTPS();
-}
-
-// A field is active if it contributes to the form signature and it is are
-// included in queries to the Autofill server.
-bool is_active(const FormFieldData& field) {
-  return !IsCheckable(field.check_status());
-}
-
-// Returns true if at least `num` fields satisfy `p`.
-// This is useful if `num` is significantly smaller than `fields.size()` because
-// it may avoid iterating over all of `fields`. It's equivalent to
-// `std::range::count_if(fields, [](auto& f) { p(*f); }) >= num`.
-template <typename Predicate>
-bool AtLeastNumSatisfy(base::span<const FormFieldData> fields,
-                       size_t num,
-                       Predicate p) {
-  for (auto it = fields.begin(); it != fields.end() && num > 0; ++it) {
-    if (std::invoke(p, *it)) {
-      --num;
-    }
-  }
-  return num == 0;
-}
-
 }  // namespace
 
 FrameTokenWithPredecessor::FrameTokenWithPredecessor() = default;
@@ -158,18 +130,6 @@
   return fields_it != fields().end() ? &*fields_it : nullptr;
 }
 
-bool FormData::ShouldRunHeuristics() const {
-  // Must be identical to FormStructure::ShouldRunHeuristics()!
-  return AtLeastNumSatisfy(fields(), kMinRequiredFieldsForHeuristics,
-                           is_active) &&
-         HasAllowedScheme(url());
-}
-
-bool FormData::ShouldRunHeuristicsForSingleFields() const {
-  // Must be identical to FormStructure::ShouldRunHeuristicsForSingleFields()!
-  return AtLeastNumSatisfy(fields(), 1, is_active) && HasAllowedScheme(url());
-}
-
 bool FormHasNonEmptyPasswordField(const FormData& form) {
   for (const auto& field : form.fields()) {
     if (field.IsPasswordInputElement()) {
diff --git a/components/autofill/core/common/form_data.h b/components/autofill/core/common/form_data.h
index 40c8cc5f..bf6031a3 100644
--- a/components/autofill/core/common/form_data.h
+++ b/components/autofill/core/common/form_data.h
@@ -347,9 +347,6 @@
     likely_contains_captcha_ = likely_contains_captcha;
   }
 
-  bool ShouldRunHeuristics() const;
-  bool ShouldRunHeuristicsForSingleFields() const;
-
  private:
   friend class FormDataTestApi;
 
diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp
index 457d2a1..0a31811 100644
--- a/components/autofill_strings.grdp
+++ b/components/autofill_strings.grdp
@@ -668,6 +668,15 @@
     <message name="IDS_AUTOFILL_UPDATE_ADDRESS_PROMPT_CANCEL_BUTTON_LABEL" desc="Label of the Cancel button in the prompt that offers the user to update an existing address.">
       No thanks
     </message>
+    <message name="IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_NAME_EMAIL_HOME_WORK_MERGE_PROMPT_TITLE" desc="Title shown at the top of prompt that offers the user to save a new address which is a result of a merge between the AccountNameEmail and a Work/Home profile">
+      Use this address in more places
+    </message>
+    <message name="IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_NAME_EMAIL_HOME_WORK_MERGE_OK_BUTTON_LABEL" desc="Label of the save button shown in the prompt that offers the user to save a new address which is a result of a merge between the AccountNameEmail and a Work/Home profile">
+      I'm in
+    </message>
+    <message name="IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_NAME_EMAIL_HOME_WORK_MERGE_CANCEL_BUTTON_LABEL" desc="Label of the cancel button shown in the prompt that offers the user to save a new address which is a result of a merge between the AccountNameEmail and a Work/Home profile">
+      Cancel
+    </message>
     <message name="IDS_AUTOFILL_EDIT_ADDRESS_DIALOG_TITLE" desc="Title shown at the top of dialog that edits an address before saving it">
       Edit address
     </message>
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_NAME_EMAIL_HOME_WORK_MERGE_CANCEL_BUTTON_LABEL.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_NAME_EMAIL_HOME_WORK_MERGE_CANCEL_BUTTON_LABEL.png.sha1
new file mode 100644
index 0000000..e92f0059
--- /dev/null
+++ b/components/autofill_strings_grdp/IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_NAME_EMAIL_HOME_WORK_MERGE_CANCEL_BUTTON_LABEL.png.sha1
@@ -0,0 +1 @@
+8712b51cf5949b5bbc66350d43f60a7bfe17942b
\ No newline at end of file
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_NAME_EMAIL_HOME_WORK_MERGE_OK_BUTTON_LABEL.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_NAME_EMAIL_HOME_WORK_MERGE_OK_BUTTON_LABEL.png.sha1
new file mode 100644
index 0000000..a92d00c
--- /dev/null
+++ b/components/autofill_strings_grdp/IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_NAME_EMAIL_HOME_WORK_MERGE_OK_BUTTON_LABEL.png.sha1
@@ -0,0 +1 @@
+aa93e77790917112402ee727d7985b2122147c68
\ No newline at end of file
diff --git a/components/autofill_strings_grdp/IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_NAME_EMAIL_HOME_WORK_MERGE_PROMPT_TITLE.png.sha1 b/components/autofill_strings_grdp/IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_NAME_EMAIL_HOME_WORK_MERGE_PROMPT_TITLE.png.sha1
new file mode 100644
index 0000000..f9141774
--- /dev/null
+++ b/components/autofill_strings_grdp/IDS_AUTOFILL_SAVE_ADDRESS_PROMPT_NAME_EMAIL_HOME_WORK_MERGE_PROMPT_TITLE.png.sha1
@@ -0,0 +1 @@
+d7dbec9cfd6109020b7396b31e9ea5127c2d9b19
\ No newline at end of file
diff --git a/components/browser_sync/BUILD.gn b/components/browser_sync/BUILD.gn
index 8c71e91..a8e2f149 100644
--- a/components/browser_sync/BUILD.gn
+++ b/components/browser_sync/BUILD.gn
@@ -45,8 +45,6 @@
     "//components/plus_addresses/core/browser/settings",
     "//components/plus_addresses/core/browser/sync_utils",
     "//components/plus_addresses/webdata",
-    "//components/power_bookmarks/core",
-    "//components/power_bookmarks/core:features",
     "//components/prefs",
     "//components/reading_list/core",
     "//components/saved_tab_groups/public",
diff --git a/components/browser_sync/DEPS b/components/browser_sync/DEPS
index 637db42..46a30ba4 100644
--- a/components/browser_sync/DEPS
+++ b/components/browser_sync/DEPS
@@ -15,7 +15,6 @@
   "+components/keyed_service/core",
   "+components/password_manager/core/browser",
   "+components/plus_addresses",
-  "+components/power_bookmarks/core",
   "+components/prefs",
   "+components/reading_list/core",
   "+components/reading_list/features",
diff --git a/components/browser_sync/common_controller_builder.cc b/components/browser_sync/common_controller_builder.cc
index 205b8eb..1e9bd92 100644
--- a/components/browser_sync/common_controller_builder.cc
+++ b/components/browser_sync/common_controller_builder.cc
@@ -51,8 +51,6 @@
 #include "components/plus_addresses/core/browser/settings/plus_address_setting_service.h"
 #include "components/plus_addresses/core/browser/sync_utils/plus_address_data_type_controller.h"
 #include "components/plus_addresses/webdata/plus_address_webdata_service.h"
-#include "components/power_bookmarks/core/power_bookmark_features.h"
-#include "components/power_bookmarks/core/power_bookmark_service.h"
 #include "components/prefs/pref_service.h"
 #include "components/reading_list/core/dual_reading_list_model.h"
 #include "components/reading_list/core/reading_list_local_data_batch_uploader.h"
@@ -320,11 +318,6 @@
   plus_address_webdata_service_.Set(plus_address_webdata_service);
 }
 
-void CommonControllerBuilder::SetPowerBookmarkService(
-    power_bookmarks::PowerBookmarkService* power_bookmark_service) {
-  power_bookmark_service_.Set(power_bookmark_service);
-}
-
 void CommonControllerBuilder::SetPrefService(PrefService* pref_service) {
   pref_service_.Set(pref_service);
 }
@@ -529,16 +522,6 @@
               std::make_unique<sync_bookmarks::BookmarkLocalDataBatchUploader>(
                   bookmark_model_.value(), pref_service_.value())));
     }
-
-    if (!disabled_types.Has(syncer::POWER_BOOKMARK) &&
-        power_bookmark_service_.value() &&
-        base::FeatureList::IsEnabled(power_bookmarks::kPowerBookmarkBackend)) {
-      // TODO(crbug.com/40261319): Support transport mode for POWER_BOOKMARK.
-      controllers.push_back(std::make_unique<DataTypeController>(
-          syncer::POWER_BOOKMARK,
-          power_bookmark_service_.value()->CreateSyncControllerDelegate(),
-          /*delegate_for_transport_mode=*/nullptr));
-    }
   }
 
   if (!disabled_types.Has(syncer::HISTORY)) {
diff --git a/components/browser_sync/common_controller_builder.h b/components/browser_sync/common_controller_builder.h
index 3fc83c9a..718f67d 100644
--- a/components/browser_sync/common_controller_builder.h
+++ b/components/browser_sync/common_controller_builder.h
@@ -71,10 +71,6 @@
 class PlusAddressWebDataService;
 }  // namespace plus_addresses
 
-namespace power_bookmarks {
-class PowerBookmarkService;
-}  // namespace power_bookmarks
-
 namespace reading_list {
 class DualReadingListModel;
 }  // namespace reading_list
@@ -187,8 +183,6 @@
       plus_addresses::PlusAddressSettingService* plus_address_setting_service,
       const scoped_refptr<plus_addresses::PlusAddressWebDataService>&
           plus_address_webdata_service);
-  void SetPowerBookmarkService(
-      power_bookmarks::PowerBookmarkService* power_bookmark_service);
   void SetPrefService(PrefService* pref_service);
   void SetPrefServiceSyncable(
       sync_preferences::PrefServiceSyncable* pref_service_syncable);
@@ -300,8 +294,6 @@
   SafeOptional<raw_ptr<sync_bookmarks::BookmarkSyncService>>
       account_bookmark_sync_service_;
   SafeOptional<raw_ptr<bookmarks::BookmarkModel>> bookmark_model_;
-  SafeOptional<raw_ptr<power_bookmarks::PowerBookmarkService>>
-      power_bookmark_service_;
   SafeOptional<raw_ptr<supervised_user::SupervisedUserSettingsService>>
       supervised_user_settings_service_;
   SafeOptional<raw_ptr<plus_addresses::PlusAddressSettingService>>
diff --git a/components/collaboration/internal/collaboration_service_impl.cc b/components/collaboration/internal/collaboration_service_impl.cc
index b7fbf74..06585c4 100644
--- a/components/collaboration/internal/collaboration_service_impl.cc
+++ b/components/collaboration/internal/collaboration_service_impl.cc
@@ -389,6 +389,8 @@
   }
 #endif
 
+  // TODO(crbug.com/40066949): Simplify this code once all users are migrated
+  // away from Sync-the-feature.
   if (sync_service_->IsSyncFeatureEnabled()) {
     // Sync-the-feature is enabled, but the required data types are not.
     // The user needs to enable them in settings.
@@ -397,7 +399,9 @@
     if (base::FeatureList::IsEnabled(
             syncer::kReplaceSyncPromosWithSignInPromos)) {
       // Sync-the-feature is not required, but the user needs to enable
-      // the required data types in settings.
+      // the required data types in settings. Note that this also includes cases
+      // where the user is not signed in at all - that is covered by
+      // GetSigninStatus().
       return SyncStatus::kSyncWithoutTabGroup;
     } else {
       // The user needs to enable Sync-the-feature.
diff --git a/components/collaboration/public/service_status.h b/components/collaboration/public/service_status.h
index a95d2e4..4e0057c3 100644
--- a/components/collaboration/public/service_status.h
+++ b/components/collaboration/public/service_status.h
@@ -20,9 +20,15 @@
 // GENERATED_JAVA_ENUM_PACKAGE: (
 //   org.chromium.components.collaboration)
 enum class SyncStatus {
+  // Sync-the-feature is disabled but required, or the Sync machinery is fully
+  // disabled (e.g. by command-line switch).
   kNotSyncing = 0,
+  // Syncing is available in principle, but the tab groups type is not enabled.
+  // This may also be returned for signed-out users.
   kSyncWithoutTabGroup = 1,
+  // Syncing of tab groups is enabled.
   kSyncEnabled = 2,
+  // Syncing is disabled due to Enterprise policy.
   kSyncDisabledByEnterprise = 3,
 };
 
diff --git a/components/lens/contextual_input.h b/components/lens/contextual_input.h
index 5b792e66..87fceb53 100644
--- a/components/lens/contextual_input.h
+++ b/components/lens/contextual_input.h
@@ -46,8 +46,13 @@
   std::optional<std::string> page_title;
   // If the context is a pdf, this is the current viewed page.
   std::optional<uint32_t> pdf_current_page;
+#if BUILDFLAG(IS_IOS)
+  // If the context is a webpage or pdf, this is the viewport screenshot.
+  std::optional<std::vector<uint8_t>> viewport_screenshot_bytes;
+#else
   // If the context is a webpage or pdf, this is the viewport screenshot.
   std::optional<SkBitmap> viewport_screenshot;
+#endif  // BUILDFLAG(IS_IOS)
   // Whether or not webpage or pdf context is eligible.
   bool is_page_context_eligible;
 };
diff --git a/components/omnibox/composebox/composebox_query_controller.cc b/components/omnibox/composebox/composebox_query_controller.cc
index bc3e37c3..5b32664 100644
--- a/components/omnibox/composebox/composebox_query_controller.cc
+++ b/components/omnibox/composebox/composebox_query_controller.cc
@@ -295,12 +295,19 @@
   UpdateFileUploadStatus(file_token, FileUploadStatus::kProcessing,
                          std::nullopt);
 
+#if BUILDFLAG(IS_IOS)
+  bool has_viewport_screenshot =
+      contextual_input_data->viewport_screenshot_bytes.has_value();
+#else
+  bool has_viewport_screenshot =
+      contextual_input_data->viewport_screenshot.has_value();
+#endif  // BUILDFLAG(IS_IOS)
   // Unlike image uploads,PDF / page content uploads need to increment the
   // long context id instead of the image sequence id.
   current_file_info.request_id_ = GetNextRequestId(
       current_file_info.mime_type_ == lens::MimeType::kImage
           ? lens::RequestIdUpdateMode::kFullImageRequest
-          : (contextual_input_data->viewport_screenshot.has_value()
+          : (has_viewport_screenshot
                  ? lens::RequestIdUpdateMode::kPageContentWithViewportRequest
                  : lens::RequestIdUpdateMode::kPageContentRequest),
       current_file_info.mime_type_,
@@ -664,14 +671,24 @@
     return;
   }
 
-#if !BUILDFLAG(IS_IOS)
   // If there is a viewport screenshot, create the viewport upload request body.
-  // TODO(crbug.com/442683956): Support alternative to SkBitmap for viewport
-  // screenshot, for iOS.
+  // TODO(crbug.com/442685171): Pass the pdf page number to the viewport
+  // upload request if available.
+#if BUILDFLAG(IS_IOS)
+  if (contextual_input_data->viewport_screenshot_bytes.has_value()) {
+    CHECK(image_options.has_value());
+    CreateImageUploadRequest(
+        file_token,
+        // Pass ownership of the viewport screenshot bytes to the callback.
+        std::move(contextual_input_data->viewport_screenshot_bytes.value()),
+        std::move(image_options),
+        base::BindOnce(&ComposeboxQueryController::OnUploadRequestBodyReady,
+                       weak_ptr_factory_.GetWeakPtr(), file_token,
+                       file_info->num_outstanding_network_requests_++));
+  }
+#else
   if (contextual_input_data->viewport_screenshot.has_value()) {
     CHECK(image_options.has_value());
-    // TODO(crbug.com/442685171): Pass the pdf page number to the viewport
-    // upload request if available.
     ProcessDecodedImageAndContinue(
         *file_info->request_id_, image_options.value(),
         base::BindOnce(&ComposeboxQueryController::OnUploadRequestBodyReady,
diff --git a/components/page_load_metrics/browser/fake_page_load_metrics_observer_delegate.cc b/components/page_load_metrics/browser/fake_page_load_metrics_observer_delegate.cc
index dfe6ce5d..75eef574 100644
--- a/components/page_load_metrics/browser/fake_page_load_metrics_observer_delegate.cc
+++ b/components/page_load_metrics/browser/fake_page_load_metrics_observer_delegate.cc
@@ -78,6 +78,10 @@
   return visibility_at_activation_;
 }
 
+bool FakePageLoadMetricsObserverDelegate::IsReloadAfterDiscard() const {
+  return is_discarded_page_reload_;
+}
+
 bool FakePageLoadMetricsObserverDelegate::
     WasPrerenderedThenActivatedInForeground() const {
   return GetVisibilityAtActivation() == PageVisibility::kForeground;
diff --git a/components/page_load_metrics/browser/fake_page_load_metrics_observer_delegate.h b/components/page_load_metrics/browser/fake_page_load_metrics_observer_delegate.h
index 0f32e05..4faf0a3 100644
--- a/components/page_load_metrics/browser/fake_page_load_metrics_observer_delegate.h
+++ b/components/page_load_metrics/browser/fake_page_load_metrics_observer_delegate.h
@@ -46,6 +46,7 @@
       size_t index) const override;
   bool StartedInForeground() const override;
   PageVisibility GetVisibilityAtActivation() const override;
+  bool IsReloadAfterDiscard() const override;
   bool WasPrerenderedThenActivatedInForeground() const override;
   const UserInitiatedInfo& GetUserInitiatedInfo() const override;
   const GURL& GetUrl() const override;
@@ -118,6 +119,7 @@
   base::TimeTicks navigation_start_;
   std::optional<base::TimeTicks> first_background_time_ = std::nullopt;
   bool started_in_foreground_ = true;
+  bool is_discarded_page_reload_ = false;
   PrerenderingState prerendering_state_ = PrerenderingState::kNoPrerendering;
   PageVisibility visibility_at_activation_ = PageVisibility::kNotInitialized;
   std::optional<base::TimeDelta> activation_start_ = std::nullopt;
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.cc b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
index 8c998c5..b6c0902 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer.cc
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
@@ -394,9 +394,12 @@
   auto insertion_result = provisional_loads_.insert(std::make_pair(
       navigation_handle,
       std::make_unique<PageLoadTracker>(
-          in_foreground, embedder_interface_.get(), currently_committed_url,
-          !has_navigated_, navigation_handle, user_initiated_info, source_id,
-          parent_tracker)));
+          PageLoadTracker::InForegroundBool{in_foreground},
+          embedder_interface_.get(), currently_committed_url,
+          PageLoadTracker::IsFirstNavigationInWebContentsBool{!has_navigated_},
+          PageLoadTracker::IsReloadAfterDiscardBool{
+              navigation_handle->ExistingDocumentWasDiscarded()},
+          navigation_handle, user_initiated_info, source_id, parent_tracker)));
   CHECK(insertion_result.second)
       << "provisional_loads_ already contains NavigationHandle.";
   for (auto& observer : lifecycle_observers_) {
diff --git a/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.cc b/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.cc
index 178a8d3..aab35bfc 100644
--- a/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.cc
+++ b/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.cc
@@ -109,6 +109,9 @@
     "PageLoad.PaintTiming.NavigationToFirstContentfulPaint";
 const char kBackgroundHistogramFirstContentfulPaint[] =
     "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.Background";
+const char kHistogramFirstContentfulPaintExcludeReloadAfterDiscard[] =
+    "PageLoad.PaintTiming.NavigationToFirstContentfulPaint."
+    "ExcludeReloadAfterDiscard";
 const char kHistogramFirstContentfulPaintInitiatingProcess[] =
     "PageLoad.Internal.PaintTiming.NavigationToFirstContentfulPaint."
     "InitiatingProcess";
@@ -117,6 +120,9 @@
 const char kBackgroundHttpsOrDataOrFileSchemeHistogramLargestContentfulPaint[] =
     "PageLoad.PaintTiming.NavigationToLargestContentfulPaint2.Background."
     "HttpsOrDataOrFileScheme";
+const char kHistogramLargestContentfulPaintExcludeReloadAfterDiscard[] =
+    "PageLoad.PaintTiming.NavigationToLargestContentfulPaint2."
+    "ExcludeReloadAfterDiscard";
 const char kHistogramLargestContentfulPaintContentType[] =
     "PageLoad.Internal.PaintTiming.LargestContentfulPaint.ContentType";
 const char kHistogramLargestContentfulPaintMainFrame[] =
@@ -450,6 +456,12 @@
                           timing.paint_timing->first_contentful_paint.value());
     }
 
+    if (!GetDelegate().IsReloadAfterDiscard()) {
+      PAGE_LOAD_HISTOGRAM(
+          internal::kHistogramFirstContentfulPaintExcludeReloadAfterDiscard,
+          timing.paint_timing->first_contentful_paint.value());
+    }
+
     PAGE_LOAD_HISTOGRAM(
         internal::kHistogramTotalSubresourceLoadTimeAtFirstContentfulPaint,
         total_subresource_load_time_);
@@ -941,6 +953,12 @@
                             lcp_time);
       }
 
+      if (!GetDelegate().IsReloadAfterDiscard()) {
+        PAGE_LOAD_HISTOGRAM(
+            internal::kHistogramLargestContentfulPaintExcludeReloadAfterDiscard,
+            lcp_time);
+      }
+
       if (content::WebContents* web_contents = GetDelegate().GetWebContents()) {
         if (content::PreloadingData* preloading_data =
                 content::PreloadingData::GetForWebContents(web_contents)) {
diff --git a/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h b/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h
index c370a9f..241a0911 100644
--- a/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h
+++ b/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h
@@ -59,6 +59,9 @@
 extern const char kBackgroundHistogramLoad[];
 extern const char kBackgroundHistogramFirstPaint[];
 
+extern const char kHistogramFirstContentfulPaintExcludeReloadAfterDiscard[];
+extern const char kHistogramLargestContentfulPaintExcludeReloadAfterDiscard[];
+
 extern const char kHistogramLoadTypeFirstContentfulPaintReload[];
 extern const char kHistogramLoadTypeFirstContentfulPaintForwardBack[];
 extern const char kHistogramLoadTypeFirstContentfulPaintNewNavigation[];
diff --git a/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer_unittest.cc b/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer_unittest.cc
index 3f8b6a7..7f4c90f 100644
--- a/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer_unittest.cc
+++ b/components/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer_unittest.cc
@@ -1773,6 +1773,72 @@
   TestHistogram(kHistogram, {{kExpected, 1}});
 }
 
+TEST_P(UmaPageLoadMetricsObserverTest, ReloadAfterDiscard_ExcludeHistograms) {
+  page_load_metrics::mojom::PageLoadTiming timing;
+  page_load_metrics::InitPageLoadTimingForTest(&timing);
+  timing.navigation_start = base::Time::FromSecondsSinceUnixEpoch(1);
+  timing.response_start = base::Milliseconds(1);
+  timing.parse_timing->parse_start = base::Milliseconds(1);
+  timing.paint_timing->first_contentful_paint = base::Milliseconds(30);
+  timing.paint_timing->largest_contentful_paint->largest_text_paint =
+      base::Milliseconds(4780);
+  timing.paint_timing->largest_contentful_paint->largest_text_paint_size = 120u;
+  PopulateRequiredTimingFields(&timing);
+
+  // Set the WebContents as discarded.
+  web_contents()->SetWasDiscarded(true);
+
+  NavigateAndCommit(GURL(kDefaultTestUrl));
+  tester()->SimulateTimingUpdate(timing);
+
+  // Navigate again to force histogram recording.
+  NavigateAndCommit(GURL(kDefaultTestUrl2));
+
+  tester()->histogram_tester().ExpectTotalCount(
+      internal::kHistogramFirstContentfulPaint, 1);
+  tester()->histogram_tester().ExpectTotalCount(
+      internal::kHistogramFirstContentfulPaintExcludeReloadAfterDiscard, 0);
+  tester()->histogram_tester().ExpectTotalCount(
+      internal::kHistogramLargestContentfulPaint, 1);
+  tester()->histogram_tester().ExpectTotalCount(
+      internal::kHistogramLargestContentfulPaintExcludeReloadAfterDiscard, 0);
+}
+
+TEST_P(UmaPageLoadMetricsObserverTest,
+       NotReloadAfterDiscard_IncludeHistograms) {
+  page_load_metrics::mojom::PageLoadTiming timing;
+  page_load_metrics::InitPageLoadTimingForTest(&timing);
+  timing.navigation_start = base::Time::FromSecondsSinceUnixEpoch(1);
+  timing.response_start = base::Milliseconds(1);
+  timing.parse_timing->parse_start = base::Milliseconds(1);
+  timing.paint_timing->first_contentful_paint = base::Milliseconds(30);
+  timing.paint_timing->largest_contentful_paint->largest_text_paint =
+      base::Milliseconds(4780);
+  timing.paint_timing->largest_contentful_paint->largest_text_paint_size = 120u;
+  PopulateRequiredTimingFields(&timing);
+
+  // Unlike the previous test, do *not* set the WebContents as discarded.
+
+  NavigateAndCommit(GURL(kDefaultTestUrl));
+  tester()->SimulateTimingUpdate(timing);
+
+  // Navigate again to force histogram recording.
+  NavigateAndCommit(GURL(kDefaultTestUrl2));
+
+  tester()->histogram_tester().ExpectTotalCount(
+      internal::kHistogramFirstContentfulPaint, 1);
+  tester()->histogram_tester().ExpectBucketCount(
+      internal::kHistogramFirstContentfulPaintExcludeReloadAfterDiscard,
+      timing.paint_timing->first_contentful_paint.value().InMilliseconds(), 1);
+  tester()->histogram_tester().ExpectTotalCount(
+      internal::kHistogramLargestContentfulPaint, 1);
+  tester()->histogram_tester().ExpectBucketCount(
+      internal::kHistogramLargestContentfulPaintExcludeReloadAfterDiscard,
+      timing.paint_timing->largest_contentful_paint->largest_text_paint.value()
+          .InMilliseconds(),
+      1);
+}
+
 class UmaPageLoadMetricsObserverIncognitoTest
     : public UmaPageLoadMetricsObserverTest {
  protected:
diff --git a/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h b/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h
index 44e25d4..c9f4e68 100644
--- a/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h
+++ b/components/page_load_metrics/browser/page_load_metrics_observer_delegate.h
@@ -121,6 +121,9 @@
   // Page's visibility at activation.
   virtual PageVisibility GetVisibilityAtActivation() const = 0;
 
+  // True if the page load is a reload of a page that was discarded.
+  virtual bool IsReloadAfterDiscard() const = 0;
+
   // True if the page load was a prerender, that was later activated by a
   // navigation that started in the foreground.
   virtual bool WasPrerenderedThenActivatedInForeground() const = 0;
diff --git a/components/page_load_metrics/browser/page_load_tracker.cc b/components/page_load_metrics/browser/page_load_tracker.cc
index 309cc8a..33881ff2 100644
--- a/components/page_load_metrics/browser/page_load_tracker.cc
+++ b/components/page_load_metrics/browser/page_load_tracker.cc
@@ -257,10 +257,11 @@
 }  // namespace
 
 PageLoadTracker::PageLoadTracker(
-    bool in_foreground,
+    InForegroundBool in_foreground,
     PageLoadMetricsEmbedderInterface* embedder_interface,
     const GURL& currently_committed_url,
-    bool is_first_navigation_in_web_contents,
+    IsFirstNavigationInWebContentsBool is_first_navigation_in_web_contents,
+    IsReloadAfterDiscardBool is_reload_after_discard,
     content::NavigationHandle* navigation_handle,
     UserInitiatedInfo user_initiated_info,
     ukm::SourceId source_id,
@@ -270,7 +271,8 @@
       navigation_start_(navigation_handle->NavigationStart()),
       url_(navigation_handle->GetURL()),
       start_url_(navigation_handle->GetURL()),
-      visibility_tracker_(base::DefaultTickClock::GetInstance(), in_foreground),
+      visibility_tracker_(base::DefaultTickClock::GetInstance(),
+                          *in_foreground),
       did_commit_(false),
       page_end_reason_(END_NONE),
       page_end_user_initiated_info_(UserInitiatedInfo::NotUserInitiated()),
@@ -282,8 +284,9 @@
       source_id_(source_id),
       web_contents_(navigation_handle->GetWebContents()),
       is_first_navigation_in_web_contents_(is_first_navigation_in_web_contents),
+      is_reload_after_discard_(is_reload_after_discard),
       is_origin_visit_(
-          CalculateIsOriginVisit(is_first_navigation_in_web_contents,
+          CalculateIsOriginVisit(*is_first_navigation_in_web_contents,
                                  navigation_handle->GetPageTransition())),
       soft_navigation_metrics_(CreateSoftNavigationMetrics()),
       page_type_(CalculatePageType(navigation_handle)),
@@ -1227,6 +1230,10 @@
   return visibility_at_activation_;
 }
 
+bool PageLoadTracker::IsReloadAfterDiscard() const {
+  return *is_reload_after_discard_;
+}
+
 bool PageLoadTracker::WasPrerenderedThenActivatedInForeground() const {
   return GetVisibilityAtActivation() == PageVisibility::kForeground;
 }
@@ -1363,7 +1370,7 @@
 }
 
 bool PageLoadTracker::IsFirstNavigationInWebContents() const {
-  return is_first_navigation_in_web_contents_;
+  return *is_first_navigation_in_web_contents_;
 }
 
 bool PageLoadTracker::IsOriginVisit() const {
diff --git a/components/page_load_metrics/browser/page_load_tracker.h b/components/page_load_metrics/browser/page_load_tracker.h
index 33ef707..12bd050 100644
--- a/components/page_load_metrics/browser/page_load_tracker.h
+++ b/components/page_load_metrics/browser/page_load_tracker.h
@@ -181,17 +181,31 @@
 class PageLoadTracker : public PageLoadMetricsUpdateDispatcher::Client,
                         public PageLoadMetricsObserverDelegate {
  public:
+  // Whether a page is in foreground when it starts loading.
+  using InForegroundBool = base::StrongAlias<struct ForegroundTag, bool>;
+  // Whether a navigation is the first to occur in a WebContents.
+  using IsFirstNavigationInWebContentsBool =
+      base::StrongAlias<struct FirstNavigationInWebContentsTag, bool>;
+  // Whether a navigation is a reload of a page that was previously discarded.
+  // This typically happens when a user re-activates a background page that the
+  // browser had discarded. See https://wicg.github.io/page-lifecycle/spec.html
+  // for the formal definition of discarding.
+  using IsReloadAfterDiscardBool =
+      base::StrongAlias<struct ReloadAfterDiscardTag, bool>;
+
   // Caller must guarantee that the `embedder_interface` pointer outlives this
   // class. The PageLoadTracker must not hold on to `navigation_handle` beyond
   // the scope of the constructor.
-  PageLoadTracker(bool in_foreground,
-                  PageLoadMetricsEmbedderInterface* embedder_interface,
-                  const GURL& currently_committed_url,
-                  bool is_first_navigation_in_web_contents,
-                  content::NavigationHandle* navigation_handle,
-                  UserInitiatedInfo user_initiated_info,
-                  ukm::SourceId source_id,
-                  base::WeakPtr<PageLoadTracker> parent_tracker);
+  PageLoadTracker(
+      InForegroundBool in_foreground,
+      PageLoadMetricsEmbedderInterface* embedder_interface,
+      const GURL& currently_committed_url,
+      IsFirstNavigationInWebContentsBool is_first_navigation_in_web_contents,
+      IsReloadAfterDiscardBool is_reload_after_discard,
+      content::NavigationHandle* navigation_handle,
+      UserInitiatedInfo user_initiated_info,
+      ukm::SourceId source_id,
+      base::WeakPtr<PageLoadTracker> parent_tracker);
 
   PageLoadTracker(const PageLoadTracker&) = delete;
   PageLoadTracker& operator=(const PageLoadTracker&) = delete;
@@ -246,6 +260,7 @@
       size_t index) const override;
   bool StartedInForeground() const override;
   PageVisibility GetVisibilityAtActivation() const override;
+  bool IsReloadAfterDiscard() const override;
   bool WasPrerenderedThenActivatedInForeground() const override;
   const UserInitiatedInfo& GetUserInitiatedInfo() const override;
   const GURL& GetUrl() const override;
@@ -581,7 +596,8 @@
   // instance is bound.
   content::GlobalRenderFrameHostId page_main_frame_id_;
 
-  const bool is_first_navigation_in_web_contents_;
+  const IsFirstNavigationInWebContentsBool is_first_navigation_in_web_contents_;
+  const IsReloadAfterDiscardBool is_reload_after_discard_;
   const bool is_origin_visit_;
   bool is_terminal_visit_ = true;
 
diff --git a/components/page_load_metrics/browser/page_load_tracker_unittest.cc b/components/page_load_metrics/browser/page_load_tracker_unittest.cc
index a738f6a..fd7f792 100644
--- a/components/page_load_metrics/browser/page_load_tracker_unittest.cc
+++ b/components/page_load_metrics/browser/page_load_tracker_unittest.cc
@@ -178,6 +178,19 @@
   EXPECT_FALSE(GetEvents().was_committed);
 }
 
+TEST_F(PageLoadTrackerTest, NotReloadAfterDiscard) {
+  SetTargetUrl(kTestUrl);
+  NavigateAndCommit(GURL(kTestUrl));
+  EXPECT_FALSE(tester()->GetDelegateForCommittedLoad().IsReloadAfterDiscard());
+}
+
+TEST_F(PageLoadTrackerTest, ReloadAfterDiscard) {
+  SetTargetUrl(kTestUrl);
+  web_contents()->SetWasDiscarded(true);
+  NavigateAndCommit(GURL(kTestUrl));
+  EXPECT_TRUE(tester()->GetDelegateForCommittedLoad().IsReloadAfterDiscard());
+}
+
 TEST_F(PageLoadTrackerTest, EventForwarding) {
   ScopedPrerenderWebContentsDelegate web_contents_delegate(*web_contents());
 
diff --git a/components/paint_preview/browser/paint_preview_client.cc b/components/paint_preview/browser/paint_preview_client.cc
index 6219a64d..4611d6b 100644
--- a/components/paint_preview/browser/paint_preview_client.cc
+++ b/components/paint_preview/browser/paint_preview_client.cc
@@ -886,9 +886,10 @@
     document_data.had_success = false;
   }
 
-  TRACE_EVENT_END("paint_preview", perfetto::Track::FromPointer(&document_data),
-                  "success", document_data.had_success, "subframes",
-                  document_data.finished_subframes.size());
+  TRACE_EVENT_NESTABLE_ASYNC_END2(
+      "paint_preview", "PaintPreviewClient::CapturePaintPreview",
+      TRACE_ID_LOCAL(&document_data), "success", document_data.had_success,
+      "subframes", document_data.finished_subframes.size());
 
   base::UmaHistogramBoolean("Browser.PaintPreview.Capture.Success",
                             document_data.had_success);
diff --git a/components/password_manager/core/browser/password_form_cache.h b/components/password_manager/core/browser/password_form_cache.h
index 0dba263b..d6159b1 100644
--- a/components/password_manager/core/browser/password_form_cache.h
+++ b/components/password_manager/core/browser/password_form_cache.h
@@ -13,7 +13,6 @@
 struct PasswordForm;
 class PasswordFormManager;
 
-#if !BUILDFLAG(IS_IOS)
 // Allows observing events inside PasswordFormManager. Declared here to allow
 // adding observers to all form mangers in the cache.
 class PasswordFormManagerObserver : public base::CheckedObserver {
@@ -23,17 +22,6 @@
   // Invoked whenever `form_manager` parses a form.
   virtual void OnPasswordFormParsed(PasswordFormManager* form_manager) = 0;
 };
-#else
-// Allows observing events inside PasswordFormManager. Declared here to allow
-// adding observers to all form mangers in the cache.
-class PasswordFormManagerObserver {
- public:
-  virtual ~PasswordFormManagerObserver() {}
-
-  // Invoked whenever `form_manager` parses a form.
-  virtual void OnPasswordFormParsed(PasswordFormManager* form_manager) = 0;
-};
-#endif
 
 // Contains information about password forms detected on a web page.
 class PasswordFormCache {
@@ -53,22 +41,14 @@
   virtual const PasswordForm* GetPasswordForm(
       PasswordManagerDriver* driver,
       autofill::FieldRendererId field_id) const = 0;
-#if !BUILDFLAG(IS_IOS)
+
   // Allows adding an observer for all newly added password form managers.
   virtual void AddObserver(PasswordFormManagerObserver* observer) {}
 
   // Removes observer from all current form managers and prevents attaching
   // observer to newly added.
   virtual void RemoveObserver(PasswordFormManagerObserver* observer) {}
-#else
-  // Allows adding an observer for all newly added password form managers.
-  virtual void SetObserver(
-      base::WeakPtr<PasswordFormManagerObserver> observer) {}
 
-  // Removes observer from all current form managers and prevents attaching
-  // observer to newly added.
-  virtual void ResetObserver() {}
-#endif
   // Returns all the `PasswordFormManager`s for the current page.
   virtual base::span<const std::unique_ptr<PasswordFormManager>>
   GetFormManagers() const = 0;
diff --git a/components/password_manager/core/browser/password_form_cache_impl.cc b/components/password_manager/core/browser/password_form_cache_impl.cc
index 779dc57..e70a203 100644
--- a/components/password_manager/core/browser/password_form_cache_impl.cc
+++ b/components/password_manager/core/browser/password_form_cache_impl.cc
@@ -52,16 +52,10 @@
 
 void PasswordFormCacheImpl::AddFormManager(
     std::unique_ptr<PasswordFormManager> manager) {
-#if !BUILDFLAG(IS_IOS)
   for (PasswordFormManagerObserver& form_manager_observer :
        form_manager_observers_) {
     manager->AddObserver(&form_manager_observer);
   }
-#else
-  if (form_manager_observer_) {
-    manager->SetObserver(form_manager_observer_);
-  }
-#endif
   form_managers_.emplace_back(std::move(manager));
 }
 
@@ -92,13 +86,9 @@
 
       // After PasswordFormManager is removed from cache it's impossible to
       // reset observation. Thus, it's safer to stop observing immediately.
-#if !BUILDFLAG(IS_IOS)
       for (PasswordFormManagerObserver& observer : form_manager_observers_) {
         submitted_manager->RemoveObserver(&observer);
       }
-#else
-      submitted_manager->ResetObserver();
-#endif
       return submitted_manager;
     }
   }
@@ -113,7 +103,6 @@
   return form_managers_.empty();
 }
 
-#if !BUILDFLAG(IS_IOS)
 void PasswordFormCacheImpl::AddObserver(PasswordFormManagerObserver* observer) {
   if (!form_manager_observers_.HasObserver(observer)) {
     form_manager_observers_.AddObserver(observer);
@@ -130,19 +119,6 @@
     manager->RemoveObserver(observer);
   }
 }
-#else
-void PasswordFormCacheImpl::SetObserver(
-    base::WeakPtr<PasswordFormManagerObserver> observer) {
-  form_manager_observer_ = observer;
-}
-
-void PasswordFormCacheImpl::ResetObserver() {
-  form_manager_observer_.reset();
-  for (const std::unique_ptr<PasswordFormManager>& manager : form_managers_) {
-    manager->ResetObserver();
-  }
-}
-#endif
 
 base::span<const std::unique_ptr<PasswordFormManager>>
 PasswordFormCacheImpl::GetFormManagers() const {
diff --git a/components/password_manager/core/browser/password_form_cache_impl.h b/components/password_manager/core/browser/password_form_cache_impl.h
index 7d7e83a..f0f75ee 100644
--- a/components/password_manager/core/browser/password_form_cache_impl.h
+++ b/components/password_manager/core/browser/password_form_cache_impl.h
@@ -45,25 +45,16 @@
   const PasswordForm* GetPasswordForm(
       PasswordManagerDriver* driver,
       autofill::FieldRendererId field_id) const override;
-#if !BUILDFLAG(IS_IOS)
   void AddObserver(PasswordFormManagerObserver* observer) override;
   void RemoveObserver(PasswordFormManagerObserver* observer) override;
-#else
-  void SetObserver(
-      base::WeakPtr<PasswordFormManagerObserver> observer) override;
-  void ResetObserver() override;
-#endif
   base::span<const std::unique_ptr<PasswordFormManager>> GetFormManagers()
       const override;
 
  private:
   // TODO(b/330313855): Check if `unique_ptr` can be removed here.
   std::vector<std::unique_ptr<PasswordFormManager>> form_managers_;
-#if !BUILDFLAG(IS_IOS)
+
   base::ObserverList<PasswordFormManagerObserver> form_manager_observers_;
-#else
-  base::WeakPtr<PasswordFormManagerObserver> form_manager_observer_;
-#endif
 };
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_form_cache_impl_unittest.cc b/components/password_manager/core/browser/password_form_cache_impl_unittest.cc
index 4494494..522f920a 100644
--- a/components/password_manager/core/browser/password_form_cache_impl_unittest.cc
+++ b/components/password_manager/core/browser/password_form_cache_impl_unittest.cc
@@ -260,11 +260,7 @@
 // Test that the cache adds observers to newly added managers.
 TEST_F(PasswordFormCacheTest, ObservationOnFormManager) {
   MockPasswordFormManagerObserver observer;
-#if !BUILDFLAG(IS_IOS)
   static_cast<PasswordFormCache*>(&cache())->AddObserver(&observer);
-#else
-  static_cast<PasswordFormCache*>(&cache())->SetObserver(observer.GetWeakPtr());
-#endif
 
   auto form_manager = std::make_unique<PasswordFormManager>(
       &client(), driver().AsWeakPtr(), CreateTestPasswordFormData(),
@@ -279,7 +275,7 @@
   form_fetcher().NotifyFetchCompleted();
   FastForwardUntilNoTasksRemain();
 }
-#if !BUILDFLAG(IS_IOS)
+
 // Test that the cache adds observers to all existing managers.
 TEST_F(PasswordFormCacheTest, ObservationOnExistingFormManager) {
   MockPasswordFormManagerObserver observer;
@@ -296,5 +292,5 @@
   form_fetcher().NotifyFetchCompleted();
   FastForwardUntilNoTasksRemain();
 }
-#endif
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc
index 3620853c..0cd5565 100644
--- a/components/password_manager/core/browser/password_form_manager.cc
+++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -1216,16 +1216,10 @@
   if (!parsed_observed_form_) {
     return;
   }
-#if !BUILDFLAG(IS_IOS)
   for (PasswordFormManagerObserver& form_parsed_observer :
        form_parsed_observers_) {
     form_parsed_observer.OnPasswordFormParsed(this);
   }
-#else
-  if (form_parsed_observer_) {
-    form_parsed_observer_->OnPasswordFormParsed(this);
-  }
-#endif
   metrics_recorder_->CacheParsingResultInFillingMode(
       *parsed_observed_form_.get());
 
@@ -1902,7 +1896,6 @@
   return stored_usernames;
 }
 
-#if !BUILDFLAG(IS_IOS)
 void PasswordFormManager::AddObserver(PasswordFormManagerObserver* observer) {
   if (!form_parsed_observers_.HasObserver(observer)) {
     form_parsed_observers_.AddObserver(observer);
@@ -1913,15 +1906,5 @@
     PasswordFormManagerObserver* observer) {
   form_parsed_observers_.RemoveObserver(observer);
 }
-#else
-void PasswordFormManager::SetObserver(
-    base::WeakPtr<PasswordFormManagerObserver> observer) {
-  form_parsed_observer_ = observer;
-}
-
-void PasswordFormManager::ResetObserver() {
-  form_parsed_observer_.reset();
-}
-#endif
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_form_manager.h b/components/password_manager/core/browser/password_form_manager.h
index 01a5e7b..5482ea9b 100644
--- a/components/password_manager/core/browser/password_form_manager.h
+++ b/components/password_manager/core/browser/password_form_manager.h
@@ -307,13 +307,9 @@
     return votes_uploader_.has_value() ? &votes_uploader_.value() : nullptr;
   }
 #endif
-#if !BUILDFLAG(IS_IOS)
+
   void AddObserver(PasswordFormManagerObserver* observer);
   void RemoveObserver(PasswordFormManagerObserver* observer);
-#else
-  void SetObserver(base::WeakPtr<PasswordFormManagerObserver> observer);
-  void ResetObserver();
-#endif
 
  protected:
   // Constructor for Credentials API.
@@ -527,11 +523,8 @@
 
   // For generating timing metrics on retrieving server-side predictions.
   std::unique_ptr<base::ElapsedTimer> server_side_predictions_timer_;
-#if !BUILDFLAG(IS_IOS)
+
   base::ObserverList<PasswordFormManagerObserver> form_parsed_observers_;
-#else
-  base::WeakPtr<PasswordFormManagerObserver> form_parsed_observer_;
-#endif
 };
 
 // Returns whether `form_data` differs from the form observed by `form_manager`
diff --git a/components/password_manager/core/browser/password_form_manager_unittest.cc b/components/password_manager/core/browser/password_form_manager_unittest.cc
index f37b8287..098e65f 100644
--- a/components/password_manager/core/browser/password_form_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -4777,7 +4777,6 @@
 
 #endif
 
-#if !BUILDFLAG(IS_IOS)
 TEST_P(PasswordFormManagerTest, NotifiesObservers) {
   MockPasswordFormManagerObserver observer;
   MockPasswordFormManagerObserver observer_2;
@@ -4805,32 +4804,6 @@
 
   task_environment_.FastForwardUntilNoTasksRemain();
 }
-#else
-TEST_P(PasswordFormManagerTest, NotifiesObserver) {
-  MockPasswordFormManagerObserver observer;
-
-  CreateFormManager(observed_form_);
-  form_manager_->SetObserver(observer.GetWeakPtr());
-
-  EXPECT_CALL(observer, OnPasswordFormParsed(form_manager_.get()));
-  SetNonFederatedAndNotifyFetchCompleted({saved_match_});
-
-  task_environment_.FastForwardUntilNoTasksRemain();
-}
-
-TEST_P(PasswordFormManagerTest, DoesNotNotifyAfterObserverRemoved) {
-  MockPasswordFormManagerObserver observer;
-
-  CreateFormManager(observed_form_);
-  form_manager_->SetObserver(observer.GetWeakPtr());
-  form_manager_->ResetObserver();
-
-  EXPECT_CALL(observer, OnPasswordFormParsed).Times(0);
-  SetNonFederatedAndNotifyFetchCompleted({saved_match_});
-
-  task_environment_.FastForwardUntilNoTasksRemain();
-}
-#endif
 
 INSTANTIATE_TEST_SUITE_P(All, PasswordFormManagerTest, testing::Bool());
 
diff --git a/components/password_manager/core/browser/undo_password_change_controller.cc b/components/password_manager/core/browser/undo_password_change_controller.cc
index 17c024d..1d753a69 100644
--- a/components/password_manager/core/browser/undo_password_change_controller.cc
+++ b/components/password_manager/core/browser/undo_password_change_controller.cc
@@ -73,7 +73,6 @@
 void UndoPasswordChangeController::OnLoginPotentiallyFailed(
     PasswordManagerDriver* driver,
     const PasswordForm& login_form) {
-#if !BUILDFLAG(IS_IOS)
   auto password_field_it = std::ranges::find(
       login_form.form_data.fields(), login_form.password_element_renderer_id,
       &autofill::FormFieldData::renderer_id);
@@ -87,7 +86,6 @@
   failed_login_form_ = login_form;
   password_form_cache_ = driver_->GetPasswordManager()->GetPasswordFormCache();
   password_form_cache_->AddObserver(this);
-#endif
 }
 
 PasswordRecoveryState UndoPasswordChangeController::GetState(
@@ -151,18 +149,15 @@
 }
 
 void UndoPasswordChangeController::FinishObserving() {
-#if !BUILDFLAG(IS_IOS)
   failed_login_form_ = std::nullopt;
   driver_ = nullptr;
   if (password_form_cache_) {
     password_form_cache_->RemoveObserver(this);
   }
-#endif
 }
 
 void UndoPasswordChangeController::OnPasswordFormParsed(
     PasswordFormManager* form_manager) {
-#if !BUILDFLAG(IS_IOS)
   CHECK(form_manager);
   if (!failed_login_form_ || !driver_) {
     return;
@@ -199,7 +194,6 @@
             form_manager->GetParsedObservedForm()
                 ->password_element_renderer_id));
   }
-#endif
 }
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/undo_password_change_controller_unittest.cc b/components/password_manager/core/browser/undo_password_change_controller_unittest.cc
index 6f8e36b..75a731e 100644
--- a/components/password_manager/core/browser/undo_password_change_controller_unittest.cc
+++ b/components/password_manager/core/browser/undo_password_change_controller_unittest.cc
@@ -302,7 +302,6 @@
             PasswordRecoveryState::kIncludeBackup);
 }
 
-#if !BUILDFLAG(IS_IOS)
 TEST_F(UndoPasswordChangeControllerTest, OnLoginPotentiallyFailedFlagOn) {
   base::test::ScopedFeatureList feature_list(features::kShowRecoveryPassword);
   best_match_form_.SetPasswordBackupNote(kBackupPassword);
@@ -460,6 +459,5 @@
       ChangeRecoveryUkmEntry::kPasswordChangeRecoveryFlowName,
       static_cast<int>(expected_metric_state));
 }
-#endif
 
 }  // namespace password_manager
diff --git a/components/signin/core/browser/account_reconcilor.h b/components/signin/core/browser/account_reconcilor.h
index 55399fc..7e62812d 100644
--- a/components/signin/core/browser/account_reconcilor.h
+++ b/components/signin/core/browser/account_reconcilor.h
@@ -460,11 +460,6 @@
 
 #if BUILDFLAG(IS_CHROMEOS)
   // On Ash, this is a pointer to `AccountManagerFacadeImpl`.
-  // Note: On Lacros too, this is a pointer to `AccountManagerFacadeImpl`, and
-  // not `ProfileAccountManager`. This was done to simplify the design since
-  // this pointer is only used to observe the closure of the OS/Ash-level signin
-  // dialog and nothing else. Reconsider this decision if this usage changes in
-  // the future.
   raw_ptr<account_manager::AccountManagerFacade> account_manager_facade_;
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
diff --git a/components/signin/core/browser/account_reconcilor_unittest.cc b/components/signin/core/browser/account_reconcilor_unittest.cc
index 40c1574..e0fe51f 100644
--- a/components/signin/core/browser/account_reconcilor_unittest.cc
+++ b/components/signin/core/browser/account_reconcilor_unittest.cc
@@ -2237,8 +2237,7 @@
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
 }
 
-// Check that token error on primary account results in a logout to all accounts
-// on Lacros. For other mirror platforms, reconcile is aborted.
+// Check that token error on primary account results in aborted reconcile
 TEST_F(AccountReconcilorMirrorTest, TokenErrorOnPrimary) {
   AccountInfo account_info = ConnectProfileToAccount(kFakeEmail);
   signin::UpdatePersistentErrorOfRefreshTokenForAccount(
diff --git a/components/signin/core/browser/mirror_account_reconcilor_delegate.cc b/components/signin/core/browser/mirror_account_reconcilor_delegate.cc
index 0707cac..e6661135 100644
--- a/components/signin/core/browser/mirror_account_reconcilor_delegate.cc
+++ b/components/signin/core/browser/mirror_account_reconcilor_delegate.cc
@@ -44,11 +44,7 @@
   // Ash.
   return ConsentLevel::kSync;
 #else
-  // For mobile (iOS, Android) and Lacros.
-  //
-  // Whenever Mirror is enabled on a Lacros Profile, the Primary Account may or
-  // may not have consented to Chrome Sync. But we want to enable
-  // `AccountReconcilor` regardless - for minting Gaia cookies.
+  // For mobile (iOS, Android).
   return ConsentLevel::kSignin;
 #endif
 }
diff --git a/components/signin/internal/identity_manager/primary_account_manager.cc b/components/signin/internal/identity_manager/primary_account_manager.cc
index 1c62d5a..09adbfc 100644
--- a/components/signin/internal/identity_manager/primary_account_manager.cc
+++ b/components/signin/internal/identity_manager/primary_account_manager.cc
@@ -661,8 +661,7 @@
 
   if (abort_signout) {
     // TODO(crbug.com/40240858): Add 'NOTREACHED()' after updating the
-    // 'SigninManager', 'Dice Response Handler',
-    // 'Lacros Profile Account Mapper'.
+    // 'SigninManager', 'Dice Response Handler'.
     VLOG(1) << "Ignoring attempt to sign out while signout disallowed";
     return;
   }
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service_builder.cc b/components/signin/internal/identity_manager/profile_oauth2_token_service_builder.cc
index 972e17c..8bccc03e 100644
--- a/components/signin/internal/identity_manager/profile_oauth2_token_service_builder.cc
+++ b/components/signin/internal/identity_manager/profile_oauth2_token_service_builder.cc
@@ -144,7 +144,7 @@
                                  account_manager_facade, is_regular_profile);
 #elif BUILDFLAG(ENABLE_DICE_SUPPORT)
   // Fall back to |MutableProfileOAuth2TokenServiceDelegate| on all platforms
-  // other than Android, iOS, and Chrome OS (Ash and Lacros).
+  // other than Android, iOS, and Chrome OS (Ash).
   return CreateMutableProfileOAuthDelegate(
       account_tracker_service, account_consistency,
       delete_signin_cookies_on_exit, token_web_data, signin_client,
diff --git a/components/signin/public/identity_manager/BUILD.gn b/components/signin/public/identity_manager/BUILD.gn
index 768578fb..4216c44 100644
--- a/components/signin/public/identity_manager/BUILD.gn
+++ b/components/signin/public/identity_manager/BUILD.gn
@@ -15,13 +15,13 @@
     "access_token_restriction.h",
     "account_capabilities.cc",
     "account_capabilities.h",
-    "account_capability_fetcher.cc",
-    "account_capability_fetcher.h",
     "account_info.cc",
     "account_info.h",
     "account_managed_status_finder.cc",
     "account_managed_status_finder.h",
     "account_managed_status_finder_outcome.h",
+    "account_state_fetcher.cc",
+    "account_state_fetcher.h",
     "accounts_cookie_mutator.h",
     "accounts_in_cookie_jar_info.cc",
     "accounts_in_cookie_jar_info.h",
@@ -113,9 +113,9 @@
     "access_token_fetcher_unittest.cc",
     "access_token_restriction_unittest.cc",
     "account_capabilities_unittest.cc",
-    "account_capability_fetcher_unittest.cc",
     "account_info_unittest.cc",
     "account_managed_status_finder_unittest.cc",
+    "account_state_fetcher_unittest.cc",
     "accounts_cookie_mutator_unittest.cc",
     "accounts_in_cookie_jar_info_unittest.cc",
     "accounts_mutator_unittest.cc",
diff --git a/components/signin/public/identity_manager/account_capability_fetcher.cc b/components/signin/public/identity_manager/account_capability_fetcher.cc
deleted file mode 100644
index b725301..0000000
--- a/components/signin/public/identity_manager/account_capability_fetcher.cc
+++ /dev/null
@@ -1,101 +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 "components/signin/public/identity_manager/account_capability_fetcher.h"
-
-#include "base/functional/bind.h"
-#include "base/functional/callback.h"
-#include "base/scoped_observation.h"
-#include "components/signin/public/identity_manager/account_info.h"
-#include "components/signin/public/identity_manager/identity_manager.h"
-#include "components/signin/public/identity_manager/tribool.h"
-
-namespace {
-base::TimeDelta g_account_capability_fetch_delay = base::Seconds(3);
-}  // namespace
-
-AccountCapabilityFetcher::AccountCapabilityFetcher(
-    signin::IdentityManager* identity_manager,
-    CoreAccountInfo core_account_info,
-    base::RepeatingCallback<signin::Tribool(const AccountInfo&)>
-        get_capability_state_callback,
-    base::OnceCallback<void(signin::Tribool)> on_capability_fetched_callback)
-    : identity_manager_(identity_manager),
-      core_account_info_(core_account_info),
-      get_capability_state_callback_(std::move(get_capability_state_callback)),
-      on_capability_fetched_callback_(
-          std::move(on_capability_fetched_callback)) {
-  CHECK(identity_manager_);
-  CHECK(on_capability_fetched_callback_);
-  CHECK(get_capability_state_callback_);
-}
-
-AccountCapabilityFetcher::~AccountCapabilityFetcher() = default;
-
-void AccountCapabilityFetcher::FetchCapability() {
-  // Start a timeout for the capability fetching.
-  capability_available_timeout_timer_.Start(
-      FROM_HERE, g_account_capability_fetch_delay,
-      base::BindOnce(&AccountCapabilityFetcher::OnCapabilityFetchedTimeout,
-                     // Unretained is fine as this class owns the timer.
-                     base::Unretained(this)));
-  // Wait for the capability to arrive.
-  GetOrWaitForCapability(core_account_info_);
-}
-
-void AccountCapabilityFetcher::EnforceTimeoutReachedForTesting() {
-  capability_available_timeout_timer_.FireNow();
-}
-
-void AccountCapabilityFetcher::OnExtendedAccountInfoUpdated(
-    const AccountInfo& account_info) {
-  if (account_info.account_id != core_account_info_.account_id) {
-    return;
-  }
-  GetOrWaitForCapability(account_info);
-}
-
-void AccountCapabilityFetcher::OnIdentityManagerShutdown(
-    signin::IdentityManager* identity_manager) {
-  CHECK(identity_manager == identity_manager_.get());
-  account_info_update_observation_.Reset();
-  identity_manager_ = nullptr;
-}
-
-void AccountCapabilityFetcher::GetOrWaitForCapability(
-    const CoreAccountInfo& core_account_info) {
-  CHECK(core_account_info.account_id == core_account_info_.account_id);
-  AccountInfo extended_account_info =
-      identity_manager_->FindExtendedAccountInfo(core_account_info);
-  signin::Tribool capability_value =
-      get_capability_state_callback_.Run(extended_account_info);
-
-  if (capability_value == signin::Tribool::kUnknown) {
-    if (!account_info_update_observation_.IsObserving()) {
-      account_info_update_observation_.Observe(identity_manager_);
-    }
-    return;
-  }
-  CHECK(capability_value != signin::Tribool::kUnknown);
-  account_info_update_observation_.Reset();
-  OnCapabilityFetched(capability_value);
-}
-
-void AccountCapabilityFetcher::OnCapabilityFetched(
-    signin::Tribool account_capability_value) {
-  // TODO(434964019): Confirm whether the capability is expected to remain
-  // unchanged, or whether we should observe and handle updates of the
-  // capability.
-  // Cancel the timeout callback.
-  capability_available_timeout_timer_.Stop();
-
-  CHECK(!on_capability_fetched_callback_.is_null());
-  std::move(on_capability_fetched_callback_).Run(account_capability_value);
-}
-
-void AccountCapabilityFetcher::OnCapabilityFetchedTimeout() {
-  account_info_update_observation_.Reset();
-  OnCapabilityFetched(signin::Tribool::kUnknown);
-  // TODO(anthie): Maybe record metrics for this case.
-}
diff --git a/components/signin/public/identity_manager/account_capability_fetcher.h b/components/signin/public/identity_manager/account_capability_fetcher.h
deleted file mode 100644
index 0c33f3c..0000000
--- a/components/signin/public/identity_manager/account_capability_fetcher.h
+++ /dev/null
@@ -1,65 +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_SIGNIN_PUBLIC_IDENTITY_MANAGER_ACCOUNT_CAPABILITY_FETCHER_H_
-#define COMPONENTS_SIGNIN_PUBLIC_IDENTITY_MANAGER_ACCOUNT_CAPABILITY_FETCHER_H_
-
-#include "base/functional/callback_forward.h"
-#include "base/scoped_observation.h"
-#include "base/timer/timer.h"
-#include "components/signin/public/identity_manager/account_info.h"
-#include "components/signin/public/identity_manager/identity_manager.h"
-#include "components/signin/public/identity_manager/tribool.h"
-
-// Waits until a capability is fetched.
-// The capability state is computed through the input callback
-// `get_capability_state_callback_`.
-// When the capability is fetched or we timeout while waiting for it,
-// it executes the provided callback `on_capability_fetched_callback`
-// and stops observing for further updates.
-// Expected to be used for a single fetch only.
-class AccountCapabilityFetcher : public signin::IdentityManager::Observer {
- public:
-  AccountCapabilityFetcher(
-      signin::IdentityManager* identity_manager,
-      CoreAccountInfo core_account_info,
-      base::RepeatingCallback<signin::Tribool(const AccountInfo&)>
-          get_capability_state_callback,
-      base::OnceCallback<void(signin::Tribool)> on_capability_fetched_callback);
-
-  AccountCapabilityFetcher();
-  ~AccountCapabilityFetcher() override;
-
-  // Starts fetching the capability. Returns the result through
-  // `on_capability_fetched_callback_` when ready and may
-  // return right away if already available. Should be called once.
-  void FetchCapability();
-
-  void EnforceTimeoutReachedForTesting();
-
- private:
-  // signin::IdentityManager::Observer:
-  void OnExtendedAccountInfoUpdated(const AccountInfo& account_info) override;
-  void OnIdentityManagerShutdown(
-      signin::IdentityManager* identity_manager) override;
-
-  void GetOrWaitForCapability(const CoreAccountInfo& core_account_info);
-
-  void OnCapabilityFetched(signin::Tribool account_capability_value);
-
-  void OnCapabilityFetchedTimeout();
-
-  base::ScopedObservation<signin::IdentityManager,
-                          signin::IdentityManager::Observer>
-      account_info_update_observation_{this};
-
-  raw_ptr<signin::IdentityManager> identity_manager_;
-  CoreAccountInfo core_account_info_;
-  base::RepeatingCallback<signin::Tribool(const AccountInfo&)>
-      get_capability_state_callback_;
-  base::OnceCallback<void(signin::Tribool)> on_capability_fetched_callback_;
-  base::OneShotTimer capability_available_timeout_timer_;
-};
-
-#endif  // COMPONENTS_SIGNIN_PUBLIC_IDENTITY_MANAGER_ACCOUNT_CAPABILITY_FETCHER_H_
diff --git a/components/signin/public/identity_manager/account_capability_fetcher_unittest.cc b/components/signin/public/identity_manager/account_capability_fetcher_unittest.cc
deleted file mode 100644
index a1ad60c39..0000000
--- a/components/signin/public/identity_manager/account_capability_fetcher_unittest.cc
+++ /dev/null
@@ -1,131 +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 "components/signin/public/identity_manager/account_capability_fetcher.h"
-
-#include <memory>
-
-#include "base/functional/bind.h"
-#include "base/test/bind.h"
-#include "base/test/task_environment.h"
-#include "base/test/test_future.h"
-#include "components/signin/public/identity_manager/identity_test_environment.h"
-#include "components/signin/public/identity_manager/tribool.h"
-
-namespace {
-constexpr char kTestEmail[] = "test@example.com";
-}  // namespace
-
-class AccountCapabilityFetcherTest : public testing::Test {
- public:
-  AccountCapabilityFetcherTest() = default;
-
-  void SetUp() override {
-    test_account_ = identity_test_env_.MakeAccountAvailable(kTestEmail);
-  }
-
-  // Helper to set the value that `get_capability_state_callback_` will return.
-  void set_capability_state(signin::Tribool state) {
-    capability_state_ = state;
-    // Update a test account field, so that subsequent calls to
-    // UpdateAccountInfoForAccount will trigger the extended info account
-    // update. In production the extended account info updating would be triggered
-    // by the capability update, however the capability value is mocked on this
-    // test suite.
-    test_account_.full_name = std::string("name") + TriboolToString(state);
-  }
-
-  // The callback passed to the fetcher to get the capability state.
-  base::RepeatingCallback<signin::Tribool(const AccountInfo&)>
-  get_capability_state_callback() {
-    return base::BindRepeating(
-        [](signin::Tribool* state, const AccountInfo&) { return *state; },
-        &capability_state_);
-  }
-
- protected:
-  base::test::SingleThreadTaskEnvironment task_environment_{
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
-  signin::IdentityTestEnvironment identity_test_env_;
-  AccountInfo test_account_;
-
-  // The current state of the capability.
-  signin::Tribool capability_state_ = signin::Tribool::kUnknown;
-};
-
-// Tests that the callback is executed immediately if the capability is already
-// known.
-TEST_F(AccountCapabilityFetcherTest, RunsCallbackWhenCapabilityAlreadyKnown) {
-  set_capability_state(signin::Tribool::kTrue);
-  base::test::TestFuture<signin::Tribool> capability_fetched_callback;
-
-  AccountCapabilityFetcher fetcher(identity_test_env_.identity_manager(),
-                                   test_account_,
-                                   get_capability_state_callback(),
-                                   capability_fetched_callback.GetCallback());
-  fetcher.FetchCapability();
-  EXPECT_TRUE(capability_fetched_callback.Wait());
-  EXPECT_EQ(signin::Tribool::kTrue,
-            capability_fetched_callback.Get<signin::Tribool>());
-}
-
-// Tests that the fetcher waits for an account update.
-TEST_F(AccountCapabilityFetcherTest,
-       RunsCallbackWhenCapabilityBecomesAvailable) {
-  base::test::TestFuture<signin::Tribool> capability_fetched_callback;
-  AccountCapabilityFetcher fetcher(identity_test_env_.identity_manager(),
-                                   test_account_,
-                                   get_capability_state_callback(),
-                                   capability_fetched_callback.GetCallback());
-  // Start the fetching. No callback is executed because the
-  // capability's value is unknown.
-  fetcher.FetchCapability();
-
-  // Setting the account capability triggers the callback.
-  set_capability_state(signin::Tribool::kTrue);
-  identity_test_env_.UpdateAccountInfoForAccount(test_account_);
-  EXPECT_TRUE(capability_fetched_callback.Wait());
-  EXPECT_EQ(signin::Tribool::kTrue,
-            capability_fetched_callback.Get<signin::Tribool>());
-}
-
-// Tests that the fetcher correctly handles a timeout.
-TEST_F(AccountCapabilityFetcherTest, RunsCallbackOnTimeout) {
-  base::test::TestFuture<signin::Tribool> capability_fetched_callback;
-  AccountCapabilityFetcher fetcher(identity_test_env_.identity_manager(),
-                                   test_account_,
-                                   get_capability_state_callback(),
-                                   capability_fetched_callback.GetCallback());
-  // Start the fetching. No callback is executed because the
-  // capability's value is unknown.
-  fetcher.FetchCapability();
-
-  // Expect the callback to be called after the timeout.
-  task_environment_.FastForwardBy(base::Seconds(5));
-  EXPECT_TRUE(capability_fetched_callback.Wait());
-  EXPECT_EQ(signin::Tribool::kUnknown,
-            capability_fetched_callback.Get<signin::Tribool>());
-}
-
-TEST_F(AccountCapabilityFetcherTest, IgnoresUpdateForOtherAccount) {
-  bool is_cb_executed = false;
-  base::OnceCallback<void(signin::Tribool)> callback =
-      base::BindLambdaForTesting(
-          [&](signin::Tribool) { is_cb_executed = true; });
-  std::unique_ptr<AccountCapabilityFetcher> fetcher(
-      std::make_unique<AccountCapabilityFetcher>(
-          identity_test_env_.identity_manager(), test_account_,
-          get_capability_state_callback(), std::move(callback)));
-
-  fetcher->FetchCapability();
-
-  set_capability_state(signin::Tribool::kTrue);
-  // Simulate an update for an unrelated account.
-  AccountInfo other_account =
-      identity_test_env_.MakeAccountAvailable("other@example.com");
-  identity_test_env_.UpdateAccountInfoForAccount(other_account);
-
-  // The callback has not been executed.
-  EXPECT_FALSE(is_cb_executed);
-}
diff --git a/components/signin/public/identity_manager/account_state_fetcher.cc b/components/signin/public/identity_manager/account_state_fetcher.cc
new file mode 100644
index 0000000..4f3c6a43
--- /dev/null
+++ b/components/signin/public/identity_manager/account_state_fetcher.cc
@@ -0,0 +1,102 @@
+// 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 "components/signin/public/identity_manager/account_state_fetcher.h"
+
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
+#include "base/scoped_observation.h"
+#include "components/signin/public/identity_manager/account_info.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
+#include "components/signin/public/identity_manager/tribool.h"
+
+namespace {
+base::TimeDelta g_account_info_fetch_delay = base::Seconds(3);
+}  // namespace
+
+AccountStateFetcher::AccountStateFetcher(
+    signin::IdentityManager* identity_manager,
+    CoreAccountInfo core_account_info,
+    base::RepeatingCallback<signin::Tribool(const AccountInfo&)>
+        get_account_state_callback,
+    base::OnceCallback<void(signin::Tribool)>
+        on_account_info_fetched_callback)
+    : identity_manager_(identity_manager),
+      core_account_info_(core_account_info),
+      get_account_state_callback_(std::move(get_account_state_callback)),
+      on_account_info_fetched_callback_(
+          std::move(on_account_info_fetched_callback)) {
+  CHECK(identity_manager_);
+  CHECK(on_account_info_fetched_callback_);
+  CHECK(get_account_state_callback_);
+}
+
+AccountStateFetcher::~AccountStateFetcher() = default;
+
+void AccountStateFetcher::FetchAccountInfo() {
+  // Start a timeout for the account info fetching.
+  account_info_timeout_timer_.Start(
+      FROM_HERE, g_account_info_fetch_delay,
+      base::BindOnce(&AccountStateFetcher::OnAccountInfoFetchTimeout,
+                     // Unretained is fine as this class owns the timer.
+                     base::Unretained(this)));
+  // Wait for the account info to arrive.
+  GetOrWaitForAccountInfo(core_account_info_);
+}
+
+void AccountStateFetcher::EnforceTimeoutReachedForTesting() {
+  account_info_timeout_timer_.FireNow();
+}
+
+void AccountStateFetcher::OnExtendedAccountInfoUpdated(
+    const AccountInfo& account_info) {
+  if (account_info.account_id != core_account_info_.account_id) {
+    return;
+  }
+  GetOrWaitForAccountInfo(account_info);
+}
+
+void AccountStateFetcher::OnIdentityManagerShutdown(
+    signin::IdentityManager* identity_manager) {
+  CHECK(identity_manager == identity_manager_.get());
+  account_info_update_observation_.Reset();
+  identity_manager_ = nullptr;
+}
+
+void AccountStateFetcher::GetOrWaitForAccountInfo(
+    const CoreAccountInfo& core_account_info) {
+  CHECK(core_account_info.account_id == core_account_info_.account_id);
+  AccountInfo extended_account_info =
+      identity_manager_->FindExtendedAccountInfo(core_account_info);
+  signin::Tribool account_info_value =
+      get_account_state_callback_.Run(extended_account_info);
+
+  if (account_info_value == signin::Tribool::kUnknown) {
+    if (!account_info_update_observation_.IsObserving()) {
+      account_info_update_observation_.Observe(identity_manager_);
+    }
+    return;
+  }
+  CHECK(account_info_value != signin::Tribool::kUnknown);
+  account_info_update_observation_.Reset();
+  OnAccountInfoFetched(account_info_value);
+}
+
+void AccountStateFetcher::OnAccountInfoFetched(
+    signin::Tribool account_info_value) {
+  // TODO(434964019): Confirm whether the account info is expected to remain
+  // unchanged, or whether we should observe and handle updates of the
+  // account info.
+  // Cancel the timeout callback.
+  account_info_timeout_timer_.Stop();
+
+  CHECK(!on_account_info_fetched_callback_.is_null());
+  std::move(on_account_info_fetched_callback_).Run(account_info_value);
+}
+
+void AccountStateFetcher::OnAccountInfoFetchTimeout() {
+  account_info_update_observation_.Reset();
+  OnAccountInfoFetched(signin::Tribool::kUnknown);
+  // TODO(anthie): Maybe record metrics for this case.
+}
diff --git a/components/signin/public/identity_manager/account_state_fetcher.h b/components/signin/public/identity_manager/account_state_fetcher.h
new file mode 100644
index 0000000..7ab33aa9
--- /dev/null
+++ b/components/signin/public/identity_manager/account_state_fetcher.h
@@ -0,0 +1,66 @@
+// 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_SIGNIN_PUBLIC_IDENTITY_MANAGER_ACCOUNT_STATE_FETCHER_H_
+#define COMPONENTS_SIGNIN_PUBLIC_IDENTITY_MANAGER_ACCOUNT_STATE_FETCHER_H_
+
+#include "base/functional/callback_forward.h"
+#include "base/scoped_observation.h"
+#include "base/timer/timer.h"
+#include "components/signin/public/identity_manager/account_info.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
+#include "components/signin/public/identity_manager/tribool.h"
+
+// Waits until some account info is fetched.
+// The account state is computed through the input callback
+// `get_account_state_callback_`.
+// When the account info is fetched or we timeout while waiting for it,
+// it executes the provided callback `on_account_info_fetched_callback_`
+// and stops observing for further updates.
+// Expected to be used for a single fetch only.
+class AccountStateFetcher : public signin::IdentityManager::Observer {
+ public:
+  AccountStateFetcher(
+      signin::IdentityManager* identity_manager,
+      CoreAccountInfo core_account_info,
+      base::RepeatingCallback<signin::Tribool(const AccountInfo&)>
+          get_account_state_callback,
+      base::OnceCallback<void(signin::Tribool)>
+          on_account_info_fetched_callback);
+
+  AccountStateFetcher();
+  ~AccountStateFetcher() override;
+
+  // Starts fetching the account info. Returns the result through
+  // `on_account_info_fetched_callback_` when ready and may
+  // return right away if already available. Should be called once.
+  void FetchAccountInfo();
+
+  void EnforceTimeoutReachedForTesting();
+
+ private:
+  // signin::IdentityManager::Observer:
+  void OnExtendedAccountInfoUpdated(const AccountInfo& account_info) override;
+  void OnIdentityManagerShutdown(
+      signin::IdentityManager* identity_manager) override;
+
+  void GetOrWaitForAccountInfo(const CoreAccountInfo& core_account_info);
+
+  void OnAccountInfoFetched(signin::Tribool account_info_value);
+
+  void OnAccountInfoFetchTimeout();
+
+  base::ScopedObservation<signin::IdentityManager,
+                          signin::IdentityManager::Observer>
+      account_info_update_observation_{this};
+
+  raw_ptr<signin::IdentityManager> identity_manager_;
+  CoreAccountInfo core_account_info_;
+  base::RepeatingCallback<signin::Tribool(const AccountInfo&)>
+      get_account_state_callback_;
+  base::OnceCallback<void(signin::Tribool)> on_account_info_fetched_callback_;
+  base::OneShotTimer account_info_timeout_timer_;
+};
+
+#endif  // COMPONENTS_SIGNIN_PUBLIC_IDENTITY_MANAGER_ACCOUNT_STATE_FETCHER_H_
diff --git a/components/signin/public/identity_manager/account_state_fetcher_unittest.cc b/components/signin/public/identity_manager/account_state_fetcher_unittest.cc
new file mode 100644
index 0000000..8dce9e7
--- /dev/null
+++ b/components/signin/public/identity_manager/account_state_fetcher_unittest.cc
@@ -0,0 +1,125 @@
+// 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 "components/signin/public/identity_manager/account_state_fetcher.h"
+
+#include <memory>
+
+#include "base/functional/bind.h"
+#include "base/test/bind.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_future.h"
+#include "components/signin/public/identity_manager/identity_test_environment.h"
+#include "components/signin/public/identity_manager/tribool.h"
+
+namespace {
+constexpr char kTestEmail[] = "test@example.com";
+}  // namespace
+
+class AccountStateFetcherTest : public testing::Test {
+ public:
+  AccountStateFetcherTest() = default;
+
+  void SetUp() override {
+    test_account_ = identity_test_env_.MakeAccountAvailable(kTestEmail);
+  }
+
+  // Helper to set the value that `get_account_state_callback` will return.
+  void set_account_info_state(signin::Tribool state) {
+    account_info_state_ = state;
+    // Update a test account field, so that subsequent calls to
+    // UpdateAccountInfoForAccount will trigger the extended info account
+    // update.
+    test_account_.full_name = std::string("name") + TriboolToString(state);
+  }
+
+  // The callback passed to the fetcher to get the account info state.
+  base::RepeatingCallback<signin::Tribool(const AccountInfo&)>
+  get_account_state_callback() {
+    return base::BindRepeating(
+        [](signin::Tribool* state, const AccountInfo&) { return *state; },
+        &account_info_state_);
+  }
+
+ protected:
+  base::test::SingleThreadTaskEnvironment task_environment_{
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+  signin::IdentityTestEnvironment identity_test_env_;
+  AccountInfo test_account_;
+
+  // The current state of the account info we are awaiting for.
+  signin::Tribool account_info_state_ = signin::Tribool::kUnknown;
+};
+
+// Tests that the callback is executed immediately if the account info is already
+// known.
+TEST_F(AccountStateFetcherTest, RunsCallbackWhenAccountInfoAlreadyKnown) {
+  set_account_info_state(signin::Tribool::kTrue);
+  base::test::TestFuture<signin::Tribool> info_fetched_callback;
+
+  AccountStateFetcher fetcher(identity_test_env_.identity_manager(),
+                             test_account_, get_account_state_callback(),
+                             info_fetched_callback.GetCallback());
+  fetcher.FetchAccountInfo();
+  EXPECT_TRUE(info_fetched_callback.Wait());
+  EXPECT_EQ(signin::Tribool::kTrue,
+            info_fetched_callback.Get<signin::Tribool>());
+}
+
+// Tests that the fetcher waits for an account info update.
+TEST_F(AccountStateFetcherTest, RunsCallbackWhenAccountInfoBecomesAvailable) {
+  base::test::TestFuture<signin::Tribool> info_fetched_callback;
+  AccountStateFetcher fetcher(identity_test_env_.identity_manager(),
+                             test_account_, get_account_state_callback(),
+                             info_fetched_callback.GetCallback());
+  // Start the fetching. No callback is executed because the
+  // account info's value is unknown.
+  fetcher.FetchAccountInfo();
+
+  // Setting the account info triggers the callback.
+  set_account_info_state(signin::Tribool::kTrue);
+  identity_test_env_.UpdateAccountInfoForAccount(test_account_);
+  EXPECT_TRUE(info_fetched_callback.Wait());
+  EXPECT_EQ(signin::Tribool::kTrue,
+            info_fetched_callback.Get<signin::Tribool>());
+}
+
+// Tests that the fetcher correctly handles a timeout.
+TEST_F(AccountStateFetcherTest, RunsCallbackOnTimeout) {
+  base::test::TestFuture<signin::Tribool> info_fetched_callback;
+  AccountStateFetcher fetcher(identity_test_env_.identity_manager(),
+                             test_account_, get_account_state_callback(),
+                             info_fetched_callback.GetCallback());
+  // Start the fetching. No callback is executed because the
+  // account info's value is unknown.
+  fetcher.FetchAccountInfo();
+
+  // Expect the callback to be called after the timeout.
+  task_environment_.FastForwardBy(base::Seconds(5));
+  EXPECT_TRUE(info_fetched_callback.Wait());
+  EXPECT_EQ(signin::Tribool::kUnknown,
+            info_fetched_callback.Get<signin::Tribool>());
+}
+
+TEST_F(AccountStateFetcherTest, IgnoresUpdateForOtherAccount) {
+  bool is_cb_executed = false;
+  base::OnceCallback<void(signin::Tribool)> callback =
+      base::BindLambdaForTesting(
+          [&](signin::Tribool) { is_cb_executed = true; });
+  std::unique_ptr<AccountStateFetcher> fetcher(
+      std::make_unique<AccountStateFetcher>(
+          identity_test_env_.identity_manager(), test_account_,
+          get_account_state_callback(), std::move(callback)));
+
+  fetcher->FetchAccountInfo();
+
+  set_account_info_state(signin::Tribool::kTrue);
+  // Simulate an update for an unrelated account.
+  AccountInfo other_account =
+      identity_test_env_.MakeAccountAvailable("other@example.com");
+  identity_test_env_.UpdateAccountInfoForAccount(other_account);
+
+  // The callback has not been executed.
+  EXPECT_FALSE(is_cb_executed);
+}
diff --git a/components/signin/public/identity_manager/identity_test_environment.cc b/components/signin/public/identity_manager/identity_test_environment.cc
index a39b81355..a5d458c 100644
--- a/components/signin/public/identity_manager/identity_test_environment.cc
+++ b/components/signin/public/identity_manager/identity_test_environment.cc
@@ -362,8 +362,6 @@
       std::move(gaia_cookie_manager_service);
   init_params.primary_account_manager = std::move(primary_account_manager);
   init_params.token_service = std::move(token_service);
-  // TODO: Set the account_manager_facade on Lacros once Mirror is enabled by
-  // default.
 #if BUILDFLAG(IS_CHROMEOS)
   init_params.account_manager_facade = account_manager_facade;
 #endif
diff --git a/components/sync/base/features.cc b/components/sync/base/features.cc
index 9276a38..0a65a59 100644
--- a/components/sync/base/features.cc
+++ b/components/sync/base/features.cc
@@ -88,6 +88,14 @@
 #endif  // BUILDFLAG(IS_CHROMEOS)
 );
 
+BASE_FEATURE(kSyncWalletFlightReservations,
+             "SyncWalletFlightReservations",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
+BASE_FEATURE(kSyncWalletVehicleRegistrations,
+             "SyncWalletVehicleRegistrations",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 BASE_FEATURE(kEnableBookmarksSelectedTypeOnSigninForTesting,
              "EnableBookmarksSelectedTypeOnSigninForTesting",
              base::FEATURE_DISABLED_BY_DEFAULT);
@@ -158,16 +166,6 @@
              base::FEATURE_DISABLED_BY_DEFAULT);
 #endif  // BUILDFLAG(IS_IOS)
 
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-BASE_FEATURE(kSyncWalletFlightReservations,
-             "SyncWalletFlightReservations",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
-BASE_FEATURE(kSyncWalletVehicleRegistrations,
-             "SyncWalletVehicleRegistrations",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-
 BASE_FEATURE(kSyncDetermineAccountManagedStatus,
              "SyncDetermineAccountManagedStatus",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/components/sync/base/features.h b/components/sync/base/features.h
index a3c0cfdc..13792b9e 100644
--- a/components/sync/base/features.h
+++ b/components/sync/base/features.h
@@ -69,6 +69,12 @@
 // kEnablePreferencesAccountStorage is enabled.
 BASE_DECLARE_FEATURE(kSyncSupportAlwaysSyncingPriorityPreferences);
 
+// Enables syncing of flight reservations coming from Google Wallet.
+BASE_DECLARE_FEATURE(kSyncWalletFlightReservations);
+
+// Enables syncing of vehicle registrations coming from Google Wallet.
+BASE_DECLARE_FEATURE(kSyncWalletVehicleRegistrations);
+
 // Normally, if kReplaceSyncPromosWithSignInPromos is disabled,
 // UserSelectableType::kBookmarks is disabled by default upon sign-in. This
 // flag makes the type enabled by default, for manual testing.
@@ -165,13 +171,6 @@
 BASE_DECLARE_FEATURE(kSyncTrustedVaultInfobarMessageImprovements);
 #endif  // BUILDFLAG(IS_IOS)
 
-#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-// Enables syncing of flight reservations coming from Google Wallet.
-BASE_DECLARE_FEATURE(kSyncWalletFlightReservations);
-// Enables syncing of vehicle registrations coming from Google Wallet.
-BASE_DECLARE_FEATURE(kSyncWalletVehicleRegistrations);
-#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-
 BASE_DECLARE_FEATURE(kSyncDetermineAccountManagedStatus);
 BASE_DECLARE_FEATURE_PARAM(base::TimeDelta,
                            kSyncDetermineAccountManagedStatusTimeout);
diff --git a/components/viz/common/gpu/context_cache_controller.cc b/components/viz/common/gpu/context_cache_controller.cc
index 09e0687e..01d8c04 100644
--- a/components/viz/common/gpu/context_cache_controller.cc
+++ b/components/viz/common/gpu/context_cache_controller.cc
@@ -13,12 +13,10 @@
 #include "base/task/sequenced_task_runner.h"
 #include "base/time/time.h"
 #include "gpu/command_buffer/client/context_support.h"
-#include "third_party/skia/include/gpu/ganesh/GrDirectContext.h"
 
 namespace viz {
 namespace {
 static const int kIdleCleanupDelaySeconds = 1;
-static const int kOldResourceCleanupDelaySeconds = 15;
 }  // namespace
 
 ContextCacheController::ScopedToken::ScopedToken() = default;
@@ -49,10 +47,6 @@
     ClientBecameNotVisible(std::move(held_visibility_));
 }
 
-void ContextCacheController::SetGrContext(GrDirectContext* gr_context) {
-  gr_context_ = gr_context;
-}
-
 void ContextCacheController::SetLock(base::Lock* lock) {
   context_lock_ = lock;
 }
@@ -98,8 +92,6 @@
     // We are freeing resources now - cancel any pending idle callbacks.
     InvalidatePendingIdleCallbacks();
 
-    if (gr_context_)
-      gr_context_->freeGpuResources();
     context_support_->SetAggressivelyFreeResources(true);
     context_support_->FlushPendingWork();
   }
@@ -138,13 +130,6 @@
   DCHECK_GT(num_clients_busy_, 0u);
   --num_clients_busy_;
 
-  // Here we ask GrContext to free any resources that haven't been used in
-  // a long while even if it is under budget.
-  if (gr_context_) {
-    gr_context_->performDeferredCleanup(
-        std::chrono::seconds(kOldResourceCleanupDelaySeconds));
-  }
-
   // If we have become idle and we are visible, queue a task to drop resources
   // after a delay. If are not visible, we have already dropped resources.
   if (num_clients_busy_ == 0 && num_clients_visible_ > 0 && task_runner_) {
@@ -205,9 +190,6 @@
     return;
   }
 
-  if (gr_context_)
-    gr_context_->freeGpuResources();
-
   // Toggle SetAggressivelyFreeResources to drop command buffer data.
   context_support_->SetAggressivelyFreeResources(true);
   context_support_->FlushPendingWork();
diff --git a/components/viz/common/gpu/context_cache_controller.h b/components/viz/common/gpu/context_cache_controller.h
index 7375def0..e0d3880 100644
--- a/components/viz/common/gpu/context_cache_controller.h
+++ b/components/viz/common/gpu/context_cache_controller.h
@@ -16,8 +16,6 @@
 #include "base/task/single_thread_task_runner.h"
 #include "components/viz/common/viz_common_export.h"
 
-class GrDirectContext;
-
 namespace base {
 class Lock;
 }
@@ -54,7 +52,6 @@
                          scoped_refptr<base::SequencedTaskRunner> task_runner);
   virtual ~ContextCacheController();
 
-  void SetGrContext(GrDirectContext* gr_context);
   void SetLock(base::Lock* lock);
 
   // Clients of the owning ContextProvider should call this function when they
@@ -94,7 +91,6 @@
 
   raw_ptr<gpu::ContextSupport> context_support_;
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
-  raw_ptr<GrDirectContext> gr_context_ = nullptr;
 
   std::unique_ptr<ScopedVisibility> held_visibility_;
 
diff --git a/components/viz/common/gpu/context_cache_controller_unittest.cc b/components/viz/common/gpu/context_cache_controller_unittest.cc
index af24b64..9e5ce67 100644
--- a/components/viz/common/gpu/context_cache_controller_unittest.cc
+++ b/components/viz/common/gpu/context_cache_controller_unittest.cc
@@ -157,54 +157,5 @@
   cache_controller.ClientBecameNotVisible(std::move(visible));
 }
 
-// Confirms that the Skia performDeferredCleanup API used by the cache
-// controller behaves as expected.
-TEST(ContextCacheControllerTest, CheckSkiaResourcePurgeAPI) {
-  StrictMock<MockContextSupport> context_support;
-  auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
-
-  // Must outlive `cache_controller`.
-  auto context_provider = TestContextProvider::Create();
-  context_provider->BindToCurrentSequence();
-
-  ContextCacheController cache_controller(&context_support, task_runner);
-  auto* gr_context = context_provider->GrContext();
-  cache_controller.SetGrContext(gr_context);
-
-  // Make us visible.
-  EXPECT_CALL(context_support, SetAggressivelyFreeResources(false));
-  auto visibility = cache_controller.ClientBecameVisible();
-  Mock::VerifyAndClearExpectations(&context_support);
-
-  // Now that we're visible, become busy, create and release a skia resource.
-  auto busy = cache_controller.ClientBecameBusy();
-  {
-    auto image_info = SkImageInfo::MakeN32Premul(200, 200);
-    std::vector<uint8_t> image_data(image_info.computeMinByteSize());
-    SkPixmap pixmap(image_info, image_data.data(), image_info.minRowBytes());
-    auto image = SkImages::RasterFromPixmapCopy(pixmap);
-    auto image_gpu = SkImages::TextureFromImage(gr_context, std::move(image));
-    gr_context->flushAndSubmit();
-  }
-
-  // Ensure we see size taken up for the image (now released, but cached for
-  // re-use).
-  EXPECT_GT(gr_context->getResourceCachePurgeableBytes(), 0u);
-
-  // Make the client idle and wait for the idle callback to trigger.
-  cache_controller.ClientBecameNotBusy(std::move(busy));
-  EXPECT_CALL(context_support, SetAggressivelyFreeResources(true));
-  EXPECT_CALL(context_support, SetAggressivelyFreeResources(false));
-  task_runner->FastForwardBy(base::Seconds(5));
-  Mock::VerifyAndClearExpectations(&context_support);
-
-  // The Skia resource cache should now be empty.
-  EXPECT_EQ(gr_context->getResourceCachePurgeableBytes(), 0u);
-
-  // Set not-visible.
-  EXPECT_CALL(context_support, SetAggressivelyFreeResources(true));
-  cache_controller.ClientBecameNotVisible(std::move(visibility));
-}
-
 }  // namespace
 }  // namespace viz
diff --git a/components/viz/test/test_context_provider.cc b/components/viz/test/test_context_provider.cc
index b30cd85..dcb53697 100644
--- a/components/viz/test/test_context_provider.cc
+++ b/components/viz/test/test_context_provider.cc
@@ -349,7 +349,6 @@
   gr_context_ = std::make_unique<skia_bindings::GrContextForGLES2Interface>(
       context_gl_.get(), support_.get(), context_gl_->test_capabilities(),
       max_resource_cache_bytes, max_glyph_cache_texture_bytes, true);
-  cache_controller_->SetGrContext(gr_context_->get());
 
   // If GlContext is already lost, also abandon the new GrContext.
   if (ContextGL()->GetGraphicsResetStatusKHR() != GL_NO_ERROR)
diff --git a/components/viz/test/test_in_process_context_provider.cc b/components/viz/test/test_in_process_context_provider.cc
index 37fac54..d7f357a5 100644
--- a/components/viz/test/test_in_process_context_provider.cc
+++ b/components/viz/test/test_in_process_context_provider.cc
@@ -108,24 +108,7 @@
 }
 
 class GrDirectContext* TestInProcessContextProvider::GrContext() {
-  CheckValidThreadOrLockAcquired();
-  if (gr_context_) {
-    return gr_context_->get();
-  }
-
-  if (!gles2_context_) {
-    return nullptr;
-  }
-
-  size_t max_resource_cache_bytes;
-  size_t max_glyph_cache_texture_bytes;
-  gpu::DefaultGrCacheLimitsForTests(&max_resource_cache_bytes,
-                                    &max_glyph_cache_texture_bytes);
-  gr_context_ = std::make_unique<skia_bindings::GrContextForGLES2Interface>(
-      ContextGL(), ContextSupport(), ContextCapabilities(),
-      max_resource_cache_bytes, max_glyph_cache_texture_bytes);
-  cache_controller_->SetGrContext(gr_context_->get());
-  return gr_context_->get();
+  return nullptr;
 }
 
 gpu::SharedImageInterface*
diff --git a/components/viz/test/test_in_process_context_provider.h b/components/viz/test/test_in_process_context_provider.h
index dfadd346..aac1d12 100644
--- a/components/viz/test/test_in_process_context_provider.h
+++ b/components/viz/test/test_in_process_context_provider.h
@@ -30,10 +30,6 @@
 }
 }  // namespace gpu
 
-namespace skia_bindings {
-class GrContextForGLES2Interface;
-}
-
 namespace viz {
 class GpuServiceImpl;
 
@@ -96,7 +92,6 @@
 
   // Used for GLES2 contexts only.
   std::unique_ptr<gpu::GLInProcessContext> gles2_context_;
-  std::unique_ptr<skia_bindings::GrContextForGLES2Interface> gr_context_;
 
   // Used for raster contexts only.
   std::unique_ptr<gpu::RasterInProcessContext> raster_context_;
diff --git a/content/browser/client_hints/client_hints.cc b/content/browser/client_hints/client_hints.cc
index 93c2917..bf15a0ce 100644
--- a/content/browser/client_hints/client_hints.cc
+++ b/content/browser/client_hints/client_hints.cc
@@ -44,6 +44,7 @@
 #include "net/nqe/effective_connection_type.h"
 #include "net/nqe/network_quality_estimator_params.h"
 #include "services/network/public/cpp/client_hints.h"
+#include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
 #include "services/network/public/cpp/network_quality_tracker.h"
 #include "services/network/public/cpp/permissions_policy/client_hints_permissions_policy_mapping.h"
@@ -1100,9 +1101,19 @@
   // origin-level or "browser-level" policies like disabling JS or other
   // features.
   for (const auto& [hint, _] : client_hints_map) {
+    // `enabled_client_hints.hints` are client hints that are enabled for the
+    // origin and allowed to be attached to the request.
     if (ShouldAddClientHint(data, hint)) {
       enabled_client_hints.hints.push_back(hint);
     }
+    // `enabled_client_hints.not_allowed_hints` are client hints that are
+    // currently not allowed to be attached to the request.
+    if (base::FeatureList::IsEnabled(
+            network::features::kOffloadAcceptCHFrameCheck) &&
+        network::features::kAcceptCHFrameOffloadNotAllowedHints.Get() &&
+        !IsClientHintAllowed(data, hint)) {
+      enabled_client_hints.not_allowed_hints.push_back(hint);
+    }
   }
   enabled_client_hints.origin = data.main_frame_origin;
   return enabled_client_hints;
diff --git a/content/browser/client_hints/client_hints_unittest.cc b/content/browser/client_hints/client_hints_unittest.cc
index d8f9f70..df87056 100644
--- a/content/browser/client_hints/client_hints_unittest.cc
+++ b/content/browser/client_hints/client_hints_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
 #include "content/public/test/mock_client_hints_controller_delegate.h"
 #include "content/public/test/test_browser_context.h"
@@ -19,6 +20,7 @@
 #include "net/http/http_response_headers.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
 #include "services/network/public/cpp/client_hints.h"
+#include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/is_potentially_trustworthy.h"
 #include "services/network/public/cpp/permissions_policy/permissions_policy_declaration.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
@@ -345,6 +347,7 @@
   // We do not care the order of contents.
   EXPECT_THAT(actual_hints.hints,
               testing::UnorderedElementsAreArray(expected_types));
+  EXPECT_TRUE(actual_hints.not_allowed_hints.empty());
 }
 
 TEST_F(ClientHintsTest, GetEnabledClientHintsSubframe) {
@@ -537,4 +540,47 @@
             CriticalHintsMissingStatus::kPresent);
 }
 
+TEST_F(ClientHintsTest, GetEnabledClientHintsSubframeNotAllowed) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeaturesAndParameters(
+      {{network::features::kOffloadAcceptCHFrameCheck,
+        {{network::features::kAcceptCHFrameOffloadNotAllowedHints.name,
+          "true"}}}},
+      {});
+
+  GURL main_url(kOriginUrl);
+  contents()->NavigateAndCommit(main_url);
+  url::Origin main_origin = url::Origin::Create(main_url);
+
+  FrameTree& frame_tree = contents()->GetPrimaryFrameTree();
+  FrameTreeNode* main_frame_node = frame_tree.root();
+  AddOneChildNode();
+  FrameTreeNode* sub_frame_node = main_frame_node->child_at(0);
+
+  blink::UserAgentMetadata ua_metadata;
+  MockClientHintsControllerDelegate delegate(ua_metadata);
+
+  GURL sub_url("https://sub.example.com");
+  const auto& actual_hints = GetEnabledClientHints(url::Origin::Create(sub_url),
+                                                   sub_frame_node, &delegate);
+
+  std::vector<network::mojom::WebClientHintsType> expected_allowed_hints;
+  std::vector<network::mojom::WebClientHintsType> expected_not_allowed_hints;
+
+  for (const auto& [hint, _] : network::GetClientHintToNameMap()) {
+    if (blink::IsClientHintSentByDefault(hint)) {
+      expected_allowed_hints.push_back(hint);
+    } else {
+      expected_not_allowed_hints.push_back(hint);
+    }
+  }
+
+  EXPECT_EQ(main_origin, actual_hints.origin);
+  EXPECT_FALSE(actual_hints.is_outermost_main_frame);
+  EXPECT_THAT(actual_hints.hints,
+              testing::UnorderedElementsAreArray(expected_allowed_hints));
+  EXPECT_THAT(actual_hints.not_allowed_hints,
+              testing::UnorderedElementsAreArray(expected_not_allowed_hints));
+}
+
 }  // namespace content
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 63deb592..8eaaec01 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -1463,6 +1463,9 @@
         head_update_params_.load_timing_info
             .service_worker_router_evaluation_start;
   }
+  if (head_update_params_.is_synthetic_response_dry_run_mode) {
+    head->from_synthetic_response = true;
+  }
 
   // If the default loader (network) was used to handle the URL load request
   // we need to see if the interceptors want to potentially create a new
diff --git a/content/browser/loader/response_head_update_params.h b/content/browser/loader/response_head_update_params.h
index 08c78bf..7601228f 100644
--- a/content/browser/loader/response_head_update_params.h
+++ b/content/browser/loader/response_head_update_params.h
@@ -25,6 +25,7 @@
   network::mojom::ServiceWorkerRouterInfoPtr router_info;
   std::optional<network::mojom::ServiceWorkerStatus>
       initial_service_worker_status;
+  bool is_synthetic_response_dry_run_mode = false;
 };
 
 }  // namespace content
diff --git a/content/browser/renderer_host/OWNERS b/content/browser/renderer_host/OWNERS
index 177aa74..44812a9 100644
--- a/content/browser/renderer_host/OWNERS
+++ b/content/browser/renderer_host/OWNERS
@@ -55,3 +55,6 @@
 
 # View transitions test.
 per-file view_transition_browsertest.cc=vmpstr@chromium.org
+
+# Local Network Access
+per-file private_network_access*.*=file://content/browser/security/local_network_access/OWNERS
diff --git a/content/browser/renderer_host/back_forward_cache_impl.cc b/content/browser/renderer_host/back_forward_cache_impl.cc
index 6ab2e63..063a6476 100644
--- a/content/browser/renderer_host/back_forward_cache_impl.cc
+++ b/content/browser/renderer_host/back_forward_cache_impl.cc
@@ -20,7 +20,9 @@
 #include "base/functional/bind.h"
 #include "base/memory/weak_ptr.h"
 #include "base/metrics/field_trial_params.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/rand_util.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -758,12 +760,34 @@
           features::kDeviceBoundSessionTerminationEvictBackForwardCache)) {
     result.No(BackForwardCacheMetrics::NotRestoredReason::
                   kCacheControlNoStoreDeviceBoundSessionTerminated);
-  } else if (render_frame_host->GetCookieChangeInfo()
-                 .http_only_cookie_modification_count_ > 0) {
+    return;
+  }
+
+  const RenderFrameHostImpl::CookieChangeListener::CookieChangeInfo&
+      cookie_change_info = render_frame_host->GetCookieChangeInfo();
+  const std::string kCookieCHangeInfoMetricName =
+      "BackForwardCache.CCNS.CookieChangeInfo.";
+  base::UmaHistogramCounts1000(
+      base::StrCat({kCookieCHangeInfoMetricName, "AllCookies"}),
+      cookie_change_info.cookie_modification_count);
+  base::UmaHistogramCounts1000(
+      base::StrCat(
+          {kCookieCHangeInfoMetricName, "AllCookiesFromMainFrameNavigation"}),
+      cookie_change_info.cookie_modification_removing_count);
+  base::UmaHistogramCounts1000(
+      base::StrCat({kCookieCHangeInfoMetricName, "HttpOnlyCookies"}),
+      cookie_change_info.http_only_cookie_modification_count);
+  base::UmaHistogramCounts1000(
+      base::StrCat({kCookieCHangeInfoMetricName,
+                    "HttpOnlyCookiesFromMainFrameNavigation"}),
+      cookie_change_info.http_only_cookie_modification_removing_count);
+
+  if (cookie_change_info.http_only_cookie_modification_count >
+      cookie_change_info.http_only_cookie_modification_removing_count) {
     result.No(BackForwardCacheMetrics::NotRestoredReason::
                   kCacheControlNoStoreHTTPOnlyCookieModified);
-  } else if (render_frame_host->GetCookieChangeInfo()
-                 .cookie_modification_count_ > 0) {
+  } else if (cookie_change_info.cookie_modification_count >
+             cookie_change_info.cookie_modification_removing_count) {
     // JavaScript cookies are modified but not HTTP cookies. Only restore based
     // on the experiment level.
     if (GetCacheControlNoStoreLevel() <=
diff --git a/content/browser/renderer_host/private_network_access_browsertest.cc b/content/browser/renderer_host/private_network_access_browsertest.cc
index 861686f..bcddb971 100644
--- a/content/browser/renderer_host/private_network_access_browsertest.cc
+++ b/content/browser/renderer_host/private_network_access_browsertest.cc
@@ -44,6 +44,10 @@
 #include "url/gurl.h"
 #include "url/origin.h"
 
+// Note: tests in this file are being migrated to work for Local Network Access;
+// please do not add new tests to this file. Instead, tests should be added to
+// content/browser/renderer_host/local_network_access_browsertest.cc
+
 namespace content {
 namespace {
 
@@ -782,39 +786,6 @@
 // These tests verify the contents of `ClientSecurityState` for top-level
 // documents in various different circumstances.
 
-// This test verifies the contents of the ClientSecurityState for the initial
-// empty document in a new main frame created by the browser.
-//
-// Note: the renderer-created main frame case is exercised by the
-// OpeneeInherits* tests below.
-IN_PROC_BROWSER_TEST_F(PrivateNetworkAccessBrowserTest,
-                       ClientSecurityStateForInitialEmptyDoc) {
-  // Start a navigation. This forces the RenderFrameHost to initialize its
-  // RenderFrame. The navigation is then cancelled by a HTTP 204 code.
-  // We're left with a RenderFrameHost containing the default
-  // ClientSecurityState values.
-  //
-  // Serve the response from a secure public server, to confirm that none of
-  // the connection's properties are reflected in the committed document, which
-  // is not a secure context and belongs to the `loopback` address space.
-  EXPECT_TRUE(
-      NavigateToURLAndExpectNoCommit(shell(), SecurePublicURL("/nocontent")));
-
-  const network::mojom::ClientSecurityStatePtr security_state =
-      root_frame_host()->BuildClientSecurityState();
-  ASSERT_FALSE(security_state.is_null());
-  EXPECT_FALSE(security_state->is_web_secure_context);
-  EXPECT_EQ(network::mojom::CrossOriginEmbedderPolicyValue::kNone,
-            security_state->cross_origin_embedder_policy.value);
-  EXPECT_EQ(network::mojom::PrivateNetworkRequestPolicy::kBlock,
-            security_state->private_network_request_policy);
-
-  // Browser-created empty main frames are trusted to access the local network,
-  // if they execute code injected via DevTools, WebView APIs or extensions.
-  EXPECT_EQ(network::mojom::IPAddressSpace::kLoopback,
-            security_state->ip_address_space);
-}
-
 // This test verifies the contents of the ClientSecurityState for `about:blank`
 // in a new main frame created by the browser.
 //
@@ -4236,48 +4207,4 @@
               IsEmpty());
 }
 
-class LocalNetworkAccessBrowserTest
-    : public PrivateNetworkAccessBrowserTestBase {
- public:
-  LocalNetworkAccessBrowserTest()
-      : PrivateNetworkAccessBrowserTestBase(
-            {
-                network::features::kLocalNetworkAccessChecks,
-            },
-            {}) {}
-};
-
-IN_PROC_BROWSER_TEST_F(LocalNetworkAccessBrowserTest, CheckSecurityState) {
-  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
-
-  const network::mojom::ClientSecurityStatePtr security_state =
-      root_frame_host()->BuildClientSecurityState();
-  ASSERT_FALSE(security_state.is_null());
-
-  EXPECT_TRUE(security_state->is_web_secure_context);
-  EXPECT_EQ(network::mojom::IPAddressSpace::kPublic,
-            security_state->ip_address_space);
-
-  EXPECT_EQ(security_state->private_network_request_policy,
-            network::mojom::PrivateNetworkRequestPolicy::kPermissionWarn);
-}
-
-IN_PROC_BROWSER_TEST_F(LocalNetworkAccessBrowserTest, CheckBlockInsteadOfWarn) {
-  PolicyTestContentBrowserClient client;
-  client.SetBlockInsteadOfWarn();
-
-  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
-
-  const network::mojom::ClientSecurityStatePtr security_state =
-      root_frame_host()->BuildClientSecurityState();
-  ASSERT_FALSE(security_state.is_null());
-
-  EXPECT_TRUE(security_state->is_web_secure_context);
-  EXPECT_EQ(network::mojom::IPAddressSpace::kPublic,
-            security_state->ip_address_space);
-
-  EXPECT_EQ(security_state->private_network_request_policy,
-            network::mojom::PrivateNetworkRequestPolicy::kPermissionBlock);
-}
-
 }  // namespace content
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 43065b5b..80bcf15 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -18759,9 +18759,9 @@
   // TODO (https://crbug.com/1399741): After adding the invalidation signals
   // API, we could mark the page as ineligible for BFCache as soon as the cookie
   // change event is received after the navigation is committed.
-  cookie_change_info_.cookie_modification_count_++;
+  cookie_change_info_.cookie_modification_count++;
   if (change.cookie.IsHttpOnly()) {
-    cookie_change_info_.http_only_cookie_modification_count_++;
+    cookie_change_info_.http_only_cookie_modification_count++;
   }
 }
 
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index 43feed9..0675d4d 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -1535,9 +1535,13 @@
    public:
     struct CookieChangeInfo {
       // The number of observed cookie modifications.
-      int64_t cookie_modification_count_ = 0;
-      // The number of observed HTTPOnly cookie modifications.
-      int64_t http_only_cookie_modification_count_ = 0;
+      int64_t cookie_modification_count = 0;
+      int64_t http_only_cookie_modification_count = 0;
+      // The number of observed cookie modifications that should be removed
+      // since we want to adjust the count by subtracting the number of cookie
+      // modification from the navigation itself.
+      int64_t cookie_modification_removing_count = 0;
+      int64_t http_only_cookie_modification_removing_count = 0;
     };
 
     CookieChangeListener(StoragePartition* storage_partition, GURL& url);
@@ -1557,9 +1561,9 @@
         base::PassKey<content::NavigationRequest> navigation_request,
         uint64_t cookie_modification_count_delta,
         uint64_t http_only_cookie_modification_count_delta) {
-      cookie_change_info_.cookie_modification_count_ -=
+      cookie_change_info_.cookie_modification_removing_count +=
           cookie_modification_count_delta;
-      cookie_change_info_.http_only_cookie_modification_count_ -=
+      cookie_change_info_.http_only_cookie_modification_removing_count +=
           http_only_cookie_modification_count_delta;
     }
 
diff --git a/content/browser/security/local_network_access/OWNERS b/content/browser/security/local_network_access/OWNERS
new file mode 100644
index 0000000..c8542ff
--- /dev/null
+++ b/content/browser/security/local_network_access/OWNERS
@@ -0,0 +1,5 @@
+clamy@chromium.org
+cthomp@chromium.org
+estark@chromium.org
+hchao@chromium.org
+jdeblasio@chromium.org
diff --git a/content/browser/security/local_network_access/local_network_access_browsertest.cc b/content/browser/security/local_network_access/local_network_access_browsertest.cc
new file mode 100644
index 0000000..7557fac5
--- /dev/null
+++ b/content/browser/security/local_network_access/local_network_access_browsertest.cc
@@ -0,0 +1,555 @@
+// 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 <memory>
+#include <set>
+#include <string>
+#include <string_view>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/memory/raw_ptr.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/synchronization/lock.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/thread_annotations.h"
+#include "build/build_config.h"
+#include "content/browser/renderer_host/frame_tree_node.h"
+#include "content/browser/renderer_host/render_frame_host_impl.h"
+#include "content/public/common/content_client.h"
+#include "content/public/common/content_features.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/url_constants.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_content_browser_client.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/resource_load_observer.h"
+#include "content/shell/browser/shell.h"
+#include "content/test/content_browser_test_utils_internal.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/http/http_byte_range.h"
+#include "net/http/http_util.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/embedded_test_server_connection_listener.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "services/network/public/cpp/features.h"
+#include "services/network/public/cpp/ip_address_space_overrides_test_utils.h"
+#include "services/network/public/cpp/network_switches.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace content {
+namespace {
+
+using ::net::test_server::METHOD_GET;
+using ::net::test_server::METHOD_OPTIONS;
+using ::testing::ElementsAre;
+using ::testing::IsEmpty;
+
+// These domains are mapped to the IP addresses above using the
+// `--host-resolver-rules` command-line switch. The exact values come from the
+// embedded HTTPS server, which has certificates for these domains
+constexpr char kLoopbackHost[] = "a.test";
+constexpr char kOtherLoopbackHost[] = "d.test";
+// not localhost, but a host with IP address space = kLocal
+constexpr char kLocalHost[] = "b.test";
+constexpr char kPublicHost[] = "c.test";
+
+// Path to a default response served by all servers in this test.
+constexpr char kDefaultPath[] = "/defaultresponse";
+
+// A |ContentBrowserClient| implementation that allows modifying the return
+// value of |ShouldAllowInsecurePrivateNetworkRequests()| at will.
+class PolicyTestContentBrowserClient
+    : public ContentBrowserTestContentBrowserClient {
+ public:
+  PolicyTestContentBrowserClient() = default;
+
+  PolicyTestContentBrowserClient(const PolicyTestContentBrowserClient&) =
+      delete;
+  PolicyTestContentBrowserClient& operator=(
+      const PolicyTestContentBrowserClient&) = delete;
+
+  ~PolicyTestContentBrowserClient() override = default;
+
+  // Adds an origin to the allowlist.
+  void SetAllowInsecurePrivateNetworkRequestsFrom(const url::Origin& origin) {
+    allowlisted_origins_.insert(origin);
+  }
+
+  void SetBlockInsteadOfWarn() { block_instead_of_warn_ = true; }
+
+  ContentBrowserClient::PrivateNetworkRequestPolicyOverride
+  ShouldOverridePrivateNetworkRequestPolicy(
+      content::BrowserContext* browser_context,
+      const url::Origin& origin) override {
+    if (block_instead_of_warn_) {
+      return ContentBrowserClient::PrivateNetworkRequestPolicyOverride::
+          kBlockInsteadOfWarn;
+    }
+    return allowlisted_origins_.find(origin) != allowlisted_origins_.end()
+               ? ContentBrowserClient::PrivateNetworkRequestPolicyOverride::
+                     kForceAllow
+               : ContentBrowserClient::PrivateNetworkRequestPolicyOverride::
+                     kDefault;
+  }
+
+ private:
+  bool block_instead_of_warn_ = false;
+  std::set<url::Origin> allowlisted_origins_;
+};
+
+// An embedded test server connection listener that simply counts connections.
+// Thread-safe.
+class ConnectionCounter
+    : public net::test_server::EmbeddedTestServerConnectionListener {
+ public:
+  ConnectionCounter() = default;
+
+  // Instances of this class are neither copyable nor movable.
+  ConnectionCounter(const ConnectionCounter&) = delete;
+  ConnectionCounter& operator=(const ConnectionCounter&) = delete;
+  ConnectionCounter(ConnectionCounter&&) = delete;
+  ConnectionCounter& operator=(ConnectionCounter&&) = delete;
+
+  // Returns the number of sockets accepted by the servers we are listening to.
+  int count() const {
+    base::AutoLock guard(lock_);
+    return count_;
+  }
+
+ private:
+  // EmbeddedTestServerConnectionListener implementation.
+
+  std::unique_ptr<net::StreamSocket> AcceptedSocket(
+      std::unique_ptr<net::StreamSocket> socket) override {
+    {
+      base::AutoLock guard(lock_);
+      count_++;
+    }
+    return socket;
+  }
+
+  void ReadFromSocket(const net::StreamSocket& socket, int rv) override {}
+
+  // `count_` is incremented on the embedded test server thread and read on the
+  // test thread, so we synchronize accesses with a lock.
+  mutable base::Lock lock_;
+  int count_ GUARDED_BY(lock_) = 0;
+};
+
+class RequestObserver {
+ public:
+  RequestObserver() = default;
+
+  // The returned callback must not outlive this instance.
+  net::test_server::EmbeddedTestServer::MonitorRequestCallback BindCallback() {
+    return base::BindRepeating(&RequestObserver::Observe,
+                               base::Unretained(this));
+  }
+
+  // The origin of the URL is not checked for equality.
+  std::vector<net::test_server::HttpMethod> RequestMethodsForUrl(
+      const GURL& url) const {
+    std::string path = url.PathForRequest();
+    std::vector<net::test_server::HttpMethod> methods;
+    {
+      base::AutoLock guard(lock_);
+      for (const auto& request : requests_) {
+        if (request.GetURL().PathForRequest() == path) {
+          methods.push_back(request.method);
+        }
+      }
+    }
+    return methods;
+  }
+
+ private:
+  void Observe(const net::test_server::HttpRequest& request) {
+    base::AutoLock guard(lock_);
+    requests_.push_back(request);
+  }
+
+  // `requests_` is mutated on the embedded test server thread and read on the
+  // test thread, so we synchronize accesses with a lock.
+  mutable base::Lock lock_;
+  std::vector<net::test_server::HttpRequest> requests_ GUARDED_BY(lock_);
+};
+
+// Removes `prefix` from the start of `str`, if present.
+// Returns nullopt otherwise.
+std::optional<std::string_view> StripPrefix(std::string_view str,
+                                            std::string_view prefix) {
+  if (!base::StartsWith(str, prefix)) {
+    return std::nullopt;
+  }
+
+  return str.substr(prefix.size());
+}
+
+// Returns a pointer to the value of the `header` header in `request`, if any.
+// Returns nullptr otherwise.
+const std::string* FindRequestHeader(
+    const net::test_server::HttpRequest& request,
+    std::string_view header) {
+  const auto it = request.headers.find(header);
+  if (it == request.headers.end()) {
+    return nullptr;
+  }
+
+  return &it->second;
+}
+
+// Returns the `Content-Range` header value for a given `range` of bytes out of
+// the given `total_size` number of bytes.
+std::string GetContentRangeHeader(const net::HttpByteRange& range,
+                                  size_t total_size) {
+  std::string first = base::NumberToString(range.first_byte_position());
+  std::string last = base::NumberToString(range.last_byte_position());
+  std::string total = base::NumberToString(total_size);
+  return base::StrCat({"bytes ", first, "-", last, "/", total});
+}
+
+// An `EmbeddedTestServer` request handler function.
+//
+// Knows how to respond to CORS and PNA preflight requests, as well as regular
+// and range requests.
+//
+// Route: /echorange?<body>
+std::unique_ptr<net::test_server::HttpResponse> HandleRangeRequest(
+    const net::test_server::HttpRequest& request) {
+  std::optional<std::string_view> query =
+      StripPrefix(request.relative_url, "/echorange?");
+  if (!query) {
+    return nullptr;
+  }
+
+  auto response = std::make_unique<net::test_server::BasicHttpResponse>();
+
+  constexpr std::pair<std::string_view, std::string_view> kCopiedHeaders[] = {
+      {"Origin", "Access-Control-Allow-Origin"},
+      {"Access-Control-Request-Private-Network",
+       "Access-Control-Allow-Private-Network"},
+      {"Access-Control-Request-Headers", "Access-Control-Allow-Headers"},
+  };
+  for (const auto& pair : kCopiedHeaders) {
+    const std::string* value = FindRequestHeader(request, pair.first);
+    if (value) {
+      response->AddCustomHeader(pair.second, *value);
+    }
+  }
+
+  // No body for a preflight response.
+  if (request.method == net::test_server::METHOD_OPTIONS) {
+    response->AddCustomHeader("Access-Control-Max-Age", "60");
+    return response;
+  }
+
+  // Cache-Control: max-age=X does not work for range request caching. Use a
+  // strong ETag instead, along with a last modified date. Both are required.
+  response->AddCustomHeader("ETag", "foo");
+  response->AddCustomHeader("Last-Modified", "Fri, 1 Apr 2022 12:34:56 UTC");
+
+  const std::string* range_header = FindRequestHeader(request, "Range");
+  if (!range_header) {
+    // Not a range request. Respond with 200 and the whole query as the body.
+    response->set_content(*query);
+    return response;
+  }
+
+  std::vector<net::HttpByteRange> ranges;
+  if (!net::HttpUtil::ParseRangeHeader(*range_header, &ranges) ||
+      ranges.size() != 1) {
+    response->set_code(net::HTTP_BAD_REQUEST);
+    return response;
+  }
+
+  net::HttpByteRange& range = ranges[0];
+  if (!range.ComputeBounds(query->size())) {
+    response->set_code(net::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE);
+    return response;
+  }
+
+  response->set_code(net::HTTP_PARTIAL_CONTENT);
+  response->AddCustomHeader("Content-Range",
+                            GetContentRangeHeader(range, query->size()));
+  response->set_content(query->substr(range.first_byte_position(),
+                                      range.last_byte_position() + 1));
+  return response;
+}
+
+// A `net::EmbeddedTestServer` that pretends to be in a given IP address space.
+//
+// Set up of the command line in order for this server to be considered a part
+// of `ip_address_space` must be done outside of server creation.
+class FakeAddressSpaceServer {
+ public:
+  FakeAddressSpaceServer(net::EmbeddedTestServer::Type type,
+                         net::test_server::HttpConnection::Protocol protocol,
+                         network::mojom::IPAddressSpace ip_address_space,
+                         const base::FilePath& test_data_path)
+      : server_(type, protocol), ip_address_space_(ip_address_space) {
+    // Use a certificate valid for multiple domains, which we can use to
+    // distinguish `loopback`, `local` and `public` address spaces.
+    server_.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
+
+    server_.SetConnectionListener(&connection_counter_);
+    server_.RegisterRequestMonitor(request_observer_.BindCallback());
+    server_.RegisterRequestHandler(base::BindRepeating(&HandleRangeRequest));
+    server_.AddDefaultHandlers(test_data_path);
+    CHECK(server_.Start());
+  }
+
+  std::string GenerateCommandLineSwitchOverride() const {
+    return network::GenerateIpAddressSpaceOverride(server_, ip_address_space_);
+  }
+
+  // Returns the underlying test server.
+  net::EmbeddedTestServer& Get() { return server_; }
+
+  // Returns the total number of sockets accepted by this server.
+  int ConnectionCount() const { return connection_counter_.count(); }
+
+  const RequestObserver& request_observer() const { return request_observer_; }
+
+ private:
+  ConnectionCounter connection_counter_;
+  RequestObserver request_observer_;
+  net::EmbeddedTestServer server_;
+  const network::mojom::IPAddressSpace ip_address_space_;
+};
+
+}  // namespace
+
+// This being an integration/browser test, we concentrate on a few behaviors
+// relevant to Local Network Access:
+//
+//  - testing the values of important properties on top-level documents:
+//    - address space
+//    - secure context bit
+//    - private network request policy
+//  - testing the inheritance semantics of these properties
+//  - testing the correct handling of the CSP: treat-as-public-address directive
+//  - testing that subresource requests are subject to LNA checks
+//  - and a few other odds and ends
+//
+// We use the `--ip-address-space-overrides` command-line switch to test against
+// `local` and `public` address spaces, even though all responses are actually
+// served from localhost. Combined with host resolver rules, this lets us define
+// three different domains that map to the different address spaces:
+//
+//  - `a.test` is `loopback`
+//  - `b.test` is `local`
+//  - `c.test` is `public`
+//
+// We also have unit tests that test all possible combinations of source and
+// destination IP address spaces in services/network/url_loader_unittest.cc.
+class LocalNetworkAccessBrowserTestBase : public ContentBrowserTest {
+ public:
+  RenderFrameHostImpl* root_frame_host() {
+    return static_cast<RenderFrameHostImpl*>(
+        shell()->web_contents()->GetPrimaryMainFrame());
+  }
+
+ protected:
+  // Allows subclasses to construct instances with different features enabled.
+  explicit LocalNetworkAccessBrowserTestBase()
+      : insecure_loopback_server_(
+            net::EmbeddedTestServer::TYPE_HTTP,
+            net::test_server::HttpConnection::Protocol::kHttp1,
+            network::mojom::IPAddressSpace::kLoopback,
+            GetTestDataFilePath()),
+        insecure_local_server_(
+            net::EmbeddedTestServer::TYPE_HTTP,
+            net::test_server::HttpConnection::Protocol::kHttp1,
+            network::mojom::IPAddressSpace::kLocal,
+            GetTestDataFilePath()),
+        insecure_public_server_(
+            net::EmbeddedTestServer::TYPE_HTTP,
+            net::test_server::HttpConnection::Protocol::kHttp1,
+            network::mojom::IPAddressSpace::kPublic,
+            GetTestDataFilePath()),
+        secure_loopback_server_(
+            net::EmbeddedTestServer::TYPE_HTTPS,
+            net::test_server::HttpConnection::Protocol::kHttp1,
+            network::mojom::IPAddressSpace::kLoopback,
+            GetTestDataFilePath()),
+        secure_local_server_(net::EmbeddedTestServer::TYPE_HTTPS,
+                             net::test_server::HttpConnection::Protocol::kHttp1,
+                             network::mojom::IPAddressSpace::kLocal,
+                             GetTestDataFilePath()),
+        secure_public_server_(
+            net::EmbeddedTestServer::TYPE_HTTPS,
+            net::test_server::HttpConnection::Protocol::kHttp1,
+            network::mojom::IPAddressSpace::kPublic,
+            GetTestDataFilePath()) {}
+
+  void SetUpOnMainThread() override {
+    ContentBrowserTest::SetUpOnMainThread();
+
+    // Rules must be added on the main thread, otherwise `AddRule()` segfaults.
+    host_resolver()->AddRule(kLoopbackHost, "127.0.0.1");
+    host_resolver()->AddRule(kOtherLoopbackHost, "127.0.0.1");
+    host_resolver()->AddRule(kLocalHost, "127.0.0.1");
+    host_resolver()->AddRule(kPublicHost, "127.0.0.1");
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    ContentBrowserTest::SetUpCommandLine(command_line);
+    // Add correct ip address space overrides.
+    network::AddIpAddressSpaceOverridesToCommandLine(
+        {insecure_loopback_server_.GenerateCommandLineSwitchOverride(),
+         insecure_local_server_.GenerateCommandLineSwitchOverride(),
+         insecure_public_server_.GenerateCommandLineSwitchOverride(),
+         secure_loopback_server_.GenerateCommandLineSwitchOverride(),
+         secure_local_server_.GenerateCommandLineSwitchOverride(),
+         secure_public_server_.GenerateCommandLineSwitchOverride()},
+        *command_line);
+  }
+
+  const FakeAddressSpaceServer& InsecureLoopbackServer() const {
+    return insecure_loopback_server_;
+  }
+
+  const FakeAddressSpaceServer& InsecureLocalServer() const {
+    return insecure_local_server_;
+  }
+
+  const FakeAddressSpaceServer& InsecurePublicServer() const {
+    return insecure_public_server_;
+  }
+
+  const FakeAddressSpaceServer& SecureLoopbackServer() const {
+    return secure_loopback_server_;
+  }
+
+  const FakeAddressSpaceServer& SecureLocalServer() const {
+    return secure_local_server_;
+  }
+
+  const FakeAddressSpaceServer& SecurePublicServer() const {
+    return secure_public_server_;
+  }
+
+  GURL InsecureLoopbackURL(const std::string& path) {
+    return insecure_loopback_server_.Get().GetURL(kLoopbackHost, path);
+  }
+
+  GURL InsecureLocalURL(const std::string& path) {
+    return insecure_local_server_.Get().GetURL(kLocalHost, path);
+  }
+
+  GURL InsecurePublicURL(const std::string& path) {
+    return insecure_public_server_.Get().GetURL(kPublicHost, path);
+  }
+
+  GURL SecureLoopbackURL(const std::string& path) {
+    return secure_loopback_server_.Get().GetURL(kLoopbackHost, path);
+  }
+
+  GURL OtherSecureLoopbackURL(const std::string& path) {
+    return secure_loopback_server_.Get().GetURL(kOtherLoopbackHost, path);
+  }
+
+  GURL SecureLocalURL(const std::string& path) {
+    return secure_local_server_.Get().GetURL(kLocalHost, path);
+  }
+
+  GURL SecurePublicURL(const std::string& path) {
+    return secure_public_server_.Get().GetURL(kPublicHost, path);
+  }
+
+  GURL NullIPURL(const std::string& path) {
+    return insecure_public_server_.Get().GetURL("0.0.0.0", path);
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+
+  FakeAddressSpaceServer insecure_loopback_server_;
+  FakeAddressSpaceServer insecure_local_server_;
+  FakeAddressSpaceServer insecure_public_server_;
+  FakeAddressSpaceServer secure_loopback_server_;
+  FakeAddressSpaceServer secure_local_server_;
+  FakeAddressSpaceServer secure_public_server_;
+};
+
+// Test with insecure local network subresource requests from the `public`
+// address space blocked.
+class LocalNetworkAccessBrowserTest : public LocalNetworkAccessBrowserTestBase {
+ public:
+  LocalNetworkAccessBrowserTest() : LocalNetworkAccessBrowserTestBase() {
+    // Some builders run with field_trial disabled, need to enable this
+    // manually.
+    base::FieldTrialParams params;
+    params["LocalNetworkAccessChecksWarn"] = "false";
+    feature_list_.InitAndEnableFeatureWithParameters(
+        network::features::kLocalNetworkAccessChecks, params);
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+// ===========================
+// CLIENT SECURITY STATE TESTS
+// ===========================
+//
+// These tests verify the contents of `ClientSecurityState` for top-level
+// documents in various different circumstances.
+
+// This test verifies the contents of the ClientSecurityState for the initial
+// empty document in a new main frame created by the browser.
+//
+// Note: the renderer-created main frame case is exercised by the
+// OpeneeInherits* tests below.
+IN_PROC_BROWSER_TEST_F(LocalNetworkAccessBrowserTest,
+                       ClientSecurityStateForInitialEmptyDoc) {
+  // Start a navigation. This forces the RenderFrameHost to initialize its
+  // RenderFrame. The navigation is then cancelled by a HTTP 204 code.
+  // We're left with a RenderFrameHost containing the default
+  // ClientSecurityState values.
+  //
+  // Serve the response from a secure public server, to confirm that none of
+  // the connection's properties are reflected in the committed document, which
+  // is not a secure context and belongs to the `loopback` address space.
+  EXPECT_TRUE(
+      NavigateToURLAndExpectNoCommit(shell(), SecurePublicURL("/nocontent")));
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      root_frame_host()->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+  EXPECT_FALSE(security_state->is_web_secure_context);
+  EXPECT_EQ(network::mojom::CrossOriginEmbedderPolicyValue::kNone,
+            security_state->cross_origin_embedder_policy.value);
+  EXPECT_EQ(network::mojom::PrivateNetworkRequestPolicy::kBlock,
+            security_state->private_network_request_policy);
+
+  // Browser-created empty main frames are trusted to access the local network,
+  // if they execute code injected via DevTools, WebView APIs or extensions.
+  EXPECT_EQ(network::mojom::IPAddressSpace::kLoopback,
+            security_state->ip_address_space);
+}
+
+IN_PROC_BROWSER_TEST_F(LocalNetworkAccessBrowserTest, CheckSecurityState) {
+  EXPECT_TRUE(NavigateToURL(shell(), SecurePublicURL(kDefaultPath)));
+
+  const network::mojom::ClientSecurityStatePtr security_state =
+      root_frame_host()->BuildClientSecurityState();
+  ASSERT_FALSE(security_state.is_null());
+
+  EXPECT_TRUE(security_state->is_web_secure_context);
+  EXPECT_EQ(network::mojom::IPAddressSpace::kPublic,
+            security_state->ip_address_space);
+
+  EXPECT_EQ(security_state->private_network_request_policy,
+            network::mojom::PrivateNetworkRequestPolicy::kPermissionBlock);
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/local_network_access_browsertest.cc b/content/browser/security/local_network_access/local_network_access_deprecation_browsertest.cc
similarity index 100%
rename from content/browser/renderer_host/local_network_access_browsertest.cc
rename to content/browser/security/local_network_access/local_network_access_deprecation_browsertest.cc
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index 5895e8c4..069b62c 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -56,6 +56,7 @@
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/browser/service_worker/service_worker_controllee_request_handler.h"
 #include "content/browser/service_worker/service_worker_fetch_dispatcher.h"
+#include "content/browser/service_worker/service_worker_loader_helpers.h"
 #include "content/browser/service_worker/service_worker_registration.h"
 #include "content/browser/service_worker/service_worker_test_utils.h"
 #include "content/browser/service_worker/service_worker_version.h"
@@ -7615,7 +7616,8 @@
 
 // Test class for synthetic response (crbug.com/352578800) browsertest.
 class ServiceWorkerSyntheticResponseBrowserTest
-    : public ServiceWorkerBrowserTest {
+    : public ServiceWorkerBrowserTest,
+      public ::testing::WithParamInterface<bool> {
  public:
   static constexpr char kHostname[] = "synthetic-response.test";
   static constexpr char kTargetPath[] =
@@ -7643,6 +7645,7 @@
     ASSERT_TRUE(https_server_->InitializeAndListen());
     https_server_->StartAcceptingConnections();
     ServiceWorkerBrowserTest::SetUpOnMainThread();
+    ServiceWorkerSyntheticResponseManager::SetDryRunMode(IsDryRunMode());
   }
 
   RenderFrameHost* GetPrimaryMainFrame() {
@@ -7680,6 +7683,7 @@
     mock_content_browser_client = std::make_unique<MockContentBrowserClient>();
     mock_content_browser_client->set_synthetic_response_enabled(true);
   }
+  bool IsDryRunMode() { return GetParam(); }
 
   std::unique_ptr<MockContentBrowserClient> mock_content_browser_client;
 
@@ -7759,7 +7763,11 @@
   base::HistogramTester histogram_tester_;
 };
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerSyntheticResponseBrowserTest,
+INSTANTIATE_TEST_SUITE_P(All,
+                         ServiceWorkerSyntheticResponseBrowserTest,
+                         testing::Bool());
+
+IN_PROC_BROWSER_TEST_P(ServiceWorkerSyntheticResponseBrowserTest,
                        FakeRegistration) {
   GURL::Replacements replacements;
   replacements.ClearQuery();
@@ -7794,7 +7802,7 @@
             blink::ServiceWorkerStatusCode::kErrorNotFound);
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerSyntheticResponseBrowserTest,
+IN_PROC_BROWSER_TEST_P(ServiceWorkerSyntheticResponseBrowserTest,
                        MatchedPageIsServiceWorkerControlled) {
   SetUpMockContentBrowserClient();
   // Navigated URL matched with the URL in the allowlist is controlled by
@@ -7807,7 +7815,7 @@
   EXPECT_EQ("[SyntheticResponse] Response from the network", GetInnerText());
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerSyntheticResponseBrowserTest,
+IN_PROC_BROWSER_TEST_P(ServiceWorkerSyntheticResponseBrowserTest,
                        ResponseHeaderIsStored) {
   SetUpMockContentBrowserClient();
   // Navigate and store the response header.
@@ -7826,8 +7834,10 @@
       static_cast<int>(ServiceWorkerMetrics::SyntheticResponseEligibility::
                            kNotEligibleByNoHeaderStored),
       1);
+  // If dry run mode, `IsHeaderStored` is not recorded.
   histogram_tester().ExpectBucketCount(
-      "ServiceWorker.SyntheticResponse.IsHeaderStored", true, 1);
+      "ServiceWorker.SyntheticResponse.IsHeaderStored", true,
+      IsDryRunMode() ? 0 : 1);
 
   // The second navigation. The browser should have stored the response header
   // from the previous navigation, and receive the response header locally.
@@ -7848,7 +7858,7 @@
       1);
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerSyntheticResponseBrowserTest,
+IN_PROC_BROWSER_TEST_P(ServiceWorkerSyntheticResponseBrowserTest,
                        InlineScriptIsNotAllowedUntilMetaCSPScriptSrc) {
   SetUpMockContentBrowserClient();
   // Navigate and store the response header.
@@ -7878,7 +7888,7 @@
                          "window.is_inline_script_executed"));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerSyntheticResponseBrowserTest,
+IN_PROC_BROWSER_TEST_P(ServiceWorkerSyntheticResponseBrowserTest,
                        HeaderMismatch) {
   SetUpMockContentBrowserClient();
   // Navigate and store the response header.
@@ -7902,7 +7912,8 @@
           kHostname,
           base::StrCat(
               {kTargetPath, "foo&echo=bar&server_slow&header_mismatch"})),
-      /*number_of_navigations=*/2, /*ignore_uncommitted_navigations=*/false);
+      /*number_of_navigations=*/IsDryRunMode() ? 1 : 2,
+      /*ignore_uncommitted_navigations=*/false);
   EXPECT_EQ("[SyntheticResponse] bar", GetInnerText());
   // After the reload, synthetic response is not enabled. `responseStart` is
   // 2000ms due to the server delay.
@@ -7918,7 +7929,7 @@
       0);
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerSyntheticResponseBrowserTest,
+IN_PROC_BROWSER_TEST_P(ServiceWorkerSyntheticResponseBrowserTest,
                        HeaderMismatch_DuplicatedHeader) {
   SetUpMockContentBrowserClient();
   // Navigate and store the response header.
@@ -7942,7 +7953,8 @@
                              base::StrCat({kTargetPath,
                                            "foo&echo=bar&server_slow&header_"
                                            "mismatch_with_duplicated_header"})),
-      /*number_of_navigations=*/2, /*ignore_uncommitted_navigations=*/false);
+      /*number_of_navigations=*/IsDryRunMode() ? 1 : 2,
+      /*ignore_uncommitted_navigations=*/false);
   EXPECT_EQ("[SyntheticResponse] bar", GetInnerText());
   // After the reload, synthetic response is not enabled. `responseStart` is
   // 2000ms due to the server delay.
@@ -7951,7 +7963,7 @@
                      "responseStart) >= 2000"));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerSyntheticResponseBrowserTest,
+IN_PROC_BROWSER_TEST_P(ServiceWorkerSyntheticResponseBrowserTest,
                        HeaderMismatch_IgnoredHeader) {
   SetUpMockContentBrowserClient();
   // Navigate and store the response header.
diff --git a/content/browser/service_worker/service_worker_loader_helpers.cc b/content/browser/service_worker/service_worker_loader_helpers.cc
index 03851ff5..133d762 100644
--- a/content/browser/service_worker/service_worker_loader_helpers.cc
+++ b/content/browser/service_worker/service_worker_loader_helpers.cc
@@ -17,6 +17,7 @@
 #include "content/browser/devtools/devtools_instrumentation.h"
 #include "content/browser/loader/browser_initiated_resource_request.h"
 #include "content/browser/service_worker/service_worker_consts.h"
+#include "content/browser/service_worker/service_worker_synthetic_response_manager.h"
 #include "content/common/features.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
@@ -456,6 +457,16 @@
   return false;
 }
 
+bool IsSyntheticResponseDryRunModeEnabled() {
+  if (ServiceWorkerSyntheticResponseManager::IsDryRunModeEnabledForTesting()) {
+    return true;
+  }
+  static const bool is_dry_run(
+      blink::features::kServiceWorkerSyntheticResponseDryRun.Get());
+
+  return is_dry_run;
+}
+
 }  // namespace service_worker_loader_helpers
 
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_loader_helpers.h b/content/browser/service_worker/service_worker_loader_helpers.h
index c3bcaf7..df2e50a20 100644
--- a/content/browser/service_worker/service_worker_loader_helpers.h
+++ b/content/browser/service_worker/service_worker_loader_helpers.h
@@ -106,7 +106,7 @@
     const GURL& client_url,
     const std::string& allowed_url,
     const base::flat_set<std::string>& denied_url_params);
-
+bool IsSyntheticResponseDryRunModeEnabled();
 }  // namespace service_worker_loader_helpers
 
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_main_resource_loader.cc b/content/browser/service_worker/service_worker_main_resource_loader.cc
index acc6acb..d3a6922 100644
--- a/content/browser/service_worker/service_worker_main_resource_loader.cc
+++ b/content/browser/service_worker/service_worker_main_resource_loader.cc
@@ -48,6 +48,7 @@
 #include "services/network/public/mojom/fetch_api.mojom.h"
 #include "services/network/public/mojom/service_worker_router_info.mojom-shared.h"
 #include "services/network/public/mojom/service_worker_router_info.mojom.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/service_worker/service_worker_loader_helpers.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_fetch_handler_bypass_option.mojom-shared.h"
 #include "third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom-shared.h"
@@ -323,6 +324,8 @@
           head_update_params.load_timing_info = response_head_->load_timing;
           head_update_params.initial_service_worker_status =
               initial_service_worker_status_.value();
+          head_update_params.is_synthetic_response_dry_run_mode =
+              is_synthetic_response_used_;
           Fallback(std::move(head_update_params));
 
           // If the kServiceWorkerStaticRouterStartServiceWorker feature is
@@ -1036,6 +1039,29 @@
     return false;
   }
 
+  if (service_worker_loader_helpers::IsSyntheticResponseDryRunModeEnabled()) {
+    if (version->GetResponseHeadForSyntheticResponse()) {
+      // With dry-run mode, update `is_synthetic_response_used_` here. This will
+      // update the actual response head through `ResponseHeadUpdateParams` and
+      // pass the information to the renderer.
+      is_synthetic_response_used_ = true;
+      RecordSyntheticResponseEligibility(
+          SyntheticResponseEligibility::kEligible);
+    } else {
+      // If dry-run mode, do not dispatch a network request for the synthetic
+      // response. Instead, set a fake response headers to
+      // `ServiceWorkerVersion` if it doesn't exist in order to simulate the
+      // next navigation is eligible for the synthetic response.
+      network::mojom::URLResponseHeadPtr fake_response_head =
+          network::mojom::URLResponseHead::New();
+      version->SetResponseHeadForSyntheticResponse(
+          std::move(fake_response_head));
+      RecordSyntheticResponseEligibility(
+          SyntheticResponseEligibility::kNotEligibleByNoHeaderStored);
+    }
+    return false;
+  }
+
   is_synthetic_response_used_ = true;
 
   synthetic_response_manager_.emplace(
diff --git a/content/browser/service_worker/service_worker_synthetic_response_manager.cc b/content/browser/service_worker/service_worker_synthetic_response_manager.cc
index d41023c..e694673 100644
--- a/content/browser/service_worker/service_worker_synthetic_response_manager.cc
+++ b/content/browser/service_worker/service_worker_synthetic_response_manager.cc
@@ -458,4 +458,13 @@
   }
   OnCloneCompleted();
 }
+
+bool ServiceWorkerSyntheticResponseManager::dry_run_mode_for_testing_ = false;
+void ServiceWorkerSyntheticResponseManager::SetDryRunMode(bool enabled) {
+  dry_run_mode_for_testing_ = enabled;
+}
+bool ServiceWorkerSyntheticResponseManager::IsDryRunModeEnabledForTesting() {
+  return dry_run_mode_for_testing_;
+}
+
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_synthetic_response_manager.h b/content/browser/service_worker/service_worker_synthetic_response_manager.h
index 0929f22..0a8c48a9 100644
--- a/content/browser/service_worker/service_worker_synthetic_response_manager.h
+++ b/content/browser/service_worker/service_worker_synthetic_response_manager.h
@@ -64,6 +64,10 @@
   void StartSyntheticResponse(FetchCallback callback);
   SyntheticResponseStatus Status() const { return status_; }
 
+  // The static function to override the dry run mode.
+  static void SetDryRunMode(bool enabled);
+  static bool IsDryRunModeEnabledForTesting();
+
  private:
   class SyntheticResponseURLLoaderClient;
 
@@ -105,6 +109,8 @@
   mojo::Remote<blink::mojom::ServiceWorkerStreamCallback> stream_callback_;
   std::optional<RaceNetworkRequestSimpleBufferManager> simple_buffer_manager_;
 
+  static bool dry_run_mode_for_testing_;
+
   base::WeakPtrFactory<ServiceWorkerSyntheticResponseManager> weak_factory_{
       this};
 };
diff --git a/content/browser/webauth/authenticator_common_impl.cc b/content/browser/webauth/authenticator_common_impl.cc
index 900591c..ef816b4 100644
--- a/content/browser/webauth/authenticator_common_impl.cc
+++ b/content/browser/webauth/authenticator_common_impl.cc
@@ -1510,6 +1510,18 @@
         blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR);
     return;
   }
+
+  if (public_key_options->extensions->remote_desktop_client_override &&
+      options->mediation == Mediation::IMMEDIATE) {
+    mojo::ReportBadMessage(
+        "Immediate mediation cannot be used with a remote desktop override "
+        "request");
+    req_state_->request_outcome = GetAssertionOutcome::kOtherFailure;
+    CompleteGetAssertionRequest(
+        blink::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR);
+    return;
+  }
+
   req_state_->mediation_ = options->mediation;
 
   if (public_key_options->challenge_url.has_value() &&
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index ec521c8..27b17a6 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -3181,6 +3181,38 @@
   }
 }
 
+TEST_F(AuthenticatorImplRemoteDesktopClientOverrideTest,
+       GetAssertionImmediateMediation) {
+  // Verify that an authorized origin may not use the extension with immediate
+  // mediation.
+  NavigateAndCommit(GURL(kCorpCrdOrigin));
+
+  PublicKeyCredentialRequestOptionsPtr options =
+      GetTestPublicKeyCredentialRequestOptions();
+  options->allow_credentials.clear();
+  options->relying_party_id = kExampleRpId;
+  options->extensions->remote_desktop_client_override =
+      RemoteDesktopClientOverride::New(
+          url::Origin::Create(GURL(kExampleOrigin)), true);
+
+  mojo::Remote<blink::mojom::Authenticator> authenticator =
+      ConnectToAuthenticator();
+  base::test::TestFuture<void> mojo_error_future;
+  SetMojoErrorHandler(base::BindLambdaForTesting([&](const std::string& error) {
+    EXPECT_EQ(error,
+              "Immediate mediation cannot be used with a remote desktop "
+              "override request");
+    mojo_error_future.SetValue();
+  }));
+
+  auto get_credential_options = GetCredentialOptions::New();
+  get_credential_options->public_key = std::move(options);
+  get_credential_options->mediation = blink::mojom::Mediation::IMMEDIATE;
+  authenticator->GetCredential(std::move(get_credential_options),
+                               base::DoNothing());
+  EXPECT_TRUE(mojo_error_future.Wait());
+}
+
 class MockAuthenticatorRequestDelegateObserver
     : public TestAuthenticatorRequestDelegate {
  public:
diff --git a/content/browser/webrtc/resources/stats_rates_calculator.js b/content/browser/webrtc/resources/stats_rates_calculator.js
index 4a81214..e201712c 100644
--- a/content/browser/webrtc/resources/stats_rates_calculator.js
+++ b/content/browser/webrtc/resources/stats_rates_calculator.js
@@ -467,188 +467,164 @@
   constructor() {
     this.previousReport = null;
     this.currentReport = null;
-    this.statsCalculators = [
-      {
-        type: 'data-channel',
-        metricCalculators: {
-          messagesSent: new RateCalculator('messagesSent', 'timestamp'),
-          messagesReceived: new RateCalculator('messagesReceived', 'timestamp'),
-          bytesSent: new RateCalculator(
-              'bytesSent', 'timestamp', CalculatorModifier.kBytesToBits),
-          bytesReceived: new RateCalculator(
-              'bytesReceived', 'timestamp', CalculatorModifier.kBytesToBits),
-        },
+    this.statsCalculators = {
+      'data-channel': {
+        messagesSent: new RateCalculator('messagesSent', 'timestamp'),
+        messagesReceived: new RateCalculator('messagesReceived', 'timestamp'),
+        bytesSent: new RateCalculator(
+            'bytesSent', 'timestamp', CalculatorModifier.kBytesToBits),
+        bytesReceived: new RateCalculator(
+            'bytesReceived', 'timestamp', CalculatorModifier.kBytesToBits),
       },
-      {
-        type: 'media-source',
-        metricCalculators: {
-          totalAudioEnergy: new AudioLevelRmsCalculator(),
-        },
+      'media-source': {
+        totalAudioEnergy: new AudioLevelRmsCalculator(),
       },
-      {
-        type: 'media-playout',
-        metricCalculators: {
-          totalPlayoutDelay: new RateCalculator('totalPlayoutDelay',
-                                                'totalSamplesCount'),
-        },
+      'media-playout': {
+        totalPlayoutDelay: new RateCalculator('totalPlayoutDelay',
+                                              'totalSamplesCount'),
       },
-      {
-        type: 'outbound-rtp',
-        metricCalculators: {
-          bytesSent: new RateCalculator(
-              'bytesSent', 'timestamp', CalculatorModifier.kBytesToBits),
-          headerBytesSent: new RateCalculator(
-              'headerBytesSent', 'timestamp', CalculatorModifier.kBytesToBits),
-          retransmittedBytesSent: new RateCalculator(
-              'retransmittedBytesSent', 'timestamp',
-              CalculatorModifier.kBytesToBits),
-          packetsSent: new RateCalculator('packetsSent', 'timestamp'),
-          retransmittedPacketsSent:
-              new RateCalculator('retransmittedPacketsSent', 'timestamp'),
-          totalPacketSendDelay: new RateCalculator(
-              'totalPacketSendDelay', 'packetsSent',
-              CalculatorModifier.kMillisecondsFromSeconds),
-          framesEncoded: new RateCalculator('framesEncoded', 'timestamp'),
-          framesSent: new RateCalculator('framesSent', 'timestamp'),
-          totalEncodedBytesTarget: new RateCalculator(
-              'totalEncodedBytesTarget', 'timestamp',
-              CalculatorModifier.kBytesToBits),
-          totalEncodeTime: new RateCalculator(
-              'totalEncodeTime', 'framesEncoded',
-              CalculatorModifier.kMillisecondsFromSeconds),
-          qpSum: new RateCalculator('qpSum', 'framesEncoded'),
-          // Currently limited to a single output.
-          psnrSum: new PsnrRateCalculator('y'),
-          codecId: new CodecCalculator(),
-        },
-      },
-      {
-        type: 'inbound-rtp',
-        metricCalculators: {
-          bytesReceived: new RateCalculator(
-              'bytesReceived', 'timestamp', CalculatorModifier.kBytesToBits),
-          headerBytesReceived: new RateCalculator(
-              'headerBytesReceived', 'timestamp',
-              CalculatorModifier.kBytesToBits),
-          retransmittedBytesReceived: new RateCalculator(
-            'retransmittedBytesReceived', 'timestamp',
+      'outbound-rtp': {
+        bytesSent: new RateCalculator(
+            'bytesSent', 'timestamp', CalculatorModifier.kBytesToBits),
+        headerBytesSent: new RateCalculator(
+            'headerBytesSent', 'timestamp', CalculatorModifier.kBytesToBits),
+        retransmittedBytesSent: new RateCalculator(
+            'retransmittedBytesSent', 'timestamp',
             CalculatorModifier.kBytesToBits),
-          fecBytesReceived: new RateCalculator(
-              'fecBytesReceived', 'timestamp',
-              CalculatorModifier.kBytesToBits),
-          packetsReceived: new RateCalculator('packetsReceived', 'timestamp'),
-          packetsDiscarded: new RateCalculator('packetsDiscarded', 'timestamp'),
-          retransmittedPacketsReceived:
-            new RateCalculator('retransmittedPacketsReceived', 'timestamp'),
-          fecPacketsReceived:
-            new RateCalculator('fecPacketsReceived', 'timestamp'),
-          fecPacketsDiscarded:
-            new RateCalculator('fecPacketsDiscarded', 'timestamp'),
-          framesReceived: [
-            new RateCalculator('framesReceived', 'timestamp'),
-            new DifferenceCalculator('framesReceived',
-                'framesDecoded', 'framesDropped'),
-          ],
-          framesDecoded: new RateCalculator('framesDecoded', 'timestamp'),
-          keyFramesDecoded: new RateCalculator('keyFramesDecoded', 'timestamp'),
-          totalDecodeTime: new RateCalculator(
-              'totalDecodeTime', 'framesDecoded',
-              CalculatorModifier.kMillisecondsFromSeconds),
-          totalInterFrameDelay: new RateCalculator(
-              'totalInterFrameDelay', 'framesDecoded',
-              CalculatorModifier.kMillisecondsFromSeconds),
-          totalSquaredInterFrameDelay: new StandardDeviationCalculator(
-              'totalSquaredInterFrameDelay', 'totalInterFrameDelay',
-              'framesDecoded', 'interFrameDelay'),
-          totalSamplesReceived:
-              new RateCalculator('totalSamplesReceived', 'timestamp'),
-          concealedSamples: [
-            new RateCalculator('concealedSamples', 'timestamp'),
-            new RateCalculator('concealedSamples', 'totalSamplesReceived'),
-          ],
-          silentConcealedSamples:
-              new RateCalculator('silentConcealedSamples', 'timestamp'),
-          insertedSamplesForDeceleration:
-              new RateCalculator('insertedSamplesForDeceleration', 'timestamp'),
-          removedSamplesForAcceleration:
-              new RateCalculator('removedSamplesForAcceleration', 'timestamp'),
-          qpSum: new RateCalculator('qpSum', 'framesDecoded'),
-          totalCorruptionProbability:
-              new RateCalculator(
-                'totalCorruptionProbability', 'corruptionMeasurements'),
-          codecId: new CodecCalculator(),
-          totalAudioEnergy: new AudioLevelRmsCalculator(),
-          jitterBufferDelay: new RateCalculator(
-              'jitterBufferDelay', 'jitterBufferEmittedCount',
-              CalculatorModifier.kMillisecondsFromSeconds),
-          jitterBufferTargetDelay: new RateCalculator(
-              'jitterBufferTargetDelay', 'jitterBufferEmittedCount',
-              CalculatorModifier.kMillisecondsFromSeconds),
-          jitterBufferMinimumDelay: new RateCalculator(
-              'jitterBufferMinimumDelay', 'jitterBufferEmittedCount',
-              CalculatorModifier.kMillisecondsFromSeconds),
-          lastPacketReceivedTimestamp: new DateCalculator(
-              'lastPacketReceivedTimestamp'),
-          estimatedPlayoutTimestamp: new DateCalculator(
-              'estimatedPlayoutTimestamp', kNtpToUnixTimeOffsetMs),
-          totalProcessingDelay: new RateCalculator(
-              'totalProcessingDelay', 'jitterBufferEmittedCount',
-              CalculatorModifier.kMillisecondsFromSeconds),
-          totalAssemblyTime: new RateCalculator(
-              'totalAssemblyTime', 'framesAssembledFromMultiplePackets',
-              CalculatorModifier.kMillisecondsFromSeconds),
-        },
+        packetsSent: new RateCalculator('packetsSent', 'timestamp'),
+        retransmittedPacketsSent:
+            new RateCalculator('retransmittedPacketsSent', 'timestamp'),
+        totalPacketSendDelay: new RateCalculator(
+            'totalPacketSendDelay', 'packetsSent',
+            CalculatorModifier.kMillisecondsFromSeconds),
+        framesEncoded: new RateCalculator('framesEncoded', 'timestamp'),
+        framesSent: new RateCalculator('framesSent', 'timestamp'),
+        totalEncodedBytesTarget: new RateCalculator(
+            'totalEncodedBytesTarget', 'timestamp',
+            CalculatorModifier.kBytesToBits),
+        totalEncodeTime: new RateCalculator(
+            'totalEncodeTime', 'framesEncoded',
+            CalculatorModifier.kMillisecondsFromSeconds),
+        qpSum: new RateCalculator('qpSum', 'framesEncoded'),
+        psnrSum: [
+          new PsnrRateCalculator('y'),
+          new PsnrRateCalculator('u'),
+          new PsnrRateCalculator('v'),
+        ],
+        codecId: new CodecCalculator(),
       },
-      {
-        type: 'remote-inbound-rtp',
-        metricCalculators: {
-          totalRoundTripTime:
-              new RateCalculator('totalRoundTripTime',
-                                 'roundTripTimeMeasurements'),
-        },
+      'inbound-rtp': {
+        bytesReceived: new RateCalculator(
+            'bytesReceived', 'timestamp', CalculatorModifier.kBytesToBits),
+        headerBytesReceived: new RateCalculator(
+            'headerBytesReceived', 'timestamp',
+            CalculatorModifier.kBytesToBits),
+        retransmittedBytesReceived: new RateCalculator(
+          'retransmittedBytesReceived', 'timestamp',
+          CalculatorModifier.kBytesToBits),
+        fecBytesReceived: new RateCalculator(
+            'fecBytesReceived', 'timestamp',
+            CalculatorModifier.kBytesToBits),
+        packetsReceived: new RateCalculator('packetsReceived', 'timestamp'),
+        packetsDiscarded: new RateCalculator('packetsDiscarded', 'timestamp'),
+        retransmittedPacketsReceived:
+          new RateCalculator('retransmittedPacketsReceived', 'timestamp'),
+        fecPacketsReceived:
+          new RateCalculator('fecPacketsReceived', 'timestamp'),
+        fecPacketsDiscarded:
+          new RateCalculator('fecPacketsDiscarded', 'timestamp'),
+        framesReceived: [
+          new RateCalculator('framesReceived', 'timestamp'),
+          new DifferenceCalculator('framesReceived',
+              'framesDecoded', 'framesDropped'),
+        ],
+        framesDecoded: new RateCalculator('framesDecoded', 'timestamp'),
+        keyFramesDecoded: new RateCalculator('keyFramesDecoded', 'timestamp'),
+        totalDecodeTime: new RateCalculator(
+            'totalDecodeTime', 'framesDecoded',
+            CalculatorModifier.kMillisecondsFromSeconds),
+        totalInterFrameDelay: new RateCalculator(
+            'totalInterFrameDelay', 'framesDecoded',
+            CalculatorModifier.kMillisecondsFromSeconds),
+        totalSquaredInterFrameDelay: new StandardDeviationCalculator(
+            'totalSquaredInterFrameDelay', 'totalInterFrameDelay',
+            'framesDecoded', 'interFrameDelay'),
+        totalSamplesReceived:
+          new RateCalculator('totalSamplesReceived', 'timestamp'),
+        concealedSamples: [
+          new RateCalculator('concealedSamples', 'timestamp'),
+          new RateCalculator('concealedSamples', 'totalSamplesReceived'),
+        ],
+        silentConcealedSamples:
+          new RateCalculator('silentConcealedSamples', 'timestamp'),
+        insertedSamplesForDeceleration:
+          new RateCalculator('insertedSamplesForDeceleration', 'timestamp'),
+        removedSamplesForAcceleration:
+          new RateCalculator('removedSamplesForAcceleration', 'timestamp'),
+        qpSum: new RateCalculator('qpSum', 'framesDecoded'),
+        totalCorruptionProbability:
+          new RateCalculator(
+              'totalCorruptionProbability', 'corruptionMeasurements'),
+        codecId: new CodecCalculator(),
+        totalAudioEnergy: new AudioLevelRmsCalculator(),
+        jitterBufferDelay: new RateCalculator(
+            'jitterBufferDelay', 'jitterBufferEmittedCount',
+            CalculatorModifier.kMillisecondsFromSeconds),
+        jitterBufferTargetDelay: new RateCalculator(
+            'jitterBufferTargetDelay', 'jitterBufferEmittedCount',
+            CalculatorModifier.kMillisecondsFromSeconds),
+        jitterBufferMinimumDelay: new RateCalculator(
+            'jitterBufferMinimumDelay', 'jitterBufferEmittedCount',
+            CalculatorModifier.kMillisecondsFromSeconds),
+        lastPacketReceivedTimestamp: new DateCalculator(
+            'lastPacketReceivedTimestamp'),
+        estimatedPlayoutTimestamp: new DateCalculator(
+            'estimatedPlayoutTimestamp', kNtpToUnixTimeOffsetMs),
+        totalProcessingDelay: new RateCalculator(
+            'totalProcessingDelay', 'jitterBufferEmittedCount',
+            CalculatorModifier.kMillisecondsFromSeconds),
+        totalAssemblyTime: new RateCalculator(
+            'totalAssemblyTime', 'framesAssembledFromMultiplePackets',
+            CalculatorModifier.kMillisecondsFromSeconds),
       },
-      {
-        type: 'remote-outbound-rtp',
-        metricCalculators: {
-          remoteTimestamp: new DateCalculator('remoteTimestamp'),
-          totalRoundTripTime:
-              new RateCalculator('totalRoundTripTime',
-                                 'roundTripTimeMeasurements'),
-        },
+      'remote-inbound-rtp': {
+        totalRoundTripTime:
+            new RateCalculator('totalRoundTripTime',
+                               'roundTripTimeMeasurements'),
       },
-      {
-        type: 'transport',
-        metricCalculators: {
-          bytesSent: new RateCalculator(
-              'bytesSent', 'timestamp', CalculatorModifier.kBytesToBits),
-          bytesReceived: new RateCalculator(
-              'bytesReceived', 'timestamp', CalculatorModifier.kBytesToBits),
-          packetsSent: new RateCalculator(
-              'packetsSent', 'timestamp'),
-          packetsReceived: new RateCalculator(
-              'packetsReceived', 'timestamp'),
-        },
+      'remote-outbound-rtp': {
+        remoteTimestamp: new DateCalculator('remoteTimestamp'),
+        totalRoundTripTime:
+            new RateCalculator('totalRoundTripTime',
+                               'roundTripTimeMeasurements'),
       },
-      {
-        type: 'candidate-pair',
-        metricCalculators: {
-          bytesSent: new RateCalculator(
-              'bytesSent', 'timestamp', CalculatorModifier.kBytesToBits),
-          bytesReceived: new RateCalculator(
-              'bytesReceived', 'timestamp', CalculatorModifier.kBytesToBits),
-          packetsSent: new RateCalculator(
-              'packetsSent', 'timestamp'),
-          packetsReceived: new RateCalculator(
-              'packetsReceived', 'timestamp'),
-          totalRoundTripTime:
-              new RateCalculator('totalRoundTripTime', 'responsesReceived'),
-          lastPacketReceivedTimestamp: new DateCalculator(
-              'lastPacketReceivedTimestamp'),
-          lastPacketSentTimestamp: new DateCalculator(
-              'lastPacketSentTimestamp'),
-        },
+      'transport': {
+        bytesSent: new RateCalculator(
+            'bytesSent', 'timestamp', CalculatorModifier.kBytesToBits),
+        bytesReceived: new RateCalculator(
+            'bytesReceived', 'timestamp', CalculatorModifier.kBytesToBits),
+        packetsSent: new RateCalculator(
+            'packetsSent', 'timestamp'),
+        packetsReceived: new RateCalculator(
+            'packetsReceived', 'timestamp'),
       },
-    ];
+      'candidate-pair': {
+        bytesSent: new RateCalculator(
+            'bytesSent', 'timestamp', CalculatorModifier.kBytesToBits),
+        bytesReceived: new RateCalculator(
+            'bytesReceived', 'timestamp', CalculatorModifier.kBytesToBits),
+        packetsSent: new RateCalculator(
+            'packetsSent', 'timestamp'),
+        packetsReceived: new RateCalculator(
+            'packetsReceived', 'timestamp'),
+        totalRoundTripTime:
+            new RateCalculator('totalRoundTripTime', 'responsesReceived'),
+        lastPacketReceivedTimestamp: new DateCalculator(
+            'lastPacketReceivedTimestamp'),
+        lastPacketSentTimestamp: new DateCalculator(
+            'lastPacketSentTimestamp'),
+      },
+    };
   }
 
   addStatsReport(report) {
@@ -661,12 +637,12 @@
   // values, such as converting total counters (e.g. bytesSent) to rates (e.g.
   // bytesSent/s).
   updateCalculatedMetrics_() {
-    this.statsCalculators.forEach(statsCalculator => {
-      this.currentReport.getByType(statsCalculator.type).forEach(stats => {
-        Object.keys(statsCalculator.metricCalculators)
+    Object.keys(this.statsCalculators).forEach(statsType => {
+      this.currentReport.getByType(statsType).forEach(stats => {
+        Object.keys(this.statsCalculators[statsType])
             .forEach(originalMetric => {
               let metricCalculators =
-                  statsCalculator.metricCalculators[originalMetric];
+                  this.statsCalculators[statsType][originalMetric];
               if (!Array.isArray(metricCalculators)) {
                 metricCalculators = [metricCalculators];
               }
diff --git a/content/renderer/accessibility/annotations/ax_image_annotator.cc b/content/renderer/accessibility/annotations/ax_image_annotator.cc
index edb9d9e..429fe9f 100644
--- a/content/renderer/accessibility/annotations/ax_image_annotator.cc
+++ b/content/renderer/accessibility/annotations/ax_image_annotator.cc
@@ -410,6 +410,12 @@
     return;
   }
 
+  if (GetImageData(src).isNull()) {
+    dst->SetImageAnnotationStatus(
+        ax::mojom::ImageAnnotationStatus::kIneligibleForAnnotation);
+    return;
+  }
+
   if (HasAnnotationInCache(src)) {
     dst->AddStringAttribute(ax::mojom::StringAttribute::kImageAnnotation,
                             GetImageAnnotation(src));
diff --git a/content/renderer/accessibility/annotations/ax_image_annotator_browsertest.cc b/content/renderer/accessibility/annotations/ax_image_annotator_browsertest.cc
index 5d75dd1..00a530e6 100644
--- a/content/renderer/accessibility/annotations/ax_image_annotator_browsertest.cc
+++ b/content/renderer/accessibility/annotations/ax_image_annotator_browsertest.cc
@@ -4,7 +4,9 @@
 
 #include "content/renderer/accessibility/annotations/ax_image_annotator.h"
 
+#include "base/strings/stringprintf.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/test/test_discardable_memory_allocator.h"
 #include "content/renderer/accessibility/annotations/ax_annotators_manager.h"
 #include "content/renderer/accessibility/render_accessibility_impl_test.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
@@ -17,6 +19,18 @@
 using blink::WebDocument;
 using testing::ElementsAre;
 
+namespace {
+
+constexpr char kImage1[] =
+    "data:imagepng;base64,"
+    "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/"
+    "w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
+constexpr char kImage2[] =
+    "data:image/png;base64,"
+    "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAIAAAACUFjqAAAACXBIWXMAAAsTAAALEwEAmpwYAA"
+    "AAB3RJTUUH4gcVABQvx8CBmAAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBk"
+    "LmUHAAAAFUlEQVQY02P8//8/A27AxIAXjFRpAKXjAxH/0Dm5AAAAAElFTkSuQmCC";
+
 class TestAXImageAnnotator : public AXImageAnnotator {
  public:
   TestAXImageAnnotator(RenderAccessibilityImpl* const render_accessibility)
@@ -85,6 +99,8 @@
   mojo::ReceiverSet<image_annotation::mojom::Annotator> receivers_;
 };
 
+}  // namespace
+
 class AXImageAnnotatorTest : public RenderAccessibilityImplTest {
  public:
   AXImageAnnotatorTest() = default;
@@ -107,10 +123,14 @@
         ->ax_annotators_manager_for_testing()
         ->AddAnnotatorForTesting(std::move(annotator));
     AXImageAnnotator::IgnoreProtocolChecksForTesting();
+    base::DiscardableMemoryAllocator::SetInstance(
+        &discardable_memory_allocator);
+
     task_environment_.RunUntilIdle();
   }
 
   void TearDown() override {
+    base::DiscardableMemoryAllocator::SetInstance(nullptr);
     GetRenderAccessibilityImpl()
         ->ax_annotators_manager_for_testing()
         ->ClearAnnotatorsForTesting();
@@ -125,6 +145,7 @@
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
   MockImageAnnotationService mock_annotator_service_;
+  base::TestDiscardableMemoryAllocator discardable_memory_allocator;
 };
 
 // TODO(crbug.com/1477047, fuchsia:132924): Reenable test on Fuchsia once
@@ -135,22 +156,24 @@
 #define MAYBE_OnImageAdded OnImageAdded
 #endif
 TEST_F(AXImageAnnotatorTest, MAYBE_OnImageAdded) {
-  LoadHTMLAndRefreshAccessibilityTree(R"HTML(
+  LoadHTMLAndRefreshAccessibilityTree(base::StringPrintf(R"HTML(
       <body>
         <p>Test document</p>
-        <img id="A" src="test1.jpg"
+        <img id="A" src="%s"
             style="width: 200px; height: 150px;">
-        <img id="B" src="test2.jpg"
+        <img id="B" src="%s"
             style="visibility: hidden; width: 200px; height: 150px;">
       </body>
-      )HTML");
+      )HTML",
+                                                         kImage1, kImage2)
+                                          .c_str());
 
   // Every time we call a method on a Mojo interface, a message is posted to the
   // current task queue. We need to ask the queue to drain itself before we
   // check test expectations.
   task_environment_.RunUntilIdle();
 
-  EXPECT_THAT(mock_annotator_service().image_ids_, ElementsAre("test1.jpg"));
+  EXPECT_THAT(mock_annotator_service().image_ids_, ElementsAre(kImage1));
   ASSERT_EQ(1u, mock_annotator_service().image_processors_.size());
   EXPECT_TRUE(mock_annotator_service().image_processors_[0].is_bound());
   EXPECT_EQ(1u, mock_annotator_service().callbacks_.size());
@@ -171,7 +194,7 @@
   SendPendingAccessibilityEvents();
 
   EXPECT_THAT(mock_annotator_service().image_ids_,
-              ElementsAre("test1.jpg", "test2.jpg", "test1.jpg", "test2.jpg"));
+              ElementsAre(kImage1, kImage2, kImage1, kImage2));
   ASSERT_EQ(4u, mock_annotator_service().image_processors_.size());
   EXPECT_TRUE(mock_annotator_service().image_processors_[0].is_bound());
   EXPECT_TRUE(mock_annotator_service().image_processors_[1].is_bound());
@@ -181,20 +204,21 @@
 }
 
 TEST_F(AXImageAnnotatorTest, OnImageUpdated) {
-  LoadHTMLAndRefreshAccessibilityTree(R"HTML(
+  LoadHTMLAndRefreshAccessibilityTree(base::StringPrintf(R"HTML(
       <body>
         <p>Test document</p>
-        <img id="A" src="test1.jpg"
-            style="width: 200px; height: 150px;">
+        <img src="%s" style="width: 200px; height: 150px;">
       </body>
-      )HTML");
+      )HTML",
+                                                         kImage1)
+                                          .c_str());
 
   // Every time we call a method on a Mojo interface, a message is posted to the
   // current task queue. We need to ask the queue to drain itself before we
   // check test expectations.
   task_environment_.RunUntilIdle();
 
-  EXPECT_THAT(mock_annotator_service().image_ids_, ElementsAre("test1.jpg"));
+  EXPECT_THAT(mock_annotator_service().image_ids_, ElementsAre(kImage1));
   ASSERT_EQ(1u, mock_annotator_service().image_processors_.size());
   EXPECT_TRUE(mock_annotator_service().image_processors_[0].is_bound());
   EXPECT_EQ(1u, mock_annotator_service().callbacks_.size());
@@ -209,24 +233,24 @@
   SendPendingAccessibilityEvents();
 
   EXPECT_THAT(mock_annotator_service().image_ids_,
-              ElementsAre("test1.jpg", "test1.jpg"));
+              ElementsAre(kImage1, kImage1));
   ASSERT_EQ(2u, mock_annotator_service().image_processors_.size());
   EXPECT_TRUE(mock_annotator_service().image_processors_[0].is_bound());
   EXPECT_TRUE(mock_annotator_service().image_processors_[1].is_bound());
   EXPECT_EQ(2u, mock_annotator_service().callbacks_.size());
 
   // Update node "A".
-  ExecuteJavaScriptForTests("document.querySelector('img').src = 'test2.jpg';");
+  ExecuteJavaScriptForTests(
+      base::StringPrintf("document.querySelector('img').src = '%s';", kImage2));
   SendPendingAccessibilityEvents();
 
   ClearHandledUpdates();
   // This should update the annotations of all images on the page, including the
   // now updated image src.
-  MarkSubtreeDirty(root_obj);
   SendPendingAccessibilityEvents();
 
   EXPECT_THAT(mock_annotator_service().image_ids_,
-              ElementsAre("test1.jpg", "test1.jpg", "test2.jpg"));
+              ElementsAre(kImage1, kImage1, kImage2));
   ASSERT_EQ(3u, mock_annotator_service().image_processors_.size());
   EXPECT_TRUE(mock_annotator_service().image_processors_[0].is_bound());
   EXPECT_TRUE(mock_annotator_service().image_processors_[1].is_bound());
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 34f755ea..679f0e1 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1668,7 +1668,6 @@
     "../browser/renderer_host/input/wheel_scroll_latching_browsertest.cc",
     "../browser/renderer_host/isolated_web_app_throttle_browsertest.cc",
     "../browser/renderer_host/jit_policy_browsertest.cc",
-    "../browser/renderer_host/local_network_access_browsertest.cc",
     "../browser/renderer_host/media/video_capture_browsertest.cc",
     "../browser/renderer_host/navigation_controller_history_intervention_browsertest.cc",
     "../browser/renderer_host/navigation_controller_impl_browsertest.cc",
@@ -1702,6 +1701,8 @@
     "../browser/screen_orientation/screen_orientation_browsertest.cc",
     "../browser/security/coop/cross_origin_opener_policy_browsertest.cc",
     "../browser/security/dip/document_isolation_policy_browsertest.cc",
+    "../browser/security/local_network_access/local_network_access_browsertest.cc",
+    "../browser/security/local_network_access/local_network_access_deprecation_browsertest.cc",
     "../browser/security_exploit_browsertest.cc",
     "../browser/serial/serial_browsertest.cc",
     "../browser/service_host/service_process_host_browsertest.cc",
diff --git a/gpu/ipc/service/arc_shared_image_interface.cc b/gpu/ipc/service/arc_shared_image_interface.cc
index 89a1568..2f12403 100644
--- a/gpu/ipc/service/arc_shared_image_interface.cc
+++ b/gpu/ipc/service/arc_shared_image_interface.cc
@@ -5,6 +5,8 @@
 #include "gpu/ipc/service/arc_shared_image_interface.h"
 
 #include "base/notimplemented.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/task/single_thread_task_runner.h"
 #include "gpu/command_buffer/client/client_shared_image.h"
 #include "gpu/command_buffer/service/shared_context_state.h"
 #include "gpu/ipc/service/gpu_channel_manager.h"
@@ -15,34 +17,74 @@
 
 // static
 scoped_refptr<ArcSharedImageInterface> ArcSharedImageInterface::Create(
-    GpuChannelManager* gpu_channel_manager) {
-  gpu::ContextResult result;
-  auto context_state = gpu_channel_manager->GetSharedContextState(&result);
+    GpuChannelManager* gpu_channel_manager,
+    scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner) {
+  scoped_refptr<ArcSharedImageInterface> arc_sii;
+  base::WaitableEvent completion(
+      base::WaitableEvent::ResetPolicy::MANUAL,
+      base::WaitableEvent::InitialState::NOT_SIGNALED);
 
-  if (!context_state) {
-    return nullptr;
+  gpu_task_runner->PostTask(
+      FROM_HERE, base::BindOnce(&ArcSharedImageInterface::CreateOnGpuThread,
+                                &arc_sii, gpu_channel_manager,
+                                std::move(gpu_task_runner), &completion));
+
+  completion.Wait();
+  return arc_sii;
+}
+
+// static
+void ArcSharedImageInterface::CreateOnGpuThread(
+    scoped_refptr<ArcSharedImageInterface>* arc_sii,
+    GpuChannelManager* gpu_channel_manager,
+    scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
+    base::WaitableEvent* completion) {
+  gpu::ContextResult result;
+  scoped_refptr<SharedContextState> context_state =
+      gpu_channel_manager->GetSharedContextState(&result);
+
+  if (context_state) {
+    *arc_sii = base::MakeRefCounted<ArcSharedImageInterface>(
+        std::make_unique<gpu::SharedImageFactory>(
+            gpu_channel_manager->gpu_preferences(),
+            gpu_channel_manager->gpu_driver_bug_workarounds(),
+            gpu_channel_manager->gpu_feature_info(), context_state.get(),
+            gpu_channel_manager->shared_image_manager(),
+            context_state->memory_tracker(),
+            /*is_for_display_compositor=*/false),
+        std::move(gpu_task_runner));
   }
 
-  return base::MakeRefCounted<gpu::ArcSharedImageInterface>(
-      std::make_unique<gpu::SharedImageFactory>(
-          gpu_channel_manager->gpu_preferences(),
-          gpu_channel_manager->gpu_driver_bug_workarounds(),
-          gpu_channel_manager->gpu_feature_info(), context_state.get(),
-          gpu_channel_manager->shared_image_manager(),
-          context_state->memory_tracker(),
-          /*is_for_display_compositor=*/false));
+  completion->Signal();
 }
 
 ArcSharedImageInterface::ArcSharedImageInterface(
-    std::unique_ptr<SharedImageFactory> shared_image_factory)
-    : shared_image_factory_(std::move(shared_image_factory)) {}
+    std::unique_ptr<SharedImageFactory> shared_image_factory,
+    scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner)
+    : shared_image_factory_(std::move(shared_image_factory)),
+      gpu_task_runner_(std::move(gpu_task_runner)) {}
 
 ArcSharedImageInterface::~ArcSharedImageInterface() {
+  base::WaitableEvent completion(
+      base::WaitableEvent::ResetPolicy::MANUAL,
+      base::WaitableEvent::InitialState::NOT_SIGNALED);
+
+  gpu_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&ArcSharedImageInterface::DestroyOnGpuThread,
+                                base::Unretained(this), &completion));
+
+  completion.Wait();
+}
+
+void ArcSharedImageInterface::DestroyOnGpuThread(
+    base::WaitableEvent* completion) {
   if (shared_image_factory_->HasImages()) {
     // Some of the backings might require a current GL context to be destroyed.
-    bool have_context = MakeContextCurrent(/*needs_gl=*/true);
+    bool have_context = MakeContextCurrentOnGpuThread(/*needs_gl=*/true);
     shared_image_factory_->DestroyAllSharedImages(have_context);
   }
+  shared_image_factory_.reset();
+  completion->Signal();
 }
 
 scoped_refptr<ClientSharedImage> ArcSharedImageInterface::CreateSharedImage(
@@ -50,6 +92,10 @@
     gpu::SurfaceHandle surface_handle,
     gfx::BufferUsage buffer_usage,
     gfx::GpuMemoryBufferHandle buffer_handle) {
+  if (encountered_error_.load(std::memory_order_relaxed)) {
+    return nullptr;
+  }
+
   auto client_buffer_handle = buffer_handle.Clone();
   auto mailbox = Mailbox::Generate();
   // Copy which can be modified.
@@ -57,8 +103,26 @@
   // Set CPU read/write usage based on buffer usage.
   si_info_copy.meta.usage |= GetCpuSIUsage(buffer_usage);
 
-  if (!MakeContextCurrent()) {
-    return nullptr;
+  gpu_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&ArcSharedImageInterface::CreateSharedImageOnGpuThread,
+                     base::Unretained(this), mailbox, si_info_copy,
+                     buffer_usage, std::move(buffer_handle)));
+
+  return base::MakeRefCounted<ClientSharedImage>(
+      mailbox, si_info_copy, gpu::SyncToken(),
+      GpuMemoryBufferHandleInfo(std::move(client_buffer_handle), buffer_usage),
+      holder_);
+}
+
+void ArcSharedImageInterface::CreateSharedImageOnGpuThread(
+    const Mailbox& mailbox,
+    const SharedImageInfo& si_info,
+    gfx::BufferUsage buffer_usage,
+    gfx::GpuMemoryBufferHandle buffer_handle) {
+  if (!MakeContextCurrentOnGpuThread()) {
+    encountered_error_.store(true, std::memory_order_relaxed);
+    return;
   }
 
   if (!shared_image_factory_->CreateSharedImage(
@@ -67,13 +131,9 @@
           si_info.meta.alpha_type, si_info.meta.usage,
           std::move(si_info.debug_label), std::move(buffer_handle))) {
     shared_image_factory_->shared_context_state()->MarkContextLost();
-    return nullptr;
+    encountered_error_.store(true, std::memory_order_relaxed);
+    return;
   }
-
-  return base::MakeRefCounted<ClientSharedImage>(
-      mailbox, si_info_copy, gpu::SyncToken(),
-      GpuMemoryBufferHandleInfo(std::move(client_buffer_handle), buffer_usage),
-      holder_);
 }
 
 void ArcSharedImageInterface::DestroySharedImage(
@@ -130,7 +190,15 @@
 }
 void ArcSharedImageInterface::DestroySharedImage(const SyncToken& sync_token,
                                                  const Mailbox& mailbox) {
-  if (!MakeContextCurrent()) {
+  gpu_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&ArcSharedImageInterface::DestroySharedImageOnGpuThread,
+                     base::Unretained(this), mailbox));
+}
+
+void ArcSharedImageInterface::DestroySharedImageOnGpuThread(
+    const Mailbox& mailbox) {
+  if (!MakeContextCurrentOnGpuThread()) {
     return;
   }
 
@@ -173,7 +241,8 @@
   NOTREACHED();
 }
 
-bool ArcSharedImageInterface::MakeContextCurrent(bool needs_gl /*=false*/) {
+bool ArcSharedImageInterface::MakeContextCurrentOnGpuThread(
+    bool needs_gl /*=false*/) {
   auto* context_state = shared_image_factory_->shared_context_state();
   if (!context_state) {
     return false;
diff --git a/gpu/ipc/service/arc_shared_image_interface.h b/gpu/ipc/service/arc_shared_image_interface.h
index e71fa9d..b0477091 100644
--- a/gpu/ipc/service/arc_shared_image_interface.h
+++ b/gpu/ipc/service/arc_shared_image_interface.h
@@ -5,10 +5,17 @@
 #ifndef GPU_IPC_SERVICE_ARC_SHARED_IMAGE_INTERFACE_H_
 #define GPU_IPC_SERVICE_ARC_SHARED_IMAGE_INTERFACE_H_
 
+#include <atomic>
+
+#include "base/task/single_thread_task_runner.h"
 #include "gpu/command_buffer/client/shared_image_interface.h"
 #include "gpu/command_buffer/service/shared_image/shared_image_factory.h"
 #include "gpu/ipc/service/gpu_ipc_service_export.h"
 
+namespace base {
+class WaitableEvent;
+}
+
 namespace gpu {
 
 class GpuChannelManager;
@@ -19,10 +26,12 @@
     : public SharedImageInterface {
  public:
   static scoped_refptr<ArcSharedImageInterface> Create(
-      GpuChannelManager* gpu_channel_manager);
+      GpuChannelManager* gpu_channel_manager,
+      scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner);
 
-  explicit ArcSharedImageInterface(
-      std::unique_ptr<SharedImageFactory> shared_image_factory);
+  ArcSharedImageInterface(
+      std::unique_ptr<SharedImageFactory> shared_image_factory,
+      scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner);
 
   ArcSharedImageInterface(const ArcSharedImageInterface&) = delete;
   ArcSharedImageInterface& operator=(const ArcSharedImageInterface&) = delete;
@@ -86,9 +95,22 @@
  private:
   ~ArcSharedImageInterface() override;
 
-  bool MakeContextCurrent(bool needs_gl = false);
+  static void CreateOnGpuThread(
+      scoped_refptr<ArcSharedImageInterface>* arc_sii,
+      GpuChannelManager* gpu_channel_manager,
+      scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
+      base::WaitableEvent* completion);
+  void DestroyOnGpuThread(base::WaitableEvent* completion);
+  void CreateSharedImageOnGpuThread(const Mailbox& mailbox,
+                                    const SharedImageInfo& si_info,
+                                    gfx::BufferUsage buffer_usage,
+                                    gfx::GpuMemoryBufferHandle buffer_handle);
+  void DestroySharedImageOnGpuThread(const Mailbox& mailbox);
+  bool MakeContextCurrentOnGpuThread(bool needs_gl = false);
 
   std::unique_ptr<gpu::SharedImageFactory> shared_image_factory_;
+  scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_;
+  std::atomic_bool encountered_error_{false};
 };
 
 }  // namespace gpu
diff --git a/internal b/internal
index ee7ed772..5b3a093 160000
--- a/internal
+++ b/internal
@@ -1 +1 @@
-Subproject commit ee7ed7723eb64518a8ca03d91fd4041e3a319574
+Subproject commit 5b3a0932dc6e77ec5474737c28832c127f9eba80
diff --git a/ios/chrome/browser/authentication/ui_bundled/account_menu/account_menu_coordinator_unittests.mm b/ios/chrome/browser/authentication/ui_bundled/account_menu/account_menu_coordinator_unittests.mm
index ca754a9..403182c 100644
--- a/ios/chrome/browser/authentication/ui_bundled/account_menu/account_menu_coordinator_unittests.mm
+++ b/ios/chrome/browser/authentication/ui_bundled/account_menu/account_menu_coordinator_unittests.mm
@@ -71,10 +71,15 @@
 
 @end
 
-// Base class for `AccountMenuCoordinatorNonManagedTest` and
-// `AccountMenuCoordinatorManagedTest`.
-class AccountMenuCoordinatorTest : public PlatformTest {
+// The test param determines whether `kSeparateProfilesForManagedAccounts` is
+// enabled.
+class AccountMenuCoordinatorTest : public PlatformTest,
+                                   public testing::WithParamInterface<bool> {
  public:
+  AccountMenuCoordinatorTest() {
+    feature_list_.InitWithFeatureState(kSeparateProfilesForManagedAccounts,
+                                       GetParam());
+  }
   void SetUp() override {
     PlatformTest::SetUp();
     scene_state_ = [[SceneState alloc] initWithAppState:nil];
@@ -157,8 +162,6 @@
     PlatformTest::TearDown();
   }
 
-  virtual const FakeSystemIdentity* primary_identity() = 0;
-
  protected:
   void VerifyMock() {
     EXPECT_OCMOCK_VERIFY((id)presentation_delegate_);
@@ -213,10 +216,10 @@
     coordinator_ = nil;
   }
 
-  // Signs in primary_identity() as primary identity.
+  // Signs in kPrimaryIdentity as primary identity.
   void SigninWithPrimaryIdentity() {
-    fake_system_identity_manager_->AddIdentity(primary_identity());
-    authentication_service_->SignIn(primary_identity(),
+    fake_system_identity_manager_->AddIdentity(kPrimaryIdentity);
+    authentication_service_->SignIn(kPrimaryIdentity,
                                     signin_metrics::AccessPoint::kUnknown);
   }
 
@@ -232,39 +235,11 @@
   std::unique_ptr<TestBrowser> browser_;
 };
 
-// The test param determines whether `kSeparateProfilesForManagedAccounts` is
-// enabled.
-class AccountMenuCoordinatorNonManagedTest
-    : public AccountMenuCoordinatorTest,
-      public testing::WithParamInterface<bool> {
- public:
-  AccountMenuCoordinatorNonManagedTest() {
-    feature_list_.InitWithFeatureState(kSeparateProfilesForManagedAccounts,
-                                       GetParam());
-  }
-  const FakeSystemIdentity* primary_identity() override {
-    return kPrimaryIdentity;
-  }
-};
-
-class AccountMenuCoordinatorManagedTest : public AccountMenuCoordinatorTest {
- public:
-  AccountMenuCoordinatorManagedTest() {
-    // TODO(crbug.com/374281861): This class needs to run with multi profile
-    // enabled. To do that, account switching needs to be supported in unttests.
-    feature_list_.InitWithFeatureState(kSeparateProfilesForManagedAccounts,
-                                       false);
-  }
-  const FakeSystemIdentity* primary_identity() override {
-    return kManagedIdentity;
-  }
-};
-
 #pragma mark - AccountMenuMediatorDelegate
 
 // Tests that `didTapManageYourGoogleAccount` requests the view controller to
 // present a view.
-TEST_P(AccountMenuCoordinatorNonManagedTest, testManageYourGoogleAccount) {
+TEST_P(AccountMenuCoordinatorTest, testManageYourGoogleAccount) {
   OCMExpect([view_controller_ presentViewController:[OCMArg any]
                                            animated:YES
                                          completion:nil]);
@@ -274,14 +249,14 @@
 
 // Tests that `didTapManageAccounts` has no impact on the view controller and
 // mediator.
-TEST_P(AccountMenuCoordinatorNonManagedTest, testEditAccountList) {
+TEST_P(AccountMenuCoordinatorTest, testEditAccountList) {
   [coordinator_ didTapManageAccounts];
   AssertOpenAndStop();
 }
 
 // Tests that `signOutFromTargetRect` requests the delegate to be stopped and
 // shows a snackbar and calls its completion.
-TEST_P(AccountMenuCoordinatorNonManagedTest, testSignOut) {
+TEST_P(AccountMenuCoordinatorTest, testSignOut) {
   base::RunLoop run_loop;
   base::RepeatingClosure closure = run_loop.QuitClosure();
   CGRect rect = CGRect();
@@ -301,13 +276,13 @@
 
 // Tests that `mediatorWantsToBeDismissed` requests to the delegate to stop the
 // coordinator.
-TEST_P(AccountMenuCoordinatorNonManagedTest, testMediatorWantsToBeDismissed) {
+TEST_P(AccountMenuCoordinatorTest, testMediatorWantsToBeDismissed) {
   AssertOpenAndStop();
 }
 
 // Tests that `triggerSignoutWithTargetRect` calls its
 // callback.
-TEST_P(AccountMenuCoordinatorNonManagedTest, testTriggerSignout) {
+TEST_P(AccountMenuCoordinatorTest, testTriggerSignout) {
   OCMExpect([mock_snackbar_commands_handler_
       showCustomSnackbarMessageOverBrowserToolbar:[OCMArg any]]);
 
@@ -329,7 +304,7 @@
 // view controller and mediator. Tests also that the
 // `SyncEncryptionPassphraseTableViewController` is allocated, and the view is
 // correctly closed when the coordinator is stopped.
-TEST_P(AccountMenuCoordinatorNonManagedTest, testPassphrase) {
+TEST_P(AccountMenuCoordinatorTest, testPassphrase) {
   SyncEncryptionPassphraseTableViewController* passphraseViewController =
       [SyncEncryptionPassphraseTableViewController alloc];
   passphraseViewController.presentationDelegate = presentation_delegate_;
@@ -343,27 +318,27 @@
 
 // Tests that `openTrustedVaultReauthForFetchKeys` calls
 // `showTrustedVaultReauthForFetchKeysFromViewController`.
-TEST_P(AccountMenuCoordinatorNonManagedTest, testFetchKeys) {
+TEST_P(AccountMenuCoordinatorTest, testFetchKeys) {
   [coordinator_ openTrustedVaultReauthForFetchKeys];
   AssertOpenAndStop();
 }
 
 // Tests that `openTrustedVaultReauthForDegradedRecoverability` calls
 // `showTrustedVaultReauthForDegradedRecoverabilityFromViewController`.
-TEST_P(AccountMenuCoordinatorNonManagedTest, testDegradedRecoverability) {
+TEST_P(AccountMenuCoordinatorTest, testDegradedRecoverability) {
   [coordinator_ openTrustedVaultReauthForDegradedRecoverability];
   AssertOpenAndStop();
 }
 
 // Tests that `openMDMErrodDialogWithSystemIdentity` has no effects on the
 // mediator and view controller.
-TEST_P(AccountMenuCoordinatorNonManagedTest, testMDMError) {
+TEST_P(AccountMenuCoordinatorTest, testMDMError) {
   [coordinator_ openMDMErrodDialogWithSystemIdentity:kPrimaryIdentity];
   AssertOpenAndStop();
 }
 
 INSTANTIATE_TEST_SUITE_P(,
-                         AccountMenuCoordinatorNonManagedTest,
+                         AccountMenuCoordinatorTest,
                          testing::Bool(),
                          [](const testing::TestParamInfo<bool>& info) {
                            return info.param ? "WithSeparateProfiles"
diff --git a/ios/chrome/browser/autocomplete/model/autocomplete_classifier_factory.cc b/ios/chrome/browser/autocomplete/model/autocomplete_classifier_factory.cc
index 3f0ed26..e8de61f06 100644
--- a/ios/chrome/browser/autocomplete/model/autocomplete_classifier_factory.cc
+++ b/ios/chrome/browser/autocomplete/model/autocomplete_classifier_factory.cc
@@ -19,14 +19,12 @@
 namespace ios {
 namespace {
 
-std::unique_ptr<KeyedService> BuildAutocompleteClassifier(
-    web::BrowserState* context) {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
+std::unique_ptr<KeyedService> BuildAutocompleteClassifier(ProfileIOS* profile) {
   return std::make_unique<AutocompleteClassifier>(
-      base::WrapUnique(new AutocompleteController(
-          base::WrapUnique(new AutocompleteProviderClientImpl(profile)),
-          AutocompleteClassifier::DefaultOmniboxProviders())),
-      base::WrapUnique(new AutocompleteSchemeClassifierImpl));
+      std::make_unique<AutocompleteController>(
+          std::make_unique<AutocompleteProviderClientImpl>(profile),
+          AutocompleteClassifier::DefaultOmniboxProviders()),
+      std::make_unique<AutocompleteSchemeClassifierImpl>());
 }
 
 }  // namespace
@@ -45,9 +43,9 @@
 }
 
 // static
-ProfileKeyedServiceFactoryIOS::TestingFactory
+ProfileKeyedServiceFactoryIOS::ProfileTestingFactory
 AutocompleteClassifierFactory::GetDefaultFactory() {
-  return base::BindRepeating(&BuildAutocompleteClassifier);
+  return base::BindOnce(&BuildAutocompleteClassifier);
 }
 
 AutocompleteClassifierFactory::AutocompleteClassifierFactory()
@@ -63,8 +61,8 @@
 
 std::unique_ptr<KeyedService>
 AutocompleteClassifierFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  return BuildAutocompleteClassifier(context);
+    ProfileIOS* profile) const {
+  return BuildAutocompleteClassifier(profile);
 }
 
 }  // namespace ios
diff --git a/ios/chrome/browser/autocomplete/model/autocomplete_classifier_factory.h b/ios/chrome/browser/autocomplete/model/autocomplete_classifier_factory.h
index 30ead1f..42004cb89 100644
--- a/ios/chrome/browser/autocomplete/model/autocomplete_classifier_factory.h
+++ b/ios/chrome/browser/autocomplete/model/autocomplete_classifier_factory.h
@@ -24,7 +24,7 @@
 
   // Returns the default factory used to build AutocompleteClassifiers. Can be
   // registered with AddTestingFactory to use real instances during testing.
-  static TestingFactory GetDefaultFactory();
+  static ProfileTestingFactory GetDefaultFactory();
 
  private:
   friend class base::NoDestructor<AutocompleteClassifierFactory>;
@@ -32,9 +32,9 @@
   AutocompleteClassifierFactory();
   ~AutocompleteClassifierFactory() override;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 }  // namespace ios
diff --git a/ios/chrome/browser/autocomplete/model/autocomplete_scoring_model_service_factory.h b/ios/chrome/browser/autocomplete/model/autocomplete_scoring_model_service_factory.h
index fbb58fd..d237b8f 100644
--- a/ios/chrome/browser/autocomplete/model/autocomplete_scoring_model_service_factory.h
+++ b/ios/chrome/browser/autocomplete/model/autocomplete_scoring_model_service_factory.h
@@ -28,10 +28,10 @@
   AutocompleteScoringModelServiceFactory();
   ~AutocompleteScoringModelServiceFactory() override;
 
-  // BrowserStateKeyedServiceFactory:
+  // ProfileKeyedServiceFactoryIOS:
   // Returns nullptr if `OptimizationGuideKeyedService` is null.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 }  // namespace ios
diff --git a/ios/chrome/browser/autocomplete/model/autocomplete_scoring_model_service_factory.mm b/ios/chrome/browser/autocomplete/model/autocomplete_scoring_model_service_factory.mm
index 98b0353..8d9c6c4 100644
--- a/ios/chrome/browser/autocomplete/model/autocomplete_scoring_model_service_factory.mm
+++ b/ios/chrome/browser/autocomplete/model/autocomplete_scoring_model_service_factory.mm
@@ -37,8 +37,7 @@
 
 std::unique_ptr<KeyedService>
 AutocompleteScoringModelServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
+    ProfileIOS* profile) const {
   OptimizationGuideService* optimization_guide =
       OptimizationGuideServiceFactory::GetForProfile(profile);
   return optimization_guide ? std::make_unique<AutocompleteScoringModelService>(
diff --git a/ios/chrome/browser/autocomplete/model/in_memory_url_index_factory.cc b/ios/chrome/browser/autocomplete/model/in_memory_url_index_factory.cc
index 5769a1e..3341dbd1 100644
--- a/ios/chrome/browser/autocomplete/model/in_memory_url_index_factory.cc
+++ b/ios/chrome/browser/autocomplete/model/in_memory_url_index_factory.cc
@@ -21,10 +21,7 @@
 
 namespace {
 
-std::unique_ptr<KeyedService> BuildInMemoryURLIndex(
-    web::BrowserState* context) {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
-
+std::unique_ptr<KeyedService> BuildInMemoryURLIndex(ProfileIOS* profile) {
   SchemeSet allowed_schemes;
   allowed_schemes.insert(kChromeUIScheme);
 
@@ -65,14 +62,14 @@
 InMemoryURLIndexFactory::~InMemoryURLIndexFactory() = default;
 
 // static
-ProfileKeyedServiceFactoryIOS::TestingFactory
+ProfileKeyedServiceFactoryIOS::ProfileTestingFactory
 InMemoryURLIndexFactory::GetDefaultFactory() {
-  return base::BindRepeating(&BuildInMemoryURLIndex);
+  return base::BindOnce(&BuildInMemoryURLIndex);
 }
 
 std::unique_ptr<KeyedService> InMemoryURLIndexFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  return BuildInMemoryURLIndex(context);
+    ProfileIOS* profile) const {
+  return BuildInMemoryURLIndex(profile);
 }
 
 }  // namespace ios
diff --git a/ios/chrome/browser/autocomplete/model/in_memory_url_index_factory.h b/ios/chrome/browser/autocomplete/model/in_memory_url_index_factory.h
index 8c8a66d..1d51ede8 100644
--- a/ios/chrome/browser/autocomplete/model/in_memory_url_index_factory.h
+++ b/ios/chrome/browser/autocomplete/model/in_memory_url_index_factory.h
@@ -23,7 +23,7 @@
 
   // Returns the default factory used to build InMemoryURLIndexes. Can be
   // registered with AddTestingFactory to use real instances during testing.
-  static TestingFactory GetDefaultFactory();
+  static ProfileTestingFactory GetDefaultFactory();
 
  private:
   friend class base::NoDestructor<InMemoryURLIndexFactory>;
@@ -31,9 +31,9 @@
   InMemoryURLIndexFactory();
   ~InMemoryURLIndexFactory() override;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 }  // namespace ios
diff --git a/ios/chrome/browser/autocomplete/model/on_device_tail_model_service_factory.h b/ios/chrome/browser/autocomplete/model/on_device_tail_model_service_factory.h
index 047c16e..a2781ff 100644
--- a/ios/chrome/browser/autocomplete/model/on_device_tail_model_service_factory.h
+++ b/ios/chrome/browser/autocomplete/model/on_device_tail_model_service_factory.h
@@ -34,7 +34,7 @@
   //
   // Returns nullptr if `OptimizationGuideKeyedService` is null.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_AUTOCOMPLETE_MODEL_ON_DEVICE_TAIL_MODEL_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/autocomplete/model/on_device_tail_model_service_factory.mm b/ios/chrome/browser/autocomplete/model/on_device_tail_model_service_factory.mm
index 3d320fb..da560db3 100644
--- a/ios/chrome/browser/autocomplete/model/on_device_tail_model_service_factory.mm
+++ b/ios/chrome/browser/autocomplete/model/on_device_tail_model_service_factory.mm
@@ -40,13 +40,12 @@
 
 std::unique_ptr<KeyedService>
 OnDeviceTailModelServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
+    ProfileIOS* profile) const {
   const std::string locale =
       GetApplicationContext()->GetApplicationLocaleStorage()->Get();
   if (!OmniboxFieldTrial::IsOnDeviceTailSuggestEnabled(locale)) {
     return nullptr;
   }
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
   OptimizationGuideService* optimization_guide =
       OptimizationGuideServiceFactory::GetForProfile(profile);
   return optimization_guide
diff --git a/ios/chrome/browser/autocomplete/model/provider_state_service_factory.h b/ios/chrome/browser/autocomplete/model/provider_state_service_factory.h
index f3f4d5a..4aeaae19 100644
--- a/ios/chrome/browser/autocomplete/model/provider_state_service_factory.h
+++ b/ios/chrome/browser/autocomplete/model/provider_state_service_factory.h
@@ -27,9 +27,9 @@
   ProviderStateServiceFactory();
   ~ProviderStateServiceFactory() override;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 }  // namespace ios
diff --git a/ios/chrome/browser/autocomplete/model/provider_state_service_factory.mm b/ios/chrome/browser/autocomplete/model/provider_state_service_factory.mm
index 4077fc31..56230b17 100644
--- a/ios/chrome/browser/autocomplete/model/provider_state_service_factory.mm
+++ b/ios/chrome/browser/autocomplete/model/provider_state_service_factory.mm
@@ -29,7 +29,7 @@
 
 std::unique_ptr<KeyedService>
 ProviderStateServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
+    ProfileIOS* profile) const {
   return std::make_unique<ProviderStateService>();
 }
 
diff --git a/ios/chrome/browser/autocomplete/model/remote_suggestions_service_factory.h b/ios/chrome/browser/autocomplete/model/remote_suggestions_service_factory.h
index 44cdf306..9a353aad 100644
--- a/ios/chrome/browser/autocomplete/model/remote_suggestions_service_factory.h
+++ b/ios/chrome/browser/autocomplete/model/remote_suggestions_service_factory.h
@@ -25,9 +25,9 @@
   RemoteSuggestionsServiceFactory();
   ~RemoteSuggestionsServiceFactory() override;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_AUTOCOMPLETE_MODEL_REMOTE_SUGGESTIONS_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/autocomplete/model/remote_suggestions_service_factory.mm b/ios/chrome/browser/autocomplete/model/remote_suggestions_service_factory.mm
index 4fe5928..da94b530 100644
--- a/ios/chrome/browser/autocomplete/model/remote_suggestions_service_factory.mm
+++ b/ios/chrome/browser/autocomplete/model/remote_suggestions_service_factory.mm
@@ -26,8 +26,7 @@
 
 std::unique_ptr<KeyedService>
 RemoteSuggestionsServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
+    ProfileIOS* profile) const {
   return std::make_unique<RemoteSuggestionsService>(
       /*document_suggestions_service=*/nullptr,
       /*enterprise_search_aggregator_suggestions_service=*/nullptr,
diff --git a/ios/chrome/browser/autocomplete/model/shortcuts_backend_factory.h b/ios/chrome/browser/autocomplete/model/shortcuts_backend_factory.h
index 4e88299..468a6f732 100644
--- a/ios/chrome/browser/autocomplete/model/shortcuts_backend_factory.h
+++ b/ios/chrome/browser/autocomplete/model/shortcuts_backend_factory.h
@@ -22,7 +22,7 @@
       ProfileIOS* profile);
   static ShortcutsBackendFactory* GetInstance();
   // Returns the default factory, useful in tests where it's null by default.
-  static TestingFactory GetDefaultFactory();
+  static ProfileTestingFactory GetDefaultFactory();
 
  private:
   friend class base::NoDestructor<ShortcutsBackendFactory>;
@@ -30,9 +30,9 @@
   ShortcutsBackendFactory();
   ~ShortcutsBackendFactory() override;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // RefcountedProfileKeyedServiceFactoryIOS implementation.
   scoped_refptr<RefcountedKeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 }  // namespace ios
diff --git a/ios/chrome/browser/autocomplete/model/shortcuts_backend_factory.mm b/ios/chrome/browser/autocomplete/model/shortcuts_backend_factory.mm
index dd5edc61..fcca20cd 100644
--- a/ios/chrome/browser/autocomplete/model/shortcuts_backend_factory.mm
+++ b/ios/chrome/browser/autocomplete/model/shortcuts_backend_factory.mm
@@ -31,8 +31,7 @@
 }
 
 scoped_refptr<RefcountedKeyedService> BuildShortcutsBackend(
-    web::BrowserState* context) {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
+    ProfileIOS* profile) {
   return CreateShortcutsBackend(profile, /*suppress_db=*/false);
 }
 
@@ -59,9 +58,9 @@
 }
 
 // static
-ShortcutsBackendFactory::TestingFactory
+ShortcutsBackendFactory::ProfileTestingFactory
 ShortcutsBackendFactory::GetDefaultFactory() {
-  return base::BindRepeating(&BuildShortcutsBackend);
+  return base::BindOnce(&BuildShortcutsBackend);
 }
 
 ShortcutsBackendFactory::ShortcutsBackendFactory()
@@ -75,9 +74,8 @@
 ShortcutsBackendFactory::~ShortcutsBackendFactory() {}
 
 scoped_refptr<RefcountedKeyedService>
-ShortcutsBackendFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  return BuildShortcutsBackend(context);
+ShortcutsBackendFactory::BuildServiceInstanceFor(ProfileIOS* profile) const {
+  return BuildShortcutsBackend(profile);
 }
 
 }  // namespace ios
diff --git a/ios/chrome/browser/autocomplete/model/zero_suggest_cache_service_factory.cc b/ios/chrome/browser/autocomplete/model/zero_suggest_cache_service_factory.cc
index a6f2895..59d6952 100644
--- a/ios/chrome/browser/autocomplete/model/zero_suggest_cache_service_factory.cc
+++ b/ios/chrome/browser/autocomplete/model/zero_suggest_cache_service_factory.cc
@@ -32,8 +32,7 @@
 
 std::unique_ptr<KeyedService>
 ZeroSuggestCacheServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
+    ProfileIOS* profile) const {
   return std::make_unique<ZeroSuggestCacheService>(
       std::make_unique<AutocompleteSchemeClassifierImpl>(), profile->GetPrefs(),
       OmniboxFieldTrial::kZeroSuggestCacheMaxSize.Get());
diff --git a/ios/chrome/browser/autocomplete/model/zero_suggest_cache_service_factory.h b/ios/chrome/browser/autocomplete/model/zero_suggest_cache_service_factory.h
index ac11385..ec8b6648 100644
--- a/ios/chrome/browser/autocomplete/model/zero_suggest_cache_service_factory.h
+++ b/ios/chrome/browser/autocomplete/model/zero_suggest_cache_service_factory.h
@@ -18,9 +18,6 @@
  public:
   static ZeroSuggestCacheService* GetForProfile(ProfileIOS* profile);
   static ZeroSuggestCacheServiceFactory* GetInstance();
-  // Returns the default factory used to build ZeroSuggestCacheService. Can be
-  // registered with AddTestingFactory to use real instances during testing.
-  static TestingFactory GetDefaultFactory();
 
  private:
   friend class base::NoDestructor<ZeroSuggestCacheServiceFactory>;
@@ -30,7 +27,7 @@
 
   // BrowerStateKeyedServiceFactory implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 }  // namespace ios
 
diff --git a/ios/chrome/browser/autofill/ui_bundled/manual_fill/card_view_controller_egtest.mm b/ios/chrome/browser/autofill/ui_bundled/manual_fill/card_view_controller_egtest.mm
index df45724..5542680 100644
--- a/ios/chrome/browser/autofill/ui_bundled/manual_fill/card_view_controller_egtest.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/manual_fill/card_view_controller_egtest.mm
@@ -724,6 +724,10 @@
   if (base::ios::IsRunningOnIOS17OrLater() && [ChromeEarlGrey isIPadIdiom]) {
     EARL_GREY_TEST_DISABLED(@"Fails on iOS 17 iPad simulator.");
   }
+  // TODO(crbug.com/443204278): Fails on iOS 26 simulator.
+  if (base::ios::IsRunningOnIOS26OrLater()) {
+    EARL_GREY_TEST_DISABLED(@"Test disabled on iOS 26.");
+  }
   [AutofillAppInterface saveLocalCreditCard];
 
   // Bring up the keyboard.
diff --git a/ios/chrome/browser/bookmarks/ui_bundled/editor/BUILD.gn b/ios/chrome/browser/bookmarks/ui_bundled/editor/BUILD.gn
index 923073b..7ac9af3 100644
--- a/ios/chrome/browser/bookmarks/ui_bundled/editor/BUILD.gn
+++ b/ios/chrome/browser/bookmarks/ui_bundled/editor/BUILD.gn
@@ -28,11 +28,11 @@
     "//ios/chrome/browser/shared/model/prefs:pref_names",
     "//ios/chrome/browser/shared/model/profile",
     "//ios/chrome/browser/shared/public/commands",
+    "//ios/chrome/browser/shared/public/snackbar",
     "//ios/chrome/browser/shared/ui/table_view",
     "//ios/chrome/browser/signin/model:authentication_service",
     "//ios/chrome/browser/signin/model:authentication_service_factory",
     "//ios/chrome/browser/sync/model",
-    "//ios/third_party/material_components_ios",
     "//ui/base",
     "//url",
   ]
diff --git a/ios/chrome/browser/bookmarks/ui_bundled/editor/bookmarks_editor_coordinator.mm b/ios/chrome/browser/bookmarks/ui_bundled/editor/bookmarks_editor_coordinator.mm
index 6efc06d..cd76d92 100644
--- a/ios/chrome/browser/bookmarks/ui_bundled/editor/bookmarks_editor_coordinator.mm
+++ b/ios/chrome/browser/bookmarks/ui_bundled/editor/bookmarks_editor_coordinator.mm
@@ -4,8 +4,6 @@
 
 #import "ios/chrome/browser/bookmarks/ui_bundled/editor/bookmarks_editor_coordinator.h"
 
-#import <MaterialComponents/MaterialSnackbar.h>
-
 #import "base/memory/raw_ptr.h"
 #import "base/metrics/user_metrics.h"
 #import "base/metrics/user_metrics_action.h"
diff --git a/ios/chrome/browser/bookmarks/ui_bundled/editor/bookmarks_editor_mediator_delegate.h b/ios/chrome/browser/bookmarks/ui_bundled/editor/bookmarks_editor_mediator_delegate.h
index da3f4cb..99e2d625 100644
--- a/ios/chrome/browser/bookmarks/ui_bundled/editor/bookmarks_editor_mediator_delegate.h
+++ b/ios/chrome/browser/bookmarks/ui_bundled/editor/bookmarks_editor_mediator_delegate.h
@@ -8,7 +8,6 @@
 #import <UIKit/UIKit.h>
 
 @class BookmarksEditorMediator;
-@class MDCSnackbarMessage;
 
 // Delegate allowing the bookmarks editor mediator to update the coordinator if
 // needed.
diff --git a/ios/chrome/browser/browsing_data/model/browsing_data_remover_factory.h b/ios/chrome/browser/browsing_data/model/browsing_data_remover_factory.h
index 1d03361..8e81fa9 100644
--- a/ios/chrome/browser/browsing_data/model/browsing_data_remover_factory.h
+++ b/ios/chrome/browser/browsing_data/model/browsing_data_remover_factory.h
@@ -27,9 +27,9 @@
   BrowsingDataRemoverFactory();
   ~BrowsingDataRemoverFactory() override;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_BROWSING_DATA_MODEL_BROWSING_DATA_REMOVER_FACTORY_H_
diff --git a/ios/chrome/browser/browsing_data/model/browsing_data_remover_factory.mm b/ios/chrome/browser/browsing_data/model/browsing_data_remover_factory.mm
index 01563d3..0df6e35c9 100644
--- a/ios/chrome/browser/browsing_data/model/browsing_data_remover_factory.mm
+++ b/ios/chrome/browser/browsing_data/model/browsing_data_remover_factory.mm
@@ -38,10 +38,8 @@
 BrowsingDataRemoverFactory::~BrowsingDataRemoverFactory() = default;
 
 std::unique_ptr<KeyedService>
-BrowsingDataRemoverFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
+BrowsingDataRemoverFactory::BuildServiceInstanceFor(ProfileIOS* profile) const {
   // TODO(crbug.com/40940855): the factory should declare the services
   // used by BrowsingDataRemoverImpl and inject them in the constructor.
-  return std::make_unique<BrowsingDataRemoverImpl>(
-      ProfileIOS::FromBrowserState(context));
+  return std::make_unique<BrowsingDataRemoverImpl>(profile);
 }
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/magic_stack/magic_stack_ranking_model_unittest.mm b/ios/chrome/browser/content_suggestions/ui_bundled/magic_stack/magic_stack_ranking_model_unittest.mm
index b4e63bf2..cc6857c 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/magic_stack/magic_stack_ranking_model_unittest.mm
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/magic_stack/magic_stack_ranking_model_unittest.mm
@@ -400,10 +400,9 @@
     PlatformTest::TearDown();
   }
 
-  web::BrowserState* SetUpEnvironment(web::BrowserState* context) {
-    ProfileIOS* setup_profile = ProfileIOS::FromBrowserState(context);
-    segmentation_test_utils_->SetupForProfile(setup_profile);
-    return context;
+  ProfileIOS* SetUpEnvironment(ProfileIOS* profile) {
+    segmentation_test_utils_->SetupForProfile(profile);
+    return profile;
   }
 
   ProfileIOS* GetProfile() { return profile_.get(); }
diff --git a/ios/chrome/browser/contextual_panel/sample/model/sample_panel_model_factory.h b/ios/chrome/browser/contextual_panel/sample/model/sample_panel_model_factory.h
index e4b00c0..9e7cae3 100644
--- a/ios/chrome/browser/contextual_panel/sample/model/sample_panel_model_factory.h
+++ b/ios/chrome/browser/contextual_panel/sample/model/sample_panel_model_factory.h
@@ -23,9 +23,9 @@
   SamplePanelModelFactory();
   ~SamplePanelModelFactory() override;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_CONTEXTUAL_PANEL_SAMPLE_MODEL_SAMPLE_PANEL_MODEL_FACTORY_H_
diff --git a/ios/chrome/browser/contextual_panel/sample/model/sample_panel_model_factory.mm b/ios/chrome/browser/contextual_panel/sample/model/sample_panel_model_factory.mm
index f1afefb..75cfc998 100644
--- a/ios/chrome/browser/contextual_panel/sample/model/sample_panel_model_factory.mm
+++ b/ios/chrome/browser/contextual_panel/sample/model/sample_panel_model_factory.mm
@@ -26,6 +26,6 @@
 SamplePanelModelFactory::~SamplePanelModelFactory() {}
 
 std::unique_ptr<KeyedService> SamplePanelModelFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
+    ProfileIOS* profile) const {
   return std::make_unique<SamplePanelModel>();
 }
diff --git a/ios/chrome/browser/discover_feed/model/discover_feed_service_factory.h b/ios/chrome/browser/discover_feed/model/discover_feed_service_factory.h
index 92a1295..8cf26910 100644
--- a/ios/chrome/browser/discover_feed/model/discover_feed_service_factory.h
+++ b/ios/chrome/browser/discover_feed/model/discover_feed_service_factory.h
@@ -26,9 +26,9 @@
   DiscoverFeedServiceFactory();
   ~DiscoverFeedServiceFactory() override;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_DISCOVER_FEED_MODEL_DISCOVER_FEED_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/discover_feed/model/discover_feed_service_factory.mm b/ios/chrome/browser/discover_feed/model/discover_feed_service_factory.mm
index fae40e74..644518d 100644
--- a/ios/chrome/browser/discover_feed/model/discover_feed_service_factory.mm
+++ b/ios/chrome/browser/discover_feed/model/discover_feed_service_factory.mm
@@ -47,10 +47,7 @@
 DiscoverFeedServiceFactory::~DiscoverFeedServiceFactory() = default;
 
 std::unique_ptr<KeyedService>
-DiscoverFeedServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
-
+DiscoverFeedServiceFactory::BuildServiceInstanceFor(ProfileIOS* profile) const {
   DiscoverFeedConfiguration* configuration =
       [[DiscoverFeedConfiguration alloc] init];
   configuration.profilePrefService = profile->GetPrefs();
diff --git a/ios/chrome/browser/download/model/background_service/background_download_service_factory.cc b/ios/chrome/browser/download/model/background_service/background_download_service_factory.cc
index b5aa7c6c..de5bb05a 100644
--- a/ios/chrome/browser/download/model/background_service/background_download_service_factory.cc
+++ b/ios/chrome/browser/download/model/background_service/background_download_service_factory.cc
@@ -61,31 +61,31 @@
 
 std::unique_ptr<KeyedService>
 BackgroundDownloadServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  DCHECK(!context->IsOffTheRecord());
+    ProfileIOS* profile) const {
+  DCHECK(!profile->IsOffTheRecord());
   auto clients = std::make_unique<download::DownloadClientMap>();
   // Clients should be registered here.
   auto prediction_model_download_client =
       std::make_unique<optimization_guide::PredictionModelDownloadClient>(
-          ProfileIOS::FromBrowserState(context));
+          profile);
   clients->insert(std::make_pair(
       download::DownloadClient::OPTIMIZATION_GUIDE_PREDICTION_MODELS,
       std::move(prediction_model_download_client)));
 
-  return BuildServiceWithClients(context, std::move(clients));
+  return BuildServiceWithClients(profile, std::move(clients));
 }
 
 std::unique_ptr<KeyedService>
 BackgroundDownloadServiceFactory::BuildServiceWithClients(
-    web::BrowserState* context,
+    ProfileIOS* profile,
     std::unique_ptr<download::DownloadClientMap> clients) const {
   auto client_set = std::make_unique<download::ClientSet>(std::move(clients));
   base::FilePath storage_dir =
-      context->GetStatePath().Append(kDownloadServiceStorageDir);
+      profile->GetStatePath().Append(kDownloadServiceStorageDir);
   scoped_refptr<base::SequencedTaskRunner> background_task_runner =
       base::ThreadPool::CreateSequencedTaskRunner(
           {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
-  auto entry_db = context->GetProtoDatabaseProvider()->GetDB<protodb::Entry>(
+  auto entry_db = profile->GetProtoDatabaseProvider()->GetDB<protodb::Entry>(
       leveldb_proto::ProtoDbType::DOWNLOAD_STORE,
       storage_dir.Append(kEntryDBStorageDir), background_task_runner);
   auto store = std::make_unique<download::DownloadStore>(std::move(entry_db));
diff --git a/ios/chrome/browser/download/model/background_service/background_download_service_factory.h b/ios/chrome/browser/download/model/background_service/background_download_service_factory.h
index 9f439725..4213109 100644
--- a/ios/chrome/browser/download/model/background_service/background_download_service_factory.h
+++ b/ios/chrome/browser/download/model/background_service/background_download_service_factory.h
@@ -32,12 +32,12 @@
   BackgroundDownloadServiceFactory();
   ~BackgroundDownloadServiceFactory() override;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 
   std::unique_ptr<KeyedService> BuildServiceWithClients(
-      web::BrowserState* context,
+      ProfileIOS* profile,
       std::unique_ptr<download::DownloadClientMap> clients) const;
 };
 
diff --git a/ios/chrome/browser/download/model/background_service/background_download_service_test.cc b/ios/chrome/browser/download/model/background_service/background_download_service_test.cc
index 07ff2daa..5aed65b 100644
--- a/ios/chrome/browser/download/model/background_service/background_download_service_test.cc
+++ b/ios/chrome/browser/download/model/background_service/background_download_service_test.cc
@@ -144,14 +144,14 @@
   // service. A pointer to the FakeClient object is kept in the test fixture
   // instance to allow test cases to manipulate it.
   std::unique_ptr<KeyedService> MakeBackgroundDowloadService(
-      web::BrowserState* browser_state) {
+      ProfileIOS* profile) {
     DCHECK(!fake_client_);
     auto fake_client = std::make_unique<NiceMock<FakeClient>>();
     fake_client_ = fake_client.get();
     auto clients = std::make_unique<download::DownloadClientMap>();
     clients->emplace(download::DownloadClient::TEST, std::move(fake_client));
     return BackgroundDownloadServiceFactory::GetInstance()
-        ->BuildServiceWithClients(browser_state, std::move(clients));
+        ->BuildServiceWithClients(profile, std::move(clients));
   }
 
  private:
diff --git a/ios/chrome/browser/download/model/browser_download_service_factory.h b/ios/chrome/browser/download/model/browser_download_service_factory.h
index 708af55b..c4d326b 100644
--- a/ios/chrome/browser/download/model/browser_download_service_factory.h
+++ b/ios/chrome/browser/download/model/browser_download_service_factory.h
@@ -19,7 +19,7 @@
   static BrowserDownloadServiceFactory* GetInstance();
 
   // Returns a default testing factory.
-  static TestingFactory GetDefaultFactory();
+  static ProfileTestingFactory GetDefaultFactory();
 
  private:
   friend class base::NoDestructor<BrowserDownloadServiceFactory>;
@@ -27,9 +27,9 @@
   BrowserDownloadServiceFactory();
   ~BrowserDownloadServiceFactory() override;
 
-  // BrowserStateKeyedServiceFactory overrides:
+  // ProfileKeyedServiceFactoryIOS overrides:
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_DOWNLOAD_MODEL_BROWSER_DOWNLOAD_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/download/model/browser_download_service_factory.mm b/ios/chrome/browser/download/model/browser_download_service_factory.mm
index c29419c..c6d13f6 100644
--- a/ios/chrome/browser/download/model/browser_download_service_factory.mm
+++ b/ios/chrome/browser/download/model/browser_download_service_factory.mm
@@ -12,10 +12,9 @@
 namespace {
 
 // Default factory.
-std::unique_ptr<KeyedService> BuildBrowserDownloadService(
-    web::BrowserState* context) {
+std::unique_ptr<KeyedService> BuildBrowserDownloadService(ProfileIOS* profile) {
   return std::make_unique<BrowserDownloadService>(
-      web::DownloadController::FromBrowserState(context));
+      web::DownloadController::FromBrowserState(profile));
 }
 
 }  // namespace
@@ -34,7 +33,7 @@
 }
 
 // static
-ProfileKeyedServiceFactoryIOS::TestingFactory
+ProfileKeyedServiceFactoryIOS::ProfileTestingFactory
 BrowserDownloadServiceFactory::GetDefaultFactory() {
   return base::BindOnce(&BuildBrowserDownloadService);
 }
@@ -49,6 +48,6 @@
 
 std::unique_ptr<KeyedService>
 BrowserDownloadServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  return BuildBrowserDownloadService(context);
+    ProfileIOS* profile) const {
+  return BuildBrowserDownloadService(profile);
 }
diff --git a/ios/chrome/browser/download/model/download_file_service_factory.h b/ios/chrome/browser/download/model/download_file_service_factory.h
index a646b87a..eed82bd 100644
--- a/ios/chrome/browser/download/model/download_file_service_factory.h
+++ b/ios/chrome/browser/download/model/download_file_service_factory.h
@@ -28,7 +28,7 @@
   ~DownloadFileServiceFactory() override;
 
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_DOWNLOAD_MODEL_DOWNLOAD_FILE_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/download/model/download_file_service_factory.mm b/ios/chrome/browser/download/model/download_file_service_factory.mm
index c5eef5e3..56905f9 100644
--- a/ios/chrome/browser/download/model/download_file_service_factory.mm
+++ b/ios/chrome/browser/download/model/download_file_service_factory.mm
@@ -35,9 +35,7 @@
 DownloadFileServiceFactory::~DownloadFileServiceFactory() = default;
 
 std::unique_ptr<KeyedService>
-DownloadFileServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
+DownloadFileServiceFactory::BuildServiceInstanceFor(ProfileIOS* profile) const {
   // DownloadRecordService may be nullptr if IsDownloadListEnabled() is false.
   DownloadRecordService* download_record_service = nullptr;
   if (IsDownloadListEnabled()) {
diff --git a/ios/chrome/browser/download/model/download_record_service_factory.h b/ios/chrome/browser/download/model/download_record_service_factory.h
index 3ab16f0..178f9c8 100644
--- a/ios/chrome/browser/download/model/download_record_service_factory.h
+++ b/ios/chrome/browser/download/model/download_record_service_factory.h
@@ -24,7 +24,7 @@
   ~DownloadRecordServiceFactory() override;
 
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_DOWNLOAD_MODEL_DOWNLOAD_RECORD_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/download/model/download_record_service_factory.mm b/ios/chrome/browser/download/model/download_record_service_factory.mm
index 47a91732..50f356e 100644
--- a/ios/chrome/browser/download/model/download_record_service_factory.mm
+++ b/ios/chrome/browser/download/model/download_record_service_factory.mm
@@ -30,7 +30,6 @@
 
 std::unique_ptr<KeyedService>
 DownloadRecordServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
+    ProfileIOS* profile) const {
   return std::make_unique<DownloadRecordServiceImpl>(profile->GetStatePath());
 }
diff --git a/ios/chrome/browser/enterprise/connectors/connectors_service_factory.h b/ios/chrome/browser/enterprise/connectors/connectors_service_factory.h
index 0c79a1b2..add8863 100644
--- a/ios/chrome/browser/enterprise/connectors/connectors_service_factory.h
+++ b/ios/chrome/browser/enterprise/connectors/connectors_service_factory.h
@@ -22,9 +22,9 @@
   ConnectorsServiceFactory();
   ~ConnectorsServiceFactory() override;
 
-  // ProfileKeyedServiceFactoryIOS:
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* browser_state) const override;
+      ProfileIOS* profile) const override;
 };
 
 }  // namespace enterprise_connectors
diff --git a/ios/chrome/browser/enterprise/connectors/connectors_service_factory.mm b/ios/chrome/browser/enterprise/connectors/connectors_service_factory.mm
index baa8c72daf..6d7a58af 100644
--- a/ios/chrome/browser/enterprise/connectors/connectors_service_factory.mm
+++ b/ios/chrome/browser/enterprise/connectors/connectors_service_factory.mm
@@ -30,8 +30,7 @@
 ConnectorsServiceFactory::~ConnectorsServiceFactory() = default;
 
 std::unique_ptr<KeyedService> ConnectorsServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* browser_state) const {
-  auto* profile = ProfileIOS::FromBrowserState(browser_state);
+    ProfileIOS* profile) const {
   return std::make_unique<ConnectorsService>(profile);
 }
 
diff --git a/ios/chrome/browser/enterprise/connectors/reporting/ios_realtime_reporting_client_factory.h b/ios/chrome/browser/enterprise/connectors/reporting/ios_realtime_reporting_client_factory.h
index 12e89e42..039584b3 100644
--- a/ios/chrome/browser/enterprise/connectors/reporting/ios_realtime_reporting_client_factory.h
+++ b/ios/chrome/browser/enterprise/connectors/reporting/ios_realtime_reporting_client_factory.h
@@ -28,18 +28,17 @@
 
   // Returns the default factory used to build IOSRealtimeReportingClient. Can
   // be registered with AddTestingFactory to use real instances during testing.
-  static TestingFactory GetDefaultFactory();
-
- protected:
-  // BrowserStateKeyedServiceFactory overrides.
-  std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* browser_state) const override;
+  static ProfileTestingFactory GetDefaultFactory();
 
  private:
   friend class base::NoDestructor<IOSRealtimeReportingClientFactory>;
 
   IOSRealtimeReportingClientFactory();
   ~IOSRealtimeReportingClientFactory() override;
+
+  // ProfileKeyedServiceFactoryIOS overrides.
+  std::unique_ptr<KeyedService> BuildServiceInstanceFor(
+      ProfileIOS* profile) const override;
 };
 
 }  // namespace enterprise_connectors
diff --git a/ios/chrome/browser/enterprise/connectors/reporting/ios_realtime_reporting_client_factory.mm b/ios/chrome/browser/enterprise/connectors/reporting/ios_realtime_reporting_client_factory.mm
index eaeb2963..a343cc0 100644
--- a/ios/chrome/browser/enterprise/connectors/reporting/ios_realtime_reporting_client_factory.mm
+++ b/ios/chrome/browser/enterprise/connectors/reporting/ios_realtime_reporting_client_factory.mm
@@ -16,9 +16,7 @@
 namespace {
 
 std::unique_ptr<KeyedService> BuildRealtimeReportingClient(
-    web::BrowserState* browser_state) {
-  auto* profile = ProfileIOS::FromBrowserState(browser_state);
-  DCHECK(profile);
+    ProfileIOS* profile) {
   return std::make_unique<IOSRealtimeReportingClient>(profile);
 }
 
@@ -39,9 +37,9 @@
 }
 
 // static
-ProfileKeyedServiceFactoryIOS::TestingFactory
+ProfileKeyedServiceFactoryIOS::ProfileTestingFactory
 IOSRealtimeReportingClientFactory::GetDefaultFactory() {
-  return base::BindRepeating(&BuildRealtimeReportingClient);
+  return base::BindOnce(&BuildRealtimeReportingClient);
 }
 
 IOSRealtimeReportingClientFactory::IOSRealtimeReportingClientFactory()
@@ -56,9 +54,8 @@
 
 std::unique_ptr<KeyedService>
 IOSRealtimeReportingClientFactory::BuildServiceInstanceFor(
-    web::BrowserState* browser_state) const {
-  auto* profile = ProfileIOS::FromBrowserState(browser_state);
-  return std::make_unique<IOSRealtimeReportingClient>(profile);
+    ProfileIOS* profile) const {
+  return BuildRealtimeReportingClient(profile);
 }
 
 }  // namespace enterprise_connectors
diff --git a/ios/chrome/browser/enterprise/connectors/reporting/ios_reporting_event_router_factory.h b/ios/chrome/browser/enterprise/connectors/reporting/ios_reporting_event_router_factory.h
index 57facd06..5ca03b95 100644
--- a/ios/chrome/browser/enterprise/connectors/reporting/ios_reporting_event_router_factory.h
+++ b/ios/chrome/browser/enterprise/connectors/reporting/ios_reporting_event_router_factory.h
@@ -26,9 +26,9 @@
   IOSReportingEventRouterFactory();
   ~IOSReportingEventRouterFactory() override;
 
-  // BrowserStateKeyedServiceFactory overrides.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* browser_state) const override;
+      ProfileIOS* profile) const override;
 };
 
 }  // namespace enterprise_connectors
diff --git a/ios/chrome/browser/enterprise/connectors/reporting/ios_reporting_event_router_factory.mm b/ios/chrome/browser/enterprise/connectors/reporting/ios_reporting_event_router_factory.mm
index 4674cfc..b0f5b241 100644
--- a/ios/chrome/browser/enterprise/connectors/reporting/ios_reporting_event_router_factory.mm
+++ b/ios/chrome/browser/enterprise/connectors/reporting/ios_reporting_event_router_factory.mm
@@ -37,8 +37,7 @@
 
 std::unique_ptr<KeyedService>
 IOSReportingEventRouterFactory::BuildServiceInstanceFor(
-    web::BrowserState* browser_state) const {
-  auto* profile = ProfileIOS::FromBrowserState(browser_state);
+    ProfileIOS* profile) const {
   return std::make_unique<ReportingEventRouter>(
       IOSRealtimeReportingClientFactory::GetForProfile(profile));
 }
diff --git a/ios/chrome/browser/gcm/model/instance_id/ios_chrome_instance_id_profile_service_factory.cc b/ios/chrome/browser/gcm/model/instance_id/ios_chrome_instance_id_profile_service_factory.cc
index 65bd487..c1cd27f7 100644
--- a/ios/chrome/browser/gcm/model/instance_id/ios_chrome_instance_id_profile_service_factory.cc
+++ b/ios/chrome/browser/gcm/model/instance_id/ios_chrome_instance_id_profile_service_factory.cc
@@ -37,10 +37,9 @@
 
 std::unique_ptr<KeyedService>
 IOSChromeInstanceIDProfileServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  DCHECK(!context->IsOffTheRecord());
+    ProfileIOS* profile) const {
+  DCHECK(!profile->IsOffTheRecord());
 
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
   return std::make_unique<instance_id::InstanceIDProfileService>(
       IOSChromeGCMProfileServiceFactory::GetForProfile(profile)->driver(),
       profile->IsOffTheRecord());
diff --git a/ios/chrome/browser/gcm/model/instance_id/ios_chrome_instance_id_profile_service_factory.h b/ios/chrome/browser/gcm/model/instance_id/ios_chrome_instance_id_profile_service_factory.h
index d1edc73..4da6aa0 100644
--- a/ios/chrome/browser/gcm/model/instance_id/ios_chrome_instance_id_profile_service_factory.h
+++ b/ios/chrome/browser/gcm/model/instance_id/ios_chrome_instance_id_profile_service_factory.h
@@ -29,9 +29,9 @@
   IOSChromeInstanceIDProfileServiceFactory();
   ~IOSChromeInstanceIDProfileServiceFactory() override;
 
-  // BrowserStateKeyedServiceFactory:
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_GCM_MODEL_INSTANCE_ID_IOS_CHROME_INSTANCE_ID_PROFILE_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/gcm/model/ios_chrome_gcm_profile_service_factory.h b/ios/chrome/browser/gcm/model/ios_chrome_gcm_profile_service_factory.h
index a27f2b4c..869f902 100644
--- a/ios/chrome/browser/gcm/model/ios_chrome_gcm_profile_service_factory.h
+++ b/ios/chrome/browser/gcm/model/ios_chrome_gcm_profile_service_factory.h
@@ -35,9 +35,9 @@
   IOSChromeGCMProfileServiceFactory();
   ~IOSChromeGCMProfileServiceFactory() override;
 
-  // BrowserStateKeyedServiceFactory:
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_GCM_MODEL_IOS_CHROME_GCM_PROFILE_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/gcm/model/ios_chrome_gcm_profile_service_factory.mm b/ios/chrome/browser/gcm/model/ios_chrome_gcm_profile_service_factory.mm
index 2100d0f2..e23354ab 100644
--- a/ios/chrome/browser/gcm/model/ios_chrome_gcm_profile_service_factory.mm
+++ b/ios/chrome/browser/gcm/model/ios_chrome_gcm_profile_service_factory.mm
@@ -56,14 +56,13 @@
 
 std::unique_ptr<KeyedService>
 IOSChromeGCMProfileServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  DCHECK(!context->IsOffTheRecord());
+    ProfileIOS* profile) const {
+  DCHECK(!profile->IsOffTheRecord());
 
   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner(
       base::ThreadPool::CreateSequencedTaskRunner(
           {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
            base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
   return std::make_unique<gcm::GCMProfileService>(
       profile->GetPrefs(), profile->GetStatePath(),
       // This callback may be invoked on a background sequence, but it calls
diff --git a/ios/chrome/browser/language/model/accept_languages_service_factory.cc b/ios/chrome/browser/language/model/accept_languages_service_factory.cc
index e81509a9..594b070 100644
--- a/ios/chrome/browser/language/model/accept_languages_service_factory.cc
+++ b/ios/chrome/browser/language/model/accept_languages_service_factory.cc
@@ -65,8 +65,7 @@
 
 std::unique_ptr<KeyedService>
 AcceptLanguagesServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
+    ProfileIOS* profile) const {
   return std::make_unique<AcceptLanguagesServiceForProfile>(
       profile->GetPrefs());
 }
diff --git a/ios/chrome/browser/language/model/accept_languages_service_factory.h b/ios/chrome/browser/language/model/accept_languages_service_factory.h
index 0cdd30d..55b5feac 100644
--- a/ios/chrome/browser/language/model/accept_languages_service_factory.h
+++ b/ios/chrome/browser/language/model/accept_languages_service_factory.h
@@ -27,9 +27,9 @@
   AcceptLanguagesServiceFactory();
   ~AcceptLanguagesServiceFactory() override;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_LANGUAGE_MODEL_ACCEPT_LANGUAGES_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/language/model/language_model_manager_factory.h b/ios/chrome/browser/language/model/language_model_manager_factory.h
index 7192b7b..6740006 100644
--- a/ios/chrome/browser/language/model/language_model_manager_factory.h
+++ b/ios/chrome/browser/language/model/language_model_manager_factory.h
@@ -27,9 +27,9 @@
   LanguageModelManagerFactory();
   ~LanguageModelManagerFactory() override;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_LANGUAGE_MODEL_LANGUAGE_MODEL_MANAGER_FACTORY_H_
diff --git a/ios/chrome/browser/language/model/language_model_manager_factory.mm b/ios/chrome/browser/language/model/language_model_manager_factory.mm
index 94bcae93..43f2d2d 100644
--- a/ios/chrome/browser/language/model/language_model_manager_factory.mm
+++ b/ios/chrome/browser/language/model/language_model_manager_factory.mm
@@ -53,8 +53,7 @@
 
 std::unique_ptr<KeyedService>
 LanguageModelManagerFactory::BuildServiceInstanceFor(
-    web::BrowserState* const state) const {
-  ProfileIOS* const profile = ProfileIOS::FromBrowserState(state);
+    ProfileIOS* profile) const {
   std::unique_ptr<language::LanguageModelManager> manager =
       std::make_unique<language::LanguageModelManager>(
           profile->GetPrefs(),
diff --git a/ios/chrome/browser/language/model/url_language_histogram_factory.cc b/ios/chrome/browser/language/model/url_language_histogram_factory.cc
index eac02c6..b339b969 100644
--- a/ios/chrome/browser/language/model/url_language_histogram_factory.cc
+++ b/ios/chrome/browser/language/model/url_language_histogram_factory.cc
@@ -29,8 +29,7 @@
 
 std::unique_ptr<KeyedService>
 UrlLanguageHistogramFactory::BuildServiceInstanceFor(
-    web::BrowserState* const context) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
+    ProfileIOS* profile) const {
   return std::make_unique<language::UrlLanguageHistogram>(profile->GetPrefs());
 }
 
diff --git a/ios/chrome/browser/language/model/url_language_histogram_factory.h b/ios/chrome/browser/language/model/url_language_histogram_factory.h
index 21afb85f..d85dcad 100644
--- a/ios/chrome/browser/language/model/url_language_histogram_factory.h
+++ b/ios/chrome/browser/language/model/url_language_histogram_factory.h
@@ -29,9 +29,9 @@
   UrlLanguageHistogramFactory();
   ~UrlLanguageHistogramFactory() override;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
   void RegisterProfilePrefs(
       user_prefs::PrefRegistrySyncable* registry) override;
 };
diff --git a/ios/chrome/browser/photos/model/photos_service_factory.h b/ios/chrome/browser/photos/model/photos_service_factory.h
index 3c9c8bf..94f0e50 100644
--- a/ios/chrome/browser/photos/model/photos_service_factory.h
+++ b/ios/chrome/browser/photos/model/photos_service_factory.h
@@ -20,7 +20,7 @@
   static PhotosServiceFactory* GetInstance();
 
   // Returns the default factory.
-  static TestingFactory GetDefaultFactory();
+  static ProfileTestingFactory GetDefaultFactory();
 
  private:
   friend class base::NoDestructor<PhotosServiceFactory>;
@@ -28,9 +28,9 @@
   PhotosServiceFactory();
   ~PhotosServiceFactory() override;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_PHOTOS_MODEL_PHOTOS_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/photos/model/photos_service_factory.mm b/ios/chrome/browser/photos/model/photos_service_factory.mm
index 62cb93c..b2c3fce 100644
--- a/ios/chrome/browser/photos/model/photos_service_factory.mm
+++ b/ios/chrome/browser/photos/model/photos_service_factory.mm
@@ -16,11 +16,10 @@
 namespace {
 
 // Build a PhotosService instance.
-std::unique_ptr<KeyedService> BuildPhotosService(web::BrowserState* context) {
+std::unique_ptr<KeyedService> BuildPhotosService(ProfileIOS* profile) {
   PhotosServiceConfiguration* configuration =
       [[PhotosServiceConfiguration alloc] init];
   ApplicationContext* application_context = GetApplicationContext();
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
   configuration.singleSignOnService =
       application_context->GetSingleSignOnService();
   configuration.prefService = profile->GetPrefs();
@@ -46,7 +45,7 @@
 }
 
 // static
-ProfileKeyedServiceFactoryIOS::TestingFactory
+ProfileKeyedServiceFactoryIOS::ProfileTestingFactory
 PhotosServiceFactory::GetDefaultFactory() {
   return base::BindOnce(&BuildPhotosService);
 }
@@ -63,6 +62,6 @@
 PhotosServiceFactory::~PhotosServiceFactory() = default;
 
 std::unique_ptr<KeyedService> PhotosServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  return BuildPhotosService(context);
+    ProfileIOS* profile) const {
+  return BuildPhotosService(profile);
 }
diff --git a/ios/chrome/browser/policy/ui_bundled/idle/BUILD.gn b/ios/chrome/browser/policy/ui_bundled/idle/BUILD.gn
index 93abb7c..7e07b04 100644
--- a/ios/chrome/browser/policy/ui_bundled/idle/BUILD.gn
+++ b/ios/chrome/browser/policy/ui_bundled/idle/BUILD.gn
@@ -24,10 +24,10 @@
     "//ios/chrome/browser/shared/model/application_context",
     "//ios/chrome/browser/shared/model/browser",
     "//ios/chrome/browser/shared/model/prefs:pref_names",
+    "//ios/chrome/browser/shared/public/snackbar",
     "//ios/chrome/browser/shared/ui/util",
     "//ios/chrome/browser/shared/ui/util:snackbar_util",
     "//ios/chrome/browser/signin/model",
-    "//ios/third_party/material_components_ios",
     "//ios/web/public",
     "//ui/base",
   ]
diff --git a/ios/chrome/browser/policy/ui_bundled/idle/idle_timeout_policy_scene_agent.mm b/ios/chrome/browser/policy/ui_bundled/idle/idle_timeout_policy_scene_agent.mm
index bb8593e0..2407f7e 100644
--- a/ios/chrome/browser/policy/ui_bundled/idle/idle_timeout_policy_scene_agent.mm
+++ b/ios/chrome/browser/policy/ui_bundled/idle/idle_timeout_policy_scene_agent.mm
@@ -4,7 +4,6 @@
 
 #import "ios/chrome/browser/policy/ui_bundled/idle/idle_timeout_policy_scene_agent.h"
 
-#import <MaterialComponents/MaterialSnackbar.h>
 #import <UIKit/UIKit.h>
 
 #import "base/time/time.h"
@@ -33,6 +32,7 @@
 #import "ios/chrome/browser/shared/public/commands/application_commands.h"
 #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
 #import "ios/chrome/browser/shared/public/commands/snackbar_commands.h"
+#import "ios/chrome/browser/shared/public/snackbar/snackbar_message.h"
 #import "ios/chrome/browser/shared/ui/util/snackbar_util.h"
 #import "ios/chrome/browser/shared/ui/util/uikit_ui_util.h"
 #import "ios/chrome/browser/signin/model/identity_manager_factory.h"
@@ -284,10 +284,10 @@
 }
 
 - (void)showSnackbar:(NSString*)messageText {
-  MDCSnackbarMessage* message = CreateSnackbarMessage(messageText);
+  SnackbarMessage* message = CreateCustomSnackbarMessage(messageText);
   message.duration = kIdleTimeoutSnackbarDuration;
   message.accessibilityLabel = messageText;
-  [_snackbarHandler showSnackbarMessage:message];
+  [_snackbarHandler showCustomSnackbarMessage:message];
 }
 
 // Returns whether the scene and app states allow for the idle timeout
diff --git a/ios/chrome/browser/policy/ui_bundled/idle/idle_timeout_policy_scene_agent_unittest.mm b/ios/chrome/browser/policy/ui_bundled/idle/idle_timeout_policy_scene_agent_unittest.mm
index b67c0b1..c5c14482 100644
--- a/ios/chrome/browser/policy/ui_bundled/idle/idle_timeout_policy_scene_agent_unittest.mm
+++ b/ios/chrome/browser/policy/ui_bundled/idle/idle_timeout_policy_scene_agent_unittest.mm
@@ -233,7 +233,8 @@
   // after actions ran since the app is foregrounded and active.
   idle_service_->RunActionsForStateForTesting(
       enterprise_idle::IdleService::LastState::kIdleOnBackground);
-  OCMExpect([mock_snackbar_handler_ showSnackbarMessage:[OCMArg isNotNil]]);
+  OCMExpect(
+      [mock_snackbar_handler_ showCustomSnackbarMessage:[OCMArg isNotNil]]);
   idle_service_->OnActionsCompleted();
   EXPECT_FALSE(idle_service_->ShouldIdleTimeoutSnackbarBePresented());
   EXPECT_OCMOCK_VERIFY(mock_snackbar_handler_);
@@ -248,7 +249,7 @@
   // Simulate that app ran actions on reforeground. The snack bar does not show
   // after actions run since the app is not foregrounded. The snackbar will be
   // pending display.
-  OCMReject([mock_snackbar_handler_ showSnackbarMessage:[OCMArg any]]);
+  OCMReject([mock_snackbar_handler_ showCustomSnackbarMessage:[OCMArg any]]);
   idle_service_->RunActionsForStateForTesting(
       enterprise_idle::IdleService::LastState::kIdleOnBackground);
   idle_service_->OnActionsCompleted();
@@ -267,7 +268,8 @@
   // transitions to `SceneActivationLevelForegroundActive`.
   idle_service_->RunActionsForStateForTesting(
       enterprise_idle::IdleService::LastState::kIdleOnBackground);
-  OCMExpect([mock_snackbar_handler_ showSnackbarMessage:[OCMArg isNotNil]]);
+  OCMExpect(
+      [mock_snackbar_handler_ showCustomSnackbarMessage:[OCMArg isNotNil]]);
   idle_service_->OnActionsCompleted();
   EXPECT_TRUE(idle_service_->ShouldIdleTimeoutSnackbarBePresented());
   scene_state_.activationLevel = SceneActivationLevelForegroundActive;
diff --git a/ios/chrome/browser/power_bookmarks/model/power_bookmark_service_factory.h b/ios/chrome/browser/power_bookmarks/model/power_bookmark_service_factory.h
index 8409671..1747bae 100644
--- a/ios/chrome/browser/power_bookmarks/model/power_bookmark_service_factory.h
+++ b/ios/chrome/browser/power_bookmarks/model/power_bookmark_service_factory.h
@@ -25,9 +25,9 @@
   PowerBookmarkServiceFactory();
   ~PowerBookmarkServiceFactory() override;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* state) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_POWER_BOOKMARKS_MODEL_POWER_BOOKMARK_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/power_bookmarks/model/power_bookmark_service_factory.mm b/ios/chrome/browser/power_bookmarks/model/power_bookmark_service_factory.mm
index 4543aa7..59f89e4 100644
--- a/ios/chrome/browser/power_bookmarks/model/power_bookmark_service_factory.mm
+++ b/ios/chrome/browser/power_bookmarks/model/power_bookmark_service_factory.mm
@@ -37,14 +37,12 @@
 
 std::unique_ptr<KeyedService>
 PowerBookmarkServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* state) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(state);
-
+    ProfileIOS* profile) const {
   bookmarks::BookmarkModel* bookmark_model =
       ios::BookmarkModelFactory::GetForProfile(profile);
 
   return std::make_unique<power_bookmarks::PowerBookmarkService>(
-      bookmark_model, state->GetStatePath().AppendASCII("power_bookmarks"),
+      bookmark_model, profile->GetStatePath().AppendASCII("power_bookmarks"),
       base::SequencedTaskRunner::GetCurrentDefault(),
       base::ThreadPool::CreateSequencedTaskRunner(
           {base::MayBlock(), base::TaskPriority::USER_BLOCKING,
diff --git a/ios/chrome/browser/privacy_sandbox/tracking_protection_settings_factory.h b/ios/chrome/browser/privacy_sandbox/tracking_protection_settings_factory.h
index 94740e0..f11fe84 100644
--- a/ios/chrome/browser/privacy_sandbox/tracking_protection_settings_factory.h
+++ b/ios/chrome/browser/privacy_sandbox/tracking_protection_settings_factory.h
@@ -27,11 +27,11 @@
   TrackingProtectionSettingsFactory();
   ~TrackingProtectionSettingsFactory() override;
 
-  // BrowserStateKeyedServiceFactory:
+  // ProfileKeyedServiceFactoryIOS:
   void RegisterProfilePrefs(
       user_prefs::PrefRegistrySyncable* registry) override;
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_PRIVACY_SANDBOX_TRACKING_PROTECTION_SETTINGS_FACTORY_H_
diff --git a/ios/chrome/browser/privacy_sandbox/tracking_protection_settings_factory.mm b/ios/chrome/browser/privacy_sandbox/tracking_protection_settings_factory.mm
index db48775..ffa79bf9 100644
--- a/ios/chrome/browser/privacy_sandbox/tracking_protection_settings_factory.mm
+++ b/ios/chrome/browser/privacy_sandbox/tracking_protection_settings_factory.mm
@@ -48,9 +48,7 @@
 
 std::unique_ptr<KeyedService>
 TrackingProtectionSettingsFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
-
+    ProfileIOS* profile) const {
   return std::make_unique<privacy_sandbox::TrackingProtectionSettings>(
       profile->GetPrefs(),
       ios::HostContentSettingsMapFactory::GetForProfile(profile),
diff --git a/ios/chrome/browser/reader_mode/model/reader_mode_model_factory.h b/ios/chrome/browser/reader_mode/model/reader_mode_model_factory.h
index 1e67ce0..3441fef3 100644
--- a/ios/chrome/browser/reader_mode/model/reader_mode_model_factory.h
+++ b/ios/chrome/browser/reader_mode/model/reader_mode_model_factory.h
@@ -23,9 +23,9 @@
   ReaderModeModelFactory();
   ~ReaderModeModelFactory() override;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_READER_MODE_MODEL_READER_MODE_MODEL_FACTORY_H_
diff --git a/ios/chrome/browser/reader_mode/model/reader_mode_model_factory.mm b/ios/chrome/browser/reader_mode/model/reader_mode_model_factory.mm
index 918aa34f..d8411b0 100644
--- a/ios/chrome/browser/reader_mode/model/reader_mode_model_factory.mm
+++ b/ios/chrome/browser/reader_mode/model/reader_mode_model_factory.mm
@@ -26,6 +26,6 @@
 ReaderModeModelFactory::~ReaderModeModelFactory() = default;
 
 std::unique_ptr<KeyedService> ReaderModeModelFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
+    ProfileIOS* profile) const {
   return std::make_unique<ReaderModeModel>();
 }
diff --git a/ios/chrome/browser/safari_data_import/coordinator/safari_data_import_entry_point_mediator_unittest.mm b/ios/chrome/browser/safari_data_import/coordinator/safari_data_import_entry_point_mediator_unittest.mm
index 46eb307..95bf75c 100644
--- a/ios/chrome/browser/safari_data_import/coordinator/safari_data_import_entry_point_mediator_unittest.mm
+++ b/ios/chrome/browser/safari_data_import/coordinator/safari_data_import_entry_point_mediator_unittest.mm
@@ -35,7 +35,6 @@
     promos_manager_ = std::make_unique<MockPromosManager>();
     tracker_ = feature_engagement::CreateTestTracker();
     tracker_->AddOnInitializedCallback(BoolArgumentQuitClosure());
-    run_loop_.Run();
 
     mediator_ = [[SafariDataImportEntryPointMediator alloc]
          initWithUIBlockerTarget:scene_state_
@@ -62,8 +61,15 @@
 };
 
 // Tests that the Safari import reminder is registered on request.
+// TODO(crbug.com/442365426): Test is flaky on device.
+#if !TARGET_OS_SIMULATOR
+#define MAYBE_TestRegisterSafariImportReminder \
+  DISABLED_TestRegisterSafariImportReminder
+#else
+#define MAYBE_TestRegisterSafariImportReminder TestRegisterSafariImportReminder
+#endif
 TEST_F(SafariDataImportEntryPointMediatorTest,
-       TestRegisterSafariImportReminder) {
+       MAYBE_TestRegisterSafariImportReminder) {
   EXPECT_CALL(*promos_manager_.get(),
               RegisterPromoForSingleDisplay(
                   promos_manager::Promo::SafariImportRemindMeLater));
@@ -72,7 +78,7 @@
   task_environment_.FastForwardBy(base::Days(1.1));
   EXPECT_FALSE(tracker_->ShouldTriggerHelpUI(
       feature_engagement::kIPHiOSSafariImportFeature));
-  task_environment_.FastForwardBy(base::Days(1));
+  task_environment_.FastForwardBy(base::Days(1.1));
   EXPECT_TRUE(tracker_->ShouldTriggerHelpUI(
       feature_engagement::kIPHiOSSafariImportFeature));
 }
diff --git a/ios/chrome/browser/safe_browsing/model/chrome_enterprise_url_lookup_service_factory.h b/ios/chrome/browser/safe_browsing/model/chrome_enterprise_url_lookup_service_factory.h
index fd77283..e802113 100644
--- a/ios/chrome/browser/safe_browsing/model/chrome_enterprise_url_lookup_service_factory.h
+++ b/ios/chrome/browser/safe_browsing/model/chrome_enterprise_url_lookup_service_factory.h
@@ -34,9 +34,9 @@
   ChromeEnterpriseRealTimeUrlLookupServiceFactory();
   ~ChromeEnterpriseRealTimeUrlLookupServiceFactory() override;
 
-  // ProfileKeyedServiceFactoryIOS:
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* browser_state) const override;
+      ProfileIOS* profile) const override;
 };
 
 }  // namespace safe_browsing
diff --git a/ios/chrome/browser/safe_browsing/model/chrome_enterprise_url_lookup_service_factory.mm b/ios/chrome/browser/safe_browsing/model/chrome_enterprise_url_lookup_service_factory.mm
index b0f02ed..3540432 100644
--- a/ios/chrome/browser/safe_browsing/model/chrome_enterprise_url_lookup_service_factory.mm
+++ b/ios/chrome/browser/safe_browsing/model/chrome_enterprise_url_lookup_service_factory.mm
@@ -83,14 +83,13 @@
 
 std::unique_ptr<KeyedService>
 ChromeEnterpriseRealTimeUrlLookupServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* browser_state) const {
+    ProfileIOS* profile) const {
   SafeBrowsingService* safe_browsing_service =
       GetApplicationContext()->GetSafeBrowsingService();
   if (!safe_browsing_service) {
     return nullptr;
   }
 
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(browser_state);
   signin::IdentityManager* identity_manager =
       IdentityManagerFactory::GetForProfile(profile);
 
diff --git a/ios/chrome/browser/safe_browsing/model/chrome_password_protection_service_factory.h b/ios/chrome/browser/safe_browsing/model/chrome_password_protection_service_factory.h
index d81a5e0..b20bf62 100644
--- a/ios/chrome/browser/safe_browsing/model/chrome_password_protection_service_factory.h
+++ b/ios/chrome/browser/safe_browsing/model/chrome_password_protection_service_factory.h
@@ -30,9 +30,9 @@
   ChromePasswordProtectionServiceFactory();
   ~ChromePasswordProtectionServiceFactory() override = default;
 
-  // BrowserStateKeyedServiceFactory:
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* browser_state) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_SAFE_BROWSING_MODEL_CHROME_PASSWORD_PROTECTION_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/safe_browsing/model/chrome_password_protection_service_factory.mm b/ios/chrome/browser/safe_browsing/model/chrome_password_protection_service_factory.mm
index 3bc0b6b..7d56853d 100644
--- a/ios/chrome/browser/safe_browsing/model/chrome_password_protection_service_factory.mm
+++ b/ios/chrome/browser/safe_browsing/model/chrome_password_protection_service_factory.mm
@@ -45,13 +45,12 @@
 
 std::unique_ptr<KeyedService>
 ChromePasswordProtectionServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* browser_state) const {
+    ProfileIOS* profile) const {
   SafeBrowsingService* safe_browsing_service =
       GetApplicationContext()->GetSafeBrowsingService();
   if (!safe_browsing_service) {
     return nullptr;
   }
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(browser_state);
   return std::make_unique<ChromePasswordProtectionService>(
       safe_browsing_service, profile,
       ios::HistoryServiceFactory::GetForProfile(
diff --git a/ios/chrome/browser/safe_browsing/model/hash_realtime_service_factory.h b/ios/chrome/browser/safe_browsing/model/hash_realtime_service_factory.h
index a1e1d15..baf3986 100644
--- a/ios/chrome/browser/safe_browsing/model/hash_realtime_service_factory.h
+++ b/ios/chrome/browser/safe_browsing/model/hash_realtime_service_factory.h
@@ -29,9 +29,9 @@
   HashRealTimeServiceFactory();
   ~HashRealTimeServiceFactory() override = default;
 
-  // BrowserStateKeyedServiceFactory:
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* browser_state) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_SAFE_BROWSING_MODEL_HASH_REALTIME_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/safe_browsing/model/hash_realtime_service_factory.mm b/ios/chrome/browser/safe_browsing/model/hash_realtime_service_factory.mm
index 4b4e3e6..f6dc2496 100644
--- a/ios/chrome/browser/safe_browsing/model/hash_realtime_service_factory.mm
+++ b/ios/chrome/browser/safe_browsing/model/hash_realtime_service_factory.mm
@@ -42,14 +42,12 @@
 }
 
 std::unique_ptr<KeyedService>
-HashRealTimeServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* browser_state) const {
+HashRealTimeServiceFactory::BuildServiceInstanceFor(ProfileIOS* profile) const {
   SafeBrowsingService* safe_browsing_service =
       GetApplicationContext()->GetSafeBrowsingService();
   if (!safe_browsing_service) {
     return nullptr;
   }
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(browser_state);
   return std::make_unique<safe_browsing::HashRealTimeService>(
       base::BindRepeating(&GetNetworkContext),
       VerdictCacheManagerFactory::GetForProfile(profile),
diff --git a/ios/chrome/browser/safe_browsing/model/ohttp_key_service_factory.h b/ios/chrome/browser/safe_browsing/model/ohttp_key_service_factory.h
index 8b24c5d3..a09878a7 100644
--- a/ios/chrome/browser/safe_browsing/model/ohttp_key_service_factory.h
+++ b/ios/chrome/browser/safe_browsing/model/ohttp_key_service_factory.h
@@ -25,7 +25,7 @@
 
   // Returns the default factory. Can be used to force instantiation during
   // testing.
-  static TestingFactory GetDefaultFactory();
+  static ProfileTestingFactory GetDefaultFactory();
 
  private:
   friend class base::NoDestructor<OhttpKeyServiceFactory>;
@@ -33,9 +33,9 @@
   OhttpKeyServiceFactory();
   ~OhttpKeyServiceFactory() override = default;
 
-  // BrowserStateKeyedServiceFactory:
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* browser_state) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_SAFE_BROWSING_MODEL_OHTTP_KEY_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/safe_browsing/model/ohttp_key_service_factory.mm b/ios/chrome/browser/safe_browsing/model/ohttp_key_service_factory.mm
index d51e441..d04d29f 100644
--- a/ios/chrome/browser/safe_browsing/model/ohttp_key_service_factory.mm
+++ b/ios/chrome/browser/safe_browsing/model/ohttp_key_service_factory.mm
@@ -21,13 +21,12 @@
 }
 
 // Default factory.
-std::unique_ptr<KeyedService> BuildOhttpKeyService(web::BrowserState* context) {
+std::unique_ptr<KeyedService> BuildOhttpKeyService(ProfileIOS* profile) {
   SafeBrowsingService* safe_browsing_service =
       GetApplicationContext()->GetSafeBrowsingService();
   if (!safe_browsing_service) {
     return nullptr;
   }
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
   auto url_loader_factory =
       std::make_unique<network::CrossThreadPendingSharedURLLoaderFactory>(
           safe_browsing_service->GetURLLoaderFactory());
@@ -54,7 +53,7 @@
 }
 
 // static
-OhttpKeyServiceFactory::TestingFactory
+ProfileKeyedServiceFactoryIOS::ProfileTestingFactory
 OhttpKeyServiceFactory::GetDefaultFactory() {
   return base::BindOnce(&BuildOhttpKeyService);
 }
@@ -66,6 +65,6 @@
                                     TestingCreation::kNoServiceForTests) {}
 
 std::unique_ptr<KeyedService> OhttpKeyServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  return BuildOhttpKeyService(context);
+    ProfileIOS* profile) const {
+  return BuildOhttpKeyService(profile);
 }
diff --git a/ios/chrome/browser/safe_browsing/model/real_time_url_lookup_service_factory.h b/ios/chrome/browser/safe_browsing/model/real_time_url_lookup_service_factory.h
index 11a9e42..b3aa080 100644
--- a/ios/chrome/browser/safe_browsing/model/real_time_url_lookup_service_factory.h
+++ b/ios/chrome/browser/safe_browsing/model/real_time_url_lookup_service_factory.h
@@ -29,9 +29,9 @@
   RealTimeUrlLookupServiceFactory();
   ~RealTimeUrlLookupServiceFactory() override = default;
 
-  // BrowserStateKeyedServiceFactory:
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* browser_state) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_SAFE_BROWSING_MODEL_REAL_TIME_URL_LOOKUP_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/safe_browsing/model/real_time_url_lookup_service_factory.mm b/ios/chrome/browser/safe_browsing/model/real_time_url_lookup_service_factory.mm
index 73c475d..186429e4 100644
--- a/ios/chrome/browser/safe_browsing/model/real_time_url_lookup_service_factory.mm
+++ b/ios/chrome/browser/safe_browsing/model/real_time_url_lookup_service_factory.mm
@@ -53,7 +53,7 @@
 
 std::unique_ptr<KeyedService>
 RealTimeUrlLookupServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* browser_state) const {
+    ProfileIOS* profile) const {
   SafeBrowsingService* safe_browsing_service =
       GetApplicationContext()->GetSafeBrowsingService();
   if (!safe_browsing_service) {
@@ -70,7 +70,6 @@
   // requests.
   safe_browsing::ReferrerChainProvider* referrer_chain_provider = nullptr;
 
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(browser_state);
   return std::make_unique<safe_browsing::RealTimeUrlLookupService>(
       safe_browsing_service->GetURLLoaderFactory(),
       VerdictCacheManagerFactory::GetForProfile(profile),
diff --git a/ios/chrome/browser/safe_browsing/model/safe_browsing_client_factory.h b/ios/chrome/browser/safe_browsing/model/safe_browsing_client_factory.h
index bb9d4746..ba1be76f 100644
--- a/ios/chrome/browser/safe_browsing/model/safe_browsing_client_factory.h
+++ b/ios/chrome/browser/safe_browsing/model/safe_browsing_client_factory.h
@@ -26,9 +26,9 @@
   SafeBrowsingClientFactory();
   ~SafeBrowsingClientFactory() override = default;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_SAFE_BROWSING_MODEL_SAFE_BROWSING_CLIENT_FACTORY_H_
diff --git a/ios/chrome/browser/safe_browsing/model/safe_browsing_client_factory.mm b/ios/chrome/browser/safe_browsing/model/safe_browsing_client_factory.mm
index da0d4b5..6a082cd 100644
--- a/ios/chrome/browser/safe_browsing/model/safe_browsing_client_factory.mm
+++ b/ios/chrome/browser/safe_browsing/model/safe_browsing_client_factory.mm
@@ -74,9 +74,7 @@
 }
 
 std::unique_ptr<KeyedService>
-SafeBrowsingClientFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
+SafeBrowsingClientFactory::BuildServiceInstanceFor(ProfileIOS* profile) const {
   safe_browsing::HashRealTimeService* hash_real_time_service = nullptr;
   if (base::FeatureList::IsEnabled(safe_browsing::kHashPrefixRealTimeLookups)) {
     hash_real_time_service = HashRealTimeServiceFactory::GetForProfile(profile);
diff --git a/ios/chrome/browser/safe_browsing/model/safe_browsing_helper_factory.h b/ios/chrome/browser/safe_browsing/model/safe_browsing_helper_factory.h
index 4d550b68..33e58244 100644
--- a/ios/chrome/browser/safe_browsing/model/safe_browsing_helper_factory.h
+++ b/ios/chrome/browser/safe_browsing/model/safe_browsing_helper_factory.h
@@ -26,9 +26,9 @@
   SafeBrowsingHelperFactory();
   ~SafeBrowsingHelperFactory() override = default;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_SAFE_BROWSING_MODEL_SAFE_BROWSING_HELPER_FACTORY_H_
diff --git a/ios/chrome/browser/safe_browsing/model/safe_browsing_helper_factory.mm b/ios/chrome/browser/safe_browsing/model/safe_browsing_helper_factory.mm
index b1f18c0d..1b9796d 100644
--- a/ios/chrome/browser/safe_browsing/model/safe_browsing_helper_factory.mm
+++ b/ios/chrome/browser/safe_browsing/model/safe_browsing_helper_factory.mm
@@ -31,9 +31,7 @@
 }
 
 std::unique_ptr<KeyedService>
-SafeBrowsingHelperFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
+SafeBrowsingHelperFactory::BuildServiceInstanceFor(ProfileIOS* profile) const {
   return std::make_unique<SafeBrowsingHelper>(
       profile->GetPrefs(), GetApplicationContext()->GetSafeBrowsingService(),
       SafeBrowsingMetricsCollectorFactory::GetForProfile(profile));
diff --git a/ios/chrome/browser/safe_browsing/model/safe_browsing_metrics_collector_factory.h b/ios/chrome/browser/safe_browsing/model/safe_browsing_metrics_collector_factory.h
index 4ab2367..09b6a9a 100644
--- a/ios/chrome/browser/safe_browsing/model/safe_browsing_metrics_collector_factory.h
+++ b/ios/chrome/browser/safe_browsing/model/safe_browsing_metrics_collector_factory.h
@@ -28,9 +28,9 @@
   SafeBrowsingMetricsCollectorFactory();
   ~SafeBrowsingMetricsCollectorFactory() override = default;
 
-  // BrowserStateKeyedServiceFactory:
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* browser_state) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_SAFE_BROWSING_MODEL_SAFE_BROWSING_METRICS_COLLECTOR_FACTORY_H_
diff --git a/ios/chrome/browser/safe_browsing/model/safe_browsing_metrics_collector_factory.mm b/ios/chrome/browser/safe_browsing/model/safe_browsing_metrics_collector_factory.mm
index 2c19d58..8cb06ad 100644
--- a/ios/chrome/browser/safe_browsing/model/safe_browsing_metrics_collector_factory.mm
+++ b/ios/chrome/browser/safe_browsing/model/safe_browsing_metrics_collector_factory.mm
@@ -28,8 +28,7 @@
 
 std::unique_ptr<KeyedService>
 SafeBrowsingMetricsCollectorFactory::BuildServiceInstanceFor(
-    web::BrowserState* browser_state) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(browser_state);
+    ProfileIOS* profile) const {
   return std::make_unique<safe_browsing::SafeBrowsingMetricsCollector>(
       profile->GetPrefs());
 }
diff --git a/ios/chrome/browser/safe_browsing/model/tailored_security/tailored_security_service_factory.h b/ios/chrome/browser/safe_browsing/model/tailored_security/tailored_security_service_factory.h
index 142263f7..7625ee06 100644
--- a/ios/chrome/browser/safe_browsing/model/tailored_security/tailored_security_service_factory.h
+++ b/ios/chrome/browser/safe_browsing/model/tailored_security/tailored_security_service_factory.h
@@ -30,9 +30,9 @@
   TailoredSecurityServiceFactory();
   ~TailoredSecurityServiceFactory() override = default;
 
-  // BrowserStateKeyedServiceFactory:
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* browser_state) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_SAFE_BROWSING_MODEL_TAILORED_SECURITY_TAILORED_SECURITY_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/safe_browsing/model/tailored_security/tailored_security_service_factory.mm b/ios/chrome/browser/safe_browsing/model/tailored_security/tailored_security_service_factory.mm
index 8dbf3393..1b68dc6 100644
--- a/ios/chrome/browser/safe_browsing/model/tailored_security/tailored_security_service_factory.mm
+++ b/ios/chrome/browser/safe_browsing/model/tailored_security/tailored_security_service_factory.mm
@@ -32,8 +32,7 @@
 
 std::unique_ptr<KeyedService>
 TailoredSecurityServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* browser_state) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(browser_state);
+    ProfileIOS* profile) const {
   return std::make_unique<safe_browsing::ChromeTailoredSecurityService>(
       profile, IdentityManagerFactory::GetForProfile(profile),
       SyncServiceFactory::GetForProfile(profile));
diff --git a/ios/chrome/browser/safe_browsing/model/verdict_cache_manager_factory.h b/ios/chrome/browser/safe_browsing/model/verdict_cache_manager_factory.h
index 57942af..5f6b0cf 100644
--- a/ios/chrome/browser/safe_browsing/model/verdict_cache_manager_factory.h
+++ b/ios/chrome/browser/safe_browsing/model/verdict_cache_manager_factory.h
@@ -26,9 +26,9 @@
   VerdictCacheManagerFactory();
   ~VerdictCacheManagerFactory() override = default;
 
-  // BrowserStateKeyedServiceFactory:
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* browser_state) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_SAFE_BROWSING_MODEL_VERDICT_CACHE_MANAGER_FACTORY_H_
diff --git a/ios/chrome/browser/safe_browsing/model/verdict_cache_manager_factory.mm b/ios/chrome/browser/safe_browsing/model/verdict_cache_manager_factory.mm
index 82a313d6..d46edf18 100644
--- a/ios/chrome/browser/safe_browsing/model/verdict_cache_manager_factory.mm
+++ b/ios/chrome/browser/safe_browsing/model/verdict_cache_manager_factory.mm
@@ -36,9 +36,7 @@
 }
 
 std::unique_ptr<KeyedService>
-VerdictCacheManagerFactory::BuildServiceInstanceFor(
-    web::BrowserState* browser_state) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(browser_state);
+VerdictCacheManagerFactory::BuildServiceInstanceFor(ProfileIOS* profile) const {
   return std::make_unique<safe_browsing::VerdictCacheManager>(
       ios::HistoryServiceFactory::GetForProfile(
           profile, ServiceAccessType::EXPLICIT_ACCESS),
diff --git a/ios/chrome/browser/settings/ui_bundled/google_services/bulk_upload/bulk_upload_coordinator.mm b/ios/chrome/browser/settings/ui_bundled/google_services/bulk_upload/bulk_upload_coordinator.mm
index d8c96b8e..b3bef54 100644
--- a/ios/chrome/browser/settings/ui_bundled/google_services/bulk_upload/bulk_upload_coordinator.mm
+++ b/ios/chrome/browser/settings/ui_bundled/google_services/bulk_upload/bulk_upload_coordinator.mm
@@ -4,8 +4,6 @@
 
 #import "ios/chrome/browser/settings/ui_bundled/google_services/bulk_upload/bulk_upload_coordinator.h"
 
-#import <MaterialComponents/MaterialSnackbar.h>
-
 #import "base/check.h"
 #import "base/metrics/user_metrics.h"
 #import "components/sync/service/sync_service.h"
@@ -119,7 +117,7 @@
 
 - (void)displayInSnackbar:(NSString*)message {
   [self.snackbarCommandsHandler
-      showSnackbarMessage:CreateSnackbarMessage(message)];
+      showCustomSnackbarMessage:CreateCustomSnackbarMessage(message)];
 }
 
 @end
diff --git a/ios/chrome/browser/shared/model/browser/browser_list_factory.h b/ios/chrome/browser/shared/model/browser/browser_list_factory.h
index d40da06e..93f478f 100644
--- a/ios/chrome/browser/shared/model/browser/browser_list_factory.h
+++ b/ios/chrome/browser/shared/model/browser/browser_list_factory.h
@@ -25,9 +25,9 @@
 
   BrowserListFactory();
 
-  // BrowserStateKeyedServiceFactory:
+  // ProfileKeyedServiceFactoryIOS:
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const final;
+      ProfileIOS* profile) const final;
 };
 
 #endif  // IOS_CHROME_BROWSER_SHARED_MODEL_BROWSER_BROWSER_LIST_FACTORY_H_
diff --git a/ios/chrome/browser/shared/model/browser/browser_list_factory.mm b/ios/chrome/browser/shared/model/browser/browser_list_factory.mm
index b8933cd3..52c24d9f 100644
--- a/ios/chrome/browser/shared/model/browser/browser_list_factory.mm
+++ b/ios/chrome/browser/shared/model/browser/browser_list_factory.mm
@@ -27,6 +27,6 @@
                                     ProfileSelection::kRedirectedInIncognito) {}
 
 std::unique_ptr<KeyedService> BrowserListFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
+    ProfileIOS* profile) const {
   return std::make_unique<BrowserList>();
 }
diff --git a/ios/chrome/browser/shared/ui/util/identity_snackbar/identity_snackbar_message_egtest.mm b/ios/chrome/browser/shared/ui/util/identity_snackbar/identity_snackbar_message_egtest.mm
index 8df47234..5dd43e08 100644
--- a/ios/chrome/browser/shared/ui/util/identity_snackbar/identity_snackbar_message_egtest.mm
+++ b/ios/chrome/browser/shared/ui/util/identity_snackbar/identity_snackbar_message_egtest.mm
@@ -158,7 +158,8 @@
 
 // Verifies no identity confirmation snackbar shows on startup when there is an
 // identity on the device but the user is signed-out.
-- (void)testNoIdentity_IdentityConfirmationToast {
+// TODO(crbug.com/443199219): Flaky on iPad.
+- (void)DISABLED_testNoIdentity_IdentityConfirmationToast {
   // TODO(crbug.com/441260415): Re-enable the test on iOS26.
   if (base::ios::IsRunningOnIOS26OrLater()) {
     EARL_GREY_TEST_DISABLED(@"Test disabled on iOS 26.");
@@ -191,7 +192,8 @@
 
 // Verifies identity confirmation snackbar shows on startup with multiple
 // identities on device with frequency limitations.
-- (void)testFrequencyLimitation_IdentityConfirmationToast {
+// TODO(crbug.com/443199219): Flaky on iPad.
+- (void)DISABLED_testFrequencyLimitation_IdentityConfirmationToast {
   // TODO(crbug.com/433726717): Test disabled on iPhones.
   if (![ChromeEarlGrey isIPadIdiom]) {
     EARL_GREY_TEST_DISABLED(@"Fails on iPhones.");
diff --git a/ios/chrome/browser/supervised_user/model/child_account_service_factory.h b/ios/chrome/browser/supervised_user/model/child_account_service_factory.h
index 028cb240..43af3b4 100644
--- a/ios/chrome/browser/supervised_user/model/child_account_service_factory.h
+++ b/ios/chrome/browser/supervised_user/model/child_account_service_factory.h
@@ -26,9 +26,9 @@
   ChildAccountServiceFactory();
   ~ChildAccountServiceFactory() override = default;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_SUPERVISED_USER_MODEL_CHILD_ACCOUNT_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/supervised_user/model/child_account_service_factory.mm b/ios/chrome/browser/supervised_user/model/child_account_service_factory.mm
index 91700dc..22eaed8b 100644
--- a/ios/chrome/browser/supervised_user/model/child_account_service_factory.mm
+++ b/ios/chrome/browser/supervised_user/model/child_account_service_factory.mm
@@ -35,9 +35,7 @@
 }
 
 std::unique_ptr<KeyedService>
-ChildAccountServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
+ChildAccountServiceFactory::BuildServiceInstanceFor(ProfileIOS* profile) const {
   CHECK(SupervisedUserServiceFactory::GetForProfile(profile));
   return std::make_unique<supervised_user::ChildAccountService>(
       CHECK_DEREF(profile->GetPrefs()),
diff --git a/ios/chrome/browser/supervised_user/model/list_family_members_service_factory.h b/ios/chrome/browser/supervised_user/model/list_family_members_service_factory.h
index d4e11e8..9da7b40 100644
--- a/ios/chrome/browser/supervised_user/model/list_family_members_service_factory.h
+++ b/ios/chrome/browser/supervised_user/model/list_family_members_service_factory.h
@@ -26,9 +26,9 @@
   ListFamilyMembersServiceFactory();
   ~ListFamilyMembersServiceFactory() override = default;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_SUPERVISED_USER_MODEL_LIST_FAMILY_MEMBERS_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/supervised_user/model/list_family_members_service_factory.mm b/ios/chrome/browser/supervised_user/model/list_family_members_service_factory.mm
index 9c4ba78..88c4a6f 100644
--- a/ios/chrome/browser/supervised_user/model/list_family_members_service_factory.mm
+++ b/ios/chrome/browser/supervised_user/model/list_family_members_service_factory.mm
@@ -32,8 +32,7 @@
 
 std::unique_ptr<KeyedService>
 ListFamilyMembersServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
+    ProfileIOS* profile) const {
   return std::make_unique<supervised_user::ListFamilyMembersService>(
       IdentityManagerFactory::GetForProfile(profile),
       profile->GetSharedURLLoaderFactory(), CHECK_DEREF(profile->GetPrefs()));
diff --git a/ios/chrome/browser/supervised_user/model/supervised_user_metrics_service_factory.h b/ios/chrome/browser/supervised_user/model/supervised_user_metrics_service_factory.h
index 0f494be..b295652 100644
--- a/ios/chrome/browser/supervised_user/model/supervised_user_metrics_service_factory.h
+++ b/ios/chrome/browser/supervised_user/model/supervised_user_metrics_service_factory.h
@@ -27,9 +27,9 @@
   SupervisedUserMetricsServiceFactory();
   ~SupervisedUserMetricsServiceFactory() override = default;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_SUPERVISED_USER_MODEL_SUPERVISED_USER_METRICS_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/supervised_user/model/supervised_user_metrics_service_factory.mm b/ios/chrome/browser/supervised_user/model/supervised_user_metrics_service_factory.mm
index a653050..5a4204c4 100644
--- a/ios/chrome/browser/supervised_user/model/supervised_user_metrics_service_factory.mm
+++ b/ios/chrome/browser/supervised_user/model/supervised_user_metrics_service_factory.mm
@@ -31,8 +31,7 @@
 
 std::unique_ptr<KeyedService>
 SupervisedUserMetricsServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
+    ProfileIOS* profile) const {
   return std::make_unique<supervised_user::SupervisedUserMetricsService>(
       profile->GetPrefs(),
       *SupervisedUserServiceFactory::GetForProfile(profile),
diff --git a/ios/chrome/browser/supervised_user/model/supervised_user_service_factory.h b/ios/chrome/browser/supervised_user/model/supervised_user_service_factory.h
index 620ae06..2c7575e 100644
--- a/ios/chrome/browser/supervised_user/model/supervised_user_service_factory.h
+++ b/ios/chrome/browser/supervised_user/model/supervised_user_service_factory.h
@@ -26,9 +26,9 @@
   SupervisedUserServiceFactory();
   ~SupervisedUserServiceFactory() override = default;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_SUPERVISED_USER_MODEL_SUPERVISED_USER_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/supervised_user/model/supervised_user_service_factory.mm b/ios/chrome/browser/supervised_user/model/supervised_user_service_factory.mm
index 188faa41..6e097ff 100644
--- a/ios/chrome/browser/supervised_user/model/supervised_user_service_factory.mm
+++ b/ios/chrome/browser/supervised_user/model/supervised_user_service_factory.mm
@@ -55,9 +55,7 @@
 
 std::unique_ptr<KeyedService>
 SupervisedUserServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
-
+    ProfileIOS* profile) const {
   std::unique_ptr<SupervisedUserServicePlatformDelegate> platform_delegate =
       std::make_unique<SupervisedUserServicePlatformDelegate>(profile);
   signin::IdentityManager* identity_manager =
diff --git a/ios/chrome/browser/supervised_user/model/supervised_user_settings_service_factory.h b/ios/chrome/browser/supervised_user/model/supervised_user_settings_service_factory.h
index 0f8f137..4541bb33 100644
--- a/ios/chrome/browser/supervised_user/model/supervised_user_settings_service_factory.h
+++ b/ios/chrome/browser/supervised_user/model/supervised_user_settings_service_factory.h
@@ -27,10 +27,10 @@
   SupervisedUserSettingsServiceFactory();
   ~SupervisedUserSettingsServiceFactory() override = default;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   bool ServiceIsRequiredForContextInitialization() const override;
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_SUPERVISED_USER_MODEL_SUPERVISED_USER_SETTINGS_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/supervised_user/model/supervised_user_settings_service_factory.mm b/ios/chrome/browser/supervised_user/model/supervised_user_settings_service_factory.mm
index d31346b9..5cd263e9 100644
--- a/ios/chrome/browser/supervised_user/model/supervised_user_settings_service_factory.mm
+++ b/ios/chrome/browser/supervised_user/model/supervised_user_settings_service_factory.mm
@@ -38,6 +38,6 @@
 
 std::unique_ptr<KeyedService>
 SupervisedUserSettingsServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
+    ProfileIOS* profile) const {
   return std::make_unique<supervised_user::SupervisedUserSettingsService>();
 }
diff --git a/ios/chrome/browser/sync/model/BUILD.gn b/ios/chrome/browser/sync/model/BUILD.gn
index c5115bc..c09f79ee 100644
--- a/ios/chrome/browser/sync/model/BUILD.gn
+++ b/ios/chrome/browser/sync/model/BUILD.gn
@@ -74,7 +74,6 @@
     "//ios/chrome/browser/passwords/model:sharing_factory",
     "//ios/chrome/browser/passwords/model:store_factory",
     "//ios/chrome/browser/plus_addresses/model",
-    "//ios/chrome/browser/power_bookmarks/model",
     "//ios/chrome/browser/reading_list/model",
     "//ios/chrome/browser/saved_tab_groups/model",
     "//ios/chrome/browser/search_engines/model",
diff --git a/ios/chrome/browser/sync/model/DEPS b/ios/chrome/browser/sync/model/DEPS
index ce0617a6..4a67b65a 100644
--- a/ios/chrome/browser/sync/model/DEPS
+++ b/ios/chrome/browser/sync/model/DEPS
@@ -20,7 +20,6 @@
   "+ios/chrome/browser/metrics/model",
   "+ios/chrome/browser/passwords/model",
   "+ios/chrome/browser/plus_addresses/model",
-  "+ios/chrome/browser/power_bookmarks/model",
   "+ios/chrome/browser/push_notification/model",
   "+ios/chrome/browser/reading_list/model",
   "+ios/chrome/browser/saved_tab_groups/model",
diff --git a/ios/chrome/browser/sync/model/sync_error_browser_agent.h b/ios/chrome/browser/sync/model/sync_error_browser_agent.h
index 488283e0..4e55814 100644
--- a/ios/chrome/browser/sync/model/sync_error_browser_agent.h
+++ b/ios/chrome/browser/sync/model/sync_error_browser_agent.h
@@ -91,8 +91,6 @@
   __weak id<SyncPresenter> sync_presenter_provider_;
   // Used to observe the ProfileState.
   __strong SyncErrorBrowserAgentProfileStateObserver* profile_state_observer_;
-
-  base::WeakPtrFactory<SyncErrorBrowserAgent> weak_ptr_factory_{this};
 };
 
 #endif  // IOS_CHROME_BROWSER_SYNC_MODEL_SYNC_ERROR_BROWSER_AGENT_H_
diff --git a/ios/chrome/browser/sync/model/sync_error_browser_agent.mm b/ios/chrome/browser/sync/model/sync_error_browser_agent.mm
index c199a696..0970995a 100644
--- a/ios/chrome/browser/sync/model/sync_error_browser_agent.mm
+++ b/ios/chrome/browser/sync/model/sync_error_browser_agent.mm
@@ -263,7 +263,7 @@
   password_manager::PasswordFormCache* password_form_cache =
       GetPasswordFormCacheFromWebState(web_state);
   if (password_form_cache) {
-    password_form_cache->SetObserver(weak_ptr_factory_.GetWeakPtr());
+    password_form_cache->AddObserver(this);
   }
 }
 
@@ -274,6 +274,6 @@
   password_manager::PasswordFormCache* password_form_cache =
       GetPasswordFormCacheFromWebState(web_state);
   if (password_form_cache) {
-    password_form_cache->ResetObserver();
+    password_form_cache->RemoveObserver(this);
   }
 }
diff --git a/ios/chrome/browser/sync/model/sync_service_factory.mm b/ios/chrome/browser/sync/model/sync_service_factory.mm
index 9c95b06..897eb7b 100644
--- a/ios/chrome/browser/sync/model/sync_service_factory.mm
+++ b/ios/chrome/browser/sync/model/sync_service_factory.mm
@@ -51,7 +51,6 @@
 #import "ios/chrome/browser/passwords/model/ios_chrome_password_sender_service_factory.h"
 #import "ios/chrome/browser/passwords/model/ios_chrome_profile_password_store_factory.h"
 #import "ios/chrome/browser/plus_addresses/model/plus_address_setting_service_factory.h"
-#import "ios/chrome/browser/power_bookmarks/model/power_bookmark_service_factory.h"
 #import "ios/chrome/browser/reading_list/model/reading_list_model_factory.h"
 #import "ios/chrome/browser/saved_tab_groups/model/tab_group_sync_service_factory.h"
 #import "ios/chrome/browser/search_engines/model/template_url_service_factory.h"
@@ -132,8 +131,6 @@
       PlusAddressSettingServiceFactory::GetForProfile(profile),
       ios::WebDataServiceFactory::GetPlusAddressWebDataForProfile(
           profile, ServiceAccessType::IMPLICIT_ACCESS));
-  builder.SetPowerBookmarkService(
-      PowerBookmarkServiceFactory::GetForProfile(profile));
   builder.SetPrefService(profile->GetPrefs());
   builder.SetPrefServiceSyncable(profile->GetSyncablePrefs());
   // TODO(crbug.com/330201909) implement for iOS.
@@ -352,7 +349,6 @@
   DependsOn(IOSTrustedVaultServiceFactory::GetInstance());
   DependsOn(IOSUserEventServiceFactory::GetInstance());
   DependsOn(PlusAddressSettingServiceFactory::GetInstance());
-  DependsOn(PowerBookmarkServiceFactory::GetInstance());
   DependsOn(ReadingListModelFactory::GetInstance());
   DependsOn(SendTabToSelfSyncServiceFactory::GetInstance());
   DependsOn(SessionSyncServiceFactory::GetInstance());
diff --git a/ios/chrome/browser/tabs_search/model/tabs_search_service_factory.h b/ios/chrome/browser/tabs_search/model/tabs_search_service_factory.h
index e7a0fdbd..4ab07a9 100644
--- a/ios/chrome/browser/tabs_search/model/tabs_search_service_factory.h
+++ b/ios/chrome/browser/tabs_search/model/tabs_search_service_factory.h
@@ -24,9 +24,9 @@
   TabsSearchServiceFactory();
   ~TabsSearchServiceFactory() override;
 
-  // BrowserStateKeyedServiceFactory:
+  // ProfileKeyedServiceFactoryIOS:
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_TABS_SEARCH_MODEL_TABS_SEARCH_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/tabs_search/model/tabs_search_service_factory.mm b/ios/chrome/browser/tabs_search/model/tabs_search_service_factory.mm
index a83bd639..167c0c6e 100644
--- a/ios/chrome/browser/tabs_search/model/tabs_search_service_factory.mm
+++ b/ios/chrome/browser/tabs_search/model/tabs_search_service_factory.mm
@@ -54,9 +54,7 @@
 TabsSearchServiceFactory::~TabsSearchServiceFactory() = default;
 
 std::unique_ptr<KeyedService> TabsSearchServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
-
+    ProfileIOS* profile) const {
   const bool is_off_the_record = profile->IsOffTheRecord();
   return std::make_unique<TabsSearchService>(
       is_off_the_record, BrowserListFactory::GetForProfile(profile),
diff --git a/ios/chrome/browser/text_selection/model/text_classifier_model_service_factory.h b/ios/chrome/browser/text_selection/model/text_classifier_model_service_factory.h
index a40972cb..6ae412c 100644
--- a/ios/chrome/browser/text_selection/model/text_classifier_model_service_factory.h
+++ b/ios/chrome/browser/text_selection/model/text_classifier_model_service_factory.h
@@ -25,9 +25,9 @@
   TextClassifierModelServiceFactory();
   ~TextClassifierModelServiceFactory() override;
 
-  // BrowserStateKeyedServiceFactory implementation:
+  // ProfileKeyedServiceFactoryIOS implementation:
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_TEXT_SELECTION_MODEL_TEXT_CLASSIFIER_MODEL_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/text_selection/model/text_classifier_model_service_factory.mm b/ios/chrome/browser/text_selection/model/text_classifier_model_service_factory.mm
index b2e6a6e9..0e15d48 100644
--- a/ios/chrome/browser/text_selection/model/text_classifier_model_service_factory.mm
+++ b/ios/chrome/browser/text_selection/model/text_classifier_model_service_factory.mm
@@ -38,13 +38,12 @@
 
 std::unique_ptr<KeyedService>
 TextClassifierModelServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
+    ProfileIOS* profile) const {
   if (!IsExpKitTextClassifierEntityEnabled() ||
       !optimization_guide::features::IsOptimizationTargetPredictionEnabled()) {
     return nullptr;
   }
 
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
   // The optimization guide service must be available for the text classifier
   // model service to be created.
   OptimizationGuideService* opt_guide =
diff --git a/ios/chrome/browser/text_selection/model/text_classifier_model_service_fake.h b/ios/chrome/browser/text_selection/model/text_classifier_model_service_fake.h
index 0c8fb84..b582a69b9 100644
--- a/ios/chrome/browser/text_selection/model/text_classifier_model_service_fake.h
+++ b/ios/chrome/browser/text_selection/model/text_classifier_model_service_fake.h
@@ -13,7 +13,7 @@
 // Fake implementation of TextClassifierModelService that can be used by tests.
 class TextClassifierModelServiceFake : public TextClassifierModelService {
  public:
-  using TestingFactory = ProfileKeyedServiceFactoryIOS::TestingFactory;
+  using TestingFactory = ProfileKeyedServiceFactoryIOS::ProfileTestingFactory;
 
   static TestingFactory GetTestingFactory();
   ~TextClassifierModelServiceFake() override;
diff --git a/ios/chrome/browser/text_selection/model/text_classifier_model_service_fake.mm b/ios/chrome/browser/text_selection/model/text_classifier_model_service_fake.mm
index 7fff441..835a008 100644
--- a/ios/chrome/browser/text_selection/model/text_classifier_model_service_fake.mm
+++ b/ios/chrome/browser/text_selection/model/text_classifier_model_service_fake.mm
@@ -15,13 +15,10 @@
 namespace {
 
 // Returns a new instance of TextClassifierModelServiceFake.
-std::unique_ptr<KeyedService> BuildInstance(web::BrowserState* context) {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
+std::unique_ptr<KeyedService> BuildInstance(ProfileIOS* profile) {
   OptimizationGuideService* opt_guide =
       OptimizationGuideServiceFactory::GetForProfile(profile);
-  std::unique_ptr<TextClassifierModelService> service =
-      base::WrapUnique(new TextClassifierModelServiceFake(opt_guide));
-  return service;
+  return std::make_unique<TextClassifierModelServiceFake>(opt_guide);
 }
 
 }  // anonymous namespace
diff --git a/ios/chrome/browser/toolbar/ui_bundled/tab_groups/test/tab_group_indicator_egtest.mm b/ios/chrome/browser/toolbar/ui_bundled/tab_groups/test/tab_group_indicator_egtest.mm
index 42999cb..0d97a712 100644
--- a/ios/chrome/browser/toolbar/ui_bundled/tab_groups/test/tab_group_indicator_egtest.mm
+++ b/ios/chrome/browser/toolbar/ui_bundled/tab_groups/test/tab_group_indicator_egtest.mm
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#import "base/ios/ios_util.h"
 #import "base/strings/sys_string_conversions.h"
 #import "components/data_sharing/public/features.h"
 #import "components/data_sharing/public/group_data.h"
@@ -366,6 +367,11 @@
 
 // Tests that renaming a tab group from the tab group indicator menu works.
 - (void)testTabGroupIndicatorMenuActionsRenameGroup {
+  // TODO(crbug.com/442817314): Re-enable this flaky test on iOS26.
+  if (base::ios::IsRunningOnIOS26OrLater()) {
+    EARL_GREY_TEST_DISABLED(@"Test disabled on iOS 26.");
+  }
+
   if ([ChromeEarlGrey isIPadIdiom]) {
     EARL_GREY_TEST_SKIPPED(@"On iPad, the tab group indicator is not displayed "
                            @"if the tab strip is visible.");
diff --git a/ios/chrome/browser/web/model/error_page_egtest.mm b/ios/chrome/browser/web/model/error_page_egtest.mm
index ce41369..a360823 100644
--- a/ios/chrome/browser/web/model/error_page_egtest.mm
+++ b/ios/chrome/browser/web/model/error_page_egtest.mm
@@ -76,6 +76,11 @@
 #define MAYBE_testBackForwardErrorPage testBackForwardErrorPage
 #endif
 - (void)MAYBE_testBackForwardErrorPage {
+  // TODO(crbug.com/443199230): Test Failing on iPad.
+  if ([ChromeEarlGrey isIPadIdiom]) {
+    EARL_GREY_TEST_DISABLED(@"Fails on iPads.");
+  }
+
   // TODO(crbug.com/40159013): Going back/forward on the same host is failing.
   // Use chrome:// to have a different hosts.
   std::string errorText = net::ErrorToShortString(net::ERR_INVALID_URL);
diff --git a/ios/chrome/browser/web/model/java_script_console/java_script_console_feature_factory.h b/ios/chrome/browser/web/model/java_script_console/java_script_console_feature_factory.h
index 54020ca..fa32d9c 100644
--- a/ios/chrome/browser/web/model/java_script_console/java_script_console_feature_factory.h
+++ b/ios/chrome/browser/web/model/java_script_console/java_script_console_feature_factory.h
@@ -23,9 +23,9 @@
   JavaScriptConsoleFeatureFactory();
   ~JavaScriptConsoleFeatureFactory() override;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_WEB_MODEL_JAVA_SCRIPT_CONSOLE_JAVA_SCRIPT_CONSOLE_FEATURE_FACTORY_H_
diff --git a/ios/chrome/browser/web/model/java_script_console/java_script_console_feature_factory.mm b/ios/chrome/browser/web/model/java_script_console/java_script_console_feature_factory.mm
index 7497908..a7ac7e1 100644
--- a/ios/chrome/browser/web/model/java_script_console/java_script_console_feature_factory.mm
+++ b/ios/chrome/browser/web/model/java_script_console/java_script_console_feature_factory.mm
@@ -31,6 +31,6 @@
 
 std::unique_ptr<KeyedService>
 JavaScriptConsoleFeatureFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
+    ProfileIOS* profile) const {
   return std::make_unique<JavaScriptConsoleFeature>();
 }
diff --git a/ios/chrome/browser/webauthn/model/ios_passkey_model_factory.cc b/ios/chrome/browser/webauthn/model/ios_passkey_model_factory.cc
index 24eea226..fd7515b7 100644
--- a/ios/chrome/browser/webauthn/model/ios_passkey_model_factory.cc
+++ b/ios/chrome/browser/webauthn/model/ios_passkey_model_factory.cc
@@ -37,8 +37,7 @@
 IOSPasskeyModelFactory::~IOSPasskeyModelFactory() {}
 
 std::unique_ptr<KeyedService> IOSPasskeyModelFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  ProfileIOS* profile = ProfileIOS::FromBrowserState(context);
+    ProfileIOS* profile) const {
   auto sync_bridge = std::make_unique<webauthn::PasskeySyncBridge>(
       DataTypeStoreServiceFactory::GetForProfile(profile)->GetStoreFactory());
 
diff --git a/ios/chrome/browser/webauthn/model/ios_passkey_model_factory.h b/ios/chrome/browser/webauthn/model/ios_passkey_model_factory.h
index 5b457ddd..5015179 100644
--- a/ios/chrome/browser/webauthn/model/ios_passkey_model_factory.h
+++ b/ios/chrome/browser/webauthn/model/ios_passkey_model_factory.h
@@ -27,9 +27,9 @@
   IOSPasskeyModelFactory();
   ~IOSPasskeyModelFactory() override;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 #endif  // IOS_CHROME_BROWSER_WEBAUTHN_MODEL_IOS_PASSKEY_MODEL_FACTORY_H_
diff --git a/ios/chrome/browser/webdata_services/model/web_data_service_factory.h b/ios/chrome/browser/webdata_services/model/web_data_service_factory.h
index 69e8e72..e39f5dc4 100644
--- a/ios/chrome/browser/webdata_services/model/web_data_service_factory.h
+++ b/ios/chrome/browser/webdata_services/model/web_data_service_factory.h
@@ -66,7 +66,7 @@
   static WebDataServiceFactory* GetInstance();
 
   // Returns the default factory, useful in tests where it's null by default.
-  static TestingFactory GetDefaultFactory();
+  static ProfileTestingFactory GetDefaultFactory();
 
  private:
   friend class base::NoDestructor<WebDataServiceFactory>;
@@ -74,9 +74,9 @@
   WebDataServiceFactory();
   ~WebDataServiceFactory() override;
 
-  // BrowserStateKeyedServiceFactory implementation.
+  // ProfileKeyedServiceFactoryIOS implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
-      web::BrowserState* context) const override;
+      ProfileIOS* profile) const override;
 };
 
 }  // namespace ios
diff --git a/ios/chrome/browser/webdata_services/model/web_data_service_factory.mm b/ios/chrome/browser/webdata_services/model/web_data_service_factory.mm
index d7db304..42a8148 100644
--- a/ios/chrome/browser/webdata_services/model/web_data_service_factory.mm
+++ b/ios/chrome/browser/webdata_services/model/web_data_service_factory.mm
@@ -25,8 +25,8 @@
 
 namespace {
 
-std::unique_ptr<KeyedService> BuildWebDataService(web::BrowserState* context) {
-  const base::FilePath& state_path = context->GetStatePath();
+std::unique_ptr<KeyedService> BuildWebDataService(ProfileIOS* profile) {
+  const base::FilePath& state_path = profile->GetStatePath();
   // On iOS (and Android), the account storage is persisted on disk.
   return std::make_unique<WebDataServiceWrapper>(
       state_path, GetApplicationContext()->GetApplicationLocaleStorage()->Get(),
@@ -108,9 +108,9 @@
 }
 
 // static
-ProfileKeyedServiceFactoryIOS::TestingFactory
+ProfileKeyedServiceFactoryIOS::ProfileTestingFactory
 WebDataServiceFactory::GetDefaultFactory() {
-  return base::BindRepeating(&BuildWebDataService);
+  return base::BindOnce(&BuildWebDataService);
 }
 
 WebDataServiceFactory::WebDataServiceFactory()
@@ -121,8 +121,8 @@
 WebDataServiceFactory::~WebDataServiceFactory() {}
 
 std::unique_ptr<KeyedService> WebDataServiceFactory::BuildServiceInstanceFor(
-    web::BrowserState* context) const {
-  return BuildWebDataService(context);
+    ProfileIOS* profile) const {
+  return BuildWebDataService(profile);
 }
 
 }  // namespace ios
diff --git a/ios/web_view/internal/sync/web_view_sync_service_factory.mm b/ios/web_view/internal/sync/web_view_sync_service_factory.mm
index fff0f0e..2fff513 100644
--- a/ios/web_view/internal/sync/web_view_sync_service_factory.mm
+++ b/ios/web_view/internal/sync/web_view_sync_service_factory.mm
@@ -105,7 +105,6 @@
   controller_builder.SetPasswordReceiverService(nullptr);
   controller_builder.SetPasswordSenderService(nullptr);
   controller_builder.SetPlusAddressServices(nullptr, nullptr);
-  controller_builder.SetPowerBookmarkService(nullptr);
   controller_builder.SetPrefServiceSyncable(nullptr);
   // TODO(crbug.com/330201909) implement for iOS.
   controller_builder.SetProductSpecificationsService(nullptr);
diff --git a/media/renderers/paint_canvas_video_renderer_unittest.cc b/media/renderers/paint_canvas_video_renderer_unittest.cc
index be176a4..2dceb47 100644
--- a/media/renderers/paint_canvas_video_renderer_unittest.cc
+++ b/media/renderers/paint_canvas_video_renderer_unittest.cc
@@ -45,7 +45,6 @@
 #include "third_party/skia/include/core/SkImage.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 #include "third_party/skia/include/core/SkSurface.h"
-#include "third_party/skia/include/gpu/ganesh/GrDirectContext.h"
 #include "third_party/skia/include/private/chromium/SkPMColor.h"
 #include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/rect_f.h"
@@ -1001,54 +1000,8 @@
       texsubimage2d_callback_;
 };
 
-#if !BUILDFLAG(IS_ANDROID)
-void MailboxHoldersReleased(const gpu::SyncToken& sync_token) {}
-#endif
 }  // namespace
 
-// NOTE: The below test tests behavior when PaintCanvasVideoRenderer is used
-// without GPU raster. It is not relevant on Android, where GPU raster is
-// always used.
-#if !BUILDFLAG(IS_ANDROID)
-// Test that PaintCanvasVideoRenderer::Paint doesn't crash when GrContext is
-// unable to wrap a video frame texture (eg due to being abandoned).
-TEST_F(PaintCanvasVideoRendererTest, ContextLost) {
-  auto context_provider = viz::TestContextProvider::Create();
-  CHECK(context_provider);
-  context_provider->BindToCurrentSequence();
-  CHECK(context_provider->GrContext());
-  context_provider->GrContext()->abandonContext();
-
-  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.
-  gpu::SharedImageMetadata metadata;
-  metadata.format = viz::SinglePlaneFormat::kRGBA_8888;
-  metadata.size = size;
-  metadata.color_space = gfx::ColorSpace::CreateSRGB();
-  metadata.surface_origin = kTopLeft_GrSurfaceOrigin;
-  metadata.alpha_type = kOpaque_SkAlphaType;
-  metadata.usage = gpu::SHARED_IMAGE_USAGE_RASTER_READ;
-  scoped_refptr<gpu::ClientSharedImage> shared_image =
-      gpu::ClientSharedImage::CreateForTesting(metadata);
-  auto video_frame = VideoFrame::WrapSharedImage(
-      PIXEL_FORMAT_NV12, shared_image, gpu::SyncToken(),
-      base::BindOnce(MailboxHoldersReleased), size, gfx::Rect(size), size,
-      kNoTimestamp);
-
-  cc::PaintFlags flags;
-  flags.setFilterQuality(cc::PaintFlags::FilterQuality::kLow);
-  PaintCanvasVideoRenderer::PaintParams params;
-  params.dest_rect = kNaturalRect;
-  renderer_.Paint(std::move(video_frame), &canvas, flags, params,
-                  context_provider.get());
-}
-#endif
-
-void EmptyCallback(const gpu::SyncToken& sync_token) {}
-
 TEST_F(PaintCanvasVideoRendererTest, CorrectFrameSizeToVisibleRect) {
   constexpr int fWidth{16}, fHeight{16};
   SkImageInfo imInfo =
diff --git a/services/data_decoder/public/cpp/json_sanitizer_non_android.cc b/services/data_decoder/public/cpp/json_sanitizer_non_android.cc
index 7b7d1a2..b760e5c4 100644
--- a/services/data_decoder/public/cpp/json_sanitizer_non_android.cc
+++ b/services/data_decoder/public/cpp/json_sanitizer_non_android.cc
@@ -28,11 +28,12 @@
                               value.type() != base::Value::Type::LIST) {
                             return base::unexpected("Invalid top-level type");
                           }
-                          std::string safe_json;
-                          if (!base::JSONWriter::Write(value, &safe_json)) {
+                          std::optional<std::string> safe_json =
+                              base::WriteJson(value);
+                          if (!safe_json.has_value()) {
                             return base::unexpected("Encoding error");
                           }
-                          return base::ok(std::move(safe_json));
+                          return base::ok(std::move(safe_json.value()));
                         }));
           },
           std::move(callback)));
diff --git a/services/device/geolocation/network_location_request.cc b/services/device/geolocation/network_location_request.cc
index 39c6723..b0cef9b 100644
--- a/services/device/geolocation/network_location_request.cc
+++ b/services/device/geolocation/network_location_request.cc
@@ -251,8 +251,7 @@
   url_loader_->SetAllowHttpErrorResults(true);
 
   request_data_ = FormUploadData(wifi_data, wifi_timestamp);
-  std::string upload_data;
-  base::JSONWriter::Write(request_data_, &upload_data);
+  std::string upload_data = base::WriteJson(request_data_).value_or("");
   url_loader_->AttachStringForUpload(upload_data, "application/json");
 
   url_loader_->DownloadToString(
diff --git a/services/image_annotation/annotator.cc b/services/image_annotation/annotator.cc
index fc49c4fb..7631ec6 100644
--- a/services/image_annotation/annotator.cc
+++ b/services/image_annotation/annotator.cc
@@ -754,8 +754,7 @@
   base::Value::Dict request;
   request.Set("imageRequests", std::move(image_request_list));
 
-  std::string json_request;
-  base::JSONWriter::Write(request, &json_request);
+  std::string json_request = base::WriteJson(request).value_or("");
 
   ReportServerRequestSizeKB(json_request.size() / 1024);
 
diff --git a/services/image_annotation/annotator_unittest.cc b/services/image_annotation/annotator_unittest.cc
index ef2c0c5..a4db6ed 100644
--- a/services/image_annotation/annotator_unittest.cc
+++ b/services/image_annotation/annotator_unittest.cc
@@ -362,13 +362,7 @@
 // Returns a "canonically" formatted version of a JSON string by parsing and
 // then rewriting it.
 std::string ReformatJson(const std::string& in) {
-  const std::optional<base::Value> json = base::JSONReader::Read(in);
-  CHECK(json);
-
-  std::string out;
-  base::JSONWriter::Write(*json, &out);
-
-  return out;
+  return base::WriteJson(base::JSONReader::Read(in).value()).value_or("");
 }
 
 // Receives the result of an annotation request and writes the result data into
diff --git a/services/network/accept_ch_frame_interceptor.cc b/services/network/accept_ch_frame_interceptor.cc
index ff53ca4..88157900a 100644
--- a/services/network/accept_ch_frame_interceptor.cc
+++ b/services/network/accept_ch_frame_interceptor.cc
@@ -167,17 +167,30 @@
   }
 
   CHECK(base::FeatureList::IsEnabled(features::kOffloadAcceptCHFrameCheck));
-  if (!std::all_of(hints.cbegin(), hints.cend(),
-                   [&](const network::mojom::WebClientHintsType& h) {
-                     const bool hint_enabled =
-                         base::Contains(enabled_client_hints_->hints, h);
-                     if (!hint_enabled) {
-                       base::UmaHistogramEnumeration(
-                           "Net.AcceptCHFrameInterceptor.MismatchClientHint",
-                           h);
-                     }
-                     return hint_enabled;
-                   })) {
+  // The Accept-CH frame can be offloaded (i.e., handled in the network
+  // service without an IPC to the browser process) if all hints in the frame
+  // are present in either the `hints` list (enabled and allowed) or the
+  // `not_allowed_hints` list (persisted but currently disallowed). If any hint
+  // is not in either list, we must fall back to the browser process to check.
+  bool needs_observer_check = false;
+  for (const auto& h : hints) {
+    const bool is_in_hints = base::Contains(enabled_client_hints_->hints, h);
+    const bool is_in_not_allowed_hints =
+        features::kAcceptCHFrameOffloadNotAllowedHints.Get() &&
+        base::Contains(enabled_client_hints_->not_allowed_hints, h);
+    const bool is_valid_for_offload = is_in_hints || is_in_not_allowed_hints;
+    if (is_in_not_allowed_hints && !is_in_hints) {
+      base::UmaHistogramEnumeration(
+          "Net.AcceptCHFrameInterceptor.OffloadSuccessForNotAllowedHint", h);
+    }
+    if (!is_valid_for_offload) {
+      needs_observer_check = true;
+      base::UmaHistogramEnumeration(
+          "Net.AcceptCHFrameInterceptor.MismatchClientHint2", h);
+    }
+  }
+
+  if (needs_observer_check) {
     return NeedsObserverCheckReason::kHintNotEnabled;
   }
 
diff --git a/services/network/accept_ch_frame_interceptor_unittest.cc b/services/network/accept_ch_frame_interceptor_unittest.cc
index 7b1081f..24f87f7 100644
--- a/services/network/accept_ch_frame_interceptor_unittest.cc
+++ b/services/network/accept_ch_frame_interceptor_unittest.cc
@@ -47,7 +47,7 @@
 };
 
 TEST_F(AcceptCHFrameInterceptorTest, NeedsObserverCheckNullOpt) {
-  const GURL kUrl("https://a.com");
+  const GURL kUrl("https://a.test");
   Initialize(std::nullopt);
   EXPECT_EQ(NeedsObserverCheck(url::Origin::Create(kUrl),
                                std::vector<mojom::WebClientHintsType>()),
@@ -57,7 +57,7 @@
 
 TEST_F(AcceptCHFrameInterceptorTest,
        NeedsObserverCheckEmptyHintsShouldBeFalse) {
-  const GURL kUrl("https://a.com");
+  const GURL kUrl("https://a.test");
   const url::Origin kOrigin(url::Origin::Create(kUrl));
   std::vector<mojom::WebClientHintsType> added_hints = {
       network::mojom::WebClientHintsType::kUAArch,
@@ -72,7 +72,7 @@
 
 TEST_F(AcceptCHFrameInterceptorTest,
        NeedsObserverCheckAMatchHintShouldBeFalse) {
-  const GURL kUrl("https://a.com");
+  const GURL kUrl("https://a.test");
   const url::Origin kOrigin(url::Origin::Create(kUrl));
   std::vector<mojom::WebClientHintsType> test_vector = {
       network::mojom::WebClientHintsType::kUAArch,
@@ -84,7 +84,7 @@
 
 TEST_F(AcceptCHFrameInterceptorTest,
        NeedsObserverCheckMultipleMatchHintsShouldBeFalse) {
-  const GURL kUrl("https://a.com");
+  const GURL kUrl("https://a.test");
   const url::Origin kOrigin(url::Origin::Create(kUrl));
   std::vector<mojom::WebClientHintsType> test_vector = {
       network::mojom::WebClientHintsType::kUAArch,
@@ -96,7 +96,7 @@
 }
 
 TEST_F(AcceptCHFrameInterceptorTest, NeedsObserverCheckAMismatchShouldBeTrue) {
-  const GURL kUrl("https://a.com");
+  const GURL kUrl("https://a.test");
   const url::Origin kOrigin(url::Origin::Create(kUrl));
   std::vector<mojom::WebClientHintsType> added_hints = {
       network::mojom::WebClientHintsType::kUAArch,
@@ -114,7 +114,7 @@
 
 TEST_F(AcceptCHFrameInterceptorTest,
        NeedsObserverCheckOneOfEntriesMismatchesShouldBeTrue) {
-  const GURL kUrl("https://a.com");
+  const GURL kUrl("https://a.test");
   const url::Origin kOrigin(url::Origin::Create(kUrl));
   std::vector<mojom::WebClientHintsType> added_hints = {
       network::mojom::WebClientHintsType::kUAArch,
@@ -133,13 +133,13 @@
 
 TEST_F(AcceptCHFrameInterceptorTest,
        NeedsObserverCheckDifferentOriginShouldBeTrue) {
-  const GURL kUrl("https://a.com");
+  const GURL kUrl("https://a.test");
   const url::Origin kOrigin(url::Origin::Create(kUrl));
   std::vector<mojom::WebClientHintsType> test_vector = {
       network::mojom::WebClientHintsType::kUAArch,
   };
   Initialize(CreateEnabledClientHints(kOrigin, test_vector));
-  const GURL kOther("https://b.com");
+  const GURL kOther("https://b.test");
   const url::Origin kOtherOrigin(url::Origin::Create(kOther));
   EXPECT_EQ(NeedsObserverCheck(kOtherOrigin, test_vector),
             AcceptCHFrameInterceptor::NeedsObserverCheckReason::
@@ -148,7 +148,7 @@
 
 TEST_F(AcceptCHFrameInterceptorTest,
        NeedsObserverCheckNotOutermostMainFrameShouldBeTrue) {
-  const GURL kUrl("https://a.com");
+  const GURL kUrl("https://a.test");
   const url::Origin kOrigin(url::Origin::Create(kUrl));
   std::vector<mojom::WebClientHintsType> test_vector = {
       network::mojom::WebClientHintsType::kUAArch,
@@ -166,14 +166,14 @@
   feature_list.InitAndEnableFeatureWithParameters(
       features::kOffloadAcceptCHFrameCheck,
       {{"AcceptCHOffloadForSubframe", "false"}});
-  const GURL kUrl("https://a.com");
+  const GURL kUrl("https://a.test");
   const url::Origin kOrigin(url::Origin::Create(kUrl));
   std::vector<mojom::WebClientHintsType> test_vector = {
       network::mojom::WebClientHintsType::kUAArch,
   };
   Initialize(CreateEnabledClientHints(kOrigin, test_vector,
                                       /*is_outermost_main_frame=*/false));
-  const GURL kOther("https://b.com");
+  const GURL kOther("https://b.test");
   const url::Origin kOtherOrigin(url::Origin::Create(kOther));
   EXPECT_EQ(NeedsObserverCheck(kOtherOrigin, test_vector),
             AcceptCHFrameInterceptor::NeedsObserverCheckReason::
@@ -186,17 +186,66 @@
   feature_list.InitAndEnableFeatureWithParameters(
       features::kOffloadAcceptCHFrameCheck,
       {{"AcceptCHOffloadForSubframe", "true"}});
-  const GURL kUrl("https://a.com");
+  const GURL kUrl("https://a.test");
   const url::Origin kOrigin(url::Origin::Create(kUrl));
   std::vector<mojom::WebClientHintsType> test_vector = {
       network::mojom::WebClientHintsType::kUAArch,
   };
   Initialize(CreateEnabledClientHints(kOrigin, test_vector,
                                       /*is_outermost_main_frame=*/false));
-  const GURL kOther("https://b.com");
+  const GURL kOther("https://b.test");
   const url::Origin kOtherOrigin(url::Origin::Create(kOther));
   EXPECT_EQ(NeedsObserverCheck(kOtherOrigin, test_vector),
             AcceptCHFrameInterceptor::NeedsObserverCheckReason::kNotNeeded);
 }
 
+TEST_F(AcceptCHFrameInterceptorTest,
+       NeedsObserverCheckNotAllowedHintWithFeature) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeatureWithParameters(
+      features::kOffloadAcceptCHFrameCheck,
+      {{"AcceptCHFrameOffloadNotAllowedHints", "true"}});
+
+  const GURL kUrl("https://a.test");
+  const url::Origin kOrigin(url::Origin::Create(kUrl));
+  auto enabled_client_hints = CreateEnabledClientHints(
+      kOrigin, {network::mojom::WebClientHintsType::kUAArch});
+  enabled_client_hints.not_allowed_hints = {
+      network::mojom::WebClientHintsType::kUAPlatform};
+  Initialize(std::move(enabled_client_hints));
+
+  // A hint that is only in `not_allowed_hints` should be considered enabled.
+  EXPECT_EQ(NeedsObserverCheck(
+                kOrigin, {network::mojom::WebClientHintsType::kUAPlatform}),
+            AcceptCHFrameInterceptor::NeedsObserverCheckReason::kNotNeeded);
+
+  // A mix of hints from both lists should also be considered enabled.
+  EXPECT_EQ(NeedsObserverCheck(
+                kOrigin, {network::mojom::WebClientHintsType::kUAArch,
+                          network::mojom::WebClientHintsType::kUAPlatform}),
+            AcceptCHFrameInterceptor::NeedsObserverCheckReason::kNotNeeded);
+}
+
+TEST_F(AcceptCHFrameInterceptorTest,
+       NeedsObserverCheckNotAllowedHintWithoutFeature) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeatureWithParameters(
+      features::kOffloadAcceptCHFrameCheck,
+      {{"AcceptCHFrameOffloadNotAllowedHints", "false"}});
+
+  const GURL kUrl("https://a.test");
+  const url::Origin kOrigin(url::Origin::Create(kUrl));
+  auto enabled_client_hints = CreateEnabledClientHints(
+      kOrigin, {network::mojom::WebClientHintsType::kUAArch});
+  enabled_client_hints.not_allowed_hints = {
+      network::mojom::WebClientHintsType::kUAPlatform};
+  Initialize(std::move(enabled_client_hints));
+
+  // A hint that is only in `not_allowed_hints` should be a mismatch.
+  EXPECT_EQ(
+      NeedsObserverCheck(kOrigin,
+                         {network::mojom::WebClientHintsType::kUAPlatform}),
+      AcceptCHFrameInterceptor::NeedsObserverCheckReason::kHintNotEnabled);
+}
+
 }  // namespace network
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc
index b681863..5c39cc7 100644
--- a/services/network/public/cpp/features.cc
+++ b/services/network/public/cpp/features.cc
@@ -166,6 +166,16 @@
              "OffloadAcceptCHFrameCheck",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+// When enabled, the network service will consider not-allowed but persisted
+// client hints as "enabled" for the purpose of the Accept-CH frame offload
+// check.
+// See crbug.com/406407746 for details.
+BASE_FEATURE_PARAM(bool,
+                   kAcceptCHFrameOffloadNotAllowedHints,
+                   &kOffloadAcceptCHFrameCheck,
+                   "AcceptCHFrameOffloadNotAllowedHints",
+                   false);
+
 // Enable offloading the network layer to check enabled client hints even when
 // cross origin redirect happens.
 // See crbug.com/406407746 for details.
diff --git a/services/network/public/cpp/features.h b/services/network/public/cpp/features.h
index 3f81a525..b0e9e73 100644
--- a/services/network/public/cpp/features.h
+++ b/services/network/public/cpp/features.h
@@ -66,6 +66,8 @@
 COMPONENT_EXPORT(NETWORK_CPP_FLAGS_AND_SWITCHES)
 BASE_DECLARE_FEATURE(kOffloadAcceptCHFrameCheck);
 COMPONENT_EXPORT(NETWORK_CPP_FLAGS_AND_SWITCHES)
+BASE_DECLARE_FEATURE_PARAM(bool, kAcceptCHFrameOffloadNotAllowedHints);
+COMPONENT_EXPORT(NETWORK_CPP_FLAGS_AND_SWITCHES)
 BASE_DECLARE_FEATURE_PARAM(bool, kAcceptCHOffloadWithRedirect);
 COMPONENT_EXPORT(NETWORK_CPP_FLAGS_AND_SWITCHES)
 BASE_DECLARE_FEATURE_PARAM(bool, kAcceptCHOffloadForSubframe);
diff --git a/services/network/public/cpp/resource_request.h b/services/network/public/cpp/resource_request.h
index 3137a61c..759539fe 100644
--- a/services/network/public/cpp/resource_request.h
+++ b/services/network/public/cpp/resource_request.h
@@ -72,7 +72,15 @@
 
       url::Origin origin;
       bool is_outermost_main_frame = false;
+      // The set of client hints that are enabled for the origin and currently
+      // allowed to be attached to the request (e.g., by Feature Policy).
       std::vector<network::mojom::WebClientHintsType> hints;
+      // The set of client hints that are persisted for the origin but are
+      // currently not allowed to be attached to the request (e.g., blocked by
+      // Feature Policy). This is used in the network service to avoid an
+      // unnecessary IPC to the browser process when an ACCEPT_CH frame contains
+      // such hints.
+      std::vector<network::mojom::WebClientHintsType> not_allowed_hints;
     };
 
     TrustedParams();
diff --git a/services/network/public/cpp/url_request_mojom_traits.cc b/services/network/public/cpp/url_request_mojom_traits.cc
index 1d4476c..828d1d57 100644
--- a/services/network/public/cpp/url_request_mojom_traits.cc
+++ b/services/network/public/cpp/url_request_mojom_traits.cc
@@ -49,6 +49,9 @@
   if (!data.ReadHints(&out->hints)) {
     return false;
   }
+  if (!data.ReadNotAllowedHints(&out->not_allowed_hints)) {
+    return false;
+  }
   return true;
 }
 
diff --git a/services/network/public/cpp/url_request_mojom_traits.h b/services/network/public/cpp/url_request_mojom_traits.h
index 933a3cc..3a028b9 100644
--- a/services/network/public/cpp/url_request_mojom_traits.h
+++ b/services/network/public/cpp/url_request_mojom_traits.h
@@ -72,6 +72,13 @@
     return enabled_client_hints.hints;
   }
 
+  static const std::vector<network::mojom::WebClientHintsType>&
+  not_allowed_hints(
+      const network::ResourceRequest::TrustedParams::EnabledClientHints&
+          enabled_client_hints) {
+    return enabled_client_hints.not_allowed_hints;
+  }
+
   static bool Read(
       network::mojom::EnabledClientHintsDataView data,
       network::ResourceRequest::TrustedParams::EnabledClientHints* out);
diff --git a/services/network/public/cpp/url_request_mojom_traits_unittest.cc b/services/network/public/cpp/url_request_mojom_traits_unittest.cc
index 93e606b..f6b7cd6 100644
--- a/services/network/public/cpp/url_request_mojom_traits_unittest.cc
+++ b/services/network/public/cpp/url_request_mojom_traits_unittest.cc
@@ -68,7 +68,7 @@
   original.request_initiator = url::Origin::Create(original.url);
   original.isolated_world_origin =
       url::Origin::Create(GURL("chrome-extension://blah"));
-  original.referrer = GURL("https://referrer.com/");
+  original.referrer = GURL("https://referrer.test/");
   original.referrer_policy =
       net::ReferrerPolicy::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN;
   original.headers.SetHeader("Accept", "text/xml");
@@ -127,16 +127,20 @@
   original.trusted_params->include_request_cookies_with_response = true;
   original.trusted_params->enabled_client_hints.emplace();
   original.trusted_params->enabled_client_hints->origin =
-      url::Origin::Create(GURL("https://a.com"));
+      url::Origin::Create(GURL("https://a.test"));
   original.trusted_params->enabled_client_hints->is_outermost_main_frame = true;
   original.trusted_params->enabled_client_hints->hints = {
       network::mojom::WebClientHintsType::kUAArch,
       network::mojom::WebClientHintsType::kUAWoW64,
   };
+  original.trusted_params->enabled_client_hints->not_allowed_hints = {
+      network::mojom::WebClientHintsType::kUAPlatform,
+      network::mojom::WebClientHintsType::kUAModel,
+  };
 
   original.trust_token_params = network::mojom::TrustTokenParams();
   original.trust_token_params->issuers.push_back(
-      url::Origin::Create(GURL("https://issuer.com")));
+      url::Origin::Create(GURL("https://issuer.test")));
   original.trust_token_params->operation =
       mojom::TrustTokenOperationType::kRedemption;
   original.trust_token_params->include_timestamp_header = true;
@@ -186,12 +190,16 @@
   original.include_request_cookies_with_response = true;
   original.enabled_client_hints.emplace();
   original.enabled_client_hints->origin =
-      url::Origin::Create(GURL("https://a.com"));
+      url::Origin::Create(GURL("https://a.test"));
   original.enabled_client_hints->is_outermost_main_frame = true;
   original.enabled_client_hints->hints = {
       network::mojom::WebClientHintsType::kUAArch,
       network::mojom::WebClientHintsType::kUAWoW64,
   };
+  original.enabled_client_hints->not_allowed_hints = {
+      network::mojom::WebClientHintsType::kUAPlatform,
+      network::mojom::WebClientHintsType::kUAModel,
+  };
   network::ResourceRequest::TrustedParams copied;
   EXPECT_TRUE(
       mojo::test::SerializeAndDeserialize<mojom::TrustedUrlRequestParams>(
diff --git a/services/network/public/mojom/url_request.mojom b/services/network/public/mojom/url_request.mojom
index 02651c7..950d6e0 100644
--- a/services/network/public/mojom/url_request.mojom
+++ b/services/network/public/mojom/url_request.mojom
@@ -52,8 +52,16 @@
   // Whether this is for an outermost main frame.
   bool is_outermost_main_frame;
 
-  // The client hints enabled for the request.
+  // The set of client hints that are enabled for the origin and currently
+  // allowed to be attached to the request (e.g., by Feature Policy).
   array<WebClientHintsType> hints;
+
+  // The set of client hints that are persisted for the origin but are
+  // currently not allowed to be attached to the request (e.g., blocked by
+  // Feature Policy). This is used in the network service to avoid an
+  // unnecessary IPC to the browser process when an ACCEPT_CH frame contains
+  // such hints.
+  array<WebClientHintsType> not_allowed_hints;
 };
 
 // See documentation at `URLRequest.trusted_params`.
diff --git a/services/network/sct_auditing/sct_auditing_handler.cc b/services/network/sct_auditing/sct_auditing_handler.cc
index e8d736dc..188b78d 100644
--- a/services/network/sct_auditing/sct_auditing_handler.cc
+++ b/services/network/sct_auditing/sct_auditing_handler.cc
@@ -214,11 +214,7 @@
     reports.Append(std::move(report_entry));
   }
 
-  std::string output;
-  if (!base::JSONWriter::Write(reports, &output)) {
-    return std::nullopt;
-  }
-  return output;
+  return base::WriteJson(reports);
 }
 
 void SCTAuditingHandler::DeserializeData(const std::string& serialized) {
diff --git a/services/network/trust_tokens/trust_token_key_commitment_parser_unittest.cc b/services/network/trust_tokens/trust_token_key_commitment_parser_unittest.cc
index 2c6f964ec..94d965d 100644
--- a/services/network/trust_tokens/trust_token_key_commitment_parser_unittest.cc
+++ b/services/network/trust_tokens/trust_token_key_commitment_parser_unittest.cc
@@ -830,15 +830,12 @@
 }
 
 void ParsesOneIssuerCorrectly(base::Value value) {
-  std::string output;
-  base::JSONWriter::Write(std::move(value), &output);
-  TrustTokenKeyCommitmentParser().Parse(output);
+  TrustTokenKeyCommitmentParser().Parse(base::WriteJson(value).value_or(""));
 }
 
 void ParsesMultipleIssuersCorrectly(base::Value value) {
-  std::string output;
-  base::JSONWriter::Write(std::move(value), &output);
-  TrustTokenKeyCommitmentParser().ParseMultipleIssuers(output);
+  TrustTokenKeyCommitmentParser().ParseMultipleIssuers(
+      base::WriteJson(value).value_or(""));
 }
 
 FUZZ_TEST(TrustTokenKeyCommitmentFuzzer, ParsesOneIssuerCorrectly);
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc
index 47a064d..74fbdb3 100644
--- a/services/network/url_loader_unittest.cc
+++ b/services/network/url_loader_unittest.cc
@@ -5975,6 +5975,64 @@
                     TestMode::kCredentialsModeOmitWorkaround,
                     TestMode::kCredentialsModeOmitWithFeatureFix));
 
+TEST_F(URLLoaderTest, AcceptCHFrameNotAllowedHintWithFeature) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeatureWithParameters(
+      features::kOffloadAcceptCHFrameCheck,
+      {{"AcceptCHFrameOffloadNotAllowedHints", "true"}});
+
+  net::TransportInfo info = net::DefaultTransportInfo();
+  info.accept_ch_frame = "Sec-CH-UA-Platform";
+
+  const GURL url("http://accept-ch.test/");
+  net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
+      url, std::make_unique<FakeTransportInfoInterceptor>(info));
+
+  MockAcceptCHFrameObserver observer;
+  set_accept_ch_frame_observer_for_next_request(&observer);
+
+  network::ResourceRequest::TrustedParams::EnabledClientHints enabled_hints;
+  enabled_hints.origin = url::Origin::Create(url);
+  enabled_hints.is_outermost_main_frame = true;
+  enabled_hints.hints = {network::mojom::WebClientHintsType::kUAArch};
+  enabled_hints.not_allowed_hints = {
+      network::mojom::WebClientHintsType::kUAPlatform};
+  set_enabled_client_hints_for_next_request(std::move(enabled_hints));
+
+  EXPECT_THAT(Load(url), IsOk());
+  EXPECT_FALSE(observer.called());
+}
+
+TEST_F(URLLoaderTest, AcceptCHFrameNotAllowedHintWithoutFeature) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeatureWithParameters(
+      features::kOffloadAcceptCHFrameCheck,
+      {{"AcceptCHFrameOffloadNotAllowedHints", "false"}});
+
+  net::TransportInfo info = net::DefaultTransportInfo();
+  info.accept_ch_frame = "Sec-CH-UA-Platform";
+
+  const GURL url("http://accept-ch.test/");
+  net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
+      url, std::make_unique<FakeTransportInfoInterceptor>(info));
+
+  MockAcceptCHFrameObserver observer;
+  set_accept_ch_frame_observer_for_next_request(&observer);
+
+  network::ResourceRequest::TrustedParams::EnabledClientHints enabled_hints;
+  enabled_hints.origin = url::Origin::Create(url);
+  enabled_hints.is_outermost_main_frame = true;
+  enabled_hints.hints = {network::mojom::WebClientHintsType::kUAArch};
+  enabled_hints.not_allowed_hints = {
+      network::mojom::WebClientHintsType::kUAPlatform};
+  set_enabled_client_hints_for_next_request(std::move(enabled_hints));
+
+  EXPECT_THAT(Load(url), IsOk());
+  EXPECT_TRUE(observer.called());
+  EXPECT_THAT(observer.accept_ch_frame(),
+              ElementsAre(network::mojom::WebClientHintsType::kUAPlatform));
+}
+
 // Tests that a request with CredentialsMode::kOmit still sends client
 // certificates when features::kOmitCorsClientCert is disabled, and when the
 // feature is enabled client certificates are not sent. Also test that when
diff --git a/services/tracing/public/cpp/perfetto/metadata_data_source.cc b/services/tracing/public/cpp/perfetto/metadata_data_source.cc
index e0978a4..28c0346 100644
--- a/services/tracing/public/cpp/perfetto/metadata_data_source.cc
+++ b/services/tracing/public/cpp/perfetto/metadata_data_source.cc
@@ -218,9 +218,7 @@
   } else if (value.is_string()) {
     metadata->set_string_value(value.GetString().c_str());
   } else {
-    std::string json_value;
-    base::JSONWriter::Write(value, &json_value);
-    metadata->set_json_value(json_value.c_str());
+    metadata->set_json_value(base::WriteJson(value).value_or(""));
   }
 }
 
diff --git a/services/tracing/public/cpp/perfetto/trace_event_metadata_source.cc b/services/tracing/public/cpp/perfetto/trace_event_metadata_source.cc
index 2778844..ea6c697 100644
--- a/services/tracing/public/cpp/perfetto/trace_event_metadata_source.cc
+++ b/services/tracing/public/cpp/perfetto/trace_event_metadata_source.cc
@@ -224,9 +224,7 @@
       } else if (it.second.is_string()) {
         new_metadata->set_string_value(it.second.GetString().c_str());
       } else {
-        std::string json_value;
-        base::JSONWriter::Write(it.second, &json_value);
-        new_metadata->set_json_value(json_value.c_str());
+        new_metadata->set_json_value(base::WriteJson(it.second).value_or(""));
       }
     }
   };
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index b5370aa..a2d19230 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2455,6 +2455,7 @@
                     "enable_features": [
                         "AutofillEnableEmailOrLoyaltyCardsFilling",
                         "AutofillEnableLoyaltyCardsFilling",
+                        "IPH_AutofillEnableLoyaltyCards",
                         "SyncAutofillLoyaltyCard"
                     ]
                 }
@@ -20775,13 +20776,45 @@
     "RenderDocumentWithNavigationQueueing": [
         {
             "platforms": [
-                "android",
                 "chromeos",
+                "fuchsia",
+                "ios",
                 "linux",
+                "mac",
                 "windows"
             ],
             "experiments": [
                 {
+                    "name": "EnabledSubframeWithQueueing",
+                    "params": {
+                        "level": "subframe",
+                        "queueing_level": "full"
+                    },
+                    "enable_features": [
+                        "DelayLayerTreeViewDeletionOnLocalSwap",
+                        "QueueNavigationsWhileWaitingForCommit",
+                        "RenderDocument"
+                    ],
+                    "disable_features": [
+                        "RenderDocumentCompositorReuse"
+                    ]
+                },
+                {
+                    "name": "EnabledCrashedFrameWithQueueing",
+                    "params": {
+                        "level": "crashed-frame",
+                        "queueing_level": "full"
+                    },
+                    "enable_features": [
+                        "DelayLayerTreeViewDeletionOnLocalSwap",
+                        "QueueNavigationsWhileWaitingForCommit",
+                        "RenderDocument"
+                    ],
+                    "disable_features": [
+                        "RenderDocumentCompositorReuse"
+                    ]
+                },
+                {
                     "name": "EnabledAllFramesWithQueueing",
                     "params": {
                         "level": "all-frames",
@@ -20799,16 +20832,16 @@
             ]
         }
     ],
-    "RenderDocumentWithNavigationQueueing_Mac": [
+    "RenderDocumentWithNavigationQueueing_Android": [
         {
             "platforms": [
-                "mac"
+                "android"
             ],
             "experiments": [
                 {
-                    "name": "EnabledSubframeWithQueueing",
+                    "name": "EnabledAllFramesWithQueueing",
                     "params": {
-                        "level": "subframe",
+                        "level": "all-frames",
                         "queueing_level": "full"
                     },
                     "enable_features": [
diff --git a/third_party/androidx/build.gradle b/third_party/androidx/build.gradle
index a7ba518..e0f56cb1 100644
--- a/third_party/androidx/build.gradle
+++ b/third_party/androidx/build.gradle
@@ -310,7 +310,7 @@
     google()
     maven {
         // This URL is generated by the fetch_all_androidx.py script.
-        url 'https://androidx.dev/snapshots/builds/14048353/artifacts/repository'
+        url 'https://androidx.dev/snapshots/builds/14050537/artifacts/repository'
     }
     mavenCentral()
 }
diff --git a/third_party/angle b/third_party/angle
index e893313..fe30cd1 160000
--- a/third_party/angle
+++ b/third_party/angle
@@ -1 +1 @@
-Subproject commit e893313ccef7686c9f4c4444c9a605b0578b1534
+Subproject commit fe30cd1a5fecfc2bb7581a742c15e0eb1fd77296
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 7e1c3d6..5fb3e60 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -2177,6 +2177,17 @@
                    "report_inconsistent_header",
                    false);
 
+// If true, the browser enables synthetic response with the dry run mode. With
+// this mode, the navigation request is involved with the service worker code
+// path, and the synthetic response eligiblity is evaluated as if the feature is
+// enabled. But it doesn't store response headers and actually "synthesize"
+// responses with them. This mode is used to compare the metrics.
+BASE_FEATURE_PARAM(bool,
+                   kServiceWorkerSyntheticResponseDryRun,
+                   &kServiceWorkerSyntheticResponse,
+                   "dry_run",
+                   false);
+
 // 'Mode' parameter for blink::features::kSoftNavigationHeuristics.
 const base::FeatureParam<SoftNavigationHeuristicsMode>::Option
     kSoftNavigationHeuristicsModes[] = {
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index 2f501ddd..d7c6366 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -1683,6 +1683,10 @@
     bool,
     kServiceWorkerSyntheticResponseReportInconsistentHeader);
 
+BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE_PARAM(
+    bool,
+    kServiceWorkerSyntheticResponseDryRun);
+
 // 'Mode' parameter for blink::features::kSoftNavigationHeuristics.
 enum class SoftNavigationHeuristicsMode : uint8_t {
   kBasic,
diff --git a/third_party/blink/renderer/core/loader/anchor_element_interaction_test.cc b/third_party/blink/renderer/core/loader/anchor_element_interaction_test.cc
index 6abc77f..8ac4bdd 100644
--- a/third_party/blink/renderer/core/loader/anchor_element_interaction_test.cc
+++ b/third_party/blink/renderer/core/loader/anchor_element_interaction_test.cc
@@ -732,6 +732,7 @@
            {"distance_from_ptr_down_hi", "0"},
            {"largest_anchor_threshold", "0.5"}}}},
         {});
+    config_scope_ = std::make_unique<ViewportHeuristicConfigTestingScope>();
   }
 
   static constexpr int kViewportWidth = 400;
@@ -851,6 +852,7 @@
 
  private:
   base::test::ScopedFeatureList feature_list_;
+  std::unique_ptr<ViewportHeuristicConfigTestingScope> config_scope_;
 };
 
 TEST_F(AnchorElementInteractionViewportHeuristicsTest, BasicTest) {
diff --git a/third_party/blink/renderer/core/loader/anchor_element_interaction_tracker.cc b/third_party/blink/renderer/core/loader/anchor_element_interaction_tracker.cc
index 3c87aed..3d9e84e 100644
--- a/third_party/blink/renderer/core/loader/anchor_element_interaction_tracker.cc
+++ b/third_party/blink/renderer/core/loader/anchor_element_interaction_tracker.cc
@@ -40,22 +40,7 @@
 const base::TimeDelta kMouseAccelerationAndVelocityInterval{
     base::Milliseconds(50)};
 
-// Config for viewport heuristic derived from field trial params.
-struct ViewportHeuristicConfig {
-  // Min/max values of distance_from_pointer_down_ratio for an anchor to be
-  // selected by the heuristic.
-  std::pair<float, float> distance_from_ptr_down_ratio_bounds;
-  // The largest anchor should be larger than the next largest anchor by this
-  // threshold to be selected by the heuristic. More specifically, for the
-  // largest anchor a1, and the next largest anchor a2:
-  // (size(a1) - size(a2)) / size(a2) >= `largest_anchor_threshold`.
-  double largest_anchor_threshold;
-  // Time to wait before informing the browser of the largest anchor element
-  // selected by the heuristic.
-  base::TimeDelta delay;
-};
-
-ViewportHeuristicConfig GetViewportHeuristicConfig() {
+ViewportHeuristicConfig GetViewportHeuristicConfigFromFeatureParams() {
   // -0.3 is the lower bound of the middle 75% of distance_from_ptr_down_ratio
   // values of clicked anchors (i.e. the P12.5 value).
   const base::FeatureParam<double> kDistanceFromPointerDownLowerBound{
@@ -85,8 +70,28 @@
       .delay = kDelay.Get()};
 }
 
+ViewportHeuristicConfig* g_config_for_testing = nullptr;
+
+const ViewportHeuristicConfig& GetViewportHeuristicConfig() {
+  static const ViewportHeuristicConfig config_from_feature_params =
+      GetViewportHeuristicConfigFromFeatureParams();
+  return (g_config_for_testing == nullptr) ? config_from_feature_params
+                                           : *g_config_for_testing;
+}
+
 }  // namespace
 
+ViewportHeuristicConfigTestingScope::ViewportHeuristicConfigTestingScope()
+    : config_(GetViewportHeuristicConfigFromFeatureParams()) {  // IN-TEST
+  DCHECK(!g_config_for_testing);
+  g_config_for_testing = &config_;
+}
+
+ViewportHeuristicConfigTestingScope::
+    ~ViewportHeuristicConfigTestingScope() {  // IN-TEST
+  g_config_for_testing = nullptr;
+}
+
 AnchorElementInteractionTracker::MouseMotionEstimator::MouseMotionEstimator(
     scoped_refptr<base::SingleThreadTaskRunner> task_runner)
     : update_timer_(
@@ -540,7 +545,7 @@
     HeapVector<Member<AnchorPositionUpdate>>& position_updates) {
   CHECK(base::FeatureList::IsEnabled(
       blink::features::kPreloadingViewportHeuristics));
-  static const ViewportHeuristicConfig config = GetViewportHeuristicConfig();
+  const ViewportHeuristicConfig& config = GetViewportHeuristicConfig();
 
   // Reset the delay timer (if active); this could happen if a programmatic
   // scroll happened after the timer started.
diff --git a/third_party/blink/renderer/core/loader/anchor_element_interaction_tracker.h b/third_party/blink/renderer/core/loader/anchor_element_interaction_tracker.h
index e410439..197d613 100644
--- a/third_party/blink/renderer/core/loader/anchor_element_interaction_tracker.h
+++ b/third_party/blink/renderer/core/loader/anchor_element_interaction_tracker.h
@@ -29,6 +29,21 @@
 
 CORE_EXPORT BASE_DECLARE_FEATURE(kPreloadingNoSamePageFragmentAnchorTracking);
 
+// Config for viewport heuristic derived from field trial params.
+struct ViewportHeuristicConfig {
+  // Min/max values of distance_from_pointer_down_ratio for an anchor to be
+  // selected by the heuristic.
+  std::pair<float, float> distance_from_ptr_down_ratio_bounds;
+  // The largest anchor should be larger than the next largest anchor by this
+  // threshold to be selected by the heuristic. More specifically, for the
+  // largest anchor a1, and the next largest anchor a2:
+  // (size(a1) - size(a2)) / size(a2) >= `largest_anchor_threshold`.
+  double largest_anchor_threshold;
+  // Time to wait before informing the browser of the largest anchor element
+  // selected by the heuristic.
+  base::TimeDelta delay;
+};
+
 // Tracks pointerdown events anywhere on a document.  On receiving a pointerdown
 // event, the tracker will retrieve the valid href from the anchor element from
 // the event and will report the href value to the browser process via Mojo. The
@@ -144,6 +159,14 @@
       viewport_heuristic_timer_;
 };
 
+struct BLINK_EXPORT ViewportHeuristicConfigTestingScope {
+  ViewportHeuristicConfigTestingScope();
+  ~ViewportHeuristicConfigTestingScope();
+
+ private:
+  ViewportHeuristicConfig config_;
+};
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_ANCHOR_ELEMENT_INTERACTION_TRACKER_H_
diff --git a/third_party/blink/renderer/core/speculation_rules/document_rule_predicate.cc b/third_party/blink/renderer/core/speculation_rules/document_rule_predicate.cc
index 3136758..f49612a 100644
--- a/third_party/blink/renderer/core/speculation_rules/document_rule_predicate.cc
+++ b/third_party/blink/renderer/core/speculation_rules/document_rule_predicate.cc
@@ -15,6 +15,7 @@
 #include "third_party/blink/renderer/core/frame/web_feature.h"
 #include "third_party/blink/renderer/core/html/html_anchor_element.h"
 #include "third_party/blink/renderer/core/url_pattern/url_pattern.h"
+#include "third_party/blink/renderer/core/url_pattern/url_pattern_utils.h"
 #include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
@@ -297,71 +298,12 @@
                             const KURL& base_url,
                             ExceptionState& exception_state,
                             String* out_error) {
-  // If rawPattern is a string, then:
-  if (String raw_string; raw_pattern->AsString(&raw_string)) {
-    // Set pattern to the result of constructing a URLPattern using the
-    // URLPattern(input, baseURL) constructor steps given rawPattern and
-    // serializedBaseURL.
-    V8URLPatternInput* url_pattern_input =
-        MakeGarbageCollected<V8URLPatternInput>(raw_string);
-    return URLPattern::Create(isolate, url_pattern_input, base_url,
-                              exception_state);
+  auto result =
+      ParseURLPatternFromJSON(isolate, *raw_pattern, base_url, exception_state);
+  if (result.has_value()) {
+    return result.value();
   }
-  // Otherwise, if rawPattern is a map
-  if (JSONObject* pattern_object = JSONObject::Cast(raw_pattern)) {
-    // Let init be «[ "baseURL" → serializedBaseURL ]», representing a
-    // dictionary of type URLPatternInit.
-    URLPatternInit* init = URLPatternInit::Create();
-    init->setBaseURL(base_url);
-
-    // For each key -> value of rawPattern:
-    for (wtf_size_t i = 0; i < pattern_object->size(); i++) {
-      JSONObject::Entry entry = pattern_object->at(i);
-      String key = entry.first;
-      String value;
-      // If value is not a string
-      if (!entry.second->AsString(&value)) {
-        SetParseErrorMessage(
-            out_error, "Values for a URL pattern object must be strings.");
-        return nullptr;
-      }
-
-      // Set init[key] to value.
-      if (key == "protocol") {
-        init->setProtocol(value);
-      } else if (key == "username") {
-        init->setUsername(value);
-      } else if (key == "password") {
-        init->setPassword(value);
-      } else if (key == "hostname") {
-        init->setHostname(value);
-      } else if (key == "port") {
-        init->setPort(value);
-      } else if (key == "pathname") {
-        init->setPathname(value);
-      } else if (key == "search") {
-        init->setSearch(value);
-      } else if (key == "hash") {
-        init->setHash(value);
-      } else if (key == "baseURL") {
-        init->setBaseURL(value);
-      } else {
-        SetParseErrorMessage(out_error,
-                             StrCat({"Invalid key \"", key,
-                                     "\" for a URL pattern object found."}));
-        return nullptr;
-      }
-    }
-
-    // Set pattern to the result of constructing a URLPattern using the
-    // URLPattern(input, baseURL) constructor steps given init.
-    V8URLPatternInput* url_pattern_input =
-        MakeGarbageCollected<V8URLPatternInput>(init);
-    return URLPattern::Create(isolate, url_pattern_input, exception_state);
-  }
-  SetParseErrorMessage(out_error,
-                       "Value for \"href_matches\" should either be a "
-                       "string, an object, or a list of strings and objects.");
+  SetParseErrorMessage(out_error, result.error());
   return nullptr;
 }
 
diff --git a/third_party/blink/renderer/core/url_pattern/BUILD.gn b/third_party/blink/renderer/core/url_pattern/BUILD.gn
index e4914818..708a302e 100644
--- a/third_party/blink/renderer/core/url_pattern/BUILD.gn
+++ b/third_party/blink/renderer/core/url_pattern/BUILD.gn
@@ -16,6 +16,8 @@
     "url_pattern_dummy_url_canon.cc",
     "url_pattern_dummy_url_canon.h",
     "url_pattern_options.h",
+    "url_pattern_utils.cc",
+    "url_pattern_utils.h",
   ]
 
   public_deps = [
diff --git a/third_party/blink/renderer/core/url_pattern/url_pattern_utils.cc b/third_party/blink/renderer/core/url_pattern/url_pattern_utils.cc
new file mode 100644
index 0000000..60463399
--- /dev/null
+++ b/third_party/blink/renderer/core/url_pattern/url_pattern_utils.cc
@@ -0,0 +1,83 @@
+// 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 "third_party/blink/renderer/core/url_pattern/url_pattern_utils.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/v8_union_urlpatterninit_usvstring.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_url_pattern_init.h"
+#include "third_party/blink/renderer/core/url_pattern/url_pattern.h"
+#include "third_party/blink/renderer/platform/json/json_parser.h"
+#include "third_party/blink/renderer/platform/json/json_values.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/wtf/text/strcat.h"
+
+namespace blink {
+
+base::expected<URLPattern*, String> ParseURLPatternFromJSON(
+    v8::Isolate* isolate,
+    const JSONValue& pattern_value,
+    const KURL& base_url,
+    ExceptionState& exception_state) {
+  // If pattern_value is a string, then:
+  if (String raw_string; pattern_value.AsString(&raw_string)) {
+    V8URLPatternInput* url_pattern_input =
+        MakeGarbageCollected<V8URLPatternInput>(raw_string);
+    return URLPattern::Create(isolate, url_pattern_input, base_url,
+                              exception_state);
+  }
+  // Otherwise, if pattern_value is a map
+  if (const JSONObject* pattern_object = JSONObject::Cast(&pattern_value)) {
+    // Let init be «[ "baseURL" → serializedBaseURL ]», representing a
+    // dictionary of type URLPatternInit.
+    URLPatternInit* init = URLPatternInit::Create();
+    init->setBaseURL(base_url);
+
+    // For each key -> value of rawPattern:
+    for (wtf_size_t i = 0; i < pattern_object->size(); i++) {
+      JSONObject::Entry entry = pattern_object->at(i);
+      String key = entry.first;
+      String value;
+      // If value is not a string
+      if (!entry.second->AsString(&value)) {
+        return base::unexpected(
+            "Values for a URL pattern object must be strings.");
+      }
+
+      // Set init[key] to value.
+      if (key == "protocol") {
+        init->setProtocol(value);
+      } else if (key == "username") {
+        init->setUsername(value);
+      } else if (key == "password") {
+        init->setPassword(value);
+      } else if (key == "hostname") {
+        init->setHostname(value);
+      } else if (key == "port") {
+        init->setPort(value);
+      } else if (key == "pathname") {
+        init->setPathname(value);
+      } else if (key == "search") {
+        init->setSearch(value);
+      } else if (key == "hash") {
+        init->setHash(value);
+      } else if (key == "baseURL") {
+        init->setBaseURL(value);
+      } else {
+        return base::unexpected(StrCat(
+            {"Invalid key \"", key, "\" for a URL pattern object found."}));
+      }
+    }
+
+    // Set pattern to the result of constructing a URLPattern using the
+    // URLPattern(input, baseURL) constructor steps given init.
+    V8URLPatternInput* url_pattern_input =
+        MakeGarbageCollected<V8URLPatternInput>(init);
+    return URLPattern::Create(isolate, url_pattern_input, exception_state);
+  }
+  return base::unexpected(
+      "Value for \"href_matches\" should either be a "
+      "string, an object, or a list of strings and objects.");
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/url_pattern/url_pattern_utils.h b/third_party/blink/renderer/core/url_pattern/url_pattern_utils.h
new file mode 100644
index 0000000..86f5fe26
--- /dev/null
+++ b/third_party/blink/renderer/core/url_pattern/url_pattern_utils.h
@@ -0,0 +1,29 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_CORE_URL_PATTERN_URL_PATTERN_UTILS_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_URL_PATTERN_URL_PATTERN_UTILS_H_
+
+#include "base/types/expected.h"
+
+namespace v8 {
+class Isolate;
+}  // namespace v8
+
+namespace blink {
+class ExceptionState;
+class JSONValue;
+class KURL;
+class String;
+class URLPattern;
+
+base::expected<URLPattern*, String> ParseURLPatternFromJSON(
+    v8::Isolate*,
+    const JSONValue&,
+    const KURL& base_url,
+    ExceptionState&);
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_URL_PATTERN_URL_PATTERN_UTILS_H_
diff --git a/third_party/blink/renderer/modules/credentialmanagement/authentication_credentials_container.cc b/third_party/blink/renderer/modules/credentialmanagement/authentication_credentials_container.cc
index c2825cf..6e910ef 100644
--- a/third_party/blink/renderer/modules/credentialmanagement/authentication_credentials_container.cc
+++ b/third_party/blink/renderer/modules/credentialmanagement/authentication_credentials_container.cc
@@ -1988,6 +1988,14 @@
           "An allowCredentials is not allowed with immediate mediation."));
       return;
     }
+    if (options->hasPublicKey() && options->publicKey()->hasExtensions() &&
+        options->publicKey()->extensions()->hasRemoteDesktopClientOverride()) {
+      resolver->Reject(MakeGarbageCollected<DOMException>(
+          DOMExceptionCode::kNotAllowedError,
+          "Immediate mediation cannot be used with a remote desktop override "
+          "request."));
+      return;
+    }
     if (!LocalFrame::ConsumeTransientUserActivation(
             To<LocalDOMWindow>(resolver->GetExecutionContext())->GetFrame(),
             UserActivationUpdateSource::kRenderer)) {
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_ascii_fast_path.h b/third_party/blink/renderer/platform/wtf/text/text_codec_ascii_fast_path.h
index 38d07fc..d34846f 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_ascii_fast_path.h
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_ascii_fast_path.h
@@ -37,17 +37,18 @@
 
 template <>
 struct UCharByteFiller<4> {
-  static void Copy(LChar* destination, const uint8_t* source) {
+  static void Copy(MachineWord word, LChar* destination) {
     // SAFETY: This is only used in a few places, and only copies
     // a MachineWord buffer, the caller guarantees that destination
-    // and source holds at least 4 elements.
-    UNSAFE_BUFFERS(memcpy(destination, source, 4));
+    // holds at least 4 elements.
+    UNSAFE_BUFFERS(memcpy(destination, &word, 4));
   }
 
-  static void Copy(UChar* destination, const uint8_t* source) {
+  static void Copy(MachineWord word, UChar* destination) {
+    auto source = base::byte_span_from_ref(word);
     // SAFETY: This is only used in a few places, and only copies
     // a MachineWord buffer, the caller guarantees that destination
-    // and source holds at least 4 elements.
+    // holds at least 4 elements.
     UNSAFE_BUFFERS({
       destination[0] = source[0];
       destination[1] = source[1];
@@ -59,17 +60,18 @@
 
 template <>
 struct UCharByteFiller<8> {
-  static void Copy(LChar* destination, const uint8_t* source) {
+  static void Copy(MachineWord word, LChar* destination) {
     // SAFETY: This is only used in a few places, and only copies
     // a MachineWord buffer, the caller guarantees that destination
-    // and source holds at least 8 elements.
-    UNSAFE_BUFFERS(memcpy(destination, source, 8));
+    // holds at least 8 elements.
+    UNSAFE_BUFFERS(memcpy(destination, &word, 8));
   }
 
-  static void Copy(UChar* destination, const uint8_t* source) {
+  static void Copy(MachineWord word, UChar* destination) {
+    auto source = base::byte_span_from_ref(word);
     // SAFETY: This is only used in a few places, and only copies
     // a MachineWord buffer, the caller guarantees that destination
-    // and source holds at least 8 elements.
+    // holds at least 8 elements.
     UNSAFE_BUFFERS({
       destination[0] = source[0];
       destination[1] = source[1];
@@ -83,12 +85,12 @@
   }
 };
 
-inline void CopyAsciiMachineWord(LChar* destination, const uint8_t* source) {
-  UCharByteFiller<sizeof(MachineWord)>::Copy(destination, source);
+inline void CopyAsciiMachineWord(MachineWord word, LChar* destination) {
+  UCharByteFiller<sizeof(MachineWord)>::Copy(word, destination);
 }
 
-inline void CopyAsciiMachineWord(UChar* destination, const uint8_t* source) {
-  UCharByteFiller<sizeof(MachineWord)>::Copy(destination, source);
+inline void CopyAsciiMachineWord(MachineWord word, UChar* destination) {
+  UCharByteFiller<sizeof(MachineWord)>::Copy(word, destination);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_latin1.cc b/third_party/blink/renderer/platform/wtf/text/text_codec_latin1.cc
index 5e1ea03..04229eb 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_latin1.cc
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_latin1.cc
@@ -137,8 +137,8 @@
 
           static constexpr size_t kMachineWordSize = sizeof(MachineWord);
           CopyAsciiMachineWord(
-              destination.take_first<kMachineWordSize>().data(),
-              source.take_first<kMachineWordSize>().data());
+              chunk, destination.take_first<kMachineWordSize>().data());
+          source.take_first<kMachineWordSize>();
         }
 
         if (source.empty()) {
@@ -192,8 +192,8 @@
 
           static constexpr size_t kMachineWordSize = sizeof(MachineWord);
           CopyAsciiMachineWord(
-              destination16.take_first<kMachineWordSize>().data(),
-              source.take_first<kMachineWordSize>().data());
+              chunk, destination16.take_first<kMachineWordSize>().data());
+          source.take_first<kMachineWordSize>();
         }
 
         if (source.empty()) {
diff --git a/third_party/blink/renderer/platform/wtf/text/text_codec_utf8.cc b/third_party/blink/renderer/platform/wtf/text/text_codec_utf8.cc
index 3f8d0222..c9635a5 100644
--- a/third_party/blink/renderer/platform/wtf/text/text_codec_utf8.cc
+++ b/third_party/blink/renderer/platform/wtf/text/text_codec_utf8.cc
@@ -403,8 +403,8 @@
               break;
             }
             CopyAsciiMachineWord(
-                destination.take_first<sizeof(MachineWord)>().data(),
-                source.take_first<sizeof(MachineWord)>().data());
+                chunk, destination.take_first<sizeof(MachineWord)>().data());
+            source.take_first<sizeof(MachineWord)>();
           }
           if (source.empty()) {
             break;
@@ -491,8 +491,8 @@
             }
 
             CopyAsciiMachineWord(
-                destination16.take_first<sizeof(MachineWord)>().data(),
-                source.take_first<sizeof(MachineWord)>().data());
+                chunk, destination16.take_first<sizeof(MachineWord)>().data());
+            source.take_first<sizeof(MachineWord)>();
           }
           if (source.empty()) {
             break;
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 27689adf..2908353 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -9642,17 +9642,10 @@
 # Gardener 2025-08-29
 crbug.com/441826647 [ Linux ] external/wpt/webdriver/tests/bidi/browsing_context/navigate/navigate.py [ Skip Timeout ]
 
-# Disabled to unblock crrev.com/c/6903230
-crbug.com/442509324 http/tests/devtools/device-mode/device-mode-responsive.js [ Failure Pass ]
-crbug.com/442509324 http/tests/devtools/device-mode/device-mode-switching-devices.js [ Failure Pass ]
-crbug.com/442509324 http/tests/devtools/device-mode/device-mode-toolbar.js [ Failure Pass ]
-
 # Gardener 2025-09-01
 crbug.com/442030691 compositing/video/video-poster.html [ Failure Pass ]
 
 # Gardener 2025-09-05
 crbug.com/443161677 [ Win11-arm64 ] http/tests/inspector-protocol/network/get-durable-response-gzip-body.js [ Failure Timeout ]
-
-# Temporarily disabled because RenderDocument is not enabled on mac bots just yet.
-# TODO(crbug.com/40615943): Re-enable this test once RenderDocument is enabled on mac bots.
-crbug.com/40615943 [ Mac ] http/tests/inspector-protocol/bfcache/report-back-forward-cache-status-blocklisted-features-same-site.js [ Failure ]
+crbug.com/443203688 external/wpt/accname/name/comp_name_from_content.html [ Failure Pass ]
+crbug.com/443229243 inspector-protocol/page/reload-with-script.js [ Failure Pass ]
diff --git a/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-responsive.js b/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-responsive.js
index 8be7de0..50fbcb7 100644
--- a/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-responsive.js
+++ b/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-responsive.js
@@ -6,7 +6,7 @@
 import {DeviceModeTestRunner} from 'device_mode_test_runner';
 
 import * as Emulation from 'devtools/panels/emulation/emulation.js';
-import * as UIModule from 'devtools/ui/legacy/legacy.js';
+import * as Geometry from 'devtools/models/geometry/geometry.js'
 
 (async function() {
   TestRunner.addResult(`Test that device mode's responsive mode behaves correctly when adjusting inputs.\n`);
@@ -17,7 +17,7 @@
   var view = new Emulation.DeviceModeView.DeviceModeView();
   var toolbar = view.toolbar;
   var model = view.model;
-  var viewportSize = new UIModule.Geometry.Size(320, 480);
+  var viewportSize = new Geometry.Size(320, 480);
   model.setAvailableSize(viewportSize, viewportSize);
 
   TestRunner.addResult(
diff --git a/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-switching-devices.js b/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-switching-devices.js
index 6e34082..28d0830f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-switching-devices.js
+++ b/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-switching-devices.js
@@ -6,7 +6,7 @@
 import {DeviceModeTestRunner} from 'device_mode_test_runner';
 
 import * as Emulation from 'devtools/panels/emulation/emulation.js';
-import * as UIModule from 'devtools/ui/legacy/legacy.js';
+import * as Geometry from 'devtools/models/geometry/geometry.js'
 
 (async function() {
   TestRunner.addResult(`Test preservation of orientation and scale when that switching devices in device mode.\n`);
@@ -24,7 +24,7 @@
   var view = new Emulation.DeviceModeView.DeviceModeView();
   var toolbar = view.toolbar;
   var model = view.model;
-  var viewportSize = new UIModule.Geometry.Size(800, 600);
+  var viewportSize = new Geometry.Size(800, 600);
   model.setAvailableSize(viewportSize, viewportSize);
 
   TestRunner.addResult('\nTest that devices automatically zoom to fit.');
diff --git a/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-toolbar.js b/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-toolbar.js
index 45ad862..01beda6 100644
--- a/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-toolbar.js
+++ b/third_party/blink/web_tests/http/tests/devtools/device-mode/device-mode-toolbar.js
@@ -7,7 +7,7 @@
 
 import * as Emulation from 'devtools/panels/emulation/emulation.js';
 import * as EmulationModel from 'devtools/models/emulation/emulation.js';
-import * as UIModule from 'devtools/ui/legacy/legacy.js';
+import * as Geometry from 'devtools/models/geometry/geometry.js'
 
 (async function() {
   TestRunner.addResult(`Test toolbar state when switching modes.\n`);
@@ -16,7 +16,7 @@
   var view = new Emulation.DeviceModeView.DeviceModeView();
   var toolbar = view.toolbar;
   var model = view.model;
-  var viewportSize = new UIModule.Geometry.Size(800, 600);
+  var viewportSize = new Geometry.Size(800, 600);
   model.setAvailableSize(viewportSize, viewportSize);
 
   // Check that default model has type None.
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/bfcache/report-back-forward-cache-status-blocklisted-features-same-site-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/bfcache/report-back-forward-cache-status-blocklisted-features-same-site-expected.txt
index 91004f2..92bf4f5 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/bfcache/report-back-forward-cache-status-blocklisted-features-same-site-expected.txt
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/bfcache/report-back-forward-cache-status-blocklisted-features-same-site-expected.txt
@@ -33,10 +33,6 @@
     loaderId : <string>
     notRestoredExplanations : [
         [0] : {
-            reason : HTTPStatusNotOK
-            type : Circumstantial
-        }
-        [1] : {
             reason : BrowsingInstanceNotSwapped
             type : Circumstantial
         }
@@ -46,10 +42,6 @@
         ]
         explanations : [
             [0] : {
-                reason : HTTPStatusNotOK
-                type : Circumstantial
-            }
-            [1] : {
                 reason : BrowsingInstanceNotSwapped
                 type : Circumstantial
             }
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index e5b234e..2a74451 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit e5b234e858cfd029bf8eafa13455f80f460643f2
+Subproject commit 2a744510a5faabae24e3c6d2ca34928f91392653
diff --git a/third_party/perfetto b/third_party/perfetto
index 313e4b6..55c5924 160000
--- a/third_party/perfetto
+++ b/third_party/perfetto
@@ -1 +1 @@
-Subproject commit 313e4b6b9117daa3241863a5ce31c203c218164a
+Subproject commit 55c592489062e1569fddcc59a4b9b5479a6b988f
diff --git a/third_party/skia b/third_party/skia
index 2a9fe9c..845ec12 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit 2a9fe9cde3e8e2184db9c225b638dabc1debd5fa
+Subproject commit 845ec125e94ce32aa235aeca99409dabf15f9f76
diff --git a/third_party/webrtc b/third_party/webrtc
index d7169bf..8d31c4a 160000
--- a/third_party/webrtc
+++ b/third_party/webrtc
@@ -1 +1 @@
-Subproject commit d7169bf89fc40930c49e083ec7969dfdd7650407
+Subproject commit 8d31c4add2eb4685afff353a35b705b089d5f21f
diff --git a/tools/clang/spanify/Spanifier.cpp b/tools/clang/spanify/Spanifier.cpp
index 90a315e7..94a2b6d 100644
--- a/tools/clang/spanify/Spanifier.cpp
+++ b/tools/clang/spanify/Spanifier.cpp
@@ -168,12 +168,13 @@
               parm_var_decl_matcher) {
   const clang::FunctionDecl& function_decl = Node;
 
-  unsigned num_params = function_decl.getNumParams();
+  const unsigned num_params = function_decl.getNumParams();
   bool is_matching = false;
   clang::ast_matchers::internal::BoundNodesTreeBuilder result;
   for (unsigned i = 0; i < num_params; i++) {
     const clang::ParmVarDecl* param = function_decl.getParamDecl(i);
-    clang::ast_matchers::internal::BoundNodesTreeBuilder param_matches;
+    clang::ast_matchers::internal::BoundNodesTreeBuilder param_matches(
+        *Builder);
     if (parm_var_decl_matcher.matches(*param, Finder, &param_matches)) {
       is_matching = true;
       result.addMatch(param_matches);
@@ -733,6 +734,40 @@
   assert(false && "Unexpected match in getSourceRange()");
 }
 
+// Unwraps typedef type locs and/or elaborated type locs, and returns the body
+// type loc.
+//
+// Note that using-declared types are also represented with typedef types in
+// clang, so this function works for both 'typedef' and 'using' declarations.
+//
+// Example TypeLoc structures:
+//     // Given T2 where typedef int T1; using T2 = T1;
+//     ElaboratedTypeLoc('T2')
+//       --(getNamedTypeLoc)--> TypedefTypeLoc('T2')
+//         --(getTypedefNameDecl)--> ElaboratedTypeLoc('T1')
+//           --(getNamedTypeLoc)--> TypedefTypeLoc('T1')
+//             --(getTypedefNameDecl)--> BuiltinTypeLoc('int')
+//     => returns BuiltinTypeLoc('int').
+//
+//     // Given base::raw_ptr<int>,
+//     ElaboratedTypeLoc('base::raw_ptr<int>')
+//       --(getNamedTypeLoc)--> TemplateSpecializationTypeLoc('raw_ptr<int>')
+//         --(getArgLoc)--> TemplateArgumentLoc('int')
+//     => returns TemplateSpecializationTypeLoc('raw_ptr<int>').
+clang::TypeLoc UnwrapTypedefTypeLoc(clang::TypeLoc type_loc) {
+  while (const clang::ElaboratedTypeLoc elaborated_type_loc =
+             type_loc.getAs<clang::ElaboratedTypeLoc>()) {
+    type_loc = elaborated_type_loc.getNamedTypeLoc();
+    if (const clang::TypedefTypeLoc typedef_type_loc =
+            type_loc.getAs<clang::TypedefTypeLoc>()) {
+      const clang::TypedefNameDecl* typedef_name_decl =
+          typedef_type_loc.getTypedefNameDecl();
+      type_loc = typedef_name_decl->getTypeSourceInfo()->getTypeLoc();
+    }
+  }
+  return type_loc;
+}
+
 std::string getNodeFromPointerTypeLoc(const clang::PointerTypeLoc* type_loc,
                                       const MatchFinder::MatchResult& result) {
   const clang::SourceManager& source_manager = *result.SourceManager;
@@ -2587,6 +2622,88 @@
   EmitEdge(rhs, lhs);
 }
 
+// When a function declaration (= function type) gets rewritten, rewrites
+// variables of a function pointer type to which the function is assigned.
+//
+// Example:
+//     // function declaration being spanified
+//     int* func(int* arg);
+//     // function pointer variable to be spanified
+//     int* (*var)(int* arg) = func;
+// In the following implementation, `var` is called LHS and `func` is called
+// RHS.
+//
+// Tests are in: func-ptr-var-original.cc
+void RewriteFunctionPointerType(const MatchFinder::MatchResult& result) {
+  const clang::VarDecl* lhs_var_decl = GetNodeOrCrash<clang::VarDecl>(
+      result, "lhs_funcptrvardecl",
+      "The rewriting target variable of function pointer type must be bound.");
+
+  // Get the FunctionProtoTypeLoc of the LHS variable.
+  clang::FunctionProtoTypeLoc lhs_func_proto_type_loc;
+  {
+    const clang::TypeLoc var_type_loc =
+        UnwrapTypedefTypeLoc(lhs_var_decl->getTypeSourceInfo()->getTypeLoc());
+    if (var_type_loc.getAs<clang::AutoTypeLoc>() ||
+        var_type_loc.getAs<clang::DecltypeTypeLoc>()) {
+      return;  // No need to rewrite auto/decltype types.
+    }
+    const clang::PointerTypeLoc pointer_type_loc =
+        var_type_loc.getAs<clang::PointerTypeLoc>();
+    assert(pointer_type_loc && "Failed to get a PointerTypeLoc.");
+    clang::TypeLoc pointee_type_loc = pointer_type_loc.getPointeeLoc();
+    // Unwrap paren type locs.
+    while (clang::ParenTypeLoc paren_type_loc =
+               pointee_type_loc.getAs<clang::ParenTypeLoc>()) {
+      pointee_type_loc = paren_type_loc.getInnerLoc();
+    }
+    lhs_func_proto_type_loc =
+        pointee_type_loc.getAs<clang::FunctionProtoTypeLoc>();
+  }
+  assert(lhs_func_proto_type_loc && "Failed to get a FunctionProtoTypeLoc.");
+
+  // RHS matches with one of the parameter types or the return type of the
+  // function declaration. Rewrite the one matched.
+  const std::string& rhs_key = GetRHS(result);
+
+  // LHS matches with the function pointer type variable (not a parameter type
+  // nor return type unlike RHS). Find the parameter or return type
+  // corresponding to the RHS match, and rewrite it.
+  std::string lhs_key;
+  if (const clang::ParmVarDecl* rhs_parm_var_decl =
+          result.Nodes.getNodeAs<clang::ParmVarDecl>("rhs_begin")) {
+    // One of the function parameter types matches on RHS.
+    const unsigned parm_index = rhs_parm_var_decl->getFunctionScopeIndex();
+    const clang::ParmVarDecl* lhs_parm_var_decl =
+        lhs_func_proto_type_loc.getParam(parm_index);
+    const clang::TypeLoc lhs_parm_type_loc = UnwrapTypedefTypeLoc(
+        lhs_parm_var_decl->getTypeSourceInfo()->getTypeLoc());
+    if (lhs_parm_type_loc.getAs<clang::ArrayTypeLoc>()) {
+      lhs_key = getNodeFromFunctionArrayParameter(&lhs_parm_type_loc,
+                                                  lhs_parm_var_decl, result);
+    } else if (lhs_parm_type_loc.getAs<clang::PointerTypeLoc>()) {
+      lhs_key = getNodeFromDecl(lhs_parm_var_decl, result);
+    } else if (const clang::TemplateSpecializationTypeLoc lhs_raw_ptr_type_loc =
+                   lhs_parm_type_loc
+                       .getAs<clang::TemplateSpecializationTypeLoc>()) {
+      lhs_key = getNodeFromRawPtrTypeLoc(&lhs_raw_ptr_type_loc, result);
+    } else {
+      assert(false && "Unknown kind of clang::TypeLoc at `lhs_parm_type_loc`");
+    }
+  } else {
+    // The function return type matches on RHS.
+    const clang::PointerTypeLoc lhs_return_type_loc =
+        lhs_func_proto_type_loc.getReturnLoc().getAs<clang::PointerTypeLoc>();
+    assert(lhs_return_type_loc);
+    lhs_key = getNodeFromPointerTypeLoc(&lhs_return_type_loc, result);
+  }
+
+  // Whenever RHS (function type) is rewritten, LHS (function pointer type)
+  // should be rewritten, too.
+  EmitEdge(lhs_key, rhs_key);
+  EmitEdge(rhs_key, lhs_key);
+}
+
 // Spanifies the matched function parameter/return type, and connects relevant
 // function declarations (forward declarations and overridden methods) to each
 // other bidirectionally per the matched function parameter/return type. Note
@@ -2640,7 +2757,7 @@
 //
 // A: Yes, it does suffice. But it's hard to build because GetRHS takes
 // `result` as the argument. When we find a match for arg1 at [2], we no longer
-// have `result` for arg1 at [1]. It's easier to create node_arg1_{1st,2nd] than
+// have `result` for arg1 at [1]. It's easier to create node_arg1_{1st,2nd} than
 // saving the results of GetRHS somewhere and retrieving it.
 void RewriteFunctionParamAndReturnType(const MatchFinder::MatchResult& result) {
   const clang::SourceManager& source_manager = *result.SourceManager;
@@ -3379,7 +3496,7 @@
     // a = fct();
     // a = reinterpret_cast<>(b);
     // a = (cond) ? expr1 : expr2;
-    auto assignement_relationship = traverse(
+    auto assignment_relationship = traverse(
         clang::TK_IgnoreUnlessSpelledInSource,
         binaryOperation(hasOperatorName("="),
                         hasOperands(lhs_expr_variations,
@@ -3387,18 +3504,18 @@
                                           conditionalOperator(hasTrueExpression(
                                               rhs_expr_variations)))),
                         unless(isExpansionInSystemHeader())));
-    Match(assignement_relationship, MatchAdjacency);
+    Match(assignment_relationship, MatchAdjacency);
 
     // Creates the edge from lhs to false_expr in a ternary conditional
     // operator.
-    auto assignement_relationship2 = traverse(
+    auto assignment_relationship2 = traverse(
         clang::TK_IgnoreUnlessSpelledInSource,
         binaryOperation(hasOperatorName("="),
                         hasOperands(lhs_expr_variations,
                                     conditionalOperator(hasFalseExpression(
                                         rhs_expr_variations))),
                         unless(isExpansionInSystemHeader())));
-    Match(assignement_relationship2, MatchAdjacency);
+    Match(assignment_relationship2, MatchAdjacency);
 
     // Supports:
     // T* temp = member;
@@ -3418,17 +3535,6 @@
             unless(isExpansionInSystemHeader())));
     Match(var_construction, MatchAdjacency);
 
-    // Supports:
-    // it == std::begin(c_array)
-    // it != std::end(c_array)
-    auto equality_op =
-        traverse(clang::TK_IgnoreUnlessSpelledInSource,
-                 binaryOperation(
-                     anyOf(hasOperatorName("=="), hasOperatorName("!=")),
-                     hasOperands(ignoringParenCasts(lhs_expr_variations),
-                                 ignoringParenCasts(c_array_iter_call_expr))));
-    Match(equality_op, RewriteComparisonWithCArrayIter);
-
     // Creates the edge from lhs to false_expr in a ternary conditional
     // operator.
     auto var_construction2 = traverse(
@@ -3443,6 +3549,17 @@
     Match(var_construction2, MatchAdjacency);
 
     // Supports:
+    // it == std::begin(c_array)
+    // it != std::end(c_array)
+    auto equality_op =
+        traverse(clang::TK_IgnoreUnlessSpelledInSource,
+                 binaryOperation(
+                     anyOf(hasOperatorName("=="), hasOperatorName("!=")),
+                     hasOperands(ignoringParenCasts(lhs_expr_variations),
+                                 ignoringParenCasts(c_array_iter_call_expr))));
+    Match(equality_op, RewriteComparisonWithCArrayIter);
+
+    // Supports:
     // return member;
     // return fct();
     // return reinterpret_cast(expr);
@@ -3545,20 +3662,58 @@
                  unless(cxxOperatorCallExpr(hasOperatorName("=")))));
     Match(call_expr, MatchAdjacency);
 
+    // Function pointer types to arbitrary function types, including typedef
+    // types and using-aliased types to function pointer types. No restriction
+    // to parameter types and return type, but the following queries require
+    // the function type to be compatible with the RHS function type.
+    auto fct_ptr_type = type(hasUnqualifiedDesugaredType(
+        pointerType(pointee(ignoringParens(functionProtoType())))));
+
+    // Function declaration with pointer/array/raw_ptr parameter types and/or
+    // pointer return type.
+    //
+    // Note that this query matches each of parameter types and return type
+    // respectively.
+    auto fct_decl =
+        functionDecl(
+            eachOf(forEachParmVarDecl(rhs_param),
+                   hasReturnTypeLoc(pointer_type_loc.bind("rhs_type_loc"))),
+            unless(exclusions))
+            .bind("fct_decl");
+    auto fct_decl_expr = expr(ignoringParenCasts(declRefExpr(to(fct_decl))));
+
+    // Supports:
+    //     void (*var)(int*) = func;
+    //     int* (*var)() = func;
+    // and equivalent typedef/using variants like:
+    //     using FuncType = void (*)(int*);
+    //     FuncType var = func;
+    auto fct_ptr_var_construction = traverse(
+        clang::TK_IgnoreUnlessSpelledInSource,
+        varDecl(hasType(fct_ptr_type), has(fct_decl_expr), unless(exclusions))
+            .bind("lhs_funcptrvardecl"));
+    Match(fct_ptr_var_construction, RewriteFunctionPointerType);
+
+    // Supports:
+    //     void (*var)(int*); var = func;
+    //     int* (*var)(); var = func;
+    // and equivalent typedef/using variants like:
+    //     typedef int* (*FuncType)();
+    //     FuncType var;
+    //     var = func;
+    auto fct_ptr_var_assignment = traverse(
+        clang::TK_IgnoreUnlessSpelledInSource,
+        binaryOperator(hasOperatorName("="),
+                       hasLHS(declRefExpr(
+                           to(varDecl(hasType(fct_ptr_type), unless(exclusions))
+                                  .bind("lhs_funcptrvardecl")))),
+                       hasRHS(fct_decl_expr)));
+    Match(fct_ptr_var_assignment, RewriteFunctionPointerType);
+
     // Map function declaration signature to function definition signature;
     // This is problematic in the case of callbacks defined in function.
-    auto fct_decls_params =
-        traverse(clang::TK_IgnoreUnlessSpelledInSource,
-                 functionDecl(forEachParmVarDecl(rhs_param), unless(exclusions))
-                     .bind("fct_decl"));
-    Match(fct_decls_params, RewriteFunctionParamAndReturnType);
-
-    auto fct_decls_returns = traverse(
-        clang::TK_IgnoreUnlessSpelledInSource,
-        functionDecl(hasReturnTypeLoc(pointer_type_loc.bind("rhs_type_loc")),
-                     unless(exclusions))
-            .bind("fct_decl"));
-    Match(fct_decls_returns, RewriteFunctionParamAndReturnType);
+    auto fct_decls = traverse(clang::TK_IgnoreUnlessSpelledInSource, fct_decl);
+    Match(fct_decls, RewriteFunctionParamAndReturnType);
   }
 
  private:
diff --git a/tools/clang/spanify/tests/func-ptr-var-expected.cc b/tools/clang/spanify/tests/func-ptr-var-expected.cc
new file mode 100644
index 0000000..53218a2
--- /dev/null
+++ b/tools/clang/spanify/tests/func-ptr-var-expected.cc
@@ -0,0 +1,197 @@
+// 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 "base/containers/span.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/raw_span.h"
+
+int UnsafeIndex();  // This function might return an out-of-bound index.
+
+// Expected rewrite:
+// void FuncArg1Arr(base::span<int, 3> arg1) {
+void FuncArg1Arr(base::span<int, 3> arg1) {
+  arg1[UnsafeIndex()] = 3;
+}
+
+// Expected rewrite:
+// void FuncArg2Arr(int arg1, base::span<int, 3> arg2) {
+void FuncArg2Arr(int arg1, base::span<int, 3> arg2) {
+  arg2[UnsafeIndex()] = 3;
+}
+
+// Expected rewrite:
+// void FuncArg1Ptr(base::span<int> arg1) {
+void FuncArg1Ptr(base::span<int> arg1) {
+  arg1[UnsafeIndex()] = 3;
+}
+
+// Expected rewrite:
+// void FuncArg2Ptr(int arg1, base::span<int> arg2) {
+void FuncArg2Ptr(int arg1, base::span<int> arg2) {
+  arg2[UnsafeIndex()] = 3;
+}
+
+// Expected rewrite:
+// base::span<int> FuncRet() {
+base::span<int> FuncRet() {
+  static int arr[] = {1, 2, 3};
+  return arr;
+}
+
+// Expected rewrite:
+// base::span<int> FuncAll(base::span<int, 3> arg1,
+//                         base::span<int> arg2,
+//                         base::base::raw_span<int> arg3) {
+base::span<int> FuncAll(base::span<int, 3> arg1,
+                        base::span<int> arg2,
+                        base::base::raw_span<int> arg3) {
+  arg1[UnsafeIndex()] = 3;
+  arg2[UnsafeIndex()] = 3;
+  arg3[UnsafeIndex()] = 3;
+  static int arr[] = {1, 2, 3};
+  return arr;
+}
+
+void test_type_alias() {
+  int arr[] = {1, 2, 3};
+
+  // TODO(yukishiino): Currently the following line is needed to get FuncRet
+  // spanified. This shouldn't be needed because we have other unsafe usages
+  // through function pointers.
+  FuncRet()[UnsafeIndex()] = 3;
+  FuncAll(arr, arr, arr)[UnsafeIndex()] = 3;
+
+  // Without a typedef / using declaration
+  {
+    // Expected rewrite:
+    // void (*p_arg1arr_init)(base::span<int, 3> arg1) = FuncArg1Arr;
+    void (*p_arg1arr_init)(base::span<int, 3> arg1) = FuncArg1Arr;
+    p_arg1arr_init(arr);
+
+    // Expected rewrite:
+    // void (*p_arg2ptr_assign)(int arg1, base::span<int> arg2);
+    void (*p_arg2ptr_assign)(int arg1, base::span<int> arg2);
+    p_arg2ptr_assign = FuncArg2Ptr;
+    p_arg2ptr_assign(3, arr);
+
+    // Expected rewrite:
+    // void (*p_arg2arr_init)(int, base::span<int, 3>) = FuncArg2Arr;
+    void (*p_arg2arr_init)(int, base::span<int, 3>) = FuncArg2Arr;
+    p_arg2arr_init(3, arr);
+
+    // Expected rewrite:
+    // base::span<int> (*p_ret_init)() = FuncRet;
+    base::span<int> (*p_ret_init)() = FuncRet;
+    // TODO(yukishiino): The following should be
+    //     base::span<int> ret_init = ...
+    int* ret_init = p_ret_init();
+    ret_init[UnsafeIndex()] = 3;
+
+    // Expected rewrite:
+    // base::span<int> (*p_ret_assign)();
+    base::span<int> (*p_ret_assign)();
+    p_ret_assign = FuncRet;
+    // TODO(yukishiino): The following should be
+    //     base::span<int> ret_assign = ...
+    int* ret_assign = p_ret_assign();
+    ret_assign[UnsafeIndex()] = 3;
+  }
+
+  // With typedef declarations
+  {
+    // Expected rewrite:
+    // typedef void (*Arg1ArrType)(base::span<int, 3> arg1);
+    typedef void (*Arg1ArrType)(base::span<int, 3> arg1);
+    Arg1ArrType p_arg1arr_init = FuncArg1Arr;
+    p_arg1arr_init(arr);
+
+    // Expected rewrite:
+    // typedef void (*Arg2PtrType)(int arg1, base::span<int> arg2);
+    typedef void (*Arg2PtrType)(int arg1, base::span<int> arg2);
+    Arg2PtrType p_arg2ptr_assign;
+    p_arg2ptr_assign = FuncArg2Ptr;
+    p_arg2ptr_assign(3, arr);
+
+    // Expected rewrite:
+    // typedef void (*Arg2ArrType)(int, base::span<int, 3>);
+    typedef void (*Arg2ArrType)(int, base::span<int, 3>);
+    Arg2ArrType p_arg2arr_init = FuncArg2Arr;
+    p_arg2arr_init(3, arr);
+
+    // Expected rewrite:
+    // typedef base::span<int> (*RetInitType)();
+    typedef base::span<int> (*RetInitType)();
+    RetInitType p_ret_init = FuncRet;
+    // TODO(yukishiino): The following should be
+    //     base::span<int> ret_init = ...
+    int* ret_init = p_ret_init();
+    ret_init[UnsafeIndex()] = 3;
+
+    // Expected rewrite:
+    // typedef base::span<int> (*RetAssignType)();
+    typedef base::span<int> (*RetAssignType)();
+    RetAssignType p_ret_assign;
+    p_ret_assign = FuncRet;
+    // TODO(yukishiino): The following should be
+    //     base::span<int> ret_assign = ...
+    int* ret_assign = p_ret_assign();
+    ret_assign[UnsafeIndex()] = 3;
+  }
+
+  // With using declarations
+  {
+    // Expected rewrite:
+    // using Arg1ArrType = void (*)(base::span<int, 3> arg1);
+    using Arg1ArrType = void (*)(base::span<int, 3> arg1);
+    Arg1ArrType p_arg1arr_init = FuncArg1Arr;
+    p_arg1arr_init(arr);
+
+    // Expected rewrite:
+    // using Arg2PtrType = void (*)(int arg1, base::span<int> arg2);
+    using Arg2PtrType = void (*)(int arg1, base::span<int> arg2);
+    Arg2PtrType p_arg2ptr_assign;
+    p_arg2ptr_assign = FuncArg2Ptr;
+    p_arg2ptr_assign(3, arr);
+
+    // Expected rewrite:
+    // using Arg2ArrType = void (*)(int, base::span<int, 3>);
+    using Arg2ArrType = void (*)(int, base::span<int, 3>);
+    Arg2ArrType p_arg2arr_init = FuncArg2Arr;
+    p_arg2arr_init(3, arr);
+
+    // Expected rewrite:
+    // using RetInitType = base::span<int> (*)();
+    using RetInitType = base::span<int> (*)();
+    RetInitType p_ret_init = FuncRet;
+    // TODO(yukishiino): The following should be
+    //     base::span<int> ret_init = ...
+    int* ret_init = p_ret_init();
+    ret_init[UnsafeIndex()] = 3;
+
+    // Expected rewrite:
+    // using RetAssignType = base::span<int> (*)();
+    using RetAssignType = base::span<int> (*)();
+    RetAssignType p_ret_assign;
+    p_ret_assign = FuncRet;
+    // TODO(yukishiino): The following should be
+    //     base::span<int> ret_assign = ...
+    int* ret_assign = p_ret_assign();
+    ret_assign[UnsafeIndex()] = 3;
+  }
+
+  // With nested typedef/using and multiple rewritings on the func ptr type
+  {
+    // Expected rewrite:
+    // typedef base::span<int> (*AllType1)(base::span<int, 3> arg1,
+    //                                     base::span<int> arg2,
+    //                                     base::base::raw_span<int> arg3);
+    typedef base::span<int> (*AllType1)(base::span<int, 3> arg1,
+                                        base::span<int> arg2,
+                                        base::base::raw_span<int> arg3);
+    using AllType2 = AllType1;
+    AllType2 p_all = FuncAll;
+    int* ret_all = p_all(arr, arr, arr);
+    ret_all[UnsafeIndex()] = 3;
+  }
+}
diff --git a/tools/clang/spanify/tests/func-ptr-var-original.cc b/tools/clang/spanify/tests/func-ptr-var-original.cc
new file mode 100644
index 0000000..fcaefcf
--- /dev/null
+++ b/tools/clang/spanify/tests/func-ptr-var-original.cc
@@ -0,0 +1,191 @@
+// 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 "base/memory/raw_ptr.h"
+
+int UnsafeIndex();  // This function might return an out-of-bound index.
+
+// Expected rewrite:
+// void FuncArg1Arr(base::span<int, 3> arg1) {
+void FuncArg1Arr(int arg1[3]) {
+  arg1[UnsafeIndex()] = 3;
+}
+
+// Expected rewrite:
+// void FuncArg2Arr(int arg1, base::span<int, 3> arg2) {
+void FuncArg2Arr(int arg1, int arg2[3]) {
+  arg2[UnsafeIndex()] = 3;
+}
+
+// Expected rewrite:
+// void FuncArg1Ptr(base::span<int> arg1) {
+void FuncArg1Ptr(int* arg1) {
+  arg1[UnsafeIndex()] = 3;
+}
+
+// Expected rewrite:
+// void FuncArg2Ptr(int arg1, base::span<int> arg2) {
+void FuncArg2Ptr(int arg1, int* arg2) {
+  arg2[UnsafeIndex()] = 3;
+}
+
+// Expected rewrite:
+// base::span<int> FuncRet() {
+int* FuncRet() {
+  static int arr[] = {1, 2, 3};
+  return arr;
+}
+
+// Expected rewrite:
+// base::span<int> FuncAll(base::span<int, 3> arg1,
+//                         base::span<int> arg2,
+//                         base::base::raw_span<int> arg3) {
+int* FuncAll(int arg1[3], int* arg2, base::raw_ptr<int> arg3) {
+  arg1[UnsafeIndex()] = 3;
+  arg2[UnsafeIndex()] = 3;
+  arg3[UnsafeIndex()] = 3;
+  static int arr[] = {1, 2, 3};
+  return arr;
+}
+
+void test_type_alias() {
+  int arr[] = {1, 2, 3};
+
+  // TODO(yukishiino): Currently the following line is needed to get FuncRet
+  // spanified. This shouldn't be needed because we have other unsafe usages
+  // through function pointers.
+  FuncRet()[UnsafeIndex()] = 3;
+  FuncAll(arr, arr, arr)[UnsafeIndex()] = 3;
+
+  // Without a typedef / using declaration
+  {
+    // Expected rewrite:
+    // void (*p_arg1arr_init)(base::span<int, 3> arg1) = FuncArg1Arr;
+    void (*p_arg1arr_init)(int arg1[3]) = FuncArg1Arr;
+    p_arg1arr_init(arr);
+
+    // Expected rewrite:
+    // void (*p_arg2ptr_assign)(int arg1, base::span<int> arg2);
+    void (*p_arg2ptr_assign)(int arg1, int* arg2);
+    p_arg2ptr_assign = FuncArg2Ptr;
+    p_arg2ptr_assign(3, arr);
+
+    // Expected rewrite:
+    // void (*p_arg2arr_init)(int, base::span<int, 3>) = FuncArg2Arr;
+    void (*p_arg2arr_init)(int, int[3]) = FuncArg2Arr;
+    p_arg2arr_init(3, arr);
+
+    // Expected rewrite:
+    // base::span<int> (*p_ret_init)() = FuncRet;
+    int* (*p_ret_init)() = FuncRet;
+    // TODO(yukishiino): The following should be
+    //     base::span<int> ret_init = ...
+    int* ret_init = p_ret_init();
+    ret_init[UnsafeIndex()] = 3;
+
+    // Expected rewrite:
+    // base::span<int> (*p_ret_assign)();
+    int* (*p_ret_assign)();
+    p_ret_assign = FuncRet;
+    // TODO(yukishiino): The following should be
+    //     base::span<int> ret_assign = ...
+    int* ret_assign = p_ret_assign();
+    ret_assign[UnsafeIndex()] = 3;
+  }
+
+  // With typedef declarations
+  {
+    // Expected rewrite:
+    // typedef void (*Arg1ArrType)(base::span<int, 3> arg1);
+    typedef void (*Arg1ArrType)(int arg1[3]);
+    Arg1ArrType p_arg1arr_init = FuncArg1Arr;
+    p_arg1arr_init(arr);
+
+    // Expected rewrite:
+    // typedef void (*Arg2PtrType)(int arg1, base::span<int> arg2);
+    typedef void (*Arg2PtrType)(int arg1, int* arg2);
+    Arg2PtrType p_arg2ptr_assign;
+    p_arg2ptr_assign = FuncArg2Ptr;
+    p_arg2ptr_assign(3, arr);
+
+    // Expected rewrite:
+    // typedef void (*Arg2ArrType)(int, base::span<int, 3>);
+    typedef void (*Arg2ArrType)(int, int[3]);
+    Arg2ArrType p_arg2arr_init = FuncArg2Arr;
+    p_arg2arr_init(3, arr);
+
+    // Expected rewrite:
+    // typedef base::span<int> (*RetInitType)();
+    typedef int* (*RetInitType)();
+    RetInitType p_ret_init = FuncRet;
+    // TODO(yukishiino): The following should be
+    //     base::span<int> ret_init = ...
+    int* ret_init = p_ret_init();
+    ret_init[UnsafeIndex()] = 3;
+
+    // Expected rewrite:
+    // typedef base::span<int> (*RetAssignType)();
+    typedef int* (*RetAssignType)();
+    RetAssignType p_ret_assign;
+    p_ret_assign = FuncRet;
+    // TODO(yukishiino): The following should be
+    //     base::span<int> ret_assign = ...
+    int* ret_assign = p_ret_assign();
+    ret_assign[UnsafeIndex()] = 3;
+  }
+
+  // With using declarations
+  {
+    // Expected rewrite:
+    // using Arg1ArrType = void (*)(base::span<int, 3> arg1);
+    using Arg1ArrType = void (*)(int arg1[3]);
+    Arg1ArrType p_arg1arr_init = FuncArg1Arr;
+    p_arg1arr_init(arr);
+
+    // Expected rewrite:
+    // using Arg2PtrType = void (*)(int arg1, base::span<int> arg2);
+    using Arg2PtrType = void (*)(int arg1, int* arg2);
+    Arg2PtrType p_arg2ptr_assign;
+    p_arg2ptr_assign = FuncArg2Ptr;
+    p_arg2ptr_assign(3, arr);
+
+    // Expected rewrite:
+    // using Arg2ArrType = void (*)(int, base::span<int, 3>);
+    using Arg2ArrType = void (*)(int, int[3]);
+    Arg2ArrType p_arg2arr_init = FuncArg2Arr;
+    p_arg2arr_init(3, arr);
+
+    // Expected rewrite:
+    // using RetInitType = base::span<int> (*)();
+    using RetInitType = int* (*)();
+    RetInitType p_ret_init = FuncRet;
+    // TODO(yukishiino): The following should be
+    //     base::span<int> ret_init = ...
+    int* ret_init = p_ret_init();
+    ret_init[UnsafeIndex()] = 3;
+
+    // Expected rewrite:
+    // using RetAssignType = base::span<int> (*)();
+    using RetAssignType = int* (*)();
+    RetAssignType p_ret_assign;
+    p_ret_assign = FuncRet;
+    // TODO(yukishiino): The following should be
+    //     base::span<int> ret_assign = ...
+    int* ret_assign = p_ret_assign();
+    ret_assign[UnsafeIndex()] = 3;
+  }
+
+  // With nested typedef/using and multiple rewritings on the func ptr type
+  {
+    // Expected rewrite:
+    // typedef base::span<int> (*AllType1)(base::span<int, 3> arg1,
+    //                                     base::span<int> arg2,
+    //                                     base::base::raw_span<int> arg3);
+    typedef int* (*AllType1)(int arg1[3], int* arg2, base::raw_ptr<int> arg3);
+    using AllType2 = AllType1;
+    AllType2 p_all = FuncAll;
+    int* ret_all = p_all(arr, arr, arr);
+    ret_all[UnsafeIndex()] = 3;
+  }
+}
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml
index 320bcaf..26d79fb7 100644
--- a/tools/metrics/histograms/metadata/media/histograms.xml
+++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -7351,13 +7351,14 @@
 </histogram>
 
 <histogram name="Media.VideoCaptureManager.DesktopCaptureImplementationAndType"
-    enum="DesktopCaptureImplementationAndType" expires_after="2025-07-27">
+    enum="DesktopCaptureImplementationAndType" expires_after="2026-09-01">
   <owner>handellm@google.com</owner>
   <owner>ccameron@chromium.org</owner>
   <summary>
     Indicates which desktop capture implementation and DesktopID::Type was used
     for a desktop capture session. Recorded on instantiation of the desktop
-    capturer.
+    capturer. Warning: this histogram was expired from 2025-07-27 to 2025-09-05;
+    data may be missing.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml
index cf241b7..30facf1 100644
--- a/tools/metrics/histograms/metadata/navigation/histograms.xml
+++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -277,6 +277,25 @@
   </summary>
 </histogram>
 
+<histogram name="BackForwardCache.CCNS.CookieChangeInfo.{CountType}"
+    units="count" expires_after="2026-01-20">
+  <owner>leimy@chromium.org</owner>
+  <owner>bfcache-dev@chromium.org</owner>
+  <summary>
+    Logs the {CountType} cookie change details for a page.
+
+    This is recorded during navigation away from any page configured with
+    Cache-Control: no-store, at the moment the browser checks if the page can be
+    stored in the BFCache.
+  </summary>
+  <token key="CountType">
+    <variant name="AllCookies"/>
+    <variant name="AllCookiesFromMainFrameNavigation"/>
+    <variant name="HttpOnlyCookies"/>
+    <variant name="HttpOnlyCookiesFromMainFrameNavigation"/>
+  </token>
+</histogram>
+
 <histogram name="BackForwardCache.EvictedAfterDocumentRestoredReason"
     enum="BackForwardCacheEvictedAfterDocumentRestoredReason"
     expires_after="2024-09-15">
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml
index c216c0e..6651717 100644
--- a/tools/metrics/histograms/metadata/net/histograms.xml
+++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -1248,14 +1248,19 @@
   </token>
 </histogram>
 
-<histogram name="Net.AcceptCHFrameInterceptor.MismatchClientHint"
-    enum="WebClientHintsType" expires_after="2026-02-01">
+<histogram name="Net.AcceptCHFrameInterceptor.MismatchClientHint2"
+    enum="WebClientHintsType" expires_after="2026-08-01">
   <owner>yyanagisawa@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
-    Records which client hint caused the Accept-CH frame offload to fail because
-    the hint was not in the enabled list. This is recorded when
-    AcceptCHFrameInterceptor::NeedsObserverCheck returns kHintNotEnabled.
+    To optimize performance, the network service can handle `Accept-CH` frames
+    directly without consulting the browser process (an optimization called
+    'offloading'). This histogram is recorded when that optimization fails. It
+    identifies the specific client hint from the `Accept-CH` frame that was not
+    in the network service's cache of hints the browser had previously
+    identified as either allowed or disallowed for the origin. A value is
+    recorded each time this mismatch occurs, forcing a fallback to the browser
+    process.
   </summary>
 </histogram>
 
@@ -1270,6 +1275,22 @@
   </summary>
 </histogram>
 
+<histogram name="Net.AcceptCHFrameInterceptor.OffloadSuccessForNotAllowedHint"
+    enum="WebClientHintsType" expires_after="2026-08-01">
+  <owner>yyanagisawa@chromium.org</owner>
+  <owner>chrome-loading@google.com</owner>
+  <summary>
+    When handling an `Accept-CH` frame, the network service can sometimes avoid
+    a costly round-trip to the browser process by checking for required client
+    hints itself (an optimization called 'offloading'). This histogram is
+    recorded for each client hint that was successfully offloaded specifically
+    because of a mechanism enabled by the AcceptCHFrameOffloadNotAllowedHints
+    feature parameter. This mechanism allows offloading for hints that are
+    persisted for an origin but currently disabled by Permissions Policy. This
+    metric helps measure the effectiveness of this opt-in optimization.
+  </summary>
+</histogram>
+
 <histogram name="Net.AlternateProtocolBrokenLocation"
     enum="BrokenAlternateProtocolLocation" expires_after="2024-02-25">
   <owner>dschinazi@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/page/histograms.xml b/tools/metrics/histograms/metadata/page/histograms.xml
index 372a5d8a..04df6b50 100644
--- a/tools/metrics/histograms/metadata/page/histograms.xml
+++ b/tools/metrics/histograms/metadata/page/histograms.xml
@@ -4338,6 +4338,18 @@
 </histogram>
 
 <histogram
+    name="PageLoad.PaintTiming.NavigationToFirstContentfulPaint.ExcludeReloadAfterDiscard"
+    units="ms" expires_after="2026-02-28">
+  <owner>fdoray@chromium.org</owner>
+  <owner>catan-team@chromium.org</owner>
+  <summary>
+    This is recorded at the same time and with the same value as
+    PageLoad.PaintTiming.NavigationToFirstContentfulPaint, but only if the
+    navigation isn't a post-discard reload.
+  </summary>
+</histogram>
+
+<histogram
     name="PageLoad.PaintTiming.NavigationToFirstContentfulPaint.Incognito"
     units="ms" expires_after="2026-03-01">
   <owner>kjarosz@google.com</owner>
@@ -4555,6 +4567,18 @@
 </histogram>
 
 <histogram
+    name="PageLoad.PaintTiming.NavigationToLargestContentfulPaint2.ExcludeReloadAfterDiscard"
+    units="ms" expires_after="2026-02-28">
+  <owner>fdoray@chromium.org</owner>
+  <owner>catan-team@chromium.org</owner>
+  <summary>
+    This is recorded at the same time and with the same value as
+    PageLoad.PaintTiming.NavigationToLargestContentfulPaint2, but only if the
+    navigation isn't a post-discard reload.
+  </summary>
+</histogram>
+
+<histogram
     name="PageLoad.PaintTiming.NavigationToLargestContentfulPaint2.Incognito"
     units="ms" expires_after="2026-01-21">
   <owner>kjarosz@google.com</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 07d22fa..b4cda88 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,8 +5,8 @@
             "full_remote_path": "perfetto-luci-artifacts/d17b40b3b5e36f3744f1d010fe3ba2d3c55559c0/linux-arm64/trace_processor_shell"
         },
         "win": {
-            "hash": "8cc66584154f077d1cbfd36997dc762c69b002f0",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/313e4b6b9117daa3241863a5ce31c203c218164a/trace_processor_shell.exe"
+            "hash": "d71b23c07437afabbfb0536e4cd93fa5a734eadf",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/10197969fa01e9ba91d58b9e0a34716533ee332f/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "d2819bf77c3920780f2b33cc43f328d24cc1e427",
@@ -22,7 +22,7 @@
         },
         "linux": {
             "hash": "09dbe5feb30a573538ea9703aea58f8e6c4570fe",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/313e4b6b9117daa3241863a5ce31c203c218164a/trace_processor_shell"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/10197969fa01e9ba91d58b9e0a34716533ee332f/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/aura/gestures/gesture_recognizer_unittest.cc b/ui/aura/gestures/gesture_recognizer_unittest.cc
index d92879b..00e8c0df 100644
--- a/ui/aura/gestures/gesture_recognizer_unittest.cc
+++ b/ui/aura/gestures/gesture_recognizer_unittest.cc
@@ -2461,8 +2461,8 @@
 // by the root window's gesture sequence.
 TEST_F(GestureRecognizerTest, GestureEventOutsideRootWindowTap) {
   TimedEvents tes;
-  std::unique_ptr<aura::Window> window(CreateTestWindowWithBounds(
-      gfx::Rect(-100, -100, 2000, 2000), root_window()));
+  std::unique_ptr<aura::Window> window(
+      CreateTestWindow({.bounds = {-100, -100, 2000, 2000}}, root_window()));
 
   gfx::Point pos1(-10, -10);
   ui::TouchEvent press1(ui::EventType::kTouchPressed, pos1, tes.Now(),
@@ -2656,7 +2656,7 @@
   EXPECT_TRUE(delegate->tap_down());
 
   std::unique_ptr<aura::Window> capture(
-      CreateTestWindowWithBounds(gfx::Rect(10, 10, 200, 200), root_window()));
+      CreateTestWindow({.bounds = {10, 10, 200, 200}}, root_window()));
   capture->SetCapture();
   RunAllPendingInMessageLoop();
 
@@ -2712,7 +2712,7 @@
 
   // Create a new window and set it as the new capture window.
   std::unique_ptr<aura::Window> window2(
-      CreateTestWindowWithBounds(gfx::Rect(100, 100, 300, 300), root_window()));
+      CreateTestWindow({.bounds = {100, 100, 300, 300}}, root_window()));
   window2->SetCapture();
   RunAllPendingInMessageLoop();
   // Check that setting capture does not generate any synthetic touch-cancels
diff --git a/ui/aura/test/test_windows.cc b/ui/aura/test/test_windows.cc
index 4751680..8d0eaf0c 100644
--- a/ui/aura/test/test_windows.cc
+++ b/ui/aura/test/test_windows.cc
@@ -26,13 +26,7 @@
       .Build();
 }
 
-Window* CreateTestWindowWithId(int id, Window* parent) {
-  return CreateTestWindowWithDelegate(NULL, id, gfx::Rect(), parent);
-}
 
-Window* CreateTestWindowWithBounds(const gfx::Rect& bounds, Window* parent) {
-  return CreateTestWindowWithDelegate(NULL, 0, bounds, parent);
-}
 
 Window* CreateTestWindow(SkColor color,
                          int id,
diff --git a/ui/aura/test/test_windows.h b/ui/aura/test/test_windows.h
index 417b905..33ffc24 100644
--- a/ui/aura/test/test_windows.h
+++ b/ui/aura/test/test_windows.h
@@ -30,8 +30,6 @@
 // Creates a test window. If parent window is nullptr, then the caller must take
 // ownership of the created window.
 // Deprecated: Use CreateTestWindow above.
-Window* CreateTestWindowWithId(int id, Window* parent);
-Window* CreateTestWindowWithBounds(const gfx::Rect& bounds, Window* parent);
 Window* CreateTestWindow(SkColor color,
                          int id,
                          const gfx::Rect& bounds,
diff --git a/ui/aura/window_event_dispatcher_unittest.cc b/ui/aura/window_event_dispatcher_unittest.cc
index 1f0f57e..77a8d2c 100644
--- a/ui/aura/window_event_dispatcher_unittest.cc
+++ b/ui/aura/window_event_dispatcher_unittest.cc
@@ -312,10 +312,12 @@
       : root_window_(root_window), lock_(false) {
     client::SetEventClient(root_window_, this);
     Window* lock_window =
-        test::CreateTestWindowWithBounds(root_window_->bounds(), root_window_);
+        test::CreateTestWindow({.bounds = root_window_->bounds()}, root_window_)
+            .release();
     lock_window->SetId(kLockWindowId);
     Window* non_lock_window =
-        test::CreateTestWindowWithBounds(root_window_->bounds(), root_window_);
+        test::CreateTestWindow({.bounds = root_window_->bounds()}, root_window_)
+            .release();
     non_lock_window->SetId(kNonLockWindowId);
   }
 
@@ -365,11 +367,13 @@
   client.GetNonLockWindow()->AddPreTargetHandler(&nonlock_ef);
   client.GetLockWindow()->AddPreTargetHandler(&lock_ef);
 
-  Window* w1 = test::CreateTestWindowWithBounds(gfx::Rect(10, 10, 20, 20),
-                                                client.GetNonLockWindow());
+  Window* w1 = test::CreateTestWindow({.bounds = {10, 10, 20, 20}},
+                                      client.GetNonLockWindow())
+                   .release();
   w1->SetId(1);
-  Window* w2 = test::CreateTestWindowWithBounds(gfx::Rect(30, 30, 20, 20),
-                                                client.GetNonLockWindow());
+  Window* w2 = test::CreateTestWindow({.bounds = {30, 30, 20, 20}},
+                                      client.GetNonLockWindow())
+                   .release();
   w2->SetId(2);
   std::unique_ptr<Window> w3(test::CreateTestWindowWithDelegate(
       &d, 3, gfx::Rect(30, 30, 20, 20), client.GetLockWindow()));
@@ -3251,8 +3255,9 @@
   // Create a window which has a focus, so should receive all KeyEvents.
   ConsumeKeyHandler key_handler;
   // Not using std::unique_ptr<> intentionally
-  aura::Window* focused(test::CreateTestWindowWithBounds(
-      gfx::Rect(200, 200, 100, 100), root_window()));
+  aura::Window* focused =
+      test::CreateTestWindow({.bounds = {200, 200, 100, 100}}, root_window())
+          .release();
   focused->SetProperty(client::kSkipImeProcessing, true);
   focused->AddPostTargetHandler(&key_handler);
   focused->Show();
diff --git a/ui/aura/window_unittest.cc b/ui/aura/window_unittest.cc
index a77c620..794ac6b1 100644
--- a/ui/aura/window_unittest.cc
+++ b/ui/aura/window_unittest.cc
@@ -1289,9 +1289,9 @@
 
 TEST_F(WindowTest, GetBoundsInRootWindow) {
   std::unique_ptr<Window> viewport(
-      CreateTestWindowWithBounds(gfx::Rect(0, 0, 300, 300), root_window()));
+      CreateTestWindow({.bounds{0, 0, 300, 300}}, root_window()));
   std::unique_ptr<Window> child(
-      CreateTestWindowWithBounds(gfx::Rect(0, 0, 100, 100), viewport.get()));
+      CreateTestWindow({.bounds = {100, 100}}, viewport.get()));
   // Sanity check.
   EXPECT_EQ("0,0 100x100", child->GetBoundsInRootWindow().ToString());
 
@@ -1306,14 +1306,14 @@
 }
 
 TEST_F(WindowTest, GetBoundsInRootWindowWithLayers) {
-  std::unique_ptr<Window> viewport(
-      CreateTestWindowWithBounds(gfx::Rect(0, 0, 300, 300), root_window()));
+  std::unique_ptr<Window> viewport =
+      CreateTestWindow({.bounds = gfx::Rect(0, 0, 300, 300)}, root_window());
 
   std::unique_ptr<Window> widget(
-      CreateTestWindowWithBounds(gfx::Rect(0, 0, 200, 200), viewport.get()));
+      CreateTestWindow({.bounds = {200, 200}}, viewport.get()));
 
   std::unique_ptr<Window> child(
-      CreateTestWindowWithBounds(gfx::Rect(0, 0, 100, 100), widget.get()));
+      CreateTestWindow({.bounds = {100, 100}}, widget.get()));
 
   // Sanity check.
   EXPECT_EQ("0,0 100x100", child->GetBoundsInRootWindow().ToString());
@@ -1333,13 +1333,13 @@
 
 TEST_F(WindowTest, GetBoundsInRootWindowWithLayersAndTranslations) {
   std::unique_ptr<Window> viewport(
-      CreateTestWindowWithBounds(gfx::Rect(0, 0, 300, 300), root_window()));
+      CreateTestWindow({.bounds = {300, 300}}, root_window()));
 
-  std::unique_ptr<Window> widget(
-      CreateTestWindowWithBounds(gfx::Rect(0, 0, 200, 200), viewport.get()));
+  std::unique_ptr<Window> widget =
+      CreateTestWindow({.bounds = {200, 200}}, viewport.get());
 
   std::unique_ptr<Window> child(
-      CreateTestWindowWithBounds(gfx::Rect(0, 0, 100, 100), widget.get()));
+      CreateTestWindow({.bounds = {100, 100}}, widget.get()));
 
   // Sanity check.
   EXPECT_EQ("0,0 100x100", child->GetBoundsInRootWindow().ToString());
@@ -1930,7 +1930,7 @@
       ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
 
   std::unique_ptr<Window> w1(
-      CreateTestWindowWithBounds(gfx::Rect(0, 0, 100, 100), root_window()));
+      CreateTestWindow({.bounds = {100, 100}}, root_window()));
 
   EXPECT_TRUE(w1->layer());
   w1->layer()->GetAnimator()->set_disable_timer_for_test(true);
@@ -3758,12 +3758,10 @@
   // WindowTest:
   void SetUp() override {
     WindowTest::SetUp();
-    viewport_ = std::unique_ptr<Window>(CreateTestWindowWithBounds(
-        gfx::Rect(/*x=*/100, /*y=*/50, /*width=*/200, /*height=*/200),
-        root_window()));
-    child_ = std::unique_ptr<Window>(CreateTestWindowWithBounds(
-        gfx::Rect(/*x=*/0, /*y=*/0, /*width=*/100, /*height*/ 100),
-        viewport_.get()));
+    viewport_ = std::unique_ptr<Window>(
+        CreateTestWindow({.bounds = {100, 50, 200, 200}}, root_window()));
+    child_ = std::unique_ptr<Window>(
+        CreateTestWindow({.bounds = {100, 100}}, viewport_.get()));
   }
 
   void TearDown() override {
diff --git a/ui/base/models/image_model_utils.cc b/ui/base/models/image_model_utils.cc
index 48960501..0644ec1 100644
--- a/ui/base/models/image_model_utils.cc
+++ b/ui/base/models/image_model_utils.cc
@@ -14,8 +14,9 @@
 namespace ui {
 
 // TODO(dpenning) consider parameterizing color choices for disabled defaults.
-ImageModel GetDefaultDisabledIconFromImageModel(ImageModel icon_model,
-                                                ColorProvider* color_provider) {
+ImageModel GetDefaultDisabledIconFromImageModel(
+    ImageModel icon_model,
+    const ColorProvider* color_provider) {
   if (icon_model.IsEmpty()) {
     return icon_model;
   }
diff --git a/ui/base/models/image_model_utils.h b/ui/base/models/image_model_utils.h
index 7fe4a3b..798dc056 100644
--- a/ui/base/models/image_model_utils.h
+++ b/ui/base/models/image_model_utils.h
@@ -13,7 +13,7 @@
 
 COMPONENT_EXPORT(UI_BASE)
 ImageModel GetDefaultDisabledIconFromImageModel(ImageModel icon,
-                                                ColorProvider* = nullptr);
+                                                const ColorProvider* = nullptr);
 
 }  // namespace ui
 
diff --git a/ui/wm/core/coordinate_conversion_unittest.cc b/ui/wm/core/coordinate_conversion_unittest.cc
index 7beabf5..b9126bb 100644
--- a/ui/wm/core/coordinate_conversion_unittest.cc
+++ b/ui/wm/core/coordinate_conversion_unittest.cc
@@ -13,23 +13,23 @@
 typedef aura::test::AuraTestBase CoordinateConversionTest;
 
 TEST_F(CoordinateConversionTest, ConvertRect) {
-  aura::Window* w = aura::test::CreateTestWindowWithBounds(
-      gfx::Rect(10, 20, 100, 200), root_window());
+  std::unique_ptr<aura::Window> w(aura::test::CreateTestWindow(
+      {.bounds = {10, 20, 100, 200}}, root_window()));
 
   gfx::Rect r1(10, 20, 100, 120);
-  ConvertRectFromScreen(w, &r1);
+  ConvertRectFromScreen(w.get(), &r1);
   EXPECT_EQ("0,0 100x120", r1.ToString());
 
   gfx::Rect r2(0, 0, 100, 200);
-  ConvertRectFromScreen(w, &r2);
+  ConvertRectFromScreen(w.get(), &r2);
   EXPECT_EQ("-10,-20 100x200", r2.ToString());
 
   gfx::Rect r3(30, 30, 100, 200);
-  ConvertRectToScreen(w, &r3);
+  ConvertRectToScreen(w.get(), &r3);
   EXPECT_EQ("40,50 100x200", r3.ToString());
 
   gfx::Rect r4(-10, -20, 100, 200);
-  ConvertRectToScreen(w, &r4);
+  ConvertRectToScreen(w.get(), &r4);
   EXPECT_EQ("0,0 100x200", r4.ToString());
 }
 
diff --git a/ui/wm/core/ime_util_chromeos_unittest.cc b/ui/wm/core/ime_util_chromeos_unittest.cc
index 58af313..b34334f 100644
--- a/ui/wm/core/ime_util_chromeos_unittest.cc
+++ b/ui/wm/core/ime_util_chromeos_unittest.cc
@@ -20,7 +20,7 @@
 TEST_F(ImeUtilChromeosTest, RestoreWindowBounds) {
   const gfx::Rect bounds(10, 20, 100, 200);
   aura::Window* window =
-      aura::test::CreateTestWindowWithBounds(bounds, root_window());
+      aura::test::CreateTestWindow({.bounds = bounds}, root_window()).release();
 
   EXPECT_EQ(nullptr, window->GetProperty(kVirtualKeyboardRestoreBoundsKey));
   EXPECT_EQ(bounds, window->bounds());
@@ -38,7 +38,7 @@
 TEST_F(ImeUtilChromeosTest, EnsureWindowNotInRect_NotCovered) {
   const gfx::Rect bounds(0, 0, 100, 200);
   aura::Window* window =
-      aura::test::CreateTestWindowWithBounds(bounds, root_window());
+      aura::test::CreateTestWindow({.bounds = bounds}, root_window()).release();
   EXPECT_EQ(bounds, window->bounds());
   EXPECT_EQ(bounds, window->GetBoundsInScreen());
 
@@ -54,7 +54,8 @@
 TEST_F(ImeUtilChromeosTest, EnsureWindowNotInRect_MoveUp) {
   const gfx::Rect original_bounds(10, 100, 100, 10);
   aura::Window* window =
-      aura::test::CreateTestWindowWithBounds(original_bounds, root_window());
+      aura::test::CreateTestWindow({.bounds = original_bounds}, root_window())
+          .release();
   EXPECT_EQ(original_bounds, window->bounds());
   EXPECT_EQ(original_bounds, window->GetBoundsInScreen());
 
@@ -71,7 +72,8 @@
 TEST_F(ImeUtilChromeosTest, EnsureWindowNotInRect_MoveToTop) {
   const gfx::Rect original_bounds(10, 10, 100, 100);
   aura::Window* window =
-      aura::test::CreateTestWindowWithBounds(original_bounds, root_window());
+      aura::test::CreateTestWindow({.bounds = original_bounds}, root_window())
+          .release();
   EXPECT_EQ(original_bounds, window->bounds());
   EXPECT_EQ(original_bounds, window->GetBoundsInScreen());
 
@@ -100,7 +102,8 @@
 TEST_F(ImeUtilChromeosTest, MoveUpThenRestore) {
   const gfx::Rect original_bounds(50, 50, 100, 100);
   aura::Window* window =
-      aura::test::CreateTestWindowWithBounds(original_bounds, root_window());
+      aura::test::CreateTestWindow({.bounds = original_bounds}, root_window())
+          .release();
   EXPECT_EQ(original_bounds, window->bounds());
   EXPECT_EQ(original_bounds, window->GetBoundsInScreen());
 
diff --git a/ui/wm/core/shadow_controller_unittest.cc b/ui/wm/core/shadow_controller_unittest.cc
index 2f9d469e..c2f0317 100644
--- a/ui/wm/core/shadow_controller_unittest.cc
+++ b/ui/wm/core/shadow_controller_unittest.cc
@@ -127,7 +127,7 @@
 TEST_F(ShadowControllerTest, ShadowBoundsDetached) {
   const gfx::Rect kInitialBounds(20, 30, 400, 300);
   std::unique_ptr<aura::Window> window(
-      aura::test::CreateTestWindowWithBounds(kInitialBounds, root_window()));
+      aura::test::CreateTestWindow({.bounds = kInitialBounds}, root_window()));
   window->Show();
   const ui::Shadow* shadow = ShadowController::GetShadowForWindow(window.get());
   ASSERT_TRUE(shadow);