diff --git a/DEPS b/DEPS
index 1eabc40..0e3b1244 100644
--- a/DEPS
+++ b/DEPS
@@ -309,7 +309,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '064cf12ad0cce462f4c2871ddbe6642746bc91ee',
+  'skia_revision': '310062ae6aee31778717d28b8fb33536dc642a4b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -329,7 +329,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': 'b6b33a84ed7badd0441cec1324ba3ef7f1d897e2',
+  'boringssl_revision': '0226f30467f540a3f62ef48d453f93927da199b6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Fuchsia sdk
   # and whatever else without interference from each other.
@@ -421,7 +421,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'f1d98befa15c18fddc72c68ea9f5278800fb813b',
+  'dawn_revision': '7e45e468cf42e3c0d21d539010fc06b839021b62',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -529,7 +529,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling llvm-libc
   # and whatever else without interference from each other.
-  'compiler_rt_revision': '0c75031f1b7a0556a6cc07b6aa97a260278c5e0d',
+  'compiler_rt_revision': '514effe33889c9cd899c10ef7ad1f79fb86ef388',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling clusterfuzz-data
   # and whatever else without interference from each other.
@@ -1201,7 +1201,7 @@
       'packages': [
           {
               'package': 'chromium/chrome/android/orderfiles/arm',
-              'version': 'AFoVTwjpRw8r8lgSatRpwiL2QkWkDECz063PWEffFqUC',
+              'version': 'iLqyq0OJbkb07A2XBhEXl-wkg-fo0TrQZ0Govmvo2igC',
           },
       ],
       'condition': 'checkout_android',
@@ -1212,7 +1212,7 @@
       'packages': [
           {
               'package': 'chromium/chrome/android/orderfiles/arm64',
-              'version': 'adjHfRaBecwZ_WoRzkIuxnkbcLsqdK3yWwa8I7jOrhIC',
+              'version': 'iyYOxdaIkUQzhd86m2bxHDSasCY4MDHOJ0WZbT1y4CcC',
           },
       ],
       'condition': 'checkout_android',
@@ -1602,7 +1602,7 @@
     'packages': [
       {
         'package': 'chromium/chrome/test/data/variations/cipd',
-        'version': '4Wxj6G1nbxmGpqhJFFili5C1Ly15LngIQAiaFmKk1DcC',
+        'version': 'oysm4wyMa-wEEu7CEakwg5WYPMC2Sm8NWV9TZ-Ah_rMC',
       },
     ],
     'dep_type': 'cipd',
@@ -1613,7 +1613,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '5e36fab7a4bfa7d98ad3a9ba760f39af8c2c12eb',
+    '73faa4938c6a3d50fccccdcdba2813f0f74d5c01',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1834,7 +1834,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_build_tools/error_prone',
-               'version': '47nFaUKq3UemCr0EHmMYPJ63Y9hRnNII7iNn5zYK9qsC',
+               'version': '_xvKMGMJix5ysOYKkNTfSBd8CHQlf-DqEmAYYoEP3wgC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -1856,7 +1856,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_build_tools/lint',
-               'version': '_v7pAuSk9urtP9QU6HH2OCUTGys9gUV74h8gJu1csI8C',
+               'version': 'd6CQ9eCLBIOopQEbwq-Sax2LJTcnhF8kso6FeFopbkgC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -1867,7 +1867,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_build_tools/manifest_merger',
-               'version': 'lKMwtNMqvRbDnUel3vBQLv-Of-xpdg_Rc54QKgdOCx0C',
+               'version': 'MFlelAeq9AjbPFiLMR9nSNIXDKTdmo99j3cyOZk_MPkC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -2344,7 +2344,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/kotlin_stdlib',
-              'version': 'oWawDQgUnvOKIXGZEvlJh9_3V_8yrKEM1C3TH9si7QkC',
+              'version': 'lJ1ajSYdxA0t3wZsp2zpIONZcyNduY7KYeswoOrtMd8C',
           },
       ],
       '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' + '@' + '67f0bdf7285d15783e7ee55c1e5d524887d43f33',
+    Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + '93825934c10d3a8179e1b8b840bbe1fd7f64a913',
 
   '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' + '@' + '0b497723227dcfa52047ca9d136b1ffbe130ea68',
+    Var('webrtc_git') + '/src.git' + '@' + '981d111a875397315b34fa6889809c8862feb60d',
 
   # 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.
@@ -3156,7 +3156,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': '2rHUg6orSG3ymd4TUQiQiTuR5Ho0FmpyrTde7lUwTrcC',
+        'version': '4ZGHAcrjscwpb9U0z_Iqybjr2-zbHIYRhmYxyVTq1B8C',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -3167,7 +3167,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'ZMM7YKBIpxed9hu1p5KOOM51JUXmDjjdYkbGYauV6ygC',
+        'version': 'JSPNBKrJTsgGEPGhmC-tSIFmtrPRr8dNteLUrPNYznAC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -3200,7 +3200,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/projector_app/app',
-        'version': 'Y-QBg0h9cHTRkaH_PMSvm11TgZvtn47Kro8BBuM5ssMC',
+        'version': 'xRvlx0alnmSj6RfDIVuiRsCxk_DilhFe1Po_wEDAhL0C',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -3793,7 +3793,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        'd7e03032fddf9552e94070778f3cfb775ab89dd2',
+        '21d8a0cb8e9d5392de3dee97d473f17ca97def28',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/ash/clipboard/clipboard_history_controller_unittest.cc b/ash/clipboard/clipboard_history_controller_unittest.cc
index a7a68fe..aad41a5 100644
--- a/ash/clipboard/clipboard_history_controller_unittest.cc
+++ b/ash/clipboard/clipboard_history_controller_unittest.cc
@@ -168,7 +168,11 @@
            static_cast<int>(ClipboardHistoryControllerShowSource::kMinValue);
        i <= static_cast<int>(ClipboardHistoryControllerShowSource::kMaxValue);
        ++i) {
-    sources.push_back(static_cast<ClipboardHistoryControllerShowSource>(i));
+    // kControlVLongpress is deprecated.
+    if (static_cast<ClipboardHistoryControllerShowSource>(i) !=
+        ClipboardHistoryControllerShowSource::kControlVLongpress) {
+      sources.push_back(static_cast<ClipboardHistoryControllerShowSource>(i));
+    }
   }
   return sources;
 }
@@ -801,10 +805,6 @@
 
 // Tests that `ShowMenu()` returns whether the menu was shown successfully.
 TEST_P(ClipboardHistoryControllerShowSourceTest, ShowMenuReturnsSuccess) {
-  if (GetSource() == ClipboardHistoryControllerShowSource::kControlVLongpress) {
-    GTEST_SKIP();
-  }
-
   base::HistogramTester histogram_tester;
 
   // Try to show the menu without populating the clipboard. The menu should not
diff --git a/ash/clipboard/clipboard_history_menu_model_adapter.cc b/ash/clipboard/clipboard_history_menu_model_adapter.cc
index 2558d78..c948e3753 100644
--- a/ash/clipboard/clipboard_history_menu_model_adapter.cc
+++ b/ash/clipboard/clipboard_history_menu_model_adapter.cc
@@ -72,9 +72,6 @@
     crosapi::mojom::ClipboardHistoryControllerShowSource show_source,
     const std::optional<base::Time>& menu_last_time_shown,
     const std::optional<base::Time>& nudge_last_time_shown) {
-  // A footer is always required when the menu is shown via Ctrl+V long press.
-  using crosapi::mojom::ClipboardHistoryControllerShowSource;
-
   // A footer is required if the menu hasn't been shown in the past 60 days.
   if (TimeSince(menu_last_time_shown.value_or(base::Time())) >=
       base::Days(60)) {
diff --git a/ash/clipboard/clipboard_history_menu_model_adapter_unittest.cc b/ash/clipboard/clipboard_history_menu_model_adapter_unittest.cc
index 758f9d6..b7ad0d3 100644
--- a/ash/clipboard/clipboard_history_menu_model_adapter_unittest.cc
+++ b/ash/clipboard/clipboard_history_menu_model_adapter_unittest.cc
@@ -66,7 +66,11 @@
            static_cast<int>(ClipboardHistoryControllerShowSource::kMinValue);
        i <= static_cast<int>(ClipboardHistoryControllerShowSource::kMaxValue);
        ++i) {
-    sources.push_back(static_cast<ClipboardHistoryControllerShowSource>(i));
+    // kControlVLongpress is deprecated.
+    if (static_cast<ClipboardHistoryControllerShowSource>(i) !=
+        ClipboardHistoryControllerShowSource::kControlVLongpress) {
+      sources.push_back(static_cast<ClipboardHistoryControllerShowSource>(i));
+    }
   }
   return sources;
 }
@@ -291,10 +295,6 @@
 
 TEST_P(ClipboardHistoryMenuModelAdapterMenuItemTest,
        HeaderAndFooterConditionallyPresent) {
-  if (GetSource() == ClipboardHistoryControllerShowSource::kControlVLongpress) {
-    GTEST_SKIP();
-  }
-
   // Write items to clipboard history so that the menu can show.
   WriteTextToClipboardAndFlushMessageLoop(u"A");
   WriteTextToClipboardAndFlushMessageLoop(u"B");
diff --git a/base/allocator/partition_allocator/src/partition_alloc/third_party/apple_apsl/README.chromium b/base/allocator/partition_allocator/src/partition_alloc/third_party/apple_apsl/README.chromium
index d6172a7..7193f27 100644
--- a/base/allocator/partition_allocator/src/partition_alloc/third_party/apple_apsl/README.chromium
+++ b/base/allocator/partition_allocator/src/partition_alloc/third_party/apple_apsl/README.chromium
@@ -27,7 +27,7 @@
 Version: CF-635
 Security Critical: yes
 Shipped: yes
-License: Apple Public Source License 2.0
+License: APSL-2.0
 License File: LICENSE
 
 Local Modifications:
diff --git a/base/third_party/symbolize/README.chromium b/base/third_party/symbolize/README.chromium
index 0ddd458..64b8725 100644
--- a/base/third_party/symbolize/README.chromium
+++ b/base/third_party/symbolize/README.chromium
@@ -3,6 +3,7 @@
 License: BSD-3-Clause
 License File: LICENSE
 Shipped: yes
+Security Critical: yes
 
 The following files were copied from:
 https://github.com/google/glog/tree/b70ea80433c2a8f20b832be97b90f1f82b0d29e9
diff --git a/chrome/VERSION b/chrome/VERSION
index 7627e22c..c7de9b79 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=142
 MINOR=0
-BUILD=7399
+BUILD=7401
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
index 0500a40..0bb5536 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
@@ -724,18 +724,12 @@
 
     @Override
     protected void updateCustomActionButton(int index, Drawable drawable, String description) {
-        ImageButton button;
-        if (ChromeFeatureList.sCctToolbarRefactor.isEnabled()) {
-            button =
-                    (ImageButton)
-                            mCustomButtonsParent.getChildAt(
-                                    mCustomButtonsParent.getChildCount() - 1 - index);
-        } else {
-            // |index| -> childIndex should ignore the optional button always present at the end.
-            int childIndex = mCustomActionButtons.getChildCount() - 2 - index;
-            assert 0 <= childIndex && childIndex <= mCustomActionButtons.getChildCount() - 2;
-            button = (ImageButton) mCustomActionButtons.getChildAt(childIndex);
-        }
+        if (ChromeFeatureList.sCctToolbarRefactor.isEnabled()) return;
+
+        // |index| -> childIndex should ignore the optional button always present at the end.
+        int childIndex = mCustomActionButtons.getChildCount() - 2 - index;
+        assert 0 <= childIndex && childIndex <= mCustomActionButtons.getChildCount() - 2;
+        ImageButton button = (ImageButton) mCustomActionButtons.getChildAt(childIndex);
         assert button != null;
         updateCustomActionButtonVisuals(button, drawable, description);
         adjustCustomActionButtonPadding(index, button);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsCoordinator.java
index 19ee803..ddf604b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsCoordinator.java
@@ -23,6 +23,7 @@
 
 import org.chromium.base.Callback;
 import org.chromium.build.annotations.Nullable;
+import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.CustomTabProfileType;
@@ -105,6 +106,7 @@
                         omniboxEnabled,
                         titleVisible,
                         isIncognito);
+        view.setTag(R.id.view_model, mModel);
         CustomTabToolbarButtonsViewBinder viewBinder = new CustomTabToolbarButtonsViewBinder();
         PropertyModelChangeProcessor.create(mModel, view, viewBinder);
         mCustomActionButtonsMcp =
@@ -195,6 +197,17 @@
         mModel.set(CUSTOM_ACTION_BUTTONS_VISIBLE, visible);
     }
 
+    /**
+     * Updates the visual appearance of a custom action button.
+     *
+     * @param index The index of the button.
+     * @param drawable The icon for the button.
+     * @param description The content description for the button.
+     */
+    public void updateCustomActionButton(int index, Drawable drawable, String description) {
+        mMediator.updateCustomActionButton(index, drawable, description);
+    }
+
     static PropertyListModel<PropertyModel, PropertyKey> getCustomActionButtonsModel(
             Context context,
             BrowserServicesIntentDataProvider intentDataProvider,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsMediator.java
index 4f198639..a0bd865 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsMediator.java
@@ -8,6 +8,8 @@
 import static org.chromium.build.NullUtil.assumeNonNull;
 import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.CUSTOM_ACTION_BUTTONS;
 import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.CUSTOM_ACTION_BUTTONS_VISIBLE;
+import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.DESCRIPTION;
+import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.ICON;
 import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.IS_INCOGNITO;
 import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.MINIMIZE_BUTTON;
 import static org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarButtonsProperties.OMNIBOX_ENABLED;
@@ -17,6 +19,7 @@
 
 import android.app.Activity;
 import android.content.res.Configuration;
+import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.view.View;
 import android.view.ViewGroup;
@@ -122,6 +125,12 @@
         mModel.set(MINIMIZE_BUTTON, getMinimizeButtonData());
     }
 
+    void updateCustomActionButton(int index, Drawable drawable, String description) {
+        var model = mModel.get(CUSTOM_ACTION_BUTTONS).get(index);
+        model.set(ICON, drawable);
+        model.set(DESCRIPTION, description);
+    }
+
     void setOptionalButtonData(@Nullable ButtonData buttonData) {
         boolean showOptionalButton =
                 mOptionalButtonCoordinator == null ? initializeOptionalButton() : true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsViewBinder.java
index 07b037b..009a823 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarButtonsViewBinder.java
@@ -150,11 +150,8 @@
             int index,
             int count,
             @Nullable PropertyKey payload) {
-        for (int i = index; i < index + count; i++) {
-            PropertyModel customButtonModel = model.get(i);
-            view.updateCustomActionButton(
-                    index, customButtonModel.get(ICON), customButtonModel.get(DESCRIPTION));
-        }
+        inflateAndPositionToolbarElements(
+                view, (PropertyModel) view.getTag(R.id.view_model), mVisFlipper);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarCoordinator.java
index 1fb951e..a905208 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarCoordinator.java
@@ -342,6 +342,15 @@
             assert false;
             return false;
         }
+
+        if (ChromeFeatureList.sCctToolbarRefactor.isEnabled()) {
+            if (mToolbarButtonsCoordinator == null) return false;
+
+            mToolbarButtonsCoordinator.updateCustomActionButton(
+                    index, params.getIcon(mActivity), params.getDescription());
+            return true;
+        }
+
         if (mToolbarManager == null) {
             return false;
         }
diff --git a/chrome/android/profiles/arm.newest.txt b/chrome/android/profiles/arm.newest.txt
index 4c5c0bb..2b42ddf6 100644
--- a/chrome/android/profiles/arm.newest.txt
+++ b/chrome/android/profiles/arm.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-142.0.7395.0_pre1511283_rc-r1-merged.afdo.bz2
+chromeos-chrome-arm-142.0.7399.0_pre1512109_rc-r1-merged.afdo.bz2
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index fe7e53d..2d5fdff 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-142.0.7395.0_pre1511283_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-142.0.7400.0_pre1512128_rc-r1-merged.afdo.bz2
diff --git a/chrome/browser/accessibility/leaked_node_detection_browsertest.cc b/chrome/browser/accessibility/leaked_node_detection_browsertest.cc
index 53bdd70..8810577 100644
--- a/chrome/browser/accessibility/leaked_node_detection_browsertest.cc
+++ b/chrome/browser/accessibility/leaked_node_detection_browsertest.cc
@@ -70,7 +70,10 @@
   WaitForNodeCounts({0U, 0U, 0U, 0U});
 }
 
-IN_PROC_BROWSER_TEST_P(LeakedNodeDetectionBrowsertest, TerminateClient) {
+// Disabled due to flaky failures. It seems that not all machines perform
+// rundown quckily upon disappearance of the client.
+IN_PROC_BROWSER_TEST_P(LeakedNodeDetectionBrowsertest,
+                       DISABLED_TerminateClient) {
   // Initialize the UI Automation client; giving it this window.
   ASSERT_HRESULT_SUCCEEDED(InitializeClient(browser()));
 
diff --git a/chrome/browser/ash/account_manager/account_manager_policy_controller_browsertest.cc b/chrome/browser/ash/account_manager/account_manager_policy_controller_browsertest.cc
index c4dfe37..a79a8e3 100644
--- a/chrome/browser/ash/account_manager/account_manager_policy_controller_browsertest.cc
+++ b/chrome/browser/ash/account_manager/account_manager_policy_controller_browsertest.cc
@@ -87,11 +87,6 @@
     profile_builder.SetProfileName(kFakePrimaryUsername);
     profile_ = IdentityTestEnvironmentProfileAdaptor::
         CreateProfileForIdentityTestEnvironment(profile_builder);
-    auto* factory =
-        g_browser_process->platform_part()->GetAccountManagerFactory();
-    account_manager_ = factory->GetAccountManager(profile()->GetPath().value());
-    account_manager_facade_ =
-        GetAccountManagerFacade(profile()->GetPath().value());
     identity_test_environment_adaptor_ =
         std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile_.get());
 
@@ -106,11 +101,14 @@
                                              primary_account_info.gaia));
 
     // Add accounts in Account Manager.
-    account_manager_->UpsertAccount(
+    auto* account_manager =
+        ash::AccountManagerFactory::Get()->GetAccountManager(
+            profile_->GetPath().value());
+    account_manager->UpsertAccount(
         ::account_manager::AccountKey::FromGaiaId(primary_account_info.gaia),
         primary_account_info.email,
         account_manager::AccountManager::kInvalidToken);
-    account_manager_->UpsertAccount(
+    account_manager->UpsertAccount(
         ::account_manager::AccountKey::FromGaiaId(kFakeSecondaryGaiaId),
         kFakeSecondaryUsername, account_manager::AccountManager::kInvalidToken);
 
@@ -124,11 +122,14 @@
   }
 
   std::vector<::account_manager::Account> GetAccountManagerAccounts() {
-    CHECK(account_manager_facade_);
+    auto* account_manager_facade =
+        ash::AccountManagerFactory::Get()->GetAccountManagerFacade(
+            profile_->GetPath().value());
+    CHECK(account_manager_facade);
 
     base::test::TestFuture<const std::vector<::account_manager::Account>&>
         future;
-    account_manager_facade_->GetAccounts(future.GetCallback());
+    account_manager_facade->GetAccounts(future.GetCallback());
     return future.Get();
   }
 
@@ -141,10 +142,6 @@
 
  private:
   base::ScopedTempDir temp_dir_;
-  raw_ptr<account_manager::AccountManager, DanglingUntriaged> account_manager_ =
-      nullptr;
-  raw_ptr<account_manager::AccountManagerFacade> account_manager_facade_ =
-      nullptr;
   std::unique_ptr<Profile> profile_;
   std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
       identity_test_environment_adaptor_;
diff --git a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/bar/BookmarkBarMediator.java b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/bar/BookmarkBarMediator.java
index 94d40ad..32466d66 100644
--- a/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/bar/BookmarkBarMediator.java
+++ b/chrome/browser/bookmarks/android/java/src/org/chromium/chrome/browser/bookmarks/bar/BookmarkBarMediator.java
@@ -17,6 +17,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewParent;
 import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.TextView;
@@ -47,6 +48,7 @@
 import org.chromium.components.browser_ui.widget.BrowserUiListMenuUtils;
 import org.chromium.components.image_fetcher.ImageFetcherConfig;
 import org.chromium.components.image_fetcher.ImageFetcherFactory;
+import org.chromium.ui.base.KeyNavigationUtil;
 import org.chromium.ui.listmenu.BasicListMenu;
 import org.chromium.ui.listmenu.ListItemType;
 import org.chromium.ui.listmenu.ListMenuItemProperties;
@@ -790,43 +792,96 @@
     // Builds and returns an OnKeyListener for every item in the popup menu.
     private View.OnKeyListener createPopupMenuItemKeyListener(
             PropertyModel model, BookmarkItem bookmarkItem) {
+        // view is the root View object inflated from list_menu_item.xml.
         return (view, keyCode, event) -> {
-            // Only proceed if the user has released the Enter key.
-            if (event.getAction() != KeyEvent.ACTION_UP || keyCode != KeyEvent.KEYCODE_ENTER) {
-                return false;
-            }
-
             if (bookmarkItem == null) return false;
-
-            if (bookmarkItem.isFolder()) {
-                // Get the pre-made "open submenu" click listener from the model.
-                View.OnClickListener clickListener =
-                        model.get(ListMenuItemProperties.CLICK_LISTENER);
-                if (clickListener != null) {
-                    // Calls ListMenuUtils#onItemWithSubmenuClicked.
-                    clickListener.onClick(view);
+            // ACTION_DOWN is used because KeyNavigationUtil#isGoBackward depends on isActionDown to
+            // be true.
+            if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                // Handle Left Arrow to go back to the parent menu.
+                if (KeyNavigationUtil.isGoBackward(event)) {
+                    // Directly find the submenu header, which the go back onClickListener is
+                    // attached to.
+                    View headerView = findMenuHeaderView(view);
+                    if (headerView != null) {
+                        // Calls headerBackClick.run() in ListMenuUtils.
+                        headerView.performClick();
+                        // We've handled the left arrow, so consume the event.
+                        return true;
+                    }
                 }
-            } else if (event.isCtrlPressed()) {
-                // Not a folder and ctrl pressed. Open bookmark in new tab.
-                mBookmarkOpener.openBookmarksInNewTabs(
-                        List.of(bookmarkItem.getId()),
-                        mProfileSupplier.get().isOffTheRecord(),
-                        Optional.of(TabLaunchType.FROM_BOOKMARK_BAR_BACKGROUND));
-                // Dismiss only when opening a bookmark (webpage) and not a folder.
-                if (mAnchoredPopupWindow != null) mAnchoredPopupWindow.dismiss();
-            } else {
-                // Not a folder and ctrl not pressed. This is a plain enter key press. Open bookmark
-                // in current tab,
-                mBookmarkOpener.openBookmarkInCurrentTab(
-                        bookmarkItem.getId(), mProfileSupplier.get().isOffTheRecord());
-                // Dismiss only when opening a bookmark (webpage) and not a folder.
-                if (mAnchoredPopupWindow != null) mAnchoredPopupWindow.dismiss();
+
+                // Handle Right Arrow to drill-down only if the item is a folder.
+                if (KeyNavigationUtil.isGoForward(event) && bookmarkItem.isFolder()) {
+                    // Get the pre-made "open submenu" click listener from the model.
+                    View.OnClickListener clickListener =
+                            model.get(ListMenuItemProperties.CLICK_LISTENER);
+                    if (clickListener != null) {
+                        // Calls ListMenuUtils#onItemWithSubmenuClicked.
+                        clickListener.onClick(view);
+                    }
+                    // We've handled the right arrow, so consume the event.
+                    return true;
+                }
             }
-            // Always consume the event to prevent fallback.
-            return true;
+
+            // Only proceed if the user has released the Enter key.
+            if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_ENTER) {
+                if (bookmarkItem.isFolder()) {
+                    // Get the pre-made "open submenu" click listener from the model.
+                    View.OnClickListener clickListener =
+                            model.get(ListMenuItemProperties.CLICK_LISTENER);
+                    if (clickListener != null) {
+                        // Calls ListMenuUtils#onItemWithSubmenuClicked.
+                        clickListener.onClick(view);
+                    }
+                } else if (event.isCtrlPressed()) {
+                    // Not a folder and ctrl pressed. Open bookmark in new tab.
+                    mBookmarkOpener.openBookmarksInNewTabs(
+                            List.of(bookmarkItem.getId()),
+                            mProfileSupplier.get().isOffTheRecord(),
+                            Optional.of(TabLaunchType.FROM_BOOKMARK_BAR_BACKGROUND));
+                    // Dismiss only when opening a bookmark (webpage) and not a folder.
+                    if (mAnchoredPopupWindow != null) mAnchoredPopupWindow.dismiss();
+                } else {
+                    // Not a folder and ctrl not pressed. This is a plain enter key press. Open
+                    // bookmark in current tab,
+                    mBookmarkOpener.openBookmarkInCurrentTab(
+                            bookmarkItem.getId(), mProfileSupplier.get().isOffTheRecord());
+                    // Dismiss only when opening a bookmark (webpage) and not a folder.
+                    if (mAnchoredPopupWindow != null) mAnchoredPopupWindow.dismiss();
+                }
+                // Always consume the event to prevent fallback.
+                return true;
+            }
+            return false;
         };
     }
 
+    /**
+     * Finds the header view within the current popup menu by traversing up from a given item
+     * (list_menu_item.xml). This method is used to trigger the back navigation for the left arrow
+     * key.
+     *
+     * @param currentItemView The view of a currently focused menu item.
+     * @return The menu header view if found, otherwise null.
+     */
+    private @Nullable View findMenuHeaderView(View currentItemView) {
+        ViewParent parent = currentItemView.getParent();
+        // Walk up the tree until we find a parent that contains R.id.menu_header.
+        while (parent instanceof View) {
+            View parentView = (View) parent;
+            ListView headerListView = parentView.findViewById(R.id.menu_header);
+            if (headerListView != null && headerListView.getChildCount() > 0) {
+                // If headerListView is not null, there will only be one item inside it,
+                // the headerView that acts as the back button.
+                return headerListView.getChildAt(0);
+            }
+            parent = parentView.getParent();
+        }
+        return null;
+    }
+
     void setAnchoredPopupWindowForTesting(AnchoredPopupWindow anchoredPopupWindow) {
         mAnchoredPopupWindow = anchoredPopupWindow;
     }
diff --git a/chrome/browser/resource_coordinator/session_restore_policy.cc b/chrome/browser/resource_coordinator/session_restore_policy.cc
index abb7c29..0ca7a9b 100644
--- a/chrome/browser/resource_coordinator/session_restore_policy.cc
+++ b/chrome/browser/resource_coordinator/session_restore_policy.cc
@@ -38,8 +38,9 @@
 #include "third_party/blink/public/common/permissions/permission_utils.h"
 
 #if !BUILDFLAG(IS_ANDROID)
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
+// TODO(crbug.com/407105162): Remove nogncheck when crbug.com/40147906 is fixed.
+#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"  // nogncheck
+#include "chrome/browser/ui/browser_window/public/browser_window_interface_iterator.h"  // nogncheck
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #endif
 
@@ -124,16 +125,16 @@
   // this!
   // In theory all tabs should belong to a tab-strip, but in tests this isn't
   // necessarily true.
-  auto* browser_list = BrowserList::GetInstance();
-  for (size_t i = 0; i < browser_list->size(); ++i) {
-    auto* browser = browser_list->get(i);
-    auto* tab_strip = browser->tab_strip_model();
-    int tab_index = tab_strip->GetIndexOfWebContents(contents);
-    if (tab_index == TabStripModel::kNoTab)
-      continue;
-    tab_data->is_pinned = tab_strip->IsTabPinned(tab_index);
-    break;
-  }
+  ForEachCurrentBrowserWindowInterfaceOrderedByActivation(
+      [&](BrowserWindowInterface* browser) {
+        auto* const tab_strip = browser->GetTabStripModel();
+        const int tab_index = tab_strip->GetIndexOfWebContents(contents);
+        if (tab_index == TabStripModel::kNoTab) {
+          return true;  // continue iteration.
+        }
+        tab_data->is_pinned = tab_strip->IsTabPinned(tab_index);
+        return false;  // end iteration.
+      });
 #endif  // !BUILDFLAG(IS_ANDROID)
 
   // Cache a handful of other properties.
diff --git a/chrome/browser/signin/chrome_signin_helper.h b/chrome/browser/signin/chrome_signin_helper.h
index 47b3ecc..760f8fd 100644
--- a/chrome/browser/signin/chrome_signin_helper.h
+++ b/chrome/browser/signin/chrome_signin_helper.h
@@ -73,6 +73,9 @@
   virtual void SetDestructionCallback(base::OnceClosure closure) = 0;
 };
 
+// `ResponseAdapter` provides an interface for accessing and modifying
+// properties of a network response. It is used by `HeaderModificationDelegate`
+// to process response headers for sign-in related requests.
 class ResponseAdapter {
  public:
   ResponseAdapter();
@@ -82,15 +85,32 @@
 
   virtual ~ResponseAdapter();
 
+  // Returns a getter for the `WebContents` associated with the request that
+  // received this response.
   virtual content::WebContents::Getter GetWebContentsGetter() const = 0;
+  // Returns true if the response is for an outermost main frame request.
   virtual bool IsOutermostMainFrame() const = 0;
+  // Returns the URL of the response. This may be different from the initial
+  // request URL if there were redirects.
   virtual GURL GetUrl() const = 0;
+  // Returns the origin that initiated the request. This may be empty for
+  // browser-initiated requests.
   virtual std::optional<url::Origin> GetRequestInitiator() const = 0;
+  // Returns the top-frame origin of the request. This may be empty for
+  // renderer-initiated requests, as those requests do not set "trusted"
+  // parameters.
   virtual const url::Origin* GetRequestTopFrameOrigin() const = 0;
+  // Returns a pointer to the HTTP response headers.
+  // May return null if a response doesn't have associated headers.
   virtual const net::HttpResponseHeaders* GetHeaders() const = 0;
+  // Removes a header from the HTTP response headers.
   virtual void RemoveHeader(const std::string& name) = 0;
 
+  // Retrieves user data associated with this response.
   virtual base::SupportsUserData::Data* GetUserData(const void* key) const = 0;
+  // Associates user data with this response.
+  // If `data` is `nullptr`, this method removes data previously associated with
+  // the `key`.
   virtual void SetUserData(
       const void* key,
       std::unique_ptr<base::SupportsUserData::Data> data) = 0;
diff --git a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc
index 4783dd684..9320ed02 100644
--- a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc
+++ b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc
@@ -270,12 +270,9 @@
 class ProxyingURLLoaderFactory::InProgressRequest::ProxyResponseAdapter
     : public ResponseAdapter {
  public:
-  ProxyResponseAdapter(InProgressRequest* in_progress_request,
+  ProxyResponseAdapter(InProgressRequest& in_progress_request,
                        net::HttpResponseHeaders* headers)
-      : in_progress_request_(in_progress_request), headers_(headers) {
-    DCHECK(in_progress_request_);
-    DCHECK(headers_);
-  }
+      : in_progress_request_(in_progress_request), headers_(headers) {}
 
   ProxyResponseAdapter(const ProxyResponseAdapter&) = delete;
   ProxyResponseAdapter& operator=(const ProxyResponseAdapter&) = delete;
@@ -306,7 +303,9 @@
   }
 
   void RemoveHeader(const std::string& name) override {
-    headers_->RemoveHeader(name);
+    if (headers_) {
+      headers_->RemoveHeader(name);
+    }
   }
 
   base::SupportsUserData::Data* GetUserData(const void* key) const override {
@@ -320,7 +319,7 @@
   }
 
  private:
-  const raw_ptr<InProgressRequest> in_progress_request_;
+  const raw_ref<InProgressRequest> in_progress_request_;
   const raw_ptr<net::HttpResponseHeaders> headers_;
 };
 
@@ -422,7 +421,7 @@
   // Even though |head| is const we can get a non-const pointer to the headers
   // and modifications we made are passed to the target client.
   {
-    ProxyResponseAdapter adapter(this, head->headers.get());
+    ProxyResponseAdapter adapter(*this, head->headers.get());
     factory_->delegate_->ProcessResponse(&adapter, GURL() /* redirect_url */);
     // The `adapter` must be destroyed before moving the `head` in the
     // `target_client_`.
@@ -437,7 +436,7 @@
   // Even though |head| is const we can get a non-const pointer to the headers
   // and modifications we made are passed to the target client.
   {
-    ProxyResponseAdapter adapter(this, head->headers.get());
+    ProxyResponseAdapter adapter(*this, head->headers.get());
     factory_->delegate_->ProcessResponse(&adapter, redirect_info.new_url);
     // The `adapter` must be destroyed before moving the `head` in the
     // `target_client_`.
diff --git a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory_unittest.cc b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory_unittest.cc
index 1059d336..6af26fd 100644
--- a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory_unittest.cc
+++ b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory_unittest.cc
@@ -10,7 +10,9 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/run_loop.h"
+#include "base/task/current_thread.h"
 #include "base/test/mock_callback.h"
+#include "base/test/test_future.h"
 #include "chrome/browser/signin/chrome_signin_helper.h"
 #include "chrome/browser/signin/header_modification_delegate.h"
 #include "content/public/test/browser_task_environment.h"
@@ -40,13 +42,19 @@
 
   ~MockDelegate() override = default;
 
-  MOCK_METHOD1(ShouldInterceptNavigation, bool(content::WebContents* contents));
-  MOCK_METHOD2(ProcessRequest,
-               void(ChromeRequestAdapter* request_adapter,
-                    const GURL& redirect_url));
-  MOCK_METHOD2(ProcessResponse,
-               void(ResponseAdapter* response_adapter,
-                    const GURL& redirect_url));
+  MOCK_METHOD(bool,
+              ShouldInterceptNavigation,
+              (content::WebContents * contents),
+              (override));
+  MOCK_METHOD(void,
+              ProcessRequest,
+              (ChromeRequestAdapter * request_adapter,
+               const GURL& redirect_url),
+              (override));
+  MOCK_METHOD(void,
+              ProcessResponse,
+              (ResponseAdapter * response_adapter, const GURL& redirect_url),
+              (override));
 
   base::WeakPtr<MockDelegate> GetWeakPtr() {
     return weak_factory_.GetWeakPtr();
@@ -95,10 +103,7 @@
                 test_factory_receiver_.BindNewPipeAndPassRemote()));
 
     loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
-        factory_remote.get(),
-        base::BindOnce(
-            &ChromeSigninProxyingURLLoaderFactoryTest::OnDownloadComplete,
-            base::Unretained(this)));
+        factory_remote.get(), request_complete_future_.GetCallback());
 
     return delegate_weak;
   }
@@ -107,10 +112,9 @@
 
   network::TestURLLoaderFactory* factory() { return &test_factory_; }
   network::SimpleURLLoader* loader() { return loader_.get(); }
-  std::string* response_body() { return response_body_.get(); }
-
-  void OnDownloadComplete(std::unique_ptr<std::string> body) {
-    response_body_ = std::move(body);
+  base::test::TestFuture<std::unique_ptr<std::string>>&
+  request_complete_future() {
+    return request_complete_future_;
   }
 
  private:
@@ -124,7 +128,7 @@
   std::unique_ptr<ProxyingURLLoaderFactory> proxying_factory_;
   network::TestURLLoaderFactory test_factory_;
   mojo::Receiver<network::mojom::URLLoaderFactory> test_factory_receiver_;
-  std::unique_ptr<std::string> response_body_;
+  base::test::TestFuture<std::unique_ptr<std::string>> request_complete_future_;
 };
 
 TEST_F(ChromeSigninProxyingURLLoaderFactoryTest, NoModification) {
@@ -134,10 +138,11 @@
   factory()->AddResponse("https://google.com/", "Hello.");
   base::WeakPtr<MockDelegate> delegate = StartRequest(std::move(request));
 
-  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(request_complete_future().Wait());
+  std::string* response_body = request_complete_future().Get().get();
   EXPECT_EQ(net::OK, loader()->NetError());
-  ASSERT_TRUE(response_body());
-  EXPECT_EQ("Hello.", *response_body());
+  ASSERT_TRUE(response_body);
+  EXPECT_EQ("Hello.", *response_body);
 }
 
 TEST_F(ChromeSigninProxyingURLLoaderFactoryTest, ModifyHeaders) {
@@ -164,7 +169,7 @@
 
   // The delegate will be called twice to process a request, first when the
   // request is started and again when the request is redirected.
-  EXPECT_CALL(*delegate, ProcessRequest(_, _))
+  EXPECT_CALL(*delegate, ProcessRequest)
       .WillOnce(
           Invoke([&](ChromeRequestAdapter* adapter, const GURL& redirect_url) {
             EXPECT_EQ(kTestURL, adapter->GetUrl());
@@ -219,7 +224,7 @@
 
   // The delegate will also be called twice to process a response, first when
   // the redirect is received and again for the redirect response.
-  EXPECT_CALL(*delegate, ProcessResponse(_, _))
+  EXPECT_CALL(*delegate, ProcessResponse)
       .WillOnce(Invoke([&](ResponseAdapter* adapter, const GURL& redirect_url) {
         EXPECT_EQ(kTestURL, adapter->GetUrl());
         EXPECT_TRUE(adapter->IsOutermostMainFrame());
@@ -284,19 +289,23 @@
   }
 
   // Wait for the request to complete and check the response.
-  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(request_complete_future().Wait());
+  std::string* response_body = request_complete_future().Get().get();
   EXPECT_EQ(net::OK, loader()->NetError());
   const network::mojom::URLResponseHead* response_head =
       loader()->ResponseInfo();
   ASSERT_TRUE(response_head && response_head->headers);
   EXPECT_FALSE(response_head->headers->HasHeader("X-Response-3"));
   EXPECT_TRUE(response_head->headers->HasHeader("X-Response-4"));
-  ASSERT_TRUE(response_body());
-  EXPECT_EQ("Hello.", *response_body());
+  ASSERT_TRUE(response_body);
+  EXPECT_EQ("Hello.", *response_body);
 
   // NOTE: TestURLLoaderFactory currently does not expose modifications to
   // request headers and so we cannot verify that the modifications have been
   // passed to the target URLLoader.
+
+  // `delegate` should be destroyed shortly.
+  base::test::RunUntil([&] { return delegate == nullptr; });
 }
 
 TEST_F(ChromeSigninProxyingURLLoaderFactoryTest, TargetFactoryFailure) {
@@ -307,7 +316,7 @@
 
   // Without a target factory the proxy will process no requests.
   auto delegate = std::make_unique<MockDelegate>();
-  EXPECT_CALL(*delegate, ProcessRequest(_, _)).Times(0);
+  EXPECT_CALL(*delegate, ProcessRequest).Times(0);
 
   network::URLLoaderFactoryBuilder factory_builder;
 
@@ -331,13 +340,9 @@
   auto loader = network::SimpleURLLoader::Create(std::move(request),
                                                  TRAFFIC_ANNOTATION_FOR_TESTS);
   loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
-      factory_remote.get(),
-      base::BindOnce(
-          &ChromeSigninProxyingURLLoaderFactoryTest::OnDownloadComplete,
-          base::Unretained(this)));
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_FALSE(response_body());
+      factory_remote.get(), request_complete_future().GetCallback());
+  ASSERT_TRUE(request_complete_future().Wait());
+  EXPECT_FALSE(request_complete_future().Get());
   EXPECT_EQ(net::ERR_FAILED, loader->NetError());
 }
 
@@ -359,12 +364,79 @@
 
   // Complete the request.
   factory()->AddResponse("https://google.com", "Hello.");
-  base::RunLoop().RunUntilIdle();
 
-  EXPECT_FALSE(delegate);
+  ASSERT_TRUE(request_complete_future().Wait());
+  std::string* response_body = request_complete_future().Get().get();
   EXPECT_EQ(net::OK, loader()->NetError());
-  ASSERT_TRUE(response_body());
-  EXPECT_EQ("Hello.", *response_body());
+  ASSERT_TRUE(response_body);
+  EXPECT_EQ("Hello.", *response_body);
+
+  // `delegate` should be destroyed shortly.
+  base::test::RunUntil([&] { return delegate == nullptr; });
+  EXPECT_FALSE(delegate);
+}
+
+// Regression test for https://crbug.com/441955793.
+TEST_F(ChromeSigninProxyingURLLoaderFactoryTest, ResponseWithNullHeaders) {
+  const GURL kTestURL("https://google.com/index.html");
+  const GURL kTestReferrer("https://chrome.com/referrer.html");
+  const GURL kTestRedirectURL("https://youtube.com/index.html");
+
+  // Set up the request.
+  auto request = std::make_unique<network::ResourceRequest>();
+  request->url = kTestURL;
+  request->referrer = kTestReferrer;
+
+  base::WeakPtr<MockDelegate> delegate = StartRequest(std::move(request));
+
+  // The delegate will be called twice to process a request, first when the
+  // request is started and again when the request is redirected.
+  EXPECT_CALL(*delegate, ProcessRequest).Times(2);
+
+  // The delegate will also be called twice to process a response, first when
+  // the redirect is received and again for the redirect response.
+  EXPECT_CALL(*delegate, ProcessResponse)
+      .WillOnce(Invoke([&](ResponseAdapter* adapter, const GURL& redirect_url) {
+        EXPECT_EQ(kTestURL, adapter->GetUrl());
+        EXPECT_EQ(kTestRedirectURL, redirect_url);
+        // This should not crash.
+        adapter->RemoveHeader("TestHeader");
+        EXPECT_FALSE(adapter->GetHeaders());
+      }))
+      .WillOnce(Invoke([&](ResponseAdapter* adapter, const GURL& redirect_url) {
+        EXPECT_EQ(kTestRedirectURL, adapter->GetUrl());
+        EXPECT_EQ(GURL(), redirect_url);
+        // This should not crash.
+        adapter->RemoveHeader("TestHeader");
+        EXPECT_FALSE(adapter->GetHeaders());
+      }));
+
+  // Set up a redirect and final response.
+  {
+    net::RedirectInfo redirect_info;
+    redirect_info.new_url = kTestRedirectURL;
+    // An HTTPS to HTTPS redirect such as this wouldn't normally change the
+    // referrer but we do for testing purposes.
+    redirect_info.new_referrer = kTestURL.spec();
+
+    // Response head with null headers.
+    auto redirect_head = network::mojom::URLResponseHead::New();
+    auto response_head = network::mojom::URLResponseHead::New();
+
+    network::TestURLLoaderFactory::Redirects redirects;
+    redirects.emplace_back(redirect_info, std::move(redirect_head));
+
+    factory()->AddResponse(
+        kTestURL, std::move(response_head), /*content=*/std::string(),
+        network::URLLoaderCompletionStatus(), std::move(redirects));
+  }
+
+  // Wait for the request to complete and check the response.
+  ASSERT_TRUE(request_complete_future().Wait());
+  const network::mojom::URLResponseHead* response_head =
+      loader()->ResponseInfo();
+  ASSERT_TRUE(response_head);
+  EXPECT_FALSE(response_head->headers);
 }
 
 }  // namespace signin
diff --git a/chrome/browser/signin/chrome_signin_url_loader_throttle.cc b/chrome/browser/signin/chrome_signin_url_loader_throttle.cc
index bce48c9..fd0f90a1 100644
--- a/chrome/browser/signin/chrome_signin_url_loader_throttle.cc
+++ b/chrome/browser/signin/chrome_signin_url_loader_throttle.cc
@@ -62,7 +62,7 @@
 
 class URLLoaderThrottle::ThrottleResponseAdapter : public ResponseAdapter {
  public:
-  ThrottleResponseAdapter(URLLoaderThrottle* throttle,
+  ThrottleResponseAdapter(URLLoaderThrottle& throttle,
                           net::HttpResponseHeaders* headers)
       : throttle_(throttle), headers_(headers) {}
 
@@ -95,7 +95,9 @@
   }
 
   void RemoveHeader(const std::string& name) override {
-    headers_->RemoveHeader(name);
+    if (headers_) {
+      headers_->RemoveHeader(name);
+    }
   }
 
   base::SupportsUserData::Data* GetUserData(const void* key) const override {
@@ -109,8 +111,8 @@
   }
 
  private:
-  const raw_ptr<URLLoaderThrottle> throttle_;
-  raw_ptr<net::HttpResponseHeaders> headers_;
+  const raw_ref<URLLoaderThrottle> throttle_;
+  const raw_ptr<net::HttpResponseHeaders> headers_;
 };
 
 // static
@@ -179,7 +181,7 @@
 
   // Modifications to |response_head.headers| will be passed to the
   // URLLoaderClient even though |response_head| is const.
-  ThrottleResponseAdapter response_adapter(this, response_head.headers.get());
+  ThrottleResponseAdapter response_adapter(*this, response_head.headers.get());
   delegate_->ProcessResponse(&response_adapter, redirect_info->new_url);
 
   request_url_ = redirect_info->new_url;
@@ -190,7 +192,7 @@
     const GURL& response_url,
     network::mojom::URLResponseHead* response_head,
     bool* defer) {
-  ThrottleResponseAdapter adapter(this, response_head->headers.get());
+  ThrottleResponseAdapter adapter(*this, response_head->headers.get());
   delegate_->ProcessResponse(&adapter, GURL() /* redirect_url */);
 }
 
diff --git a/chrome/browser/signin/chrome_signin_url_loader_throttle_unittest.cc b/chrome/browser/signin/chrome_signin_url_loader_throttle_unittest.cc
index ea3e22b..78774ecf 100644
--- a/chrome/browser/signin/chrome_signin_url_loader_throttle_unittest.cc
+++ b/chrome/browser/signin/chrome_signin_url_loader_throttle_unittest.cc
@@ -32,13 +32,19 @@
 
   ~MockDelegate() override = default;
 
-  MOCK_METHOD1(ShouldInterceptNavigation, bool(content::WebContents* contents));
-  MOCK_METHOD2(ProcessRequest,
-               void(ChromeRequestAdapter* request_adapter,
-                    const GURL& redirect_url));
-  MOCK_METHOD2(ProcessResponse,
-               void(ResponseAdapter* response_adapter,
-                    const GURL& redirect_url));
+  MOCK_METHOD(bool,
+              ShouldInterceptNavigation,
+              (content::WebContents * contents),
+              (override));
+  MOCK_METHOD(void,
+              ProcessRequest,
+              (ChromeRequestAdapter * request_adapter,
+               const GURL& redirect_url),
+              (override));
+  MOCK_METHOD(void,
+              ProcessResponse,
+              (ResponseAdapter * response_adapter, const GURL& redirect_url),
+              (override));
 };
 
 content::WebContents::Getter NullWebContentsGetter() {
@@ -50,14 +56,14 @@
 TEST(ChromeSigninURLLoaderThrottleTest, NoIntercept) {
   auto* delegate = new MockDelegate();
 
-  EXPECT_CALL(*delegate, ShouldInterceptNavigation(_)).WillOnce(Return(false));
+  EXPECT_CALL(*delegate, ShouldInterceptNavigation).WillOnce(Return(false));
   EXPECT_FALSE(URLLoaderThrottle::MaybeCreate(base::WrapUnique(delegate),
                                               NullWebContentsGetter()));
 }
 
 TEST(ChromeSigninURLLoaderThrottleTest, Intercept) {
   auto* delegate = new MockDelegate();
-  EXPECT_CALL(*delegate, ShouldInterceptNavigation(_)).WillOnce(Return(true));
+  EXPECT_CALL(*delegate, ShouldInterceptNavigation).WillOnce(Return(true));
   auto throttle = URLLoaderThrottle::MaybeCreate(base::WrapUnique(delegate),
                                                  NullWebContentsGetter());
   ASSERT_TRUE(throttle);
@@ -67,7 +73,7 @@
   const GURL kTestURL("https://google.com/index.html");
   const GURL kTestReferrer("https://chrome.com/referrer.html");
   base::MockCallback<base::OnceClosure> destruction_callback;
-  EXPECT_CALL(*delegate, ProcessRequest(_, _))
+  EXPECT_CALL(*delegate, ProcessRequest)
       .WillOnce(
           Invoke([&](ChromeRequestAdapter* adapter, const GURL& redirect_url) {
             EXPECT_EQ(kTestURL, adapter->GetUrl());
@@ -114,7 +120,7 @@
   base::SupportsUserData::Data* response_user_data_ptr =
       response_user_data.get();
 
-  EXPECT_CALL(*delegate, ProcessResponse(_, _))
+  EXPECT_CALL(*delegate, ProcessResponse)
       .WillOnce(Invoke([&](ResponseAdapter* adapter, const GURL& redirect_url) {
         EXPECT_EQ(kTestURL, adapter->GetUrl());
         EXPECT_TRUE(adapter->IsOutermostMainFrame());
@@ -133,7 +139,7 @@
       }));
 
   base::MockCallback<base::OnceClosure> ignored_destruction_callback;
-  EXPECT_CALL(*delegate, ProcessRequest(_, _))
+  EXPECT_CALL(*delegate, ProcessRequest)
       .WillOnce(
           Invoke([&](ChromeRequestAdapter* adapter, const GURL& redirect_url) {
             EXPECT_EQ(network::mojom::RequestDestination::kDocument,
@@ -194,7 +200,7 @@
 
   // Phase 3: Complete the request.
 
-  EXPECT_CALL(*delegate, ProcessResponse(_, _))
+  EXPECT_CALL(*delegate, ProcessResponse)
       .WillOnce(Invoke([&](ResponseAdapter* adapter, const GURL& redirect_url) {
         EXPECT_EQ(kTestRedirectURL, adapter->GetUrl());
         EXPECT_TRUE(adapter->IsOutermostMainFrame());
@@ -233,12 +239,12 @@
 
 TEST(ChromeSigninURLLoaderThrottleTest, InterceptSubFrame) {
   auto* delegate = new MockDelegate();
-  EXPECT_CALL(*delegate, ShouldInterceptNavigation(_)).WillOnce(Return(true));
+  EXPECT_CALL(*delegate, ShouldInterceptNavigation).WillOnce(Return(true));
   auto throttle = URLLoaderThrottle::MaybeCreate(base::WrapUnique(delegate),
                                                  NullWebContentsGetter());
   ASSERT_TRUE(throttle);
 
-  EXPECT_CALL(*delegate, ProcessRequest(_, _))
+  EXPECT_CALL(*delegate, ProcessRequest)
       .Times(2)
       .WillRepeatedly(
           [](ChromeRequestAdapter* adapter, const GURL& redirect_url) {
@@ -256,7 +262,7 @@
   throttle->WillStartRequest(&request, &defer);
   EXPECT_FALSE(defer);
 
-  EXPECT_CALL(*delegate, ProcessResponse(_, _))
+  EXPECT_CALL(*delegate, ProcessResponse)
       .Times(2)
       .WillRepeatedly(([](ResponseAdapter* adapter, const GURL& redirect_url) {
         EXPECT_FALSE(adapter->IsOutermostMainFrame());
@@ -282,4 +288,75 @@
   EXPECT_FALSE(defer);
 }
 
+// Regression test for https://crbug.com/441955793.
+TEST(ChromeSigninURLLoaderThrottleTest, InterceptNullHeaders) {
+  auto* delegate = new MockDelegate();
+  EXPECT_CALL(*delegate, ShouldInterceptNavigation).WillOnce(Return(true));
+  auto throttle = URLLoaderThrottle::MaybeCreate(base::WrapUnique(delegate),
+                                                 NullWebContentsGetter());
+  ASSERT_TRUE(throttle);
+
+  // Phase 1: Start a HTTPS request.
+
+  const GURL kTestURL("https://google.com/index.html");
+  const GURL kTestReferrer("https://chrome.com/referrer.html");
+  EXPECT_CALL(*delegate, ProcessRequest);
+
+  network::ResourceRequest request;
+  request.url = kTestURL;
+  request.referrer = kTestReferrer;
+  bool defer = false;
+  throttle->WillStartRequest(&request, &defer);
+  EXPECT_FALSE(defer);
+  testing::Mock::VerifyAndClearExpectations(delegate);
+
+  // Phase 2: Redirect the request to a header-less URL.
+
+  const GURL kTestRedirectURL("chrome-extension://abcd/index.html");
+  EXPECT_CALL(*delegate, ProcessResponse)
+      .WillOnce(Invoke([&](ResponseAdapter* adapter, const GURL& redirect_url) {
+        EXPECT_EQ(kTestURL, adapter->GetUrl());
+        EXPECT_FALSE(adapter->GetHeaders());
+        // This should not crash.
+        adapter->RemoveHeader("TestHeader");
+        EXPECT_EQ(kTestRedirectURL, redirect_url);
+      }));
+  EXPECT_CALL(*delegate, ProcessRequest);
+
+  net::RedirectInfo redirect_info;
+  redirect_info.new_url = kTestRedirectURL;
+  redirect_info.new_referrer = kTestURL.spec();
+
+  // Response head with null headers.
+  auto response_head = network::mojom::URLResponseHead::New();
+  std::vector<std::string> request_headers_to_remove;
+  net::HttpRequestHeaders modified_request_headers;
+  net::HttpRequestHeaders modified_cors_exempt_request_headers;
+  throttle->WillRedirectRequest(
+      &redirect_info, *response_head, &defer, &request_headers_to_remove,
+      &modified_request_headers, &modified_cors_exempt_request_headers);
+  EXPECT_FALSE(defer);
+
+  EXPECT_FALSE(response_head->headers);
+  testing::Mock::VerifyAndClearExpectations(delegate);
+
+  // Phase 3: Complete the request.
+
+  EXPECT_CALL(*delegate, ProcessResponse)
+      .WillOnce(Invoke([&](ResponseAdapter* adapter, const GURL& redirect_url) {
+        EXPECT_EQ(kTestRedirectURL, adapter->GetUrl());
+        EXPECT_FALSE(adapter->GetHeaders());
+        // This should not crash.
+        adapter->RemoveHeader("TestHeader");
+        EXPECT_EQ(GURL(), redirect_url);
+      }));
+
+  // Response head with null headers.
+  response_head = network::mojom::URLResponseHead::New();
+  throttle->WillProcessResponse(kTestRedirectURL, response_head.get(), &defer);
+
+  EXPECT_FALSE(response_head->headers);
+  EXPECT_FALSE(defer);
+}
+
 }  // namespace signin
diff --git a/chrome/browser/ui/tabs/BUILD.gn b/chrome/browser/ui/tabs/BUILD.gn
index b33a90c..8558f0c 100644
--- a/chrome/browser/ui/tabs/BUILD.gn
+++ b/chrome/browser/ui/tabs/BUILD.gn
@@ -549,7 +549,6 @@
       "//components/sync_sessions",
       "//components/tab_groups",
       "//components/tabs",
-      "//components/wallet/content/browser",
       "//components/wallet/core/common:features",
       "//net",
       "//ui/base/unowned_user_data",
@@ -567,6 +566,10 @@
     if (!is_android) {
       deps += [ "//chrome/browser/ui/views/zoom" ]
     }
+
+    if (is_win || is_mac || is_linux || is_chromeos) {
+      deps += [ "//chrome/browser/wallet" ]
+    }
   }
 
   # This is a separate component to avoid possible circular deps.
diff --git a/chrome/browser/ui/tabs/public/tab_features.h b/chrome/browser/ui/tabs/public/tab_features.h
index 22dfeb93..315c65c 100644
--- a/chrome/browser/ui/tabs/public/tab_features.h
+++ b/chrome/browser/ui/tabs/public/tab_features.h
@@ -114,6 +114,13 @@
 class TabContextualizationController;
 }  // namespace lens
 
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
+    BUILDFLAG(IS_CHROMEOS)
+namespace wallet {
+class ChromeWalletablePassClient;
+}  // namespace wallet
+#endif
+
 namespace tabs {
 
 class TabAlertController;
@@ -432,6 +439,10 @@
   std::unique_ptr<lens::TabContextualizationController>
       tab_contextualization_controller_;
 
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
+    BUILDFLAG(IS_CHROMEOS)
+  std::unique_ptr<wallet::ChromeWalletablePassClient> walletable_pass_client_;
+#endif
   // Must be the last member.
   base::WeakPtrFactory<TabFeatures> weak_factory_{this};
 };
diff --git a/chrome/browser/ui/tabs/tab_features.cc b/chrome/browser/ui/tabs/tab_features.cc
index db509e6..c8adbac 100644
--- a/chrome/browser/ui/tabs/tab_features.cc
+++ b/chrome/browser/ui/tabs/tab_features.cc
@@ -77,6 +77,10 @@
 #include "chrome/browser/ui/views/zoom/zoom_view_controller.h"
 #include "chrome/browser/ui/web_applications/pwa_install_page_action.h"
 #include "chrome/browser/ui/webui/webui_embedding_context.h"
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || \
+    BUILDFLAG(IS_CHROMEOS)
+#include "chrome/browser/wallet/chrome_walletable_pass_client.h"
+#endif
 #include "chrome/browser/web_applications/web_app_tab_helper.h"
 #include "chrome/browser/web_applications/web_app_utils.h"
 #include "chrome/common/chrome_features.h"
@@ -91,7 +95,6 @@
 #include "components/permissions/permission_indicators_tab_data.h"
 #include "components/security_interstitials/core/features.h"
 #include "components/tabs/public/tab_interface.h"
-#include "components/wallet/content/browser/content_walletable_pass_ingestion_controller.h"
 #include "components/wallet/core/common/wallet_features.h"
 #include "net/base/features.h"
 #include "ui/base/unowned_user_data/user_data_factory.h"
@@ -375,11 +378,8 @@
       std::make_unique<InactiveWindowMouseEventController>();
 
   if (base::FeatureList::IsEnabled(wallet::kWalletablePassDetection)) {
-    if (auto* opt_guide =
-            OptimizationGuideKeyedServiceFactory::GetForProfile(profile)) {
-      wallet::ContentWalletablePassIngestionController::CreateForWebContents(
-          tab.GetContents(), opt_guide);
-    }
+    walletable_pass_client_ =
+        std::make_unique<wallet::ChromeWalletablePassClient>(&tab);
   }
 #endif
 
diff --git a/chrome/browser/ui/views/frame/browser_view_layout.cc b/chrome/browser/ui/views/frame/browser_view_layout.cc
index ec24160..60c4c765 100644
--- a/chrome/browser/ui/views/frame/browser_view_layout.cc
+++ b/chrome/browser/ui/views/frame/browser_view_layout.cc
@@ -617,11 +617,13 @@
         top_container_separator_->SetBounds(
             available_bounds.x(), available_bounds.y(),
             available_bounds.width(), separator_height);
+        multi_contents_view_->SetShouldShowTopSeparator(false);
+      } else {
+        // If the loading bar will be shown, it's supposed to replace the
+        // separator.
+        multi_contents_view_->SetShouldShowTopSeparator(!loading_bar_);
+        SetViewVisibility(top_container_separator_, false);
       }
-      // If the loading bar will be shown, it's supposed to replace the
-      // separator.
-      multi_contents_view_->SetShouldShowTopSeparator(
-          !show_overlay_contents_separator && !loading_bar_);
     } else {
       separator_height = top_container_separator_->GetPreferredSize().height();
       SetViewVisibility(top_container_separator_, true);
diff --git a/chrome/browser/wallet/BUILD.gn b/chrome/browser/wallet/BUILD.gn
new file mode 100644
index 0000000..4a1ca9a
--- /dev/null
+++ b/chrome/browser/wallet/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+static_library("wallet") {
+  sources = [
+    "chrome_walletable_pass_client.cc",
+    "chrome_walletable_pass_client.h",
+  ]
+
+  deps = [
+    "//base",
+    "//chrome/browser/optimization_guide",
+    "//chrome/browser/profiles",
+    "//components/optimization_guide/core",
+    "//components/wallet/content/browser",
+    "//components/wallet/core/browser",
+  ]
+}
diff --git a/chrome/browser/wallet/DEPS b/chrome/browser/wallet/DEPS
new file mode 100644
index 0000000..c0118526
--- /dev/null
+++ b/chrome/browser/wallet/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+  # go/keep-sorted start
+  "+components/wallet/content/browser",
+  "+components/wallet/core/browser",
+  # go/keep-sorted end
+]
diff --git a/chrome/browser/wallet/chrome_walletable_pass_client.cc b/chrome/browser/wallet/chrome_walletable_pass_client.cc
new file mode 100644
index 0000000..a08af58
--- /dev/null
+++ b/chrome/browser/wallet/chrome_walletable_pass_client.cc
@@ -0,0 +1,37 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/wallet/chrome_walletable_pass_client.h"
+
+#include "base/check_deref.h"
+#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
+#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/optimization_guide/core/hints/optimization_guide_decider.h"
+#include "components/optimization_guide/core/optimization_guide_model_executor.h"
+#include "components/tabs/public/tab_interface.h"
+#include "content/public/browser/web_contents.h"
+
+namespace wallet {
+
+ChromeWalletablePassClient::ChromeWalletablePassClient(tabs::TabInterface* tab)
+    : tab_(CHECK_DEREF(tab)), controller_(tab_->GetContents(), this) {}
+
+ChromeWalletablePassClient::~ChromeWalletablePassClient() = default;
+
+optimization_guide::OptimizationGuideDecider*
+ChromeWalletablePassClient::GetOptimizationGuideDecider() {
+  Profile* profile =
+      Profile::FromBrowserContext(tab_->GetContents()->GetBrowserContext());
+  return OptimizationGuideKeyedServiceFactory::GetForProfile(profile);
+}
+
+optimization_guide::OptimizationGuideModelExecutor*
+ChromeWalletablePassClient::GetOptimizationGuideModelExecutor() {
+  Profile* profile =
+      Profile::FromBrowserContext(tab_->GetContents()->GetBrowserContext());
+  return OptimizationGuideKeyedServiceFactory::GetForProfile(profile);
+}
+
+}  // namespace wallet
diff --git a/chrome/browser/wallet/chrome_walletable_pass_client.h b/chrome/browser/wallet/chrome_walletable_pass_client.h
new file mode 100644
index 0000000..33deefc3
--- /dev/null
+++ b/chrome/browser/wallet/chrome_walletable_pass_client.h
@@ -0,0 +1,51 @@
+// Copyright 2025 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WALLET_CHROME_WALLETABLE_PASS_CLIENT_H_
+#define CHROME_BROWSER_WALLET_CHROME_WALLETABLE_PASS_CLIENT_H_
+
+#include "base/memory/raw_ref.h"
+#include "components/wallet/content/browser/content_walletable_pass_ingestion_controller.h"
+#include "components/wallet/core/browser/walletable_pass_client.h"
+
+namespace optimization_guide {
+class OptimizationGuideDecider;
+class OptimizationGuideModelExecutor;
+}  // namespace optimization_guide
+
+namespace tabs {
+class TabInterface;
+}  // namespace tabs
+
+namespace wallet {
+
+class ContentWalletablePassIngestionController;
+
+// The Chrome implementation of `wallet::WalletablePassClient`.
+//
+// This class bridges the core wallet component with browser services, such as
+// the Optimization Guide and UI interactions (e.g., showing a saving pass
+// bubble). Its lifecycle is scoped to a single tab and managed by
+// `TabFeatures`.
+class ChromeWalletablePassClient : public WalletablePassClient {
+ public:
+  explicit ChromeWalletablePassClient(tabs::TabInterface* tab);
+
+  ~ChromeWalletablePassClient() override;
+
+  // WalleablePassClient implementation.
+  optimization_guide::OptimizationGuideDecider* GetOptimizationGuideDecider()
+      override;
+  optimization_guide::OptimizationGuideModelExecutor*
+  GetOptimizationGuideModelExecutor() override;
+
+ private:
+  const raw_ref<tabs::TabInterface> tab_;
+
+  ContentWalletablePassIngestionController controller_;
+};
+
+}  // namespace wallet
+
+#endif  // CHROME_BROWSER_WALLET_CHROME_WALLETABLE_PASS_CLIENT_H_
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index 4a77129..128e34f2 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1757180102-166c06c7ee4ce6104f6e8bb226d3019ce4116d5f-5b31578217d3cdd1df34c58236011f941a5ddb5d.profdata
+chrome-android32-main-1757246363-2880d1d14437a119c991e1cc7a326bac35208bfa-aaccc0c9b286ebc29b52814c35ccd31543414a4a.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index a9c6d23..ebae5cec 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1757192256-65f3202086b24a61257f2c80fba7766abed2ba81-75ef9c359dea932eab72da60e5f3b9d3ad850c83.profdata
+chrome-android64-main-1757283738-16e09bca18c213a5430517a2a3d270f8e88b2556-81273a91e6978b2f8d28dae019823085961ce80b.profdata
diff --git a/chrome/build/android-desktop-x64.pgo.txt b/chrome/build/android-desktop-x64.pgo.txt
index a56a246b..bb149ff 100644
--- a/chrome/build/android-desktop-x64.pgo.txt
+++ b/chrome/build/android-desktop-x64.pgo.txt
@@ -1 +1 @@
-chrome-android-desktop-x64-main-1757180102-c202664934b1ec4742de06b04c9e16e25ca45e34-5b31578217d3cdd1df34c58236011f941a5ddb5d.profdata
+chrome-android-desktop-x64-main-1757287645-ff4b3752328d1fe1263c552dfa4a68c1ff258572-f77f925a2c6b576b533f03c8e7427a87d8a205ce.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index fa335402..1103562 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1757180102-bbbf2fa8b50b1b2455ab2e28e1da1c5c30074c77-5b31578217d3cdd1df34c58236011f941a5ddb5d.profdata
+chrome-mac-main-1757267985-a242d9feb4b25f4dbd95970c70396aeaf34b4fe3-b477c9f0e43efecb7c6b9621b0d0735004a58688.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index c275b2c..54f6c177 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1757170509-12a8214cf0824f098f6e3a2ef5998f5e6e178ef9-9bd75e0392503aed07d8dc1a0d1f696d46eb04ff.profdata
+chrome-win32-main-1757267985-68887a69027a37dae62d932a9f85d78c79201a3a-b477c9f0e43efecb7c6b9621b0d0735004a58688.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 879f785..e6092d3 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1757180102-17631aa2f1c48bc44cebdd68cc8c7ae09985dea3-5b31578217d3cdd1df34c58236011f941a5ddb5d.profdata
+chrome-win64-main-1757267985-368bbc529a16ac1f96b4e6429f595488dc90740f-b477c9f0e43efecb7c6b9621b0d0735004a58688.profdata
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 7fc05a7..263d569 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-16410.0.0-1071539
\ No newline at end of file
+16410.0.0-1071545
\ No newline at end of file
diff --git a/chromeos/ash/components/account_manager/account_manager_facade_factory.cc b/chromeos/ash/components/account_manager/account_manager_facade_factory.cc
index 6a8a7945..e1a1ae3f 100644
--- a/chromeos/ash/components/account_manager/account_manager_facade_factory.cc
+++ b/chromeos/ash/components/account_manager/account_manager_facade_factory.cc
@@ -4,76 +4,15 @@
 
 #include "chromeos/ash/components/account_manager/account_manager_facade_factory.h"
 
-#include <limits>
-#include <map>
-#include <memory>
-#include <utility>
+#include <string>
 
-#include "base/no_destructor.h"
 #include "chromeos/ash/components/account_manager/account_manager_factory.h"
-#include "components/account_manager_core/account_manager_facade_impl.h"
-#include "components/account_manager_core/chromeos/account_manager.h"
-#include "components/account_manager_core/chromeos/account_manager_mojo_service.h"
 
 namespace ash {
-namespace {
-
-crosapi::AccountManagerMojoService* GetAccountManagerMojoService(
-    const std::string& profile_path) {
-  crosapi::AccountManagerMojoService* account_manager_mojo_service =
-      ash::AccountManagerFactory::Get()->GetAccountManagerMojoService(
-          profile_path);
-  DCHECK(account_manager_mojo_service);
-
-  return account_manager_mojo_service;
-}
-
-// Map from |profile_path| to AccountManagerFacade.
-std::map<std::string,
-         std::unique_ptr<account_manager::AccountManagerFacadeImpl>>&
-GetMap() {
-  static base::NoDestructor<std::map<
-      std::string, std::unique_ptr<account_manager::AccountManagerFacadeImpl>>>
-      account_manager_facade_map;
-  return *account_manager_facade_map.get();
-}
-
-}  // namespace
-
 account_manager::AccountManagerFacade* GetAccountManagerFacade(
     const std::string& profile_path) {
-  auto& account_manager_facade_map = GetMap();
-
-  auto it = account_manager_facade_map.find(profile_path);
-  if (it == account_manager_facade_map.end()) {
-    mojo::Remote<crosapi::mojom::AccountManager> remote;
-    GetAccountManagerMojoService(profile_path)
-        ->BindReceiver(remote.BindNewPipeAndPassReceiver());
-
-    // This is set to a sentinel value which will pass all minimum version
-    // checks.
-    // Calls within Ash are in the same process and don't need to check version
-    // compatibility with itself.
-    constexpr uint32_t remote_version = std::numeric_limits<uint32_t>::max();
-    // TODO(crbug.com/40800999): to avoid incorrect usage, pass a nullptr
-    // `AccountManager` when this is not running in a test.
-    account_manager::AccountManager* account_manager_for_tests =
-        ash::AccountManagerFactory::Get()->GetAccountManager(profile_path);
-    auto account_manager_facade =
-        std::make_unique<account_manager::AccountManagerFacadeImpl>(
-            std::move(remote), remote_version,
-            account_manager_for_tests->GetWeakPtr());
-    it = account_manager_facade_map
-             .emplace(profile_path, std::move(account_manager_facade))
-             .first;
-  }
-
-  return it->second.get();
-}
-
-void DeleteAccountManagerFacadeInstanceForTesting(
-    const std::string& profile_path) {
-  GetMap().erase(profile_path);
+  return ash::AccountManagerFactory::Get()->GetAccountManagerFacade(
+      profile_path);
 }
 
 }  // namespace ash
diff --git a/chromeos/ash/components/account_manager/account_manager_facade_factory.h b/chromeos/ash/components/account_manager/account_manager_facade_factory.h
index f022d215..0d9196d3 100644
--- a/chromeos/ash/components/account_manager/account_manager_facade_factory.h
+++ b/chromeos/ash/components/account_manager/account_manager_facade_factory.h
@@ -26,13 +26,6 @@
 account_manager::AccountManagerFacade* GetAccountManagerFacade(
     const std::string& profile_path);
 
-// Deletes existing instances of AccountManagerFacade.
-// TODO(crbug.com/421058020): Integrate `GetAccountManagerFacade` into
-// `AccountManagerFactory` and remove this.
-COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_ACCOUNT_MANAGER)
-void DeleteAccountManagerFacadeInstanceForTesting(
-    const std::string& profile_path);
-
 }  // namespace ash
 
 #endif  // CHROMEOS_ASH_COMPONENTS_ACCOUNT_MANAGER_ACCOUNT_MANAGER_FACADE_FACTORY_H_
diff --git a/chromeos/ash/components/account_manager/account_manager_factory.cc b/chromeos/ash/components/account_manager/account_manager_factory.cc
index 0da7115..fdc6005 100644
--- a/chromeos/ash/components/account_manager/account_manager_factory.cc
+++ b/chromeos/ash/components/account_manager/account_manager_factory.cc
@@ -7,8 +7,11 @@
 #include <string>
 #include <utility>
 
+#include "base/callback_list.h"
 #include "base/check.h"
 #include "base/check_op.h"
+#include "base/functional/callback.h"
+#include "components/account_manager_core/account_manager_facade_impl.h"
 #include "components/account_manager_core/chromeos/account_manager.h"
 #include "components/account_manager_core/chromeos/account_manager_mojo_service.h"
 
@@ -22,6 +25,8 @@
   g_instance = this;
 }
 AccountManagerFactory::~AccountManagerFactory() {
+  on_destruction_callbacks_.Notify();
+
   CHECK_EQ(g_instance, this);
   g_instance = nullptr;
 }
@@ -47,12 +52,28 @@
       .account_manager_mojo_service.get();
 }
 
+account_manager::AccountManagerFacade*
+AccountManagerFactory::GetAccountManagerFacade(
+    const std::string& profile_path) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  return GetAccountManagerHolder(profile_path).account_manager_facade.get();
+}
+
+base::CallbackListSubscription AccountManagerFactory::AddOnDestructionCallback(
+    base::OnceClosure callback) {
+  return on_destruction_callbacks_.Add(std::move(callback));
+}
+
 AccountManagerFactory::AccountManagerHolder::AccountManagerHolder(
     std::unique_ptr<account_manager::AccountManager> account_manager,
     std::unique_ptr<crosapi::AccountManagerMojoService>
-        account_manager_mojo_service)
+        account_manager_mojo_service,
+    std::unique_ptr<account_manager::AccountManagerFacade>
+        account_manager_facade)
     : account_manager(std::move(account_manager)),
-      account_manager_mojo_service(std::move(account_manager_mojo_service)) {}
+      account_manager_mojo_service(std::move(account_manager_mojo_service)),
+      account_manager_facade(std::move(account_manager_facade)) {}
 
 AccountManagerFactory::AccountManagerHolder::~AccountManagerHolder() = default;
 
@@ -65,11 +86,30 @@
     auto account_manager_mojo_service =
         std::make_unique<crosapi::AccountManagerMojoService>(
             account_manager.get());
+
+    mojo::Remote<crosapi::mojom::AccountManager> remote;
+    account_manager_mojo_service->BindReceiver(
+        remote.BindNewPipeAndPassReceiver());
+
+    // This is set to a sentinel value which will pass all minimum version
+    // checks.
+    // Calls within Ash are in the same process and don't need to check version
+    // compatibility with itself.
+    constexpr uint32_t remote_version = std::numeric_limits<uint32_t>::max();
+    // TODO(crbug.com/40800999): to avoid incorrect usage, pass a nullptr
+    // `AccountManager` when this is not running in a test.
+    base::WeakPtr<account_manager::AccountManager> account_manager_for_tests =
+        account_manager->GetWeakPtr();
+    auto account_manager_facade =
+        std::make_unique<account_manager::AccountManagerFacadeImpl>(
+            std::move(remote), remote_version, account_manager_for_tests);
+
     it = account_managers_
              .emplace(
                  std::piecewise_construct, std::forward_as_tuple(profile_path),
                  std::forward_as_tuple(std::move(account_manager),
-                                       std::move(account_manager_mojo_service)))
+                                       std::move(account_manager_mojo_service),
+                                       std::move(account_manager_facade)))
              .first;
   }
   return it->second;
diff --git a/chromeos/ash/components/account_manager/account_manager_factory.h b/chromeos/ash/components/account_manager/account_manager_factory.h
index 9320f66..5313dcf 100644
--- a/chromeos/ash/components/account_manager/account_manager_factory.h
+++ b/chromeos/ash/components/account_manager/account_manager_factory.h
@@ -9,11 +9,14 @@
 #include <string>
 #include <unordered_map>
 
+#include "base/callback_list.h"
 #include "base/component_export.h"
+#include "base/functional/callback.h"
 #include "base/sequence_checker.h"
 
 namespace account_manager {
 class AccountManager;
+class AccountManagerFacade;
 }  // namespace account_manager
 
 namespace crosapi {
@@ -51,12 +54,23 @@
   crosapi::AccountManagerMojoService* GetAccountManagerMojoService(
       const std::string& profile_path);
 
+  // Returns the `AccountManagerFacade` corresponding to the given
+  // `profile_path`.
+  account_manager::AccountManagerFacade* GetAccountManagerFacade(
+      const std::string& profile_path);
+
+  // Register a callback that will be called on ~AccountManagerFactory().
+  base::CallbackListSubscription AddOnDestructionCallback(
+      base::OnceClosure callback);
+
  private:
   struct AccountManagerHolder {
     AccountManagerHolder(
         std::unique_ptr<account_manager::AccountManager> account_manager,
         std::unique_ptr<crosapi::AccountManagerMojoService>
-            account_manager_mojo_service);
+            account_manager_mojo_service,
+        std::unique_ptr<account_manager::AccountManagerFacade>
+            account_manager_facade);
     AccountManagerHolder(const AccountManagerHolder&) = delete;
     AccountManagerHolder& operator=(const AccountManagerHolder&) = delete;
     ~AccountManagerHolder();
@@ -64,6 +78,8 @@
     const std::unique_ptr<account_manager::AccountManager> account_manager;
     const std::unique_ptr<crosapi::AccountManagerMojoService>
         account_manager_mojo_service;
+    const std::unique_ptr<account_manager::AccountManagerFacade>
+        account_manager_facade;
   };
 
   const AccountManagerHolder& GetAccountManagerHolder(
@@ -73,6 +89,8 @@
   // Account Managers and AccountManagerMojoService objects.
   std::unordered_map<std::string, AccountManagerHolder> account_managers_;
 
+  base::OnceCallbackList<void()> on_destruction_callbacks_;
+
   SEQUENCE_CHECKER(sequence_checker_);
 };
 
diff --git a/chromeos/ash/components/emoji/gif_tenor_api_fetcher.cc b/chromeos/ash/components/emoji/gif_tenor_api_fetcher.cc
index f7c6e24..fe226b25 100644
--- a/chromeos/ash/components/emoji/gif_tenor_api_fetcher.cc
+++ b/chromeos/ash/components/emoji/gif_tenor_api_fetcher.cc
@@ -105,13 +105,13 @@
     const net::NetworkTrafficAnnotationTag& annotation_tag) {
   return std::make_unique<EndpointFetcher>(
       /*url_loader_factory=*/std::move(url_loader_factory),
-      /*url=*/url,
-      /*content_type=*/kHttpContentType,
-      /*timeout=*/kTimeout,
-      /*post_data=*/"",
-      /*headers=*/std::vector<std::string>(),
-      /*cors_exempt_headers=*/std::vector<std::string>(), ash::GetChannel(),
+      /*identity_manager=*/nullptr,
       EndpointFetcher::RequestParams::Builder(kHttpMethod, annotation_tag)
+          .SetAuthType(endpoint_fetcher::CHROME_API_KEY)
+          .SetChannel(ash::GetChannel())
+          .SetContentType(kHttpContentType)
+          .SetTimeout(kTimeout)
+          .SetUrl(url)
           .Build());
 }
 
diff --git a/chromeos/crosapi/mojom/clipboard_history.mojom b/chromeos/crosapi/mojom/clipboard_history.mojom
index 57050bb1..6e2a94e1 100644
--- a/chromeos/crosapi/mojom/clipboard_history.mojom
+++ b/chromeos/crosapi/mojom/clipboard_history.mojom
@@ -28,7 +28,7 @@
   [Default] kUnknown,
   // Deprecated: Shown by a toast.
   [MinVersion=1] kToast,
-  // Shown by long-pressing Ctrl+V.
+  // Deprecated: Shown by long-pressing Ctrl+V.
   [MinVersion=2] kControlVLongpress,
   // Shown from the submenu embedded in a render view's context memu.
   [MinVersion=3] kRenderViewContextSubmenu,
diff --git a/clank b/clank
index 5e36fab..73faa49 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 5e36fab7a4bfa7d98ad3a9ba760f39af8c2c12eb
+Subproject commit 73faa4938c6a3d50fccccdcdba2813f0f74d5c01
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json
index 523e34c..53f1c77 100644
--- a/components/certificate_transparency/data/log_list.json
+++ b/components/certificate_transparency/data/log_list.json
@@ -1,6 +1,6 @@
 {
-  "version": "66.2",
-  "log_list_timestamp": "2025-09-06T12:53:29Z",
+  "version": "66.3",
+  "log_list_timestamp": "2025-09-07T12:54:02Z",
   "operators": [
     {
       "name": "Google",
diff --git a/components/signin/internal/identity_manager/BUILD.gn b/components/signin/internal/identity_manager/BUILD.gn
index a4ce0d8..2f17b8c 100644
--- a/components/signin/internal/identity_manager/BUILD.gn
+++ b/components/signin/internal/identity_manager/BUILD.gn
@@ -112,6 +112,7 @@
     ]
     deps += [
       "//ash/constants",
+      "//chromeos/ash/components/account_manager",
       "//components/account_manager_core",
     ]
   }
@@ -203,6 +204,7 @@
 
     deps += [
       "//ash/constants",
+      "//chromeos/ash/components/account_manager",
       "//components/account_manager_core:test_support",
     ]
   }
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc
index 45929df4..3082464 100644
--- a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc
+++ b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.cc
@@ -8,10 +8,12 @@
 #include <utility>
 #include <vector>
 
+#include "base/check_deref.h"
 #include "base/containers/contains.h"
 #include "base/functional/bind.h"
 #include "base/logging.h"
 #include "build/build_config.h"
+#include "chromeos/ash/components/account_manager/account_manager_factory.h"
 #include "components/account_manager_core/account.h"
 #include "components/signin/internal/identity_manager/account_tracker_service.h"
 #include "components/signin/public/base/signin_client.h"
@@ -138,6 +140,23 @@
       is_regular_profile_(is_regular_profile),
       weak_factory_(this) {
   network_connection_tracker_->AddNetworkConnectionObserver(this);
+
+  // In production, AccountManagerFactory should always outlive `this`, but in
+  // tests, it may be destroyed before `this` and `account_manager_facade_` may
+  // dangle. So, observe AccountManagerFactory and reset the raw_ptr on its
+  // destruction.
+  // TODO(crbug.com/421058020): Fix tests to properly mimic the production
+  // construction/destruction order, and remove the observer.
+  account_manager_factory_cb_subscription_ =
+      CHECK_DEREF(ash::AccountManagerFactory::Get())
+          .AddOnDestructionCallback(base::BindOnce(
+              [](base::WeakPtr<ProfileOAuth2TokenServiceDelegateChromeOS>
+                     self) {
+                if (self) {
+                  self->account_manager_facade_ = nullptr;
+                }
+              },
+              weak_factory_.GetWeakPtr()));
 }
 
 ProfileOAuth2TokenServiceDelegateChromeOS::
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.h b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.h
index 660d4cd..a9cedd62 100644
--- a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.h
+++ b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos.h
@@ -11,9 +11,11 @@
 #include <string>
 #include <vector>
 
+#include "base/callback_list.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/scoped_observation.h"
 #include "base/sequence_checker.h"
 #include "components/account_manager_core/account.h"
 #include "components/account_manager_core/account_manager_facade.h"
@@ -100,7 +102,8 @@
   const raw_ptr<AccountTrackerService, DanglingUntriaged>
       account_tracker_service_;
   const raw_ptr<network::NetworkConnectionTracker> network_connection_tracker_;
-  const raw_ptr<account_manager::AccountManagerFacade> account_manager_facade_;
+  raw_ptr<account_manager::AccountManagerFacade> account_manager_facade_ =
+      nullptr;
 
   // When the delegate receives an account from either `GetAccounts` or
   // `OnAccountUpserted`, this account is first added to pending accounts, until
@@ -116,6 +119,8 @@
   // Is |this| attached to a regular (non-Signin && non-LockScreen) Profile.
   const bool is_regular_profile_;
 
+  base::CallbackListSubscription account_manager_factory_cb_subscription_;
+
   SEQUENCE_CHECKER(sequence_checker_);
   base::WeakPtrFactory<ProfileOAuth2TokenServiceDelegateChromeOS> weak_factory_;
 };
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc
index 2a43c5ec..f14e7ba 100644
--- a/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc
+++ b/components/signin/internal/identity_manager/profile_oauth2_token_service_delegate_chromeos_unittest.cc
@@ -20,6 +20,7 @@
 #include "base/scoped_observation.h"
 #include "base/test/gmock_callback_support.h"
 #include "base/test/task_environment.h"
+#include "chromeos/ash/components/account_manager/account_manager_factory.h"
 #include "components/account_manager_core/account.h"
 #include "components/account_manager_core/account_manager_facade.h"
 #include "components/account_manager_core/account_manager_facade_impl.h"
@@ -168,6 +169,36 @@
       token_service_observation_{this};
 };
 
+AccountManager::DelayNetworkCallRunner ImmediateCallbackRunner() {
+  return base::BindRepeating(
+      [](base::OnceClosure closure) { std::move(closure).Run(); });
+}
+
+AccountInfo CreateAccountInfoTestFixture(
+    const AccountTrackerService& account_tracker_service,
+    const GaiaId& gaia_id,
+    const std::string& email) {
+  AccountInfo account_info;
+
+  account_info.gaia = gaia_id;
+  account_info.email = email;
+  account_info.full_name = "name";
+  account_info.given_name = "name";
+  account_info.hosted_domain = "example.com";
+  account_info.locale = "en";
+  account_info.picture_url = "https://example.com";
+  account_info.account_id = account_tracker_service.PickAccountIdForAccount(
+      account_info.gaia, account_info.email);
+  AccountCapabilitiesTestMutator(&account_info.capabilities)
+      .set_is_subject_to_enterprise_features(true);
+
+  // Cannot use |ASSERT_TRUE| due to a |void| return type in an |ASSERT_TRUE|
+  // branch.
+  EXPECT_TRUE(account_info.IsValid());
+
+  return account_info;
+}
+
 }  // namespace
 
 class ProfileOAuth2TokenServiceDelegateChromeOSTest : public testing::Test {
@@ -183,26 +214,29 @@
 
  protected:
   void SetUp() override {
-    ASSERT_TRUE(tmp_dir_.CreateUniqueTempDir());
+    ASSERT_TRUE(profile_dir_.CreateUniqueTempDir());
     AccountTrackerService::RegisterPrefs(pref_service_.registry());
     AccountManager::RegisterPrefs(pref_service_.registry());
 
     client_ = std::make_unique<TestSigninClient>(&pref_service_);
 
-    account_manager_.Initialize(tmp_dir_.GetPath(),
-                                client_->GetURLLoaderFactory(),
-                                immediate_callback_runner_);
-    account_manager_.SetPrefService(&pref_service_);
-    task_environment_.RunUntilIdle();
+    account_manager_ = ash::AccountManagerFactory::Get()->GetAccountManager(
+        profile_dir_.GetPath().value());
+    account_manager_->Initialize(profile_dir_.GetPath(),
+                                 client_->GetURLLoaderFactory(),
+                                 ImmediateCallbackRunner());
+    account_manager_->SetPrefService(&pref_service_);
 
-    account_manager_mojo_service_ =
-        std::make_unique<crosapi::AccountManagerMojoService>(&account_manager_);
     account_manager_facade_ =
-        CreateAccountManagerFacade(account_manager_mojo_service_.get());
+        ash::AccountManagerFactory::Get()->GetAccountManagerFacade(
+            profile_dir_.GetPath().value());
+
+    task_environment_.RunUntilIdle();
 
     account_tracker_service_.Initialize(&pref_service_, base::FilePath());
 
-    account_info_ = CreateAccountInfoTestFixture(kGaiaId, kUserEmail);
+    account_info_ = CreateAccountInfoTestFixture(account_tracker_service_,
+                                                 kGaiaId, kUserEmail);
     account_tracker_service_.SeedAccountInfo(account_info_);
     ResetProfileOAuth2TokenServiceDelegateChromeOS();
   }
@@ -225,29 +259,6 @@
     return account_manager::AccountKey::FromGaiaId(account_info_.gaia);
   }
 
-  AccountInfo CreateAccountInfoTestFixture(const GaiaId& gaia_id,
-                                           const std::string& email) {
-    AccountInfo account_info;
-
-    account_info.gaia = gaia_id;
-    account_info.email = email;
-    account_info.full_name = "name";
-    account_info.given_name = "name";
-    account_info.hosted_domain = "example.com";
-    account_info.locale = "en";
-    account_info.picture_url = "https://example.com";
-    account_info.account_id = account_tracker_service_.PickAccountIdForAccount(
-        account_info.gaia, account_info.email);
-    AccountCapabilitiesTestMutator(&account_info.capabilities)
-        .set_is_subject_to_enterprise_features(true);
-
-    // Cannot use |ASSERT_TRUE| due to a |void| return type in an |ASSERT_TRUE|
-    // branch.
-    EXPECT_TRUE(account_info.IsValid());
-
-    return account_info;
-  }
-
   void AddSuccessfulOAuthTokenResponse() {
     client_->GetTestURLLoaderFactory()->AddResponse(
         GaiaUrls::GetInstance()->oauth2_token_url().spec(),
@@ -277,7 +288,7 @@
     base::RunLoop run_loop;
     EXPECT_CALL(observer, OnRefreshTokenAvailable(testing::_))
         .WillOnce(base::test::RunClosure(run_loop.QuitClosure()));
-    account_manager_.UpsertAccount(account_key, raw_email, token);
+    account_manager_->UpsertAccount(account_key, raw_email, token);
     run_loop.Run();
   }
 
@@ -288,36 +299,21 @@
     base::RunLoop run_loop;
     EXPECT_CALL(observer, OnRefreshTokenRevoked(testing::_))
         .WillOnce(base::test::RunClosure(run_loop.QuitClosure()));
-    account_manager_.RemoveAccount(account_key);
+    account_manager_->RemoveAccount(account_key);
     run_loop.Run();
   }
 
-  std::unique_ptr<AccountManagerFacade> CreateAccountManagerFacade(
-      crosapi::AccountManagerMojoService* account_manager_mojo_service) {
-    DCHECK(account_manager_mojo_service);
-    mojo::Remote<crosapi::mojom::AccountManager> remote;
-    account_manager_mojo_service->BindReceiver(
-        remote.BindNewPipeAndPassReceiver());
-    return std::make_unique<account_manager::AccountManagerFacadeImpl>(
-        std::move(remote),
-        /*remote_version=*/std::numeric_limits<uint32_t>::max(),
-        /*account_manager_for_tests=*/nullptr);
-  }
-
   base::test::TaskEnvironment task_environment_;
+  ash::AccountManagerFactory account_manager_factory_;
 
-  base::ScopedTempDir tmp_dir_;
+  base::ScopedTempDir profile_dir_;
   AccountInfo account_info_;
   AccountTrackerService account_tracker_service_;
-  AccountManager account_manager_;
-  std::unique_ptr<crosapi::AccountManagerMojoService>
-      account_manager_mojo_service_;
-  std::unique_ptr<account_manager::AccountManagerFacade>
-      account_manager_facade_;
+
+  raw_ptr<AccountManager> account_manager_ = nullptr;
+  raw_ptr<account_manager::AccountManagerFacade> account_manager_facade_ =
+      nullptr;
   std::unique_ptr<signin::ProfileOAuth2TokenServiceDelegateChromeOS> delegate_;
-  AccountManager::DelayNetworkCallRunner immediate_callback_runner_ =
-      base::BindRepeating(
-          [](base::OnceClosure closure) -> void { std::move(closure).Run(); });
   sync_preferences::TestingPrefServiceSyncable pref_service_;
   std::unique_ptr<TestSigninClient> client_;
 };
@@ -410,7 +406,7 @@
     // after adding a new account on ChromeOS.
     EXPECT_CALL(observer, OnAuthErrorChanged);
     EXPECT_CALL(observer, OnEndBatchChanges);
-    account_manager_.UpsertAccount(gaia_account_key(), kUserEmail, kGaiaToken);
+    account_manager_->UpsertAccount(gaia_account_key(), kUserEmail, kGaiaToken);
     upsert_run_loop.Run();
     testing::Mock::VerifyAndClearExpectations(&observer);
   }
@@ -424,7 +420,7 @@
     // changing its error state.
     EXPECT_CALL(observer, OnAuthErrorChanged);
     EXPECT_CALL(observer, OnEndBatchChanges);
-    account_manager_.UpdateToken(gaia_account_key(), "new-gaia-token");
+    account_manager_->UpdateToken(gaia_account_key(), "new-gaia-token");
     update_run_loop.Run();
     testing::Mock::VerifyAndClearExpectations(&observer);
   }
@@ -543,8 +539,8 @@
   // UpsertAccountAndWaitForCompletion can't be used here, as it uses an
   // observer to wait for completion. Observers aren't called in this flow, so
   // UpsertAccountAndWaitForCompletion would hang here.
-  account_manager_.UpsertAccount(gaia_account_key(), account_info_.email,
-                                 kGaiaToken);
+  account_manager_->UpsertAccount(gaia_account_key(), account_info_.email,
+                                  kGaiaToken);
   task_environment_.RunUntilIdle();
 
   EXPECT_TRUE(observer.account_ids_.empty());
@@ -562,64 +558,6 @@
   EXPECT_EQ(account_info_.account_id, observer.batch_change_records_[0][0]);
 }
 
-// If observers register themselves with |ProfileOAuth2TokenServiceDelegate|
-// before |AccountManager| has been initialized, they should receive all the
-// accounts stored in |AccountManager| in a single batch.
-TEST_F(ProfileOAuth2TokenServiceDelegateChromeOSTest,
-       BatchChangeObserversAreNotifiedOncePerBatch) {
-  // Setup
-  AccountInfo account1 = CreateAccountInfoTestFixture(
-      GaiaId("1"), "user1@example.com" /* email */);
-  AccountInfo account2 = CreateAccountInfoTestFixture(
-      GaiaId("2"), "user2@example.com" /* email */);
-
-  account_tracker_service_.SeedAccountInfo(account1);
-  account_tracker_service_.SeedAccountInfo(account2);
-  account_manager_.UpsertAccount(
-      account_manager::AccountKey::FromGaiaId(account1.gaia),
-      "user1@example.com", "token1");
-  account_manager_.UpsertAccount(
-      account_manager::AccountKey::FromGaiaId(account2.gaia),
-      "user2@example.com", "token2");
-  task_environment_.RunUntilIdle();
-
-  AccountManager account_manager;
-  // AccountManager will not be fully initialized until
-  // |task_environment_.RunUntilIdle()| is called.
-  account_manager.Initialize(tmp_dir_.GetPath(), client_->GetURLLoaderFactory(),
-                             immediate_callback_runner_);
-  account_manager.SetPrefService(&pref_service_);
-
-  auto account_manager_mojo_service =
-      std::make_unique<crosapi::AccountManagerMojoService>(&account_manager);
-  auto account_manager_facade =
-      CreateAccountManagerFacade(account_manager_mojo_service.get());
-
-  // Register callbacks before AccountManager has been fully initialized.
-  auto delegate =
-      std::make_unique<signin::ProfileOAuth2TokenServiceDelegateChromeOS>(
-          client_.get(), &account_tracker_service_,
-          network::TestNetworkConnectionTracker::GetInstance(),
-          account_manager_facade.get(),
-          /*is_regular_profile=*/true);
-  delegate->LoadCredentials(account1.account_id /* primary_account_id */);
-  TestOAuth2TokenServiceObserver observer(delegate.get());
-  // Wait until AccountManager is fully initialized.
-  task_environment_.RunUntilIdle();
-
-  // Tests
-
-  // The observer should receive at least one batch change callback: batch of
-  // all accounts stored in AccountManager: because of the delegate's
-  // invocation of |AccountManagerFacade::GetAccounts| in |LoadCredentials|.
-  EXPECT_FALSE(observer.batch_change_records_.empty());
-  const std::vector<CoreAccountId>& first_batch =
-      observer.batch_change_records_[0];
-  EXPECT_EQ(2UL, first_batch.size());
-  EXPECT_TRUE(base::Contains(first_batch, account1.account_id));
-  EXPECT_TRUE(base::Contains(first_batch, account2.account_id));
-}
-
 TEST_F(ProfileOAuth2TokenServiceDelegateChromeOSTest,
        GetAccountsReturnsGaiaAccounts) {
   EXPECT_TRUE(delegate_->GetAccounts().empty());
@@ -660,7 +598,7 @@
   account_manager::AccountKey gaia_account_key2 =
       account_manager::AccountKey::FromGaiaId(GaiaId("random-gaia-id"));
   account_tracker_service_.SeedAccountInfo(CreateAccountInfoTestFixture(
-      GaiaId(gaia_account_key2.id()), kUserEmail2));
+      account_tracker_service_, GaiaId(gaia_account_key2.id()), kUserEmail2));
   UpsertAccountAndWaitForCompletion(gaia_account_key2, kUserEmail2,
                                     AccountManager::kInvalidToken);
 
@@ -709,9 +647,9 @@
   // `UpsertAccount` will asynchronously send a notification through
   // `AccountManagerFacade`, so `RemoveAccount` should remove the account before
   // `ProfileOAuth2TokenServiceDelegateChromeOS` can add this account.
-  account_manager_.UpsertAccount(gaia_account_key(), account_info_.email,
-                                 kGaiaToken);
-  account_manager_.RemoveAccount(gaia_account_key());
+  account_manager_->UpsertAccount(gaia_account_key(), account_info_.email,
+                                  kGaiaToken);
+  account_manager_->RemoveAccount(gaia_account_key());
 
   task_environment_.RunUntilIdle();
 
@@ -733,9 +671,9 @@
   EXPECT_CALL(observer, OnRefreshTokenRevoked(account_info_.account_id))
       .WillOnce(base::test::RunClosure(run_loop.QuitClosure()));
 
-  account_manager_.UpsertAccount(gaia_account_key(), account_info_.email,
-                                 AccountManager::kInvalidToken);
-  account_manager_.RemoveAccount(gaia_account_key());
+  account_manager_->UpsertAccount(gaia_account_key(), account_info_.email,
+                                  AccountManager::kInvalidToken);
+  account_manager_->RemoveAccount(gaia_account_key());
 
   run_loop.Run();
 
@@ -885,3 +823,101 @@
   EXPECT_EQ(account_info_.account_id, observer.last_err_account_id_);
   EXPECT_EQ(error, observer.last_err_);
 }
+
+class ProfileOAuth2TokenServiceDelegateChromeOSObserverTest
+    : public testing::Test {
+ public:
+  void SetUp() override {
+    account_manager_factory_ = std::make_unique<ash::AccountManagerFactory>();
+
+    ASSERT_TRUE(profile_dir_.CreateUniqueTempDir());
+
+    AccountTrackerService::RegisterPrefs(pref_service_.registry());
+    AccountManager::RegisterPrefs(pref_service_.registry());
+
+    client_ = std::make_unique<TestSigninClient>(ProfilePrefs());
+    account_tracker_service_.Initialize(ProfilePrefs(), base::FilePath());
+  }
+
+ protected:
+  PrefService* ProfilePrefs() { return &pref_service_; }
+  base::FilePath ProfilePath() { return profile_dir_.GetPath(); }
+
+  base::test::TaskEnvironment task_environment_;
+  std::unique_ptr<ash::AccountManagerFactory> account_manager_factory_;
+
+  base::ScopedTempDir profile_dir_;
+  sync_preferences::TestingPrefServiceSyncable pref_service_;
+  std::unique_ptr<TestSigninClient> client_;
+  AccountTrackerService account_tracker_service_;
+};
+
+// If observers register themselves with |ProfileOAuth2TokenServiceDelegate|
+// before |AccountManager| has been initialized, they should receive all the
+// accounts stored in |AccountManager| in a single batch.
+TEST_F(ProfileOAuth2TokenServiceDelegateChromeOSObserverTest,
+       BatchChangeObserversAreNotifiedOncePerBatch) {
+  // Setup
+  AccountInfo account1 = CreateAccountInfoTestFixture(
+      account_tracker_service_, GaiaId("1"), "user1@example.com");
+  AccountInfo account2 = CreateAccountInfoTestFixture(
+      account_tracker_service_, GaiaId("2"), "user2@example.com");
+
+  account_tracker_service_.SeedAccountInfo(account1);
+  account_tracker_service_.SeedAccountInfo(account2);
+
+  {
+    auto* account_manager =
+        ash::AccountManagerFactory::Get()->GetAccountManager(
+            ProfilePath().value());
+    account_manager->Initialize(ProfilePath(), client_->GetURLLoaderFactory(),
+                                ImmediateCallbackRunner());
+
+    account_manager->SetPrefService(ProfilePrefs());
+    task_environment_.RunUntilIdle();
+
+    account_manager->UpsertAccount(
+        account_manager::AccountKey::FromGaiaId(account1.gaia),
+        "user1@example.com", "token1");
+    account_manager->UpsertAccount(
+        account_manager::AccountKey::FromGaiaId(account2.gaia),
+        "user2@example.com", "token2");
+    task_environment_.RunUntilIdle();
+  }
+
+  // Re-create AccountManager.
+  account_manager_factory_.reset();
+  account_manager_factory_ = std::make_unique<ash::AccountManagerFactory>();
+  auto* account_manager = ash::AccountManagerFactory::Get()->GetAccountManager(
+      ProfilePath().value());
+  // AccountManager will not be fully initialized until `RunUntilIdle`.
+  account_manager->Initialize(ProfilePath(), client_->GetURLLoaderFactory(),
+                              ImmediateCallbackRunner());
+  account_manager->SetPrefService(ProfilePrefs());
+
+  // Register callbacks before AccountManager has been fully initialized.
+  auto delegate =
+      std::make_unique<signin::ProfileOAuth2TokenServiceDelegateChromeOS>(
+          client_.get(), &account_tracker_service_,
+          network::TestNetworkConnectionTracker::GetInstance(),
+          ash::AccountManagerFactory::Get()->GetAccountManagerFacade(
+              ProfilePath().value()),
+          /*is_regular_profile=*/true);
+  delegate->LoadCredentials(account1.account_id /* primary_account_id */);
+  TestOAuth2TokenServiceObserver observer(delegate.get());
+
+  // Wait until AccountManager is fully initialized.
+  task_environment_.RunUntilIdle();
+
+  // Tests
+
+  // The observer should receive at least one batch change callback: batch of
+  // all accounts stored in AccountManager: because of the delegate's
+  // invocation of |AccountManagerFacade::GetAccounts| in |LoadCredentials|.
+  EXPECT_FALSE(observer.batch_change_records_.empty());
+  const std::vector<CoreAccountId>& first_batch =
+      observer.batch_change_records_[0];
+  EXPECT_EQ(2UL, first_batch.size());
+  EXPECT_TRUE(base::Contains(first_batch, account1.account_id));
+  EXPECT_TRUE(base::Contains(first_batch, account2.account_id));
+}
diff --git a/components/signin/public/identity_manager/identity_manager_builder_unittest.cc b/components/signin/public/identity_manager/identity_manager_builder_unittest.cc
index d58c1cc..589369b 100644
--- a/components/signin/public/identity_manager/identity_manager_builder_unittest.cc
+++ b/components/signin/public/identity_manager/identity_manager_builder_unittest.cc
@@ -26,7 +26,7 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS)
-#include "components/account_manager_core/mock_account_manager_facade.h"
+#include "chromeos/ash/components/account_manager/account_manager_factory.h"
 #endif
 
 #if BUILDFLAG(IS_IOS)
@@ -81,7 +81,7 @@
 TEST_F(IdentityManagerBuilderTest, BuildIdentityManagerInitParameters) {
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-  base::FilePath dest_path = temp_dir.GetPath();
+  base::FilePath profile_path = temp_dir.GetPath();
 
 #if BUILDFLAG(IS_ANDROID)
   SetUpFakeAccountManagerFacade();
@@ -94,7 +94,7 @@
   params.network_connection_tracker =
       network::TestNetworkConnectionTracker::GetInstance();
   params.pref_service = GetPrefService();
-  params.profile_path = dest_path;
+  params.profile_path = profile_path;
   params.signin_client = GetSigninClient();
 
 #if BUILDFLAG(IS_IOS)
@@ -105,9 +105,13 @@
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS)
-  auto account_manager_facade =
-      std::make_unique<account_manager::MockAccountManagerFacade>();
-  params.account_manager_facade = account_manager_facade.get();
+  // This enables `AccountManagerFactory::Get()`, which is needed for
+  // `ProfileOAuth2TokenServiceDelegateChromeOS`.
+  ash::AccountManagerFactory account_manager_factory;
+
+  params.account_manager_facade =
+      ash::AccountManagerFactory::Get()->GetAccountManagerFacade(
+          profile_path.value());
   params.is_regular_profile = true;
 #endif
 
diff --git a/components/signin/public/identity_manager/identity_test_environment.cc b/components/signin/public/identity_manager/identity_test_environment.cc
index a5d458c..e4e91b46 100644
--- a/components/signin/public/identity_manager/identity_test_environment.cc
+++ b/components/signin/public/identity_manager/identity_test_environment.cc
@@ -64,25 +64,6 @@
 
 namespace signin {
 
-#if BUILDFLAG(IS_CHROMEOS)
-int ScopedIdentityTestEnvironmentTracker::count_ = 0;
-
-ScopedIdentityTestEnvironmentTracker::ScopedIdentityTestEnvironmentTracker() {
-  ++count_;
-}
-
-ScopedIdentityTestEnvironmentTracker::~ScopedIdentityTestEnvironmentTracker() {
-  --count_;
-  if (count_ == 0) {
-    // TODO(crbug.com/421058020): Integrate `GetAccountManagerFacade` into
-    // `AccountManagerFactory` and let it manage the lifetime.
-    // Remove the facade for the empty path as it was previously a separate
-    // instance and reset after each test.
-    ash::DeleteAccountManagerFacadeInstanceForTesting("");
-  }
-}
-#endif  // BUILDFLAG(IS_CHROMEOS)
-
 class IdentityManagerDependenciesOwner {
  public:
   IdentityManagerDependenciesOwner(
diff --git a/components/signin/public/identity_manager/identity_test_environment.h b/components/signin/public/identity_manager/identity_test_environment.h
index a8d5d0e..bef48824 100644
--- a/components/signin/public/identity_manager/identity_test_environment.h
+++ b/components/signin/public/identity_manager/identity_test_environment.h
@@ -41,24 +41,6 @@
 class IdentityManagerDependenciesOwner;
 class TestIdentityManagerObserver;
 
-#if BUILDFLAG(IS_CHROMEOS)
-// TODO(crbug.com/421058020): This is needed for managing lifetime of
-// AccountManagerFactoryFacadeImpl. Remove this once we've integrated the facade
-// factory into AccountManagerFactory.
-class ScopedIdentityTestEnvironmentTracker {
- public:
-  ScopedIdentityTestEnvironmentTracker();
-  ScopedIdentityTestEnvironmentTracker(
-      const ScopedIdentityTestEnvironmentTracker&) = delete;
-  ScopedIdentityTestEnvironmentTracker& operator=(
-      const ScopedIdentityTestEnvironmentTracker&) = delete;
-  ~ScopedIdentityTestEnvironmentTracker();
-
- private:
-  static int count_;
-};
-#endif  // BUILDFLAG(IS_CHROMEOS)
-
 // Arguments for `IdentityTestEnvironment::MakeAccountAvailable()`. Keeps
 // references, so do not rely on it for storage.
 //
@@ -495,11 +477,6 @@
   base::OnceClosure on_access_token_requested_callback_;
   std::vector<AccessTokenRequestState> requesters_;
 
-#if BUILDFLAG(IS_CHROMEOS)
-  ScopedIdentityTestEnvironmentTracker
-      scoped_identity_test_environment_tracker_;
-#endif  // BUILDFLAG(IS_CHROMEOS)
-
   base::WeakPtrFactory<IdentityTestEnvironment> weak_ptr_factory_{this};
 };
 
diff --git a/components/wallet/content/browser/content_walletable_pass_ingestion_controller.cc b/components/wallet/content/browser/content_walletable_pass_ingestion_controller.cc
index ffb500b..d559307 100644
--- a/components/wallet/content/browser/content_walletable_pass_ingestion_controller.cc
+++ b/components/wallet/content/browser/content_walletable_pass_ingestion_controller.cc
@@ -10,14 +10,10 @@
 namespace wallet {
 
 ContentWalletablePassIngestionController::
-    ContentWalletablePassIngestionController(
-        content::WebContents* web_contents,
-        optimization_guide::OptimizationGuideDecider*
-            optimization_guide_decider)
-    : WalletablePassIngestionController(optimization_guide_decider),
-      content::WebContentsObserver(web_contents),
-      content::WebContentsUserData<ContentWalletablePassIngestionController>(
-          *web_contents) {}
+    ContentWalletablePassIngestionController(content::WebContents* web_contents,
+                                             WalletablePassClient* client)
+    : WalletablePassIngestionController(client),
+      content::WebContentsObserver(web_contents) {}
 
 ContentWalletablePassIngestionController::
     ~ContentWalletablePassIngestionController() = default;
@@ -32,6 +28,4 @@
   // TODO(crbug.com/422366321): Add walletable pass detection logic here.
 }
 
-WEB_CONTENTS_USER_DATA_KEY_IMPL(ContentWalletablePassIngestionController);
-
 }  // namespace wallet
diff --git a/components/wallet/content/browser/content_walletable_pass_ingestion_controller.h b/components/wallet/content/browser/content_walletable_pass_ingestion_controller.h
index 886af1c..912591c 100644
--- a/components/wallet/content/browser/content_walletable_pass_ingestion_controller.h
+++ b/components/wallet/content/browser/content_walletable_pass_ingestion_controller.h
@@ -7,7 +7,6 @@
 
 #include "components/wallet/core/browser/walletable_pass_ingestion_controller.h"
 #include "content/public/browser/web_contents_observer.h"
-#include "content/public/browser/web_contents_user_data.h"
 
 namespace content {
 class RenderFrameHost;
@@ -22,10 +21,11 @@
 // observing the `WebContents` it is attached to.
 class ContentWalletablePassIngestionController
     : public WalletablePassIngestionController,
-      public content::WebContentsObserver,
-      public content::WebContentsUserData<
-          ContentWalletablePassIngestionController> {
+      public content::WebContentsObserver {
  public:
+  ContentWalletablePassIngestionController(content::WebContents* web_contents,
+                                           WalletablePassClient* client);
+
   ContentWalletablePassIngestionController(
       const ContentWalletablePassIngestionController&) = delete;
   ContentWalletablePassIngestionController& operator=(
@@ -36,15 +36,6 @@
   // content::WebContentsObserver:
   void DidFinishLoad(content::RenderFrameHost* render_frame_host,
                      const GURL& validated_url) override;
-
- private:
-  friend class content::WebContentsUserData<
-      ContentWalletablePassIngestionController>;
-  ContentWalletablePassIngestionController(
-      content::WebContents* web_contents,
-      optimization_guide::OptimizationGuideDecider* optimization_guide_decider);
-
-  WEB_CONTENTS_USER_DATA_KEY_DECL();
 };
 
 }  // namespace wallet
diff --git a/components/wallet/core/browser/BUILD.gn b/components/wallet/core/browser/BUILD.gn
index 1da21abd4..77236139 100644
--- a/components/wallet/core/browser/BUILD.gn
+++ b/components/wallet/core/browser/BUILD.gn
@@ -2,8 +2,11 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//components/optimization_guide/features.gni")
+
 static_library("browser") {
   sources = [
+    "walletable_pass_client.h",
     "walletable_pass_ingestion_controller.cc",
     "walletable_pass_ingestion_controller.h",
     "walletable_pass_service.cc",
@@ -17,17 +20,28 @@
   ]
 }
 
-source_set("unit_tests") {
+source_set("test_support") {
   testonly = true
-  sources = [
-    "walletable_pass_ingestion_controller_unittest.cc",
-    "walletable_pass_service_unittest.cc",
-  ]
+  sources = [ "walletable_pass_ingestion_controller_test_api.h" ]
   deps = [
     ":browser",
     "//base",
+    "//url",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [ "walletable_pass_service_unittest.cc" ]
+  if (build_with_model_execution) {
+    sources += [ "walletable_pass_ingestion_controller_unittest.cc" ]
+  }
+  deps = [
+    ":browser",
+    ":test_support",
+    "//base",
     "//base/test:test_support",
-    "//components/optimization_guide/core:hints_test_support",
+    "//components/optimization_guide/core:test_support",
     "//testing/gmock",
     "//testing/gtest",
     "//url",
diff --git a/components/wallet/core/browser/walletable_pass_client.h b/components/wallet/core/browser/walletable_pass_client.h
new file mode 100644
index 0000000..97668de
--- /dev/null
+++ b/components/wallet/core/browser/walletable_pass_client.h
@@ -0,0 +1,36 @@
+// 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_WALLET_CORE_BROWSER_WALLETABLE_PASS_CLIENT_H_
+#define COMPONENTS_WALLET_CORE_BROWSER_WALLETABLE_PASS_CLIENT_H_
+
+namespace optimization_guide {
+class OptimizationGuideDecider;
+class OptimizationGuideModelExecutor;
+}  // namespace optimization_guide
+
+namespace wallet {
+
+// A client interface that must be supplied to the Wallet component by the
+// embedder (e.g., Chrome). The client's goal is to provide access to
+// browser-level services required for walletable pass detection and extraction,
+// such as the Optimization Guide. This allows the component to function without
+// a direct dependency on the browser's implementation details.
+//
+// An implementation of this client is associated with a single tab and its
+// lifecycle.
+class WalletablePassClient {
+ public:
+  virtual ~WalletablePassClient() = default;
+
+  virtual optimization_guide::OptimizationGuideDecider*
+  GetOptimizationGuideDecider() = 0;
+
+  virtual optimization_guide::OptimizationGuideModelExecutor*
+  GetOptimizationGuideModelExecutor() = 0;
+};
+
+}  // namespace wallet
+
+#endif  // COMPONENTS_WALLET_CORE_BROWSER_WALLETABLE_PASS_CLIENT_H_
diff --git a/components/wallet/core/browser/walletable_pass_ingestion_controller.cc b/components/wallet/core/browser/walletable_pass_ingestion_controller.cc
index 287901d0..03572764 100644
--- a/components/wallet/core/browser/walletable_pass_ingestion_controller.cc
+++ b/components/wallet/core/browser/walletable_pass_ingestion_controller.cc
@@ -4,15 +4,18 @@
 
 #include "components/wallet/core/browser/walletable_pass_ingestion_controller.h"
 
+#include "base/check_deref.h"
 #include "components/optimization_guide/core/hints/optimization_guide_decider.h"
+#include "components/optimization_guide/core/optimization_guide_model_executor.h"
+#include "components/optimization_guide/proto/features/walletable_pass_extraction.pb.h"
 #include "components/optimization_guide/proto/hints.pb.h"
 #include "url/gurl.h"
 
 namespace wallet {
 
 WalletablePassIngestionController::WalletablePassIngestionController(
-    optimization_guide::OptimizationGuideDecider* optimization_guide_decider)
-    : optimization_guide_decider_(optimization_guide_decider) {
+    WalletablePassClient* client)
+    : client_(CHECK_DEREF(client)) {
   RegisterOptimizationTypes();
 }
 
@@ -26,7 +29,7 @@
   }
 
   // Check if URL is allowlisted via optimization guide
-  return optimization_guide_decider_->CanApplyOptimization(
+  return client_->GetOptimizationGuideDecider()->CanApplyOptimization(
              url,
              optimization_guide::proto::WALLETABLE_PASS_DETECTION_ALLOWLIST,
              /*optimization_metadata=*/nullptr) ==
@@ -34,8 +37,52 @@
 }
 
 void WalletablePassIngestionController::RegisterOptimizationTypes() {
-  optimization_guide_decider_->RegisterOptimizationTypes(
+  client_->GetOptimizationGuideDecider()->RegisterOptimizationTypes(
       {optimization_guide::proto::WALLETABLE_PASS_DETECTION_ALLOWLIST});
 }
 
+void WalletablePassIngestionController::ExtractWalletablePass(
+    const std::string& url,
+    optimization_guide::proto::AnnotatedPageContent annotated_page_content) {
+  // Construct request
+  optimization_guide::proto::WalletablePassExtractionRequest request;
+  request.mutable_page_context()->set_url(url);
+  *request.mutable_page_context()->mutable_annotated_page_content() =
+      std::move(annotated_page_content);
+
+  client_->GetOptimizationGuideModelExecutor()->ExecuteModel(
+      optimization_guide::ModelBasedCapabilityKey::kWalletablePassExtraction,
+      std::move(request),
+      /*execution_timeout=*/std::nullopt,
+      base::BindOnce(
+          &WalletablePassIngestionController::OnExtractWalletablePass,
+          weak_ptr_factory_.GetWeakPtr()));
+}
+
+void WalletablePassIngestionController::OnExtractWalletablePass(
+    optimization_guide::OptimizationGuideModelExecutionResult result,
+    std::unique_ptr<optimization_guide::ModelQualityLogEntry> log_entry) {
+  // Handle model execution failure first.
+  if (!result.response.has_value()) {
+    // TODO(crbug.com/441892746): Report model execution failure to UMA
+    return;
+  }
+
+  // The execution succeeded, now attempt to parse the response.
+  auto parsed_response = optimization_guide::ParsedAnyMetadata<
+      optimization_guide::proto::WalletablePassExtractionResponse>(
+      *result.response);
+  if (!parsed_response) {
+    // TODO(crbug.com/441892746): Report invalid or unparsable response to UMA
+    return;
+  }
+
+  if (parsed_response->walletable_pass_size() == 0) {
+    // TODO(crbug.com/441892746): Report no walletable pass found to UMA
+    return;
+  }
+
+  // TODO(crbug.com/441830204): Get the first walletable pass and show in UI.
+}
+
 }  // namespace wallet
diff --git a/components/wallet/core/browser/walletable_pass_ingestion_controller.h b/components/wallet/core/browser/walletable_pass_ingestion_controller.h
index c39581e..35dae65 100644
--- a/components/wallet/core/browser/walletable_pass_ingestion_controller.h
+++ b/components/wallet/core/browser/walletable_pass_ingestion_controller.h
@@ -5,12 +5,18 @@
 #ifndef COMPONENTS_WALLET_CORE_BROWSER_WALLETABLE_PASS_INGESTION_CONTROLLER_H_
 #define COMPONENTS_WALLET_CORE_BROWSER_WALLETABLE_PASS_INGESTION_CONTROLLER_H_
 
-#include "base/memory/raw_ptr.h"
+#include <string>
+
+#include "base/memory/raw_ref.h"
+#include "base/memory/weak_ptr.h"
+#include "components/optimization_guide/proto/features/common_quality_data.pb.h"
+#include "components/wallet/core/browser/walletable_pass_client.h"
 
 class GURL;
 
 namespace optimization_guide {
-class OptimizationGuideDecider;
+class ModelQualityLogEntry;
+struct OptimizationGuideModelExecutionResult;
 }  // namespace optimization_guide
 
 namespace wallet {
@@ -18,8 +24,8 @@
 // Controls the detection of walletable passes on a web page.
 class WalletablePassIngestionController {
  public:
-  explicit WalletablePassIngestionController(
-      optimization_guide::OptimizationGuideDecider* optimization_guide_decider);
+  explicit WalletablePassIngestionController(WalletablePassClient* client);
+
   virtual ~WalletablePassIngestionController();
 
   // Not copyable or movable.
@@ -28,18 +34,35 @@
   WalletablePassIngestionController& operator=(
       const WalletablePassIngestionController&) = delete;
 
-  // Checks if the URL is eligible for pass extraction. This is determined by
-  // consulting an allowlist managed by the Optimization Guide.
-  bool IsEligibleForExtraction(const GURL& url) const;
-
  protected:
   // Registers optimization types with the Optimization Guide to query the pass
   // extraction allowlist.
   void RegisterOptimizationTypes();
 
+  // Checks if the URL is eligible for pass extraction. This is determined by
+  // consulting an allowlist managed by the Optimization Guide.
+  bool IsEligibleForExtraction(const GURL& url) const;
+
+  // Extracts a walletable pass from the provided page content. This method
+  // invokes the Optimization Guide's model executor to perform the extraction.
+  void ExtractWalletablePass(
+      const std::string& url,
+      optimization_guide::proto::AnnotatedPageContent annotated_page_content);
+
  private:
-  raw_ptr<optimization_guide::OptimizationGuideDecider>
-      optimization_guide_decider_;
+  friend class WalletablePassIngestionControllerTestApi;
+
+  // Callback for when the pass extraction from the model executor is complete.
+  void OnExtractWalletablePass(
+      optimization_guide::OptimizationGuideModelExecutionResult result,
+      std::unique_ptr<optimization_guide::ModelQualityLogEntry> log_entry);
+
+  // A raw reference to the client, which owns `this` and therefore outlives
+  // it.
+  const raw_ref<WalletablePassClient> client_;
+
+  base::WeakPtrFactory<WalletablePassIngestionController> weak_ptr_factory_{
+      this};
 };
 
 }  // namespace wallet
diff --git a/components/wallet/core/browser/walletable_pass_ingestion_controller_test_api.h b/components/wallet/core/browser/walletable_pass_ingestion_controller_test_api.h
new file mode 100644
index 0000000..65321c6
--- /dev/null
+++ b/components/wallet/core/browser/walletable_pass_ingestion_controller_test_api.h
@@ -0,0 +1,49 @@
+// 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_WALLET_CORE_BROWSER_WALLETABLE_PASS_INGESTION_CONTROLLER_TEST_API_H_
+#define COMPONENTS_WALLET_CORE_BROWSER_WALLETABLE_PASS_INGESTION_CONTROLLER_TEST_API_H_
+
+#include <string>
+
+#include "base/check_deref.h"
+#include "base/memory/raw_ref.h"
+#include "components/wallet/core/browser/walletable_pass_ingestion_controller.h"
+#include "url/gurl.h"
+
+namespace optimization_guide::proto {
+class AnnotatedPageContent;
+}
+
+namespace wallet {
+
+// Exposes some testing operations for WalletablePassIngestionController.
+class WalletablePassIngestionControllerTestApi {
+ public:
+  explicit WalletablePassIngestionControllerTestApi(
+      WalletablePassIngestionController* controller)
+      : controller_(CHECK_DEREF(controller)) {}
+
+  bool IsEligibleForExtraction(const GURL& url) {
+    return controller_->IsEligibleForExtraction(url);
+  }
+
+  void ExtractWalletablePass(
+      const std::string& url,
+      const optimization_guide::proto::AnnotatedPageContent& content) {
+    controller_->ExtractWalletablePass(url, content);
+  }
+
+ private:
+  const raw_ref<WalletablePassIngestionController> controller_;
+};
+
+inline WalletablePassIngestionControllerTestApi test_api(
+    WalletablePassIngestionController* controller) {
+  return WalletablePassIngestionControllerTestApi(controller);
+}
+
+}  // namespace wallet
+
+#endif  // COMPONENTS_WALLET_CORE_BROWSER_WALLETABLE_PASS_INGESTION_CONTROLLER_TEST_API_H_
diff --git a/components/wallet/core/browser/walletable_pass_ingestion_controller_unittest.cc b/components/wallet/core/browser/walletable_pass_ingestion_controller_unittest.cc
index 4a26fe2..1a6d87d 100644
--- a/components/wallet/core/browser/walletable_pass_ingestion_controller_unittest.cc
+++ b/components/wallet/core/browser/walletable_pass_ingestion_controller_unittest.cc
@@ -4,64 +4,111 @@
 
 #include "components/wallet/core/browser/walletable_pass_ingestion_controller.h"
 
+#include <memory>
+
 #include "components/optimization_guide/core/hints/mock_optimization_guide_decider.h"
+#include "components/optimization_guide/core/mock_optimization_guide_model_executor.h"
+#include "components/wallet/core/browser/walletable_pass_client.h"
+#include "components/wallet/core/browser/walletable_pass_ingestion_controller_test_api.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
-using testing::Eq;
-using testing::Matcher;
+using optimization_guide::ModelBasedCapabilityKey::kWalletablePassExtraction;
+using optimization_guide::OptimizationGuideDecision::kFalse;
+using optimization_guide::OptimizationGuideDecision::kTrue;
+using optimization_guide::proto::WALLETABLE_PASS_DETECTION_ALLOWLIST;
+using testing::_;
 using testing::Return;
 
 namespace wallet {
 namespace {
 
-class WalletablePassIngestionControllerTest : public testing::Test {
+class MockWalletablePassClient : public WalletablePassClient {
  public:
-  WalletablePassIngestionControllerTest() : controller_(&mock_decider_) {}
+  MOCK_METHOD(optimization_guide::OptimizationGuideDecider*,
+              GetOptimizationGuideDecider,
+              (),
+              (override));
+  MOCK_METHOD(optimization_guide::OptimizationGuideModelExecutor*,
+              GetOptimizationGuideModelExecutor,
+              (),
+              (override));
+};
 
+class WalletablePassIngestionControllerTest : public testing::Test {
  protected:
+  WalletablePassIngestionControllerTest() = default;
+
+  void SetUp() override {
+    ON_CALL(mock_client_, GetOptimizationGuideDecider())
+        .WillByDefault(Return(&mock_decider_));
+    ON_CALL(mock_client_, GetOptimizationGuideModelExecutor())
+        .WillByDefault(Return(&mock_model_executor_));
+    controller_ =
+        std::make_unique<WalletablePassIngestionController>(&mock_client_);
+  }
+
+  WalletablePassIngestionController* controller() { return controller_.get(); }
+  optimization_guide::MockOptimizationGuideDecider& mock_decider() {
+    return mock_decider_;
+  }
+  optimization_guide::MockOptimizationGuideModelExecutor&
+  mock_model_executor() {
+    return mock_model_executor_;
+  }
+
+ private:
   testing::NiceMock<optimization_guide::MockOptimizationGuideDecider>
       mock_decider_;
+  testing::NiceMock<optimization_guide::MockOptimizationGuideModelExecutor>
+      mock_model_executor_;
+  testing::NiceMock<MockWalletablePassClient> mock_client_;
 
-  WalletablePassIngestionController controller_;
+  std::unique_ptr<WalletablePassIngestionController> controller_;
 };
 
 TEST_F(WalletablePassIngestionControllerTest,
        IsEligibleForExtraction_NonHttpUrl_NotEligible) {
   GURL file_url("file:///test.html");
-  EXPECT_FALSE(controller_.IsEligibleForExtraction(file_url));
+  EXPECT_FALSE(test_api(controller()).IsEligibleForExtraction(file_url));
 
   GURL ftp_url("ftp://example.com");
-  EXPECT_FALSE(controller_.IsEligibleForExtraction(ftp_url));
+  EXPECT_FALSE(test_api(controller()).IsEligibleForExtraction(ftp_url));
 }
 
 TEST_F(WalletablePassIngestionControllerTest,
        IsEligibleForExtraction_AllowlistedUrl) {
   GURL https_url("https://example.com");
-  EXPECT_CALL(
-      mock_decider_,
-      CanApplyOptimization(
-          Eq(https_url),
-          Eq(optimization_guide::proto::WALLETABLE_PASS_DETECTION_ALLOWLIST),
-          Matcher<optimization_guide::OptimizationMetadata*>(Eq(nullptr))))
-      .WillOnce(Return(optimization_guide::OptimizationGuideDecision::kTrue));
+  EXPECT_CALL(mock_decider(),
+              CanApplyOptimization(
+                  https_url, WALLETABLE_PASS_DETECTION_ALLOWLIST, nullptr))
+      .WillOnce(Return(kTrue));
 
-  EXPECT_TRUE(controller_.IsEligibleForExtraction(https_url));
+  EXPECT_TRUE(test_api(controller()).IsEligibleForExtraction(https_url));
 }
 
 TEST_F(WalletablePassIngestionControllerTest,
        IsEligibleForExtraction_NotAllowlistedUrl) {
   GURL http_url("http://example.com");
-  EXPECT_CALL(
-      mock_decider_,
-      CanApplyOptimization(
-          Eq(http_url),
-          Eq(optimization_guide::proto::WALLETABLE_PASS_DETECTION_ALLOWLIST),
-          Matcher<optimization_guide::OptimizationMetadata*>(Eq(nullptr))))
-      .WillOnce(Return(optimization_guide::OptimizationGuideDecision::kFalse));
+  EXPECT_CALL(mock_decider(),
+              CanApplyOptimization(
+                  http_url, WALLETABLE_PASS_DETECTION_ALLOWLIST, nullptr))
+      .WillOnce(Return(kFalse));
 
-  EXPECT_FALSE(controller_.IsEligibleForExtraction(http_url));
+  EXPECT_FALSE(test_api(controller()).IsEligibleForExtraction(http_url));
+}
+
+TEST_F(WalletablePassIngestionControllerTest,
+       ExtractWalletablePass_CallsModelExecutor) {
+  std::string url = "https://example.com";
+  optimization_guide::proto::AnnotatedPageContent content;
+  content.set_tab_id(123);
+
+  EXPECT_CALL(mock_model_executor(),
+              ExecuteModel(kWalletablePassExtraction, _, _, _));
+
+  test_api(controller()).ExtractWalletablePass(url, content);
 }
 
 }  // namespace
diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc
index 9d1b26f..57de7917 100644
--- a/content/browser/accessibility/accessibility_win_browsertest.cc
+++ b/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -6659,4 +6659,82 @@
   win_event_waiter.Wait();
 }
 
+class AccessibilityWinNarratorContainmentEnabledBrowserTest
+    : public AccessibilityWinUIABrowserTest {
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  void SetUp() override {
+    // UIA provider is already enabled by AccessibilityWinUIABrowserTest.
+    // Only enable the mitigation flag here.
+    scoped_feature_list_.InitAndEnableFeature(
+        ::features::kFixNarratorWebContentContainment);
+    AccessibilityWinUIABrowserTest::SetUp();
+  }
+};
+
+// TODO: Enable this test. Currently disabled because the parent in the test environment
+// isn't the same as the parent in prod.
+IN_PROC_BROWSER_TEST_F(AccessibilityWinNarratorContainmentEnabledBrowserTest,
+                       DISABLED_ParentClassNameIsChromeWidgetWin1) {
+  LoadInitialAccessibilityTreeFromHtml(R"HTML(<!doctype html><html></html>)HTML");
+
+  // 1. Get the HWND that hosts the web contents, then the UIA element for it.
+  RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
+      shell()->web_contents()->GetRenderWidgetHostView());
+  ASSERT_NE(nullptr, rwhva);
+  HWND hwnd = rwhva->AccessibilityGetAcceleratedWidget();
+  ASSERT_NE(gfx::kNullAcceleratedWidget, hwnd);
+
+  Microsoft::WRL::ComPtr<IUIAutomation> uia;
+  ASSERT_HRESULT_SUCCEEDED(CoCreateInstance(CLSID_CUIAutomation, nullptr,
+                                            CLSCTX_INPROC_SERVER,
+                                            IID_PPV_ARGS(&uia)));
+
+  Microsoft::WRL::ComPtr<IUIAutomationElement> hwnd_elem;
+  ASSERT_HRESULT_SUCCEEDED(uia->ElementFromHandle(hwnd, &hwnd_elem));
+  ASSERT_NE(nullptr, hwnd_elem.Get());
+
+  // 2) Get the parent of the web content element with a walker.
+  Microsoft::WRL::ComPtr<IUIAutomationTreeWalker> walker;
+  ASSERT_HRESULT_SUCCEEDED(uia->get_ControlViewWalker(&walker));
+
+  Microsoft::WRL::ComPtr<IUIAutomationElement> content_root;
+  ASSERT_HRESULT_SUCCEEDED(walker->GetFirstChildElement(hwnd_elem.Get(),
+                                                        &content_root));
+  ASSERT_NE(nullptr, content_root.Get());
+
+  Microsoft::WRL::ComPtr<IUIAutomationElement> parent_elem;
+  ASSERT_HRESULT_SUCCEEDED(walker->GetParentElement(content_root.Get(),
+                                                    &parent_elem));
+  ASSERT_NE(nullptr, parent_elem.Get());
+
+  // 3) Assert ClassName.
+  //
+  // Windows Narrator’s Scan Mode only contains navigation within web content when
+  // the UIA parent of the document reports the class name "Chrome_WidgetWin_1".
+  // Chromium currently supplies that via a temporary mitigation in
+  // ViewAccessibility::OnViewAddedToWidget(), gated by
+  // features::kFixNarratorWebContentContainment.
+  //
+  // If this test fails:
+  //  1) You likely broke Narrator’s web-content containment (users may arrow
+  //     out of the page in Scan Mode).
+  //  2) If the failure is due to a class name change, update the string we set
+  //     in ViewAccessibility::OnViewAddedToWidget() to the new expected value,
+  //     and adjust this assertion to match.
+  //  3) If the behavior changed or you’re unsure, reach out to the Accessibility team.
+  //
+  // Notes:
+  //  - This intentionally asserts the *exact* UIA class name.
+  //  - There is a paired test with the feature disabled that expects
+  //    "ContentsContainerView" to guard the baseline.
+  //  - This is a stopgap until Narrator updates its tab-boundary heuristic.
+  //  - See crbug.com/443225250 for background.
+  base::win::ScopedBstr class_name;
+  ASSERT_HRESULT_SUCCEEDED(
+      parent_elem->get_CurrentClassName(class_name.Receive()));
+  ASSERT_TRUE(class_name.Get() != nullptr);
+  EXPECT_STREQ(L"Chrome_WidgetWin_1", class_name.Get());
+}
+
 }  // namespace content
diff --git a/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc b/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc
index 0eea939..c3c28a0 100644
--- a/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc
+++ b/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc
@@ -1287,23 +1287,22 @@
   wgpu::Device device_b = GetNewDevice();
 
   // Associate both mailboxes
-  gpu::webgpu::ReservedTexture reservation_a =
-      webgpu()->ReserveTexture(device_a.Get());
-  webgpu()->AssociateMailbox(
-      reservation_a.deviceId, reservation_a.deviceGeneration, reservation_a.id,
-      reservation_a.generation, WGPUTextureUsage_RenderAttachment,
-      webgpu::WEBGPU_MAILBOX_NONE, shared_image_a->mailbox());
+  wgpu::TextureDescriptor desc = {.usage =
+                                      wgpu::TextureUsage::RenderAttachment};
 
-  gpu::webgpu::ReservedTexture reservation_b =
-      webgpu()->ReserveTexture(device_b.Get());
-  webgpu()->AssociateMailbox(
-      reservation_b.deviceId, reservation_b.deviceGeneration, reservation_b.id,
-      reservation_b.generation, WGPUTextureUsage_RenderAttachment,
-      webgpu::WEBGPU_MAILBOX_NONE, shared_image_b->mailbox());
+  std::unique_ptr<WebGPUTextureScopedAccess> webgpu_scoped_access_a =
+      shared_image_a->BeginWebGPUTextureAccess(
+          webgpu(), sii->GenVerifiedSyncToken(), device_a, desc, /*usage=*/0,
+          webgpu::WEBGPU_MAILBOX_NONE);
+
+  std::unique_ptr<WebGPUTextureScopedAccess> webgpu_scoped_access_b =
+      shared_image_b->BeginWebGPUTextureAccess(
+          webgpu(), sii->GenVerifiedSyncToken(), device_b, desc, /*usage=*/0,
+          webgpu::WEBGPU_MAILBOX_NONE);
 
   // Dissociate both mailboxes in the same order.
-  webgpu()->DissociateMailbox(reservation_a.id, reservation_a.generation);
-  webgpu()->DissociateMailbox(reservation_b.id, reservation_b.generation);
+  WebGPUTextureScopedAccess::EndAccess(std::move(webgpu_scoped_access_a));
+  WebGPUTextureScopedAccess::EndAccess(std::move(webgpu_scoped_access_b));
 
   // Send all the previous commands to the WebGPU decoder.
   webgpu()->FlushCommands();
@@ -1312,51 +1311,6 @@
 // Test that passing a descriptor to ReserveTexture produces a client-side
 // WGPUTexture that correctly reflects said descriptor.
 TEST_P(WebGPUMailboxTextureTest, ReflectionOfDescriptor) {
-  // Check that reserving a texture with a full descriptor give the same data
-  // back through reflection.
-  wgpu::TextureDescriptor desc1 = {};
-  desc1.size = {1, 2, 3};
-  desc1.format = wgpu::TextureFormat::R32Float;
-  desc1.usage = wgpu::TextureUsage::CopyDst;
-  desc1.dimension = wgpu::TextureDimension::e2D;
-  desc1.sampleCount = 1;
-  desc1.mipLevelCount = 1;
-  gpu::webgpu::ReservedTexture reservation1 = webgpu()->ReserveTexture(
-      device_.Get(), reinterpret_cast<const WGPUTextureDescriptor*>(&desc1));
-  wgpu::Texture texture1 = wgpu::Texture::Acquire(reservation1.texture);
-
-  ASSERT_EQ(desc1.size.width, texture1.GetWidth());
-  ASSERT_EQ(desc1.size.height, texture1.GetHeight());
-  ASSERT_EQ(desc1.size.depthOrArrayLayers, texture1.GetDepthOrArrayLayers());
-  ASSERT_EQ(desc1.format, texture1.GetFormat());
-  ASSERT_EQ(desc1.usage, texture1.GetUsage());
-  ASSERT_EQ(desc1.dimension, texture1.GetDimension());
-  ASSERT_EQ(desc1.sampleCount, texture1.GetSampleCount());
-  ASSERT_EQ(desc1.mipLevelCount, texture1.GetMipLevelCount());
-
-  // Test with a different descriptor to check data is not hardcoded. Not that
-  // this is actually not a valid descriptor (diimension == 1D with height !=
-  // 1), but that it should still be reflected exactly.
-  wgpu::TextureDescriptor desc2 = {};
-  desc2.size = {4, 5, 6};
-  desc2.format = wgpu::TextureFormat::RGBA8Unorm;
-  desc2.usage = wgpu::TextureUsage::CopySrc;
-  desc2.dimension = wgpu::TextureDimension::e1D;
-  desc2.sampleCount = 4;
-  desc2.mipLevelCount = 3;
-  gpu::webgpu::ReservedTexture reservation2 = webgpu()->ReserveTexture(
-      device_.Get(), reinterpret_cast<const WGPUTextureDescriptor*>(&desc2));
-  wgpu::Texture texture2 = wgpu::Texture::Acquire(reservation2.texture);
-
-  ASSERT_EQ(desc2.size.width, texture2.GetWidth());
-  ASSERT_EQ(desc2.size.height, texture2.GetHeight());
-  ASSERT_EQ(desc2.size.depthOrArrayLayers, texture2.GetDepthOrArrayLayers());
-  ASSERT_EQ(desc2.format, texture2.GetFormat());
-  ASSERT_EQ(desc2.usage, texture2.GetUsage());
-  ASSERT_EQ(desc2.dimension, texture2.GetDimension());
-  ASSERT_EQ(desc2.sampleCount, texture2.GetSampleCount());
-  ASSERT_EQ(desc2.mipLevelCount, texture2.GetMipLevelCount());
-
   // Associate mailboxes so that releasing the reserved wgpu::Textures does not
   // fail. Note that these texture parameters do not match. It doesn't matter
   // since the textures are not used in this test except for frontend
@@ -1376,14 +1330,60 @@
                               GetSharedImageUsage(AccessType::Read),
                               "TestLabel"},
                              kNullSurfaceHandle);
-  webgpu()->AssociateMailbox(
-      reservation1.deviceId, reservation1.deviceGeneration, reservation1.id,
-      reservation1.generation, static_cast<WGPUTextureUsage>(desc1.usage),
-      webgpu::WEBGPU_MAILBOX_NONE, shared_image1->mailbox());
-  webgpu()->AssociateMailbox(
-      reservation2.deviceId, reservation2.deviceGeneration, reservation2.id,
-      reservation2.generation, static_cast<WGPUTextureUsage>(desc2.usage),
-      webgpu::WEBGPU_MAILBOX_NONE, shared_image2->mailbox());
+
+  // Check that reserving a texture with a full descriptor give the same data
+  // back through reflection.
+  wgpu::TextureDescriptor desc1 = {};
+  desc1.size = {1, 2, 3};
+  desc1.format = wgpu::TextureFormat::R32Float;
+  desc1.usage = wgpu::TextureUsage::CopyDst;
+  desc1.dimension = wgpu::TextureDimension::e2D;
+  desc1.sampleCount = 1;
+  desc1.mipLevelCount = 1;
+
+  // Test with a different descriptor to check data is not hardcoded. Not that
+  // this is actually not a valid descriptor (diimension == 1D with height !=
+  // 1), but that it should still be reflected exactly.
+  wgpu::TextureDescriptor desc2 = {};
+  desc2.size = {4, 5, 6};
+  desc2.format = wgpu::TextureFormat::RGBA8Unorm;
+  desc2.usage = wgpu::TextureUsage::CopySrc;
+  desc2.dimension = wgpu::TextureDimension::e1D;
+  desc2.sampleCount = 4;
+  desc2.mipLevelCount = 3;
+
+  std::unique_ptr<WebGPUTextureScopedAccess> webgpu_scoped_access1 =
+      shared_image1->BeginWebGPUTextureAccess(
+          webgpu(), sii->GenVerifiedSyncToken(), device_, desc1, /*usage=*/0,
+          webgpu::WEBGPU_MAILBOX_NONE);
+  std::unique_ptr<WebGPUTextureScopedAccess> webgpu_scoped_access2 =
+      shared_image2->BeginWebGPUTextureAccess(
+          webgpu(), sii->GenVerifiedSyncToken(), device_, desc2, /*usage=*/0,
+          webgpu::WEBGPU_MAILBOX_NONE);
+
+  wgpu::Texture texture1 = webgpu_scoped_access1->texture();
+  wgpu::Texture texture2 = webgpu_scoped_access2->texture();
+
+  ASSERT_EQ(desc1.size.width, texture1.GetWidth());
+  ASSERT_EQ(desc1.size.height, texture1.GetHeight());
+  ASSERT_EQ(desc1.size.depthOrArrayLayers, texture1.GetDepthOrArrayLayers());
+  ASSERT_EQ(desc1.format, texture1.GetFormat());
+  ASSERT_EQ(desc1.usage, texture1.GetUsage());
+  ASSERT_EQ(desc1.dimension, texture1.GetDimension());
+  ASSERT_EQ(desc1.sampleCount, texture1.GetSampleCount());
+  ASSERT_EQ(desc1.mipLevelCount, texture1.GetMipLevelCount());
+
+  ASSERT_EQ(desc2.size.width, texture2.GetWidth());
+  ASSERT_EQ(desc2.size.height, texture2.GetHeight());
+  ASSERT_EQ(desc2.size.depthOrArrayLayers, texture2.GetDepthOrArrayLayers());
+  ASSERT_EQ(desc2.format, texture2.GetFormat());
+  ASSERT_EQ(desc2.usage, texture2.GetUsage());
+  ASSERT_EQ(desc2.dimension, texture2.GetDimension());
+  ASSERT_EQ(desc2.sampleCount, texture2.GetSampleCount());
+  ASSERT_EQ(desc2.mipLevelCount, texture2.GetMipLevelCount());
+
+  WebGPUTextureScopedAccess::EndAccess(std::move(webgpu_scoped_access1));
+  WebGPUTextureScopedAccess::EndAccess(std::move(webgpu_scoped_access2));
 }
 
 // Test that passing a texture with invalid view formats to AssociateMailbox
@@ -1396,9 +1396,6 @@
   desc.dimension = wgpu::TextureDimension::e2D;
   desc.sampleCount = 1;
   desc.mipLevelCount = 1;
-  gpu::webgpu::ReservedTexture reservation = webgpu()->ReserveTexture(
-      device_.Get(), reinterpret_cast<const WGPUTextureDescriptor*>(&desc));
-  wgpu::Texture texture = wgpu::Texture::Acquire(reservation.texture);
 
   SharedImageInterface* sii = GetSharedImageInterface();
   scoped_refptr<gpu::ClientSharedImage> shared_image =
@@ -1408,23 +1405,25 @@
                               GetSharedImageUsage(AccessType::ReadWrite),
                               "TestLabel"},
                              kNullSurfaceHandle);
-  WGPUTextureFormat view_formats = {
-      WGPUTextureFormat_R8Unorm,
-  };
+  wgpu::TextureFormat view_formats = wgpu::TextureFormat::R8Unorm;
+  desc.viewFormats = &view_formats;
+  desc.viewFormatCount = 1;
 
   // AssociateMailbox may cause validation errors, given the invalid
   // viewFormats, so wrap it in an error scope.
   device_.PushErrorScope(wgpu::ErrorFilter::Validation);
-  webgpu()->AssociateMailbox(
-      reservation.deviceId, reservation.deviceGeneration, reservation.id,
-      reservation.generation, static_cast<WGPUTextureUsage>(desc.usage),
-      &view_formats, 1, webgpu::WEBGPU_MAILBOX_NONE, shared_image->mailbox());
+
+  std::unique_ptr<WebGPUTextureScopedAccess> webgpu_scoped_access =
+      shared_image->BeginWebGPUTextureAccess(
+          webgpu(), sii->GenVerifiedSyncToken(), device_, desc, /*usage=*/0,
+          webgpu::WEBGPU_MAILBOX_NONE);
+
   device_.PopErrorScope(
       wgpu::CallbackMode::AllowSpontaneous,
       [](wgpu::PopErrorScopeStatus, wgpu::ErrorType, wgpu::StringView) {});
 
   // DissociateMailbox should NOT cause validation errors.
-  webgpu()->DissociateMailbox(reservation.id, reservation.generation);
+  WebGPUTextureScopedAccess::EndAccess(std::move(webgpu_scoped_access));
 }
 
 // Test that if some other GL context is current when
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
index c794177..1682af0 100644
--- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-9c085f15d837f050161bedce2390fa702e289c12
\ No newline at end of file
+0c46153b8d84c5f0d98bcae9a1874d4a867c54ac
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
index a544a04..898f9f0f 100644
--- a/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeExtensionKeychainInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@
-db113675c2ad8cf60d9778600f9710221ba9e5d3
\ No newline at end of file
+f200f73ce2452bf3d90e0fe0aa604cc6051b3404
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
index ea3826dc..f186195 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-bdc0dabe504df546455a114409bdea441250ec75
\ No newline at end of file
+7efe2dbb38ec876898411a503983285d4063c281
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
index 7f1d67f..13759649d 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@
-4ccff6cdc582f2f724e9a0c33f1a637bb1aebe91
\ No newline at end of file
+3dfe7bd9c8595a284f3370540d679e276e6320c1
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
index 92b7e696..cafc8333 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-45b562afec6106366b603eb5d9aff9a724980f10
\ No newline at end of file
+c821f98d7ce81949a05392ddc328fcc833e30532
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
index 396deb8a..dfb251d 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios_asan.zip.sha1
@@ -1 +1 @@
-45ceee3d0178c6a95cad5a8a738896f2b9876c0d
\ No newline at end of file
+4b389893aeb237f16878ddfc1377e4c9000c59c8
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
index 32c2cd60..ed44f18a 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-51a02889ec54352d7db19bafeac6e26030181fc0
\ No newline at end of file
+3f38bc273b1ecd66c70da0053dc17b72776b0ab4
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
index 2c86dbb4..4a6ce9e 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-9f347a994255c6dbb9b6fbd11baf65f282a54f0a
\ No newline at end of file
+2f2bfecb8be6d8c3b977d9086225b8d8737c4419
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
index 8e7a4d9..4b9001a2 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-223e9972022523869e3841f2075d4907648a75e0
\ No newline at end of file
+54acb71c2a8746650316c114dabac6d25357d766
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
index 46383f45..ce38796 100644
--- a/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_extension_keychain_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-d96062b89764c89f5334e062757d9b3b2c949785
\ No newline at end of file
+536fe04bfa239bace4bac680a86f5325a12da670
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index 6c23927..bea74f66 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-f1378b14b3b00e79ce5c77116f205cc3c813db82
\ No newline at end of file
+8865f29e0edb409401e46dc1ecb7f4bfccef52d8
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
index c9cee59..9274ebd8 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-9dace594374b3ce6ed8808d4bb0fe1948b081de7
\ No newline at end of file
+d88fed13a1ede7101fbe6d6d7e08d893641e2c7a
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index 53c7e5f..f0509770 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-fcf8694a707a6b2cbb50c03e7b78b3a79cc0847b
\ No newline at end of file
+8fb64219f562488d69e0f4520d6c6ce6a7f8b4d2
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
index 1136925d..111fee0 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-75d8831b35949fd000ad2ceaf6a71c9b84bf45e8
\ No newline at end of file
+d05bd82f7515b51c6d51d77bd8768beb18f4d8f1
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index af8d4f8..7fbf237 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-89f791fdd3073869ab38159b0712dd8bead7dfab
\ No newline at end of file
+6b55678b743d70466806be708c662136386f8745
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
index ca52ed7..184f8d5 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-f46538a724326fd8318633e6c1114902020429db
\ No newline at end of file
+794710b30392f08f5cd5fc13056e651c659302cd
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index d9a8cb6..c91648d 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-b3b15e68ca4fd0a2081f123e24f3c35d1bc38a67
\ No newline at end of file
+c0482c73232a817821e2f398e97c8c66de512f9d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
index bc23270..8e1fb25 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-3d6e8afa5f346f6361a0747f0e10877546c6268c
\ No newline at end of file
+107373232828d604ed67204c2e6f1fde74bfaa9c
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
index 10c3adf8..43f1daa3 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-806d92d7a3301826135c4a1f8fd70ffe882ed67f
\ No newline at end of file
+29678ebfcf30150d20539d7c7ec3dace753d1cdd
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
index 87df133..0e31bcd 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-d9ea8a7adc8a1819b80b4f07d7a37e329a50d3b5
\ No newline at end of file
+d60bf7194300a79a85b4241c92d84df231de092d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index e406889c..78351e7e4 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-eeb698facd71f556e6b6609d7b2d8030023188f8
\ No newline at end of file
+ae2ac2094093926efbcafc466e596b393cc4c1c4
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1
index 0919943..538b0f4 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-e2e1a4372f520263fa7e03cc151acbec99f9402f
\ No newline at end of file
+fb49e5aaf78e4afc2b6155a7db6978ec8839fb8b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index 75e613a14..fdbdc25 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-37ed1334026702a1512b0d61eead18258ac2c3d1
\ No newline at end of file
+65bac264352e14cde048804f7c9012211aa7d3d0
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1
index ea68634..0985370a 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-f7e102adb07906a278476c5a87b6a185443e113d
\ No newline at end of file
+5813bd6fe923699acfa8cac29b6a81fdea2b22e1
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index 0cf23b4..2ba3356 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-262d1823d35332473beed8a5394ddabc465be200
\ No newline at end of file
+d2f444f71ca4a4d787cffa451efeb5596baf76e8
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
index 4dc39da..9db98e78 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios_asan.zip.sha1
@@ -1 +1 @@
-e69cbd8f9f14aea24453f208308c514f7a9f6149
\ No newline at end of file
+dfbdd29a93af4c8d6d5b47bd9ed7896d3b4e1393
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index 827b63e6..b29e03d 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-d7010338ddb97daf4d9dd63d71127671330a148c
\ No newline at end of file
+d9aa10b0f393917956dff4eb685a84e4f8b09f34
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
index 76138dfc..9fe5fe7 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator_asan.zip.sha1
@@ -1 +1 @@
-a9e0f201a5c75f1fea44d41fbf95d4de34d378d8
\ No newline at end of file
+d88f91ae48ae255b62e13f78b036b61a74237042
\ No newline at end of file
diff --git a/ios_internal b/ios_internal
index d7e0303..21d8a0c 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit d7e03032fddf9552e94070778f3cfb775ab89dd2
+Subproject commit 21d8a0cb8e9d5392de3dee97d473f17ca97def28
diff --git a/net/http/transport_security_state_static.pins b/net/http/transport_security_state_static.pins
index a9fb9653a..a7199ae 100644
--- a/net/http/transport_security_state_static.pins
+++ b/net/http/transport_security_state_static.pins
@@ -43,9 +43,9 @@
 #   hash function for preloaded entries again (we have already done so once).
 #
 
-# Last updated: 2025-09-06 12:53 UTC
+# Last updated: 2025-09-07 12:54 UTC
 PinsListTimestamp
-1757163209
+1757249642
 
 TestSPKI
 sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
diff --git a/net/http/transport_security_state_static_pins.json b/net/http/transport_security_state_static_pins.json
index 96441aa..782993f6 100644
--- a/net/http/transport_security_state_static_pins.json
+++ b/net/http/transport_security_state_static_pins.json
@@ -31,7 +31,7 @@
 // the 'static_spki_hashes' and 'bad_static_spki_hashes' fields in 'pinsets'
 // refer to, and the timestamp at which the pins list was last updated.
 //
-// Last updated: 2025-09-06 12:53 UTC
+// Last updated: 2025-09-07 12:54 UTC
 //
 {
   "pinsets": [
diff --git a/net/third_party/uri_template/README.chromium b/net/third_party/uri_template/README.chromium
index c041106..badef8c 100644
--- a/net/third_party/uri_template/README.chromium
+++ b/net/third_party/uri_template/README.chromium
@@ -3,10 +3,11 @@
 URL: https://github.com/google/google-api-cpp-client/
 Revision: d0bbe169d81a50936ec5fcea4e6dbcfb97303f13
 Update Mechanism: Manual
-Date: August 6, 2018
+Date: 2018-08-06
 License: Apache-2.0
 License File: LICENSE
 Shipped: yes
+Security Critical: yes
 
 Description:
 This code is derived from the URI template parsing code in the Google API C++
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index d8c010da..36c20b4 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -332509,6 +332509,10 @@
      ]
     },
     "sandbox": {
+     "autoplay-disabled-by-csp-expected.txt": [
+      "2d040081d02082ef1e6ad2e27ec67d2b5cba8cee",
+      []
+     ],
      "service-worker-sandbox.https-expected.txt": [
       "e6a2b864198427d716bd6ef32c826dc1d0717a24",
       []
@@ -332518,6 +332522,14 @@
       []
      ],
      "support": {
+      "autoplay.html": [
+       "62d0adc3d204f2df9337bf30343591bfb1958e67",
+       []
+      ],
+      "autoplay.html.headers": [
+       "09e65834224c8b917d0a6a2fae17f79ff251fcb6",
+       []
+      ],
       "empty.html": [
        "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
        []
@@ -332542,6 +332554,18 @@
        "c7e4e7cc5bd3fa25851c1e26c3c04eb95050d94b",
        []
       ],
+      "sandboxed-last-directive-csp.headers": [
+       "371abe3b936e686c901cc9f6f366b8c68e6f3f8b",
+       []
+      ],
+      "sandboxed-last-directive-csp.html": [
+       "9480e521de21ef930674721de943f96e1fd1219a",
+       []
+      ],
+      "sandboxed-post-message-to-parent.headers": [
+       "0368ae01896a2cadb6019ab2c1eb5346d9c3b764",
+       []
+      ],
       "sandboxed-post-message-to-parent.html": [
        "ef4b1a0b95a7e00275c423d49dd28f98545950d3",
        []
@@ -497894,6 +497918,13 @@
      ]
     },
     "sandbox": {
+     "autoplay-disabled-by-csp.html": [
+      "1d1ed0e50b7182ed0d1f8ab7d1b7c7b98e709030",
+      [
+       null,
+       {}
+      ]
+     ],
      "iframe-inside-csp.sub.html": [
       "cd402bdba0198bf763e1733004c2005614b9a542",
       [
@@ -497930,7 +497961,14 @@
       ]
      ],
      "sandbox-empty.sub.html": [
-      "47034710203a1fb8a3326cd7c8d8367166837628",
+      "47c3aa1e3657cf2eb5acfeb06bd1936b6e117d0f",
+      [
+       null,
+       {}
+      ]
+     ],
+     "sandbox-last-directive-csp.html": [
+      "b4b2cdbe3296dff091594f73dafb4f4791e5ca72",
       [
        null,
        {}
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/autoplay-disabled-by-csp-expected.txt b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/autoplay-disabled-by-csp-expected.txt
new file mode 100644
index 0000000..2d04008
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/autoplay-disabled-by-csp-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = Uncaught SecurityError: Failed to read a named property 'document' from 'Window': Blocked a frame with origin "http://web-platform.test:8001" from accessing a cross-origin frame.
+[TIMEOUT] csp-derived sandboxing flags prevent autoplay.
+  Test timed out
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/autoplay-disabled-by-csp.html b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/autoplay-disabled-by-csp.html
new file mode 100644
index 0000000..1d1ed0e5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/autoplay-disabled-by-csp.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+  <head>
+  <link rel="help" href="https://html.spec.whatwg.org/multipage/#eligible-for-autoplay" />
+  <title>Test that autoplay is blocked by a document's active sandboxing flags</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src='../support/logTest.sub.js?logs=["Loaded iframe"]'></script>
+  <script src="/common/media.js"></script>
+  </head>
+  <body>
+    <iframe id="iframe" src="support/autoplay.html"></iframe>
+    <script>
+      async_test((t) => {
+        iframe.addEventListener('load', () => {
+          log('Loaded iframe');
+          var v = iframe.contentWindow.document.getElementById('v');
+
+          v.addEventListener('playing', t.unreached_func(
+            'video should not autoplay due to sandboxing flags'
+          ));
+
+          v.src = getVideoURI('/media/movie_5') + '?' + new Date() + Math.random()
+          t.step_timeout(() => t.done(), 500);
+        });
+      }, 'csp-derived sandboxing flags prevent autoplay.')
+    </script>
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/sandbox-empty.sub.html b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/sandbox-empty.sub.html
index 4703471..47c3aa1 100644
--- a/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/sandbox-empty.sub.html
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/sandbox-empty.sub.html
@@ -18,7 +18,7 @@
        }
     </script>
 
-    <iframe src="support/sandboxed-post-message-to-parent.sub.html?sandbox="
+    <iframe src="support/sandboxed-post-message-to-parent.html"
             onload="log('PASS2')"></iframe>
 </body>
 
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/sandbox-last-directive-csp.html b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/sandbox-last-directive-csp.html
new file mode 100644
index 0000000..b4b2cdb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/sandbox-last-directive-csp.html
@@ -0,0 +1,18 @@
+<html>
+<head>
+    <!-- Programmatically converted from a WebKit Reftest, please forgive resulting idiosyncracies.-->
+    <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline' 'self'; connect-src 'self';">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <script src='../support/logTest.sub.js?logs=["PASS (1/2): Script can execute","PASS (2/2): Eval works"]'></script>
+    <script src='../support/alertAssert.sub.js?alerts=[]'></script>
+</head>
+<body>
+  <script>
+    window.onmessage = function(e) {
+      log(e.data);
+    }
+  </script>
+  <iframe src="support/sandboxed-last-directive-csp.html"></iframe>
+</body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/autoplay.html b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/autoplay.html
new file mode 100644
index 0000000..62d0adc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/autoplay.html
@@ -0,0 +1 @@
+<video id="v" autoplay></video>
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/autoplay.html.headers b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/autoplay.html.headers
new file mode 100644
index 0000000..09e6583
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/autoplay.html.headers
@@ -0,0 +1 @@
+Content-Security-Policy: sandbox
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/sandboxed-last-directive-csp.headers b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/sandboxed-last-directive-csp.headers
new file mode 100644
index 0000000..371abe3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/sandboxed-last-directive-csp.headers
@@ -0,0 +1 @@
+Content-Security-Policy: sandbox; sandbox allow-scripts
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/sandboxed-last-directive-csp.html b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/sandboxed-last-directive-csp.html
new file mode 100644
index 0000000..9480e52
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/sandboxed-last-directive-csp.html
@@ -0,0 +1,4 @@
+<script>
+  window.parent.postMessage('PASS (1/2): Script can execute', '*');
+  eval("window.parent.postMessage('PASS (2/2): Eval works', '*')");
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/sandboxed-post-message-to-parent.headers b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/sandboxed-post-message-to-parent.headers
new file mode 100644
index 0000000..0368ae0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/sandbox/support/sandboxed-post-message-to-parent.headers
@@ -0,0 +1 @@
+Content-Security-Policy: sandbox
diff --git a/third_party/boringssl/src b/third_party/boringssl/src
index b6b33a8..0226f30 160000
--- a/third_party/boringssl/src
+++ b/third_party/boringssl/src
@@ -1 +1 @@
-Subproject commit b6b33a84ed7badd0441cec1324ba3ef7f1d897e2
+Subproject commit 0226f30467f540a3f62ef48d453f93927da199b6
diff --git a/third_party/compiler-rt/src b/third_party/compiler-rt/src
index 0c75031..514effe 160000
--- a/third_party/compiler-rt/src
+++ b/third_party/compiler-rt/src
@@ -1 +1 @@
-Subproject commit 0c75031f1b7a0556a6cc07b6aa97a260278c5e0d
+Subproject commit 514effe33889c9cd899c10ef7ad1f79fb86ef388
diff --git a/third_party/crashpad/crashpad/third_party/cpp-httplib/README.crashpad b/third_party/crashpad/crashpad/third_party/cpp-httplib/README.crashpad
index df90727..7564e12 100644
--- a/third_party/crashpad/crashpad/third_party/cpp-httplib/README.crashpad
+++ b/third_party/crashpad/crashpad/third_party/cpp-httplib/README.crashpad
@@ -6,7 +6,7 @@
 Update Mechanism: Manual
 License: MIT
 License File: cpp-httplib/LICENSE
-Security Critical: no (test only)
+Security Critical: no
 Shipped: no
 CPEPrefix: cpe:/a:cpp-httplib_project:cpp-httplib
 
diff --git a/third_party/dawn b/third_party/dawn
index f1d98be..7e45e46 160000
--- a/third_party/dawn
+++ b/third_party/dawn
@@ -1 +1 @@
-Subproject commit f1d98befa15c18fddc72c68ea9f5278800fb813b
+Subproject commit 7e45e468cf42e3c0d21d539010fc06b839021b62
diff --git a/third_party/fuchsia-gn-sdk/README.chromium b/third_party/fuchsia-gn-sdk/README.chromium
index dabbe4a5..24551cf1 100644
--- a/third_party/fuchsia-gn-sdk/README.chromium
+++ b/third_party/fuchsia-gn-sdk/README.chromium
@@ -6,9 +6,10 @@
 License: BSD-2-Clause
 License File: LICENSE
 Date: 2024-02-26
-Update Mechanism: Static
+Update Mechanism: Static (https://crbug.com/422063622)
 
 Description:
+Pending ATL review for Static exception.
 This directory contains the files that complement the Fuchsia SDK
 for projects that use the GN build tool. The files in src/ were originally
 copied from
diff --git a/third_party/perfetto b/third_party/perfetto
index 67f0bdf..93825934 160000
--- a/third_party/perfetto
+++ b/third_party/perfetto
@@ -1 +1 @@
-Subproject commit 67f0bdf7285d15783e7ee55c1e5d524887d43f33
+Subproject commit 93825934c10d3a8179e1b8b840bbe1fd7f64a913
diff --git a/third_party/skia b/third_party/skia
index 064cf12..310062a 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit 064cf12ad0cce462f4c2871ddbe6642746bc91ee
+Subproject commit 310062ae6aee31778717d28b8fb33536dc642a4b
diff --git a/third_party/updater/README.chromium b/third_party/updater/README.chromium
index 510e1b1..c4a9a1b 100644
--- a/third_party/updater/README.chromium
+++ b/third_party/updater/README.chromium
@@ -1,5 +1,5 @@
 Name: ChromiumUpdater
-URL: https://chromium.googlesource.com/chromium/src/+/main/chrome/updater/README.md
+URL: Internal
 Version: N/A
 Revision: DEPS
 Update Mechanism: Manual
@@ -24,3 +24,5 @@
 To update the versions of the updater in this directory, wait for the version
 you want to become available in CIPD, then update /DEPS to point to it. If the
 files change, you may also have to update ./BUILD.gn.
+
+For more info see https://chromium.googlesource.com/chromium/src/+/main/chrome/updater/README.md
diff --git a/third_party/webrtc b/third_party/webrtc
index 0b49772..981d111 160000
--- a/third_party/webrtc
+++ b/third_party/webrtc
@@ -1 +1 @@
-Subproject commit 0b497723227dcfa52047ca9d136b1ffbe130ea68
+Subproject commit 981d111a875397315b34fa6889809c8862feb60d
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 1f3096e..ae74010 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": "221d9ddf67dbfe98d176e5b21d7f111eec1ed899",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/67f0bdf7285d15783e7ee55c1e5d524887d43f33/trace_processor_shell.exe"
+            "hash": "9d3f883a8404ec4cd731460ce94070cb222614b8",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/win/93825934c10d3a8179e1b8b840bbe1fd7f64a913/trace_processor_shell.exe"
         },
         "linux_arm": {
             "hash": "d2819bf77c3920780f2b33cc43f328d24cc1e427",
@@ -22,7 +22,7 @@
         },
         "linux": {
             "hash": "381f28daa9257db8026190b94133a173fe3d6bab",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/67f0bdf7285d15783e7ee55c1e5d524887d43f33/trace_processor_shell"
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/93825934c10d3a8179e1b8b840bbe1fd7f64a913/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/accessibility/accessibility_features.cc b/ui/accessibility/accessibility_features.cc
index ff8ee8a..d37256a 100644
--- a/ui/accessibility/accessibility_features.cc
+++ b/ui/accessibility/accessibility_features.cc
@@ -196,6 +196,15 @@
 }
 
 #if BUILDFLAG(IS_WIN)
+BASE_FEATURE(kFixNarratorWebContentContainment,
+             "FixNarratorWebContentContainment",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
+bool IsFixNarratorWebContentContainmentEnabled() {
+  return base::FeatureList::IsEnabled(
+      ::features::kFixNarratorWebContentContainment);
+}
+
 BASE_FEATURE(kIChromeAccessible,
              "IChromeAccessible",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/ui/accessibility/accessibility_features.h b/ui/accessibility/accessibility_features.h
index 3820dea..609a3a46 100644
--- a/ui/accessibility/accessibility_features.h
+++ b/ui/accessibility/accessibility_features.h
@@ -154,6 +154,12 @@
 AX_BASE_EXPORT bool IsAccessibilityOnScreenAXModeEnabled();
 
 #if BUILDFLAG(IS_WIN)
+// When enabled, modify the exposed UIA accessibility tree to match Narrator's
+// expectations. This fixes a bug keeping Narrator's cursor contained within
+// the web content.
+AX_BASE_EXPORT BASE_DECLARE_FEATURE(kFixNarratorWebContentContainment);
+AX_BASE_EXPORT bool IsFixNarratorWebContentContainmentEnabled();
+
 // Use Chrome-specific accessibility COM API.
 AX_BASE_EXPORT BASE_DECLARE_FEATURE(kIChromeAccessible);
 AX_BASE_EXPORT bool IsIChromeAccessibleEnabled();
diff --git a/ui/color/color_provider_utils.cc b/ui/color/color_provider_utils.cc
index eb000032..e458754 100644
--- a/ui/color/color_provider_utils.cc
+++ b/ui/color/color_provider_utils.cc
@@ -143,66 +143,6 @@
 
 ColorProviderUtilsCallbacks::~ColorProviderUtilsCallbacks() = default;
 
-std::string_view ColorModeName(ColorProviderKey::ColorMode color_mode) {
-  switch (color_mode) {
-    case ColorProviderKey::ColorMode::kLight:
-      return "kLight";
-    case ColorProviderKey::ColorMode::kDark:
-      return "kDark";
-    default:
-      return "<invalid>";
-  }
-}
-
-std::string_view ContrastModeName(
-    ColorProviderKey::ContrastMode contrast_mode) {
-  switch (contrast_mode) {
-    case ColorProviderKey::ContrastMode::kNormal:
-      return "kNormal";
-    case ColorProviderKey::ContrastMode::kHigh:
-      return "kHigh";
-    default:
-      return "<invalid>";
-  }
-}
-
-std::string_view ForcedColorsName(
-    ColorProviderKey::ForcedColors forced_colors) {
-  switch (forced_colors) {
-    case ColorProviderKey::ForcedColors::kNone:
-      return "kNone";
-    case ColorProviderKey::ForcedColors::kSystem:
-      return "kSystem";
-    case ColorProviderKey::ForcedColors::kDusk:
-      return "kDusk";
-    case ColorProviderKey::ForcedColors::kDesert:
-      return "kDesert";
-    case ColorProviderKey::ForcedColors::kNightSky:
-      return "kNightSky";
-    case ColorProviderKey::ForcedColors::kWhite:
-      return "kWhite";
-    case ColorProviderKey::ForcedColors::kAquatic:
-      return "kAquatic";
-    default:
-      return "<invalid>";
-  }
-}
-
-std::string_view SystemThemeName(ui::SystemTheme system_theme) {
-  switch (system_theme) {
-    case ui::SystemTheme::kDefault:
-      return "kDefault";
-#if BUILDFLAG(IS_LINUX)
-    case ui::SystemTheme::kGtk:
-      return "kGtk";
-    case ui::SystemTheme::kQt:
-      return "kQt";
-#endif
-    default:
-      return "<invalid>";
-  }
-}
-
 #include "ui/color/color_id_map_macros.inc"
 
 std::string ColorIdName(ColorId color_id) {
diff --git a/ui/color/color_provider_utils.h b/ui/color/color_provider_utils.h
index 01c6987..019223a 100644
--- a/ui/color/color_provider_utils.h
+++ b/ui/color/color_provider_utils.h
@@ -32,22 +32,6 @@
 // logging. Do not retain the results for longer than the scope in which these
 // functions are called.
 
-// Converts the ColorMode.
-std::string_view COMPONENT_EXPORT(COLOR)
-    ColorModeName(ColorProviderKey::ColorMode color_mode);
-
-// Converts the ContrastMode.
-std::string_view COMPONENT_EXPORT(COLOR)
-    ContrastModeName(ColorProviderKey::ContrastMode contrast_mode);
-
-// Converts the ForcedColors.
-std::string_view COMPONENT_EXPORT(COLOR)
-    ForcedColorsName(ColorProviderKey::ForcedColors forced_colors);
-
-// Converts SystemTheme.
-std::string_view COMPONENT_EXPORT(COLOR)
-    SystemThemeName(ui::SystemTheme system_theme);
-
 // Converts ColorId.
 std::string COMPONENT_EXPORT(COLOR) ColorIdName(ColorId color_id);
 
diff --git a/ui/color/win/native_color_mixers_win.cc b/ui/color/win/native_color_mixers_win.cc
index 179dc53..f18031f 100644
--- a/ui/color/win/native_color_mixers_win.cc
+++ b/ui/color/win/native_color_mixers_win.cc
@@ -21,7 +21,6 @@
 #include "ui/color/color_transform.h"
 #include "ui/color/win/accent_color_observer.h"
 #include "ui/gfx/color_palette.h"
-#include "ui/gfx/color_utils.h"
 
 namespace ui {
 
diff --git a/ui/views/accessibility/view_accessibility.cc b/ui/views/accessibility/view_accessibility.cc
index 752ab583..e5943a0 100644
--- a/ui/views/accessibility/view_accessibility.cc
+++ b/ui/views/accessibility/view_accessibility.cc
@@ -968,11 +968,27 @@
 }
 
 void ViewAccessibility::OnViewAddedToWidget() {
-  // Ideally, we would like to set the class name when the object is created,
-  // this would be done in the ctor, but due to inheritance and the
-  // implementation of `GetClassName`, it would not work. As such, we set it
-  // here, since at this point the view object is fully initialized.
-  SetClassName(std::string(view_->GetClassName()));
+  // The accessibility class name is set after the view has been attached
+  // to a widget, ensuring the object is fully constructed and its class
+  // name is stable.
+  std::string effective_class = std::string(view_->GetClassName());
+
+#if BUILDFLAG(IS_WIN)
+  // On Windows, Narrator restricts focus to web content in Scan Mode only when
+  // the root web area’s parent has class name "Chrome_WidgetWin_1". This is a
+  // hardcoded behavior. It worked before Chromium enabled UIA by default, since
+  // the MSAA Proxy added the root web area under a window with that class name.
+  // We’re collaborating with the Narrator team to update their tab detection
+  // logic, but rollout will take time. This is a temporary mitigation. See
+  // https://crbug.com/443225250 for details.
+  if (::ui::AXPlatform::GetInstance().IsUiaProviderEnabled() &&
+      features::IsFixNarratorWebContentContainmentEnabled() &&
+      effective_class == "ContentsContainerView") {
+    effective_class = "Chrome_WidgetWin_1";
+  }
+#endif  // BUILDFLAG(IS_WIN)
+
+  SetClassName(effective_class);
 }
 
 void ViewAccessibility::SetPlaceholder(const std::string& placeholder) {
diff --git a/url/third_party/mozilla/README.chromium b/url/third_party/mozilla/README.chromium
index 94c80db..bac6348 100644
--- a/url/third_party/mozilla/README.chromium
+++ b/url/third_party/mozilla/README.chromium
@@ -1,7 +1,7 @@
 Name: url_parse
 Version: unknown
 URL: https://hg.mozilla.org/mozilla-central/file/tip/netwerk/base/nsURLParsers.cpp
-License: MPLv2
+License: MPL-2
 License File: LICENSE.txt
 Shipped: yes
 Security Critical: yes