diff --git a/.gitmodules b/.gitmodules
index 8f49c126..5091812 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -607,6 +607,10 @@
 	path = chrome/browser/nearby_sharing/internal
 	url = https://chrome-internal.googlesource.com/chrome/browser/nearby_sharing/internal.git
 	gclient-condition = checkout_src_internal
+[submodule "chrome/browser/resources/chromeos/quickoffice"]
+	path = chrome/browser/resources/chromeos/quickoffice
+	url = https://chrome-internal.googlesource.com/quickoffice/crx.git
+	gclient-condition = (checkout_chromeos or checkout_linux) and checkout_src_internal
 [submodule "chrome/browser/resources/settings_internal"]
 	path = chrome/browser/resources/settings_internal
 	url = https://chrome-internal.googlesource.com/chrome/browser/resources/settings_internal.git
diff --git a/DEPS b/DEPS
index 784a2d76..9c146def 100644
--- a/DEPS
+++ b/DEPS
@@ -256,7 +256,7 @@
   # luci-go CIPD package version.
   # Make sure the revision is uploaded by infra-packagers builder.
   # https://ci.chromium.org/p/infra-internal/g/infra-packagers/console
-  'luci_go': 'git_revision:540222a3d0b11c1370539a1f698643113a0ee029',
+  'luci_go': 'git_revision:bd7ce256f73f85cb75c630b40afa382cdf7fcc51',
 
   # This can be overridden, e.g. with custom_vars, to build clang from HEAD
   # instead of downloading the prebuilt pinned revision.
@@ -305,15 +305,15 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'src_internal_revision': 'd478c0ffef4852b4e4d56a6fd914a9e0e94653d2',
+  'src_internal_revision': '5a392040dbeaedc5f2cfabe8ac08793c446f8d6c',
   # 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': '6ff0fdf79bfa8baf79c778e2713f4aa01fba26a6',
+  'skia_revision': '65a5cd082bea45d16a7b4a251934acc632e77032',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '67b89a482182b443a888dac94e96767526ec08f9',
+  'v8_revision': 'eb5ccbd8cda19af0d91ad55fb750637a3ec0f0b8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
@@ -325,7 +325,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '6a34da391b15f5373247fda48c10a12bc4143c94',
+  'pdfium_revision': '7233e99fcaeb18adbf048be2df0b1cca355abc70',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -380,7 +380,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '2cb6e99795633dee1ea15183629bbc98f335702c',
+  'catapult_revision': 'f25d23e77a963e88af9199c7c3a0638268e44538',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling chromium_variations
   # and whatever else without interference from each other.
@@ -400,7 +400,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': '58176c04eea85c8e8746c2142a7cc3cb4c9e9553',
+  'devtools_frontend_revision': 'cef1d4d47c8c59859778863f2ab83b7b9db68aa3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -424,7 +424,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': '3e56a384d541a9340164373c5640585401933b14',
+  'dawn_revision': 'd3e897d992221ddddce7a9a7893fa66db8559c52',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -468,7 +468,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.
-  'cros_components_revision': 'c33fd88eeac4c67cd038ad565ddd94e17093e165',
+  'cros_components_revision': 'ccadd234bf9dfa004a69560ed58874a857541e19',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -824,7 +824,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    'f88561d375f33d5fb658a55f7dba75e0bb41780a',
+    'dcf0a93ec1e24456a5d335b278c99775a58dc7c6',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1046,7 +1046,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_build_tools/lint',
-               'version': 'aCHp55GHeldC4gUHZhm4HHX0nRp0Hr4x13l8t-xO_EoC',
+               'version': 'WRfTG1DnMqZHCdWAtNv2HfU9XUBWoAN58YlHtYB-vKEC',
           },
       ],
       'condition': 'checkout_android',
@@ -1057,7 +1057,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_build_tools/manifest_merger',
-               'version': 'doEA4zEMMRwIiYmB3veT2pt-7z3UasxhbTo279pDV40C',
+               'version': 'kyXImK5GOP19ROuy-2wf_I_zzcVr2RVsPvB0jhLyrCEC',
           },
       ],
       'condition': 'checkout_android',
@@ -1218,13 +1218,13 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '88cc0b8ca8ab9103b94db6552e9f1ed4789445a8',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'dbd29671bd11c2d59fa898722bdbbcb7d48b8f8b',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '145e21383e933fc2247a6f54e04772ac246f3763',
+      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '34951c1d294f6e511c2ce3ecb17973a3a37cc1af',
     'condition': 'checkout_src_internal',
   },
 
@@ -1871,7 +1871,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'f4bf599a8b575df685c31d9c4729a70a04e377ed',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '04c09a823d9601c256b97ee1ffeef796d7d8f5fa',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '8eee61b66c5987e48fed3fc362910a52f91eb1ca',
 
   'src/third_party/webrtc':
     Var('webrtc_git') + '/src.git' + '@' + '283a5fd7ec64d231b1369843ac24d18222ecfde7',
@@ -3856,6 +3856,12 @@
       'condition': 'checkout_src_internal',
   },
 
+  'src/chrome/browser/resources/chromeos/quickoffice': {
+      'url': Var('chrome_git') + '/quickoffice/crx.git' + '@' +
+        '23bde3495989fbc0112213613d2498030be51417',
+      'condition': '(checkout_chromeos or checkout_linux) and checkout_src_internal',
+  },
+
   'src/chrome/browser/resources/settings_internal': {
       'url': Var('chrome_git') + '/chrome/browser/resources/settings_internal.git' + '@' +
         '5d6316b2434986e6b073e1d24585578bb27da451', # from svn revision 41419
@@ -4031,7 +4037,7 @@
 
   'src/remoting/android/internal': {
       'url': Var('chrome_git') + '/chrome/remoting/android/internal.git' + '@' +
-        'd4b268b20d45eeb46d9c7cb2b9d88f921254fdae',
+        '016a13fdc552a86d4ca8e730f156e6487c93056b',
       'condition': 'checkout_android and checkout_src_internal',
   },
 
diff --git a/WATCHLISTS b/WATCHLISTS
index 7d7cab2..764f3cc 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -2439,6 +2439,7 @@
     'aura': ['sadrul@chromium.org'],
     'aura_compositor': ['jbauman+watch@chromium.org'],
     'autofill_payments': ['armalhotra+autofillwatch@google.com',
+                          'feliciac+autofillwatch@google.com',
                           'jsaul+autofillwatch@google.com',
                           'shgar+autofillwatch@google.com',
                           'siashah+autofillwatch@chromium.org',
diff --git a/android_webview/browser/aw_autofill_client.cc b/android_webview/browser/aw_autofill_client.cc
index feed1d3..5714091 100644
--- a/android_webview/browser/aw_autofill_client.cc
+++ b/android_webview/browser/aw_autofill_client.cc
@@ -128,7 +128,8 @@
   return nullptr;
 }
 
-autofill::payments::PaymentsClient* AwAutofillClient::GetPaymentsClient() {
+autofill::payments::PaymentsNetworkInterface*
+AwAutofillClient::GetPaymentsNetworkInterface() {
   return nullptr;
 }
 
diff --git a/android_webview/browser/aw_autofill_client.h b/android_webview/browser/aw_autofill_client.h
index 73b7ad1..f8941b7d 100644
--- a/android_webview/browser/aw_autofill_client.h
+++ b/android_webview/browser/aw_autofill_client.h
@@ -91,7 +91,8 @@
   syncer::SyncService* GetSyncService() override;
   signin::IdentityManager* GetIdentityManager() override;
   autofill::FormDataImporter* GetFormDataImporter() override;
-  autofill::payments::PaymentsClient* GetPaymentsClient() override;
+  autofill::payments::PaymentsNetworkInterface* GetPaymentsNetworkInterface()
+      override;
   autofill::StrikeDatabase* GetStrikeDatabase() override;
   ukm::UkmRecorder* GetUkmRecorder() override;
   ukm::SourceId GetUkmSourceId() override;
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 57e5775..668f6e7 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -4080,6 +4080,7 @@
     "system/time/calendar_unittest_utils.h",
     "system/time/calendar_up_next_pixeltest.cc",
     "system/time/calendar_view_pixeltest.cc",
+    "system/toast/system_nudge_view_pixeltest.cc",
     "system/toast/system_toast_view_pixeltest.cc",
     "system/unified/date_tray_pixeltest.cc",
     "system/unified/feature_tile_pixeltest.cc",
diff --git a/ash/app_list/views/app_list_item_view.cc b/ash/app_list/views/app_list_item_view.cc
index 8812863..c461c30 100644
--- a/ash/app_list/views/app_list_item_view.cc
+++ b/ash/app_list/views/app_list_item_view.cc
@@ -1729,6 +1729,14 @@
           GetColorProvider()->GetColor(GetBackgroundLayerColorId()));
     }
   }
+
+  UpdateIconView(/*update_item_icon=*/true);
+
+  // Redraw progress indicator to adjust colors.
+  if (progress_indicator_) {
+    progress_indicator_->InvalidateLayer();
+  }
+
   SchedulePaint();
 }
 
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 6396dd39..8582aa18 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -804,6 +804,9 @@
       <message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_TOGGLE_END_BUTTON" translateable="false" desc="The text used for the label of the toggle button in the focus mode detailed view and countdown view for when focus mode is active.">
         End Focus
       </message>
+      <message name="IDS_ASH_STATUS_TRAY_FOCUS_MODE_FIRST_TIME_SUBLABEL" translateable="false" desc="The text used for the sublabel of the detailed view toggle row for when a user has never used focus mode before.">
+        Set a timer and task to focus
+      </message>
 
       <message name="IDS_ASH_STATUS_TRAY_UPDATE" desc="The label used in the tray popup to notify that the user should restart to get system updates.">
         Restart to update
diff --git a/ash/components/arc/mojom/app.mojom b/ash/components/arc/mojom/app.mojom
index 229a69e..a68f06ed 100644
--- a/ash/components/arc/mojom/app.mojom
+++ b/ash/components/arc/mojom/app.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Next MinVersion: 62
+// Next MinVersion: 63
 
 module arc.mojom;
 
@@ -16,6 +16,8 @@
 struct InstallationResult {
   string package_name;
   bool success;  // true if app was installed successfully.
+  [MinVersion=62] bool is_launchable_app; // true if the package installed
+                                          // successfully and is launchable.
 };
 
 // Describes application storage.
diff --git a/ash/components/arc/test/fake_app_instance.cc b/ash/components/arc/test/fake_app_instance.cc
index db7286e..befb28f 100644
--- a/ash/components/arc/test/fake_app_instance.cc
+++ b/ash/components/arc/test/fake_app_instance.cc
@@ -290,10 +290,12 @@
 }
 
 void FakeAppInstance::SendInstallationFinished(const std::string& package_name,
-                                               bool success) {
+                                               bool success,
+                                               bool is_launchable_app) {
   mojom::InstallationResult result;
   result.package_name = package_name;
   result.success = success;
+  result.is_launchable_app = is_launchable_app;
   app_host_->OnInstallationFinished(
       mojom::InstallationResultPtr(result.Clone()));
 }
diff --git a/ash/components/arc/test/fake_app_instance.h b/ash/components/arc/test/fake_app_instance.h
index b5eb4128..4660ab6c 100644
--- a/ash/components/arc/test/fake_app_instance.h
+++ b/ash/components/arc/test/fake_app_instance.h
@@ -194,7 +194,9 @@
   void SendPackageUninstalled(const std::string& pacakge_name);
 
   void SendInstallationStarted(const std::string& package_name);
-  void SendInstallationFinished(const std::string& package_name, bool success);
+  void SendInstallationFinished(const std::string& package_name,
+                                bool success,
+                                bool is_launchable_app = true);
   void SendInstallationProgressChanged(const std::string& package_name,
                                        float progress);
   void SendInstallationActiveChanged(const std::string& package_name,
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 4d75ec2..c2dea6c8 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -2257,7 +2257,7 @@
              base::FEATURE_ENABLED_BY_DEFAULT);
 
 // Controls whether to show promise icons during app installations.
-BASE_FEATURE(kPromiseIcons, "PromiseIcons", base::FEATURE_DISABLED_BY_DEFAULT);
+BASE_FEATURE(kPromiseIcons, "PromiseIcons", base::FEATURE_ENABLED_BY_DEFAULT);
 
 // Controls whether to show promise icons during web app installations.
 BASE_FEATURE(kPromiseIconsForWebApps,
diff --git a/ash/shelf/shelf_app_button.cc b/ash/shelf/shelf_app_button.cc
index 86a2ac79..c074bee 100644
--- a/ash/shelf/shelf_app_button.cc
+++ b/ash/shelf/shelf_app_button.cc
@@ -1064,6 +1064,17 @@
   Layout();
 }
 
+void ShelfAppButton::OnThemeChanged() {
+  views::Button::OnThemeChanged();
+
+  UpdateIconImage();
+
+  // Redraw progress indicator to adjust colors.
+  if (progress_indicator_) {
+    progress_indicator_->InvalidateLayer();
+  }
+}
+
 void ShelfAppButton::OnGestureEvent(ui::GestureEvent* event) {
   switch (event->type()) {
     case ui::ET_GESTURE_TAP_DOWN:
diff --git a/ash/shelf/shelf_app_button.h b/ash/shelf/shelf_app_button.h
index 449f4db..7759a1f 100644
--- a/ash/shelf/shelf_app_button.h
+++ b/ash/shelf/shelf_app_button.h
@@ -129,6 +129,7 @@
   bool OnMouseDragged(const ui::MouseEvent& event) override;
   void Layout() override;
   void ChildPreferredSizeChanged(views::View* child) override;
+  void OnThemeChanged() override;
 
   // Update button state from ShelfItem.
   void ReflectItemStatus(const ShelfItem& item);
diff --git a/ash/system/focus_mode/focus_mode_controller.cc b/ash/system/focus_mode/focus_mode_controller.cc
index 8b263f27..f37d492 100644
--- a/ash/system/focus_mode/focus_mode_controller.cc
+++ b/ash/system/focus_mode/focus_mode_controller.cc
@@ -190,6 +190,17 @@
   }
 }
 
+bool FocusModeController::HasStartedSessionBefore() const {
+  // Since `kFocusModeDoNotDisturb` is always set whenever a focus session is
+  // started, we can use this as an indicator of if the user has ever started a
+  // focus session before.
+  if (PrefService* active_user_prefs =
+          Shell::Get()->session_controller()->GetActivePrefService()) {
+    return active_user_prefs->HasPrefPath(prefs::kFocusModeDoNotDisturb);
+  }
+  return false;
+}
+
 void FocusModeController::OnTimerTick() {
   if (in_focus_session_ && base::Time::Now() >= end_time_) {
     ToggleFocusMode();
@@ -202,17 +213,17 @@
 }
 
 void FocusModeController::UpdateFromUserPrefs() {
-  PrefService* primary_user_prefs =
+  PrefService* active_user_prefs =
       Shell::Get()->session_controller()->GetActivePrefService();
-  if (!primary_user_prefs) {
+  if (!active_user_prefs) {
     // Can be null in tests.
     return;
   }
 
   session_duration_ =
-      primary_user_prefs->GetTimeDelta(prefs::kFocusModeSessionDuration);
+      active_user_prefs->GetTimeDelta(prefs::kFocusModeSessionDuration);
   turn_on_do_not_disturb_ =
-      primary_user_prefs->GetBoolean(prefs::kFocusModeDoNotDisturb);
+      active_user_prefs->GetBoolean(prefs::kFocusModeDoNotDisturb);
 
   if (session_duration_ <= base::TimeDelta()) {
     session_duration_ = kDefaultSessionDuration;
@@ -220,12 +231,12 @@
 }
 
 void FocusModeController::SaveSettingsToUserPrefs() {
-  if (PrefService* primary_user_prefs =
+  if (PrefService* active_user_prefs =
           Shell::Get()->session_controller()->GetActivePrefService()) {
-    primary_user_prefs->SetTimeDelta(prefs::kFocusModeSessionDuration,
-                                     session_duration_);
-    primary_user_prefs->SetBoolean(prefs::kFocusModeDoNotDisturb,
-                                   turn_on_do_not_disturb_);
+    active_user_prefs->SetTimeDelta(prefs::kFocusModeSessionDuration,
+                                    session_duration_);
+    active_user_prefs->SetBoolean(prefs::kFocusModeDoNotDisturb,
+                                  turn_on_do_not_disturb_);
   }
 }
 
diff --git a/ash/system/focus_mode/focus_mode_controller.h b/ash/system/focus_mode/focus_mode_controller.h
index f684e7b..6d1f7a2 100644
--- a/ash/system/focus_mode/focus_mode_controller.h
+++ b/ash/system/focus_mode/focus_mode_controller.h
@@ -68,6 +68,9 @@
   // during an active focus session.
   void SetSessionDuration(const base::TimeDelta& new_session_duration);
 
+  // Returns whether the user has ever started a focus session previously.
+  bool HasStartedSessionBefore() const;
+
  private:
   void SetEnabled(bool enabled);
 
diff --git a/ash/system/focus_mode/focus_mode_controller_unittest.cc b/ash/system/focus_mode/focus_mode_controller_unittest.cc
index 2646984b..bffc7be 100644
--- a/ash/system/focus_mode/focus_mode_controller_unittest.cc
+++ b/ash/system/focus_mode/focus_mode_controller_unittest.cc
@@ -151,4 +151,14 @@
   EXPECT_TRUE(system_tray->IsBubbleShown());
 }
 
+// Tests that we can determine if a focus session has started before.
+TEST_F(FocusModeControllerMultiUserTest, FirstTimeUserFlow) {
+  SimulateUserLogin(GetUser1AccountId());
+  auto* controller = FocusModeController::Get();
+  EXPECT_FALSE(controller->HasStartedSessionBefore());
+
+  FocusModeController::Get()->ToggleFocusMode();
+  EXPECT_TRUE(controller->HasStartedSessionBefore());
+}
+
 }  // namespace ash
diff --git a/ash/system/focus_mode/focus_mode_detailed_view.cc b/ash/system/focus_mode/focus_mode_detailed_view.cc
index 64684208..066943a0 100644
--- a/ash/system/focus_mode/focus_mode_detailed_view.cc
+++ b/ash/system/focus_mode/focus_mode_detailed_view.cc
@@ -35,7 +35,6 @@
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/vector_icon_types.h"
-#include "ui/message_center/message_center.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/highlight_path_generator.h"
 #include "ui/views/controls/label.h"
@@ -341,6 +340,13 @@
   TypographyProvider::Get()->StyleLabel(ash::TypographyToken::kCrosButton1,
                                         *toggle_view_->text_label());
 
+  // As part of the first time user flow, if the user has never started a
+  // session before, we want to provide description text.
+  if (!focus_mode_controller->HasStartedSessionBefore()) {
+    toggle_view_->SetSubText(l10n_util::GetStringUTF16(
+        IDS_ASH_STATUS_TRAY_FOCUS_MODE_FIRST_TIME_SUBLABEL));
+  }
+
   if (in_focus_session) {
     cached_end_time_ = focus_mode_controller->end_time();
     toggle_view_->SetSubText(
diff --git a/ash/system/focus_mode/focus_mode_detailed_view_unittest.cc b/ash/system/focus_mode/focus_mode_detailed_view_unittest.cc
index af3b2d9..7c84d274 100644
--- a/ash/system/focus_mode/focus_mode_detailed_view_unittest.cc
+++ b/ash/system/focus_mode/focus_mode_detailed_view_unittest.cc
@@ -7,7 +7,9 @@
 #include <memory>
 
 #include "ash/constants/ash_features.h"
+#include "ash/constants/ash_pref_names.h"
 #include "ash/shell.h"
+#include "ash/strings/grit/ash_strings.h"
 #include "ash/style/icon_button.h"
 #include "ash/style/pill_button.h"
 #include "ash/style/switch.h"
@@ -18,15 +20,12 @@
 #include "ash/system/model/system_tray_model.h"
 #include "ash/system/tray/fake_detailed_view_delegate.h"
 #include "ash/system/tray/hover_highlight_view.h"
-#include "ash/system/tray/tri_view.h"
 #include "ash/test/ash_test_base.h"
 #include "base/i18n/time_formatting.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "base/time/time.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/events/keycodes/keyboard_codes_posix.h"
 #include "ui/message_center/message_center.h"
 #include "ui/views/controls/label.h"
@@ -50,6 +49,12 @@
     widget_ = CreateFramelessTestWidget();
     widget_->SetFullscreen(true);
 
+    // Focus Mode considers it to be a first time user flow if
+    // `kFocusModeDoNotDisturb` has never been set by the user before. For
+    // normal feature testing purposes, we will intentionally set it so that the
+    // pref will not be marked as using the default value.
+    prefs()->SetBoolean(prefs::kFocusModeDoNotDisturb, true);
+
     CreateFakeFocusModeDetailedView();
   }
 
@@ -82,6 +87,10 @@
     return focus_mode_detailed_view_->toggle_view_->sub_text_label();
   }
 
+  bool IsToggleRowSubLabelVisible() {
+    return GetToggleRowSubLabel() && GetToggleRowSubLabel()->GetVisible();
+  }
+
   PillButton* GetToggleRowButton() {
     return views::AsViewClass<PillButton>(
         focus_mode_detailed_view_->toggle_view_->right_view());
@@ -117,6 +126,10 @@
     return focus_mode_detailed_view_->end_time_label_;
   }
 
+  PrefService* prefs() {
+    return Shell::Get()->session_controller()->GetActivePrefService();
+  }
+
   FakeDetailedViewDelegate detailed_view_delegate_;
 
  private:
@@ -231,8 +244,7 @@
     EXPECT_EQ(active, focus_mode_controller->in_focus_session());
     EXPECT_EQ(active ? u"Focusing" : u"Focus", GetToggleRowLabel()->GetText());
 
-    EXPECT_EQ(active,
-              GetToggleRowSubLabel() && GetToggleRowSubLabel()->GetVisible());
+    EXPECT_EQ(active, IsToggleRowSubLabelVisible());
 
     if (active) {
       EXPECT_EQ(focus_mode_util::GetFormattedEndTimeString(
@@ -499,4 +511,29 @@
             GetEndTimeLabel()->GetText());
 }
 
+// Verify that the toggle row sublabel is shown in the first time user flow.
+TEST_F(FocusModeDetailedViewTest, FirstTimeUserFlow) {
+  // Clear `kFocusModeDoNotDisturb` to trigger the first time user flow.
+  prefs()->ClearPref(prefs::kFocusModeDoNotDisturb);
+
+  // Recreate the detailed view so that the UI is updated after we set the user
+  // pref.
+  CreateFakeFocusModeDetailedView();
+
+  // Verify that the first time user flow text is displayed.
+  EXPECT_TRUE(IsToggleRowSubLabelVisible());
+  EXPECT_EQ(GetToggleRowSubLabel()->GetText(),
+            l10n_util::GetStringUTF16(
+                IDS_ASH_STATUS_TRAY_FOCUS_MODE_FIRST_TIME_SUBLABEL));
+
+  // Start and stop a focus session. This puts us back into the focus panel
+  // outside of the first time user flow.
+  LeftClickOn(GetToggleRowButton());
+  CreateFakeFocusModeDetailedView();
+  LeftClickOn(GetToggleRowButton());
+
+  // Verify that the first time user flow text no longer is displayed.
+  EXPECT_FALSE(IsToggleRowSubLabelVisible());
+}
+
 }  // namespace ash
diff --git a/ash/system/focus_mode/focus_mode_feature_pod_controller.cc b/ash/system/focus_mode/focus_mode_feature_pod_controller.cc
index c79bc1e6..9031891 100644
--- a/ash/system/focus_mode/focus_mode_feature_pod_controller.cc
+++ b/ash/system/focus_mode/focus_mode_feature_pod_controller.cc
@@ -11,7 +11,6 @@
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/focus_mode/focus_mode_controller.h"
 #include "ash/system/focus_mode/focus_mode_util.h"
-#include "ash/system/unified/feature_pod_button.h"
 #include "ash/system/unified/feature_tile.h"
 #include "ash/system/unified/unified_system_tray_controller.h"
 #include "base/check.h"
@@ -65,6 +64,16 @@
 
 void FocusModeFeaturePodController::OnIconPressed() {
   auto* controller = FocusModeController::Get();
+
+  // As part of the first time user flow, if the user has never started a
+  // session before, we want to direct them to the focus panel so they can get
+  // more context and change focus settings instead of starting a session
+  // immediately.
+  if (!controller->HasStartedSessionBefore()) {
+    OnLabelPressed();
+    return;
+  }
+
   TrackToggleUMA(/*target_toggle_state=*/!controller->in_focus_session());
   controller->ToggleFocusMode();
 }
@@ -96,6 +105,14 @@
   tile_->SetIconButtonTooltipText(label_text);
   tile_->SetTooltipText(label_text);
 
+  // As part of the first time user flow, if the user has never started a
+  // session before, we hide the session duration sublabel since they are not
+  // able to start a focus session immediately anyway.
+  if (!controller->HasStartedSessionBefore()) {
+    tile_->SetSubLabelVisibility(false);
+    return;
+  }
+
   const base::TimeDelta session_duration_remaining =
       in_focus_session ? controller->end_time() - base::Time::Now()
                        : controller->session_duration();
diff --git a/ash/system/focus_mode/focus_mode_feature_pod_controller_unittest.cc b/ash/system/focus_mode/focus_mode_feature_pod_controller_unittest.cc
index e048abf..eebfa918 100644
--- a/ash/system/focus_mode/focus_mode_feature_pod_controller_unittest.cc
+++ b/ash/system/focus_mode/focus_mode_feature_pod_controller_unittest.cc
@@ -7,6 +7,8 @@
 #include <memory>
 
 #include "ash/constants/ash_features.h"
+#include "ash/constants/ash_pref_names.h"
+#include "ash/shell.h"
 #include "ash/system/focus_mode/focus_mode_controller.h"
 #include "ash/system/focus_mode/focus_mode_detailed_view.h"
 #include "ash/system/unified/feature_tile.h"
@@ -31,6 +33,13 @@
   // AshTestBase:
   void SetUp() override {
     AshTestBase::SetUp();
+
+    // Focus Mode considers it to be a first time user flow if
+    // `kFocusModeDoNotDisturb` has never been set by the user before. For
+    // normal feature testing purposes, we will intentionally set it so that the
+    // pref will not be marked as using the default value.
+    prefs()->SetBoolean(prefs::kFocusModeDoNotDisturb, true);
+
     CreateFakeFocusModeTile();
   }
 
@@ -61,6 +70,10 @@
     EXPECT_TRUE(views::IsViewClass<FocusModeDetailedView>(detailed_view));
   }
 
+  PrefService* prefs() {
+    return Shell::Get()->session_controller()->GetActivePrefService();
+  }
+
  protected:
   base::test::ScopedFeatureList feature_list_;
   std::unique_ptr<FocusModeFeaturePodController> controller_;
@@ -112,4 +125,46 @@
   ExpectFocusModeDetailedViewShown();
 }
 
+// Verify that the tile operates correctly for the first time user flow. This
+// includes:
+// - The session duration is hidden.
+// - Clicking the tile icon shows to the focus mode detailed view.
+TEST_F(FocusModeFeaturePodControllerTest, FirstTimeUserFlow) {
+  // Clear `kFocusModeDoNotDisturb` to trigger the first time user flow.
+  prefs()->ClearPref(prefs::kFocusModeDoNotDisturb);
+
+  // Recreate the tile so that the UI is updated after we set the user pref.
+  CreateFakeFocusModeTile();
+
+  // Verify that the tile sub label is hidden for the first time user flow.
+  auto* focus_mode_controller = FocusModeController::Get();
+  EXPECT_FALSE(focus_mode_controller->in_focus_session());
+  EXPECT_FALSE(tile_->sub_label()->GetVisible());
+
+  // Verify that clicking the icon does not start the focus session for the
+  // first time user flow, but instead shows the focus mode detailed view.
+  controller_->OnIconPressed();
+  EXPECT_FALSE(focus_mode_controller->in_focus_session());
+  ExpectFocusModeDetailedViewShown();
+
+  // Start a session, and recreate the tile since the bubble was closed.
+  focus_mode_controller->ToggleFocusMode();
+  CreateFakeFocusModeTile();
+
+  // Verify that the tile sub label should be visible.
+  EXPECT_TRUE(focus_mode_controller->in_focus_session());
+  EXPECT_TRUE(tile_->sub_label()->GetVisible());
+
+  // End a session. Check that the tile session duration text is now visible,
+  // and is not hidden since we are no longer in the first time user flow.
+  focus_mode_controller->ToggleFocusMode();
+  EXPECT_FALSE(focus_mode_controller->in_focus_session());
+  EXPECT_TRUE(tile_->sub_label()->GetVisible());
+
+  // Verify that clicking the icon goes back to the normal flow of and starting
+  // a Focus Mode Session.
+  controller_->OnIconPressed();
+  EXPECT_TRUE(focus_mode_controller->in_focus_session());
+}
+
 }  // namespace ash
diff --git a/ash/system/holding_space/pinned_files_section.cc b/ash/system/holding_space/pinned_files_section.cc
index dfc76ed2..15aa716 100644
--- a/ash/system/holding_space/pinned_files_section.cc
+++ b/ash/system/holding_space/pinned_files_section.cc
@@ -73,6 +73,17 @@
     return true;
   }
 
+  // If the model is empty and the holding space wallpaper nudge is enabled,
+  // then we need to show the placeholder so that there is something when the
+  // user clicks the force-shown tray.
+  // TODO(http://b/307787722): Replace this with the desired final behavior for
+  // holding space wallpaper nudge.
+  if (features::IsHoldingSpaceWallpaperNudgeEnabled() &&
+      HoldingSpaceController::Get()->model() &&
+      !HoldingSpaceController::Get()->model()->items().empty()) {
+    return true;
+  }
+
   // The placeholder should only be shown if:
   // * a holding space item has been added at some point in time,
   // * a holding space item has *never* been pinned, and
diff --git a/ash/system/network/network_feature_tile_pixeltest.cc b/ash/system/network/network_feature_tile_pixeltest.cc
index 80e01ac..406a4d3 100644
--- a/ash/system/network/network_feature_tile_pixeltest.cc
+++ b/ash/system/network/network_feature_tile_pixeltest.cc
@@ -11,6 +11,7 @@
 #include "chromeos/ash/components/network/network_state_test_helper.h"
 #include "chromeos/ash/services/network_config/public/cpp/cros_network_config_test_helper.h"
 #include "chromeos/constants/chromeos_features.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 
@@ -55,7 +56,19 @@
     widget_ = CreateFramelessTestWidget();
     widget_->SetFullscreen(true);
 
-    feature_tile_ = widget_->SetContentsView(std::move(feature_tile));
+    auto* contents =
+        widget_->SetContentsView(std::make_unique<views::BoxLayoutView>());
+    contents->SetMainAxisAlignment(
+        views::BoxLayout::MainAxisAlignment::kCenter);
+    contents->SetCrossAxisAlignment(
+        views::BoxLayout::CrossAxisAlignment::kCenter);
+    // The tile colors have transparency, so set a background color so they
+    // render like in production.
+    contents->SetBackground(views::CreateThemedSolidBackground(
+        cros_tokens::kCrosSysSystemBaseElevated));
+
+    feature_tile_ =
+        widget_->GetContentsView()->AddChildView(std::move(feature_tile));
 
     // Add the non-default cellular and ethernet devices to Shill.
     network_state_helper()->manager_test()->AddTechnology(shill::kTypeCellular,
@@ -141,7 +154,7 @@
   ASSERT_TRUE(tile_view);
   EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
       "check_tile_view",
-      /*revision_number=*/2, tile_view));
+      /*revision_number=*/3, tile_view));
 }
 
 TEST_F(NetworkFeatureTilePixelTest, Ethernet) {
@@ -153,7 +166,7 @@
   ASSERT_TRUE(tile_view);
   EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
       "check_tile_view",
-      /*revision_number=*/1, tile_view));
+      /*revision_number=*/2, tile_view));
 }
 
 TEST_F(NetworkFeatureTilePixelTest, Wifi) {
@@ -165,7 +178,7 @@
   ASSERT_TRUE(tile_view);
   EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
       "check_tile_view",
-      /*revision_number=*/1, tile_view));
+      /*revision_number=*/2, tile_view));
 }
 
 TEST_F(NetworkFeatureTilePixelTest, WifiSecurity) {
@@ -177,7 +190,7 @@
   ASSERT_TRUE(tile_view);
   EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
       "check_tile_view",
-      /*revision_number=*/0, tile_view));
+      /*revision_number=*/1, tile_view));
 }
 
 TEST_F(NetworkFeatureTilePixelTest, Cellular) {
@@ -189,7 +202,7 @@
   ASSERT_TRUE(tile_view);
   EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
       "check_tile_view",
-      /*revision_number=*/1, tile_view));
+      /*revision_number=*/2, tile_view));
 }
 
 }  // namespace ash
diff --git a/ash/system/power/adaptive_charging_controller.cc b/ash/system/power/adaptive_charging_controller.cc
index 21b26a1e..399b988f 100644
--- a/ash/system/power/adaptive_charging_controller.cc
+++ b/ash/system/power/adaptive_charging_controller.cc
@@ -15,7 +15,7 @@
 
 #if DCHECK_IS_ON()
 // Fake input for notification testing.
-constexpr int kFakeNotificationInputForTesting = 8;
+constexpr base::TimeDelta kFakeNotificationInputForTesting = base::Hours(8);
 #endif  // DCHECK_IS_ON()
 
 }  // namespace
@@ -100,7 +100,7 @@
       proto.battery_time_to_full_sec() > 0) {
     // Converts time to full from second to hours.
     notification_controller_->ShowAdaptiveChargingNotification(
-        static_cast<int>(proto.battery_time_to_full_sec() / 3600));
+        base::Seconds(proto.battery_time_to_full_sec()));
   } else {
     notification_controller_->ShowAdaptiveChargingNotification();
   }
diff --git a/ash/system/power/adaptive_charging_notification_controller.cc b/ash/system/power/adaptive_charging_notification_controller.cc
index ec4683216..224bb8b0 100644
--- a/ash/system/power/adaptive_charging_notification_controller.cc
+++ b/ash/system/power/adaptive_charging_notification_controller.cc
@@ -38,20 +38,20 @@
     ~AdaptiveChargingNotificationController() = default;
 
 void AdaptiveChargingNotificationController::ShowAdaptiveChargingNotification(
-    absl::optional<int> hours_to_full) {
+    absl::optional<base::TimeDelta> time_to_full) {
   if (!ShouldShowNotification())
     return;
 
   std::u16string notification_message;
-  if (hours_to_full.has_value()) {
-    DCHECK_GE(hours_to_full.value(), 0);
+  if (time_to_full.has_value()) {
+    DCHECK(time_to_full.value().is_positive());
     notification_message = l10n_util::GetStringFUTF16(
         IDS_ASH_ADAPTIVE_CHARGING_NOTIFICATION_MESSAGE_TEMPORARY,
         base::TimeFormatTimeOfDayWithHourClockType(
             base::Time::FromDeltaSinceWindowsEpoch(
-                base::Time::Now().ToDeltaSinceWindowsEpoch().RoundToMultiple(
-                    kTimeDeltaRoundingInterval)) +
-                base::Hours(hours_to_full.value()),
+                (base::Time::Now().ToDeltaSinceWindowsEpoch() +
+                 time_to_full.value())
+                    .RoundToMultiple(kTimeDeltaRoundingInterval)),
             base::GetHourClockType(), base::kKeepAmPm));
   } else {
     notification_message = l10n_util::GetStringUTF16(
diff --git a/ash/system/power/adaptive_charging_notification_controller.h b/ash/system/power/adaptive_charging_notification_controller.h
index 8e08061..ff6392d9 100644
--- a/ash/system/power/adaptive_charging_notification_controller.h
+++ b/ash/system/power/adaptive_charging_notification_controller.h
@@ -9,6 +9,7 @@
 
 #include "ash/ash_export.h"
 #include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/message_center/public/cpp/notification_delegate.h"
 
@@ -27,12 +28,12 @@
   // Show the adaptive charging notification. There are two possible
   // scenarios:
   // 1. When the battery is kept at 80% indefinitely (i.e. no value of
-  // |hours_to_full| is provided), the notification is a
+  // |time_to_full| is provided), the notification is a
   // normal notification.
-  // 2. When the battery is temporary kept at 80% (i.e. |hours_to_full| has
-  // a value), the notification will have higher priority (SYSTEM_PRIORITY).
+  // 2. When the battery is temporary kept at 80% (i.e. |time_to_full| has
+  // a value), the estimated time to full will be shown.
   void ShowAdaptiveChargingNotification(
-      absl::optional<int> hours_to_full = absl::nullopt);
+      absl::optional<base::TimeDelta> time_to_full = absl::nullopt);
 
   void CloseAdaptiveChargingNotification(bool by_user = false);
 
diff --git a/ash/system/power/adaptive_charging_notification_controller_unittest.cc b/ash/system/power/adaptive_charging_notification_controller_unittest.cc
index f8d5cfe..7c331e3 100644
--- a/ash/system/power/adaptive_charging_notification_controller_unittest.cc
+++ b/ash/system/power/adaptive_charging_notification_controller_unittest.cc
@@ -79,14 +79,14 @@
   SetAdaptiveChargingPref(false);
 
   GetController()->ShowAdaptiveChargingNotification();
-  GetController()->ShowAdaptiveChargingNotification(5);
+  GetController()->ShowAdaptiveChargingNotification(base::Hours(5));
 
   EXPECT_EQ(VisibleNotificationCount(), 0u);
 }
 
 TEST_F(AdaptiveChargingNotificationControllerTest, ShowNotificationWithHour) {
   SetAdaptiveChargingPref(true);
-  GetController()->ShowAdaptiveChargingNotification(5);
+  GetController()->ShowAdaptiveChargingNotification(base::Hours(5));
 
   EXPECT_EQ(VisibleNotificationCount(), 1u);
 }
@@ -116,7 +116,7 @@
       /*thread_ticks_override=*/nullptr);
 
   SetAdaptiveChargingPref(true);
-  GetController()->ShowAdaptiveChargingNotification(5);
+  GetController()->ShowAdaptiveChargingNotification(base::Hours(5));
 
   const message_center::Notification* notification =
       message_center::MessageCenter::Get()->FindPopupNotificationById(
@@ -140,13 +140,14 @@
       []() {
         base::Time time;
         EXPECT_TRUE(base::Time::FromUTCExploded(kTestDateTimeExploded, &time));
-        return time + base::Minutes(3);  // Local time is 12:45pm.
+        return time + base::Minutes(2);  // Local time is 12:44pm.
       },
       /*time_ticks_override=*/nullptr,
       /*thread_ticks_override=*/nullptr);
 
   SetAdaptiveChargingPref(true);
-  GetController()->ShowAdaptiveChargingNotification(5);
+  GetController()->ShowAdaptiveChargingNotification(
+      base::Seconds(5 * 3600 + 120));
 
   const message_center::Notification* notification =
       message_center::MessageCenter::Get()->FindPopupNotificationById(
@@ -154,15 +155,15 @@
 
   ASSERT_TRUE(notification);
 
-  // Current local time is 12:45 pm, so 5 hours after should be 6:00pm (rounding
-  // from 5:45pm).
+  // Current local time is 12:44 pm, so 5 hours 2 mins after should be 6:00pm
+  // (rounding from 5:46pm).
   EXPECT_TRUE(base::Contains(notification->message(), u"6:00\u202fpm"));
 }
 
 TEST_F(AdaptiveChargingNotificationControllerTest,
        ClickButtonMakesNotificationDisappear) {
   SetAdaptiveChargingPref(true);
-  GetController()->ShowAdaptiveChargingNotification(5);
+  GetController()->ShowAdaptiveChargingNotification(base::Hours(5));
   EXPECT_EQ(VisibleNotificationCount(), 1u);
 
   // Notification should disappear after click.
diff --git a/ash/system/toast/system_nudge_view_pixeltest.cc b/ash/system/toast/system_nudge_view_pixeltest.cc
new file mode 100644
index 0000000..1314583
--- /dev/null
+++ b/ash/system/toast/system_nudge_view_pixeltest.cc
@@ -0,0 +1,150 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "ash/public/cpp/system/anchored_nudge_data.h"
+#include "ash/system/toast/system_nudge_view.h"
+#include "ash/test/ash_test_base.h"
+#include "ash/test/pixel/ash_pixel_differ.h"
+#include "ash/test/pixel/ash_pixel_test_init_params.h"
+#include "components/vector_icons/vector_icons.h"
+#include "ui/base/models/image_model.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/views/background.h"
+#include "ui/views/layout/flex_layout_view.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+
+namespace ash {
+
+namespace {
+
+// Creates an `AnchoredNudgeData` object with only the required elements.
+// This will create a nudge shown on its default location.
+AnchoredNudgeData CreateBaseNudgeData() {
+  // Set up nudge data contents.
+  const std::string id = "id";
+  const std::u16string body_text = u"text";
+  auto catalog_name = NudgeCatalogName::kTestCatalogName;
+
+  return AnchoredNudgeData(id, catalog_name, body_text);
+}
+
+// Nudge constants
+const std::u16string button_text = u"Button";
+const std::u16string title_text = u"Title text";
+const std::u16string long_body_text =
+    u"Nudge body text should be clear, short and succinct (80 characters "
+    u"recommended)";
+
+}  // namespace
+
+class SystemNudgeViewPixelTest : public AshTestBase {
+ public:
+  void SetUp() override {
+    AshTestBase::SetUp();
+
+    test_widget_ = CreateFramelessTestWidget();
+    // Set a size larger than the nudge max dimensions.
+    test_widget_->SetBounds(gfx::Rect(800, 600));
+    test_widget_->SetContentsView(
+        views::Builder<views::FlexLayoutView>()
+            .SetMainAxisAlignment(views::LayoutAlignment::kCenter)
+            .SetCrossAxisAlignment(views::LayoutAlignment::kCenter)
+            .SetBackground(views::CreateThemedSolidBackground(
+                cros_tokens::kCrosSysSystemBase))
+            .Build());
+  }
+
+  views::View* GetContentsView() { return test_widget_->GetContentsView(); }
+
+  void TearDown() override {
+    test_widget_.reset();
+    AshTestBase::TearDown();
+  }
+
+  // AshTestBase:
+  absl::optional<pixel_test::InitParams> CreatePixelTestInitParams()
+      const override {
+    return pixel_test::InitParams();
+  }
+
+ private:
+  std::unique_ptr<views::Widget> test_widget_;
+};
+
+TEST_F(SystemNudgeViewPixelTest, TextOnly) {
+  // Set up base nudge data, which has an id, a catalog name and a body text.
+  auto nudge_data = CreateBaseNudgeData();
+
+  GetContentsView()->AddChildView(
+      std::make_unique<SystemNudgeView>(nudge_data));
+
+  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
+      "screenshot", /*revision_number=*/0, GetContentsView()));
+}
+
+TEST_F(SystemNudgeViewPixelTest, TextOnly_LongText) {
+  // Set up base nudge data and set a long text.
+  auto nudge_data = CreateBaseNudgeData();
+  nudge_data.body_text = long_body_text;
+
+  GetContentsView()->AddChildView(
+      std::make_unique<SystemNudgeView>(nudge_data));
+
+  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
+      "screenshot", /*revision_number=*/0, GetContentsView()));
+}
+
+TEST_F(SystemNudgeViewPixelTest, WithButtons) {
+  // Set up base nudge data, set a long text and add buttons.
+  auto nudge_data = CreateBaseNudgeData();
+  nudge_data.body_text = long_body_text;
+  nudge_data.primary_button_text = button_text;
+  nudge_data.secondary_button_text = button_text;
+
+  GetContentsView()->AddChildView(
+      std::make_unique<SystemNudgeView>(nudge_data));
+
+  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
+      "screenshot", /*revision_number=*/0, GetContentsView()));
+}
+
+TEST_F(SystemNudgeViewPixelTest, TitleAndLeadingImage) {
+  // Set up base nudge data, set a long text, a title and a leading image.
+  auto nudge_data = CreateBaseNudgeData();
+  nudge_data.image_model = ui::ImageModel::FromVectorIcon(
+      vector_icons::kDogfoodIcon, cros_tokens::kCrosSysOnSurface,
+      /*icon_size=*/60);
+  nudge_data.title_text = title_text;
+  nudge_data.body_text = long_body_text;
+
+  GetContentsView()->AddChildView(
+      std::make_unique<SystemNudgeView>(nudge_data));
+
+  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
+      "screenshot", /*revision_number=*/0, GetContentsView()));
+}
+
+TEST_F(SystemNudgeViewPixelTest, TitleAndLeadingImageWithButtons) {
+  // Set up base nudge data, set a long text, title, leading image and buttons.
+  auto nudge_data = CreateBaseNudgeData();
+  nudge_data.image_model = ui::ImageModel::FromVectorIcon(
+      vector_icons::kDogfoodIcon, cros_tokens::kCrosSysOnSurface,
+      /*icon_size=*/60);
+  nudge_data.title_text = title_text;
+  nudge_data.body_text = long_body_text;
+  nudge_data.primary_button_text = button_text;
+  nudge_data.secondary_button_text = button_text;
+
+  GetContentsView()->AddChildView(
+      std::make_unique<SystemNudgeView>(nudge_data));
+
+  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
+      "screenshot", /*revision_number=*/0, GetContentsView()));
+}
+
+}  // namespace ash
diff --git a/ash/system/toast/system_nudge_view_unittest.cc b/ash/system/toast/system_nudge_view_unittest.cc
index a941f41..0b9546a 100644
--- a/ash/system/toast/system_nudge_view_unittest.cc
+++ b/ash/system/toast/system_nudge_view_unittest.cc
@@ -7,11 +7,11 @@
 #include "ash/constants/ash_features.h"
 #include "ash/public/cpp/ash_view_ids.h"
 #include "ash/public/cpp/system/anchored_nudge_data.h"
-#include "ash/style/ash_color_id.h"
 #include "ash/system/toast/nudge_constants.h"
 #include "ash/test/ash_test_base.h"
 #include "base/test/scoped_feature_list.h"
 #include "components/vector_icons/vector_icons.h"
+#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/image_view.h"
@@ -136,7 +136,8 @@
   std::unique_ptr<views::Widget> widget = CreateFramelessTestWidget();
   const std::u16string title_text = u"Title text";
   const ui::ImageModel image_model = ui::ImageModel::FromVectorIcon(
-      vector_icons::kDogfoodIcon, kColorAshIconColorPrimary, /*icon_size=*/60);
+      vector_icons::kDogfoodIcon, cros_tokens::kCrosSysOnSurface,
+      /*icon_size=*/60);
 
   // Set up base nudge data and add a title and an image model.
   auto nudge_data = CreateBaseNudgeData();
diff --git a/ash/system/unified/feature_tile.cc b/ash/system/unified/feature_tile.cc
index fd968faa..abc845e97 100644
--- a/ash/system/unified/feature_tile.cc
+++ b/ash/system/unified/feature_tile.cc
@@ -10,11 +10,11 @@
 #include "ash/style/dark_light_mode_controller_impl.h"
 #include "ash/style/typography.h"
 #include "ash/system/tray/tray_constants.h"
-#include "chromeos/constants/chromeos_features.h"
 #include "components/vector_icons/vector_icons.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/base/models/image_model.h"
 #include "ui/chromeos/styles/cros_tokens_color_mappings.h"
+#include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/text_constants.h"
 #include "ui/views/animation/ink_drop.h"
@@ -25,6 +25,7 @@
 #include "ui/views/controls/highlight_path_generator.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
+#include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/flex_layout.h"
 #include "ui/views/layout/flex_layout_view.h"
 #include "ui/views/layout/layout_types.h"
@@ -48,8 +49,10 @@
 constexpr gfx::Size kIconButtonSize(36, 52);
 constexpr int kIconButtonCornerRadius = 12;
 constexpr gfx::Insets kIconButtonMargins = gfx::Insets::VH(6, 6);
-constexpr gfx::Size kTitlesContainerSize(98, kFeatureTileHeight);
 constexpr gfx::Insets kDrillInArrowMargins = gfx::Insets::TLBR(0, 4, 0, 10);
+constexpr gfx::Insets kTitleContainerWithoutDiveInButtonMargins =
+    gfx::Insets::TLBR(0, 0, 0, 10);
+constexpr gfx::Insets kTitleContainerWithDiveInButtonMargins = gfx::Insets();
 
 // Compact tile constants
 constexpr int kCompactWidth = 86;
@@ -124,22 +127,16 @@
 void FeatureTile::CreateChildViews() {
   const bool is_compact = type_ == TileType::kCompact;
 
-  auto* layout_manager = SetLayoutManager(std::make_unique<FlexLayout>());
-  layout_manager->SetOrientation(is_compact
-                                     ? views::LayoutOrientation::kVertical
-                                     : views::LayoutOrientation::kHorizontal);
+  auto* layout_manager = SetLayoutManager(std::make_unique<views::BoxLayout>());
+  layout_manager->SetOrientation(
+      is_compact ? views::BoxLayout::Orientation::kVertical
+                 : views::BoxLayout::Orientation::kHorizontal);
 
   ink_drop_container_ =
       AddChildView(std::make_unique<views::InkDropContainerView>());
-  layout_manager->SetChildViewIgnoredByLayout(ink_drop_container_, true);
 
   auto* focus_ring = views::FocusRing::Get(this);
   focus_ring->SetColorId(cros_tokens::kCrosSysFocusRing);
-  // Since the focus ring doesn't set a LayoutManager it won't get drawn unless
-  // excluded by the tile's LayoutManager.
-  // TODO(crbug/1385946): Modify LayoutManagerBase and FocusRing to always
-  // exclude focus ring from the layout.
-  layout_manager->SetChildViewIgnoredByLayout(focus_ring, true);
 
   SetPreferredSize(is_compact ? kCompactSize : kDefaultSize);
 
@@ -155,23 +152,23 @@
   icon_button_->SetEnabled(false);
   icon_button_->SetCanProcessEventsWithinSubtree(false);
 
-  auto* title_container = AddChildView(std::make_unique<FlexLayoutView>());
-  title_container->SetCanProcessEventsWithinSubtree(false);
-  title_container->SetOrientation(views::LayoutOrientation::kVertical);
-  title_container->SetMainAxisAlignment(views::LayoutAlignment::kCenter);
-  title_container->SetCrossAxisAlignment(views::LayoutAlignment::kStretch);
+  title_container_ = AddChildView(std::make_unique<FlexLayoutView>());
+  title_container_->SetCanProcessEventsWithinSubtree(false);
+  title_container_->SetOrientation(views::LayoutOrientation::kVertical);
+  title_container_->SetMainAxisAlignment(views::LayoutAlignment::kCenter);
+  title_container_->SetCrossAxisAlignment(views::LayoutAlignment::kStretch);
 
-  label_ = title_container->AddChildView(std::make_unique<views::Label>());
+  label_ = title_container_->AddChildView(std::make_unique<views::Label>());
   label_->SetAutoColorReadabilityEnabled(false);
 
-  sub_label_ = title_container->AddChildView(std::make_unique<views::Label>());
+  sub_label_ = title_container_->AddChildView(std::make_unique<views::Label>());
   sub_label_->SetHorizontalAlignment(is_compact ? gfx::ALIGN_CENTER
                                                 : gfx::ALIGN_LEFT);
   sub_label_->SetAutoColorReadabilityEnabled(false);
 
   if (is_compact) {
-    title_container->SetProperty(views::kMarginsKey,
-                                 kCompactTitlesContainerMargins);
+    title_container_->SetProperty(views::kMarginsKey,
+                                  kCompactTitlesContainerMargins);
     label_->SetVerticalAlignment(gfx::ALIGN_MIDDLE);
     label_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
 
@@ -187,7 +184,10 @@
     sub_label_->SetLineHeight(kCompactTitleLineHeight);
     sub_label_->SetVisible(false);
   } else {
-    title_container->SetPreferredSize(kTitlesContainerSize);
+    // `title_container_` will take all the remaining space of the tile.
+    layout_manager->SetFlexForView(title_container_, 1);
+    title_container_->SetProperty(views::kMarginsKey,
+                                  kTitleContainerWithoutDiveInButtonMargins);
     label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
     TypographyProvider::Get()->StyleLabel(TypographyToken::kCrosButton2,
                                           *label_);
@@ -224,6 +224,8 @@
 void FeatureTile::CreateDecorativeDrillInArrow() {
   CHECK_EQ(type_, TileType::kPrimary);
 
+  title_container_->SetProperty(views::kMarginsKey,
+                                kTitleContainerWithDiveInButtonMargins);
   drill_in_arrow_ = AddChildView(std::make_unique<views::ImageView>());
   // The icon is set in UpdateDrillArrowColor().
   drill_in_arrow_->SetPreferredSize(gfx::Size(kIconSize, kIconSize));
@@ -369,7 +371,7 @@
 }
 
 int FeatureTile::GetSubLabelMaxWidth() const {
-  return kTitlesContainerSize.width();
+  return title_container_->size().width();
 }
 
 void FeatureTile::SetSubLabel(const std::u16string& sub_label) {
diff --git a/ash/system/unified/feature_tile.h b/ash/system/unified/feature_tile.h
index 66e2e02..63948ebc 100644
--- a/ash/system/unified/feature_tile.h
+++ b/ash/system/unified/feature_tile.h
@@ -18,6 +18,7 @@
 }  // namespace gfx
 
 namespace views {
+class FlexLayoutView;
 class ImageButton;
 class ImageView;
 class InkDropContainerView;
@@ -185,6 +186,7 @@
   raw_ptr<views::Label, ExperimentalAsh> label_ = nullptr;
   raw_ptr<views::Label, ExperimentalAsh> sub_label_ = nullptr;
   raw_ptr<views::ImageView, ExperimentalAsh> drill_in_arrow_ = nullptr;
+  raw_ptr<views::FlexLayoutView> title_container_ = nullptr;
 
   // The radius of the tile's curved edges.
   int corner_radius_;
diff --git a/ash/system/unified/feature_tile_pixeltest.cc b/ash/system/unified/feature_tile_pixeltest.cc
index eb35d27..460fee80 100644
--- a/ash/system/unified/feature_tile_pixeltest.cc
+++ b/ash/system/unified/feature_tile_pixeltest.cc
@@ -74,8 +74,6 @@
   auto* tile = widget_->GetContentsView()->AddChildView(
       std::make_unique<FeatureTile>(base::DoNothing(), /*is_togglable=*/true,
                                     FeatureTile::TileType::kPrimary));
-  // Use the default size from go/cros-quick-settings-spec
-  tile->SetPreferredSize(gfx::Size(180, 64));
   tile->SetVectorIcon(vector_icons::kDogfoodIcon);
   tile->SetLabel(u"Label");
   tile->SetSubLabel(u"Sub-label");
@@ -105,6 +103,38 @@
       /*revision_number=*/0, widget_.get()));
 }
 
+TEST_F(FeatureTilePixelTest, PrimaryTileWithoutDiveInButton) {
+  auto* tile = widget_->GetContentsView()->AddChildView(
+      std::make_unique<FeatureTile>(base::DoNothing(), /*is_togglable=*/true,
+                                    FeatureTile::TileType::kPrimary));
+  tile->SetVectorIcon(vector_icons::kDogfoodIcon);
+  tile->SetLabel(u"Label");
+  tile->SetSubLabel(u"Sub-label");
+  // Needed for accessibility paint checks.
+  tile->SetTooltipText(u"Tooltip");
+
+  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
+      "basic",
+      /*revision_number=*/0, widget_.get()));
+
+  widget_->GetFocusManager()->SetFocusedView(tile);
+  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
+      "focused",
+      /*revision_number=*/0, widget_.get()));
+
+  tile->SetToggled(true);
+  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
+      "toggled",
+      /*revision_number=*/0, widget_.get()));
+
+  // Test eliding.
+  tile->SetLabel(u"A very very long label");
+  tile->SetSubLabel(u"A very very long label");
+  EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
+      "elided",
+      /*revision_number=*/0, widget_.get()));
+}
+
 TEST_F(FeatureTilePixelTest, PrimaryTile_RTL) {
   // Turn on RTL mode.
   base::i18n::SetRTLForTesting(true);
@@ -114,9 +144,6 @@
   auto* tile = widget_->GetContentsView()->AddChildView(
       std::make_unique<FeatureTile>(base::DoNothing(), /*is_togglable=*/true,
                                     FeatureTile::TileType::kPrimary));
-
-  // Use the default size from go/cros-quick-settings-spec
-  tile->SetPreferredSize(gfx::Size(180, 64));
   tile->SetVectorIcon(vector_icons::kDogfoodIcon);
   tile->SetLabel(u"Label");
   tile->SetSubLabel(u"Sub-label");
@@ -134,8 +161,6 @@
   auto* tile = widget_->GetContentsView()->AddChildView(
       std::make_unique<FeatureTile>(base::DoNothing(), /*is_togglable=*/true,
                                     FeatureTile::TileType::kCompact));
-  // Use the default size from go/cros-quick-settings-spec
-  tile->SetPreferredSize(gfx::Size(86, 64));
   tile->SetVectorIcon(vector_icons::kDogfoodIcon);
   tile->SetLabel(u"Multi-line label");
   // Needed for accessibility paint checks.
diff --git a/ash/user_education/holding_space_wallpaper_nudge/holding_space_wallpaper_nudge_controller.cc b/ash/user_education/holding_space_wallpaper_nudge/holding_space_wallpaper_nudge_controller.cc
index b884526..66469b6a 100644
--- a/ash/user_education/holding_space_wallpaper_nudge/holding_space_wallpaper_nudge_controller.cc
+++ b/ash/user_education/holding_space_wallpaper_nudge/holding_space_wallpaper_nudge_controller.cc
@@ -14,6 +14,7 @@
 #include "ash/drag_drop/scoped_drag_drop_observer.h"
 #include "ash/public/cpp/holding_space/holding_space_client.h"
 #include "ash/public/cpp/holding_space/holding_space_controller.h"
+#include "ash/public/cpp/holding_space/holding_space_controller_observer.h"
 #include "ash/public/cpp/holding_space/holding_space_model.h"
 #include "ash/public/cpp/holding_space/holding_space_util.h"
 #include "ash/public/cpp/wallpaper/wallpaper_controller.h"
@@ -221,7 +222,8 @@
 // (b) holding space is visible in the shelf on all displays
 //
 // While the observed drag-and-drop sequence is in progress.
-class DragDropDelegate : public WallpaperDragDropDelegate {
+class DragDropDelegate : public WallpaperDragDropDelegate,
+                         public HoldingSpaceControllerObserver {
  private:
   // WallpaperDragDropDelegate:
   void GetDropFormats(int* formats,
@@ -252,6 +254,12 @@
       return;
     }
 
+    // Begin observing the `HoldingSpaceController` in case holding space is
+    // opened/closed. This observation will continue until destruction.
+    if (!holding_space_controller_observer_.IsObserving()) {
+      holding_space_controller_observer_.Observe(HoldingSpaceController::Get());
+    }
+
     // Once the user has dragged a file from the Files app over the wallpaper,
     // observe the drag-and-drop sequence to ensure that (a) the shelf is
     // visible on the active display and that (b) holding space is visible in
@@ -362,7 +370,7 @@
     // sequences and reset the shelf to its natural state.
     if (!location_in_screen) {
       drag_drop_observer_.reset();
-      force_holding_space_show_in_shelf_.reset();
+      force_holding_space_show_in_shelf_for_drag_.reset();
 
       // Reset shelf auto-hide behavior asynchronously so that it won't animate
       // out and immediately back in again if the user drops a file from the
@@ -387,12 +395,12 @@
 
     // Ensure that holding space is visible in the shelf on all displays while
     // the observed drag-and-drop sequence is in progress.
-    if (!force_holding_space_show_in_shelf_) {
-      force_holding_space_show_in_shelf_ =
+    if (!force_holding_space_show_in_shelf_for_drag_) {
+      force_holding_space_show_in_shelf_for_drag_ =
           std::make_unique<HoldingSpaceController::ScopedForceShowInShelf>();
     }
 
-    if (!NudgeShouldBeShown()) {
+    if (!NudgeShouldBeShown() || help_bubble_anchor_) {
       return;
     }
 
@@ -415,16 +423,22 @@
     help_bubble_params.extended_properties =
         user_education_util::CreateExtendedProperties(HelpBubbleStyle::kNudge);
 
+    // `base::AutoReset` is safe here, because this is guaranteed to be
+    // destroyed before destruction of `this` is complete.
+    base::AutoReset<uintptr_t> reset_help_bubble_anchor(
+        &help_bubble_anchor_, /*new_value=*/0, /*expected_old_value=*/0);
+
     // While the help bubble is showing, do not allow either the associated
-    // `shelf` or `holding_space_tray` to hide.
-    // TODO(http://b/283171784): Explicitly close the help bubble if the user
-    // opens holding space or successfully pins a file to holding space.
+    // `shelf` or `holding_space_tray` to hide. Also reset the pointer to
+    // the `help_bubble_anchor_` on close.
     base::OnceClosure close_callback = base::BindOnce(
         [](Shelf::ScopedDisableAutoHide*,
-           HoldingSpaceController::ScopedForceShowInShelf*) {},
+           HoldingSpaceController::ScopedForceShowInShelf*,
+           const base::AutoReset<uintptr_t>&) {},
         base::Owned(std::make_unique<Shelf::ScopedDisableAutoHide>(shelf)),
-        base::Owned(std::make_unique<
-                    HoldingSpaceController::ScopedForceShowInShelf>()));
+        base::Owned(
+            std::make_unique<HoldingSpaceController::ScopedForceShowInShelf>()),
+        base::OwnedRef(std::move(reset_help_bubble_anchor)));
 
     // Attempt to show the help bubble.
     if (auto scoped_help_bubble_closer =
@@ -442,6 +456,10 @@
       // bubbles have already closed.
       scoped_help_bubble_closer_ = std::move(scoped_help_bubble_closer);
 
+      // Store a pointer to the `HoldingSpaceTray` anchoring the help bubble to
+      // test for potential overlap later.
+      help_bubble_anchor_ = reinterpret_cast<uintptr_t>(holding_space_tray);
+
       // If successful in showing the help bubble, ping the `holding_space_tray`
       // to further attract the user's attention.
       UserEducationPingController::Get()->CreatePing(
@@ -449,6 +467,35 @@
     }
   }
 
+  // HoldingSpaceControllerObserver:
+  void OnHoldingSpaceControllerDestroying() override {
+    holding_space_controller_observer_.Reset();
+  }
+
+  void OnHoldingSpaceTrayBubbleVisibilityChanged(const HoldingSpaceTray* tray,
+                                                 bool visible) override {
+    if (visible && help_bubble_anchor_) {
+      force_holding_space_show_in_shelf_for_tray_bubble_ =
+          std::make_unique<HoldingSpaceController::ScopedForceShowInShelf>();
+
+      // If the tray that emitted this event is the one that the currently open
+      // help bubble is anchored to, close the help bubble to avoid overlap
+      // between the two bubbles.
+      if (reinterpret_cast<uintptr_t>(tray) == help_bubble_anchor_) {
+        scoped_help_bubble_closer_.RunAndReset();
+      }
+    } else {
+      force_holding_space_show_in_shelf_for_tray_bubble_.reset();
+    }
+  }
+
+  // A pointer to the `HoldingSpaceTray` anchoring the currently open help
+  // bubble. Used to determine if the help bubble should be dismissed to prevent
+  // overlap between the help bubble and `HoldingSpaceTrayBubble`. NOTE: Do not
+  // dereference this pointer. It is for comparison only, as there is no
+  // guarantee that this `HoldingSpaceTray` still exists.
+  uintptr_t help_bubble_anchor_ = 0;
+
   // Used to observe a single drag-and-drop sequence once the user has dragged
   // a file from the Files app over the wallpaper.
   std::unique_ptr<ScopedDragDropObserver> drag_drop_observer_;
@@ -460,7 +507,12 @@
   // Used to ensure that holding space is visible in the shelf on all displays
   // while an observed drag-and-drop sequence is in progress.
   std::unique_ptr<HoldingSpaceController::ScopedForceShowInShelf>
-      force_holding_space_show_in_shelf_;
+      force_holding_space_show_in_shelf_for_drag_;
+
+  // Used to ensure that holding space is visible in the shelf on all displays
+  // while the tray bubble is open.
+  std::unique_ptr<HoldingSpaceController::ScopedForceShowInShelf>
+      force_holding_space_show_in_shelf_for_tray_bubble_;
 
   // Used to close the help bubble on drop-to-pin.
   base::ScopedClosureRunner scoped_help_bubble_closer_;
@@ -468,6 +520,11 @@
   // Used to highlight the wallpaper when data is dragged over it so that the
   // user better understands the wallpaper is a drop target.
   std::unique_ptr<Highlight> wallpaper_highlight_;
+
+  // Observes the `HoldingSpaceController` to watch for tray bubble visibility.
+  base::ScopedObservation<HoldingSpaceController,
+                          HoldingSpaceControllerObserver>
+      holding_space_controller_observer_{this};
 };
 
 }  // namespace
diff --git a/ash/user_education/holding_space_wallpaper_nudge/holding_space_wallpaper_nudge_controller_unittest.cc b/ash/user_education/holding_space_wallpaper_nudge/holding_space_wallpaper_nudge_controller_unittest.cc
index 31747b4e..13bf7e3 100644
--- a/ash/user_education/holding_space_wallpaper_nudge/holding_space_wallpaper_nudge_controller_unittest.cc
+++ b/ash/user_education/holding_space_wallpaper_nudge/holding_space_wallpaper_nudge_controller_unittest.cc
@@ -378,6 +378,113 @@
       scoped_animation_duration_scale_mode_;
 };
 
+// HoldingSpaceWallpaperNudgeControllerTest ------------------------------------
+
+// Base class for tests that verify general Holding Space wallpaper nudge
+// behavior.
+class HoldingSpaceWallpaperNudgeControllerTest
+    : public HoldingSpaceWallpaperNudgeControllerTestBase {
+ public:
+  HoldingSpaceWallpaperNudgeControllerTest()
+      : HoldingSpaceWallpaperNudgeControllerTestBase(
+            /*drop_to_pin_enabled=*/false,
+            /*rate_limiting_enabled=*/true,
+            base::test::TaskEnvironment::TimeSource::SYSTEM_TIME) {}
+};
+
+TEST_F(HoldingSpaceWallpaperNudgeControllerTest, HideBubbleOnHoldingSpaceOpen) {
+  // The holding space tray is always visible in the shelf when the
+  // predictability feature is enabled. Force disable it so that we verify that
+  // holding space visibility is updated by the
+  // `HoldingSpaceWallpaperNudgeController`.
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndDisableFeature(
+      features::kHoldingSpacePredictability);
+
+  // Set up a primary and secondary display and cache IDs.
+  UpdateDisplay("1024x768,1024x768");
+  const int64_t primary_display_id = GetPrimaryDisplay().id();
+  const int64_t secondary_display_id = GetSecondaryDisplay().id();
+
+  // Log in a regular user.
+  const AccountId& account_id = AccountId::FromUserEmail("user@test");
+  SimulateUserLogin(account_id);
+
+  // Register a model and client for holding space.
+  HoldingSpaceModel holding_space_model;
+  testing::StrictMock<MockHoldingSpaceClient> holding_space_client;
+  HoldingSpaceController::Get()->RegisterClientAndModelForUser(
+      account_id, &holding_space_client, &holding_space_model);
+
+  // Configure the client to crack file system URLs. Note that this is only
+  // expected to occur when Files app data is dragged over the wallpaper.
+  EXPECT_CALL(holding_space_client, CrackFileSystemUrl)
+      .WillRepeatedly(Invoke([](const GURL& file_system_url) {
+        return base::FilePath(base::StrCat(
+            {"//path/to/", std::string(&file_system_url.spec().back())}));
+      }));
+
+  // Needed by the client to create the placeholder.
+  EXPECT_CALL(holding_space_client, IsDriveDisabled)
+      .WillRepeatedly(testing::Return(false));
+
+  // Create and show a widget on the primary display from which data can be
+  // drag-and-dropped.
+  auto widget = CreateTestWidgetForDisplayId(primary_display_id);
+  widget->SetContentsView(std::make_unique<DraggableView>(
+      base::BindLambdaForTesting([&](ui::OSExchangeData* data) {
+        data->SetString(u"Payload");
+        SetFilesAppData(data, u"file-system:a\nfile-system:b");
+      })));
+  widget->CenterWindow(gfx::Size(100, 100));
+  widget->Show();
+
+  // Set animation durations to zero to speed things up.
+  SetAnimationDurationMultiplier(
+      ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
+
+  // Mark the holding space feature as available since there is no holding
+  // space keyed service which would otherwise be responsible for doing so.
+  holding_space_prefs::MarkTimeOfFirstAvailability(
+      Shell::Get()->session_controller()->GetLastActiveUserPrefService());
+
+  // Cache both shelves and holding space trays.
+  auto* const primary_shelf = GetShelfForDisplayId(primary_display_id);
+  auto* const secondary_shelf = GetShelfForDisplayId(secondary_display_id);
+  auto* const primary_tray = GetHoldingSpaceTrayForShelf(primary_shelf);
+  auto* const secondary_tray = GetHoldingSpaceTrayForShelf(secondary_shelf);
+
+  // Drag data from the `widget` to the wallpaper to show the nudge, then
+  // cancel the drag immediately.
+  MoveMouseTo(widget.get());
+  PressLeftButton();
+  MoveMouseBy(/*x=*/widget->GetWindowBoundsInScreen().width(), /*y=*/0);
+  PressAndReleaseKey(ui::VKEY_ESCAPE);
+  ReleaseLeftButton();
+
+  // Expect only the primary display's holding space tray to have a help bubble.
+  EXPECT_TRUE(HasHelpBubble(primary_tray));
+  EXPECT_FALSE(HasHelpBubble(secondary_tray));
+
+  // Expect the state not to change at all if the secondary display's holding
+  // space bubble is opened, as it does not overlap with the help bubble.
+  secondary_tray->ShowBubble();
+  EXPECT_TRUE(HasHelpBubble(primary_tray));
+  EXPECT_FALSE(HasHelpBubble(secondary_tray));
+  secondary_tray->CloseBubble();
+
+  // Expect the help bubble to close if the primary display's holding space is
+  // opened, as that would overlap.
+  primary_tray->ShowBubble();
+  EXPECT_FALSE(HasHelpBubble(primary_tray));
+  EXPECT_FALSE(HasHelpBubble(secondary_tray));
+  primary_tray->CloseBubble();
+
+  // Clean up holding space controller.
+  HoldingSpaceController::Get()->RegisterClientAndModelForUser(
+      account_id, /*client=*/nullptr, /*model=*/nullptr);
+}
+
 // HoldingSpaceWallpaperNudgeControllerDragAndDropTest -------------------------
 
 // Base class for drag-and-drop tests of the
@@ -456,6 +563,10 @@
         }));
   }
 
+  // Needed by the client to create the placeholder.
+  EXPECT_CALL(holding_space_client, IsDriveDisabled)
+      .WillRepeatedly(testing::Return(false));
+
   // Mark the holding space feature as available since there is no holding
   // space keyed service which would otherwise be responsible for doing so.
   holding_space_prefs::MarkTimeOfFirstAvailability(
@@ -702,6 +813,10 @@
             {"//path/to/", std::string(&file_system_url.spec().back())}));
       }));
 
+  // Needed by the client to create the placeholder.
+  EXPECT_CALL(holding_space_client, IsDriveDisabled)
+      .WillRepeatedly(testing::Return(false));
+
   // Create and show a widget from which data can be drag-and-dropped.
   auto widget = CreateTestWidgetForDisplayId(display_id);
   widget->SetContentsView(std::make_unique<DraggableView>(
diff --git a/base/debug/allocation_trace.h b/base/debug/allocation_trace.h
index 229ed9e..8dcb65f 100644
--- a/base/debug/allocation_trace.h
+++ b/base/debug/allocation_trace.h
@@ -11,12 +11,12 @@
 #include <cstdint>
 
 #include "base/allocator/dispatcher/subsystem.h"
-#include "base/allocator/partition_allocator/src/partition_alloc/pointers/raw_ptr_exclusion.h"
 #include "base/base_export.h"
 #include "base/bits.h"
 #include "base/compiler_specific.h"
 #include "base/debug/debugging_buildflags.h"
 #include "base/debug/stack_trace.h"
+#include "base/memory/raw_ptr_exclusion.h"
 #include "build/build_config.h"
 
 namespace base::debug::tracer {
diff --git a/base/functional/bind_internal.h b/base/functional/bind_internal.h
index 4eb827f..37e66ed1 100644
--- a/base/functional/bind_internal.h
+++ b/base/functional/bind_internal.h
@@ -15,7 +15,6 @@
 
 #include "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_buildflags.h"
 #include "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_config.h"
-#include "base/allocator/partition_allocator/src/partition_alloc/pointers/raw_ptr.h"
 #include "base/check.h"
 #include "base/compiler_specific.h"
 #include "base/functional/callback_internal.h"
diff --git a/base/metrics/statistics_recorder_unittest.cc b/base/metrics/statistics_recorder_unittest.cc
index eacc82d..eae7bcc 100644
--- a/base/metrics/statistics_recorder_unittest.cc
+++ b/base/metrics/statistics_recorder_unittest.cc
@@ -390,35 +390,22 @@
   const Value::List* buckets_list = histogram_dict->FindList("buckets");
   ASSERT_TRUE(buckets_list);
   EXPECT_EQ(2u, buckets_list->size());
-}
 
-// Check the serialized JSON with a different verbosity level.
-TEST_P(StatisticsRecorderTest, ToJSONOmitBuckets) {
-  Histogram::FactoryGet("TestHistogram1", 1, 1000, 50, HistogramBase::kNoFlags)
-      ->Add(30);
-  Histogram::FactoryGet("TestHistogram1", 1, 1000, 50, HistogramBase::kNoFlags)
-      ->Add(40);
-  Histogram::FactoryGet("TestHistogram2", 1, 1000, 50, HistogramBase::kNoFlags)
-      ->Add(30);
-  Histogram::FactoryGet("TestHistogram2", 1, 1000, 50, HistogramBase::kNoFlags)
-      ->Add(40);
-
-  std::string json =
-      StatisticsRecorder::ToJSON(JSON_VERBOSITY_LEVEL_OMIT_BUCKETS);
-  absl::optional<Value> root = JSONReader::Read(json);
+  // Check the serialized JSON with a different verbosity level.
+  json = StatisticsRecorder::ToJSON(JSON_VERBOSITY_LEVEL_OMIT_BUCKETS);
+  root = JSONReader::Read(json);
   ASSERT_TRUE(root);
-  Value::Dict* root_dict = root->GetIfDict();
+  root_dict = root->GetIfDict();
   ASSERT_TRUE(root_dict);
-  const Value::List* histogram_list = root_dict->FindList("histograms");
+  histogram_list = root_dict->FindList("histograms");
   ASSERT_TRUE(histogram_list);
-
   ASSERT_EQ(2u, histogram_list->size());
   const Value::Dict* histogram_dict2 = (*histogram_list)[0].GetIfDict();
   ASSERT_TRUE(histogram_dict2);
-  auto sample_count = histogram_dict2->FindInt("count");
+  sample_count = histogram_dict2->FindInt("count");
   ASSERT_TRUE(sample_count);
   EXPECT_EQ(2, *sample_count);
-  const Value::List* buckets_list = histogram_dict2->FindList("buckets");
+  buckets_list = histogram_dict2->FindList("buckets");
   // Bucket information should be omitted.
   ASSERT_FALSE(buckets_list);
 }
diff --git a/base/test/test_suite.h b/base/test/test_suite.h
index f1d64aa0..90ebf53 100644
--- a/base/test/test_suite.h
+++ b/base/test/test_suite.h
@@ -24,7 +24,7 @@
 
 #if BUILDFLAG(IS_WIN)
 #include <vector>
-#include "base/allocator/partition_allocator/src/partition_alloc/pointers/raw_ptr_exclusion.h"
+#include "base/memory/raw_ptr_exclusion.h"
 #endif
 
 namespace logging {
diff --git a/build/config/rust.gni b/build/config/rust.gni
index 9a7bb78..f1241704 100644
--- a/build/config/rust.gni
+++ b/build/config/rust.gni
@@ -87,7 +87,7 @@
   enable_rust_base_conversions = enable_rust
 
   # The base::JSONReader implementation. Requires base conversions.
-  enable_rust_json = enable_rust
+  enable_rust_json = enable_rust && enable_all_rust_features
 
   # Support for chrome://crash-rust to check crash dump collection works.
   enable_rust_crash = enable_rust
diff --git a/build/gn_helpers.py b/build/gn_helpers.py
index 94c1a84..34dfb13 100644
--- a/build/gn_helpers.py
+++ b/build/gn_helpers.py
@@ -546,7 +546,10 @@
 
 
 def CreateBuildCommand(output_directory):
-  """Returns [cmd, -C, output_directory], where |cmd| is auto{siso,ninja}."""
+  """Returns [cmd, -C, output_directory].
+
+  Where |cmd| is one of: siso ninja, ninja, or autoninja.
+  """
   suffix = '.bat' if sys.platform.startswith('win32') else ''
   # Prefer the version on PATH, but fallback to known version if PATH doesn't
   # have one (e.g. on bots).
@@ -560,7 +563,7 @@
     siso_cmd = [f'{siso_prefix}siso{suffix}', 'ninja']
   else:
     ninja_cmd = [f'autoninja{suffix}']
-    siso_cmd = [f'autosiso{suffix}']
+    siso_cmd = list(ninja_cmd)
 
   if output_directory and os.path.relpath(output_directory) != '.':
     ninja_cmd += ['-C', output_directory]
diff --git a/build/gn_helpers_unittest.py b/build/gn_helpers_unittest.py
index 6e305d7..ed3df42 100755
--- a/build/gn_helpers_unittest.py
+++ b/build/gn_helpers_unittest.py
@@ -323,7 +323,7 @@
 
       siso_deps = pathlib.Path(temp_dir) / '.siso_deps'
       siso_deps.touch()
-      self.assertEqual(f'autosiso{suffix}',
+      self.assertEqual(f'autoninja{suffix}',
                        gn_helpers.CreateBuildCommand(temp_dir)[0])
 
       with mock.patch('shutil.which', lambda x: None):
diff --git a/build/sanitizers/asan_suppressions.cc b/build/sanitizers/asan_suppressions.cc
index 1bd9963a..3bda1f37 100644
--- a/build/sanitizers/asan_suppressions.cc
+++ b/build/sanitizers/asan_suppressions.cc
@@ -19,8 +19,6 @@
     "odr_violation:^core::\n"
     "odr_violation:^object::\n"
     "odr_violation:^std::io::\n"
-    "odr_violation:^serde::\n"
-    "odr_violation:^serde_json_lenient::\n"
     "odr_violation:^std::panicking::\n"
     "odr_violation:^read_fonts::tables::\n"
 
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index d85c864..d6f9d33 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -693,8 +693,7 @@
 
   void SetPropertyTreesNeedRebuild();
 
-  // Returns the layer with the given |element_id|. In layer-list mode, only
-  // scrollable layers are registered in this map.
+  // Returns the layer with the given |element_id|.
   Layer* LayerByElementId(ElementId element_id);
   const Layer* LayerByElementId(ElementId element_id) const;
 
diff --git a/chrome/VERSION b/chrome/VERSION
index 534b880a..c0e9152 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=121
 MINOR=0
-BUILD=6119
+BUILD=6120
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java
index db04a12..c1c05b75 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java
@@ -26,13 +26,11 @@
 import org.chromium.chrome.browser.partnerbookmarks.PartnerBookmarksShim;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.read_later.ReadingListUtils;
-import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.components.bookmarks.BookmarkId;
 import org.chromium.components.bookmarks.BookmarkItem;
 import org.chromium.components.bookmarks.BookmarkType;
 import org.chromium.components.power_bookmarks.PowerBookmarkMeta;
 import org.chromium.components.power_bookmarks.PowerBookmarkType;
-import org.chromium.content_public.browser.WebContents;
 import org.chromium.url.GURL;
 
 import java.util.ArrayList;
@@ -105,27 +103,13 @@
         BookmarkBridgeJni.get().getImageUrlForBookmark(mNativeBookmarkBridge, url, callback);
     }
 
-    /**
-     * @param tab Tab whose current URL is checked against.
-     * @return {@code true} if the current Tab URL has a bookmark associated with it. If the
-     *     bookmark backend is not loaded, return {@code false}.
-     */
-    public boolean hasBookmarkIdForTab(@Nullable Tab tab) {
-        ThreadUtils.assertOnUiThread();
-        if (mNativeBookmarkBridge == 0) return false;
-        return getUserBookmarkIdForTab(tab) != null;
-    }
-
-    /**
-     * @param tab Tab whose current URL is checked against.
-     * @return BookmarkId or {@link null} if bookmark backend is not loaded or the tab is frozen.
-     */
-    public @Nullable BookmarkId getUserBookmarkIdForTab(@Nullable Tab tab) {
+    /** Returns the most recently added BookmarkId */
+    public @Nullable BookmarkId getMostRecentlyAddedUserBookmarkIdForUrl(@NonNull GURL url) {
         ThreadUtils.assertOnUiThread();
         if (mNativeBookmarkBridge == 0) return null;
-        if (tab == null || tab.isFrozen() || mNativeBookmarkBridge == 0) return null;
+        assert mIsNativeBookmarkModelLoaded;
         return BookmarkBridgeJni.get()
-                .getBookmarkIdForWebContents(mNativeBookmarkBridge, tab.getWebContents(), true);
+                .getMostRecentlyAddedUserBookmarkIdForUrl(mNativeBookmarkBridge, url);
     }
 
     /**
@@ -994,8 +978,7 @@
 
         void getImageUrlForBookmark(long nativeBookmarkBridge, GURL url, Callback<GURL> callback);
 
-        BookmarkId getBookmarkIdForWebContents(
-                long nativeBookmarkBridge, WebContents webContents, boolean onlyEditable);
+        BookmarkId getMostRecentlyAddedUserBookmarkIdForUrl(long nativeBookmarkBridge, GURL url);
 
         BookmarkItem getBookmarkById(long nativeBookmarkBridge, long id, int type);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java
index 24a1c14a..96e5e30b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java
@@ -5,11 +5,13 @@
 package org.chromium.chrome.browser.bookmarks;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import org.chromium.base.ObserverList;
 import org.chromium.base.ResettersForTesting;
 import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.components.bookmarks.BookmarkId;
 import org.chromium.components.bookmarks.BookmarkItem;
 import org.chromium.components.bookmarks.BookmarkType;
@@ -155,4 +157,23 @@
     public BookmarkId getDefaultFolderViewLocation() {
         return getRootFolderId();
     }
+
+    /**
+     * @param tab Tab whose current URL is checked against.
+     * @return {@code true} if the current tab URL has a bookmark associated with it. If the
+     *     bookmark backend is not loaded, return {@code false}.
+     */
+    public boolean hasBookmarkIdForTab(@Nullable Tab tab) {
+        if (tab == null) return false;
+        return isBookmarked(tab.getOriginalUrl());
+    }
+
+    /**
+     * @param tab Tab whose current URL is checked against.
+     * @return BookmarkId or {@link null} if bookmark backend is not loaded.
+     */
+    public @Nullable BookmarkId getUserBookmarkIdForTab(@Nullable Tab tab) {
+        if (tab == null) return null;
+        return getMostRecentlyAddedUserBookmarkIdForUrl(tab.getOriginalUrl());
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkBridgeTest.java
index 0821745..0002a8c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkBridgeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkBridgeTest.java
@@ -343,14 +343,6 @@
     @Test
     @SmallTest
     @UiThreadTest
-    @Feature({"Bookmark"})
-    public void testGetUserBookmarkIdForTab() {
-        Assert.assertNull(mBookmarkBridge.getUserBookmarkIdForTab(null));
-    }
-
-    @Test
-    @SmallTest
-    @UiThreadTest
     @RequiresRestart
     public void testAddToReadingList() {
         Assert.assertNull(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTest.java
index 13a9416..e965aa4 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTest.java
@@ -118,6 +118,10 @@
                 ShoppingPersistedTabDataTestUtils.GREAT_BRITAIN_CURRENCY_CODE);
         shoppingPersistedTabData.setPriceDropGurl(new GURL("https://www.google.com"));
         shoppingPersistedTabData.setIsCurrentPriceDropSeen(true);
+        shoppingPersistedTabData.setProductTitle(
+                ShoppingPersistedTabDataTestUtils.FAKE_PRODUCT_TITLE);
+        shoppingPersistedTabData.setProductImageUrl(
+                new GURL(ShoppingPersistedTabDataTestUtils.FAKE_PRODUCT_IMAGE_URL));
         ByteBuffer serialized = shoppingPersistedTabData.getSerializer().get();
         ShoppingPersistedTabData deserialized = new ShoppingPersistedTabData(tab);
         deserialized.deserialize(serialized);
@@ -131,6 +135,12 @@
         Assert.assertTrue(deserialized.getIsCurrentPriceDropSeen());
         Assert.assertEquals(
                 new GURL("https://www.google.com"), deserialized.getPriceDropDataForTesting().gurl);
+        Assert.assertEquals(
+                ShoppingPersistedTabDataTestUtils.FAKE_PRODUCT_TITLE,
+                deserialized.getProductTitle());
+        Assert.assertEquals(
+                new GURL(ShoppingPersistedTabDataTestUtils.FAKE_PRODUCT_IMAGE_URL),
+                deserialized.getProductImageUrl());
         MetricsResult metricsResult =
                 deserialized.getPriceDropMetricsLoggerForTesting().getMetricsResultForTesting();
         Assert.assertFalse(metricsResult.isProductDetailPage);
@@ -668,6 +678,12 @@
         Assert.assertEquals(287_000_000L, shoppingPersistedTabData.getPriceMicros());
         Assert.assertEquals(
                 123_456_789_012_345L, shoppingPersistedTabData.getPreviousPriceMicros());
+        Assert.assertEquals(
+                ShoppingPersistedTabDataTestUtils.FAKE_PRODUCT_TITLE,
+                shoppingPersistedTabData.getProductTitle());
+        Assert.assertEquals(
+                ShoppingPersistedTabDataTestUtils.FAKE_PRODUCT_IMAGE_URL,
+                shoppingPersistedTabData.getProductImageUrl().getSpec());
     }
 
     @UiThreadTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTestUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTestUtils.java
index fc5c7ca..ffbac2c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTestUtils.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabDataTestUtils.java
@@ -82,15 +82,21 @@
     static final int TAB_ID = 1;
     static final boolean IS_INCOGNITO = false;
     static final String FAKE_OFFER_ID = "100";
+    static final String FAKE_PRODUCT_TITLE = "Product Title";
+    static final String FAKE_PRODUCT_IMAGE_URL = "https://www.google.com/image";
 
     static final BuyableProduct BUYABLE_PRODUCT_PROTO_INITIAL =
             BuyableProduct.newBuilder()
                     .setCurrentPrice(createProductPrice(PRICE_MICROS, UNITED_STATES_CURRENCY_CODE))
+                    .setTitle(FAKE_PRODUCT_TITLE)
+                    .setImageUrl(FAKE_PRODUCT_IMAGE_URL)
                     .build();
     static final BuyableProduct BUYABLE_PRODUCT_PROTO_PRICE_UPDATED =
             BuyableProduct.newBuilder()
                     .setCurrentPrice(
                             createProductPrice(UPDATED_PRICE_MICROS, UNITED_STATES_CURRENCY_CODE))
+                    .setTitle(FAKE_PRODUCT_TITLE)
+                    .setImageUrl(FAKE_PRODUCT_IMAGE_URL)
                     .build();
     static final ProductPriceUpdate PRODUCT_UPDATE_PROTO =
             ProductPriceUpdate.newBuilder()
diff --git a/chrome/app/chrome_command_ids.h b/chrome/app/chrome_command_ids.h
index 50aa06c..43ab20de 100644
--- a/chrome/app/chrome_command_ids.h
+++ b/chrome/app/chrome_command_ids.h
@@ -269,7 +269,6 @@
 #define IDC_RECENT_TABS_LOGIN_FOR_DEVICE_TABS  40277
 #define IDC_OPEN_RECENT_TAB             40278
 #define IDC_OPEN_SAFETY_HUB             40279
-#define IDC_SHOW_PASSWORD_CHECKUP       40280
 
 // Spell-check
 // Insert any additional suggestions before _LAST; these have to be consecutive.
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index eab5eda..123746b 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -152,7 +152,7 @@
     Next
   </message>
   <message name="IDS_CELLULAR_SETUP_SKIP_DISCOVERY_LABEL" desc="Label for button that skips the multiple profile selection step and sets up a new profile during eSIM cellular setup">
-    Skip &amp; Set up new profile
+    Skip &amp; set up new profile
   </message>
   <message name="IDS_CELLULAR_SETUP_CONFIRM_LABEL" desc="Label for button that verifies the confirmation code entered during cellular setup">
     Confirm
@@ -227,7 +227,7 @@
     We've found multiple profiles available to download. Select the ones you would like to download before proceeding.
   </message>
   <message name="IDS_CELLULAR_SETUP_PROFILE_LIST_PAGE_MESSAGE_WITH_LINK" desc="Label informing the user that they can choose to setup an eSIM profile manually.">
-    You can also setup an eSIM profile <ph name="BEGIN_LINK">&lt;a href="#" &gt;</ph>manually<ph name="END_LINK">&lt;/a&gt;</ph>.
+    You can also set up an eSIM profile <ph name="BEGIN_LINK">&lt;a href="#" &gt;</ph>manually<ph name="END_LINK">&lt;/a&gt;</ph>
   </message>
  <message name="IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE" desc="Label for informing the user on ways to retrieve an eSim profile">
     Scan a QR Code using your device camera or enter the activation code provided by your carrier.
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_PROFILE_LIST_PAGE_MESSAGE_WITH_LINK.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_PROFILE_LIST_PAGE_MESSAGE_WITH_LINK.png.sha1
index f324034..3516e6a 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_PROFILE_LIST_PAGE_MESSAGE_WITH_LINK.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_PROFILE_LIST_PAGE_MESSAGE_WITH_LINK.png.sha1
@@ -1 +1 @@
-2219ca55c9f7f72a9f082f97d881881e91f1ac27
\ No newline at end of file
+2cf7efa3b82b4f37c620d65dbb6d1ef4575bdb72
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_SKIP_DISCOVERY_LABEL.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_SKIP_DISCOVERY_LABEL.png.sha1
index fe186935a..3516e6a 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_SKIP_DISCOVERY_LABEL.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_CELLULAR_SETUP_SKIP_DISCOVERY_LABEL.png.sha1
@@ -1 +1 @@
-c3e2157a5e4c36dbb471ffacb5843357522d38f5
\ No newline at end of file
+2cf7efa3b82b4f37c620d65dbb6d1ef4575bdb72
\ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index c17603c..9e1c61b 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -11235,6 +11235,12 @@
      flag_descriptions::kSyncSessionOnVisibilityChangedDescription, kOsAll,
      FEATURE_VALUE_TYPE(syncer::kSyncSessionOnVisibilityChanged)},
 
+#if BUILDFLAG(IS_ANDROID)
+    {"dynamic-top-chrome", flag_descriptions::kDynamicTopChromeName,
+     flag_descriptions::kDynamicTopChromeDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kDynamicTopChrome)},
+#endif
+
 #if !BUILDFLAG(IS_ANDROID)
     {"password-generation-strong-label-experiment",
      flag_descriptions::kPasswordGenerationStrongLabelExperimentName,
diff --git a/chrome/browser/android/preferences/autofill/autofill_payment_methods_delegate.cc b/chrome/browser/android/preferences/autofill/autofill_payment_methods_delegate.cc
index 5fc0382..da5586f 100644
--- a/chrome/browser/android/preferences/autofill/autofill_payment_methods_delegate.cc
+++ b/chrome/browser/android/preferences/autofill/autofill_payment_methods_delegate.cc
@@ -16,7 +16,7 @@
 #include "chrome/browser/ui/autofill/risk_util.h"
 #include "components/autofill/content/browser/content_autofill_driver.h"
 #include "components/autofill/core/browser/browser_autofill_manager.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/virtual_card_enrollment_flow.h"
 #include "components/autofill/core/browser/payments/virtual_card_enrollment_manager.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
@@ -42,12 +42,14 @@
 AutofillPaymentMethodsDelegate::AutofillPaymentMethodsDelegate(Profile* profile)
     : profile_(profile) {
   personal_data_manager_ = PersonalDataManagerFactory::GetForProfile(profile);
-  payments_client_ = std::make_unique<payments::PaymentsClient>(
-      profile->GetURLLoaderFactory(),
-      IdentityManagerFactory::GetForProfile(profile), personal_data_manager_);
+  payments_network_interface_ =
+      std::make_unique<payments::PaymentsNetworkInterface>(
+          profile->GetURLLoaderFactory(),
+          IdentityManagerFactory::GetForProfile(profile),
+          personal_data_manager_);
   virtual_card_enrollment_manager_ =
-      std::make_unique<VirtualCardEnrollmentManager>(personal_data_manager_,
-                                                     payments_client_.get());
+      std::make_unique<VirtualCardEnrollmentManager>(
+          personal_data_manager_, payments_network_interface_.get());
 }
 
 AutofillPaymentMethodsDelegate::~AutofillPaymentMethodsDelegate() = default;
diff --git a/chrome/browser/android/preferences/autofill/autofill_payment_methods_delegate.h b/chrome/browser/android/preferences/autofill/autofill_payment_methods_delegate.h
index 60ea666..61a719d6 100644
--- a/chrome/browser/android/preferences/autofill/autofill_payment_methods_delegate.h
+++ b/chrome/browser/android/preferences/autofill/autofill_payment_methods_delegate.h
@@ -24,7 +24,7 @@
 class VirtualCardEnrollmentManager;
 
 namespace payments {
-class PaymentsClient;
+class PaymentsNetworkInterface;
 }
 
 // Delegate that listens to changes made in the settings related to payment
@@ -56,7 +56,8 @@
  private:
   raw_ptr<Profile> profile_;                            // weak reference
   raw_ptr<PersonalDataManager> personal_data_manager_;  // weak reference
-  std::unique_ptr<payments::PaymentsClient> payments_client_;
+  std::unique_ptr<payments::PaymentsNetworkInterface>
+      payments_network_interface_;
   std::unique_ptr<VirtualCardEnrollmentManager>
       virtual_card_enrollment_manager_;
 };
diff --git a/chrome/browser/apps/app_deduplication_service/BUILD.gn b/chrome/browser/apps/app_deduplication_service/BUILD.gn
index adc1d743..779973f 100644
--- a/chrome/browser/apps/app_deduplication_service/BUILD.gn
+++ b/chrome/browser/apps/app_deduplication_service/BUILD.gn
@@ -28,7 +28,6 @@
   deps = [
     "//base",
     "//chrome/browser/apps/almanac_api_client",
-    "//chrome/browser/apps/app_provisioning_service",
     "//chrome/browser/apps/app_service",
     "//chrome/browser/profiles",
     "//chrome/browser/profiles:profile",
@@ -57,7 +56,6 @@
     "//base",
     "//base/test:test_support",
     "//chrome/browser/apps/almanac_api_client",
-    "//chrome/browser/apps/app_provisioning_service",
     "//chrome/browser/apps/app_service",
     "//chrome/common:constants",
     "//chrome/test:test_support",
diff --git a/chrome/browser/apps/app_deduplication_service/app_deduplication_service.cc b/chrome/browser/apps/app_deduplication_service/app_deduplication_service.cc
index 47141ce5..dcc61f3 100644
--- a/chrome/browser/apps/app_deduplication_service/app_deduplication_service.cc
+++ b/chrome/browser/apps/app_deduplication_service/app_deduplication_service.cc
@@ -65,8 +65,6 @@
     : profile_(profile),
       server_connector_(std::make_unique<AppDeduplicationServerConnector>()),
       device_info_manager_(std::make_unique<DeviceInfoManager>(profile)) {
-  app_provisioning_data_observeration_.Observe(
-      AppProvisioningDataManager::Get());
   app_registry_cache_observation_.Observe(
       &apps::AppServiceProxyFactory::GetForProfile(profile)
            ->AppRegistryCache());
diff --git a/chrome/browser/apps/app_deduplication_service/app_deduplication_service.h b/chrome/browser/apps/app_deduplication_service/app_deduplication_service.h
index 663ea454..11c3d7d2 100644
--- a/chrome/browser/apps/app_deduplication_service/app_deduplication_service.h
+++ b/chrome/browser/apps/app_deduplication_service/app_deduplication_service.h
@@ -18,8 +18,6 @@
 #include "chrome/browser/apps/app_deduplication_service/duplicate_group.h"
 #include "chrome/browser/apps/app_deduplication_service/entry_types.h"
 #include "chrome/browser/apps/app_deduplication_service/proto/deduplication_data.pb.h"
-#include "chrome/browser/apps/app_provisioning_service/app_provisioning_data_manager.h"
-#include "chrome/browser/apps/app_provisioning_service/proto/app_data.pb.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/services/app_service/public/cpp/app_registry_cache.h"
 
@@ -32,7 +30,6 @@
 namespace apps::deduplication {
 
 class AppDeduplicationService : public KeyedService,
-                                public AppProvisioningDataManager::Observer,
                                 public apps::AppRegistryCache::Observer {
  public:
   explicit AppDeduplicationService(Profile* profile);
@@ -118,9 +115,6 @@
   std::map<Entry, uint32_t> entry_to_group_map_;
   raw_ptr<Profile, ExperimentalAsh> profile_;
 
-  base::ScopedObservation<AppProvisioningDataManager,
-                          AppProvisioningDataManager::Observer>
-      app_provisioning_data_observeration_{this};
   base::ScopedObservation<apps::AppRegistryCache,
                           apps::AppRegistryCache::Observer>
       app_registry_cache_observation_{this};
diff --git a/chrome/browser/apps/app_deduplication_service/app_deduplication_service_unittest.cc b/chrome/browser/apps/app_deduplication_service/app_deduplication_service_unittest.cc
index f960c06..a07b0d34 100644
--- a/chrome/browser/apps/app_deduplication_service/app_deduplication_service_unittest.cc
+++ b/chrome/browser/apps/app_deduplication_service/app_deduplication_service_unittest.cc
@@ -13,8 +13,6 @@
 #include "chrome/browser/apps/app_deduplication_service/app_deduplication_server_connector.h"
 #include "chrome/browser/apps/app_deduplication_service/app_deduplication_service_factory.h"
 #include "chrome/browser/apps/app_deduplication_service/proto/deduplication_data.pb.h"
-#include "chrome/browser/apps/app_provisioning_service/app_provisioning_data_manager.h"
-#include "chrome/browser/apps/app_provisioning_service/proto/app_data.pb.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/common/chrome_features.h"
diff --git a/chrome/browser/apps/app_service/publishers/arc_apps.cc b/chrome/browser/apps/app_service/publishers/arc_apps.cc
index 0854cff0..2fb0a16 100644
--- a/chrome/browser/apps/app_service/publishers/arc_apps.cc
+++ b/chrome/browser/apps/app_service/publishers/arc_apps.cc
@@ -1559,13 +1559,15 @@
 }
 
 void ArcApps::OnInstallationFinished(const std::string& package_name,
-                                     bool success) {
+                                     bool success,
+                                     bool is_launchable_app) {
   if (ash::features::ArePromiseIconsEnabled() &&
       ArcVersionEligibleForPromiseIcons()) {
-    // Remove the promise app of any failed installation.
-    if (success) {
+    if (success && is_launchable_app) {
       return;
     }
+    // Remove the promise app of any failed installation or non-launchable
+    // package.
     PackageId package_id(AppType::kArc, package_name);
     if (!proxy()->PromiseAppRegistryCache()->HasPromiseApp(package_id)) {
       return;
diff --git a/chrome/browser/apps/app_service/publishers/arc_apps.h b/chrome/browser/apps/app_service/publishers/arc_apps.h
index a4250a4d..2c057d1b 100644
--- a/chrome/browser/apps/app_service/publishers/arc_apps.h
+++ b/chrome/browser/apps/app_service/publishers/arc_apps.h
@@ -160,7 +160,8 @@
   void OnInstallationActiveChanged(const std::string& package_name,
                                    bool active) override;
   void OnInstallationFinished(const std::string& package_name,
-                              bool success) override;
+                              bool success,
+                              bool is_launchable_app) override;
 
   // arc::ArcIntentHelperObserver overrides.
   void OnIntentFiltersUpdated(
diff --git a/chrome/browser/apps/app_service/publishers/arc_apps_unittest.cc b/chrome/browser/apps/app_service/publishers/arc_apps_unittest.cc
index c085d7c6..d9d018f 100644
--- a/chrome/browser/apps/app_service/publishers/arc_apps_unittest.cc
+++ b/chrome/browser/apps/app_service/publishers/arc_apps_unittest.cc
@@ -734,6 +734,25 @@
 }
 
 TEST_F(ArcAppsPublisherPromiseAppTest,
+       SuccessfulInstallationOfNonLaunchablePackageRemovesPromiseApp) {
+  // Add a promise app to the cache.
+  std::unique_ptr<apps::PromiseApp> promise_app =
+      std::make_unique<apps::PromiseApp>(kTestPackageId);
+  promise_app->status = apps::PromiseStatus::kPending;
+  cache()->OnPromiseApp(std::move(promise_app));
+
+  // Check that the promise app exists.
+  EXPECT_TRUE(cache()->HasPromiseApp(kTestPackageId));
+
+  // Confirm that the promise app gets removed after successful installation of
+  // a non-launchable package.
+  arc_test()->app_instance()->SendInstallationFinished(
+      kTestPackageName, /*success=*/true,
+      /*is_launchable_app=*/false);
+  EXPECT_FALSE(cache()->HasPromiseApp(kTestPackageId));
+}
+
+TEST_F(ArcAppsPublisherPromiseAppTest,
        SuccessfulInstallationRemovesPromiseApp) {
   // Add a promise app to the cache.
   std::unique_ptr<apps::PromiseApp> promise_app =
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index c549c9a..1978a85 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -4000,9 +4000,6 @@
   const GURL auth_url = embedded_test_server()->GetURL("/auth-basic");
   content::NavigationController* guest_controller =
       &GetGuestView()->GetController();
-  LoginPromptBrowserTestObserver login_observer;
-  login_observer.Register(
-      content::Source<content::NavigationController>(guest_controller));
   WindowedAuthNeededObserver auth_needed(guest_controller);
   WindowedAuthSuppliedObserver auth_supplied(guest_controller);
   // There are two navigations occurring here. The first fails due to the need
@@ -4016,7 +4013,8 @@
                       content::JsReplace("location.href = $1;", auth_url)));
   auth_needed.Wait();
 
-  LoginHandler* login_handler = login_observer.handlers().front();
+  LoginHandler* login_handler =
+      LoginHandler::GetAllLoginHandlersForTest().front();
   login_handler->SetAuth(u"basicuser", u"secret");
   auth_supplied.Wait();
   nav_observer.WaitForNavigationFinished();
@@ -4031,11 +4029,6 @@
       &GetGuestView()->GetController();
   content::NavigationController* tab_controller =
       &browser()->tab_strip_model()->GetActiveWebContents()->GetController();
-  LoginPromptBrowserTestObserver login_observer;
-  login_observer.Register(
-      content::Source<content::NavigationController>(guest_controller));
-  login_observer.Register(
-      content::Source<content::NavigationController>(tab_controller));
   WindowedAuthNeededObserver guest_auth_needed(guest_controller);
   WindowedAuthNeededObserver tab_auth_needed(tab_controller);
   WindowedAuthSuppliedObserver guest_auth_supplied(guest_controller);
@@ -4061,9 +4054,11 @@
   // identical challenges if multiple prompts are shown for them. However,
   // credentials can't be shared across StoragePartitions. So providing
   // credentials within the guest should not affect the tab.
-  ASSERT_EQ(2u, login_observer.handlers().size());
-  LoginHandler* guest_login_handler = login_observer.handlers().front();
-  LoginHandler* tab_login_handler = login_observer.handlers().back();
+  ASSERT_EQ(2u, LoginHandler::GetAllLoginHandlersForTest().size());
+  LoginHandler* guest_login_handler =
+      LoginHandler::GetAllLoginHandlersForTest().front();
+  LoginHandler* tab_login_handler =
+      LoginHandler::GetAllLoginHandlersForTest().back();
   EXPECT_EQ(tab_controller,
             &tab_login_handler->web_contents()->GetController());
   EXPECT_TRUE(guest_login_handler->auth_info().MatchesExceptPath(
@@ -4074,8 +4069,9 @@
   guest_nav_observer.WaitForNavigationFinished();
 
   // The tab should still be prompting for credentials.
-  ASSERT_EQ(1u, login_observer.handlers().size());
-  EXPECT_EQ(tab_login_handler, login_observer.handlers().front());
+  ASSERT_EQ(1u, LoginHandler::GetAllLoginHandlersForTest().size());
+  EXPECT_EQ(tab_login_handler,
+            LoginHandler::GetAllLoginHandlersForTest().front());
 }
 
 namespace {
diff --git a/chrome/browser/ash/app_list/app_service/app_service_shortcut_item_browsertest.cc b/chrome/browser/ash/app_list/app_service/app_service_shortcut_item_browsertest.cc
index 095cbb9..d15b7035 100644
--- a/chrome/browser/ash/app_list/app_service/app_service_shortcut_item_browsertest.cc
+++ b/chrome/browser/ash/app_list/app_service/app_service_shortcut_item_browsertest.cc
@@ -456,7 +456,7 @@
       std::make_unique<Shortcut>(cache()->GetShortcutHostAppId(shortcut_id),
                                  cache()->GetShortcutLocalId(shortcut_id));
   delta->icon_key = IconKey();
-  delta->icon_key->update_version = 100;
+  delta->icon_key->update_version = true;
   cache()->UpdateShortcut(std::move(delta));
 
   EXPECT_EQ(app_list_item->CloneMetadata()->icon_version, 1);
diff --git a/chrome/browser/ash/app_list/arc/arc_app_list_prefs.cc b/chrome/browser/ash/app_list/arc/arc_app_list_prefs.cc
index 885e0ab5..412445a 100644
--- a/chrome/browser/ash/app_list/arc/arc_app_list_prefs.cc
+++ b/chrome/browser/ash/app_list/arc/arc_app_list_prefs.cc
@@ -2512,7 +2512,8 @@
       HandlePackageRemoved(result->package_name);
     }
     for (auto& observer : observer_list_)
-      observer.OnInstallationFinished(result->package_name, result->success);
+      observer.OnInstallationFinished(result->package_name, result->success,
+                                      result->is_launchable_app);
     if (result->success) {
       InstallationCounterReasonEnum reason =
           InstallationCounterReasonEnum::USER;
diff --git a/chrome/browser/ash/app_list/arc/arc_app_list_prefs.h b/chrome/browser/ash/app_list/arc/arc_app_list_prefs.h
index 8bf823e..984b4b7b 100644
--- a/chrome/browser/ash/app_list/arc/arc_app_list_prefs.h
+++ b/chrome/browser/ash/app_list/arc/arc_app_list_prefs.h
@@ -284,7 +284,8 @@
     // Notifies that installation of package finished. |succeed| is set to true
     // in case of success.
     virtual void OnInstallationFinished(const std::string& package_name,
-                                        bool success) {}
+                                        bool success,
+                                        bool is_launchable_app) {}
 
     // Notifies that ArcAppListPrefs is destroyed.
     virtual void OnArcAppListPrefsDestroyed() {}
diff --git a/chrome/browser/ash/app_list/arc/mock_arc_app_list_prefs_observer.h b/chrome/browser/ash/app_list/arc/mock_arc_app_list_prefs_observer.h
index cfa1a60..a90a19c 100644
--- a/chrome/browser/ash/app_list/arc/mock_arc_app_list_prefs_observer.h
+++ b/chrome/browser/ash/app_list/arc/mock_arc_app_list_prefs_observer.h
@@ -53,8 +53,10 @@
                void(const std::string& package_name, bool uninstalled));
   MOCK_METHOD0(OnPackageListInitialRefreshed, void());
   MOCK_METHOD1(OnInstallationStarted, void(const std::string& package_name));
-  MOCK_METHOD2(OnInstallationFinished,
-               void(const std::string& package_name, bool success));
+  MOCK_METHOD3(OnInstallationFinished,
+               void(const std::string& package_name,
+                    bool success,
+                    bool is_launchable_app));
 };
 
 }  // namespace arc
diff --git a/chrome/browser/ash/apps/apk_web_app_service_factory.cc b/chrome/browser/ash/apps/apk_web_app_service_factory.cc
index c345d2c6..dbaa8b8 100644
--- a/chrome/browser/ash/apps/apk_web_app_service_factory.cc
+++ b/chrome/browser/ash/apps/apk_web_app_service_factory.cc
@@ -16,8 +16,10 @@
 // static
 ApkWebAppService* ApkWebAppServiceFactory::GetForProfile(Profile* profile) {
   // ApkWebAppService is not supported if web apps aren't available.
-  if (!web_app::AreWebAppsEnabled(profile))
+  if (!web_app::AreWebAppsEnabled(profile) ||
+      !arc::IsArcAllowedForProfile(profile)) {
     return nullptr;
+  }
 
   return static_cast<ApkWebAppService*>(
       GetInstance()->GetServiceForBrowserContext(profile, true));
diff --git a/chrome/browser/ash/arc/nearby_share/ui/error_dialog_view.cc b/chrome/browser/ash/arc/nearby_share/ui/error_dialog_view.cc
index f4bd3ba..302d3d2d 100644
--- a/chrome/browser/ash/arc/nearby_share/ui/error_dialog_view.cc
+++ b/chrome/browser/ash/arc/nearby_share/ui/error_dialog_view.cc
@@ -8,8 +8,6 @@
 
 #include "ash/frame/non_client_frame_view_ash.h"
 #include "base/functional/callback_forward.h"
-#include "chrome/browser/nearby_sharing/common/nearby_share_features.h"
-#include "chrome/browser/nearby_sharing/common/nearby_share_resource_getter.h"
 #include "components/strings/grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/views/view.h"
@@ -27,11 +25,7 @@
   SetAcceptCallback(std::move(close_callback));
 
   AddDialogMessage(
-      features::IsNameEnabled()
-          ? NearbyShareResourceGetter::GetInstance()->GetStringWithFeatureName(
-                IDS_ASH_ARC_NEARBY_SHARE_ERROR_DIALOG_MESSAGE_PH)
-          : l10n_util::GetStringUTF16(
-                IDS_ASH_ARC_NEARBY_SHARE_ERROR_DIALOG_MESSAGE));
+      l10n_util::GetStringUTF16(IDS_ASH_ARC_NEARBY_SHARE_ERROR_DIALOG_MESSAGE));
 }
 
 ErrorDialogView::~ErrorDialogView() = default;
diff --git a/chrome/browser/ash/policy/reporting/arc_app_install_event_log_collector.cc b/chrome/browser/ash/policy/reporting/arc_app_install_event_log_collector.cc
index 50ae5b6..38d74a2 100644
--- a/chrome/browser/ash/policy/reporting/arc_app_install_event_log_collector.cc
+++ b/chrome/browser/ash/policy/reporting/arc_app_install_event_log_collector.cc
@@ -123,7 +123,8 @@
 
 void ArcAppInstallEventLogCollector::OnInstallationFinished(
     const std::string& package_name,
-    bool success) {
+    bool success,
+    bool is_launchable_app) {
   if (!pending_packages_.count(package_name)) {
     return;
   }
diff --git a/chrome/browser/ash/policy/reporting/arc_app_install_event_log_collector.h b/chrome/browser/ash/policy/reporting/arc_app_install_event_log_collector.h
index c42ebd5..6dcf6dd 100644
--- a/chrome/browser/ash/policy/reporting/arc_app_install_event_log_collector.h
+++ b/chrome/browser/ash/policy/reporting/arc_app_install_event_log_collector.h
@@ -83,7 +83,8 @@
   // ArcAppListPrefs::Observer:
   void OnInstallationStarted(const std::string& package_name) override;
   void OnInstallationFinished(const std::string& package_name,
-                              bool success) override;
+                              bool success,
+                              bool is_launchable_app) override;
 
  protected:
   // Overrides to handle events from InstallEventLogCollectorBase.
diff --git a/chrome/browser/ash/policy/reporting/arc_app_install_event_log_collector_unittest.cc b/chrome/browser/ash/policy/reporting/arc_app_install_event_log_collector_unittest.cc
index 477e114..c8e4518 100644
--- a/chrome/browser/ash/policy/reporting/arc_app_install_event_log_collector_unittest.cc
+++ b/chrome/browser/ash/policy/reporting/arc_app_install_event_log_collector_unittest.cc
@@ -432,7 +432,8 @@
   std::unique_ptr<ArcAppInstallEventLogCollector> collector =
       std::make_unique<ArcAppInstallEventLogCollector>(delegate(), profile(),
                                                        packages_);
-  collector->OnInstallationFinished(kPackageName, /* success */ true);
+  collector->OnInstallationFinished(kPackageName, /*success=*/true,
+                                    /*is_launchable_app=*/true);
 
   int second_to_last_request_index = delegate()->requests().size() - 2;
   EXPECT_EQ(1, delegate()->update_policy_success_rate_count());
@@ -447,7 +448,8 @@
   std::unique_ptr<ArcAppInstallEventLogCollector> collector =
       std::make_unique<ArcAppInstallEventLogCollector>(delegate(), profile(),
                                                        packages_);
-  collector->OnInstallationFinished(kPackageName, /* success */ false);
+  collector->OnInstallationFinished(kPackageName, /*success=*/false,
+                                    /*is_launchable_app=*/false);
 
   int second_to_last_request_index = delegate()->requests().size() - 2;
   EXPECT_EQ(1, delegate()->update_policy_success_rate_count());
diff --git a/chrome/browser/ash/scanning/fake_lorgnette_scanner_manager.cc b/chrome/browser/ash/scanning/fake_lorgnette_scanner_manager.cc
index 1bda8fc3..25410c5f 100644
--- a/chrome/browser/ash/scanning/fake_lorgnette_scanner_manager.cc
+++ b/chrome/browser/ash/scanning/fake_lorgnette_scanner_manager.cc
@@ -110,6 +110,14 @@
       FROM_HERE, base::BindOnce(std::move(callback), set_options_response_));
 }
 
+void FakeLorgnetteScannerManager::GetCurrentConfig(
+    const lorgnette::GetCurrentConfigRequest& request,
+    GetCurrentConfigCallback callback) {
+  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
+      FROM_HERE,
+      base::BindOnce(std::move(callback), get_current_config_response_));
+}
+
 void FakeLorgnetteScannerManager::StartPreparedScan(
     const lorgnette::StartPreparedScanRequest& request,
     StartPreparedScanCallback callback) {
@@ -216,6 +224,11 @@
   set_options_response_ = response;
 }
 
+void FakeLorgnetteScannerManager::SetGetCurrentConfigResponse(
+    const absl::optional<lorgnette::GetCurrentConfigResponse>& response) {
+  get_current_config_response_ = response;
+}
+
 void FakeLorgnetteScannerManager::SetStartPreparedScanResponse(
     const absl::optional<lorgnette::StartPreparedScanResponse>& response) {
   start_prepared_scan_response_ = response;
diff --git a/chrome/browser/ash/scanning/fake_lorgnette_scanner_manager.h b/chrome/browser/ash/scanning/fake_lorgnette_scanner_manager.h
index 9c97ff0..cb15f70a 100644
--- a/chrome/browser/ash/scanning/fake_lorgnette_scanner_manager.h
+++ b/chrome/browser/ash/scanning/fake_lorgnette_scanner_manager.h
@@ -37,6 +37,8 @@
                     CloseScannerCallback callback) override;
   void SetOptions(const lorgnette::SetOptionsRequest& request,
                   SetOptionsCallback callback) override;
+  void GetCurrentConfig(const lorgnette::GetCurrentConfigRequest& request,
+                        GetCurrentConfigCallback callback) override;
   void StartPreparedScan(const lorgnette::StartPreparedScanRequest& request,
                          StartPreparedScanCallback callback) override;
   void ReadScanData(const lorgnette::ReadScanDataRequest& request,
@@ -77,6 +79,10 @@
   void SetSetOptionsResponse(
       const absl::optional<lorgnette::SetOptionsResponse>& response);
 
+  // Sets the response returned by GetCurrentConfig().
+  void SetGetCurrentConfigResponse(
+      const absl::optional<lorgnette::GetCurrentConfigResponse>& response);
+
   // Sets the response returned by StartPreparedScan().
   void SetStartPreparedScanResponse(
       const absl::optional<lorgnette::StartPreparedScanResponse>& response);
@@ -100,6 +106,8 @@
   absl::optional<lorgnette::OpenScannerResponse> open_scanner_response_;
   absl::optional<lorgnette::CloseScannerResponse> close_scanner_response_;
   absl::optional<lorgnette::SetOptionsResponse> set_options_response_;
+  absl::optional<lorgnette::GetCurrentConfigResponse>
+      get_current_config_response_;
   absl::optional<lorgnette::StartPreparedScanResponse>
       start_prepared_scan_response_;
   absl::optional<lorgnette::ReadScanDataResponse> read_scan_data_response_;
diff --git a/chrome/browser/ash/scanning/lorgnette_scanner_manager.cc b/chrome/browser/ash/scanning/lorgnette_scanner_manager.cc
index 83108fd..5c81657 100644
--- a/chrome/browser/ash/scanning/lorgnette_scanner_manager.cc
+++ b/chrome/browser/ash/scanning/lorgnette_scanner_manager.cc
@@ -240,6 +240,15 @@
   }
 
   // LorgnetteScannerManager:
+  void GetCurrentConfig(const lorgnette::GetCurrentConfigRequest& request,
+                        GetCurrentConfigCallback callback) override {
+    GetLorgnetteManagerClient()->GetCurrentConfig(
+        request,
+        base::BindOnce(&LorgnetteScannerManagerImpl::OnGetCurrentConfigResponse,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  }
+
+  // LorgnetteScannerManager:
   void StartPreparedScan(const lorgnette::StartPreparedScanRequest& request,
                          StartPreparedScanCallback callback) override {
     GetLorgnetteManagerClient()->StartPreparedScan(
@@ -445,6 +454,12 @@
     std::move(callback).Run(response);
   }
 
+  void OnGetCurrentConfigResponse(
+      GetCurrentConfigCallback callback,
+      absl::optional<lorgnette::GetCurrentConfigResponse> response) {
+    std::move(callback).Run(response);
+  }
+
   void OnStartPreparedScanResponse(
       StartPreparedScanCallback callback,
       absl::optional<lorgnette::StartPreparedScanResponse> response) {
diff --git a/chrome/browser/ash/scanning/lorgnette_scanner_manager.h b/chrome/browser/ash/scanning/lorgnette_scanner_manager.h
index 3030cdc0..1407339 100644
--- a/chrome/browser/ash/scanning/lorgnette_scanner_manager.h
+++ b/chrome/browser/ash/scanning/lorgnette_scanner_manager.h
@@ -36,6 +36,8 @@
       const absl::optional<lorgnette::CloseScannerResponse>& response)>;
   using SetOptionsCallback = base::OnceCallback<void(
       const absl::optional<lorgnette::SetOptionsResponse>& response)>;
+  using GetCurrentConfigCallback = base::OnceCallback<void(
+      const absl::optional<lorgnette::GetCurrentConfigResponse>& response)>;
   using StartPreparedScanCallback = base::OnceCallback<void(
       const absl::optional<lorgnette::StartPreparedScanResponse>& response)>;
   using ReadScanDataCallback = base::OnceCallback<void(
@@ -97,6 +99,12 @@
   virtual void SetOptions(const lorgnette::SetOptionsRequest& request,
                           SetOptionsCallback callback) = 0;
 
+  // Gets the config for the scanner described by |request|.  If an error
+  // occurs, absl::nullopt is returned in the callback.
+  virtual void GetCurrentConfig(
+      const lorgnette::GetCurrentConfigRequest& request,
+      GetCurrentConfigCallback callback) = 0;
+
   // Starts a scan using information in |request| and returns the result using
   // the provided |callback|.  If an error occurs, absl::nullopt is returned in
   // the callback.
diff --git a/chrome/browser/ash/scanning/lorgnette_scanner_manager_unittest.cc b/chrome/browser/ash/scanning/lorgnette_scanner_manager_unittest.cc
index 81fcdca..5cdc565 100644
--- a/chrome/browser/ash/scanning/lorgnette_scanner_manager_unittest.cc
+++ b/chrome/browser/ash/scanning/lorgnette_scanner_manager_unittest.cc
@@ -263,6 +263,15 @@
                        base::Unretained(this)));
   }
 
+  // Calls LorgnetteScannerManager::GetCurrentConfig() and binds a callback to
+  // process the result.
+  void GetCurrentConfig() {
+    lorgnette_scanner_manager_->GetCurrentConfig(
+        lorgnette::GetCurrentConfigRequest(),
+        base::BindOnce(&LorgnetteScannerManagerTest::GetCurrentConfigCallback,
+                       base::Unretained(this)));
+  }
+
   // Calls LorgnetteScannerManager::StartPreparedScan() and binds a callback to
   // process the result.
   void StartPreparedScan() {
@@ -356,6 +365,11 @@
     return set_options_response_;
   }
 
+  absl::optional<lorgnette::GetCurrentConfigResponse>
+  get_current_config_response() const {
+    return get_current_config_response_;
+  }
+
   absl::optional<lorgnette::StartPreparedScanResponse>
   start_prepared_scan_response() const {
     return start_prepared_scan_response_;
@@ -414,6 +428,12 @@
     run_loop_->Quit();
   }
 
+  void GetCurrentConfigCallback(
+      const absl::optional<lorgnette::GetCurrentConfigResponse>& response) {
+    get_current_config_response_ = response;
+    run_loop_->Quit();
+  }
+
   void StartPreparedScanCallback(
       const absl::optional<lorgnette::StartPreparedScanResponse>& response) {
     start_prepared_scan_response_ = response;
@@ -466,6 +486,8 @@
   absl::optional<lorgnette::OpenScannerResponse> open_scanner_response_;
   absl::optional<lorgnette::CloseScannerResponse> close_scanner_response_;
   absl::optional<lorgnette::SetOptionsResponse> set_options_response_;
+  absl::optional<lorgnette::GetCurrentConfigResponse>
+      get_current_config_response_;
   absl::optional<lorgnette::StartPreparedScanResponse>
       start_prepared_scan_response_;
   absl::optional<lorgnette::ReadScanDataResponse> read_scan_data_response_;
@@ -1029,6 +1051,22 @@
   EXPECT_THAT(response, EqualsProto(set_options_response().value()));
 }
 
+// Test getting the config for a scanner.
+TEST_F(LorgnetteScannerManagerTest, GetCurrentConfig) {
+  constexpr std::string kScannerToken = "scanner-token";
+
+  lorgnette::GetCurrentConfigResponse response;
+  response.mutable_scanner()->set_token(kScannerToken);
+  response.set_result(lorgnette::OPERATION_RESULT_SUCCESS);
+  response.mutable_config()->mutable_scanner()->set_token(kScannerToken);
+
+  GetLorgnetteManagerClient()->SetGetCurrentConfigResponse(response);
+  GetCurrentConfig();
+  WaitForResult();
+  ASSERT_TRUE(get_current_config_response());
+  EXPECT_THAT(response, EqualsProto(get_current_config_response().value()));
+}
+
 // Test starting a prepared scan.
 TEST_F(LorgnetteScannerManagerTest, StartPreparedScan) {
   lorgnette::ScannerHandle handle;
diff --git a/chrome/browser/bookmarks/android/bookmark_bridge.cc b/chrome/browser/bookmarks/android/bookmark_bridge.cc
index d0e1a83b..6bf4d48 100644
--- a/chrome/browser/bookmarks/android/bookmark_bridge.cc
+++ b/chrome/browser/bookmarks/android/bookmark_bridge.cc
@@ -226,47 +226,32 @@
 }
 
 base::android::ScopedJavaLocalRef<jobject>
-BookmarkBridge::GetBookmarkIdForWebContents(
+BookmarkBridge::GetMostRecentlyAddedUserBookmarkIdForUrl(
     JNIEnv* env,
-    const JavaParamRef<jobject>& jweb_contents,
-    jboolean only_editable) {
+    const JavaParamRef<jobject>& j_url) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  std::unique_ptr<GURL> url = url::GURLAndroid::ToNativeGURL(env, j_url);
 
-  auto* web_contents = content::WebContents::FromJavaWebContents(jweb_contents);
-  if (!web_contents)
-    return nullptr;
-
-  GURL url = dom_distiller::url_utils::GetOriginalUrlFromDistillerUrl(
-      web_contents->GetLastCommittedURL());
-
-  // TODO(crbug.com/1150559): This is a hack to avoid a historical issue that
-  // this function doesn't wait for any backend loaded.
-  if (reading_list_manager_->IsLoaded()) {
-    const auto* node = reading_list_manager_->Get(url);
-    if (node)
-      return JavaBookmarkIdCreateBookmarkId(env, node->id(),
-                                            GetBookmarkType(node));
+  std::vector<const bookmarks::BookmarkNode*> nodes;
+  const auto* readingListNode = reading_list_manager_->Get(*url);
+  if (readingListNode) {
+    nodes.push_back(readingListNode);
   }
 
-  // Get all the nodes for |url| and sort them by date added.
-  bookmarks::ManagedBookmarkService* managed =
-      ManagedBookmarkServiceFactory::GetForProfile(profile_);
-  bookmarks::BookmarkModel* model =
-      BookmarkModelFactory::GetForBrowserContext(profile_);
-
-  std::vector<const bookmarks::BookmarkNode*> nodes = model->GetNodesByURL(url);
+  // Get all the nodes for |url| from BookmarkModel and sort them by date added.
+  std::vector<const bookmarks::BookmarkNode*> bookmarkModelResult =
+      BookmarkModelFactory::GetForBrowserContext(profile_)->GetNodesByURL(*url);
+  nodes.insert(nodes.end(), bookmarkModelResult.begin(),
+               bookmarkModelResult.end());
   std::sort(nodes.begin(), nodes.end(), &bookmarks::MoreRecentlyAdded);
 
-  // Return the first node matching the search criteria.
-  for (const auto* node : nodes) {
-    if (only_editable && managed->IsNodeManaged(node)) {
-      continue;
-    }
-    return JavaBookmarkIdCreateBookmarkId(env, node->id(),
-                                          GetBookmarkType(node));
+  if (nodes.size() == 0) {
+    return nullptr;
   }
 
-  return nullptr;
+  // Return the first node matching the search criteria.
+  return JavaBookmarkIdCreateBookmarkId(env, nodes.front()->id(),
+                                        GetBookmarkType(nodes.front()));
 }
 
 jboolean BookmarkBridge::IsEditBookmarksEnabled(JNIEnv* env) {
diff --git a/chrome/browser/bookmarks/android/bookmark_bridge.h b/chrome/browser/bookmarks/android/bookmark_bridge.h
index d6d24bd..aa2b73a6 100644
--- a/chrome/browser/bookmarks/android/bookmark_bridge.h
+++ b/chrome/browser/bookmarks/android/bookmark_bridge.h
@@ -64,11 +64,10 @@
       const base::android::JavaParamRef<jobject>& j_url,
       const base::android::JavaParamRef<jobject>& j_callback);
 
-  base::android::ScopedJavaLocalRef<jobject> GetBookmarkIdForWebContents(
+  base::android::ScopedJavaLocalRef<jobject>
+  GetMostRecentlyAddedUserBookmarkIdForUrl(
       JNIEnv* env,
-
-      const base::android::JavaParamRef<jobject>& jweb_contents,
-      jboolean only_editable);
+      const base::android::JavaParamRef<jobject>& j_url);
 
   bool IsDoingExtensiveChanges(JNIEnv* env);
 
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 43b9f92..5d67549e 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -232,6 +232,9 @@
         <include name="IDR_CHROME_URLS_DISABLED_PAGE_HTML" file="resources\chromeos\chrome_urls_disabled_page\app.html" type="BINDATA" />
         <include name="IDR_ECHO_MANIFEST" file="resources\chromeos\echo\manifest.json" type="BINDATA" />
         <include name="IDR_INCOGNITO_NAVIGATION_BLOCKED_PAGE_HTML" file="resources\chromeos\enterprise\incognito_navigation_blocked_page\incognito_blocked.html" flattenhtml="true" type="BINDATA" />
+        <if expr="_google_chrome">
+          <include name="IDR_QUICKOFFICE_MANIFEST" file="resources\chromeos\quickoffice\manifest.json" type="BINDATA" />
+        </if>
       </if>
       <if expr="_google_chrome">
         <include name="IDR_PREF_HASH_SEED_BIN" file="resources\settings_internal\pref_hash_seed.bin" type="BINDATA" />
diff --git a/chrome/browser/content_extraction/inner_text.cc b/chrome/browser/content_extraction/inner_text.cc
index b0d0e8f..2e32306 100644
--- a/chrome/browser/content_extraction/inner_text.cc
+++ b/chrome/browser/content_extraction/inner_text.cc
@@ -75,9 +75,10 @@
   auto* agent_ptr = agent.get();
   agent_ptr->GetInnerText(
       std::move(params),
-      base::BindOnce(&OnGotInnerText, start_time, std::move(agent),
-                     mojo::WrapCallbackWithDefaultInvokeIfNotRun(
-                         std::move(callback), nullptr)));
+      mojo::WrapCallbackWithDefaultInvokeIfNotRun(
+          base::BindOnce(&OnGotInnerText, start_time, std::move(agent),
+                         std::move(callback)),
+          nullptr));
 }
 
 namespace internal {
diff --git a/chrome/browser/extensions/api/tabs/tabs_apitest.cc b/chrome/browser/extensions/api/tabs/tabs_apitest.cc
index f89bdb0..944918a 100644
--- a/chrome/browser/extensions/api/tabs/tabs_apitest.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_apitest.cc
@@ -540,6 +540,11 @@
   ASSERT_TRUE(RunExtensionTest("tabs/prerendering")) << message_;
 }
 
+IN_PROC_BROWSER_TEST_F(ExtensionApiTabPrerenderingTest,
+                       PrerenderingIntoANewTab) {
+  ASSERT_TRUE(RunExtensionTest("tabs/prerendering_into_new_tab")) << message_;
+}
+
 // Adding a new test? Awesome. But API tests are the old hotness. The new
 // hotness is api_test_utils. See tabs_test.cc for an example.
 // We are trying to phase out many uses of API tests as they tend to be flaky.
diff --git a/chrome/browser/extensions/component_extensions_allowlist/allowlist.cc b/chrome/browser/extensions/component_extensions_allowlist/allowlist.cc
index f1459df..fd03b01 100644
--- a/chrome/browser/extensions/component_extensions_allowlist/allowlist.cc
+++ b/chrome/browser/extensions/component_extensions_allowlist/allowlist.cc
@@ -52,9 +52,6 @@
 #if BUILDFLAG(IS_CHROMEOS)
     extension_misc::kContactCenterInsightsExtensionId,
     extension_misc::kDeskApiExtensionId,
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
-    extension_misc::kQuickOfficeComponentExtensionId,
-#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #endif
   };
 
@@ -106,6 +103,9 @@
     case IDR_CONTACT_CENTER_INSIGHTS_MANIFEST:
     case IDR_DESK_API_MANIFEST:
     case IDR_ECHO_MANIFEST:
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+    case IDR_QUICKOFFICE_MANIFEST:
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #endif  // BUILDFLAG(IS_CHROMEOS)
       return true;
   }
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index a1b5b99..7bec51e 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -547,11 +547,9 @@
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     if (!base::FeatureList::IsEnabled(
             chromeos::features::kDisableOfficeEditingComponentApp)) {
-      AddComponentFromDirWithManifestFilename(
-          base::FilePath("/usr/share/chromeos-assets/quickoffice"),
-          extension_misc::kQuickOfficeComponentExtensionId,
-          extensions::kManifestFilename, extensions::kManifestFilename,
-          base::DoNothing());
+      Add(IDR_QUICKOFFICE_MANIFEST,
+          base::FilePath(
+              FILE_PATH_LITERAL("/usr/share/chromeos-assets/quickoffice")));
     }
 #endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #endif  // BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/browser/fast_checkout/fast_checkout_client_impl_unittest.cc b/chrome/browser/fast_checkout/fast_checkout_client_impl_unittest.cc
index acaf124..bdc0f4b3 100644
--- a/chrome/browser/fast_checkout/fast_checkout_client_impl_unittest.cc
+++ b/chrome/browser/fast_checkout/fast_checkout_client_impl_unittest.cc
@@ -270,8 +270,8 @@
     test_client_->InjectFastCheckoutController(
         std::move(fast_checkout_controller));
 
-    autofill_client()->set_test_payments_client(
-        std::make_unique<autofill::payments::TestPaymentsClient>(
+    autofill_client()->set_test_payments_network_interface(
+        std::make_unique<autofill::payments::TestPaymentsNetworkInterface>(
             autofill_client()->GetURLLoaderFactory(),
             autofill_client()->GetIdentityManager(),
             autofill_client()->GetPersonalDataManager()));
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 45fdf09..cbf85ca 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1865,6 +1865,11 @@
     "expiry_milestone": 124
   },
   {
+    "name": "dynamic-top-chrome",
+    "owners": ["wenyufu@chromium.org", "clank-large-form-factors@google.com"],
+    "expiry_milestone": 126
+  },
+  {
     "name": "eap-gtc-wifi-authentication",
     "owners": [ "cros-connectivity@google.com" ],
     "expiry_milestone": 120
@@ -2645,11 +2650,6 @@
     "expiry_milestone": 130
   },
   {
-    "name": "enable-feed-synthetic-capabilities",
-    "owners": [ "sczs@chromium.org", "adamta@chromium.org" ],
-    "expiry_milestone": 120
-  },
-  {
     "name": "enable-fenced-frames",
     "owners": [ "dom@chromium.org", "shivanisha@chromium.org", "chrome-fenced-frames@google.com" ],
     "expiry_milestone": 130
@@ -7086,6 +7086,11 @@
     "expiry_milestone": -1
   },
   {
+    "name": "set-up-list-content-notification",
+    "owners": ["tinazwang@google.com", "chrome-sherlock@google.com"],
+    "expiry_milestone": 130
+  },
+  {
     "name": "settings-app-notification-settings",
     "owners": [ "yulunwu@chromium.org" ],
     "expiry_milestone": 96
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 298e378..a27eb8594 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -4050,6 +4050,11 @@
     "Enables the Android feature Edge-to-Edge and forces a draw ToEdge on most "
     "web pages.";
 
+const char kDynamicTopChromeName[] = "Dynamic Top Chrome";
+const char kDynamicTopChromeDescription[] =
+    "Enables top Chrome (e.g. top toolbar) to change according to the current "
+    "window size.";
+
 const char kEnableCommandLineOnNonRootedName[] =
     "Enable command line on non-rooted devices";
 const char kEnableCommandLineOnNoRootedDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 9b43f58..17cac6d 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2349,6 +2349,9 @@
 extern const char kDrawWebEdgeToEdgeName[];
 extern const char kDrawWebEdgeToEdgeDescription[];
 
+extern const char kDynamicTopChromeName[];
+extern const char kDynamicTopChromeDescription[];
+
 extern const char kEnableAndroidGamepadVibrationName[];
 extern const char kEnableAndroidGamepadVibrationDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 0b19f02f..4623312 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -244,6 +244,7 @@
     &kDrawEdgeToEdge,
     &kDrawNativeEdgeToEdge,
     &kDrawWebEdgeToEdge,
+    &kDynamicTopChrome,
     &kEarlyInitializeStartupMetrics,
     &kEmptyStates,
     &kExperimentsForAgsa,
@@ -783,6 +784,10 @@
              "DrawWebEdgeToEdge",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kDynamicTopChrome,
+             "DynamicTopChrome",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 BASE_FEATURE(kEarlyInitializeStartupMetrics,
              "EarlyInitializeStartupMetrics",
              base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index 6f60935..c25b857f 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -106,6 +106,7 @@
 BASE_DECLARE_FEATURE(kDrawNativeEdgeToEdge);
 BASE_DECLARE_FEATURE(kDrawWebEdgeToEdge);
 BASE_DECLARE_FEATURE(kDragDropIntoOmnibox);
+BASE_DECLARE_FEATURE(kDynamicTopChrome);
 BASE_DECLARE_FEATURE(kEarlyInitializeStartupMetrics);
 BASE_DECLARE_FEATURE(kEmptyStates);
 BASE_DECLARE_FEATURE(kExperimentsForAgsa);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 879a922..9f06bfa 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -263,6 +263,7 @@
     public static final String DRAW_EDGE_TO_EDGE = "DrawEdgeToEdge";
     public static final String DRAW_NATIVE_EDGE_TO_EDGE = "DrawNativeEdgeToEdge";
     public static final String DRAW_WEB_EDGE_TO_EDGE = "DrawWebEdgeToEdge";
+    public static final String DYNAMIC_TOP_CHROME = "DynamicTopChrome";
     public static final String EARLY_INITIALIZE_STARTUP_METRICS = "EarlyInitializeStartupMetrics";
     public static final String ENABLE_PROTO_API_FOR_CLASSIFY_URL = "EnableProtoApiForClassifyUrl";
     public static final String EXPERIMENTS_FOR_AGSA = "ExperimentsForAgsa";
diff --git a/chrome/browser/nearby_sharing/nearby_notification_manager.cc b/chrome/browser/nearby_sharing/nearby_notification_manager.cc
index 8e8237fb..338d9f8 100644
--- a/chrome/browser/nearby_sharing/nearby_notification_manager.cc
+++ b/chrome/browser/nearby_sharing/nearby_notification_manager.cc
@@ -30,7 +30,6 @@
 #include "chrome/browser/nearby_sharing/common/nearby_share_enums.h"
 #include "chrome/browser/nearby_sharing/common/nearby_share_features.h"
 #include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h"
-#include "chrome/browser/nearby_sharing/common/nearby_share_resource_getter.h"
 #include "chrome/browser/nearby_sharing/nearby_share_metrics.h"
 #include "chrome/browser/nearby_sharing/nearby_sharing_service.h"
 #include "chrome/browser/notifications/notification_display_service.h"
@@ -85,10 +84,7 @@
       /*title=*/std::u16string(),
       /*message=*/std::u16string(),
       /*icon=*/ui::ImageModel(),
-      features::IsNameEnabled()
-          ? NearbyShareResourceGetter::GetInstance()->GetStringWithFeatureName(
-                IDS_NEARBY_NOTIFICATION_SOURCE_PH)
-          : l10n_util::GetStringUTF16(IDS_NEARBY_NOTIFICATION_SOURCE),
+      l10n_util::GetStringUTF16(IDS_NEARBY_NOTIFICATION_SOURCE),
       /*origin_url=*/GURL(),
       message_center::NotifierId(message_center::NotifierType::SYSTEM_COMPONENT,
                                  kNearbyNotifier,
@@ -973,12 +969,8 @@
 
   message_center::Notification notification =
       CreateNearbyNotification(kNearbyInProgressNotificationId);
-  notification.set_title(
-      features::IsNameEnabled()
-          ? NearbyShareResourceGetter::GetInstance()->GetStringWithFeatureName(
-                IDS_NEARBY_NOTIFICATION_CONNECTION_REQUEST_TITLE_PH)
-          : l10n_util::GetStringUTF16(
-                IDS_NEARBY_NOTIFICATION_CONNECTION_REQUEST_TITLE));
+  notification.set_title(l10n_util::GetStringUTF16(
+      IDS_NEARBY_NOTIFICATION_CONNECTION_REQUEST_TITLE));
   notification.set_message(
       GetConnectionRequestNotificationMessage(share_target, transfer_metadata));
   notification.set_icon(GetImageFromShareTarget(share_target));
@@ -1013,18 +1005,9 @@
 
   notification.set_title(
       l10n_util::GetStringUTF16(IDS_NEARBY_NOTIFICATION_ONBOARDING_TITLE));
-
-  const std::u16string onboarding_message =
-      features::IsNameEnabled()
-          ? NearbyShareResourceGetter::GetInstance()->GetStringWithFeatureName(
-                IDS_NEARBY_NOTIFICATION_ONBOARDING_MESSAGE_PH)
-          : l10n_util::GetStringUTF16(
-                IDS_NEARBY_NOTIFICATION_ONBOARDING_MESSAGE);
-
-  notification.set_message(is_onboarding_complete
-                               ? l10n_util::GetStringUTF16(
-                                     IDS_NEARBY_NOTIFICATION_GO_VISIBLE_MESSAGE)
-                               : onboarding_message);
+  notification.set_message(l10n_util::GetStringUTF16(
+      is_onboarding_complete ? IDS_NEARBY_NOTIFICATION_GO_VISIBLE_MESSAGE
+                             : IDS_NEARBY_NOTIFICATION_ONBOARDING_MESSAGE));
 
   std::vector<message_center::ButtonInfo> notification_actions;
   notification_actions.emplace_back(l10n_util::GetStringUTF16(
diff --git a/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc b/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc
index 54e72da..0dbacbd06 100644
--- a/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc
+++ b/chrome/browser/nearby_sharing/nearby_notification_manager_unittest.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/nearby_sharing/nearby_notification_manager.h"
 
 #include <memory>
-#include <string>
 #include <vector>
 
 #include "ash/public/cpp/holding_space/holding_space_controller.h"
@@ -32,7 +31,6 @@
 #include "chrome/browser/nearby_sharing/common/nearby_share_enums.h"
 #include "chrome/browser/nearby_sharing/common/nearby_share_features.h"
 #include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h"
-#include "chrome/browser/nearby_sharing/common/nearby_share_resource_getter.h"
 #include "chrome/browser/nearby_sharing/constants.h"
 #include "chrome/browser/nearby_sharing/mock_nearby_sharing_service.h"
 #include "chrome/browser/nearby_sharing/nearby_sharing_service_factory.h"
@@ -500,39 +498,7 @@
   EXPECT_EQ(&kNearbyShareIcon, &notification.vector_small_image());
   EXPECT_EQ(l10n_util::GetStringUTF16(IDS_NEARBY_NOTIFICATION_SOURCE),
             notification.display_source());
-  const std::vector<message_center::ButtonInfo>& buttons =
-      notification.buttons();
-  ASSERT_EQ(1u, buttons.size());
 
-  const message_center::ButtonInfo& cancel_button = buttons[0];
-  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_APP_CANCEL), cancel_button.title);
-}
-
-TEST_P(NearbyNotificationManagerTest,
-       ShowProgress_ShowsNotification_NameEnabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures({features::kIsNameEnabled}, {});
-  ShareTarget share_target;
-  TransferMetadata transfer_metadata = TransferMetadataBuilder().build();
-
-  manager()->ShowProgress(share_target, transfer_metadata);
-
-  std::vector<message_center::Notification> notifications =
-      GetDisplayedNotifications();
-  ASSERT_EQ(1u, notifications.size());
-
-  const message_center::Notification& notification = notifications[0];
-  EXPECT_EQ(message_center::NOTIFICATION_TYPE_PROGRESS, notification.type());
-  EXPECT_EQ(std::u16string(), notification.message());
-  EXPECT_TRUE(notification.icon().IsEmpty());
-  EXPECT_EQ(GURL(), notification.origin_url());
-  EXPECT_TRUE(notification.never_timeout());
-  EXPECT_TRUE(notification.pinned());
-  EXPECT_FALSE(notification.renotify());
-  EXPECT_EQ(&kNearbyShareIcon, &notification.vector_small_image());
-  EXPECT_EQ(NearbyShareResourceGetter::GetInstance()->GetStringWithFeatureName(
-                IDS_NEARBY_NOTIFICATION_SOURCE_PH),
-            notification.display_source());
   const std::vector<message_center::ButtonInfo>& buttons =
       notification.buttons();
   ASSERT_EQ(1u, buttons.size());
@@ -808,7 +774,7 @@
 
   const message_center::Notification& notification = notifications[0];
 
-  const std::u16string expected_title = l10n_util::GetStringUTF16(
+  std::u16string expected_title = l10n_util::GetStringUTF16(
       IDS_NEARBY_NOTIFICATION_CONNECTION_REQUEST_TITLE);
   std::u16string plural_message = l10n_util::GetPluralStringFUTF16(
       IDS_NEARBY_NOTIFICATION_CONNECTION_REQUEST_MESSAGE, 1);
@@ -848,84 +814,6 @@
       notification.buttons();
   ASSERT_EQ(expected_button_titles.size(), buttons.size());
 
-  for (size_t i = 0; i < expected_button_titles.size(); ++i) {
-    EXPECT_EQ(expected_button_titles[i], buttons[i].title);
-  }
-}
-
-TEST_P(NearbyNotificationManagerConnectionRequestTest,
-       ShowConnectionRequest_ShowsNotification_NameEnabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures({features::kIsNameEnabled}, {});
-  bool with_token = std::get<0>(GetParam());
-
-  std::string device_name = "device";
-  std::string token = "3141";
-
-  ShareTarget share_target;
-  share_target.device_name = device_name;
-  share_target.file_attachments.push_back(
-      CreateFileAttachment(FileAttachment::Type::kImage));
-
-  TransferMetadataBuilder transfer_metadata_builder;
-  transfer_metadata_builder.set_status(
-      TransferMetadata::Status::kAwaitingLocalConfirmation);
-  if (with_token) {
-    transfer_metadata_builder.set_token(token);
-  }
-  TransferMetadata transfer_metadata = transfer_metadata_builder.build();
-
-  manager()->ShowConnectionRequest(share_target, transfer_metadata);
-
-  std::vector<message_center::Notification> notifications =
-      GetDisplayedNotifications();
-  ASSERT_EQ(1u, notifications.size());
-
-  const message_center::Notification& notification = notifications[0];
-
-  const std::u16string expected_title =
-      NearbyShareResourceGetter::GetInstance()->GetStringWithFeatureName(
-          IDS_NEARBY_NOTIFICATION_CONNECTION_REQUEST_TITLE_PH);
-  std::u16string plural_message = l10n_util::GetPluralStringFUTF16(
-      IDS_NEARBY_NOTIFICATION_CONNECTION_REQUEST_MESSAGE, 1);
-
-  std::u16string expected_message = base::ReplaceStringPlaceholders(
-      plural_message,
-      {base::ASCIIToUTF16(device_name),
-       l10n_util::GetPluralStringFUTF16(
-           IDS_NEARBY_FILE_ATTACHMENTS_NOT_CAPITALIZED_IMAGES, 1)},
-      /*offsets=*/nullptr);
-
-  if (with_token) {
-    expected_message = base::StrCat(
-        {expected_message, u"\n",
-         l10n_util::GetStringFUTF16(IDS_NEARBY_SECURE_CONNECTION_ID,
-                                    base::UTF8ToUTF16(token))});
-  }
-
-  EXPECT_EQ(message_center::NOTIFICATION_TYPE_SIMPLE, notification.type());
-  EXPECT_EQ(expected_title, notification.title());
-  EXPECT_EQ(expected_message, notification.message());
-  // TODO(crbug.com/1102348): verify notification.icon()
-  EXPECT_EQ(GURL(), notification.origin_url());
-  EXPECT_TRUE(notification.never_timeout());
-  EXPECT_FALSE(notification.renotify());
-  // TODO(b/309841194): verify notification icon in when kNameEnabled is
-  // enabled.
-  EXPECT_EQ(NearbyShareResourceGetter::GetInstance()->GetStringWithFeatureName(
-                IDS_NEARBY_NOTIFICATION_SOURCE_PH),
-            notification.display_source());
-
-  std::vector<std::u16string> expected_button_titles;
-  expected_button_titles.push_back(
-      l10n_util::GetStringUTF16(IDS_NEARBY_NOTIFICATION_ACCEPT_ACTION));
-  expected_button_titles.push_back(
-      l10n_util::GetStringUTF16(IDS_NEARBY_NOTIFICATION_DECLINE_ACTION));
-
-  const std::vector<message_center::ButtonInfo>& buttons =
-      notification.buttons();
-  ASSERT_EQ(expected_button_titles.size(), buttons.size());
-
   for (size_t i = 0; i < expected_button_titles.size(); ++i)
     EXPECT_EQ(expected_button_titles[i], buttons[i].title);
 }
@@ -987,48 +875,6 @@
     EXPECT_EQ(expected_button_titles[i], buttons[i].title);
 }
 
-TEST_P(NearbyNotificationManagerTest,
-       ShowNearbyDeviceTryingToShare_ShowsNotification_NameEnabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures({features::kIsNameEnabled}, {});
-  manager()->ShowNearbyDeviceTryingToShare();
-
-  std::vector<message_center::Notification> notifications =
-      GetDisplayedNotifications();
-  ASSERT_EQ(1u, notifications.size());
-
-  const message_center::Notification& notification = notifications[0];
-  EXPECT_EQ(message_center::NOTIFICATION_TYPE_SIMPLE, notification.type());
-  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_NEARBY_NOTIFICATION_ONBOARDING_TITLE),
-            notification.title());
-  EXPECT_EQ(NearbyShareResourceGetter::GetInstance()->GetStringWithFeatureName(
-                IDS_NEARBY_NOTIFICATION_ONBOARDING_MESSAGE_PH),
-            notification.message());
-  EXPECT_TRUE(notification.icon().IsEmpty());
-  EXPECT_EQ(GURL(), notification.origin_url());
-  EXPECT_FALSE(notification.never_timeout());
-  EXPECT_FALSE(notification.renotify());
-  EXPECT_EQ(&kNearbyShareIcon, &notification.vector_small_image());
-  EXPECT_EQ(NearbyShareResourceGetter::GetInstance()->GetStringWithFeatureName(
-                IDS_NEARBY_NOTIFICATION_SOURCE_PH),
-            notification.display_source());
-  EXPECT_EQ(2u, notification.buttons().size());
-
-  std::vector<std::u16string> expected_button_titles;
-  expected_button_titles.push_back(
-      l10n_util::GetStringUTF16(IDS_NEARBY_NOTIFICATION_SET_UP_ACTION));
-  expected_button_titles.push_back(
-      l10n_util::GetStringUTF16(IDS_NEARBY_NOTIFICATION_DISMISS_ACTION));
-
-  const std::vector<message_center::ButtonInfo>& buttons =
-      notification.buttons();
-  ASSERT_EQ(expected_button_titles.size(), buttons.size());
-
-  for (size_t i = 0; i < expected_button_titles.size(); ++i) {
-    EXPECT_EQ(expected_button_titles[i], buttons[i].title);
-  }
-}
-
 TEST_P(
     NearbyNotificationManagerTest,
     ShowNearbyDeviceTryingToShare_AlreadyOnboarded_ShowsGoVisibleNotification) {
@@ -1055,50 +901,7 @@
   EXPECT_EQ(l10n_util::GetStringUTF16(IDS_NEARBY_NOTIFICATION_SOURCE),
             notification.display_source());
   EXPECT_EQ(2u, notification.buttons().size());
-  std::vector<std::u16string> expected_button_titles;
-  expected_button_titles.push_back(
-      l10n_util::GetStringUTF16(IDS_NEARBY_NOTIFICATION_GO_VISIBLE_ACTION));
-  expected_button_titles.push_back(
-      l10n_util::GetStringUTF16(IDS_NEARBY_NOTIFICATION_DISMISS_ACTION));
 
-  const std::vector<message_center::ButtonInfo>& buttons =
-      notification.buttons();
-  ASSERT_EQ(expected_button_titles.size(), buttons.size());
-
-  for (size_t i = 0; i < expected_button_titles.size(); ++i) {
-    EXPECT_EQ(expected_button_titles[i], buttons[i].title);
-  }
-}
-
-TEST_P(
-    NearbyNotificationManagerTest,
-    ShowNearbyDeviceTryingToShare_AlreadyOnboarded_ShowsGoVisibleNotification_NameEnabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures({features::kIsNameEnabled}, {});
-  pref_service_.SetBoolean(prefs::kNearbySharingOnboardingCompletePrefName,
-                           true);
-  manager()->ShowNearbyDeviceTryingToShare();
-
-  std::vector<message_center::Notification> notifications =
-      GetDisplayedNotifications();
-  ASSERT_EQ(1u, notifications.size());
-
-  const message_center::Notification& notification = notifications[0];
-  EXPECT_EQ(message_center::NOTIFICATION_TYPE_SIMPLE, notification.type());
-  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_NEARBY_NOTIFICATION_ONBOARDING_TITLE),
-            notification.title());
-  EXPECT_EQ(
-      l10n_util::GetStringUTF16(IDS_NEARBY_NOTIFICATION_GO_VISIBLE_MESSAGE),
-      notification.message());
-  EXPECT_TRUE(notification.icon().IsEmpty());
-  EXPECT_EQ(GURL(), notification.origin_url());
-  EXPECT_FALSE(notification.never_timeout());
-  EXPECT_FALSE(notification.renotify());
-  EXPECT_EQ(&kNearbyShareIcon, &notification.vector_small_image());
-  EXPECT_EQ(NearbyShareResourceGetter::GetInstance()->GetStringWithFeatureName(
-                IDS_NEARBY_NOTIFICATION_SOURCE_PH),
-            notification.display_source());
-  EXPECT_EQ(2u, notification.buttons().size());
   std::vector<std::u16string> expected_button_titles;
   expected_button_titles.push_back(
       l10n_util::GetStringUTF16(IDS_NEARBY_NOTIFICATION_GO_VISIBLE_ACTION));
@@ -1132,26 +935,6 @@
 }
 
 TEST_P(NearbyNotificationManagerTest,
-       FastInitiationDeviceFound_ShowsNearbyDeviceTryingToShare_NameEnabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures({features::kIsNameEnabled}, {});
-  manager()->OnFastInitiationDevicesDetected();
-
-  std::vector<message_center::Notification> notifications =
-      GetDisplayedNotifications();
-  ASSERT_EQ(1u, notifications.size());
-
-  // Minimum to confirm it's actually the onboarding notification.
-  const message_center::Notification& notification = notifications[0];
-  EXPECT_EQ(message_center::NOTIFICATION_TYPE_SIMPLE, notification.type());
-  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_NEARBY_NOTIFICATION_ONBOARDING_TITLE),
-            notification.title());
-  EXPECT_EQ(NearbyShareResourceGetter::GetInstance()->GetStringWithFeatureName(
-                IDS_NEARBY_NOTIFICATION_ONBOARDING_MESSAGE_PH),
-            notification.message());
-}
-
-TEST_P(NearbyNotificationManagerTest,
        FastInitiationDeviceLost_ClosesNearbyDeviceTryingToShare) {
   manager()->OnFastInitiationDevicesDetected();
   EXPECT_EQ(1u, GetDisplayedNotifications().size());
@@ -1190,31 +973,6 @@
   EXPECT_EQ(0u, notification.buttons().size());
 }
 
-TEST_P(NearbyNotificationManagerTest,
-       ShowSuccess_ShowsNotification_NameEnabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures({features::kIsNameEnabled}, {});
-  manager()->ShowSuccess(ShareTarget());
-
-  std::vector<message_center::Notification> notifications =
-      GetDisplayedNotifications();
-  ASSERT_EQ(1u, notifications.size());
-
-  const message_center::Notification& notification = notifications[0];
-  EXPECT_EQ(message_center::NOTIFICATION_TYPE_SIMPLE, notification.type());
-
-  EXPECT_EQ(std::u16string(), notification.message());
-  EXPECT_TRUE(notification.icon().IsEmpty());
-  EXPECT_EQ(GURL(), notification.origin_url());
-  EXPECT_FALSE(notification.never_timeout());
-  EXPECT_FALSE(notification.renotify());
-  EXPECT_EQ(&kNearbyShareIcon, &notification.vector_small_image());
-  EXPECT_EQ(NearbyShareResourceGetter::GetInstance()->GetStringWithFeatureName(
-                IDS_NEARBY_NOTIFICATION_SOURCE_PH),
-            notification.display_source());
-  EXPECT_EQ(0u, notification.buttons().size());
-}
-
 TEST_P(NearbyNotificationManagerTest, ShowSuccess_DeviceNameEncoding) {
   ShareTarget share_target;
   share_target.device_name = "🌵";
@@ -1267,31 +1025,6 @@
   EXPECT_EQ(0u, notification.buttons().size());
 }
 
-TEST_P(NearbyNotificationManagerTest,
-       ShowFailure_ShowsNotification_NameEnabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures({features::kIsNameEnabled}, {});
-  manager()->ShowFailure(ShareTarget(), TransferMetadataBuilder().build());
-
-  std::vector<message_center::Notification> notifications =
-      GetDisplayedNotifications();
-  ASSERT_EQ(1u, notifications.size());
-
-  const message_center::Notification& notification = notifications[0];
-  EXPECT_EQ(message_center::NOTIFICATION_TYPE_SIMPLE, notification.type());
-
-  EXPECT_EQ(std::u16string(), notification.message());
-  EXPECT_TRUE(notification.icon().IsEmpty());
-  EXPECT_EQ(GURL(), notification.origin_url());
-  EXPECT_FALSE(notification.never_timeout());
-  EXPECT_FALSE(notification.renotify());
-  EXPECT_EQ(&kNearbyShareIcon, &notification.vector_small_image());
-  EXPECT_EQ(NearbyShareResourceGetter::GetInstance()->GetStringWithFeatureName(
-                IDS_NEARBY_NOTIFICATION_SOURCE_PH),
-            notification.display_source());
-  EXPECT_EQ(0u, notification.buttons().size());
-}
-
 TEST_P(NearbyNotificationManagerTest, ShowFailure_DeviceNameEncoding) {
   ShareTarget share_target;
   share_target.device_name = "🌵";
@@ -2089,53 +1822,8 @@
         notification.buttons();
     ASSERT_EQ(expected_button_titles.size(), buttons.size());
 
-    for (size_t i = 0; i < expected_button_titles.size(); ++i) {
+    for (size_t i = 0; i < expected_button_titles.size(); ++i)
       EXPECT_EQ(expected_button_titles[i], buttons[i].title);
-    }
-}
-
-TEST_P(NearbyNotificationManagerTest,
-       ShowVisibilityReminder_Contacts_Mode_NameEnabled) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitWithFeatures({features::kIsNameEnabled}, {});
-  pref_service_.SetInteger(prefs::kNearbySharingBackgroundVisibilityName,
-                           static_cast<int>(Visibility::kAllContacts));
-
-  manager()->ShowVisibilityReminder();
-  std::vector<message_center::Notification> notifications =
-      GetDisplayedNotifications();
-  ASSERT_EQ(1u, notifications.size());
-  const message_center::Notification& notification = notifications[0];
-  EXPECT_EQ(message_center::NOTIFICATION_TYPE_SIMPLE, notification.type());
-  EXPECT_EQ(l10n_util::GetStringUTF16(
-                IDS_NEARBY_NOTIFICATION_VISIBILITY_REMINDER_TITLE),
-            notification.title());
-  EXPECT_EQ(l10n_util::GetStringUTF16(
-                IDS_NEARBY_NOTIFICATION_VISIBILITY_REMINDER_MESSAGE),
-            notification.message());
-  EXPECT_TRUE(notification.icon().IsEmpty());
-  EXPECT_EQ(GURL(), notification.origin_url());
-  EXPECT_FALSE(notification.never_timeout());
-  EXPECT_FALSE(notification.renotify());
-  EXPECT_EQ(&kNearbyShareIcon, &notification.vector_small_image());
-  EXPECT_EQ(NearbyShareResourceGetter::GetInstance()->GetStringWithFeatureName(
-                IDS_NEARBY_NOTIFICATION_SOURCE_PH),
-            notification.display_source());
-  EXPECT_EQ(2u, notification.buttons().size());
-
-  std::vector<std::u16string> expected_button_titles;
-  expected_button_titles.push_back(
-      l10n_util::GetStringUTF16(IDS_NEARBY_NOTIFICATION_GO_TO_SETTINGS_ACTION));
-  expected_button_titles.push_back(
-      l10n_util::GetStringUTF16(IDS_NEARBY_NOTIFICATION_DISMISS_ACTION));
-
-  const std::vector<message_center::ButtonInfo>& buttons =
-      notification.buttons();
-  ASSERT_EQ(expected_button_titles.size(), buttons.size());
-
-  for (size_t i = 0; i < expected_button_titles.size(); ++i) {
-    EXPECT_EQ(expected_button_titles[i], buttons[i].title);
-  }
 }
 
 TEST_P(NearbyNotificationManagerTest, ShowVisibilityReminder_Hidden_Mode) {
diff --git a/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.cc
index 1719680..9ec07894 100644
--- a/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.cc
@@ -178,15 +178,12 @@
 
 void LcpCriticalPathPredictorPageLoadMetricsObserver::SetLcpElementLocator(
     const std::string& lcp_element_locator,
-    bool lcp_timing_was_predicted) {
+    absl::optional<uint32_t> predicted_lcp_index) {
   if (!lcpp_data_inputs_) {
     lcpp_data_inputs_.emplace();
   }
   lcpp_data_inputs_->lcp_element_locator = lcp_element_locator;
-  // At most one element can be predicted.
-  // TODO(crbug.com/1493255): Check below condition.
-  // CHECK(!lcp_timing_was_predicted_ || !lcp_timing_was_predicted);
-  lcp_timing_was_predicted_ |= lcp_timing_was_predicted;
+  predicted_lcp_indexes_.push_back(predicted_lcp_index);
 }
 
 void LcpCriticalPathPredictorPageLoadMetricsObserver::AppendFetchedFontUrl(
@@ -225,6 +222,26 @@
     return;
   }
 
+  if (predicted_lcp_indexes_.empty()) {
+    return;
+  }
+  // Then, We have a prelearn data and at least one LCP locator in current
+  // load. Let's stat it.
+
+  std::set<uint32_t> valid_indexes;
+  bool false_positive = false;
+  // TODO(crbug.com/1493255): Introduce more UMA using these flags.
+  [[maybe_unused]] bool dup_index = false;
+  for (const absl::optional<uint32_t>& maybe_index : predicted_lcp_indexes_) {
+    // There is an yet another LCP after valid index LCP.
+    false_positive |= !valid_indexes.empty();
+
+    if (!maybe_index.has_value()) {
+      continue;
+    }
+    dup_index |= !valid_indexes.insert(*maybe_index).second;
+  }
+
   base::UmaHistogramBoolean(internal::kHistogramLCPPPredictSuccess,
-                            lcp_timing_was_predicted_);
+                            valid_indexes.size() == 1u && !false_positive);
 }
diff --git a/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.h
index 2572b42..7b6c69c 100644
--- a/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_LCP_CRITICAL_PATH_PREDICTOR_PAGE_LOAD_METRICS_OBSERVER_H_
 #define CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_LCP_CRITICAL_PATH_PREDICTOR_PAGE_LOAD_METRICS_OBSERVER_H_
 
+#include <vector>
+
 #include "chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_util.h"
 #include "components/page_load_metrics/browser/page_load_metrics_observer.h"
 #include "content/public/browser/page_user_data.h"
@@ -56,7 +58,7 @@
   ~LcpCriticalPathPredictorPageLoadMetricsObserver() override;
 
   void SetLcpElementLocator(const std::string& lcp_element_locator,
-                            bool is_predicted);
+                            absl::optional<uint32_t> predicted_lcp_index);
   void SetLcpInfluencerScriptUrls(
       const std::vector<GURL>& lcp_influencer_scripts);
   // Append fetched font URLs to the list to be passed to LCPP.
@@ -95,9 +97,11 @@
 
   absl::optional<predictors::LcppDataInputs> lcpp_data_inputs_;
 
-  // True iff one of `lcp_element_locator` via SetLcpElementLocator was
-  // predicted as true LCP.
-  bool lcp_timing_was_predicted_ = false;
+  // Prediction result. This keeps SetLcpElementLocator's second argument.
+  // `predicted_lcp_index` is predicted index of `lcp_element_locators` in
+  // LCPCriticalPathPredictorNavigationTimeHint.
+  // absl::nullopt value means the LCP didn't hit any of `lcp_element_locators`.
+  std::vector<absl::optional<uint32_t>> predicted_lcp_indexes_;
 
   base::WeakPtrFactory<LcpCriticalPathPredictorPageLoadMetricsObserver>
       weak_factory_{this};
diff --git a/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer_unittest.cc
index 15cd298a9..6d7b02f 100644
--- a/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/lcp_critical_path_predictor_page_load_metrics_observer_unittest.cc
@@ -95,11 +95,12 @@
     navigation->GetNavigationHandle()->SetLCPPNavigationHint(hint);
   }
 
-  void SetMockLcpElementLocator(GURL url,
-                                const std::string& mock_element_locator = "foo",
-                                bool is_predicted = false) {
+  void SetMockLcpElementLocator(
+      GURL url,
+      const std::string& mock_element_locator = "foo",
+      absl::optional<uint32_t> mock_predicted_index = absl::nullopt) {
     lcpp_observers_[url]->SetLcpElementLocator(mock_element_locator,
-                                               is_predicted);
+                                               mock_predicted_index);
   }
 
   void ConfirmResult(GURL url,
@@ -177,7 +178,10 @@
                   /*learn_lcpp=*/false, /*record_uma=*/activate);
   }
 
-  void TestLCPPrediction(bool is_predicted) {
+  static const uint32_t kNotFound = static_cast<uint32_t>(-1);
+
+  void TestLCPPrediction(std::vector<uint32_t> predicted_lcp_indexes,
+                         bool expect_predicted) {
     const GURL main_frame_url("https://test.example");
     // Let predictor learn pseudo("lcp_previous") LCP locator
     predictors::ResourcePrefetchPredictor* predictor =
@@ -191,14 +195,18 @@
 
     // Predict LCP with the learned result.
     NavigationWithLCPPHint(main_frame_url, /*provide_lcpp_hint=*/true);
-    SetMockLcpElementLocator(main_frame_url, "lcp_actual", is_predicted);
+    for (auto index : predicted_lcp_indexes) {
+      SetMockLcpElementLocator(
+          main_frame_url, "lcp_actual",
+          index == kNotFound ? absl::nullopt : absl::optional<uint32_t>(index));
+    }
     tester()->NavigateToUntrackedUrl();
-    // Result only depends `is_predicted` parameter.
     EXPECT_THAT(tester()->histogram_tester().GetAllSamples(
                     internal::kHistogramLCPPPredictSuccess),
-                base::BucketsAre(base::Bucket(is_predicted, 1)));
+                base::BucketsAre(base::Bucket(expect_predicted, 1)));
   }
 
+ private:
   page_load_metrics::mojom::PageLoadTiming timing_;
   std::map<GURL, LcpCriticalPathPredictorPageLoadMetricsObserver*>
       lcpp_observers_;
@@ -225,9 +233,26 @@
 }
 
 TEST_F(LcpCriticalPathPredictorPageLoadMetricsObserverTest, PredictLCPSuccess) {
-  TestLCPPrediction(/*is_predicted=*/true);
+  TestLCPPrediction({0u}, /*expect_predicted=*/true);
+}
+
+TEST_F(LcpCriticalPathPredictorPageLoadMetricsObserverTest,
+       PredictLCPSuccess2) {
+  TestLCPPrediction({kNotFound, 0u}, /*expect_predicted=*/true);
 }
 
 TEST_F(LcpCriticalPathPredictorPageLoadMetricsObserverTest, PredictLCPFailed) {
-  TestLCPPrediction(/*is_predicted=*/false);
+  TestLCPPrediction({kNotFound}, /*expect_predicted=*/false);
+}
+
+TEST_F(LcpCriticalPathPredictorPageLoadMetricsObserverTest, PredictLCPFailed2) {
+  TestLCPPrediction({0u, kNotFound}, /*expect_predicted=*/false);
+}
+
+TEST_F(LcpCriticalPathPredictorPageLoadMetricsObserverTest, PredictLCPFailed3) {
+  TestLCPPrediction({0u, 0u}, /*expect_predicted=*/false);
+}
+
+TEST_F(LcpCriticalPathPredictorPageLoadMetricsObserverTest, PredictLCPFailed4) {
+  TestLCPPrediction({0u, 1u}, /*expect_predicted=*/false);
 }
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index 511f1a2..789c125 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -1553,11 +1553,6 @@
       base::BindRepeating(&HandleTestAuthRequest));
   ASSERT_TRUE(http_test_server.Start());
 
-  LoginPromptBrowserTestObserver login_observer;
-  // We need to register to all sources, because the navigation observer we are
-  // interested in is for a new tab to be opened, and thus does not exist yet.
-  login_observer.Register(content::NotificationService::AllSources());
-
   password_manager::TestPasswordStore* password_store =
       static_cast<password_manager::TestPasswordStore*>(
           ProfilePasswordStoreFactory::GetForProfile(
@@ -1576,8 +1571,8 @@
 
   WindowedAuthSuppliedObserver auth_supplied_observer(nav_controller);
   // Offer valid credentials on the auth challenge.
-  ASSERT_EQ(1u, login_observer.handlers().size());
-  LoginHandler* handler = *login_observer.handlers().begin();
+  ASSERT_EQ(1u, LoginHandler::GetAllLoginHandlersForTest().size());
+  LoginHandler* handler = LoginHandler::GetAllLoginHandlersForTest().front();
   ASSERT_TRUE(handler);
   PasswordsNavigationObserver nav_observer(WebContents());
   // Any username/password will work.
diff --git a/chrome/browser/pdf/pdf_extension_accessibility_test.cc b/chrome/browser/pdf/pdf_extension_accessibility_test.cc
index be45ad9..644df08 100644
--- a/chrome/browser/pdf/pdf_extension_accessibility_test.cc
+++ b/chrome/browser/pdf/pdf_extension_accessibility_test.cc
@@ -1013,8 +1013,14 @@
 // This test suite validates the navigation done using the accessibility client.
 using PDFExtensionAccessibilityNavigationTest = PDFExtensionAccessibilityTest;
 
+// TODO(crbug.com/1487426): Fix the flakiness on ChromeOS.
+#if BUILDFLAG(IS_CHROMEOS)
+#define MAYBE_LinkNavigation DISABLED_LinkNavigation
+#else
+#define MAYBE_LinkNavigation LinkNavigation
+#endif  // BUILDFLAG(IS_CHROMEOS)
 IN_PROC_BROWSER_TEST_F(PDFExtensionAccessibilityNavigationTest,
-                       LinkNavigation) {
+                       MAYBE_LinkNavigation) {
   // Enable accessibility and load the test file.
   content::BrowserAccessibilityState::GetInstance()->EnableAccessibility();
   MimeHandlerViewGuest* guest = LoadPdfGetMimeHandlerView(
diff --git a/chrome/browser/portal/portal_browsertest.cc b/chrome/browser/portal/portal_browsertest.cc
index 9161df4..028dcb1 100644
--- a/chrome/browser/portal/portal_browsertest.cc
+++ b/chrome/browser/portal/portal_browsertest.cc
@@ -170,16 +170,14 @@
   content::NavigationController& portal_controller =
       portal_contents->GetController();
 
-  LoginPromptBrowserTestObserver login_observer;
-  login_observer.Register(
-      content::Source<content::NavigationController>(&portal_controller));
   WindowedAuthNeededObserver auth_needed(&portal_controller);
   ASSERT_TRUE(content::ExecJs(portal_contents,
                               "location.href = '/auth-basic?realm=Aperture'"));
   auth_needed.Wait();
 
   WindowedAuthSuppliedObserver auth_supplied(&portal_controller);
-  LoginHandler* login_handler = login_observer.handlers().front();
+  LoginHandler* login_handler =
+      LoginHandler::GetAllLoginHandlersForTest().front();
   EXPECT_EQ(login_handler->auth_info().realm, "Aperture");
   login_handler->SetAuth(u"basicuser", u"secret");
   auth_supplied.Wait();
diff --git a/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_host.cc b/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_host.cc
index 3bb290d..74b1905f 100644
--- a/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_host.cc
+++ b/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_host.cc
@@ -40,7 +40,7 @@
 
 void LCPCriticalPathPredictorHost::SetLcpElementLocator(
     const std::string& lcp_element_locator,
-    bool lcp_timing_was_predicted) {
+    absl::optional<uint32_t> predicted_lcp_index) {
   // `LcpCriticalPathPredictorPageLoadMetricsObserver::OnCommit()` stores
   // `LcpCriticalPathPredictorPageLoadMetricsObserver` in `PageData` as a weak
   // pointer. This weak pointer can be deleted at any time.
@@ -49,7 +49,7 @@
               render_frame_host().GetPage())) {
     if (auto* plmo =
             page_data->GetLcpCriticalPathPredictorPageLoadMetricsObserver()) {
-      plmo->SetLcpElementLocator(lcp_element_locator, lcp_timing_was_predicted);
+      plmo->SetLcpElementLocator(lcp_element_locator, predicted_lcp_index);
     }
   }
 }
diff --git a/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_host.h b/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_host.h
index 52afacc..486e548 100644
--- a/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_host.h
+++ b/chrome/browser/predictors/lcp_critical_path_predictor/lcp_critical_path_predictor_host.h
@@ -39,8 +39,9 @@
   ~LCPCriticalPathPredictorHost() override;
 
   // Implements blink::mojom::LCPCriticalPathPredictorHost.
-  void SetLcpElementLocator(const std::string& lcp_element_locator,
-                            bool lcp_timing_was_predicted) override;
+  void SetLcpElementLocator(
+      const std::string& lcp_element_locator,
+      absl::optional<uint32_t> predicted_lcp_index) override;
   void SetLcpInfluencerScriptUrls(
       const std::vector<GURL>& lcp_influencer_scripts) override;
   void NotifyFetchedFont(const GURL& font_url) override;
diff --git a/chrome/browser/preloading/prerender/prerender_browsertest.cc b/chrome/browser/preloading/prerender/prerender_browsertest.cc
index 116b12a1..69babbf 100644
--- a/chrome/browser/preloading/prerender/prerender_browsertest.cc
+++ b/chrome/browser/preloading/prerender/prerender_browsertest.cc
@@ -624,14 +624,8 @@
 
   // Start a prerender.
   GURL prerender_url = embedded_test_server()->GetURL("/prerender/empty.html");
-  content::TestNavigationObserver nav_observer(prerender_url);
-  nav_observer.StartWatchingNewWebContents();
-  prerender_helper().AddPrerendersAsync({prerender_url},
-                                        /*eagerness=*/absl::nullopt, "_blank");
-  nav_observer.WaitForNavigationFinished();
-  EXPECT_EQ(nav_observer.last_navigation_url(), prerender_url);
-  int host_id = prerender_helper().GetHostForUrl(prerender_url);
-  EXPECT_NE(host_id, content::RenderFrameHost::kNoFrameTreeNodeId);
+  int host_id = prerender_helper().AddPrerender(
+      prerender_url, /*eagerness=*/absl::nullopt, "_blank");
 
   // Navigate a prerendered page to another page.
   GURL navigation_url =
@@ -644,7 +638,8 @@
       content::WebContents::FromFrameTreeNodeId(host_id);
   ASSERT_TRUE(prerender_web_contents);
   prerender_web_contents->Close();
-  EXPECT_EQ(prerender_helper().GetHostForUrl(prerender_url),
+  EXPECT_EQ(content::test::PrerenderTestHelper::GetHostForUrl(
+                *prerender_web_contents, prerender_url),
             content::RenderFrameHost::kNoFrameTreeNodeId);
 
   histogram_tester.ExpectUniqueSample(
diff --git a/chrome/browser/resources/chromeos/quickoffice b/chrome/browser/resources/chromeos/quickoffice
new file mode 160000
index 0000000..23bde34
--- /dev/null
+++ b/chrome/browser/resources/chromeos/quickoffice
@@ -0,0 +1 @@
+Subproject commit 23bde3495989fbc0112213613d2498030be51417
diff --git a/chrome/browser/resources/feedback/BUILD.gn b/chrome/browser/resources/feedback/BUILD.gn
index 680a63c..bfeccab1 100644
--- a/chrome/browser/resources/feedback/BUILD.gn
+++ b/chrome/browser/resources/feedback/BUILD.gn
@@ -39,6 +39,7 @@
 
   non_web_component_files = [
     "js/autofill_metadata.ts",
+    "js/feedback_browser_proxy.ts",
     "js/feedback.ts",
     "js/feedback_util.ts",
     "js/logs_map_page.ts",
diff --git a/chrome/browser/resources/feedback/js/feedback.ts b/chrome/browser/resources/feedback/js/feedback.ts
index 9d2caee..13c0b02f 100644
--- a/chrome/browser/resources/feedback/js/feedback.ts
+++ b/chrome/browser/resources/feedback/js/feedback.ts
@@ -10,6 +10,7 @@
 import {assert} from 'chrome://resources/js/assert.js';
 import {$, getRequiredElement} from 'chrome://resources/js/util.js';
 
+import {FeedbackBrowserProxy, FeedbackBrowserProxyImpl} from './feedback_browser_proxy.js';
 import {FEEDBACK_LANDING_PAGE, FEEDBACK_LANDING_PAGE_TECHSTOP, FEEDBACK_LEGAL_HELP_URL, FEEDBACK_PRIVACY_POLICY_URL, FEEDBACK_TERM_OF_SERVICE_URL, openUrlInAppWindow} from './feedback_util.js';
 import {domainQuestions, questionnaireBegin, questionnaireNotification} from './questionnaire.js';
 import {takeScreenshot} from './take_screenshot.js';
@@ -19,7 +20,7 @@
 const dialogArgs: string = chrome.getVariableValue('dialogArguments');
 
 /**
- * The object will be manipulated by feedbackHelper
+ * The object will be manipulated by sendReport().
  */
 let feedbackInfo: chrome.feedbackPrivate.FeedbackInfo = {
   assistantDebugInfoAllowed: false,
@@ -41,76 +42,32 @@
 };
 
 
-class FeedbackHelper {
-  getSystemInformation(): Promise<chrome.feedbackPrivate.LogsMapEntry[]> {
-    return new Promise(
-        resolve => chrome.feedbackPrivate.getSystemInformation(resolve));
-  }
+async function sendFeedbackReport(useSystemInfo: boolean) {
+  const ID = Math.round(Date.now() / 1000);
+  const FLOW = feedbackInfo.flow;
 
-  getUserEmail(): Promise<string> {
-    return new Promise(resolve => chrome.feedbackPrivate.getUserEmail(resolve));
-  }
+  const result = await FeedbackBrowserProxyImpl.getInstance().sendFeedback(
+      feedbackInfo, useSystemInfo, formOpenTime);
 
-  sendFeedbackReport(useSystemInfo: boolean) {
-    const ID = Math.round(Date.now() / 1000);
-    const FLOW = feedbackInfo.flow;
-
-    chrome.feedbackPrivate
-        .sendFeedback(feedbackInfo, useSystemInfo, formOpenTime)
-        .then(result => {
-          if (result.status === chrome.feedbackPrivate.Status.SUCCESS) {
-            if (FLOW !== chrome.feedbackPrivate.FeedbackFlow.LOGIN &&
-                result.landingPageType !==
-                    chrome.feedbackPrivate.LandingPageType.NO_LANDING_PAGE) {
-              const landingPage = result.landingPageType ===
-                      chrome.feedbackPrivate.LandingPageType.NORMAL ?
-                  FEEDBACK_LANDING_PAGE :
-                  FEEDBACK_LANDING_PAGE_TECHSTOP;
-              window.open(landingPage, '_blank');
-            }
-          } else {
-            console.warn(
-                'Feedback: Report for request with ID ' + ID +
-                ' will be sent later.');
-          }
-          scheduleWindowClose();
-        });
+  if (result.status === chrome.feedbackPrivate.Status.SUCCESS) {
+    if (FLOW !== chrome.feedbackPrivate.FeedbackFlow.LOGIN &&
+        result.landingPageType !==
+            chrome.feedbackPrivate.LandingPageType.NO_LANDING_PAGE) {
+      const landingPage = result.landingPageType ===
+              chrome.feedbackPrivate.LandingPageType.NORMAL ?
+          FEEDBACK_LANDING_PAGE :
+          FEEDBACK_LANDING_PAGE_TECHSTOP;
+      window.open(landingPage, '_blank');
+    }
+  } else {
+    console.warn(
+        'Feedback: Report for request with ID ' + ID + ' will be sent later.');
   }
-
-  // Send a message to show the WebDialog
-  showDialog() {
-    chrome.send('showDialog');
-  }
-
-  // Send a message to close the WebDialog
-  closeDialog() {
-    chrome.send('dialogClose');
-  }
-
-  // <if expr="chromeos_ash">
-  showAssistantLogsInfo() {
-    chrome.send('showAssistantLogsInfo');
-  }
-
-  showBluetoothLogsInfo() {
-    chrome.send('showBluetoothLogsInfo');
-  }
-  // </if>
-
-  showSystemInfo() {
-    chrome.send('showSystemInfo');
-  }
-
-  showMetrics() {
-    chrome.send('showMetrics');
-  }
-
-  showAutofillMetadataInfo() {
-    chrome.send('showAutofillMetadataInfo', [feedbackInfo.autofillMetadata]);
-  }
+  scheduleWindowClose();
 }
 
-const feedbackHelper: FeedbackHelper = new FeedbackHelper();
+const browserProxy: FeedbackBrowserProxy =
+    FeedbackBrowserProxyImpl.getInstance();
 
 const MAX_ATTACH_FILE_SIZE: number = 3 * 1024 * 1024;
 
@@ -271,7 +228,7 @@
   // <if expr="chromeos_ash">
   // This is needed on CrOS. Otherwise, the feedback window will stay behind
   // the Chrome window.
-  feedbackHelper.showDialog();
+  browserProxy.showDialog();
   // </if>
 
   const file = (fileSelectedEvent.target as HTMLInputElement).files![0];
@@ -556,7 +513,7 @@
   feedbackInfo.productId = productId;
 
   // Request sending the report, show the landing page (if allowed)
-  feedbackHelper.sendFeedbackReport(useSystemInfo);
+  sendFeedbackReport(useSystemInfo);
 
   return true;
 }
@@ -603,7 +560,7 @@
  */
 function scheduleWindowClose() {
   setTimeout(function() {
-    feedbackHelper.closeDialog();
+    browserProxy.closeDialog();
   }, 100);
 }
 
@@ -669,7 +626,7 @@
         resizeAppWindow();
       });
 
-      feedbackHelper.showDialog();
+      browserProxy.showDialog();
 
       // Allow feedback to be sent even if the screenshot failed.
       if (!screenshotCanvas) {
@@ -692,7 +649,7 @@
       });
     });
 
-    feedbackHelper.getUserEmail().then(function(email) {
+    browserProxy.getUserEmail().then(function(email) {
       // Never add an empty option.
       if (!email) {
         return;
@@ -745,7 +702,7 @@
       autofillMetadataUrlElement.onclick = function(e) {
         e.preventDefault();
 
-        feedbackHelper.showAutofillMetadataInfo();
+        browserProxy.showAutofillMetadataInfo(feedbackInfo.autofillMetadata!);
       };
 
       autofillMetadataUrlElement.onauxclick = function(e) {
@@ -760,7 +717,7 @@
       sysInfoUrlElement.onclick = function(e) {
         e.preventDefault();
 
-        feedbackHelper.showSystemInfo();
+        browserProxy.showSystemInfo();
       };
 
       sysInfoUrlElement.onauxclick = function(e) {
@@ -773,7 +730,7 @@
       histogramUrlElement.onclick = function(e) {
         e.preventDefault();
 
-        feedbackHelper.showMetrics();
+        browserProxy.showMetrics();
       };
 
       histogramUrlElement.onauxclick = function(e) {
@@ -813,7 +770,7 @@
         bluetoothLogsInfoLinkElement.onclick = function(e) {
           e.preventDefault();
 
-          feedbackHelper.showBluetoothLogsInfo();
+          browserProxy.showBluetoothLogsInfo();
 
           bluetoothLogsInfoLinkElement.onauxclick = function(e) {
             e.preventDefault();
@@ -826,7 +783,7 @@
         assistantLogsInfoLinkElement.onclick = function(e) {
           e.preventDefault();
 
-          feedbackHelper.showAssistantLogsInfo();
+          browserProxy.showAssistantLogsInfo();
 
           assistantLogsInfoLinkElement.onauxclick = function(e) {
             e.preventDefault();
@@ -846,8 +803,6 @@
     }
     applyData(feedbackInfo);
 
-    Object.assign(window, {feedbackInfo, feedbackHelper});
-
     // Setup our event handlers.
     getRequiredElement('attach-file').addEventListener(
         'change', onFileSelected);
diff --git a/chrome/browser/resources/feedback/js/feedback_browser_proxy.ts b/chrome/browser/resources/feedback/js/feedback_browser_proxy.ts
new file mode 100644
index 0000000..7626578
--- /dev/null
+++ b/chrome/browser/resources/feedback/js/feedback_browser_proxy.ts
@@ -0,0 +1,86 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+export interface FeedbackBrowserProxy {
+  getSystemInformation(): Promise<chrome.feedbackPrivate.LogsMapEntry[]>;
+  getUserEmail(): Promise<string>;
+
+  sendFeedback(
+      feedback: chrome.feedbackPrivate.FeedbackInfo, loadSystemInfo?: boolean,
+      formOpenTime?: number):
+      Promise<chrome.feedbackPrivate.SendFeedbackResult>;
+
+  // Send a message to show the WebDialog
+  showDialog(): void;
+
+  // Send a message to close the WebDialog
+  closeDialog(): void;
+
+  // <if expr="chromeos_ash">
+  showAssistantLogsInfo(): void;
+  showBluetoothLogsInfo(): void;
+  // </if>
+
+  showSystemInfo(): void;
+  showMetrics(): void;
+  showAutofillMetadataInfo(autofillMetadata: string): void;
+}
+
+export class FeedbackBrowserProxyImpl implements FeedbackBrowserProxy {
+  getSystemInformation(): Promise<chrome.feedbackPrivate.LogsMapEntry[]> {
+    return new Promise(
+        resolve => chrome.feedbackPrivate.getSystemInformation(resolve));
+  }
+
+  getUserEmail(): Promise<string> {
+    return new Promise(resolve => chrome.feedbackPrivate.getUserEmail(resolve));
+  }
+
+  sendFeedback(
+      feedback: chrome.feedbackPrivate.FeedbackInfo, loadSystemInfo?: boolean,
+      formOpenTime?: number) {
+    return chrome.feedbackPrivate.sendFeedback(
+        feedback, loadSystemInfo, formOpenTime);
+  }
+
+  showDialog() {
+    chrome.send('showDialog');
+  }
+
+  closeDialog() {
+    chrome.send('dialogClose');
+  }
+
+  // <if expr="chromeos_ash">
+  showAssistantLogsInfo() {
+    chrome.send('showAssistantLogsInfo');
+  }
+
+  showBluetoothLogsInfo() {
+    chrome.send('showBluetoothLogsInfo');
+  }
+  // </if>
+
+  showSystemInfo() {
+    chrome.send('showSystemInfo');
+  }
+
+  showMetrics() {
+    chrome.send('showMetrics');
+  }
+
+  showAutofillMetadataInfo(autofillMetadata: string) {
+    chrome.send('showAutofillMetadataInfo', [autofillMetadata]);
+  }
+
+  static getInstance(): FeedbackBrowserProxy {
+    return instance || (instance = new FeedbackBrowserProxyImpl());
+  }
+
+  static setInstance(obj: FeedbackBrowserProxy) {
+    instance = obj;
+  }
+}
+
+let instance: FeedbackBrowserProxy|null = null;
diff --git a/chrome/browser/resources/password_manager/checkup_section.ts b/chrome/browser/resources/password_manager/checkup_section.ts
index 6b6bee8..6e4ab11 100644
--- a/chrome/browser/resources/password_manager/checkup_section.ts
+++ b/chrome/browser/resources/password_manager/checkup_section.ts
@@ -225,10 +225,6 @@
       PasswordManagerImpl.getInstance().recordPasswordCheckInteraction(
           PasswordCheckInteraction.START_CHECK_AUTOMATICALLY);
     }
-    if (route.page === Page.CHECKUP) {
-      PasswordManagerImpl.getInstance()
-          .dismissSafetyHubPasswordMenuNotification();
-    }
   }
 
   private async onStatusChanged_(
diff --git a/chrome/browser/resources/password_manager/password_manager_proxy.ts b/chrome/browser/resources/password_manager/password_manager_proxy.ts
index b0c78069..a579fa7 100644
--- a/chrome/browser/resources/password_manager/password_manager_proxy.ts
+++ b/chrome/browser/resources/password_manager/password_manager_proxy.ts
@@ -377,9 +377,6 @@
    * @param ids The ids for the password entries being moved.
    */
   movePasswordsToAccount(ids: number[]): void;
-
-  /** Dismiss the menu notifications for the Safety Hub password module. */
-  dismissSafetyHubPasswordMenuNotification(): void;
 }
 
 /**
@@ -605,10 +602,6 @@
     chrome.passwordsPrivate.movePasswordsToAccount(ids);
   }
 
-  dismissSafetyHubPasswordMenuNotification() {
-    chrome.send('dismissSafetyHubPasswordMenuNotification');
-  }
-
   static getInstance(): PasswordManagerProxy {
     return instance || (instance = new PasswordManagerImpl());
   }
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.ts b/chrome/browser/resources/settings/basic_page/basic_page.ts
index 9d78e58..d50c1437 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.ts
+++ b/chrome/browser/resources/settings/basic_page/basic_page.ts
@@ -41,6 +41,11 @@
 import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
 import {assert} from 'chrome://resources/js/assert.js';
 import {beforeNextRender, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+// clang-format off
+// <if expr="chromeos_ash">
+import {OpenWindowProxyImpl} from 'chrome://resources/js/open_window_proxy.js';
+// </if>
+// clang-format on
 
 import {SettingsIdleLoadElement} from '../controls/settings_idle_load.js';
 import {loadTimeData} from '../i18n_setup.js';
@@ -330,10 +335,8 @@
 
   // <if expr="chromeos_ash">
   private onOpenChromeOsLanguagesSettingsClick_() {
-    const chromeOSLanguagesSettingsPath =
-        loadTimeData.getString('chromeOSLanguagesSettingsPath');
-    window.location.href =
-        `chrome://os-settings/${chromeOSLanguagesSettingsPath}`;
+    OpenWindowProxyImpl.getInstance().openUrl(
+        loadTimeData.getString('osSettingsLanguagesPageUrl'));
   }
   // </if>
 
diff --git a/chrome/browser/resources/settings/safety_hub/safety_hub_browser_proxy.ts b/chrome/browser/resources/settings/safety_hub/safety_hub_browser_proxy.ts
index 04969e6d..e6e1c82 100644
--- a/chrome/browser/resources/settings/safety_hub/safety_hub_browser_proxy.ts
+++ b/chrome/browser/resources/settings/safety_hub/safety_hub_browser_proxy.ts
@@ -115,12 +115,6 @@
   /** Resets the notification permission for the origins. */
   resetNotificationPermissionForOrigins(origin: string[]): void;
 
-  /**
-   * When Safety Hub is visited, the active three-dot menu notification is
-   * dismissed, if there is any.
-   */
-  dismissActiveMenuNotification(): void;
-
   /** Gets data for the password top card. */
   getPasswordCardData(): Promise<CardInfo>;
 
@@ -190,10 +184,6 @@
     chrome.send('resetNotificationPermissionForOrigins', [origins]);
   }
 
-  dismissActiveMenuNotification() {
-    chrome.send('dismissActiveMenuNotification');
-  }
-
   getPasswordCardData() {
     return sendWithPromise('getPasswordCardData');
   }
diff --git a/chrome/browser/resources/settings/safety_hub/safety_hub_page.ts b/chrome/browser/resources/settings/safety_hub/safety_hub_page.ts
index c7850f8c..8f62cb6 100644
--- a/chrome/browser/resources/settings/safety_hub/safety_hub_page.ts
+++ b/chrome/browser/resources/settings/safety_hub/safety_hub_page.ts
@@ -20,7 +20,7 @@
 import {MetricsBrowserProxy, MetricsBrowserProxyImpl, SafetyHubCardState} from '../metrics_browser_proxy.js';
 import {RelaunchMixin, RestartType} from '../relaunch_mixin.js';
 import {routes} from '../route.js';
-import {RouteObserverMixin, Router} from '../router.js';
+import {Router} from '../router.js';
 
 import {CardInfo, CardState, NotificationPermission, SafetyHubBrowserProxy, SafetyHubBrowserProxyImpl, SafetyHubEvent, UnusedSitePermissions} from './safety_hub_browser_proxy.js';
 import {SiteInfo} from './safety_hub_module.js';
@@ -34,8 +34,8 @@
   };
 }
 
-const SettingsSafetyHubPageElementBase = RouteObserverMixin(
-    RelaunchMixin(WebUiListenerMixin(I18nMixin(PolymerElement))));
+const SettingsSafetyHubPageElementBase =
+    RelaunchMixin(WebUiListenerMixin(I18nMixin(PolymerElement)));
 
 export class SettingsSafetyHubPageElement extends
     SettingsSafetyHubPageElementBase {
@@ -107,15 +107,6 @@
     this.initializeUserEducation_();
   }
 
-  override currentRouteChanged() {
-    if (Router.getInstance().getCurrentRoute() !== routes.SAFETY_HUB) {
-      return;
-    }
-    // When the user navigates to the Safety Hub page, any active menu
-    // notification is dismissed.
-    this.browserProxy_.dismissActiveMenuNotification();
-  }
-
   private initializeCards_() {
     // TODO(1443466): Add listeners for cards.
     this.browserProxy_.getPasswordCardData().then((data: CardInfo) => {
diff --git a/chrome/browser/screen_ai/screen_ai_install_state.cc b/chrome/browser/screen_ai/screen_ai_install_state.cc
index 427c129..f8058b63 100644
--- a/chrome/browser/screen_ai/screen_ai_install_state.cc
+++ b/chrome/browser/screen_ai/screen_ai_install_state.cc
@@ -28,7 +28,7 @@
 
 namespace {
 const int kScreenAICleanUpDelayInDays = 30;
-const char kMinExpectedVersion[] = "119.0";
+const char kMinExpectedVersion[] = "121.1";
 
 bool IsDeviceCompatible() {
   // Check if the CPU has the required instruction set to run the Screen AI
diff --git a/chrome/browser/screen_ai/screen_ai_service_router.cc b/chrome/browser/screen_ai/screen_ai_service_router.cc
index 3a077ee..62dea07a 100644
--- a/chrome/browser/screen_ai/screen_ai_service_router.cc
+++ b/chrome/browser/screen_ai/screen_ai_service_router.cc
@@ -29,6 +29,8 @@
 // the component and are required to initialize the library.
 const base::FilePath::CharType kMainContentExtractionFilesList[] =
     FILE_PATH_LITERAL("files_list_main_content_extraction.txt");
+const base::FilePath::CharType kOcrFilesList[] =
+    FILE_PATH_LITERAL("files_list_ocr.txt");
 
 class ComponentFiles {
  public:
@@ -81,6 +83,11 @@
 #endif
     model_files_[relative_file_path] =
         base::File(full_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+    if (!model_files_[relative_file_path].IsValid()) {
+      VLOG(0) << "Could not open " << full_path;
+      model_files_.clear();
+      return;
+    }
   }
 }
 
@@ -174,10 +181,26 @@
     return;
   }
 
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE,
+      {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
+      base::BindOnce(&ComponentFiles::Load, kOcrFilesList),
+      base::BindOnce(&ScreenAIServiceRouter::InitializeOCR,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     ocr_service_.BindNewPipeAndPassReceiver()));
+}
+
+void ScreenAIServiceRouter::InitializeOCR(
+    mojo::PendingReceiver<mojom::OCRService> receiver,
+    std::unique_ptr<ComponentFiles> component_files) {
+  if (component_files->model_files_.empty()) {
+    ScreenAIServiceRouter::SetLibraryLoadState(false);
+    return;
+  }
+
   screen_ai_service_factory_->InitializeOCR(
-      screen_ai::ScreenAIInstallState::GetInstance()
-          ->get_component_binary_path(),
-      ocr_service_.BindNewPipeAndPassReceiver(),
+      component_files->library_binary_path_,
+      std::move(component_files->model_files_), std::move(receiver),
       base::BindOnce(&ScreenAIServiceRouter::SetLibraryLoadState,
                      weak_ptr_factory_.GetWeakPtr()));
 }
diff --git a/chrome/browser/screen_ai/screen_ai_service_router.h b/chrome/browser/screen_ai/screen_ai_service_router.h
index 3496ffe..a4e901c 100644
--- a/chrome/browser/screen_ai/screen_ai_service_router.h
+++ b/chrome/browser/screen_ai/screen_ai_service_router.h
@@ -38,6 +38,8 @@
   void InitializeMainContentExtractionIfNeeded();
 
  private:
+  void InitializeOCR(mojo::PendingReceiver<mojom::OCRService> receiver,
+                     std::unique_ptr<ComponentFiles> model_files);
   void InitializeMainContentExtraction(
       mojo::PendingReceiver<mojom::MainContentExtractionService> receiver,
       std::unique_ptr<ComponentFiles> model_files);
diff --git a/chrome/browser/ssl/https_first_mode_settings_tracker.cc b/chrome/browser/ssl/https_first_mode_settings_tracker.cc
index 2f2d554c..e3aa3b5 100644
--- a/chrome/browser/ssl/https_first_mode_settings_tracker.cc
+++ b/chrome/browser/ssl/https_first_mode_settings_tracker.cc
@@ -87,6 +87,9 @@
 // kFallbackEntriesRollingWindowSize.
 constexpr char kFallbackEventsPrefTimestampKey[] = "timestamp";
 
+constexpr int kNavigationCounterDefaultRollingWindowSizeInDays = 7;
+constexpr int kNavigationCounterDefaultSaveInterval = 10;
+
 namespace {
 
 using security_interstitials::https_only_mode::SiteEngagementHeuristicState;
@@ -268,6 +271,15 @@
         GetSyntheticFieldTrialGroupName(setting));
   }
 
+  // Restore navigation counts from the pref to be used in the Typically Secure
+  // heuristic.
+  navigation_counts_dict_ =
+      profile_->GetPrefs()->GetDict(prefs::kHttpsUpgradeNavigations).Clone();
+  navigation_counter_ = std::make_unique<DailyNavigationCounter>(
+      &navigation_counts_dict_, clock_,
+      kNavigationCounterDefaultRollingWindowSizeInDays,
+      kNavigationCounterDefaultSaveInterval);
+
   content::GetUIThreadTaskRunner({base::TaskPriority::BEST_EFFORT})
       ->PostTask(FROM_HERE, base::BindOnce(&HttpsFirstModeService::AfterStartup,
                                            weak_factory_.GetWeakPtr()));
@@ -537,6 +549,17 @@
   return HttpsFirstModeSetting::kDisabled;
 }
 
+void HttpsFirstModeService::IncrementRecentNavigationCount() {
+  if (navigation_counter_->Increment()) {
+    profile_->GetPrefs()->SetDict(prefs::kHttpsUpgradeNavigations,
+                                  navigation_counts_dict_.Clone());
+  }
+}
+
+size_t HttpsFirstModeService::GetRecentNavigationCount() const {
+  return navigation_counter_->GetTotal();
+}
+
 void HttpsFirstModeService::SetClockForTesting(base::Clock* clock) {
   clock_ = clock;
 }
diff --git a/chrome/browser/ssl/https_first_mode_settings_tracker.h b/chrome/browser/ssl/https_first_mode_settings_tracker.h
index 5b80ca64..f5cf570 100644
--- a/chrome/browser/ssl/https_first_mode_settings_tracker.h
+++ b/chrome/browser/ssl/https_first_mode_settings_tracker.h
@@ -13,6 +13,7 @@
 #include "base/task/task_traits.h"
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
 #include "chrome/browser/safe_browsing/advanced_protection_status_manager.h"
+#include "chrome/browser/ssl/daily_navigation_counter.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/site_engagement/content/site_engagement_score.h"
@@ -89,6 +90,11 @@
 
   HttpsFirstModeSetting GetCurrentSetting() const;
 
+  // Increment recent navigation count and maybe save the counts to a pref.
+  void IncrementRecentNavigationCount();
+  // Returns the number of navigations counted recently in a rolling window.
+  size_t GetRecentNavigationCount() const;
+
   // Sets the clock for use in tests.
   void SetClockForTesting(base::Clock* clock);
   // Returns the current number of fallback entries recorded.
@@ -122,6 +128,9 @@
   PrefChangeRegistrar pref_change_registrar_;
   raw_ptr<base::Clock> clock_;
 
+  base::Value::Dict navigation_counts_dict_;
+  std::unique_ptr<DailyNavigationCounter> navigation_counter_;
+
   base::ScopedObservation<
       safe_browsing::AdvancedProtectionStatusManager,
       safe_browsing::AdvancedProtectionStatusManager::StatusChangedObserver>
diff --git a/chrome/browser/ssl/https_upgrades_browsertest.cc b/chrome/browser/ssl/https_upgrades_browsertest.cc
index a0c6e8d..ecb86a28 100644
--- a/chrome/browser/ssl/https_upgrades_browsertest.cc
+++ b/chrome/browser/ssl/https_upgrades_browsertest.cc
@@ -5,6 +5,7 @@
 #include <algorithm>
 #include <vector>
 
+#include "base/memory/raw_ptr.h"
 #include "base/strings/strcat.h"
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
@@ -114,6 +115,10 @@
   // automatically enable HFM) and HTTPS upgrades feature flag.
   kAllAutoHFM,
 
+  // Enables HFM in Incognito mode. Runs testcases inside an Incognito
+  // window.
+  kHttpsFirstModeIncognito,
+
   // Enables HFM pref, HFM with Site Engagement heuristic, HFM for typically
   // secure users and HTTPS upgrades feature flag.
   kAll,
@@ -204,6 +209,12 @@
             /*disabled_features=*/{});
         break;
 
+      case HttpsUpgradesTestType::kHttpsFirstModeIncognito:
+        feature_list_.InitWithFeatures(
+            /*enabled_features=*/{features::kHttpsFirstModeIncognito},
+            /*disabled_features=*/{});
+        break;
+
       // Enable HTTPS-Upgrades, HFM and HFM with Site Engagement heuristic.
       case HttpsUpgradesTestType::kAll:
         // HFM pref is enabled in SetUpOnMainThread.
@@ -260,6 +271,13 @@
     HttpsUpgradesInterceptor::SetHttpsPortForTesting(https_server()->port());
     HttpsUpgradesInterceptor::SetHttpPortForTesting(http_server()->port());
 
+    // Incognito tests swap out the default Browser instance for an Incognito
+    // window, and then should behave like kHttpsFirstMode type tests.
+    if (https_upgrades_test_type() ==
+        HttpsUpgradesTestType::kHttpsFirstModeIncognito) {
+      UseIncognitoBrowser();
+    }
+
     // Only enable the HTTPS-First Mode pref when the test config calls for it.
     // Some of the HFM heuristics check that the preference wasn't set so as
     // not to override user preference (e.g. if the user changed the pref by
@@ -274,6 +292,8 @@
     browser()->profile()->GetPrefs()->ClearPref(
         prefs::kHttpsOnlyModeAutoEnabled);
     browser()->profile()->GetPrefs()->ClearPref(prefs::kHttpsUpgradeFallbacks);
+    browser()->profile()->GetPrefs()->ClearPref(
+        prefs::kHttpsUpgradeNavigations);
   }
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
@@ -288,6 +308,19 @@
     mock_cert_verifier_.TearDownInProcessBrowserTestFixture();
   }
 
+  // Incognito testing support
+  //
+  // Returns the active Browser for the test type being run.
+  Browser* GetBrowser() const {
+    return incognito_browser_ ? incognito_browser_.get() : browser();
+  }
+  // Call to use an Incognito browser rather than the default.
+  void UseIncognitoBrowser() {
+    ASSERT_EQ(nullptr, incognito_browser_.get());
+    incognito_browser_ = CreateIncognitoBrowser();
+  }
+  bool IsIncognito() { return incognito_browser_ != nullptr; }
+
  protected:
   HttpsUpgradesTestType https_upgrades_test_type() const { return GetParam(); }
 
@@ -324,12 +357,16 @@
 
   // Whether HFM is enabled by the UI setting and the tests should run steps
   // that assume the HTTP interstitial will trigger (i.e., for fallback HTTP
-  // navigations when HTTPS-First Mode is enabled).
+  // navigations when HTTPS-First Mode is enabled). This includes the
+  // HFM-in-Incognito Mode tests, as those are run in an Incognito mode window
+  // and thus have HFM enabled.
   bool IsHttpsFirstModePrefEnabled() const {
     return https_upgrades_test_type() ==
                HttpsUpgradesTestType::kHttpsFirstModeOnly ||
            https_upgrades_test_type() ==
                HttpsUpgradesTestType::kHttpsFirstModeAndHttpsUpgrades ||
+           https_upgrades_test_type() ==
+               HttpsUpgradesTestType::kHttpsFirstModeIncognito ||
            https_upgrades_test_type() == HttpsUpgradesTestType::kAll;
   }
 
@@ -405,6 +442,7 @@
   net::EmbeddedTestServer https_server_{net::EmbeddedTestServer::TYPE_HTTPS};
   content::ContentMockCertVerifier mock_cert_verifier_;
   base::HistogramTester histograms_;
+  raw_ptr<Browser, AcrossTasksDanglingUntriaged> incognito_browser_ = nullptr;
 };
 
 INSTANTIATE_TEST_SUITE_P(
@@ -419,6 +457,7 @@
         HttpsUpgradesTestType::
             kHttpsFirstModeForTypicallySecureUsersAndHttpsUpgrades,
         HttpsUpgradesTestType::kAllAutoHFM,
+        HttpsUpgradesTestType::kHttpsFirstModeIncognito,
         HttpsUpgradesTestType::kAll,
         HttpsUpgradesTestType::kNeither),
     // Map param to a human-readable string for better test output.
@@ -439,6 +478,8 @@
           return "HttpsFirstModeForTypicallySecureUsersAndHttpsUpgrades";
         case HttpsUpgradesTestType::kAllAutoHFM:
           return "AllAutoHFM";
+        case HttpsUpgradesTestType::kHttpsFirstModeIncognito:
+          return "HttpsFirstModeIncognito";
         case HttpsUpgradesTestType::kAll:
           return "AllFeatures";
         case HttpsUpgradesTestType::kNeither:
@@ -502,7 +543,7 @@
 IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest,
                        UrlWithHttpsScheme_ShouldLoad) {
   GURL https_url = https_server()->GetURL("foo.com", "/simple.html");
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   EXPECT_TRUE(content::NavigateToURL(contents, https_url));
 
   // Verify that navigation event metrics were not recorded as the navigation
@@ -519,7 +560,7 @@
 // that exact URL.
 IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest, Localhost_ShouldNotUpgrade) {
   GURL localhost_url = http_server()->GetURL("localhost", "/simple.html");
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   EXPECT_TRUE(content::NavigateToURL(contents, localhost_url));
 
   // Verify that navigation event metrics were not recorded as the navigation
@@ -555,7 +596,7 @@
           GetChromeTestDataDir().MaybeAsASCII(),
           local_ip_url.GetWithEmptyPath());
 
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
 
   if (IsHttpsFirstModePrefEnabled()) {
     // HFM should attempt the upgrade, fail, and fallback to the interstitial.
@@ -596,7 +637,7 @@
   // Note that we don't test with an RFC1918 IP because the test server
   // wouldn't receive the traffic (since it relies on DNS).
 
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   if (IsHttpsFirstModePrefEnabled()) {
     EXPECT_FALSE(content::NavigateToURL(contents, nonunique_url1));
     EXPECT_FALSE(content::NavigateToURL(contents, nonunique_url2));
@@ -632,7 +673,7 @@
                        UrlWithHttpsScheme_BrokenSSL_ShouldNotFallback) {
   GURL https_url = https_server()->GetURL("bad-https.com", "/simple.html");
 
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   EXPECT_FALSE(content::NavigateToURL(contents, https_url));
   EXPECT_EQ(https_url, contents->GetLastCommittedURL());
 
@@ -654,7 +695,7 @@
   GURL http_url = http_server()->GetURL("bad-https.com", "/simple.html");
   GURL https_url = https_server()->GetURL("bad-https.com", "/simple.html");
 
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, http_url);
   EXPECT_EQ(http_url, contents->GetLastCommittedURL());
 
@@ -703,9 +744,14 @@
 IN_PROC_BROWSER_TEST_P(
     HttpsUpgradesBrowserTest,
     MAYBE_UrlWithHttpScheme_BrokenSSL_ShouldInterstitial_SiteEngagement) {
+  // HFM+SE is not enabled in Incognito.
+  if (IsIncognito()) {
+    return;
+  }
+
   content::WebContents* contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
+      GetBrowser()->tab_strip_model()->GetActiveWebContents();
+  Profile* profile = GetBrowser()->profile();
   content::SSLHostStateDelegate* state = profile->GetSSLHostStateDelegate();
 
   // Set test clock.
@@ -891,8 +937,13 @@
 IN_PROC_BROWSER_TEST_P(
     HttpsUpgradesBrowserTest,
     PRE_UrlWithHttpScheme_BrokenSSL_ShouldInterstitial_TypicallySecureUser) {
+  // HFM-for-Typically-Secure-Users is not enabled in Incognito.
+  if (IsIncognito()) {
+    return;
+  }
+
   content::WebContents* contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
+      GetBrowser()->tab_strip_model()->GetActiveWebContents();
   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
 
   if (!IsHttpsFirstModePrefEnabled()) {
@@ -908,7 +959,8 @@
   SetSiteEngagementScore(GURL("https://google.com"), 90);
 
   base::SimpleTestClock clock;
-  base::Time now = base::Time::NowFromSystemTime();
+  base::Time now;
+  EXPECT_TRUE(base::Time::FromUTCString("2023-10-15T06:00:00Z", &now));
   // Start the clock at standard system time.
   clock.SetNow(now);
 
@@ -988,13 +1040,18 @@
 IN_PROC_BROWSER_TEST_P(
     HttpsUpgradesBrowserTest,
     MAYBE_UrlWithHttpScheme_BrokenSSL_ShouldInterstitial_TypicallySecureUser) {
+  // HFM-for-Typically-Secure-Users is not enabled in Incognito.
+  if (IsIncognito()) {
+    return;
+  }
+
   // Advance the clock to one day after the last fallback event, which happened
   // on the 15th day.
   base::SimpleTestClock clock;
   clock.SetNow(base::Time::NowFromSystemTime() + base::Days(16));
 
   content::WebContents* contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
+      GetBrowser()->tab_strip_model()->GetActiveWebContents();
   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
 
   HttpsFirstModeService* hfm_service =
@@ -1004,11 +1061,14 @@
   // runs, and we need to move the clock forward for this to work. So call it
   // explicitly again here.
   hfm_service->CheckUserIsTypicallySecureAndMaybeEnableHttpsFirstMode();
+  size_t initial_navigation_count = hfm_service->GetRecentNavigationCount();
 
   GURL http_url = http_server()->GetURL("bad-https.com", "/simple.html");
   GURL https_url = https_server()->GetURL("bad-https.com", "/simple.html");
   NavigateAndWaitForFallback(contents, http_url);
   EXPECT_EQ(http_url, contents->GetLastCommittedURL());
+  EXPECT_EQ(initial_navigation_count + 1u,
+            hfm_service->GetRecentNavigationCount());
 
   bool expect_interstitial =
       IsHttpsFirstModePrefEnabled() || IsTypicallySecureUserFeatureEnabled();
@@ -1049,6 +1109,8 @@
   clock.Advance(base::Days(1));
   NavigateAndWaitForFallback(contents, http_url);
   EXPECT_EQ(http_url, contents->GetLastCommittedURL());
+  EXPECT_EQ(initial_navigation_count + 2u,
+            hfm_service->GetRecentNavigationCount());
 
   if (expect_interstitial) {
     EXPECT_TRUE(
@@ -1077,6 +1139,8 @@
   // Disable HFM. Should no longer auto-enable it.
   SetPref(false);
   NavigateAndWaitForFallback(contents, http_url);
+  EXPECT_EQ(initial_navigation_count + 3u,
+            hfm_service->GetRecentNavigationCount());
   EXPECT_EQ(http_url, contents->GetLastCommittedURL());
   EXPECT_FALSE(
       chrome_browser_interstitials::IsShowingHttpsFirstModeInterstitial(
@@ -1087,6 +1151,8 @@
   SetPref(true);
   NavigateAndWaitForFallback(contents, http_url);
   EXPECT_EQ(http_url, contents->GetLastCommittedURL());
+  EXPECT_EQ(initial_navigation_count + 4u,
+            hfm_service->GetRecentNavigationCount());
 
   EXPECT_TRUE(chrome_browser_interstitials::IsShowingHttpsFirstModeInterstitial(
       contents));
@@ -1163,7 +1229,7 @@
           }));
 
   GURL http_url("http://example.com");
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, http_url);
 }
 
@@ -1173,7 +1239,7 @@
                        InterstitialBypassed_HttpFallbackLoaded) {
   GURL http_url = http_server()->GetURL("bad-https.com", "/simple.html");
 
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, http_url);
 
   if (IsHttpsFirstModePrefEnabled()) {
@@ -1223,7 +1289,7 @@
   GURL http_url = http_server()->GetURL("foo.com", "/close-socket");
   GURL https_url = https_server()->GetURL("foo.com", "/close-socket");
 
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, http_url);
   EXPECT_EQ(http_url, contents->GetLastCommittedURL());
 
@@ -1255,7 +1321,7 @@
 
   GURL http_url = http_server()->GetURL("bad-https.com", "/simple.html");
   GURL https_url = https_server()->GetURL("bad-https.com", "/simple.html");
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
 
   {
     // Set up an interceptor that will return ERR_NAME_NOT_RESOLVED. Navigating
@@ -1327,7 +1393,7 @@
   GURL redirecting_http_url =
       http_server()->GetURL("foo.com", www_redirect_path);
 
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
 
   // Set up an interceptor that will return ERR_NAME_NOT_RESOLVED for
   // nonexistentsite.com.
@@ -1370,7 +1436,7 @@
 
   GURL http_url = http_server()->GetURL("blorp", "/simple.html");
   GURL https_url = https_server()->GetURL("blorp", "/simple.html");
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
 
   // Set up an interceptor that will return ERR_NAME_NOT_RESOLVED. Navigating
   // to the HTTP URL should get upgraded to HTTPS, and then fallback to HTTP
@@ -1402,7 +1468,7 @@
       https_server()->GetURL("foo.com", "/iframe_blank.html"));
   const GURL iframe_url(http_server()->GetURL("foo.com", "/simple.html"));
 
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   EXPECT_TRUE(content::NavigateToURL(contents, parent_url));
 
   content::TestNavigationObserver nav_observer(contents, 1);
@@ -1425,7 +1491,7 @@
   const GURL iframe_url(http_server()->GetURL("bar.com", "/simple.html"));
 
   // Navigate to `parent_url` and bypass the HTTPS-Only Mode warning.
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, parent_url);
 
   if (IsHttpsFirstModePrefEnabled()) {
@@ -1482,7 +1548,7 @@
   HttpsUpgradesInterceptor::SetHttpsPortForTesting(timeout_server.port());
 
   const GURL http_url = http_server()->GetURL("foo.com", "/simple.html");
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, http_url);
 
   if (IsHttpsFirstModePrefEnabled()) {
@@ -1507,7 +1573,7 @@
       "/ssl/page_with_form_targeting_http_url.html", replacement_text);
 
   // Navigate to the page hosting the form on "foo.com".
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   content::NavigateToURLBlockUntilNavigationsComplete(
       contents, http_server()->GetURL("bad-https.com", replacement_path), 1);
 
@@ -1559,7 +1625,7 @@
   GURL url = https_server()->GetURL("foo.com",
                                     "/server-redirect?" + target_url.spec());
 
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
 
   // NavigateToURL() returns `false` because the final redirected URL does not
   // match `url`. Separately ensure the navigation succeeded using a navigation
@@ -1623,7 +1689,7 @@
   HttpsUpgradesInterceptor::SetHttpsPortForTesting(downgrading_server.port());
 
   GURL url = downgrading_server.GetURL("foo.com", "/");
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, url);
 
   if (IsHttpsFirstModePrefEnabled()) {
@@ -1648,7 +1714,7 @@
   GURL http_url = http_server()->GetURL("foo.com", "/close-socket");
   GURL https_url = https_server()->GetURL("foo.com", "/close-socket");
 
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   auto* helper = SecurityStateTabHelper::FromWebContents(contents);
   NavigateAndWaitForFallback(contents, http_url);
   EXPECT_EQ(http_url, contents->GetLastCommittedURL());
@@ -1680,7 +1746,7 @@
   GURL http_url = http_server()->GetURL("bad-https.com", "/simple.html");
   GURL https_url = https_server()->GetURL("bad-https.com", "/simple.html");
 
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   auto* helper = SecurityStateTabHelper::FromWebContents(contents);
   NavigateAndWaitForFallback(contents, http_url);
   EXPECT_EQ(http_url, contents->GetLastCommittedURL());
@@ -1739,7 +1805,7 @@
   // HTTPS server will have a cert error.
   GURL https_url = https_server()->GetURL("bad-https.com", "/simple.html");
 
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, http_url);
 
   if (IsHttpsFirstModePrefEnabled()) {
@@ -1794,7 +1860,7 @@
   GURL http_url = http_server()->GetURL("foo.com", "/close-socket");
   GURL https_url = https_server()->GetURL("foo.com", "/close-socket");
 
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, http_url);
   EXPECT_EQ(http_url, contents->GetLastCommittedURL());
 
@@ -1806,7 +1872,7 @@
       contents, "window.certificateErrorPageController.openHelpCenter();"));
 
   // New tab should include the p-link "first_mode".
-  EXPECT_EQ(browser()
+  EXPECT_EQ(GetBrowser()
                 ->tab_strip_model()
                 ->GetActiveWebContents()
                 ->GetVisibleURL()
@@ -1843,7 +1909,7 @@
   ASSERT_EQ(http_url.host(), bad_https_url.host());
   ASSERT_EQ(bad_https_url.host(), good_https_url.host());
 
-  auto* tab = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* tab = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   auto* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
   auto* state = static_cast<StatefulSSLHostStateDelegate*>(
       profile->GetSSLHostStateDelegate());
@@ -1919,7 +1985,7 @@
   GURL http_url = http_server()->GetURL("foo.com", "/close-socket");
   GURL https_url = https_server()->GetURL("foo.com", "/close-socket");
 
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, http_url);
   EXPECT_EQ(http_url, contents->GetLastCommittedURL());
 
@@ -1951,7 +2017,7 @@
   GURL http_url = http_server()->GetURL("foo.com", "/close-socket");
   GURL https_url = https_server()->GetURL("foo.com", "/close-socket");
 
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, http_url);
   EXPECT_EQ(http_url, contents->GetLastCommittedURL());
 
@@ -1959,7 +2025,7 @@
       contents));
 
   // Leave the interstitial by closing the tab.
-  chrome::CloseWebContents(browser(), contents, false);
+  chrome::CloseWebContents(GetBrowser(), contents, false);
 
   // Verify that the interstitial metrics were correctly recorded.
   histograms()->ExpectBucketCount(
@@ -1975,7 +2041,7 @@
 // the next time they visit the host.
 IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest, AllowlistEntryExpires) {
   content::WebContents* contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
+      GetBrowser()->tab_strip_model()->GetActiveWebContents();
   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
   content::SSLHostStateDelegate* state = profile->GetSSLHostStateDelegate();
 
@@ -2031,7 +2097,7 @@
 // seven days in the future from now.
 IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest, RevisitingBumpsExpiration) {
   content::WebContents* contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
+      GetBrowser()->tab_strip_model()->GetActiveWebContents();
   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
   content::SSLHostStateDelegate* state = profile->GetSSLHostStateDelegate();
 
@@ -2096,7 +2162,7 @@
 // it is more strict).
 IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest, PreferHstsOverHttpsFirstMode) {
   content::WebContents* contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
+      GetBrowser()->tab_strip_model()->GetActiveWebContents();
   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
 
   // URL for HTTPS server that will result in a certificate error.
@@ -2185,7 +2251,7 @@
   GURL downgrading_http_url =
       downgrading_https_url.ReplaceComponents(swap_http_scheme);
 
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
 
   // Navigate to a "good" HTTPS site.
   EXPECT_TRUE(content::NavigateToURL(contents, good_https_url));
@@ -2239,7 +2305,7 @@
     return;
   }
   content::WebContents* contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
+      GetBrowser()->tab_strip_model()->GetActiveWebContents();
 
   // Without any policy allowlist, navigate to HTTP URL on foo.com. It *should*
   // get upgraded to HTTPS.
@@ -2327,7 +2393,7 @@
     return;
   }
   content::WebContents* contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
+      GetBrowser()->tab_strip_model()->GetActiveWebContents();
   auto* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
 
   // Without any policy allowlist, navigate to an HTTP URL. It should show the
@@ -2368,7 +2434,7 @@
   prefs->SetBoolean(prefs::kHttpsUpgradesEnabled, false);
 
   content::WebContents* contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
+      GetBrowser()->tab_strip_model()->GetActiveWebContents();
   GURL http_url = http_server()->GetURL("foo.com", "/simple.html");
   GURL https_url = https_server()->GetURL("foo.com", "/simple.html");
 
@@ -2404,7 +2470,7 @@
 IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest,
                        MAYBE_InsecureContentSettingDisablesUpgrades) {
   content::WebContents* contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
+      GetBrowser()->tab_strip_model()->GetActiveWebContents();
   GURL http_url = http_server()->GetURL("foo.com", "/simple.html");
   GURL https_url = https_server()->GetURL("foo.com", "/simple.html");
   auto* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
@@ -2474,7 +2540,7 @@
 IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest,
                        MAYBE_InsecureContentSettingDisablesHFMForEngagedSites) {
   content::WebContents* contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
+      GetBrowser()->tab_strip_model()->GetActiveWebContents();
   GURL http_url = http_server()->GetURL("foo.com", "/simple.html");
   GURL https_url = https_server()->GetURL("foo.com", "/simple.html");
   auto* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
@@ -2562,7 +2628,7 @@
       "good-https.com",
       base::StrCat({"/server-redirect-301?", redirecting_http_url.spec()}));
 
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   EXPECT_FALSE(
       content::NavigateToURL(contents, initial_redirecting_good_https_url));
 
@@ -2586,8 +2652,16 @@
 // HTTP allowlist is cleared.
 IN_PROC_BROWSER_TEST_P(HttpsUpgradesBrowserTest,
                        TogglingSettingClearsAllowlist) {
+  // The allowlist in an Incognito window is in-memory only, and is not cleared
+  // when the main profile's pref changes.
+  // TODO(crbug.com/1494186): Add a test to cover the Incognito allowlisting
+  // behavior explicitly.
+  if (IsIncognito()) {
+    return;
+  }
+
   auto http_url = http_server()->GetURL("bad-https.com", "/simple.html");
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
 
   // Start by enabling HTTPS-First Mode.
   SetPref(true);
@@ -2629,8 +2703,8 @@
   }
   GURL http_url = http_server()->GetURL("foo.com", "/simple.html");
   GURL https_url = https_server()->GetURL("foo.com", "/simple.html");
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
-  OmniboxClient* omnibox_client = browser()
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
+  OmniboxClient* omnibox_client = GetBrowser()
                                       ->window()
                                       ->GetLocationBar()
                                       ->GetOmniboxView()
@@ -2667,8 +2741,8 @@
   }
   GURL http_url = http_server()->GetURL("foo.com", "/simple.html");
   GURL https_url = https_server()->GetURL("foo.com", "/simple.html");
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
-  OmniboxClient* omnibox_client = browser()
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
+  OmniboxClient* omnibox_client = GetBrowser()
                                       ->window()
                                       ->GetLocationBar()
                                       ->GetOmniboxView()
@@ -2696,8 +2770,8 @@
   }
   GURL http_url = http_server()->GetURL("foo.com", "/simple.html");
   GURL https_url = https_server()->GetURL("foo.com", "/simple.html");
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
-  OmniboxClient* omnibox_client = browser()
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
+  OmniboxClient* omnibox_client = GetBrowser()
                                       ->window()
                                       ->GetLocationBar()
                                       ->GetOmniboxView()
@@ -2752,7 +2826,7 @@
   GURL http_url = http_server()->GetURL("bad-https.com", "/simple.html");
   GURL https_url = https_server()->GetURL("bad-https.com", "/simple.html");
 
-  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  auto* contents = GetBrowser()->tab_strip_model()->GetActiveWebContents();
   NavigateAndWaitForFallback(contents, http_url);
   EXPECT_EQ(http_url, contents->GetLastCommittedURL());
 
@@ -2904,3 +2978,38 @@
   histograms()->ExpectTotalCount(
       "Security.HttpsFirstMode.SettingEnabledAtStartup2", 1);
 }
+
+using TypicallySecureUserBrowserTest = InProcessBrowserTest;
+
+IN_PROC_BROWSER_TEST_F(TypicallySecureUserBrowserTest,
+                       PRE_RestoreCountsOnStartup_OneNavigation) {
+  HttpsFirstModeService* hfm_service =
+      HttpsFirstModeServiceFactory::GetForProfile(browser()->profile());
+  hfm_service->IncrementRecentNavigationCount();
+}
+
+IN_PROC_BROWSER_TEST_F(TypicallySecureUserBrowserTest,
+                       RestoreCountsOnStartup_OneNavigation) {
+  HttpsFirstModeService* hfm_service =
+      HttpsFirstModeServiceFactory::GetForProfile(browser()->profile());
+  // A single navigation will not be persisted to the pref and won't be restored
+  // on startup.
+  EXPECT_EQ(0u, hfm_service->GetRecentNavigationCount());
+}
+
+IN_PROC_BROWSER_TEST_F(TypicallySecureUserBrowserTest,
+                       PRE_RestoreCountsOnStartup_TenNavigations) {
+  HttpsFirstModeService* hfm_service =
+      HttpsFirstModeServiceFactory::GetForProfile(browser()->profile());
+  // Increment repeatedly to force the counts to be persisted to the pref.
+  for (size_t i = 0; i < 10; i++) {
+    hfm_service->IncrementRecentNavigationCount();
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(TypicallySecureUserBrowserTest,
+                       RestoreCountsOnStartup_TenNavigations) {
+  HttpsFirstModeService* hfm_service =
+      HttpsFirstModeServiceFactory::GetForProfile(browser()->profile());
+  EXPECT_EQ(10u, hfm_service->GetRecentNavigationCount());
+}
diff --git a/chrome/browser/ssl/https_upgrades_interceptor.cc b/chrome/browser/ssl/https_upgrades_interceptor.cc
index 91ed9fa..591eee5 100644
--- a/chrome/browser/ssl/https_upgrades_interceptor.cc
+++ b/chrome/browser/ssl/https_upgrades_interceptor.cc
@@ -190,9 +190,18 @@
       !g_browser_process->profile_manager()->IsValidProfile(profile)) {
     return nullptr;
   }
+
   PrefService* prefs = profile->GetPrefs();
   bool https_first_mode_enabled =
       prefs && prefs->GetBoolean(prefs::kHttpsOnlyModeEnabled);
+
+  if (base::FeatureList::IsEnabled(features::kHttpsFirstModeIncognito)) {
+    if (profile->IsIncognitoProfile() && prefs &&
+        prefs->GetBoolean(prefs::kHttpsFirstModeIncognito)) {
+      https_first_mode_enabled = true;
+    }
+  }
+
   return std::make_unique<HttpsUpgradesInterceptor>(
       frame_tree_node_id, https_first_mode_enabled, navigation_ui_data);
 }
diff --git a/chrome/browser/ssl/https_upgrades_navigation_throttle.cc b/chrome/browser/ssl/https_upgrades_navigation_throttle.cc
index 4f68b48..c89dad9d 100644
--- a/chrome/browser/ssl/https_upgrades_navigation_throttle.cc
+++ b/chrome/browser/ssl/https_upgrades_navigation_throttle.cc
@@ -64,6 +64,13 @@
   interstitial_state.enabled_by_pref =
       prefs && prefs->GetBoolean(prefs::kHttpsOnlyModeEnabled);
 
+  if (base::FeatureList::IsEnabled(features::kHttpsFirstModeIncognito)) {
+    if (profile->IsIncognitoProfile() && prefs &&
+        prefs->GetBoolean(prefs::kHttpsFirstModeIncognito)) {
+      interstitial_state.enabled_by_pref = true;
+    }
+  }
+
   StatefulSSLHostStateDelegate* state =
       static_cast<StatefulSSLHostStateDelegate*>(
           profile->GetSSLHostStateDelegate());
@@ -74,6 +81,7 @@
       HttpsFirstModeServiceFactory::GetForProfile(profile);
   if (hfm_service) {
     // Can be null in some cases, e.g. when using Ash sign-in profile.
+    hfm_service->IncrementRecentNavigationCount();
     interstitial_state.enabled_by_typically_secure_browsing =
         hfm_service->IsInterstitialEnabledByTypicallySecureUserHeuristic();
   }
diff --git a/chrome/browser/supervised_user/youtube_restrictions_browsertest.cc b/chrome/browser/supervised_user/youtube_restrictions_browsertest.cc
deleted file mode 100644
index ef761bb2..0000000
--- a/chrome/browser/supervised_user/youtube_restrictions_browsertest.cc
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright 2023 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <string>
-
-#include "base/test/bind.h"
-#include "base/test/scoped_feature_list.h"
-#include "build/build_config.h"
-#include "chrome/common/chrome_features.h"
-#include "chrome/test/base/mixin_based_in_process_browser_test.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "chrome/test/supervised_user/supervision_mixin.h"
-#include "components/google/core/common/google_switches.h"
-#include "components/network_session_configurator/common/network_switches.h"
-#include "components/safe_search_api/safe_search_util.h"
-#include "components/supervised_user/core/common/features.h"
-#include "content/public/test/browser_test.h"
-#include "content/public/test/browser_test_utils.h"
-#include "net/dns/mock_host_resolver.h"
-#include "net/test/embedded_test_server/http_request.h"
-
-namespace {
-
-using FilterWebsites = base::StrongAlias<class FilterWebsitesTag, bool>;
-
-class YouTubeRestrictionsBrowserTest
-    : public MixinBasedInProcessBrowserTest,
-      public ::testing::WithParamInterface<FilterWebsites> {
- protected:
-  YouTubeRestrictionsBrowserTest() {
-    // TODO(crbug.com/1394910): Use HTTPS URLs in tests to avoid having to
-    // disable this feature.
-    https_upgrades_feature_.InitAndDisableFeature(features::kHttpsUpgrades);
-
-    if (FilterWebsitesRequested()) {
-      filter_websites_feature_.InitAndEnableFeature(
-          supervised_user::kFilterWebsitesForSupervisedUsersOnDesktopAndIOS);
-    } else {
-      filter_websites_feature_.InitAndDisableFeature(
-          supervised_user::kFilterWebsitesForSupervisedUsersOnDesktopAndIOS);
-    }
-  }
-  ~YouTubeRestrictionsBrowserTest() override {
-    filter_websites_feature_.Reset();
-    https_upgrades_feature_.Reset();
-  }
-
-  MOCK_METHOD(void, InterceptYoutubeRestrictHeader, (std::string value));
-  MOCK_METHOD(void, InterceptRequest, ());
-
-  void SetUpOnMainThread() override {
-    MixinBasedInProcessBrowserTest::SetUpOnMainThread();
-
-    host_resolver()->AddRule("youtube.com", "127.0.0.1");
-
-    youtube_server_.AddDefaultHandlers(GetChromeTestDataDir());
-    youtube_server_.RegisterRequestMonitor(base::BindLambdaForTesting(
-        [&](const net::test_server::HttpRequest& request) {
-          InterceptRequest();
-          for (const auto& [key, value] : request.headers) {
-            if (key.compare(safe_search_api::kYouTubeRestrictHeaderName) == 0) {
-              InterceptYoutubeRestrictHeader(value);
-            }
-          }
-        }));
-
-    ASSERT_TRUE(youtube_server_.Start());
-  }
-
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    MixinBasedInProcessBrowserTest::SetUpCommandLine(command_line);
-
-    // Note for the google and youtube tests below, the throttles expect that
-    // the URLs are to google.com or youtube.com. Networking code also
-    // automatically upgrades http requests to these domains to https (see the
-    // preload list in https://www.chromium.org/hsts). So as a result we need
-    // to make the requests to an https server. Since the HTTPS server only
-    // serves a valid cert for localhost, so this is needed to load pages from
-    // "www.google.com" without an interstitial.
-    command_line->AppendSwitch(switches::kIgnoreCertificateErrors);
-
-    // The production code only allows known ports (80 for http and 443 for
-    // https), but the test server runs on a random port.
-    command_line->AppendSwitch(switches::kIgnoreGooglePortNumbers);
-  }
-
-  // Some platforms will filter websites (use url checking) regardless the
-  // feature status because they're already released. See
-  // supervised_user::IsChildAccountSupervisionEnabled()
-  bool FilterWebsitesRequested() const { return GetParam().value(); }
-
-  base::test::ScopedFeatureList https_upgrades_feature_;
-  base::test::ScopedFeatureList filter_websites_feature_;
-  supervised_user::SupervisionMixin supervision_mixin_{
-      mixin_host_,
-      this,
-      {.sign_in_mode =
-           supervised_user::SupervisionMixin::SignInMode::kSupervised}};
-  net::EmbeddedTestServer youtube_server_{net::EmbeddedTestServer::TYPE_HTTPS};
-};
-
-// TODO(https://crbug.com/1494241): Add more test coverage.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-#define MAYBE_RestrictionHeaderIsNotSent DISABLED_RestrictionHeaderIsNotSent
-#else
-#define MAYBE_RestrictionHeaderIsNotSent RestrictionHeaderIsNotSent
-#endif
-IN_PROC_BROWSER_TEST_P(YouTubeRestrictionsBrowserTest,
-                       MAYBE_RestrictionHeaderIsNotSent) {
-  if (supervised_user::IsChildAccountSupervisionEnabled()) {
-    // Configures mocking of classifications not when it was requested by test
-    // fixture, but when it is actually enabled - because for some platforms,
-    // url classification is enabled by default.
-    supervision_mixin_.api_mock_setup_mixin()
-        .api_mock()
-        .QueueAllowedUrlClassification();
-  }
-
-  GURL youtube_url(youtube_server_.GetURL("youtube.com", "/empty.html"));
-
-  EXPECT_CALL(*this, InterceptRequest())
-      .Times(::testing::AtLeast(1));  // Main request + favicon.
-
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
-  EXPECT_CALL(*this, InterceptYoutubeRestrictHeader(::testing::_))
-      .Times(::testing::AtLeast(1));
-#else
-  EXPECT_CALL(*this, InterceptYoutubeRestrictHeader(::testing::_)).Times(0);
-#endif
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), youtube_url));
-}
-
-// Instead of /0, /1... print human-readable description of the test.
-std::string PrettyPrintTestCaseName(
-    const ::testing::TestParamInfo<FilterWebsites>& info) {
-  return info.param ? "FilterWebsites" : "NoFilterWebsites";
-}
-
-INSTANTIATE_TEST_SUITE_P(All,
-                         YouTubeRestrictionsBrowserTest,
-                         ::testing::Values(FilterWebsites(true),
-                                           FilterWebsites(false)),
-                         &PrettyPrintTestCaseName);
-
-}  // namespace
diff --git a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabData.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabData.java
index b66685b..d745362 100644
--- a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabData.java
+++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/ShoppingPersistedTabData.java
@@ -183,6 +183,8 @@
         public String offerId;
         public GURL gurl;
         public boolean isCurrentPriceDropSeen;
+        public String productTitle;
+        public GURL productImageUrl;
 
         PriceDropData() {
             this.priceMicros = NO_PRICE_KNOWN;
@@ -634,6 +636,8 @@
             // Use UnsignedLongs to convert OfferId to avoid overflow.
             setMainOfferId(UnsignedLongs.toString(buyableProduct.getOfferId()));
             setPriceDropGurl(tab.getUrl());
+            setProductTitle(buyableProduct.getTitle());
+            setProductImageUrl(new GURL(buyableProduct.getImageUrl()));
             foundBuyableProduct = FoundBuyableProduct.FOUND_WITH_PRICE_UPDATE;
         }
 
@@ -702,6 +706,28 @@
     }
 
     @VisibleForTesting
+    protected void setProductTitle(String productTitle) {
+        mPriceDropData.productTitle = productTitle;
+        save();
+    }
+
+    @VisibleForTesting
+    protected String getProductTitle() {
+        return mPriceDropData.productTitle;
+    }
+
+    @VisibleForTesting
+    protected void setProductImageUrl(GURL imageUrl) {
+        mPriceDropData.productImageUrl = imageUrl;
+        save();
+    }
+
+    @VisibleForTesting
+    protected GURL getProductImageUrl() {
+        return mPriceDropData.productImageUrl;
+    }
+
+    @VisibleForTesting
     protected String getCurrencyCode() {
         return mPriceDropData.currencyCode;
     }
@@ -887,6 +913,14 @@
             builder.setSerializedGurl(mPriceDropData.gurl.serialize());
         }
 
+        if (mPriceDropData.productTitle != null) {
+            builder.setProductTitle(mPriceDropData.productTitle);
+        }
+
+        if (mPriceDropData.productImageUrl != null) {
+            builder.setProductImageUrl(mPriceDropData.productImageUrl.serialize());
+        }
+
         return () -> {
             return builder.build().toByteString().asReadOnlyByteBuffer();
         };
@@ -913,6 +947,9 @@
                     GURL.deserialize(shoppingPersistedTabDataProto.getSerializedGurl());
             mPriceDropData.isCurrentPriceDropSeen =
                     shoppingPersistedTabDataProto.getIsCurrentPriceDropSeen();
+            mPriceDropData.productTitle = shoppingPersistedTabDataProto.getProductTitle();
+            mPriceDropData.productImageUrl =
+                    GURL.deserialize(shoppingPersistedTabDataProto.getProductImageUrl());
             return true;
         } catch (InvalidProtocolBufferException e) {
             Log.e(TAG,
diff --git a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/proto/shopping_persisted_tab_data.proto b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/proto/shopping_persisted_tab_data.proto
index 333c1966..c35b6c59 100644
--- a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/proto/shopping_persisted_tab_data.proto
+++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/proto/shopping_persisted_tab_data.proto
@@ -34,4 +34,10 @@
 
   // Whether the user has seen the current price drop in the tab switcher grid.
   optional bool is_current_price_drop_seen = 8;
+
+  // The title of the product.
+  optional string product_title = 9;
+
+  // The gurl of the product image.
+  optional string product_image_url = 10;
 }
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
index 1f4544b..8ec144e 100644
--- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
+++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_unittest.cc
@@ -6692,7 +6692,7 @@
       std::make_unique<apps::Shortcut>("app_id", "local_id");
   apps::ShortcutId shortcut_id = shortcut->shortcut_id;
   shortcut->icon_key = apps::IconKey();
-  shortcut->icon_key->update_version = 100;
+  shortcut->icon_key->update_version = false;
 
   apps::StubIconLoader shortcut_stub_icon_loader;
   apps::StubIconLoader app_stub_icon_loader;
@@ -6729,8 +6729,9 @@
   // Verify icon update loads icon again.
   apps::ShortcutPtr delta =
       std::make_unique<apps::Shortcut>("app_id", "local_id");
-  delta->icon_key = apps::IconKey(1, 1);
-  delta->icon_key->update_version = 101;
+  delta->icon_key = apps::IconKey(apps::IconKey::kInvalidResourceId,
+                                  apps::IconEffects::kCrOsStandardIcon);
+  delta->icon_key->update_version = true;
   cache()->UpdateShortcut(std::move(delta));
 
   EXPECT_EQ(2, shortcut_stub_icon_loader.NumLoadIconFromIconKeyCalls());
@@ -6786,7 +6787,7 @@
   apps::ShortcutPtr same_shortcut =
       std::make_unique<apps::Shortcut>("app_id", "local_id");
   same_shortcut->icon_key = apps::IconKey();
-  same_shortcut->icon_key->update_version = 100;
+  same_shortcut->icon_key->update_version = false;
   cache()->UpdateShortcut(std::move(same_shortcut));
   // In this case icon loaded on shortcut creation.
   EXPECT_EQ(4, shortcut_stub_icon_loader.NumLoadIconFromIconKeyCalls());
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index ae055124..743f5c9 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -71,7 +71,7 @@
 #include "components/autofill/core/browser/payments/credit_card_risk_based_authenticator.h"
 #include "components/autofill/core/browser/payments/mandatory_reauth_manager.h"
 #include "components/autofill/core/browser/payments/offer_notification_options.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/ui/payments/bubble_show_options.h"
 #include "components/autofill/core/browser/ui/payments/card_unmask_prompt_controller_impl.h"
 #include "components/autofill/core/browser/ui/payments/card_unmask_prompt_view.h"
@@ -346,22 +346,24 @@
 FormDataImporter* ChromeAutofillClient::GetFormDataImporter() {
   if (!form_data_importer_) {
     form_data_importer_ = std::make_unique<FormDataImporter>(
-        this, GetPaymentsClient(), GetPersonalDataManager(),
+        this, GetPaymentsNetworkInterface(), GetPersonalDataManager(),
         GetPersonalDataManager()->app_locale());
   }
   return form_data_importer_.get();
 }
 
-payments::PaymentsClient* ChromeAutofillClient::GetPaymentsClient() {
-  if (!payments_client_) {
-    payments_client_ = std::make_unique<payments::PaymentsClient>(
-        Profile::FromBrowserContext(web_contents()->GetBrowserContext())
-            ->GetURLLoaderFactory(),
-        GetIdentityManager(), GetPersonalDataManager(),
-        Profile::FromBrowserContext(web_contents()->GetBrowserContext())
-            ->IsOffTheRecord());
+payments::PaymentsNetworkInterface*
+ChromeAutofillClient::GetPaymentsNetworkInterface() {
+  if (!payments_network_interface_) {
+    payments_network_interface_ =
+        std::make_unique<payments::PaymentsNetworkInterface>(
+            Profile::FromBrowserContext(web_contents()->GetBrowserContext())
+                ->GetURLLoaderFactory(),
+            GetIdentityManager(), GetPersonalDataManager(),
+            Profile::FromBrowserContext(web_contents()->GetBrowserContext())
+                ->IsOffTheRecord());
   }
-  return payments_client_.get();
+  return payments_network_interface_.get();
 }
 
 StrikeDatabase* ChromeAutofillClient::GetStrikeDatabase() {
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h
index 3264516..396e4f0 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.h
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -125,7 +125,7 @@
   syncer::SyncService* GetSyncService() override;
   signin::IdentityManager* GetIdentityManager() override;
   FormDataImporter* GetFormDataImporter() override;
-  payments::PaymentsClient* GetPaymentsClient() override;
+  payments::PaymentsNetworkInterface* GetPaymentsNetworkInterface() override;
   StrikeDatabase* GetStrikeDatabase() override;
   ukm::UkmRecorder* GetUkmRecorder() override;
   ukm::SourceId GetUkmSourceId() override;
@@ -340,7 +340,8 @@
   // These members are initialized lazily in their respective getters.
   // Therefore, do not access the members directly.
   std::unique_ptr<AutofillDownloadManager> download_manager_;
-  std::unique_ptr<payments::PaymentsClient> payments_client_;
+  std::unique_ptr<payments::PaymentsNetworkInterface>
+      payments_network_interface_;
   std::unique_ptr<CreditCardCvcAuthenticator> cvc_authenticator_;
   std::unique_ptr<CreditCardOtpAuthenticator> otp_authenticator_;
   std::unique_ptr<CreditCardRiskBasedAuthenticator> risk_based_authenticator_;
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index 7d579886..6fa2a2fd 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -648,9 +648,6 @@
     case IDC_SHOW_PASSWORD_MANAGER:
       ShowPasswordManager(browser_);
       break;
-    case IDC_SHOW_PASSWORD_CHECKUP:
-      ShowPasswordCheck(browser_);
-      break;
     case IDC_SHOW_PAYMENT_METHODS:
       ShowPaymentMethods(browser_);
       break;
diff --git a/chrome/browser/ui/browser_ui_prefs.cc b/chrome/browser/ui/browser_ui_prefs.cc
index 44a707d..95d3988 100644
--- a/chrome/browser/ui/browser_ui_prefs.cc
+++ b/chrome/browser/ui/browser_ui_prefs.cc
@@ -172,5 +172,6 @@
   registry->RegisterBooleanPref(prefs::kHttpsUpgradesEnabled, true);
 
   registry->RegisterDictionaryPref(prefs::kHttpsUpgradeFallbacks);
+  registry->RegisterDictionaryPref(prefs::kHttpsUpgradeNavigations);
   registry->RegisterBooleanPref(prefs::kHttpsOnlyModeAutoEnabled, false);
 }
diff --git a/chrome/browser/ui/global_media_controls/presentation_request_notification_producer.cc b/chrome/browser/ui/global_media_controls/presentation_request_notification_producer.cc
index 63cae73..b7260784 100644
--- a/chrome/browser/ui/global_media_controls/presentation_request_notification_producer.cc
+++ b/chrome/browser/ui/global_media_controls/presentation_request_notification_producer.cc
@@ -165,7 +165,9 @@
   // If there is a presentation, there would already be an item associated with
   // that, so `this` doesn't have to provide another item.
   if (has_presentation && provider_.is_bound()) {
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
     provider_->HideMediaUI();
+#endif
     provider_->HideItem();
   }
 }
diff --git a/chrome/browser/ui/login/login_handler.cc b/chrome/browser/ui/login/login_handler.cc
index 012f9c3..7c9963f 100644
--- a/chrome/browser/ui/login/login_handler.cc
+++ b/chrome/browser/ui/login/login_handler.cc
@@ -77,6 +77,13 @@
                             AUTH_PROMPT_TYPE_ENUM_COUNT);
 }
 
+// All login handlers should be tracked in this global singleton.
+using LoginHandlerVector = std::vector<base::WeakPtr<LoginHandler>>;
+LoginHandlerVector& GetAllLoginHandlers() {
+  static base::NoDestructor<LoginHandlerVector> instance;
+  return *instance;
+}
+
 }  // namespace
 
 // ----------------------------------------------------------------------------
@@ -90,6 +97,14 @@
 }
 
 LoginHandler::~LoginHandler() {
+  auto& login_handlers = GetAllLoginHandlers();
+  for (auto it = login_handlers.begin(); it != login_handlers.end(); ++it) {
+    if (it->get() == this) {
+      login_handlers.erase(it);
+      break;
+    }
+  }
+
   password_manager::HttpAuthManager* http_auth_manager =
       GetHttpAuthManagerForLogin();
   if (http_auth_manager)
@@ -103,6 +118,17 @@
   }
 }
 
+// static
+std::vector<LoginHandler*> LoginHandler::GetAllLoginHandlersForTest() {
+  std::vector<LoginHandler*> output;
+  for (auto& weak_ptr : GetAllLoginHandlers()) {
+    if (weak_ptr) {
+      output.push_back(weak_ptr.get());
+    }
+  }
+  return output;
+}
+
 void LoginHandler::StartMainFrame(
     const content::GlobalRequestID& request_id,
     const GURL& request_url,
@@ -131,16 +157,6 @@
     return;
   }
 
-  // This is OK; we break out of the Observe() if we aren't handling the same
-  // auth_info() or BrowserContext.
-  //
-  // TODO(davidben): Only listen to notifications within a single
-  // BrowserContext.
-  registrar_.Add(this, chrome::NOTIFICATION_AUTH_SUPPLIED,
-                 content::NotificationService::AllBrowserContextsAndSources());
-  registrar_.Add(this, chrome::NOTIFICATION_AUTH_CANCELLED,
-                 content::NotificationService::AllBrowserContextsAndSources());
-
   prompt_started_ = true;
   ShowLoginPrompt(request_url);
 }
@@ -208,65 +224,15 @@
   std::move(callback).Run(absl::nullopt);
 }
 
-void LoginHandler::Observe(int type,
-                           const content::NotificationSource& source,
-                           const content::NotificationDetails& details) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(type == chrome::NOTIFICATION_AUTH_SUPPLIED ||
-         type == chrome::NOTIFICATION_AUTH_CANCELLED);
-
-  // Break out early if we aren't interested in the notification.
-  if (!web_contents_ || WasAuthHandled())
-    return;
-
-  LoginNotificationDetails* login_details =
-      content::Details<LoginNotificationDetails>(details).ptr();
-
-  // WasAuthHandled() should always test positive before we publish
-  // AUTH_SUPPLIED or AUTH_CANCELLED notifications.
-  DCHECK(login_details->handler() != this);
-
-  // Only handle notification for the identical auth info. When comparing
-  // AuthChallengeInfos, ignore path because the same credentials can be used
-  // for different paths.
-  if (!auth_info().MatchesExceptPath(login_details->handler()->auth_info()))
-    return;
-
-  // Ignore login notification events from other StoragePartitions.
-  // TODO(crbug.com/1261928): Getting the StoragePartition from the WebContents
-  // is fine for now, but we'll need to plumb frame information to LoginHandler
-  // as part of removing the multi-WebContents architecture.
-  content::StoragePartition* source_partition =
-      login_details->handler()->web_contents() ? login_details->handler()
-                                                     ->web_contents()
-                                                     ->GetPrimaryMainFrame()
-                                                     ->GetStoragePartition()
-                                               : nullptr;
-  content::StoragePartition* partition =
-      web_contents()->GetPrimaryMainFrame()->GetStoragePartition();
-  if (!source_partition || source_partition != partition) {
-    return;
-  }
-
-  // Set or cancel the auth in this handler. Defer an event loop iteration to
-  // avoid potential reentrancy issues.
-  if (type == chrome::NOTIFICATION_AUTH_SUPPLIED) {
-    AuthSuppliedLoginNotificationDetails* supplied_details =
-        content::Details<AuthSuppliedLoginNotificationDetails>(details).ptr();
-    SetAuth(supplied_details->username(), supplied_details->password());
-  } else {
-    DCHECK(type == chrome::NOTIFICATION_AUTH_CANCELLED);
-    CancelAuth();
-  }
-}
-
 LoginHandler::LoginHandler(const net::AuthChallengeInfo& auth_info,
                            content::WebContents* web_contents,
                            LoginAuthRequiredCallback auth_required_callback)
     : web_contents_(web_contents->GetWeakPtr()),
       auth_info_(auth_info),
       auth_required_callback_(std::move(auth_required_callback)),
-      prompt_started_(false) {}
+      prompt_started_(false) {
+  GetAllLoginHandlers().push_back(weak_factory_.GetWeakPtr());
+}
 
 void LoginHandler::StartInternal(
     const content::GlobalRequestID& request_id,
@@ -333,6 +299,15 @@
   NavigationController* controller = &web_contents_->GetController();
   AuthSuppliedLoginNotificationDetails details(this, username, password);
 
+  // Intentionally make a copy to avoid issues with iterator invalidation.
+  LoginHandlerVector vec = GetAllLoginHandlers();
+  for (auto& weak_login_handler : vec) {
+    if (weak_login_handler && weak_login_handler.get() != this) {
+      weak_login_handler->OtherHandlerFinished(/*supplied=*/true, this,
+                                               username, password);
+    }
+  }
+
   service->Notify(
       chrome::NOTIFICATION_AUTH_SUPPLIED,
       content::Source<NavigationController>(controller),
@@ -346,6 +321,16 @@
   if (!prompt_started_)
     return;
 
+  // Intentionally make a copy to avoid issues with iterator invalidation.
+  LoginHandlerVector vec = GetAllLoginHandlers();
+  for (auto& weak_login_handler : vec) {
+    if (weak_login_handler && weak_login_handler.get() != this) {
+      weak_login_handler->OtherHandlerFinished(/*supplied=*/false, this,
+                                               /*username=*/std::u16string(),
+                                               /*password=*/std::u16string());
+    }
+  }
+
   content::NotificationService* service =
       content::NotificationService::current();
   NavigationController* controller =
@@ -356,6 +341,56 @@
                   content::Details<LoginNotificationDetails>(&details));
 }
 
+void LoginHandler::OtherHandlerFinished(bool supplied,
+                                        LoginHandler* other_handler,
+                                        const std::u16string& username,
+                                        const std::u16string& password) {
+  // Break out early if we aren't interested in the notification.
+  if (!web_contents_ || WasAuthHandled()) {
+    return;
+  }
+
+  // Only listen to notifications within a single BrowserContext.
+  if (other_handler->web_contents() &&
+      other_handler->web_contents()->GetBrowserContext() !=
+          web_contents_->GetBrowserContext()) {
+    return;
+  }
+
+  // We should never dispatch to self.
+  DCHECK(other_handler != this);
+
+  // Only handle notification for the identical auth info. When comparing
+  // AuthChallengeInfos, ignore path because the same credentials can be used
+  // for different paths.
+  if (!auth_info().MatchesExceptPath(other_handler->auth_info())) {
+    return;
+  }
+
+  // Ignore login notification events from other StoragePartitions.
+  // TODO(crbug.com/1261928): Getting the StoragePartition from the WebContents
+  // is fine for now, but we'll need to plumb frame information to LoginHandler
+  // as part of removing the multi-WebContents architecture.
+  content::StoragePartition* source_partition =
+      other_handler->web_contents() ? other_handler->web_contents()
+                                          ->GetPrimaryMainFrame()
+                                          ->GetStoragePartition()
+                                    : nullptr;
+  content::StoragePartition* partition =
+      web_contents()->GetPrimaryMainFrame()->GetStoragePartition();
+  if (!source_partition || source_partition != partition) {
+    return;
+  }
+
+  // Set or cancel the auth in this handler. Defer an event loop iteration to
+  // avoid potential reentrancy issues.
+  if (supplied) {
+    SetAuth(username, password);
+  } else {
+    CancelAuth();
+  }
+}
+
 password_manager::PasswordManagerClient*
 LoginHandler::GetPasswordManagerClientFromWebContent() {
   if (!web_contents_)
@@ -480,16 +515,6 @@
     return;
   }
 
-  // This is OK; we break out of the Observe() if we aren't handling the same
-  // auth_info() or BrowserContext.
-  //
-  // TODO(davidben): Only listen to notifications within a single
-  // BrowserContext.
-  registrar_.Add(this, chrome::NOTIFICATION_AUTH_SUPPLIED,
-                 content::NotificationService::AllBrowserContextsAndSources());
-  registrar_.Add(this, chrome::NOTIFICATION_AUTH_CANCELLED,
-                 content::NotificationService::AllBrowserContextsAndSources());
-
   // Always cancel main frame requests that receive auth challenges. An
   // interstitial will be committed as the result of the cancellation, and the
   // login prompt will be shown on top of it once the interstitial commits.
diff --git a/chrome/browser/ui/login/login_handler.h b/chrome/browser/ui/login/login_handler.h
index 779d481..d5ac22b3 100644
--- a/chrome/browser/ui/login/login_handler.h
+++ b/chrome/browser/ui/login/login_handler.h
@@ -30,8 +30,7 @@
 
 // This is the base implementation for the OS-specific classes that prompt for
 // authentication information.
-class LoginHandler : public content::LoginDelegate,
-                     public content::NotificationObserver {
+class LoginHandler : public content::LoginDelegate {
  public:
   // The purpose of this struct is to enforce that BuildViewImpl receives either
   // both the login model and the observed form, or none. That is a bit spoiled
@@ -59,6 +58,9 @@
       content::WebContents* web_contents,
       LoginAuthRequiredCallback auth_required_callback);
 
+  // Exposed for testing.
+  static std::vector<LoginHandler*> GetAllLoginHandlersForTest();
+
   // The main entry point for an auth request for a main-frame request. This
   // method allows extensions to handle the auth request, and otherwise cancels
   // the request to show a blank error page. ShowLoginPromptAfterCommit() can be
@@ -92,14 +94,6 @@
   // This function can be called from either thread.
   void CancelAuth();
 
-  // Implements the content::NotificationObserver interface.
-  // Listens for AUTH_SUPPLIED and AUTH_CANCELLED notifications from other
-  // LoginHandlers so that this LoginHandler has the chance to dismiss itself
-  // if it was waiting for the same authentication.
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
   // Who/where/what asked for the authentication.
   const net::AuthChallengeInfo& auth_info() const { return auth_info_; }
 
@@ -139,6 +133,15 @@
   // Notify observers that authentication is cancelled.
   void NotifyAuthCancelled();
 
+  // When any handler finishes, called on every other handler. |username| and
+  // |password| are only valid if |supplied| is true. If |supplied| is false
+  // then the handler was cancelled. This gives |this| handler the opportunity
+  // to dismiss itself if it was waiting for the same authentication.
+  void OtherHandlerFinished(bool supplied,
+                            LoginHandler* other_handler,
+                            const std::u16string& username,
+                            const std::u16string& password);
+
   // Returns the PasswordManagerClient from the web content.
   password_manager::PasswordManagerClient*
   GetPasswordManagerClientFromWebContent();
diff --git a/chrome/browser/ui/page_info/chrome_page_info_delegate.cc b/chrome/browser/ui/page_info/chrome_page_info_delegate.cc
index 49354be..ccc3b64 100644
--- a/chrome/browser/ui/page_info/chrome_page_info_delegate.cc
+++ b/chrome/browser/ui/page_info/chrome_page_info_delegate.cc
@@ -26,6 +26,7 @@
 #include "chrome/browser/usb/usb_chooser_context.h"
 #include "chrome/browser/usb/usb_chooser_context_factory.h"
 #include "chrome/browser/vr/vr_tab_helper.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "components/content_settings/browser/page_specific_content_settings.h"
@@ -417,7 +418,14 @@
 #endif
 
 bool ChromePageInfoDelegate::IsHttpsFirstModeEnabled() {
-  return GetProfile()->GetPrefs()->GetBoolean(prefs::kHttpsOnlyModeEnabled);
+  bool https_first_mode_fully_enabled =
+      GetProfile()->GetPrefs()->GetBoolean(prefs::kHttpsOnlyModeEnabled);
+  bool https_first_mode_enabled_in_incognito =
+      base::FeatureList::IsEnabled(features::kHttpsFirstModeIncognito) &&
+      GetProfile()->GetPrefs()->GetBoolean(prefs::kHttpsFirstModeIncognito);
+  return https_first_mode_fully_enabled ||
+         (GetProfile()->IsIncognitoProfile() &&
+          https_first_mode_enabled_in_incognito);
 }
 
 void ChromePageInfoDelegate::SetSecurityStateForTests(
diff --git a/chrome/browser/ui/safety_hub/menu_notification_service.cc b/chrome/browser/ui/safety_hub/menu_notification_service.cc
index 75b5c18e..3aa54fd 100644
--- a/chrome/browser/ui/safety_hub/menu_notification_service.cc
+++ b/chrome/browser/ui/safety_hub/menu_notification_service.cc
@@ -222,22 +222,3 @@
       ->notification->ResetAllTimeNotificationCount();
   SaveNotificationsToPrefs();
 }
-
-void SafetyHubMenuNotificationService::DismissActiveNotification() {
-  for (auto const& item : module_info_map_) {
-    if (item.second->notification->IsCurrentlyActive()) {
-      item.second->notification->Dismiss();
-    }
-  }
-}
-
-void SafetyHubMenuNotificationService::DismissPasswordNotification() {
-  // TODO(crbug.com/1443466): Uncomment the following lines in
-  // crrev.com/c/4982626.
-  // SafetyHubMenuNotification* notification =
-  //     module_info_map_.at(safety_hub::SafetyHubModuleType::PASSWORDS)
-  //         ->notification.get();
-  // if (notification->IsCurrentlyActive()) {
-  //   notification->Dismiss();
-  // }
-}
diff --git a/chrome/browser/ui/safety_hub/menu_notification_service.h b/chrome/browser/ui/safety_hub/menu_notification_service.h
index f57423b..42b945b 100644
--- a/chrome/browser/ui/safety_hub/menu_notification_service.h
+++ b/chrome/browser/ui/safety_hub/menu_notification_service.h
@@ -83,12 +83,6 @@
   // returned.
   absl::optional<MenuNotificationEntry> GetNotificationToShow();
 
-  // Dismisses all the active menu notifications.
-  void DismissActiveNotification();
-
-  // Dismisses the active menu notification of the password module.
-  void DismissPasswordNotification();
-
   // Returns the |service_info_map_|. For testing purposes only.
   SafetyHubMenuNotification* GetNotificationForTesting(
       safety_hub::SafetyHubModuleType service_type);
diff --git a/chrome/browser/ui/safety_hub/menu_notification_service_unittest.cc b/chrome/browser/ui/safety_hub/menu_notification_service_unittest.cc
index 7ea2ab0..33f592c9 100644
--- a/chrome/browser/ui/safety_hub/menu_notification_service_unittest.cc
+++ b/chrome/browser/ui/safety_hub/menu_notification_service_unittest.cc
@@ -450,21 +450,3 @@
   notification = menu_notification_service()->GetNotificationToShow();
   EXPECT_FALSE(notification.has_value());
 }
-
-TEST_F(SafetyHubMenuNotificationServiceTest, DismissNotifications) {
-  // Generate a mock notification for unused site permissions.
-  CreateMockUnusedSitePermissionsEntry();
-  absl::optional<MenuNotificationEntry> notification =
-      menu_notification_service()->GetNotificationToShow();
-  EXPECT_TRUE(notification.has_value());
-  ExpectPluralString(
-      IDS_SETTINGS_SAFETY_HUB_UNUSED_SITE_PERMISSIONS_MENU_NOTIFICATION, 1,
-      notification.value().label);
-
-  // When all notifications are dismissed, there should be no more notification.
-  menu_notification_service()->DismissActiveNotification();
-  EXPECT_FALSE(
-      menu_notification_service()->GetNotificationToShow().has_value());
-
-  // TODO(crbug.com/1443466): Add test for DismissPasswordNotification().
-}
diff --git a/chrome/browser/ui/safety_hub/password_status_check_result.cc b/chrome/browser/ui/safety_hub/password_status_check_result.cc
index ab4e5b1..ffa7cb3 100644
--- a/chrome/browser/ui/safety_hub/password_status_check_result.cc
+++ b/chrome/browser/ui/safety_hub/password_status_check_result.cc
@@ -67,5 +67,5 @@
 }
 
 int PasswordStatusCheckResult::GetNotificationCommandId() const {
-  return IDC_SHOW_PASSWORD_CHECKUP;
+  return IDC_SHOW_PASSWORD_MANAGER;
 }
diff --git a/chrome/browser/ui/tabs/organization/tab_data.cc b/chrome/browser/ui/tabs/organization/tab_data.cc
index a159c968..de3ca21 100644
--- a/chrome/browser/ui/tabs/organization/tab_data.cc
+++ b/chrome/browser/ui/tabs/organization/tab_data.cc
@@ -56,6 +56,11 @@
     return false;
   }
 
+  // All non http(s) schemes are invalid.
+  if (!original_url_.SchemeIsHTTPOrHTTPS()) {
+    return false;
+  }
+
   if (original_tab_strip_model_
           ->GetTabGroupForTab(
               original_tab_strip_model_->GetIndexOfWebContents(web_contents_))
diff --git a/chrome/browser/ui/tabs/organization/tab_organization_service_unittest.cc b/chrome/browser/ui/tabs/organization/tab_organization_service_unittest.cc
index fa95ce5e4..d4184bf8 100644
--- a/chrome/browser/ui/tabs/organization/tab_organization_service_unittest.cc
+++ b/chrome/browser/ui/tabs/organization/tab_organization_service_unittest.cc
@@ -20,6 +20,13 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/page_transition_types.h"
 
+namespace {
+
+constexpr char kValidURL[] = "http://zombo.com";
+constexpr char kInvalidURL[] = "chrome://page";
+
+}  // anonymous namespace
+
 class TabOrganizationServiceTest : public BrowserWithTestWindowTest {
  public:
   TabOrganizationServiceTest() = default;
@@ -41,6 +48,8 @@
     std::unique_ptr<content::WebContents> web_contents =
         content::WebContentsTester::CreateTestWebContents(profile_.get(),
                                                           nullptr);
+    content::WebContentsTester::For(web_contents.get())
+        ->NavigateAndCommit(GURL(kValidURL));
 
     content::WebContents* web_contents_ptr = web_contents.get();
 
@@ -161,6 +170,36 @@
   EXPECT_EQ(session->tab_organizations().size(), 1u);
 
   TabOrganization* organization = session->GetNextTabOrganization();
+  ASSERT_TRUE(organization);
+
+  organization->Accept();
+  EXPECT_EQ(browser1->tab_strip_model()->group_model()->ListTabGroups().size(),
+            1u);
+}
+
+TEST_F(TabOrganizationServiceTest,
+       TabOrganizationSessionCreateSessionForBrowserNoInvalidTabDatas) {
+  const int valid_tab_count = 2;
+  Browser* browser1 = AddBrowser();
+  for (int i = 0; i < valid_tab_count; i++) {
+    AddTabToBrowser(browser1, 0);
+  }
+
+  // Add an invalid tab.
+  content::WebContents* invalid_web_contents = AddTabToBrowser(browser1, 0);
+  content::WebContentsTester::For(invalid_web_contents)
+      ->NavigateAndCommit(GURL(kInvalidURL));
+
+  std::unique_ptr<TabOrganizationSession> session =
+      TabOrganizationSession::CreateSessionForBrowser(browser1, service());
+  EXPECT_EQ(static_cast<int>(session->request()->tab_datas().size()),
+            valid_tab_count);
+
+  session->StartRequest();
+  EXPECT_NE(session->request()->response(), nullptr);
+  EXPECT_EQ(session->tab_organizations().size(), 1u);
+
+  TabOrganization* organization = session->GetNextTabOrganization();
   EXPECT_TRUE(organization);
 
   organization->Accept();
diff --git a/chrome/browser/ui/tabs/organization/tab_organization_session.cc b/chrome/browser/ui/tabs/organization/tab_organization_session.cc
index fa426855..0422ba0 100644
--- a/chrome/browser/ui/tabs/organization/tab_organization_session.cc
+++ b/chrome/browser/ui/tabs/organization/tab_organization_session.cc
@@ -51,8 +51,13 @@
   std::vector<std::unique_ptr<TabData>> tab_datas;
   TabStripModel* tab_strip_model = browser->tab_strip_model();
   for (int index = 0; index < tab_strip_model->count(); index++) {
-    request->AddTabData(std::make_unique<TabData>(
-        tab_strip_model, tab_strip_model->GetWebContentsAt(index)));
+    std::unique_ptr<TabData> tab_data = std::make_unique<TabData>(
+        tab_strip_model, tab_strip_model->GetWebContentsAt(index));
+    if (!tab_data->IsValidForOrganizing()) {
+      continue;
+    }
+
+    request->AddTabData(std::move(tab_data));
   }
 
   return std::make_unique<TabOrganizationSession>(service, std::move(request));
diff --git a/chrome/browser/ui/tabs/organization/tab_organization_unittest.cc b/chrome/browser/ui/tabs/organization/tab_organization_unittest.cc
index f815d90..a196afb 100644
--- a/chrome/browser/ui/tabs/organization/tab_organization_unittest.cc
+++ b/chrome/browser/ui/tabs/organization/tab_organization_unittest.cc
@@ -50,16 +50,17 @@
 
   GURL GetUniqueTestURL() {
     static int offset = 1;
-    GURL url("chrome://page_" + base::NumberToString(offset));
+    GURL url("http://page_" + base::NumberToString(offset));
     offset++;
     return url;
   }
 
-  content::WebContents* AddTab(TabStripModel* tab_strip_model = nullptr) {
+  content::WebContents* AddTab(TabStripModel* tab_strip_model = nullptr,
+                               absl::optional<GURL> url = absl::nullopt) {
     std::unique_ptr<content::WebContents> contents_unique_ptr =
         CreateWebContents();
     content::WebContentsTester::For(contents_unique_ptr.get())
-        ->NavigateAndCommit(GURL(GetUniqueTestURL()));
+        ->NavigateAndCommit(url.has_value() ? url.value() : GetUniqueTestURL());
     content::WebContents* content_ptr = contents_unique_ptr.get();
     if (!tab_strip_model) {
       tab_strip_model = tab_strip_model_.get();
@@ -283,6 +284,33 @@
   EXPECT_EQ(observer.update_call_count, 2);
 }
 
+TEST_F(TabOrganizationTest, TabDataHttpHttpsOnlyURLs) {
+  {
+    content::WebContents* web_contents =
+        AddTab(tab_strip_model(), GURL("http://zombo.com"));
+    TabData tab_data(tab_strip_model(), web_contents);
+    EXPECT_TRUE(tab_data.IsValidForOrganizing());
+  }
+  {
+    content::WebContents* web_contents =
+        AddTab(tab_strip_model(), GURL("https://zombo.com"));
+    TabData tab_data(tab_strip_model(), web_contents);
+    EXPECT_TRUE(tab_data.IsValidForOrganizing());
+  }
+  {
+    content::WebContents* web_contents =
+        AddTab(tab_strip_model(), GURL("chrome://page"));
+    TabData tab_data(tab_strip_model(), web_contents);
+    EXPECT_FALSE(tab_data.IsValidForOrganizing());
+  }
+  {
+    content::WebContents* web_contents =
+        AddTab(tab_strip_model(), GURL("file://dangerous_file.exe"));
+    TabData tab_data(tab_strip_model(), web_contents);
+    EXPECT_FALSE(tab_data.IsValidForOrganizing());
+  }
+}
+
 // TabOrganization tests.
 
 TEST_F(TabOrganizationTest, TabOrganizationIDs) {
diff --git a/chrome/browser/ui/views/autofill/payments/local_card_migration_uitest.cc b/chrome/browser/ui/views/autofill/payments/local_card_migration_uitest.cc
index dcd5a356..d278e13 100644
--- a/chrome/browser/ui/views/autofill/payments/local_card_migration_uitest.cc
+++ b/chrome/browser/ui/views/autofill/payments/local_card_migration_uitest.cc
@@ -199,14 +199,14 @@
     ASSERT_TRUE(SetupClients());
     chrome::NewTab(GetBrowser(0));
 
-    // Set up the URL loader factory for the payments client so we can intercept
-    // those network requests too.
+    // Set up the URL loader factory for the PaymentsNetworkInterface so we can
+    // intercept those network requests too.
     test_shared_loader_factory_ =
         base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
             &test_url_loader_factory_);
     ContentAutofillClient* client =
         ContentAutofillClient::FromWebContents(GetActiveWebContents());
-    client->GetPaymentsClient()->set_url_loader_factory_for_testing(
+    client->GetPaymentsNetworkInterface()->set_url_loader_factory_for_testing(
         test_shared_loader_factory_);
 
     // Set up this class as the ObserverForTest implementation.
diff --git a/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc b/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc
index ebc4ae3..93efbbc4 100644
--- a/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc
+++ b/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc
@@ -51,7 +51,7 @@
 #include "components/autofill/core/browser/metrics/payments/credit_card_save_metrics.h"
 #include "components/autofill/core/browser/metrics/payments/manage_cards_prompt_metrics.h"
 #include "components/autofill/core/browser/payments/credit_card_save_manager.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/strike_databases/payments/credit_card_save_strike_database.h"
 #include "components/autofill/core/browser/test_autofill_clock.h"
@@ -203,14 +203,14 @@
     // that this method starts observing will also be the one to notify later.
     AddBlankTabAndShow(GetBrowser(0));
 
-    // Set up the URL loader factory for the payments client so we can intercept
-    // those network requests too.
+    // Set up the URL loader factory for the PaymentsNetworkInterface so we can
+    // intercept those network requests too.
     test_shared_loader_factory_ =
         base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
             &test_url_loader_factory_);
     autofill_manager()
         ->client()
-        .GetPaymentsClient()
+        .GetPaymentsNetworkInterface()
         ->set_url_loader_factory_for_testing(test_shared_loader_factory_);
 
     // Wait for Personal Data Manager to be fully loaded to prevent that
diff --git a/chrome/browser/ui/views/find_bar_view.cc b/chrome/browser/ui/views/find_bar_view.cc
index cb162fa..b80f890 100644
--- a/chrome/browser/ui/views/find_bar_view.cc
+++ b/chrome/browser/ui/views/find_bar_view.cc
@@ -41,6 +41,7 @@
 #include "ui/events/event.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/paint_vector_icon.h"
+#include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/background.h"
 #include "ui/views/border.h"
 #include "ui/views/bubble/bubble_border.h"
@@ -106,14 +107,17 @@
       return;
 
     last_result_ = result;
+    // TODO(1499078): Get NO_RESULTS to be announced under Orca and ChromeVox.
     SetText(l10n_util::GetStringFUTF16(
         IDS_FIND_IN_PAGE_COUNT,
         base::FormatNumber(last_result_->active_match_ordinal()),
         base::FormatNumber(last_result_->number_of_matches())));
 
     if (last_result_->final_update()) {
-      NotifyAccessibilityEvent(ax::mojom::Event::kLiveRegionChanged,
-                               /* send_native_event = */ true);
+      ui::AXNodeData node_data;
+      GetAccessibleNodeData(&node_data);
+      GetViewAccessibility().AnnouncePolitely(
+          node_data.GetString16Attribute(ax::mojom::StringAttribute::kName));
     }
   }
 
diff --git a/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc b/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
index b87a559..40070f2 100644
--- a/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
+++ b/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
@@ -440,11 +440,9 @@
   EXPECT_EQ(u"a", GetFindBarSelectedText());
 
   // Open another tab (tab B).
-  content::WindowedNotificationObserver observer(
-      content::NOTIFICATION_LOAD_STOP,
-      content::NotificationService::AllSources());
-  chrome::AddSelectedTabWithURL(browser(), url, ui::PAGE_TRANSITION_TYPED);
-  observer.Wait();
+  auto* const contents =
+      chrome::AddSelectedTabWithURL(browser(), url, ui::PAGE_TRANSITION_TYPED);
+  content::WaitForLoadStop(contents);
 
   // Make sure Find box is open.
   chrome::Find(browser());
@@ -485,11 +483,9 @@
   chrome::Find(browser());
   EXPECT_TRUE(IsViewFocused(browser(), VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
 
-  content::WindowedNotificationObserver observer(
-      content::NOTIFICATION_LOAD_STOP,
-      content::NotificationService::AllSources());
-  chrome::AddSelectedTabWithURL(browser(), url, ui::PAGE_TRANSITION_TYPED);
-  observer.Wait();
+  auto* contents =
+      chrome::AddSelectedTabWithURL(browser(), url, ui::PAGE_TRANSITION_TYPED);
+  content::WaitForLoadStop(contents);
 
   // Make sure Find box is not open when starting the new tab.
   EXPECT_FALSE(IsViewFocused(browser(), VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index b5eda573..0bb18e75 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -58,9 +58,6 @@
 #include "components/tab_groups/tab_group_color.h"
 #include "components/tab_groups/tab_group_id.h"
 #include "components/tab_groups/tab_group_visual_data.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_types.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
@@ -328,12 +325,9 @@
                                                    int additional_tabs,
                                                    const GURL& url) {
   for (int i = 0; i < additional_tabs; i++) {
-    content::WindowedNotificationObserver observer(
-        content::NOTIFICATION_LOAD_STOP,
-        content::NotificationService::AllSources());
-    chrome::AddSelectedTabWithURL(browser, url,
-                                  ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
-    observer.Wait();
+    auto* contents = chrome::AddSelectedTabWithURL(
+        browser, url, ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
+    content::WaitForLoadStop(contents);
   }
   browser->window()->Show();
   StopAnimating(GetTabStripForBrowser(browser));
@@ -3455,14 +3449,16 @@
 namespace {
 
 // Invoked from the nested run loop.
-void CancelOnNewTabWhenDraggingStep2(
-    DetachToBrowserTabDragControllerTest* test,
-    const BrowserList* browser_list) {
+void CancelOnNewTabWhenDraggingStep2(DetachToBrowserTabDragControllerTest* test,
+                                     const BrowserList* browser_list,
+                                     base::OnceClosure quit_closure,
+                                     WebContents** contents_out) {
   ASSERT_TRUE(TabDragController::IsActive());
   ASSERT_EQ(2u, browser_list->size());
 
-  chrome::AddTabAt(browser_list->GetLastActive(), GURL(url::kAboutBlankURL),
-                   0, false);
+  *contents_out = chrome::AddAndReturnTabAt(
+      browser_list->GetLastActive(), GURL(url::kAboutBlankURL), 0, false);
+  std::move(quit_closure).Run();
 }
 
 }  // namespace
@@ -3480,16 +3476,20 @@
       GetCenterInScreenCoordinates(tab_strip->tab_at(0));
   ASSERT_TRUE(PressInput(tab_0_center));
 
+  base::RunLoop run_loop;
+  auto quit_closure = run_loop.QuitClosure();
+  WebContents* web_contents = nullptr;
   // Add another tab. This should trigger exiting the nested loop. Add at the
   // beginning to exercise past crash when model/tabstrip got out of sync.
   // crbug.com/474082
-  content::WindowedNotificationObserver observer(
-      content::NOTIFICATION_LOAD_STOP,
-      content::NotificationService::AllSources());
   ASSERT_TRUE(DragInputToNotifyWhenDone(
       tab_0_center + gfx::Vector2d(0, GetDetachY(tab_strip)),
-      base::BindOnce(&CancelOnNewTabWhenDraggingStep2, this, browser_list)));
-  observer.Wait();
+      base::BindOnce(&CancelOnNewTabWhenDraggingStep2, this, browser_list,
+                     std::move(quit_closure),
+                     base::Unretained(&web_contents))));
+  run_loop.Run();
+  ASSERT_TRUE(!!web_contents);
+  content::WaitForLoadStop(web_contents);
 
   // Should be two windows and not dragging.
   ASSERT_FALSE(tab_strip->GetDragContext()->IsDragSessionActive());
diff --git a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
index 4d388ad1..a78cb41 100644
--- a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
+++ b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
@@ -212,8 +212,9 @@
     (BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX))
     int message_id = IDS_APP_MENU_BUTTON_UPDATE;
     if (base::FeatureList::IsEnabled(features::kUpdateTextOptions)) {
-      // Choose an update text option randomly.
-      int update_text_option = base::RandInt(1, 3);
+      // Select an update text option randomly. Show this text in all browser
+      // windows.
+      static const int update_text_option = base::RandInt(1, 3);
       if (update_text_option == 1) {
         message_id = IDS_APP_MENU_BUTTON_UPDATE_ALT1;
       } else if (update_text_option == 2) {
diff --git a/chrome/browser/ui/webui/app_management/app_management_page_handler.cc b/chrome/browser/ui/webui/app_management/app_management_page_handler.cc
index 24dbdb8c..3b2ccda 100644
--- a/chrome/browser/ui/webui/app_management/app_management_page_handler.cc
+++ b/chrome/browser/ui/webui/app_management/app_management_page_handler.cc
@@ -26,6 +26,7 @@
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/apps/link_capturing/link_capturing_features.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/locks/all_apps_lock.h"
@@ -66,6 +67,7 @@
 #include "url/origin.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/components/arc/arc_features.h"
 #include "ash/components/arc/session/connection_holder.h"
 #include "chrome/browser/ash/app_list/arc/arc_app_utils.h"
 #include "chrome/browser/ash/apps/apk_web_app_service.h"
@@ -100,6 +102,32 @@
 constexpr char const* kAppIdsWithHiddenStoragePermission[] = {
     arc::kPlayStoreAppId,
 };
+
+// In ICU library, undefined locale is treated as unknown language (ICU-20273).
+const char kUndefinedTranslatedLocaleName[] = "und";
+
+app_management::mojom::LocalePtr CreateLocaleForTag(
+    const std::string& locale_tag,
+    const std::string& system_locale) {
+  const std::string display_name =
+      base::UTF16ToUTF8(l10n_util::GetDisplayNameForLocale(
+          locale_tag, system_locale, /*is_for_ui=*/true));
+  const std::string native_display_name = base::UTF16ToUTF8(
+      l10n_util::GetDisplayNameForLocale(locale_tag, locale_tag,
+                                         /*is_for_ui=*/true));
+
+  // In Android, it's possible for Apps to set custom locale tag, hence these
+  // locales might be untranslatable (based on ICU-20273).
+  // In this case, we'll pass empty string and let the UI decides what to
+  // display. For ARC, we'll display the `locale_tag` as is (relying on
+  // Polymer to escape possible HTML tags).
+  return app_management::mojom::Locale::New(
+      locale_tag,
+      display_name == kUndefinedTranslatedLocaleName ? "" : display_name,
+      native_display_name == kUndefinedTranslatedLocaleName
+          ? ""
+          : native_display_name);
+}
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 app_management::mojom::ExtensionAppPermissionMessagePtr
@@ -608,6 +636,21 @@
                               : OptionalBool::kFalse;
   app->resize_locked = update.ResizeLocked().value_or(false);
   app->hide_resize_locked = !update.ResizeLocked().has_value();
+
+  if (base::FeatureList::IsEnabled(arc::kPerAppLanguage)) {
+    const std::string& system_locale =
+        g_browser_process->GetApplicationLocale();
+    // Translate supported locales.
+    for (const std::string& locale_tag : update.SupportedLocales()) {
+      app->supported_locales.push_back(
+          CreateLocaleForTag(locale_tag, system_locale));
+    }
+    // Translate selected locale.
+    std::optional<std::string> locale_tag = update.SelectedLocale();
+    if (locale_tag.has_value()) {
+      app->selected_locale = CreateLocaleForTag(*locale_tag, system_locale);
+    }
+  }
 #endif
 #if BUILDFLAG(IS_CHROMEOS)
   app->is_preferred_app = apps::AppServiceProxyFactory::GetForProfile(profile_)
diff --git a/chrome/browser/ui/webui/ash/settings/pages/multidevice/multidevice_section.cc b/chrome/browser/ui/webui/ash/settings/pages/multidevice/multidevice_section.cc
index ec26c32e..715014c 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/multidevice/multidevice_section.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/multidevice/multidevice_section.cc
@@ -749,9 +749,8 @@
 
   // Nearby Share, registered regardless of the flag.
   generator->RegisterTopLevelSubpage(
-      ::features::IsNameEnabled() ? IDS_SETTINGS_NEARBY_SHARE_TITLE_PH
-                                  : IDS_SETTINGS_NEARBY_SHARE_TITLE,
-      mojom::Subpage::kNearbyShare, mojom::SearchResultIcon::kNearbyShare,
+      IDS_SETTINGS_NEARBY_SHARE_TITLE, mojom::Subpage::kNearbyShare,
+      mojom::SearchResultIcon::kNearbyShare,
       mojom::SearchResultDefaultRank::kMedium, mojom::kNearbyShareSubpagePath);
   static constexpr mojom::Setting kNearbyShareSettings[] = {
       mojom::Setting::kNearbyShareOnOff,
diff --git a/chrome/browser/ui/webui/nearby_share/shared_resources.cc b/chrome/browser/ui/webui/nearby_share/shared_resources.cc
index 2ee143a..9e25b29 100644
--- a/chrome/browser/ui/webui/nearby_share/shared_resources.cc
+++ b/chrome/browser/ui/webui/nearby_share/shared_resources.cc
@@ -9,8 +9,6 @@
 #include "base/containers/span.h"
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/nearby_sharing/common/nearby_share_features.h"
-#include "chrome/browser/nearby_sharing/common/nearby_share_resource_getter.h"
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
@@ -42,6 +40,8 @@
        IDS_NEARBY_CONTACT_VISIBILITY_DOWNLOAD_FAILED},
       {"nearbyShareContactVisibilityDownloading",
        IDS_NEARBY_CONTACT_VISIBILITY_DOWNLOADING},
+      {"nearbyShareContactVisibilityNoContactsSubtitle",
+       IDS_NEARBY_CONTACT_VISIBILITY_NO_CONTACTS_SUBTITLE},
       {"nearbyShareContactVisibilityNoContactsTitle",
        IDS_NEARBY_CONTACT_VISIBILITY_NO_CONTACTS_TITLE},
       {"nearbyShareContactVisibilityNone", IDS_NEARBY_VISIBLITY_HIDDEN},
@@ -80,6 +80,7 @@
       {"nearbyShareDiscoveryPagePlaceholder",
        IDS_NEARBY_DISCOVERY_PAGE_PLACEHOLDER},
       {"nearbyShareDiscoveryPageSubtitle", IDS_NEARBY_DISCOVERY_PAGE_SUBTITLE},
+      {"nearbyShareDiscoveryPageTitle", IDS_NEARBY_DISCOVERY_PAGE_TITLE},
       {"nearbyShareErrorCancelled", IDS_NEARBY_ERROR_CANCELLED},
       {"nearbyShareErrorCantReceive", IDS_NEARBY_ERROR_CANT_RECEIVE},
       {"nearbyShareErrorCantShare", IDS_NEARBY_ERROR_CANT_SHARE},
@@ -93,6 +94,7 @@
       {"nearbyShareErrorTryAgain", IDS_NEARBY_ERROR_TRY_AGAIN},
       {"nearbyShareErrorUnsupportedFileType",
        IDS_NEARBY_ERROR_UNSUPPORTED_FILE_TYPE},
+      {"nearbyShareFeatureName", IDS_NEARBY_SHARE_FEATURE_NAME},
       {"nearbyShareOnboardingPageDeviceName",
        IDS_NEARBY_ONBOARDING_PAGE_DEVICE_NAME},
       {"nearbyShareOnboardingPageDeviceNameHelp",
@@ -103,11 +105,14 @@
        IDS_NEARBY_ONBOARDING_PAGE_DEVICE_VISIBILITY_HELP_ALL_CONTACTS},
       {"nearbyShareOnboardingPageSubtitle",
        IDS_NEARBY_ONBOARDING_PAGE_SUBTITLE},
+      {"nearbyShareOnboardingPageTitle", IDS_NEARBY_ONBOARDING_PAGE_TITLE},
       {"nearbySharePreviewMultipleFileTitle",
        IDS_NEARBY_PREVIEW_TITLE_MULTIPLE_FILE},
       {"nearbyShareSecureConnectionId", IDS_NEARBY_SECURE_CONNECTION_ID},
       {"nearbyShareSettingsHelpCaptionBottom",
        IDS_NEARBY_SETTINGS_HELP_CAPTION_BOTTOM},
+      {"nearbyShareSettingsHelpCaptionTop",
+       IDS_NEARBY_SETTINGS_HELP_CAPTION_TOP},
       {"nearbyShareVisibilityPageManageContacts",
        IDS_NEARBY_VISIBILITY_PAGE_MANAGE_CONTACTS},
       {"nearbyShareVisibilityPageSubtitle",
@@ -129,6 +134,8 @@
        IDS_NEARBY_RECEIVE_CONFIRM_PAGE_CONNECTION_ID},
       {"nearbyShareErrorNoConnectionMedium",
        IDS_NEARBY_HIGH_VISIBILITY_CONNECTION_MEDIUM_ERROR},
+      {"nearbyShareErrorNoConnectionMediumDescription",
+       IDS_NEARBY_HIGH_VISIBILITY_CONNECTION_MEDIUM_DESCRIPTION},
       {"nearbyShareErrorTransferInProgressTitle",
        IDS_NEARBY_HIGH_VISIBILITY_TRANSFER_IN_PROGRESS_ERROR},
       {"nearbyShareErrorTransferInProgressDescription",
@@ -140,43 +147,4 @@
 
   data_source->AddString("nearbyShareManageContactsUrl",
                          chrome::kNearbyShareManageContactsURL);
-
-  if (features::IsNameEnabled()) {
-    static constexpr webui::LocalizedString kLocalizedPlaceholderStringPairs[] =
-        {
-            {"nearbyShareContactVisibilityNoContactsSubtitle",
-             IDS_NEARBY_CONTACT_VISIBILITY_NO_CONTACTS_SUBTITLE_PH},
-            {"nearbyShareDiscoveryPageTitle",
-             IDS_NEARBY_DISCOVERY_PAGE_TITLE_PH},
-            {"nearbyShareOnboardingPageTitle",
-             IDS_NEARBY_ONBOARDING_PAGE_TITLE_PH},
-            {"nearbyShareFeatureName", IDS_NEARBY_SHARE_FEATURE_NAME_PH},
-            {"nearbyShareErrorNoConnectionMediumDescription",
-             IDS_NEARBY_HIGH_VISIBILITY_CONNECTION_MEDIUM_DESCRIPTION_PH},
-            {"nearbyShareSettingsHelpCaptionTop",
-             IDS_NEARBY_SETTINGS_HELP_CAPTION_TOP_PH},
-        };
-
-    for (const webui::LocalizedString string_pair :
-         kLocalizedPlaceholderStringPairs) {
-      data_source->AddString(
-          string_pair.name,
-          NearbyShareResourceGetter::GetInstance()->GetStringWithFeatureName(
-              string_pair.id));
-    }
-  } else {
-    static constexpr webui::LocalizedString kLocalizedStringPairs[] = {
-        {"nearbyShareContactVisibilityNoContactsSubtitle",
-         IDS_NEARBY_CONTACT_VISIBILITY_NO_CONTACTS_SUBTITLE},
-        {"nearbyShareDiscoveryPageTitle", IDS_NEARBY_DISCOVERY_PAGE_TITLE},
-        {"nearbyShareOnboardingPageTitle", IDS_NEARBY_ONBOARDING_PAGE_TITLE},
-        {"nearbyShareFeatureName", IDS_NEARBY_SHARE_FEATURE_NAME},
-        {"nearbyShareErrorNoConnectionMediumDescription",
-         IDS_NEARBY_HIGH_VISIBILITY_CONNECTION_MEDIUM_DESCRIPTION},
-        {"nearbyShareSettingsHelpCaptionTop",
-         IDS_NEARBY_SETTINGS_HELP_CAPTION_TOP},
-    };
-
-    data_source->AddLocalizedStrings(kLocalizedStringPairs);
-  }
 }
diff --git a/chrome/browser/ui/webui/password_manager/password_manager_ui.cc b/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
index 54a7ae8..bc2315a 100644
--- a/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
+++ b/chrome/browser/ui/webui/password_manager/password_manager_ui.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/ui/webui/plural_string_handler.h"
 #include "chrome/browser/ui/webui/policy_indicator_localized_strings_provider.h"
 #include "chrome/browser/ui/webui/sanitized_image_source.h"
-#include "chrome/browser/ui/webui/settings/safety_hub_handler.h"
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/browser/web_applications/web_app_helpers.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
@@ -588,7 +587,6 @@
   web_ui->AddMessageHandler(
       std::make_unique<password_manager::SyncHandler>(profile));
   web_ui->AddMessageHandler(std::make_unique<ExtensionControlHandler>());
-  web_ui->AddMessageHandler(std::make_unique<SafetyHubHandler>(profile));
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   web_ui->AddMessageHandler(
       std::make_unique<password_manager::PromoCardsHandler>(
diff --git a/chrome/browser/ui/webui/settings/OWNERS b/chrome/browser/ui/webui/settings/OWNERS
index 551452d..2516b51 100644
--- a/chrome/browser/ui/webui/settings/OWNERS
+++ b/chrome/browser/ui/webui/settings/OWNERS
@@ -1,5 +1,7 @@
 file://chrome/browser/resources/settings/OWNERS
 
+per-file accessibility_main_handler*=file://ui/accessibility/OWNERS
+
 per-file people_handler*=msalama@chromium.org
 per-file people_handler*=treib@chromium.org
 
diff --git a/chrome/browser/ui/webui/settings/safety_hub_handler.cc b/chrome/browser/ui/webui/settings/safety_hub_handler.cc
index c3cc7b5..2a86c63b 100644
--- a/chrome/browser/ui/webui/settings/safety_hub_handler.cc
+++ b/chrome/browser/ui/webui/settings/safety_hub_handler.cc
@@ -19,7 +19,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ui/safety_hub/extensions_result.h"
-#include "chrome/browser/ui/safety_hub/menu_notification_service_factory.h"
 #include "chrome/browser/ui/safety_hub/notification_permission_review_service.h"
 #include "chrome/browser/ui/safety_hub/notification_permission_review_service_factory.h"
 #include "chrome/browser/ui/safety_hub/password_status_check_service.h"
@@ -367,18 +366,6 @@
   SendNotificationPermissionReviewList();
 }
 
-void SafetyHubHandler::HandleDismissActiveMenuNotification(
-    const base::Value::List& args) {
-  SafetyHubMenuNotificationServiceFactory::GetForProfile(profile_)
-      ->DismissActiveNotification();
-}
-
-void SafetyHubHandler::HandleDismissPasswordMenuNotification(
-    const base::Value::List& args) {
-  SafetyHubMenuNotificationServiceFactory::GetForProfile(profile_)
-      ->DismissPasswordNotification();
-}
-
 void SafetyHubHandler::HandleBlockNotificationPermissionForOrigins(
     const base::Value::List& args) {
   CHECK_EQ(1U, args.size());
@@ -687,16 +674,6 @@
           &SafetyHubHandler::HandleResetNotificationPermissionForOrigins,
           base::Unretained(this)));
   web_ui()->RegisterMessageCallback(
-      "dismissActiveMenuNotification",
-      base::BindRepeating(
-          &SafetyHubHandler::HandleDismissActiveMenuNotification,
-          base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
-      "dismissSafetyHubPasswordMenuNotification",
-      base::BindRepeating(
-          &SafetyHubHandler::HandleDismissPasswordMenuNotification,
-          base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
       "blockNotificationPermissionForOrigins",
       base::BindRepeating(
           &SafetyHubHandler::HandleBlockNotificationPermissionForOrigins,
diff --git a/chrome/browser/ui/webui/settings/safety_hub_handler.h b/chrome/browser/ui/webui/settings/safety_hub_handler.h
index c6bc20b3..e1a4013 100644
--- a/chrome/browser/ui/webui/settings/safety_hub_handler.h
+++ b/chrome/browser/ui/webui/settings/safety_hub_handler.h
@@ -148,12 +148,6 @@
   void HandleUndoIgnoreOriginsForNotificationPermissionReview(
       const base::Value::List& args);
 
-  // Handles dismissing the active menu notification for Safety Hub.
-  void HandleDismissActiveMenuNotification(const base::Value::List& args);
-
-  // Handles dismissing the menu notifications for the password module.
-  void HandleDismissPasswordMenuNotification(const base::Value::List& args);
-
   // Returns the data for Safe Browsing card.
   void HandleGetSafeBrowsingCardData(const base::Value::List& args);
 
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index 46ae289..47a6b922 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -901,8 +901,11 @@
   html_source->AddLocalizedStrings(kLocalizedStrings);
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   html_source->AddString(
-      "chromeOSLanguagesSettingsPath",
-      chromeos::settings::mojom::kLanguagesAndInputSectionPath);
+      "osSettingsLanguagesPageUrl",
+      ash::features::IsOsSettingsRevampWayfindingEnabled()
+          ? BuildOSSettingsUrl(chromeos::settings::mojom::kLanguagesSubpagePath)
+          : BuildOSSettingsUrl(
+                chromeos::settings::mojom::kLanguagesAndInputSectionPath));
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
diff --git a/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
index f32cab4..84e9c1a4 100644
--- a/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
@@ -39,7 +39,6 @@
 #include "ash/constants/ash_features.h"
 #include "chrome/browser/ash/crosapi/browser_util.h"
 #include "chrome/browser/nearby_sharing/common/nearby_share_features.h"
-#include "chrome/browser/nearby_sharing/common/nearby_share_resource_getter.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if BUILDFLAG(IS_CHROMEOS)
@@ -260,9 +259,9 @@
 }
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-// TODO(b/309864078): move `AddNearbyShareData` to multidevice section.
 void AddNearbyShareData(content::WebUIDataSource* html_source) {
   static constexpr webui::LocalizedString kLocalizedStrings[] = {
+      {"nearbyShareTitle", IDS_SETTINGS_NEARBY_SHARE_TITLE},
       {"nearbyShareSetUpButtonTitle",
        IDS_SETTINGS_NEARBY_SHARE_SET_UP_BUTTON_TITLE},
       {"nearbyShareDeviceNameRowTitle",
@@ -328,18 +327,6 @@
 
   html_source->AddLocalizedStrings(kLocalizedStrings);
 
-  const char localized_title_string[] = "nearbyShareTitle";
-
-  if (features::IsNameEnabled()) {
-    html_source->AddString(
-        localized_title_string,
-        NearbyShareResourceGetter::GetInstance()->GetStringWithFeatureName(
-            IDS_SETTINGS_NEARBY_SHARE_TITLE_PH));
-  } else {
-    html_source->AddLocalizedString(localized_title_string,
-                                    IDS_SETTINGS_NEARBY_SHARE_TITLE);
-  }
-
   // To use lottie, the worker-src CSP needs to be updated for the web ui that
   // is using it. Since as of now there are only a couple of webuis using
   // lottie animations, this update has to be performed manually. As the usage
diff --git a/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc b/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc
index 607be4a8..720f4a13 100644
--- a/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc
+++ b/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc
@@ -157,6 +157,14 @@
   return mojo_session;
 }
 
+tab_search::mojom::TabOrganizationSessionPtr CreateNotStartedMojoSession() {
+  tab_search::mojom::TabOrganizationSessionPtr mojo_session =
+      tab_search::mojom::TabOrganizationSession::New();
+  mojo_session->state = tab_search::mojom::TabOrganizationState::kNotStarted;
+
+  return mojo_session;
+}
+
 }  // namespace
 
 TabSearchPageHandler::TabSearchPageHandler(
@@ -958,7 +966,7 @@
     }
   }
 
-  page_->TabOrganizationSessionUpdated(CreateFailedMojoSession());
+  page_->TabOrganizationSessionUpdated(CreateNotStartedMojoSession());
 }
 
 bool TabSearchPageHandler::ShouldTrackBrowser(Browser* browser) {
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index d10d4f4..cb5b80f 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1699552779-efb58059ef7f788541d21ef4c94d013d2037ff06.profdata
+chrome-android32-main-1699595874-faa3982cb69fcc7da93391509bd91481abd29470.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index c42478dd..c40364d 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1699552779-21ce6bed292aabcce41ab53df4f55c6e9ae059c7.profdata
+chrome-android64-main-1699595874-ce8dabb7239701a82c760d3268ef449c22dacd7a.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 2b4571c..cb13dba 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1699552779-57cb909fda639dd784a41e56f28fe0e445705da6.profdata
+chrome-linux-main-1699574313-196ec7657aaa36cbe2dc99204f61fca63dd1f9cd.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index db3106d..bb25a60c 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1699559677-ef223596d5e84f984c85aaf9939778409d2dc0a9.profdata
+chrome-mac-arm-main-1699588646-239a7f5d74840d365b72e34c6649461fb8610e29.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 9a12cd7..beaed00 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1699552779-3845385aa504bad318466ff8621bd5fbbc76d213.profdata
+chrome-mac-main-1699574313-95bfde08b679b94e24dc0cc6cdfb3881908564e8.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index e9a4438..df62233 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1699552779-38ad86077c27f486b6393c11f3a6f706c44099d0.profdata
+chrome-win-arm64-main-1699574313-93c5961dcca784ae7255602deb40ccb68622266d.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index a45495f1..a484502 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1699552779-d4f1954faeebab045135f223f498f337bf73a7be.profdata
+chrome-win32-main-1699585108-cf0e2744794430c56898c5fe35dcafc190d9d701.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 518bc50..fc532f9 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1699552779-5dbc43b0333faa8639c80202eefdfa9e843e0d1c.profdata
+chrome-win64-main-1699585108-7043c07a4f6de1337cc06dc62fc03086548c00da.profdata
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 99fb71f..c2862c9 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -110,6 +110,9 @@
 // Upgrade fallback happens.
 inline constexpr char kHttpsUpgradeFallbacks[] = "https_upgrade_fallbacks";
 
+// A dictionary containing information about HTTPS Upgrade related navigations.
+inline constexpr char kHttpsUpgradeNavigations[] = "https_upgrade_navigations";
+
 // Stores information about the important sites dialog, including the time and
 // frequency it has been ignored.
 inline constexpr char kImportantSitesDialogHistory[] = "important_sites_dialog";
diff --git a/chrome/renderer/autofill/form_autofill_browsertest.cc b/chrome/renderer/autofill/form_autofill_browsertest.cc
index 0c1870a..afc54fca 100644
--- a/chrome/renderer/autofill/form_autofill_browsertest.cc
+++ b/chrome/renderer/autofill/form_autofill_browsertest.cc
@@ -278,6 +278,10 @@
   return true;
 }
 
+FormCache::UpdateFormCacheResult UpdateFormCache(FormCache& form_cache) {
+  return form_cache.UpdateFormCache(*base::MakeRefCounted<FieldDataManager>());
+}
+
 }  // namespace
 
 class FormAutofillTest : public ChromeRenderViewTest {
@@ -334,8 +338,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     ASSERT_EQ(1U, forms.size());
 
     const FormData& form = forms[0];
@@ -422,8 +425,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     ASSERT_EQ(1U, forms.size());
 
     // Get the input element we want to find.
@@ -432,9 +434,9 @@
     // Find the form that contains the input element.
     FormData form_data;
     FormFieldData field;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form_data, &field));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        input_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form_data, &field));
     if (!unowned) {
       EXPECT_EQ(u"TestForm", form_data.name);
       EXPECT_EQ(GURL("http://abc.com"), form_data.action);
@@ -664,8 +666,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     ASSERT_EQ(1U, forms.size());
 
     // Get the input element we want to find.
@@ -674,9 +675,9 @@
     // Find the form and verify it's the correct form.
     FormData form;
     FormFieldData field;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form, &field));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        input_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form, &field));
     if (!unowned) {
       EXPECT_EQ(u"TestForm", form.name);
       EXPECT_EQ(GURL("http://abc.com"), form.action);
@@ -723,8 +724,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     ASSERT_EQ(1U, forms.size());
 
     // Get the textarea element we want to find.
@@ -736,9 +736,9 @@
     // Find the form and verify it's the correct form.
     FormData form;
     FormFieldData field;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(textarea_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form, &field));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        textarea_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form, &field));
     if (!unowned) {
       EXPECT_EQ(u"TestForm", form.name);
       EXPECT_EQ(GURL("http://abc.com"), form.action);
@@ -791,8 +791,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     ASSERT_EQ(1U, forms.size());
 
     // Get the input element we want to find.
@@ -801,9 +800,9 @@
     // Find the form that contains the input element.
     FormData form;
     FormFieldData field;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form, &field));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        input_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form, &field));
     if (!unowned) {
       EXPECT_EQ(u"TestForm", form.name);
       EXPECT_EQ(GURL("http://abc.com"), form.action);
@@ -846,9 +845,9 @@
     // Find the newly-filled form that contains the input element.
     FormData form2;
     FormFieldData field2;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form2, &field2));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        input_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form2, &field2));
     if (!unowned) {
       EXPECT_EQ(u"TestForm", form2.name);
       EXPECT_EQ(GURL("http://abc.com"), form2.action);
@@ -887,8 +886,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     ASSERT_EQ(1U, forms.size());
 
     // Get the input element we want to find.
@@ -897,9 +895,9 @@
     // Find the form that contains the input element.
     FormData form;
     FormFieldData field;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form, &field));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        input_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form, &field));
     if (!unowned) {
       EXPECT_EQ(u"TestForm", form.name);
       EXPECT_EQ(GURL("http://abc.com"), form.action);
@@ -934,9 +932,9 @@
     // Find the newly-filled form that contains the input element.
     FormData form2;
     FormFieldData field2;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form2, &field2));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        input_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form2, &field2));
     if (!unowned) {
       EXPECT_EQ(u"TestForm", form2.name);
       EXPECT_EQ(GURL("http://abc.com"), form2.action);
@@ -967,8 +965,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     ASSERT_EQ(1U, forms.size());
 
     // Get the input element we want to find.
@@ -977,9 +974,9 @@
     // Find the form that contains the input element.
     FormData form;
     FormFieldData field;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form, &field));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        input_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form, &field));
     if (!unowned) {
       EXPECT_EQ(u"TestForm", form.name);
       EXPECT_EQ(GURL("http://abc.com"), form.action);
@@ -1014,9 +1011,9 @@
     // Find the newly-filled form that contains the input element.
     FormData form2;
     FormFieldData field2;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form2, &field2));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        input_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form2, &field2));
     if (!unowned) {
       EXPECT_EQ(u"TestForm", form2.name);
       EXPECT_EQ(GURL("http://abc.com"), form2.action);
@@ -1050,8 +1047,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     const size_t expected_size = unowned ? 1 : 2;
     ASSERT_EQ(expected_size, forms.size());
 
@@ -1061,9 +1057,9 @@
     // Find the form that contains the input element.
     FormData form;
     FormFieldData field;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form, &field));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        input_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form, &field));
     if (!unowned) {
       EXPECT_TRUE(form.name.empty());
       EXPECT_EQ(GURL("http://abc.com"), form.action);
@@ -1105,9 +1101,9 @@
     // Find the newly-filled form that contains the input element.
     FormData form2;
     FormFieldData field2;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form2, &field2));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        input_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form2, &field2));
     if (!unowned) {
       EXPECT_TRUE(form2.name.empty());
       EXPECT_EQ(GURL("http://abc.com"), form2.action);
@@ -1147,8 +1143,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     ASSERT_EQ(1U, forms.size());
 
     // Get the input element we want to find.
@@ -1160,9 +1155,9 @@
     // Find the form that contains the input element.
     FormData form;
     FormFieldData field;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form, &field));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        input_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form, &field));
     if (!unowned) {
       EXPECT_EQ(u"TestForm", form.name);
       EXPECT_EQ(GURL("http://abc.com"), form.action);
@@ -1237,9 +1232,9 @@
     // Find the newly-filled form that contains the input element.
     FormData form2;
     FormFieldData field2;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form2, &field2));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        input_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form2, &field2));
     if (!unowned) {
       EXPECT_EQ(u"TestForm", form2.name);
       EXPECT_EQ(GURL("http://abc.com"), form2.action);
@@ -1304,8 +1299,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     ASSERT_EQ(1U, forms.size());
 
     // Get the input element we want to find.
@@ -1340,9 +1334,9 @@
     // Find the form that contains the input element.
     FormData form;
     FormFieldData field;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form, &field));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        input_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form, &field));
     EXPECT_EQ(u"TestForm", form.name);
     EXPECT_EQ(GURL("http://abc.com"), form.action);
 
@@ -1375,9 +1369,9 @@
     // Find the newly-filled form that contains the input element.
     FormData form2;
     FormFieldData field2;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form2, &field2));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        input_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form2, &field2));
     EXPECT_EQ(u"TestForm", form2.name);
     EXPECT_EQ(GURL("http://abc.com"), form2.action);
 
@@ -1484,8 +1478,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     ASSERT_EQ(1U, forms.size());
 
     // Get the input element we want to find.
@@ -1506,9 +1499,9 @@
     // Find the form that contains the input element.
     FormData form;
     FormFieldData field;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form, &field));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        input_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form, &field));
     EXPECT_EQ(u"TestForm", form.name);
     EXPECT_EQ(GURL("http://abc.com"), form.action);
 
@@ -1535,9 +1528,9 @@
     // Find the newly-filled form that contains the input element.
     FormData form2;
     FormFieldData field2;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form2, &field2));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        input_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form2, &field2));
     EXPECT_EQ(u"TestForm", form2.name);
     EXPECT_EQ(GURL("http://abc.com"), form2.action);
 
@@ -1602,8 +1595,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     ASSERT_EQ(1U, forms.size());
 
     // Get the input element we want to find.
@@ -1624,9 +1616,9 @@
     // Find the form that contains the input element.
     FormData form;
     FormFieldData field;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form, &field));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        input_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form, &field));
     EXPECT_EQ(u"TestForm", form.name);
     EXPECT_EQ(GURL("http://abc.com"), form.action);
 
@@ -1653,9 +1645,9 @@
     // Find the newly-filled form that contains the input element.
     FormData form2;
     FormFieldData field2;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form2, &field2));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        input_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form2, &field2));
     EXPECT_EQ(u"TestForm", form2.name);
     EXPECT_EQ(GURL("http://abc.com"), form2.action);
 
@@ -1719,8 +1711,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     ASSERT_EQ(1U, forms.size());
 
     // Get the input element we want to find.
@@ -1745,9 +1736,9 @@
     // Find the form that contains the input element.
     FormData form;
     FormFieldData field;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form, &field));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        input_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form, &field));
     EXPECT_EQ(u"TestForm", form.name);
     EXPECT_EQ(GURL("http://abc.com"), form.action);
 
@@ -1774,9 +1765,9 @@
     // Find the newly-filled form that contains the input element.
     FormData form2;
     FormFieldData field2;
-    EXPECT_TRUE(FindFormAndFieldForFormControlElement(input_element, nullptr,
-                                                      /*extract_options=*/{},
-                                                      &form2, &field2));
+    EXPECT_TRUE(FindFormAndFieldForFormControlElement(
+        input_element, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form2, &field2));
     EXPECT_EQ(u"TestForm", form2.name);
     EXPECT_EQ(GURL("http://abc.com"), form2.action);
 
@@ -1837,8 +1828,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     ASSERT_EQ(1U, forms.size());
 
     // Set the auto-filled attribute.
@@ -1865,7 +1855,8 @@
     FormData form;
     FormFieldData field;
     EXPECT_TRUE(FindFormAndFieldForFormControlElement(
-        firstname, nullptr, /*extract_options=*/{}, &form, &field));
+        firstname, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form, &field));
     if (!unowned) {
       EXPECT_EQ(u"TestForm", form.name);
       EXPECT_EQ(GURL("http://abc.com"), form.action);
@@ -1947,8 +1938,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     ASSERT_EQ(1U, forms.size());
 
     // Set the autofilled attribute and specify the section attribute.
@@ -2001,7 +1991,8 @@
     FormData form;
     FormFieldData field;
     EXPECT_TRUE(FindFormAndFieldForFormControlElement(
-        firstname_shipping, nullptr, /*extract_options=*/{}, &form, &field));
+        firstname_shipping, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form, &field));
     if (!unowned) {
       EXPECT_EQ(u"TestForm", form.name);
       EXPECT_EQ(GURL("http://abc.com"), form.action);
@@ -2057,8 +2048,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     ASSERT_EQ(1U, forms.size());
 
     // Set the auto-filled attribute.
@@ -2083,7 +2073,8 @@
     FormData form;
     FormFieldData field;
     EXPECT_TRUE(FindFormAndFieldForFormControlElement(
-        firstname, nullptr, /*extract_options=*/{}, &form, &field));
+        firstname, *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form, &field));
     if (!unowned) {
       EXPECT_EQ(u"TestForm", form.name);
       EXPECT_EQ(GURL("http://abc.com"), form.action);
@@ -2127,8 +2118,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     ASSERT_EQ(1U, forms.size());
 
     std::vector<WebFormControlElement> elements;
@@ -2180,8 +2170,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     ASSERT_EQ(1U, forms.size());
 
     std::vector<WebFormControlElement> elements;
@@ -2231,8 +2220,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     ASSERT_EQ(1U, forms.size());
 
     std::vector<WebFormControlElement> elements;
@@ -2283,8 +2271,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     ASSERT_EQ(1U, forms.size());
 
     // Set the autofilled attribute.
@@ -2977,8 +2964,9 @@
 
   FormData form;
   FormFieldData field;
-  EXPECT_TRUE(WebFormElementToFormData(forms[0], input_element, nullptr,
-                                       {ExtractOption::kValue}, &form, &field));
+  EXPECT_TRUE(WebFormElementToFormData(
+      forms[0], input_element, *base::MakeRefCounted<FieldDataManager>(),
+      {ExtractOption::kValue}, &form, &field));
   EXPECT_EQ(u"TestForm", form.name);
   EXPECT_EQ(GetFormRendererId(forms[0]), form.unique_renderer_id);
   EXPECT_EQ(GURL("http://cnn.com/submit/"), form.action);
@@ -3059,9 +3047,10 @@
   ASSERT_FALSE(web_form.IsNull());
 
   FormData form;
-  EXPECT_TRUE(WebFormElementToFormData(web_form, WebFormControlElement(),
-                                       nullptr, /*extract_options=*/{}, &form,
-                                       nullptr));
+  EXPECT_TRUE(
+      WebFormElementToFormData(web_form, WebFormControlElement(),
+                               *base::MakeRefCounted<FieldDataManager>(),
+                               /*extract_options=*/{}, &form, nullptr));
 
   const std::vector<FormFieldData>& fields = form.fields;
   ASSERT_EQ(1U, fields.size());
@@ -3090,9 +3079,9 @@
 
   FormData form;
   FormFieldData field;
-  EXPECT_FALSE(WebFormElementToFormData(forms[0], input_element, nullptr,
-                                        {ExtractOption::kValue}, &form,
-                                        &field));
+  EXPECT_FALSE(WebFormElementToFormData(
+      forms[0], input_element, *base::MakeRefCounted<FieldDataManager>(),
+      {ExtractOption::kValue}, &form, &field));
 }
 
 // Tests that the |should_autocomplete| is set to false for all the fields when
@@ -3117,9 +3106,10 @@
   ASSERT_FALSE(web_form.IsNull());
 
   FormData form;
-  EXPECT_TRUE(WebFormElementToFormData(web_form, WebFormControlElement(),
-                                       nullptr, /*extract_options=*/{}, &form,
-                                       nullptr));
+  EXPECT_TRUE(
+      WebFormElementToFormData(web_form, WebFormControlElement(),
+                               *base::MakeRefCounted<FieldDataManager>(),
+                               /*extract_options=*/{}, &form, nullptr));
 
   for (const FormFieldData& field : form.fields) {
     EXPECT_FALSE(field.should_autocomplete);
@@ -3147,9 +3137,10 @@
   ASSERT_FALSE(web_form.IsNull());
 
   FormData form;
-  EXPECT_TRUE(WebFormElementToFormData(web_form, WebFormControlElement(),
-                                       nullptr, /*extract_options=*/{}, &form,
-                                       nullptr));
+  EXPECT_TRUE(
+      WebFormElementToFormData(web_form, WebFormControlElement(),
+                               *base::MakeRefCounted<FieldDataManager>(),
+                               /*extract_options=*/{}, &form, nullptr));
 
   ASSERT_EQ(3U, form.fields.size());
 
@@ -3173,10 +3164,11 @@
   ASSERT_FALSE(web_form.IsNull());
 
   FormData form;
-  EXPECT_TRUE(WebFormElementToFormData(web_form, WebFormControlElement(),
-                                       /*field_data_manager=*/nullptr,
-                                       /*extract_options=*/{}, &form,
-                                       /*field=*/nullptr));
+  EXPECT_TRUE(
+      WebFormElementToFormData(web_form, WebFormControlElement(),
+                               *base::MakeRefCounted<FieldDataManager>(),
+                               /*extract_options=*/{}, &form,
+                               /*field=*/nullptr));
 
   ASSERT_EQ(1U, form.fields.size());
   EXPECT_FALSE(form.fields[0].should_autocomplete);
@@ -3200,9 +3192,10 @@
   ASSERT_FALSE(web_form.IsNull());
 
   FormData form;
-  EXPECT_TRUE(WebFormElementToFormData(web_form, WebFormControlElement(),
-                                       nullptr, /*extract_options=*/{}, &form,
-                                       nullptr));
+  EXPECT_TRUE(
+      WebFormElementToFormData(web_form, WebFormControlElement(),
+                               *base::MakeRefCounted<FieldDataManager>(),
+                               /*extract_options=*/{}, &form, nullptr));
 
   EXPECT_EQ(3U, form.fields.size());
   EXPECT_EQ(u"firstname_field", form.fields[0].css_classes);
@@ -3229,9 +3222,10 @@
   ASSERT_FALSE(web_form.IsNull());
 
   FormData form;
-  EXPECT_TRUE(WebFormElementToFormData(web_form, WebFormControlElement(),
-                                       nullptr, /*extract_options=*/{}, &form,
-                                       nullptr));
+  EXPECT_TRUE(
+      WebFormElementToFormData(web_form, WebFormControlElement(),
+                               *base::MakeRefCounted<FieldDataManager>(),
+                               /*extract_options=*/{}, &form, nullptr));
 
   EXPECT_EQ(4U, form.fields.size());
 
@@ -3282,8 +3276,7 @@
   ASSERT_NE(nullptr, web_frame);
 
   FormCache form_cache(web_frame);
-  std::vector<FormData> forms =
-      form_cache.UpdateFormCache(nullptr).updated_forms;
+  std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
   ASSERT_EQ(2U, forms.size());
 
   // First form.
@@ -3356,12 +3349,11 @@
   ASSERT_NE(nullptr, web_frame);
 
   FormCache form_cache(web_frame);
-  std::vector<FormData> forms =
-      form_cache.UpdateFormCache(nullptr).updated_forms;
+  std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
   ASSERT_EQ(1U, forms.size());
 
   // Second call should give nothing as there are no new forms.
-  forms = form_cache.UpdateFormCache(nullptr).updated_forms;
+  forms = UpdateFormCache(form_cache).updated_forms;
   ASSERT_TRUE(forms.empty());
 
   // Append to the current form will re-extract.
@@ -3373,7 +3365,7 @@
       "document.getElementById('testform').appendChild(newInput);");
   base::RunLoop().RunUntilIdle();
 
-  forms = form_cache.UpdateFormCache(nullptr).updated_forms;
+  forms = UpdateFormCache(form_cache).updated_forms;
   ASSERT_EQ(1U, forms.size());
 
   const std::vector<FormFieldData>& fields = forms[0].fields;
@@ -3434,7 +3426,7 @@
   base::RunLoop().RunUntilIdle();
 
   web_frame = GetMainFrame();
-  forms = form_cache.UpdateFormCache(nullptr).updated_forms;
+  forms = UpdateFormCache(form_cache).updated_forms;
   ASSERT_EQ(1U, forms.size());
 
   const std::vector<FormFieldData>& fields2 = forms[0].fields;
@@ -3468,8 +3460,7 @@
   ASSERT_NE(nullptr, web_frame);
 
   FormCache form_cache(web_frame);
-  std::vector<FormData> forms =
-      form_cache.UpdateFormCache(nullptr).updated_forms;
+  std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
   ASSERT_TRUE(forms.empty());
 }
 
@@ -3492,9 +3483,10 @@
     WebFormElement web_form = web_forms[0];
 
     FormData form;
-    EXPECT_TRUE(WebFormElementToFormData(web_form, WebFormControlElement(),
-                                         nullptr, /*extract_options=*/{}, &form,
-                                         nullptr));
+    EXPECT_TRUE(
+        WebFormElementToFormData(web_form, WebFormControlElement(),
+                                 *base::MakeRefCounted<FieldDataManager>(),
+                                 /*extract_options=*/{}, &form, nullptr));
   }
 }
 
@@ -3629,7 +3621,8 @@
   FormData form;
   // Simulate seeing an unowned form containing just the input "fieldID".
   UnownedFormElementsToFormData({GetFormControlElementById("fieldId")}, {},
-                                nullptr, GetMainFrame()->GetDocument(), nullptr,
+                                nullptr, GetMainFrame()->GetDocument(),
+                                *base::MakeRefCounted<FieldDataManager>(),
                                 /*extract_options=*/{}, &form, nullptr);
   ASSERT_EQ(form.fields.size(), 1u);
   FormFieldData& form_field_data = form.fields[0];
@@ -4822,9 +4815,10 @@
   ASSERT_EQ(1U, forms.size());
 
   FormData form;
-  EXPECT_TRUE(WebFormElementToFormData(forms[0], WebFormControlElement(),
-                                       nullptr, {ExtractOption::kValue}, &form,
-                                       nullptr));
+  EXPECT_TRUE(
+      WebFormElementToFormData(forms[0], WebFormControlElement(),
+                               *base::MakeRefCounted<FieldDataManager>(),
+                               {ExtractOption::kValue}, &form, nullptr));
   EXPECT_EQ(u"TestForm", form.name);
   EXPECT_EQ(GURL("http://cnn.com"), form.action);
 
@@ -4879,9 +4873,10 @@
   ASSERT_EQ(1U, forms.size());
 
   FormData form;
-  EXPECT_TRUE(WebFormElementToFormData(forms[0], WebFormControlElement(),
-                                       nullptr, {ExtractOption::kValue}, &form,
-                                       nullptr));
+  EXPECT_TRUE(
+      WebFormElementToFormData(forms[0], WebFormControlElement(),
+                               *base::MakeRefCounted<FieldDataManager>(),
+                               {ExtractOption::kValue}, &form, nullptr));
   EXPECT_EQ(u"TestForm", form.name);
   EXPECT_EQ(GURL("http://cnn.com"), form.action);
 
@@ -5118,9 +5113,10 @@
   EXPECT_EQ(1U, forms.size());
 
   FormData form;
-  EXPECT_TRUE(WebFormElementToFormData(forms[0], WebFormControlElement(),
-                                       nullptr, {ExtractOption::kValue}, &form,
-                                       nullptr));
+  EXPECT_TRUE(
+      WebFormElementToFormData(forms[0], WebFormControlElement(),
+                               *base::MakeRefCounted<FieldDataManager>(),
+                               {ExtractOption::kValue}, &form, nullptr));
 
   EXPECT_EQ(form.fields.size(), 6u);
   std::vector<FormFieldData> undo_fields;
@@ -5424,7 +5420,8 @@
 
   // Extract the country select-one value as text.
   EXPECT_TRUE(WebFormElementToFormData(
-      forms[0], WebFormControlElement(), nullptr,
+      forms[0], WebFormControlElement(),
+      *base::MakeRefCounted<FieldDataManager>(),
       {ExtractOption::kValue, ExtractOption::kOptionText}, &form, nullptr));
   EXPECT_EQ(u"TestForm", form.name);
   EXPECT_EQ(GURL("http://cnn.com"), form.action);
@@ -5460,9 +5457,10 @@
 
   form.fields.clear();
   // Extract the country select-one value as value.
-  EXPECT_TRUE(WebFormElementToFormData(forms[0], WebFormControlElement(),
-                                       nullptr, {ExtractOption::kValue}, &form,
-                                       nullptr));
+  EXPECT_TRUE(
+      WebFormElementToFormData(forms[0], WebFormControlElement(),
+                               *base::MakeRefCounted<FieldDataManager>(),
+                               {ExtractOption::kValue}, &form, nullptr));
   EXPECT_EQ(u"TestForm", form.name);
   EXPECT_EQ(GURL("http://cnn.com"), form.action);
 
@@ -5520,8 +5518,9 @@
 
   FormData form;
   EXPECT_TRUE(UnownedFormElementsToFormData(
-      control_elements, iframe_elements, nullptr, frame->GetDocument(), nullptr,
-      extract_options, &form, nullptr));
+      control_elements, iframe_elements, nullptr, frame->GetDocument(),
+      *base::MakeRefCounted<FieldDataManager>(), extract_options, &form,
+      nullptr));
 
   EXPECT_TRUE(form.name.empty());
   EXPECT_FALSE(form.action.is_valid());
@@ -5571,8 +5570,9 @@
 
   FormData form;
   EXPECT_FALSE(UnownedFormElementsToFormData(
-      control_elements, iframe_elements, nullptr, frame->GetDocument(), nullptr,
-      extract_options, &form, nullptr));
+      control_elements, iframe_elements, nullptr, frame->GetDocument(),
+      *base::MakeRefCounted<FieldDataManager>(), extract_options, &form,
+      nullptr));
 }
 
 TEST_F(FormAutofillTest, FormlessForms) {
@@ -5596,7 +5596,8 @@
     FormData form;
     EXPECT_TRUE(UnownedFormElementsToFormData(
         control_elements, iframe_elements, nullptr, frame->GetDocument(),
-        nullptr, extract_options, &form, nullptr));
+        *base::MakeRefCounted<FieldDataManager>(), extract_options, &form,
+        nullptr));
   }
 }
 
@@ -5670,8 +5671,7 @@
     ASSERT_NE(nullptr, web_frame);
 
     FormCache form_cache(web_frame);
-    std::vector<FormData> forms =
-        form_cache.UpdateFormCache(nullptr).updated_forms;
+    std::vector<FormData> forms = UpdateFormCache(form_cache).updated_forms;
     EXPECT_EQ(test_case.number_of_extracted_forms, forms.size());
     if (!forms.empty())
       EXPECT_EQ(test_case.is_form_tag, forms.back().is_form_tag);
@@ -5698,8 +5698,9 @@
   ASSERT_FALSE(control_element.IsNull());
   FormData form;
   FormFieldData field;
-  EXPECT_TRUE(WebFormElementToFormData(web_form, control_element, nullptr,
-                                       /*extract_options=*/{}, &form, &field));
+  EXPECT_TRUE(WebFormElementToFormData(
+      web_form, control_element, *base::MakeRefCounted<FieldDataManager>(),
+      /*extract_options=*/{}, &form, &field));
 
   const std::vector<FormFieldData>& fields = form.fields;
   ASSERT_EQ(2U, fields.size());
@@ -5709,8 +5710,9 @@
   frame->ExecuteScript(blink::WebScriptSource(
       WebString("document.getElementById('firstname').remove();")));
   form = {};
-  EXPECT_FALSE(WebFormElementToFormData(web_form, control_element, nullptr,
-                                        /*extract_options=*/{}, &form, &field));
+  EXPECT_FALSE(WebFormElementToFormData(
+      web_form, control_element, *base::MakeRefCounted<FieldDataManager>(),
+      /*extract_options=*/{}, &form, &field));
 }
 
 TEST_F(FormAutofillTest, AriaLabelAndDescription) {
@@ -5735,8 +5737,9 @@
   ASSERT_FALSE(control_element.IsNull());
   FormData form;
   FormFieldData field;
-  EXPECT_TRUE(WebFormElementToFormData(web_form, control_element, nullptr,
-                                       /*extract_options=*/{}, &form, &field));
+  EXPECT_TRUE(WebFormElementToFormData(
+      web_form, control_element, *base::MakeRefCounted<FieldDataManager>(),
+      /*extract_options=*/{}, &form, &field));
 
   const std::vector<FormFieldData>& fields = form.fields;
   ASSERT_EQ(3U, fields.size());
@@ -5776,8 +5779,9 @@
   ASSERT_FALSE(control_element.IsNull());
   FormData form;
   FormFieldData field;
-  EXPECT_TRUE(WebFormElementToFormData(web_form, control_element, nullptr,
-                                       /*extract_options=*/{}, &form, &field));
+  EXPECT_TRUE(WebFormElementToFormData(
+      web_form, control_element, *base::MakeRefCounted<FieldDataManager>(),
+      /*extract_options=*/{}, &form, &field));
 
   const std::vector<FormFieldData>& fields = form.fields;
   ASSERT_EQ(3U, fields.size());
diff --git a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
index e01e50c..fe5cf79ae 100644
--- a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
+++ b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
@@ -377,7 +377,6 @@
 
     // TODO(crbug/862989): Remove workaround preventing non-test classes to bind
     // fake_driver_ or fake_pw_client_.
-    password_autofill_agent_->Init(autofill_agent_);
     password_autofill_agent_->GetPasswordManagerDriver();
     password_generation_->RequestPasswordManagerClientForTesting();
     base::RunLoop().RunUntilIdle();  // Executes binding the interfaces.
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index a70d9a1..cb0e310c 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -4209,7 +4209,6 @@
         "../browser/supervised_user/supervised_user_regional_url_filter_browsertest.cc",
         "../browser/supervised_user/supervised_user_service_browsertest.cc",
         "../browser/supervised_user/supervised_user_url_filter_browsertest.cc",
-        "../browser/supervised_user/youtube_restrictions_browsertest.cc",
         "../browser/ui/views/extensions/extension_install_dialog_view_supervised_browsertest.cc",
       ]
 
diff --git a/chrome/test/data/extensions/api_test/tabs/prerendering_into_new_tab/empty.js b/chrome/test/data/extensions/api_test/tabs/prerendering_into_new_tab/empty.js
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/tabs/prerendering_into_new_tab/empty.js
diff --git a/chrome/test/data/extensions/api_test/tabs/prerendering_into_new_tab/initiator.html b/chrome/test/data/extensions/api_test/tabs/prerendering_into_new_tab/initiator.html
new file mode 100644
index 0000000..3d01f9fa
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/tabs/prerendering_into_new_tab/initiator.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>initiator</title>
+<script type="speculationrules">
+  {
+    "prerender": [{
+      "source": "list",
+      "urls": ["prerendering.html"],
+      "target_hint": "_blank"
+    }]
+  }
+</script>
+</head>
+<body><a href="prerendering.html" target="_blank" id="link">link</a></body>
+</html>
diff --git a/chrome/test/data/extensions/api_test/tabs/prerendering_into_new_tab/manifest.json b/chrome/test/data/extensions/api_test/tabs/prerendering_into_new_tab/manifest.json
new file mode 100644
index 0000000..54919ad
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/tabs/prerendering_into_new_tab/manifest.json
@@ -0,0 +1,16 @@
+{
+  "name": "chrome.tabs for prerendering into a new tab",
+  "version": "0.1",
+  "manifest_version": 2,
+  "description": "end-to-end browser test for chrome.tabs API with prerendering into a new tab",
+  "background": {
+    "scripts": [
+      "test.js"
+    ]
+  },
+  "permissions": [
+    "tabs",
+    "webRequest",
+    "<all_urls>"
+  ]
+}
diff --git a/chrome/test/data/extensions/api_test/tabs/prerendering_into_new_tab/prerendering.html b/chrome/test/data/extensions/api_test/tabs/prerendering_into_new_tab/prerendering.html
new file mode 100644
index 0000000..23d9148
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/tabs/prerendering_into_new_tab/prerendering.html
@@ -0,0 +1,2 @@
+<title>prerendering</title>
+<script src='empty.js' />
diff --git a/chrome/test/data/extensions/api_test/tabs/prerendering_into_new_tab/test.js b/chrome/test/data/extensions/api_test/tabs/prerendering_into_new_tab/test.js
new file mode 100644
index 0000000..dae09d50
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/tabs/prerendering_into_new_tab/test.js
@@ -0,0 +1,130 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+let testServerPort = 0;
+let tabId = 0;
+let prerenderingTabId = 0;
+let prerenderingFrameId = 0;
+let prerenderingDocumentId = 0;
+
+function getUrl(path) {
+  return `http://example.com:${
+      testServerPort}/extensions/api_test/tabs/prerendering_into_new_tab/${
+      path}`;
+}
+
+async function setup() {
+  // The pre-rendered frame includes a resource for empty.js. We use a
+  // webRequest listener to intercept the call for the resource in order to
+  // identify the frame / document of the prerendered page.
+  const kInitiatorUrl = getUrl('initiator.html');
+  const kEmptyJsUrl = getUrl('empty.js');
+  await new Promise(resolve => {
+    const onBeforeRequest =
+        (details => {
+          if (details.documentLifecycle === 'prerender') {
+            prerenderingTabId = details.tabId;
+            prerenderingFrameId = details.frameId;
+            prerenderingDocumentId = details.documentId;
+            chrome.test.assertNe(0, prerenderingFrameId);
+            chrome.webRequest.onBeforeRequest.removeListener(onBeforeRequest);
+            resolve();
+          }
+        });
+    chrome.webRequest.onBeforeRequest.addListener(
+        onBeforeRequest, {urls: [kEmptyJsUrl]}, []);
+    chrome.test.waitForRoundTrip('msg', () => {
+      chrome.tabs.update(tabId, {url: kInitiatorUrl});
+    });
+  });
+  chrome.test.assertNe(0, prerenderingDocumentId);
+}
+
+// Checks that `allFrames: true` does not return an invisible tab (pre-rendered
+// new tab frames).
+async function testGetTitleForAllFrames() {
+  await setup();
+  chrome.tabs.executeScript(
+      prerenderingTabId, {allFrames: true, code: 'document.title;'},
+      results => {
+        chrome.test.assertEq(undefined, results);
+      });
+  chrome.tabs.executeScript(
+      tabId, {allFrames: true, code: 'document.title;'}, results => {
+        chrome.test.assertEq(1, results.length);
+        chrome.test.assertEq('initiator', results[0]);
+        chrome.test.succeed();
+      });
+}
+
+// Checks that `getAllInWindow` does not return an invisible tab (pre-rendered
+// new tab frames).
+async function testGetAllInWindow() {
+  await setup();
+  console.log('testGetAllInWindow called');
+  chrome.tabs.getAllInWindow(null, function(tabs) {
+    chrome.test.assertEq(1, tabs.length);
+    chrome.test.assertEq(getUrl('initiator.html'), tabs[0].url);
+    chrome.test.succeed();
+  });
+}
+
+// Checks that `query` does not return an invisible tab (pre-rendered
+// new tab frames).
+async function testQuery() {
+  await setup();
+  chrome.tabs.query({}, function(tabs) {
+    chrome.test.assertEq(1, tabs.length);
+    chrome.test.assertEq(getUrl('initiator.html'), tabs[0].url);
+    chrome.test.succeed();
+  });
+}
+
+// Checks that `frameId` not returning an invisible tab when specifying a
+// pre-rendered frame.
+async function testGetTitleByFrameId() {
+  await setup();
+  chrome.tabs.executeScript(
+      prerenderingTabId,
+      {frameId: prerenderingFrameId, code: 'document.title;'}, results => {
+        chrome.test.assertEq(undefined, results);
+        chrome.test.succeed();
+      });
+}
+
+// Checks that manifest v2 does not support `documentId`.
+async function testGetTitleByDocumentId() {
+  await setup();
+  chrome.test.assertThrows(
+      chrome.tabs.executeScript,
+      [
+        prerenderingTabId,
+        {documentId: prerenderingDocumentId, code: 'document.title;'},
+        results => chrome.test.fail('should not succeed.')
+      ],
+      'Error in invocation of tabs.executeScript(optional integer tabId, ' +
+          'extensionTypes.InjectDetails details, optional function ' +
+          'callback): Error at parameter \'details\': Unexpected property: \'' +
+          'documentId\'.');
+  chrome.test.succeed();
+}
+
+chrome.test.getConfig(async config => {
+  testServerPort = config.testServer.port;
+  chrome.test.assertNe(0, testServerPort);
+
+  const tabs = await new Promise(
+      resolve => chrome.tabs.query({active: true}, tabs => resolve(tabs)));
+  chrome.test.assertEq(1, tabs.length);
+  tabId = tabs[0].id;
+
+  // TODO(https://crbug.com/1350676): add more tests for tabs.on* event listeners.
+  chrome.test.runTests([
+    testGetTitleForAllFrames,
+    testGetAllInWindow,
+    testQuery,
+    testGetTitleByFrameId,
+    testGetTitleByDocumentId,
+  ]);
+});
diff --git a/chrome/test/data/webui/app_settings/app_test.ts b/chrome/test/data/webui/app_settings/app_test.ts
index e89a970..cb243c9 100644
--- a/chrome/test/data/webui/app_settings/app_test.ts
+++ b/chrome/test/data/webui/app_settings/app_test.ts
@@ -52,6 +52,7 @@
       publisherId: '',
       formattedOrigin: '',
       scopeExtensions: [],
+      supportedLocales: [],
     };
 
     if (optConfig) {
diff --git a/chrome/test/data/webui/cr_components/app_management/app_management_test_support.ts b/chrome/test/data/webui/cr_components/app_management/app_management_test_support.ts
index abf98f4..a27cb6f 100644
--- a/chrome/test/data/webui/cr_components/app_management/app_management_test_support.ts
+++ b/chrome/test/data/webui/cr_components/app_management/app_management_test_support.ts
@@ -60,6 +60,7 @@
     publisherId: '',
     formattedOrigin: '',
     scopeExtensions: [],
+    supportedLocales: [],
   };
 
   if (optConfig) {
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_legacy_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_legacy_test.js
index eb902c57..a661e49 100644
--- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_legacy_test.js
+++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_legacy_test.js
@@ -534,7 +534,7 @@
             assertProfileDiscoveryPageLegacy();
             assertFocusDefaultButtonEventFired();
             assertEquals(
-                eSimPage.forwardButtonLabel, 'Skip & Set up new profile');
+                eSimPage.forwardButtonLabel, 'Skip & set up new profile');
 
             endFlowAndVerifyResult(
                 ESimSetupFlowResult.CANCELLED_NEEDS_CONFIRMATION_CODE);
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_test.js
index c99c7a8d..a52f6e9 100644
--- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_test.js
+++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_test.js
@@ -639,7 +639,7 @@
             assertProfileDiscoveryPage();
             assertFocusDefaultButtonEventFired();
             assertEquals(
-                eSimPage.forwardButtonLabel, 'Skip & Set up new profile');
+                eSimPage.forwardButtonLabel, 'Skip & set up new profile');
 
             endFlowAndVerifyResult(
                 ESimSetupFlowResult.CANCELLED_NEEDS_CONFIRMATION_CODE);
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_browsertest.cc b/chrome/test/data/webui/cr_elements/cr_elements_browsertest.cc
index e1c6a505..788a001 100644
--- a/chrome/test/data/webui/cr_elements/cr_elements_browsertest.cc
+++ b/chrome/test/data/webui/cr_elements/cr_elements_browsertest.cc
@@ -162,7 +162,8 @@
 };
 
 // TOD(crbug.com/906991): revisit after PlzDedicatedWorker launch.
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_CHROMEOS) || \
+    BUILDFLAG(IS_MAC)
 #define MAYBE_CrLottie DISABLED_CrLottie
 #else
 #define MAYBE_CrLottie CrLottie
diff --git a/chrome/test/data/webui/password_manager/password_manager_app_test.ts b/chrome/test/data/webui/password_manager/password_manager_app_test.ts
index fc1dfc7b..b470e0a 100644
--- a/chrome/test/data/webui/password_manager/password_manager_app_test.ts
+++ b/chrome/test/data/webui/password_manager/password_manager_app_test.ts
@@ -242,12 +242,4 @@
     assertTrue(!!spinner);
     assertTrue(spinner.active);
   });
-
-  test(
-      'dismiss Safety Hub menu notification for password module',
-      async function() {
-        Router.getInstance().navigateTo(Page.CHECKUP);
-        await passwordManager.whenCalled(
-            'dismissSafetyHubPasswordMenuNotification');
-      });
 });
diff --git a/chrome/test/data/webui/password_manager/test_password_manager_proxy.ts b/chrome/test/data/webui/password_manager/test_password_manager_proxy.ts
index 13b53b52..2c1e872 100644
--- a/chrome/test/data/webui/password_manager/test_password_manager_proxy.ts
+++ b/chrome/test/data/webui/password_manager/test_password_manager_proxy.ts
@@ -54,7 +54,6 @@
       'changeCredential',
       'cancelExportPasswords',
       'continueImport',
-      'dismissSafetyHubPasswordMenuNotification',
       'exportPasswords',
       'extendAuthValidity',
       'fetchFamilyMembers',
@@ -372,8 +371,4 @@
   movePasswordsToAccount(ids: number[]) {
     this.methodCalled('movePasswordsToAccount', ids);
   }
-
-  dismissSafetyHubPasswordMenuNotification() {
-    this.methodCalled('dismissSafetyHubPasswordMenuNotification');
-  }
 }
diff --git a/chrome/test/data/webui/settings/chromeos/app_management/fake_page_handler.ts b/chrome/test/data/webui/settings/chromeos/app_management/fake_page_handler.ts
index 793f63e..04d1d08e 100644
--- a/chrome/test/data/webui/settings/chromeos/app_management/fake_page_handler.ts
+++ b/chrome/test/data/webui/settings/chromeos/app_management/fake_page_handler.ts
@@ -100,6 +100,7 @@
       publisherId: '',
       formattedOrigin: '',
       scopeExtensions: [],
+      supportedLocales: [],
     };
 
     if (optConfig) {
diff --git a/chrome/test/data/webui/settings/safety_hub_page_test.ts b/chrome/test/data/webui/settings/safety_hub_page_test.ts
index bc8c0bf..8f5c9ac 100644
--- a/chrome/test/data/webui/settings/safety_hub_page_test.ts
+++ b/chrome/test/data/webui/settings/safety_hub_page_test.ts
@@ -359,9 +359,4 @@
     // Ensure the Security Settings page is shown.
     assertEquals(routes.SECURITY, Router.getInstance().getCurrentRoute());
   });
-
-  test('Dismiss all menu notifications on page load', async function() {
-    Router.getInstance().navigateTo(routes.SAFETY_HUB);
-    await safetyHubBrowserProxy.whenCalled('dismissActiveMenuNotification');
-  });
 });
diff --git a/chrome/test/data/webui/settings/test_safety_hub_browser_proxy.ts b/chrome/test/data/webui/settings/test_safety_hub_browser_proxy.ts
index b6173e90..91fe0047 100644
--- a/chrome/test/data/webui/settings/test_safety_hub_browser_proxy.ts
+++ b/chrome/test/data/webui/settings/test_safety_hub_browser_proxy.ts
@@ -49,7 +49,6 @@
       'getVersionCardData',
       'getSafetyHubHasRecommendations',
       'getSafetyHubEntryPointSubheader',
-      'dismissActiveMenuNotification',
     ]);
   }
 
@@ -164,8 +163,4 @@
   setSafetyHubEntryPointSubheader(value: string) {
     this.entryPointSubheader_ = value;
   }
-
-  dismissActiveMenuNotification() {
-    this.methodCalled('dismissActiveMenuNotification');
-  }
 }
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 84a965b..82c8077 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-15672.0.0
\ No newline at end of file
+15673.0.0
\ No newline at end of file
diff --git a/chromeos/ash/components/dbus/lorgnette_manager/fake_lorgnette_manager_client.cc b/chromeos/ash/components/dbus/lorgnette_manager/fake_lorgnette_manager_client.cc
index 8f5b043..8e73d6b 100644
--- a/chromeos/ash/components/dbus/lorgnette_manager/fake_lorgnette_manager_client.cc
+++ b/chromeos/ash/components/dbus/lorgnette_manager/fake_lorgnette_manager_client.cc
@@ -53,6 +53,15 @@
       FROM_HERE, base::BindOnce(std::move(callback), set_options_response_));
 }
 
+void FakeLorgnetteManagerClient::GetCurrentConfig(
+    const lorgnette::GetCurrentConfigRequest& request,
+    chromeos::DBusMethodCallback<lorgnette::GetCurrentConfigResponse>
+        callback) {
+  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
+      FROM_HERE,
+      base::BindOnce(std::move(callback), get_current_config_response_));
+}
+
 void FakeLorgnetteManagerClient::StartPreparedScan(
     const lorgnette::StartPreparedScanRequest& request,
     chromeos::DBusMethodCallback<lorgnette::StartPreparedScanResponse>
@@ -158,6 +167,11 @@
   set_options_response_ = response;
 }
 
+void FakeLorgnetteManagerClient::SetGetCurrentConfigResponse(
+    const absl::optional<lorgnette::GetCurrentConfigResponse>& response) {
+  get_current_config_response_ = response;
+}
+
 void FakeLorgnetteManagerClient::SetStartPreparedScanResponse(
     const absl::optional<lorgnette::StartPreparedScanResponse>& response) {
   start_prepared_scan_response_ = response;
diff --git a/chromeos/ash/components/dbus/lorgnette_manager/fake_lorgnette_manager_client.h b/chromeos/ash/components/dbus/lorgnette_manager/fake_lorgnette_manager_client.h
index e1f9d20..0c429427 100644
--- a/chromeos/ash/components/dbus/lorgnette_manager/fake_lorgnette_manager_client.h
+++ b/chromeos/ash/components/dbus/lorgnette_manager/fake_lorgnette_manager_client.h
@@ -45,6 +45,10 @@
   void SetOptions(const lorgnette::SetOptionsRequest& request,
                   chromeos::DBusMethodCallback<lorgnette::SetOptionsResponse>
                       callback) override;
+  void GetCurrentConfig(
+      const lorgnette::GetCurrentConfigRequest& request,
+      chromeos::DBusMethodCallback<lorgnette::GetCurrentConfigResponse>
+          callback) override;
   void StartPreparedScan(
       const lorgnette::StartPreparedScanRequest& request,
       chromeos::DBusMethodCallback<lorgnette::StartPreparedScanResponse>
@@ -98,6 +102,10 @@
   void SetSetOptionsResponse(
       const absl::optional<lorgnette::SetOptionsResponse>& response);
 
+  // Sets the response returned by GetCurrentConfig().
+  void SetGetCurrentConfigResponse(
+      const absl::optional<lorgnette::GetCurrentConfigResponse>& response);
+
   // Sets the response returned by StartPreparedScan()
   void SetStartPreparedScanResponse(
       const absl::optional<lorgnette::StartPreparedScanResponse>& response);
@@ -120,6 +128,8 @@
   absl::optional<lorgnette::OpenScannerResponse> open_scanner_response_;
   absl::optional<lorgnette::CloseScannerResponse> close_scanner_response_;
   absl::optional<lorgnette::SetOptionsResponse> set_options_response_;
+  absl::optional<lorgnette::GetCurrentConfigResponse>
+      get_current_config_response_;
   absl::optional<lorgnette::StartPreparedScanResponse>
       start_prepared_scan_response_;
   absl::optional<lorgnette::ReadScanDataResponse> read_scan_data_response_;
diff --git a/chromeos/ash/components/dbus/lorgnette_manager/lorgnette_manager_client.cc b/chromeos/ash/components/dbus/lorgnette_manager/lorgnette_manager_client.cc
index c02e6ac..95b3fd62 100644
--- a/chromeos/ash/components/dbus/lorgnette_manager/lorgnette_manager_client.cc
+++ b/chromeos/ash/components/dbus/lorgnette_manager/lorgnette_manager_client.cc
@@ -151,6 +151,25 @@
                        weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
   }
 
+  void GetCurrentConfig(
+      const lorgnette::GetCurrentConfigRequest& request,
+      chromeos::DBusMethodCallback<lorgnette::GetCurrentConfigResponse>
+          callback) override {
+    dbus::MethodCall method_call(lorgnette::kManagerServiceInterface,
+                                 lorgnette::kGetCurrentConfigMethod);
+    dbus::MessageWriter writer(&method_call);
+    if (!writer.AppendProtoAsArrayOfBytes(request)) {
+      LOG(ERROR) << "Failed to encode GetCurrentConfigRequest protobuf";
+      base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
+          FROM_HERE, base::BindOnce(std::move(callback), absl::nullopt));
+      return;
+    }
+    lorgnette_daemon_proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::BindOnce(&LorgnetteManagerClientImpl::OnGetCurrentConfigResponse,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  }
+
   void StartPreparedScan(
       const lorgnette::StartPreparedScanRequest& request,
       chromeos::DBusMethodCallback<lorgnette::StartPreparedScanResponse>
@@ -596,6 +615,28 @@
     std::move(callback).Run(response_proto);
   }
 
+  // Handles the response received after calling GetCurrentConfig().
+  void OnGetCurrentConfigResponse(
+      chromeos::DBusMethodCallback<lorgnette::GetCurrentConfigResponse>
+          callback,
+      dbus::Response* response) {
+    if (!response) {
+      LOG(ERROR) << "Failed to obtain GetCurrentConfigResponse";
+      std::move(callback).Run(absl::nullopt);
+      return;
+    }
+
+    lorgnette::GetCurrentConfigResponse response_proto;
+    dbus::MessageReader reader(response);
+    if (!reader.PopArrayOfBytesAsProto(&response_proto)) {
+      LOG(ERROR) << "Failed to decode GetCurrentConfigResponse proto";
+      std::move(callback).Run(absl::nullopt);
+      return;
+    }
+
+    std::move(callback).Run(response_proto);
+  }
+
   // Handles the response received after calling StartPreparedScan.
   void OnStartPreparedScanResponse(
       chromeos::DBusMethodCallback<lorgnette::StartPreparedScanResponse>
diff --git a/chromeos/ash/components/dbus/lorgnette_manager/lorgnette_manager_client.h b/chromeos/ash/components/dbus/lorgnette_manager/lorgnette_manager_client.h
index 9cf4f03..7e9e670 100644
--- a/chromeos/ash/components/dbus/lorgnette_manager/lorgnette_manager_client.h
+++ b/chromeos/ash/components/dbus/lorgnette_manager/lorgnette_manager_client.h
@@ -77,6 +77,13 @@
       const lorgnette::SetOptionsRequest& request,
       chromeos::DBusMethodCallback<lorgnette::SetOptionsResponse> callback) = 0;
 
+  // Gets the config for the the scanner described by |request| and returns the
+  // result using the provided |callback|.
+  virtual void GetCurrentConfig(
+      const lorgnette::GetCurrentConfigRequest& request,
+      chromeos::DBusMethodCallback<lorgnette::GetCurrentConfigResponse>
+          callback) = 0;
+
   // Starts a scan using information in |request| and returns the result using
   // the provided |callback|.
   virtual void StartPreparedScan(
diff --git a/chromeos/ash/components/dbus/lorgnette_manager/lorgnette_manager_client_unittest.cc b/chromeos/ash/components/dbus/lorgnette_manager/lorgnette_manager_client_unittest.cc
index 761a466..7cfc4a4 100644
--- a/chromeos/ash/components/dbus/lorgnette_manager/lorgnette_manager_client_unittest.cc
+++ b/chromeos/ash/components/dbus/lorgnette_manager/lorgnette_manager_client_unittest.cc
@@ -186,6 +186,24 @@
   return response;
 }
 
+// Convenience method for creating a lorgnette::GetCurrentConfigRequest.
+lorgnette::GetCurrentConfigRequest CreateGetCurrentConfigRequest() {
+  lorgnette::GetCurrentConfigRequest request;
+  request.mutable_scanner()->set_token(kScannerHandle);
+
+  return request;
+}
+
+// Convenience method for creating a lorgnette::GetCurrentConfigResponse.
+lorgnette::GetCurrentConfigResponse CreateGetCurrentConfigResponse() {
+  lorgnette::GetCurrentConfigResponse response;
+  response.mutable_scanner()->set_token(kScannerHandle);
+  response.set_result(lorgnette::OPERATION_RESULT_SUCCESS);
+  response.mutable_config()->mutable_scanner()->set_token(kScannerHandle);
+
+  return response;
+}
+
 // Convenience method for creating a lorgnette::StartPreparedScanRequest.
 lorgnette::StartPreparedScanRequest CreateStartPreparedScanRequest() {
   lorgnette::ScannerHandle handle;
@@ -533,6 +551,17 @@
         .WillOnce(Invoke(this, &LorgnetteManagerClientTest::OnSetOptions));
   }
 
+  // Adds an expectation to |mock_proxy_| that kGetCurrentConfigMethod will be
+  // called. When called, |mock_proxy_| will respond with |response|.
+  void SetGetCurrentConfigExpectation(dbus::Response* response) {
+    get_current_config_response_ = response;
+    EXPECT_CALL(*mock_proxy_.get(),
+                DoCallMethod(HasMember(lorgnette::kGetCurrentConfigMethod),
+                             dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, _))
+        .WillOnce(
+            Invoke(this, &LorgnetteManagerClientTest::OnGetCurrentConfig));
+  }
+
   // Adds an expectation to |mock_proxy_| that kStartPreparedScanMethod will be
   // called. When called, |mock_proxy_| will respond with |response|.
   void SetStartPreparedScanExpectation(dbus::Response* response) {
@@ -753,6 +782,21 @@
         FROM_HERE, base::BindOnce(std::move(*callback), set_options_response_));
   }
 
+  // Responsible for responding to a kGetCurrentConfigMethod call and verifying
+  // that |method_call| is formatted correctly.
+  void OnGetCurrentConfig(dbus::MethodCall* method_call,
+                          int timeout_ms,
+                          dbus::ObjectProxy::ResponseCallback* callback) {
+    // Verify that the get config request was created and sent correctly.
+    lorgnette::GetCurrentConfigRequest request;
+    ASSERT_TRUE(
+        dbus::MessageReader(method_call).PopArrayOfBytesAsProto(&request));
+    EXPECT_THAT(request, EqualsProto(CreateGetCurrentConfigRequest()));
+    task_environment_.GetMainThreadTaskRunner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(std::move(*callback), get_current_config_response_));
+  }
+
   // Responsible for responding to a kStartPreparedScanMethod call and verifying
   // that |method_call| is formatted correctly.
   void OnStartPreparedScan(dbus::MethodCall* method_call,
@@ -879,6 +923,9 @@
   // Used to respond to kSetOptionsMethod D-Bus calls.
   raw_ptr<dbus::Response, DanglingUntriaged | ExperimentalAsh>
       set_options_response_ = nullptr;
+  // Used to respond to kGetCurrentConfigMethod D-Bus calls.
+  raw_ptr<dbus::Response, DanglingUntriaged | ExperimentalAsh>
+      get_current_config_response_ = nullptr;
   // Used to respond to kStartPreparedScanMethod D-Bus calls.
   raw_ptr<dbus::Response, DanglingUntriaged | ExperimentalAsh>
       start_prepared_scan_response_ = nullptr;
@@ -1316,6 +1363,63 @@
   run_loop.Run();
 }
 
+// Test that the client can get the config for a scanner.
+TEST_F(LorgnetteManagerClientTest, GetCurrentConfig) {
+  std::unique_ptr<dbus::Response> response = dbus::Response::CreateEmpty();
+  const lorgnette::GetCurrentConfigResponse kExpectedResponse =
+      CreateGetCurrentConfigResponse();
+  ASSERT_TRUE(dbus::MessageWriter(response.get())
+                  .AppendProtoAsArrayOfBytes(kExpectedResponse));
+  SetGetCurrentConfigExpectation(response.get());
+
+  base::RunLoop run_loop;
+  GetClient()->GetCurrentConfig(
+      CreateGetCurrentConfigRequest(),
+      base::BindLambdaForTesting(
+          [&](absl::optional<lorgnette::GetCurrentConfigResponse> result) {
+            run_loop.Quit();
+            ASSERT_TRUE(result.has_value());
+            EXPECT_THAT(result.value(), EqualsProto(kExpectedResponse));
+          }));
+
+  run_loop.Run();
+}
+
+// Test that the client handles a null response to a kGetCurrentConfigMethod
+// D-Bus call.
+TEST_F(LorgnetteManagerClientTest, GetCurrentConfigNullResponse) {
+  SetGetCurrentConfigExpectation(nullptr);
+
+  base::RunLoop run_loop;
+  GetClient()->GetCurrentConfig(
+      CreateGetCurrentConfigRequest(),
+      base::BindLambdaForTesting(
+          [&](absl::optional<lorgnette::GetCurrentConfigResponse> result) {
+            EXPECT_EQ(result, absl::nullopt);
+            run_loop.Quit();
+          }));
+
+  run_loop.Run();
+}
+
+// Test that the client handles the case when it can't parse a response from a
+// kGetCurrentConfigMethod D-Bus call into an appropriate protobuf.
+TEST_F(LorgnetteManagerClientTest, GetCurrentConfigInvalidResponse) {
+  std::unique_ptr<dbus::Response> response = dbus::Response::CreateEmpty();
+  SetGetCurrentConfigExpectation(response.get());
+
+  base::RunLoop run_loop;
+  GetClient()->GetCurrentConfig(
+      CreateGetCurrentConfigRequest(),
+      base::BindLambdaForTesting(
+          [&](absl::optional<lorgnette::GetCurrentConfigResponse> result) {
+            EXPECT_EQ(result, absl::nullopt);
+            run_loop.Quit();
+          }));
+
+  run_loop.Run();
+}
+
 // Test that the client can start a prepared scan.
 TEST_F(LorgnetteManagerClientTest, StartPreparedScan) {
   std::unique_ptr<dbus::Response> response = dbus::Response::CreateEmpty();
diff --git a/chromeos/profiles/arm.afdo.newest.txt b/chromeos/profiles/arm.afdo.newest.txt
index 87e0880..08b5c955 100644
--- a/chromeos/profiles/arm.afdo.newest.txt
+++ b/chromeos/profiles/arm.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-none-121-6085.0-1699275463-benchmark-121.0.6111.0-r1-redacted.afdo.xz
+chromeos-chrome-arm-none-121-6085.0-1699275463-benchmark-121.0.6117.0-r2-redacted.afdo.xz
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt
index fa493586..9bb8344 100644
--- a/chromeos/profiles/atom.afdo.newest.txt
+++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-atom-121-6085.0-1699270938-benchmark-121.0.6110.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-atom-121-6085.0-1699270938-benchmark-121.0.6117.0-r2-redacted.afdo.xz
diff --git a/clank b/clank
index f88561d..dcf0a93 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit f88561d375f33d5fb658a55f7dba75e0bb41780a
+Subproject commit dcf0a93ec1e24456a5d335b278c99775a58dc7c6
diff --git a/components/BUILD.gn b/components/BUILD.gn
index d32e3287..8a95249 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -413,6 +413,7 @@
       "//components/cast_receiver:unit_tests",
       "//components/cast_streaming:unit_tests",
       "//components/certificate_transparency:unit_tests",
+      "//components/commerce/content/browser:unit_tests",
       "//components/content_capture/browser:unit_tests",
       "//components/content_relationship_verification:unit_tests",
       "//components/contextual_search/core/browser:unit_tests",
@@ -430,6 +431,7 @@
       "//components/endpoint_fetcher:unit_tests",
       "//components/enterprise/content:unit_tests",
       "//components/favicon/content:unit_tests",
+      "//components/feed/core/v2:core_unit_tests",
       "//components/file_access:unit_tests",
       "//components/gcm_driver/instance_id:unit_tests",
       "//components/heavy_ad_intervention:unit_tests",
@@ -526,10 +528,8 @@
     deps += [
       "//components/background_sync:unit_tests",
       "//components/blocked_content:unit_tests",
-      "//components/commerce/content/browser:unit_tests",
       "//components/content_settings/browser:unit_tests",
       "//components/content_settings/browser/ui:unit_tests",
-      "//components/feed/core/v2:core_unit_tests",
       "//components/media_router/browser:unit_tests",
       "//components/media_router/common:unit_tests",
       "//components/media_router/common/providers/cast/channel:unit_tests",
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index 9f5b4ace..eec4d3ad 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -315,7 +315,7 @@
       is_user_gesture_required_(true),
       is_secure_context_required_(false),
       form_tracker_(render_frame),
-      field_data_manager_(password_autofill_agent_->GetFieldDataManager()),
+      field_data_manager_(base::MakeRefCounted<FieldDataManager>()),
       focus_state_notifier_(this) {
   render_frame->GetWebFrame()->SetAutofillClient(this);
   password_autofill_agent_->Init(this);
@@ -390,7 +390,7 @@
   FormData form;
   FormFieldData field;
   if (FindFormAndFieldForFormControlElement(
-          element, field_data_manager_.get(),
+          element, field_data_manager(),
           MaybeExtractDatalist({ExtractOption::kBounds}), &form, &field)) {
     if (auto* autofill_driver = unsafe_autofill_driver()) {
       autofill_driver->TextFieldDidScroll(form, field, field.bounds);
@@ -462,7 +462,7 @@
   FormFieldData field;
   if (!form_control_element.IsReadOnly() &&
       FindFormAndFieldForFormControlElement(
-          last_queried_element_, field_data_manager_.get(),
+          last_queried_element_, field_data_manager(),
           MaybeExtractDatalist({ExtractOption::kBounds}), &form, &field)) {
     if (auto* autofill_driver = unsafe_autofill_driver()) {
       autofill_driver->FocusOnFormField(form, field, field.bounds);
@@ -489,8 +489,9 @@
                                          SubmissionSource source) {
   DCHECK(MaybeWasOwnedByFrame(form, unsafe_render_frame()));
   FormData form_data;
-  if (!form_util::ExtractFormData(form, *field_data_manager_.get(), &form_data))
+  if (!form_util::ExtractFormData(form, field_data_manager(), &form_data)) {
     return;
+  }
   FireHostSubmitEvents(form_data, known_success, source);
 }
 
@@ -546,6 +547,10 @@
   ClearPreviewedForm();
 
   const auto input_element = element.DynamicTo<WebInputElement>();
+  if (!input_element.IsNull()) {
+    password_autofill_agent_->UpdateStateForTextChange(input_element);
+  }
+
   if (password_generation_agent_ && !input_element.IsNull() &&
       password_generation_agent_->TextDidChangeInTextField(input_element)) {
     is_popup_possibly_visible_ = true;
@@ -567,7 +572,7 @@
   FormData form;
   FormFieldData field;
   if (FindFormAndFieldForFormControlElement(
-          element, field_data_manager_.get(),
+          element, field_data_manager(),
           MaybeExtractDatalist({ExtractOption::kBounds}), &form, &field)) {
     if (auto* autofill_driver = unsafe_autofill_driver()) {
       autofill_driver->TextFieldDidChange(form, field, field.bounds,
@@ -641,7 +646,7 @@
   if (updated_form_element.IsNull()) {
     CollectFormlessElements(&updated_form_data);
   } else {
-    form_util::ExtractFormData(updated_form_element, *field_data_manager_.get(),
+    form_util::ExtractFormData(updated_form_element, field_data_manager(),
                                &updated_form_data);
   }
   // Deep-compare forms, but don't take into account the fields' values.
@@ -940,7 +945,7 @@
 
   return form_util::UnownedFormElementsToFormData(
       control_elements, iframe_elements, nullptr, document,
-      field_data_manager_.get(), extract_options, output,
+      field_data_manager(), extract_options, output,
       /*field=*/nullptr);
 }
 
@@ -1062,7 +1067,7 @@
   FormData form;
   FormFieldData field;
   if (!FindFormAndFieldForFormControlElement(
-          element, field_data_manager_.get(),
+          element, field_data_manager(),
           MaybeExtractDatalist({ExtractOption::kBounds}), &form, &field)) {
     // If we didn't find the cached form, at least let autocomplete have a shot
     // at providing suggestions.
@@ -1142,8 +1147,8 @@
   if (WebFormElement fe = FindFormByRendererId(doc, form_id); !fe.IsNull()) {
     FormData form;
     if (WebFormElementToFormData(fe, WebFormControlElement(),
-                                 field_data_manager_.get(), extract_options,
-                                 &form, nullptr)) {
+                                 field_data_manager(), extract_options, &form,
+                                 nullptr)) {
       std::move(callback).Run(std::move(form));
       return;
     }
@@ -1185,7 +1190,7 @@
     return;
   }
   FormCache::UpdateFormCacheResult cache =
-      form_cache_->UpdateFormCache(field_data_manager_.get());
+      form_cache_->UpdateFormCache(field_data_manager());
   content::RenderFrame* render_frame = unsafe_render_frame();
   if (render_frame) {
     form_issues::MaybeEmitFormIssuesToDevtools(*render_frame->GetWebFrame(),
@@ -1304,7 +1309,7 @@
   // found, notify the driver that the form was modified dynamically.
   FormData form;
   FormFieldData field;
-  if (FindFormAndFieldForFormControlElement(element, field_data_manager_.get(),
+  if (FindFormAndFieldForFormControlElement(element, field_data_manager(),
                                             /*extract_options=*/{}, &form,
                                             &field) &&
       !field.options.empty()) {
@@ -1438,7 +1443,7 @@
   }
   FormData form;
   FormFieldData field;
-  if (FindFormAndFieldForFormControlElement(element, field_data_manager_.get(),
+  if (FindFormAndFieldForFormControlElement(element, field_data_manager(),
                                             /*extract_options=*/{}, &form,
                                             &field)) {
     if (auto* autofill_driver = unsafe_autofill_driver()) {
@@ -1499,7 +1504,7 @@
       FormData form_data;
       FormFieldData field;
       if (FindFormAndFieldForFormControlElement(
-              element, field_data_manager_.get(),
+              element, field_data_manager(),
               MaybeExtractDatalist({ExtractOption::kBounds}), &form_data,
               &field)) {
         if (auto* autofill_driver = unsafe_autofill_driver()) {
@@ -1590,8 +1595,8 @@
 absl::optional<FormData> AutofillAgent::GetSubmittedForm() const {
   if (!last_interacted_form_.IsNull()) {
     FormData form;
-    if (form_util::ExtractFormData(last_interacted_form_,
-                                   *field_data_manager_.get(), &form)) {
+    if (form_util::ExtractFormData(last_interacted_form_, field_data_manager(),
+                                   &form)) {
       return absl::make_optional(form);
     } else if (provisionally_saved_form_.has_value()) {
       return absl::make_optional(provisionally_saved_form_.value());
@@ -1636,8 +1641,7 @@
 
   last_interacted_form_ = form;
   provisionally_saved_form_ = absl::make_optional<FormData>();
-  if (!form_util::ExtractFormData(last_interacted_form_,
-                                  *field_data_manager_.get(),
+  if (!form_util::ExtractFormData(last_interacted_form_, field_data_manager(),
                                   &provisionally_saved_form_.value())) {
     provisionally_saved_form_.reset();
   }
diff --git a/components/autofill/content/renderer/autofill_agent.h b/components/autofill/content/renderer/autofill_agent.h
index 7b539b5..7ce4712 100644
--- a/components/autofill/content/renderer/autofill_agent.h
+++ b/components/autofill/content/renderer/autofill_agent.h
@@ -179,6 +179,10 @@
     return last_queried_element_;
   }
 
+  FieldDataManager& field_data_manager() const {
+    return *field_data_manager_.get();
+  }
+
  protected:
   // blink::WebAutofillClient:
   void DidAddOrRemoveFormRelatedElementsDynamically() override;
@@ -462,7 +466,12 @@
   // titles for unowned forms).
   bool is_heavy_form_data_scraping_enabled_ = false;
 
-  const scoped_refptr<FieldDataManager> field_data_manager_;
+  // Map WebFormControlElement to the pair of:
+  // 1) The most recent text that user typed or autofilled in input elements.
+  // Used for storing username/password before JavaScript changes them.
+  // 2) Field properties mask, i.e. whether the field was autofilled, modified
+  // by user, etc. (see FieldPropertiesMask).
+  scoped_refptr<FieldDataManager> field_data_manager_;
 
   // This notifier is used to avoid sending redundant messages to the password
   // manager driver mojo interface.
diff --git a/components/autofill/content/renderer/autofill_agent_browsertest.cc b/components/autofill/content/renderer/autofill_agent_browsertest.cc
index c939e05..b28c37a 100644
--- a/components/autofill/content/renderer/autofill_agent_browsertest.cc
+++ b/components/autofill/content/renderer/autofill_agent_browsertest.cc
@@ -467,7 +467,8 @@
   EXPECT_EQ(1U, forms.size());
   FormData form;
   EXPECT_TRUE(form_util::WebFormElementToFormData(
-      forms[0], blink::WebFormControlElement(), nullptr,
+      forms[0], blink::WebFormControlElement(),
+      *base::MakeRefCounted<FieldDataManager>(),
       {form_util::ExtractOption::kValue}, &form, nullptr));
 
   ASSERT_TRUE(autofill_agent_->focused_element().IsNull());
diff --git a/components/autofill/content/renderer/form_autofill_issues_browsertest.cc b/components/autofill/content/renderer/form_autofill_issues_browsertest.cc
index f829f89..68bd27a 100644
--- a/components/autofill/content/renderer/form_autofill_issues_browsertest.cc
+++ b/components/autofill/content/renderer/form_autofill_issues_browsertest.cc
@@ -7,6 +7,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "components/autofill/content/renderer/form_autofill_util.h"
 #include "components/autofill/content/renderer/test_utils.h"
+#include "components/autofill/core/common/field_data_manager.h"
 #include "components/autofill/core/common/form_field_data.h"
 #include "content/public/test/render_view_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -211,8 +212,8 @@
   FormData form_data;
   form_util::WebFormElementToFormData(
       WebFormElementFromHTML(kHtml), WebFormControlElement(),
-      /*field_data_manager=*/nullptr, {form_util::ExtractOption::kValue},
-      &form_data, nullptr);
+      *base::MakeRefCounted<FieldDataManager>(),
+      {form_util::ExtractOption::kValue}, &form_data, nullptr);
 
   std::vector<blink::WebAutofillClient::FormIssue> form_issues =
       CheckForLabelsWithIncorrectForAttribute(web_frame->GetDocument(),
@@ -236,8 +237,8 @@
   FormData form_data;
   form_util::WebFormElementToFormData(
       WebFormElementFromHTML(kHtml), WebFormControlElement(),
-      /*field_data_manager=*/nullptr, {form_util::ExtractOption::kValue},
-      &form_data, nullptr);
+      *base::MakeRefCounted<FieldDataManager>(),
+      {form_util::ExtractOption::kValue}, &form_data, nullptr);
 
   std::vector<blink::WebAutofillClient::FormIssue> form_issues =
       CheckForLabelsWithIncorrectForAttribute(web_frame->GetDocument(),
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc
index 68104cb..aaa307be 100644
--- a/components/autofill/content/renderer/form_autofill_util.cc
+++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -1381,7 +1381,7 @@
     const blink::WebFormControlElement* form_control_element,
     const WebVector<WebFormControlElement>& control_elements,
     const std::vector<blink::WebElement>& iframe_elements,
-    const FieldDataManager* field_data_manager,
+    const FieldDataManager& field_data_manager,
     DenseSet<ExtractOption> extract_options,
     FormData* form,
     FormFieldData* optional_field) {
@@ -1419,7 +1419,7 @@
     form->fields.emplace_back();
     shadow_fields.emplace_back();
     WebFormControlElementToFormField(
-        form_element, control_element, field_data_manager, extract_options,
+        form_element, control_element, &field_data_manager, extract_options,
         &form->fields.back(), &shadow_fields.back());
     fields_extracted[i] = true;
 
@@ -1534,7 +1534,7 @@
 bool ScriptModifiedUsernameAcceptable(
     const std::u16string& value,
     const std::u16string& typed_value,
-    const FieldDataManager* field_data_manager) {
+    const FieldDataManager& field_data_manager) {
   // The minimal size of a field value that will be substring-matched.
   constexpr size_t kMinMatchSize = 3u;
   const auto lowercase = base::i18n::ToLower(value);
@@ -1552,7 +1552,7 @@
 
   // If the page-generated value comes from user typed or autofilled values in
   // other fields, that's also likely OK.
-  return field_data_manager->FindMatchedValue(value);
+  return field_data_manager.FindMatchedValue(value);
 }
 
 // Build a map from entries in |form_control_renderer_ids| to their indices,
@@ -1715,7 +1715,7 @@
                      const FieldDataManager& field_data_manager,
                      FormData* data) {
   return WebFormElementToFormData(
-      form_element, WebFormControlElement(), &field_data_manager,
+      form_element, WebFormControlElement(), field_data_manager,
       {ExtractOption::kValue, ExtractOption::kOptionText,
        ExtractOption::kOptions},
       data,
@@ -2143,7 +2143,7 @@
     // potential usernames, as long as the |value| is not deemed acceptable.
     if (field->form_control_type == FormControlType::kInputPassword ||
         !ScriptModifiedUsernameAcceptable(field->value, user_input,
-                                          field_data_manager)) {
+                                          *field_data_manager)) {
       field->user_input = user_input;
     }
   }
@@ -2152,7 +2152,7 @@
 bool WebFormElementToFormData(
     const blink::WebFormElement& form_element,
     const blink::WebFormControlElement& form_control_element,
-    const FieldDataManager* field_data_manager,
+    const FieldDataManager& field_data_manager,
     DenseSet<ExtractOption> extract_options,
     FormData* form,
     FormFieldData* field) {
@@ -2245,7 +2245,7 @@
     const std::vector<blink::WebElement>& iframe_elements,
     const blink::WebFormControlElement* element,
     const blink::WebDocument& document,
-    const FieldDataManager* field_data_manager,
+    const FieldDataManager& field_data_manager,
     DenseSet<ExtractOption> extract_options,
     FormData* form,
     FormFieldData* field) {
@@ -2265,7 +2265,7 @@
 
 bool FindFormAndFieldForFormControlElement(
     const WebFormControlElement& element,
-    const FieldDataManager* field_data_manager,
+    const FieldDataManager& field_data_manager,
     DenseSet<ExtractOption> extract_options,
     FormData* form,
     FormFieldData* field) {
diff --git a/components/autofill/content/renderer/form_autofill_util.h b/components/autofill/content/renderer/form_autofill_util.h
index 91b7b4c..c811c84 100644
--- a/components/autofill/content/renderer/form_autofill_util.h
+++ b/components/autofill/content/renderer/form_autofill_util.h
@@ -273,7 +273,7 @@
 bool WebFormElementToFormData(
     const blink::WebFormElement& form_element,
     const blink::WebFormControlElement& form_control_element,
-    const FieldDataManager* field_data_manager,
+    const FieldDataManager& field_data_manager,
     DenseSet<ExtractOption> extract_options,
     FormData* form,
     FormFieldData* field);
@@ -314,7 +314,7 @@
     const std::vector<blink::WebElement>& iframe_elements,
     const blink::WebFormControlElement* element,
     const blink::WebDocument& document,
-    const FieldDataManager* field_data_manager,
+    const FieldDataManager& field_data_manager,
     DenseSet<ExtractOption> extract_options,
     FormData* form,
     FormFieldData* field);
@@ -326,7 +326,7 @@
 // is not found or cannot be serialized.
 bool FindFormAndFieldForFormControlElement(
     const blink::WebFormControlElement& element,
-    const FieldDataManager* field_data_manager,
+    const FieldDataManager& field_data_manager,
     DenseSet<ExtractOption> extract_options,
     FormData* form,
     FormFieldData* field);
diff --git a/components/autofill/content/renderer/form_autofill_util_browsertest.cc b/components/autofill/content/renderer/form_autofill_util_browsertest.cc
index dc278e8..d6be6c6 100644
--- a/components/autofill/content/renderer/form_autofill_util_browsertest.cc
+++ b/components/autofill/content/renderer/form_autofill_util_browsertest.cc
@@ -210,7 +210,7 @@
   FormData form_data;
   ASSERT_TRUE(WebFormElementToFormData(
       GetFormElementById(GetMainFrame()->GetDocument(), "form-id"),
-      WebFormControlElement(), /*field_data_manager=*/nullptr,
+      WebFormControlElement(), *base::MakeRefCounted<FieldDataManager>(),
       {ExtractOption::kOptions}, &form_data, /*field=*/nullptr));
   EXPECT_EQ(form_data.name, u"form-name");
   EXPECT_EQ(form_data.id_attribute, u"form-id");
@@ -242,8 +242,9 @@
 
   FormData form_data;
   ASSERT_TRUE(WebFormElementToFormData(
-      web_form, WebFormControlElement(), /*field_data_manager=*/nullptr,
-      {ExtractOption::kOptions}, &form_data, /*field=*/nullptr));
+      web_form, WebFormControlElement(),
+      *base::MakeRefCounted<FieldDataManager>(), {ExtractOption::kOptions},
+      &form_data, /*field=*/nullptr));
 
   ASSERT_EQ(form_data.fields.size(), 1u);
   ASSERT_EQ(form_data.fields[0].options.size(), 1u);
@@ -571,7 +572,8 @@
   autofill::FormData target;
   EXPECT_TRUE(UnownedFormElementsToFormData(
       control_elements, iframe_elements, /*element=*/nullptr,
-      web_frame->GetDocument(), nullptr, /*extract_options=*/{}, &target,
+      web_frame->GetDocument(), *base::MakeRefCounted<FieldDataManager>(),
+      /*extract_options=*/{}, &target,
       /*field=*/nullptr));
   const struct {
     const char16_t* const name;
@@ -612,7 +614,8 @@
   autofill::FormData target;
   EXPECT_TRUE(UnownedFormElementsToFormData(
       control_elements, iframe_elements, /*element=*/nullptr,
-      web_frame->GetDocument(), nullptr, /*extract_options=*/{}, &target,
+      web_frame->GetDocument(), *base::MakeRefCounted<FieldDataManager>(),
+      /*extract_options=*/{}, &target,
       /*field=*/nullptr));
   const struct {
     const char16_t* const name;
@@ -655,7 +658,8 @@
   autofill::FormData target;
   EXPECT_TRUE(UnownedFormElementsToFormData(
       control_elements, iframe_elements, /*element=*/nullptr,
-      web_frame->GetDocument(), nullptr, /*extract_options=*/{}, &target,
+      web_frame->GetDocument(), *base::MakeRefCounted<FieldDataManager>(),
+      /*extract_options=*/{}, &target,
       /*field=*/nullptr));
   ASSERT_EQ(2u, target.fields.size());
   EXPECT_EQ(u"name1", target.fields[0].name);
@@ -910,10 +914,11 @@
   auto web_form = GetFormElementById(doc, "form1");
 
   FormData form_data;
-  ASSERT_TRUE(WebFormElementToFormData(web_form, WebFormControlElement(),
-                                       /*field_data_manager=*/nullptr,
-                                       {ExtractOption::kValue}, &form_data,
-                                       /*field=*/nullptr));
+  ASSERT_TRUE(
+      WebFormElementToFormData(web_form, WebFormControlElement(),
+                               *base::MakeRefCounted<FieldDataManager>(),
+                               {ExtractOption::kValue}, &form_data,
+                               /*field=*/nullptr));
 
   EXPECT_FALSE(form_data.is_action_empty);
 }
@@ -924,10 +929,11 @@
   auto web_form = GetFormElementById(doc, "form1");
 
   FormData form_data;
-  ASSERT_TRUE(WebFormElementToFormData(web_form, WebFormControlElement(),
-                                       /*field_data_manager=*/nullptr,
-                                       {ExtractOption::kValue}, &form_data,
-                                       /*field=*/nullptr));
+  ASSERT_TRUE(
+      WebFormElementToFormData(web_form, WebFormControlElement(),
+                               *base::MakeRefCounted<FieldDataManager>(),
+                               {ExtractOption::kValue}, &form_data,
+                               /*field=*/nullptr));
 
   EXPECT_TRUE(form_data.is_action_empty);
 }
@@ -939,8 +945,8 @@
 
   FormData form_data;
   ASSERT_TRUE(FindFormAndFieldForFormControlElement(
-      web_control, /*field_data_manager=*/nullptr, {ExtractOption::kBounds},
-      &form_data,
+      web_control, *base::MakeRefCounted<FieldDataManager>(),
+      {ExtractOption::kBounds}, &form_data,
       /*field=*/nullptr));
 
   EXPECT_FALSE(form_data.fields.back().bounds.IsEmpty());
@@ -953,8 +959,8 @@
 
   FormData form_data;
   ASSERT_TRUE(FindFormAndFieldForFormControlElement(
-      web_control, /*field_data_manager=*/nullptr, /*extract_options=*/{},
-      &form_data,
+      web_control, *base::MakeRefCounted<FieldDataManager>(),
+      /*extract_options=*/{}, &form_data,
       /*field=*/nullptr));
 
   EXPECT_TRUE(form_data.fields.back().bounds.IsEmpty());
@@ -967,8 +973,8 @@
 
   FormData form_data;
   ASSERT_TRUE(FindFormAndFieldForFormControlElement(
-      web_control, /*field_data_manager=*/nullptr, {ExtractOption::kBounds},
-      &form_data,
+      web_control, *base::MakeRefCounted<FieldDataManager>(),
+      {ExtractOption::kBounds}, &form_data,
       /*field=*/nullptr));
 
   EXPECT_FALSE(form_data.fields.back().bounds.IsEmpty());
@@ -1016,8 +1022,8 @@
   FormData form_data;
   FormFieldData form_field_data;
   ASSERT_TRUE(FindFormAndFieldForFormControlElement(
-      web_control, /*field_data_manager=*/nullptr, {ExtractOption::kDatalist},
-      &form_data, &form_field_data));
+      web_control, *base::MakeRefCounted<FieldDataManager>(),
+      {ExtractOption::kDatalist}, &form_data, &form_field_data));
 
   auto& options = form_data.fields.back().datalist_options;
   ASSERT_EQ(options.size(), 2u);
@@ -1038,8 +1044,8 @@
   FormData form_data;
   FormFieldData form_field_data;
   ASSERT_TRUE(FindFormAndFieldForFormControlElement(
-      web_control, /*field_data_manager=*/nullptr, /*extract_options=*/{},
-      &form_data, &form_field_data));
+      web_control, *base::MakeRefCounted<FieldDataManager>(),
+      /*extract_options=*/{}, &form_data, &form_field_data));
   EXPECT_TRUE(form_data.fields.back().datalist_options.empty());
 }
 
@@ -1475,16 +1481,18 @@
         form_util::GetUnownedIframeElements(doc);
     ASSERT_TRUE(UnownedFormElementsToFormData(
         control_elements, iframe_elements, /*element=*/nullptr, doc,
-        /*field_data_manager=*/nullptr, /*extract_options=*/{}, &form_data,
+        *base::MakeRefCounted<FieldDataManager>(),
+        /*extract_options=*/{}, &form_data,
         /*field=*/nullptr));
     host_form = FormRendererId();
   } else {  // Real <form>.
     ASSERT_GT(std::strlen(test_case.form_id), 0u);
     auto form_element = GetFormElementById(doc, test_case.form_id);
-    ASSERT_TRUE(WebFormElementToFormData(form_element, WebFormControlElement(),
-                                         /*field_data_manager=*/nullptr,
-                                         /*extract_options=*/{}, &form_data,
-                                         /*field=*/nullptr));
+    ASSERT_TRUE(
+        WebFormElementToFormData(form_element, WebFormControlElement(),
+                                 *base::MakeRefCounted<FieldDataManager>(),
+                                 /*extract_options=*/{}, &form_data,
+                                 /*field=*/nullptr));
     host_form = GetFormRendererId(form_element);
   }
 
@@ -1657,10 +1665,11 @@
 
   auto form_element = GetFormElementById(doc, "form");
   FormData form_data;
-  ASSERT_TRUE(WebFormElementToFormData(form_element, WebFormControlElement(),
-                                       /*field_data_manager=*/nullptr,
-                                       /*extract_options=*/{}, &form_data,
-                                       /*field=*/nullptr));
+  ASSERT_TRUE(
+      WebFormElementToFormData(form_element, WebFormControlElement(),
+                               *base::MakeRefCounted<FieldDataManager>(),
+                               /*extract_options=*/{}, &form_data,
+                               /*field=*/nullptr));
   EXPECT_EQ(form_data.fields.size(),
             IsAutofillingSelectListEnabled() ? 2u : 1u);
 
@@ -1705,10 +1714,11 @@
   WebFormElement form = GetFormElementById(doc, "f");
   {
     FormData form_data;
-    ASSERT_TRUE(WebFormElementToFormData(form, WebFormControlElement(),
-                                         /*field_data_manager_=*/nullptr,
-                                         /*extract_options=*/{}, &form_data,
-                                         /*field=*/nullptr));
+    ASSERT_TRUE(
+        WebFormElementToFormData(form, WebFormControlElement(),
+                                 *base::MakeRefCounted<FieldDataManager>(),
+                                 /*extract_options=*/{}, &form_data,
+                                 /*field=*/nullptr));
     EXPECT_EQ(form_data.fields.size(), kMaxExtractableFields - 1);
     EXPECT_EQ(form_data.child_frames.size(), kMaxExtractableChildFrames);
   }
@@ -1719,10 +1729,11 @@
   for (int i = 0; i < 3; ++i) {
     CreateFormElement("iframe");
     FormData form_data;
-    ASSERT_TRUE(WebFormElementToFormData(form, WebFormControlElement(),
-                                         /*field_data_manager=*/nullptr,
-                                         /*extract_options=*/{}, &form_data,
-                                         /*field=*/nullptr));
+    ASSERT_TRUE(
+        WebFormElementToFormData(form, WebFormControlElement(),
+                                 *base::MakeRefCounted<FieldDataManager>(),
+                                 /*extract_options=*/{}, &form_data,
+                                 /*field=*/nullptr));
     EXPECT_EQ(form_data.fields.size(), kMaxExtractableFields - 1);
     EXPECT_TRUE(form_data.child_frames.empty());
   }
@@ -1752,10 +1763,11 @@
   WebFormElement form = GetFormElementById(doc, "f");
   {
     FormData form_data;
-    ASSERT_TRUE(WebFormElementToFormData(form, WebFormControlElement(),
-                                         /*field_data_manager=*/nullptr,
-                                         /*extract_options=*/{}, &form_data,
-                                         /*field=*/nullptr));
+    ASSERT_TRUE(
+        WebFormElementToFormData(form, WebFormControlElement(),
+                                 *base::MakeRefCounted<FieldDataManager>(),
+                                 /*extract_options=*/{}, &form_data,
+                                 /*field=*/nullptr));
     EXPECT_EQ(form_data.fields.size(), kMaxExtractableFields - 1);
     EXPECT_EQ(form_data.child_frames.size(), kMaxExtractableChildFrames);
   }
@@ -1767,10 +1779,11 @@
     SCOPED_TRACE(base::NumberToString(i));
     CreateFormElement("input");
     FormData form_data;
-    ASSERT_FALSE(WebFormElementToFormData(form, WebFormControlElement(),
-                                          nullptr, /*extract_options=*/{},
-                                          &form_data,
-                                          /*field=*/nullptr));
+    ASSERT_FALSE(
+        WebFormElementToFormData(form, WebFormControlElement(),
+                                 *base::MakeRefCounted<FieldDataManager>(),
+                                 /*extract_options=*/{}, &form_data,
+                                 /*field=*/nullptr));
     EXPECT_TRUE(form_data.fields.empty());
     EXPECT_TRUE(form_data.child_frames.empty());
   }
diff --git a/components/autofill/content/renderer/form_cache.cc b/components/autofill/content/renderer/form_cache.cc
index 0f221c5d..1c61288 100644
--- a/components/autofill/content/renderer/form_cache.cc
+++ b/components/autofill/content/renderer/form_cache.cc
@@ -120,7 +120,7 @@
 FormCache::~FormCache() = default;
 
 FormCache::UpdateFormCacheResult FormCache::UpdateFormCache(
-    const FieldDataManager* field_data_manager) {
+    const FieldDataManager& field_data_manager) {
   initial_checked_state_.clear();
   initial_select_values_.clear();
   initial_selectlist_values_.clear();
diff --git a/components/autofill/content/renderer/form_cache.h b/components/autofill/content/renderer/form_cache.h
index dae64e4..e49a5c8 100644
--- a/components/autofill/content/renderer/form_cache.h
+++ b/components/autofill/content/renderer/form_cache.h
@@ -85,7 +85,7 @@
   // Updates |extracted_forms_| to contain the forms that are currently in the
   // DOM.
   UpdateFormCacheResult UpdateFormCache(
-      const FieldDataManager* field_data_manager);
+      const FieldDataManager& field_data_manager);
 
   // Clears the values of all input elements in the section of the form that
   // contains |element|.  Returns false if the form is not found.
diff --git a/components/autofill/content/renderer/form_cache_browsertest.cc b/components/autofill/content/renderer/form_cache_browsertest.cc
index ef4de62..670e391 100644
--- a/components/autofill/content/renderer/form_cache_browsertest.cc
+++ b/components/autofill/content/renderer/form_cache_browsertest.cc
@@ -14,6 +14,7 @@
 #include "components/autofill/content/renderer/form_cache_test_api.h"
 #include "components/autofill/content/renderer/test_utils.h"
 #include "components/autofill/core/common/autofill_features.h"
+#include "components/autofill/core/common/field_data_manager.h"
 #include "components/autofill/core/common/form_field_data.h"
 #include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
 #include "content/public/test/render_view_test.h"
@@ -63,6 +64,10 @@
   return nullptr;
 }
 
+FormCache::UpdateFormCacheResult UpdateFormCache(FormCache& form_cache) {
+  return form_cache.UpdateFormCache(*base::MakeRefCounted<FieldDataManager>());
+}
+
 class FormCacheBrowserTest : public content::RenderViewTest {
  public:
   FormCacheBrowserTest() {
@@ -98,7 +103,7 @@
   )");
 
   FormCache form_cache(GetMainFrame());
-  FormCache::UpdateFormCacheResult forms = form_cache.UpdateFormCache(nullptr);
+  FormCache::UpdateFormCacheResult forms = UpdateFormCache(form_cache);
 
   EXPECT_THAT(forms.updated_forms,
               UnorderedElementsAre(HasId(FormRendererId()), HasName("form1")));
@@ -131,7 +136,7 @@
   )");
 
   FormCache form_cache(GetMainFrame());
-  FormCache::UpdateFormCacheResult forms = form_cache.UpdateFormCache(nullptr);
+  FormCache::UpdateFormCacheResult forms = UpdateFormCache(form_cache);
 
   EXPECT_THAT(forms.updated_forms,
               UnorderedElementsAre(HasId(FormRendererId()), HasName("form1"),
@@ -151,7 +156,7 @@
     document.getElementById("form2").innerHTML = "";
   )");
 
-  forms = form_cache.UpdateFormCache(nullptr);
+  forms = UpdateFormCache(form_cache);
 
   EXPECT_TRUE(forms.updated_forms.empty());
   EXPECT_THAT(forms.removed_forms,
@@ -161,7 +166,7 @@
     document.getElementById("unowned_element").remove();
   )");
 
-  forms = form_cache.UpdateFormCache(nullptr);
+  forms = UpdateFormCache(form_cache);
 
   EXPECT_TRUE(forms.updated_forms.empty());
   EXPECT_THAT(forms.removed_forms, ElementsAre(FormRendererId()));
@@ -174,7 +179,7 @@
     `;
   )");
 
-  forms = form_cache.UpdateFormCache(nullptr);
+  forms = UpdateFormCache(form_cache);
 
   EXPECT_THAT(forms.updated_forms, ElementsAre(HasName("form2")));
   EXPECT_TRUE(forms.removed_forms.empty());
@@ -188,7 +193,7 @@
     `;
   )");
 
-  forms = form_cache.UpdateFormCache(nullptr);
+  forms = UpdateFormCache(form_cache);
 
   EXPECT_THAT(forms.updated_forms, ElementsAre(HasName("form2")));
   EXPECT_TRUE(forms.removed_forms.empty());
@@ -202,8 +207,7 @@
   )");
 
   FormCache form_cache(GetMainFrame());
-  FormCache::UpdateFormCacheResult forms =
-      form_cache.UpdateFormCache(/*field_data_manager=*/nullptr);
+  FormCache::UpdateFormCacheResult forms = UpdateFormCache(form_cache);
   EXPECT_THAT(forms.updated_forms,
               UnorderedElementsAre(HasName("f"), HasName("g")));
   EXPECT_TRUE(forms.removed_forms.empty());
@@ -212,7 +216,7 @@
     document.getElementById("label").innerHTML = "Last Name";
   )");
 
-  forms = form_cache.UpdateFormCache(/*field_data_manager=*/nullptr);
+  forms = UpdateFormCache(form_cache);
   EXPECT_THAT(forms.updated_forms, ElementsAre(HasName("g")));
   EXPECT_TRUE(forms.removed_forms.empty());
 }
@@ -231,8 +235,7 @@
       GetFrameToken(GetMainFrame()->GetDocument(), "frame2");
 
   FormCache form_cache(GetMainFrame());
-  FormCache::UpdateFormCacheResult forms =
-      form_cache.UpdateFormCache(/*field_data_manager=*/nullptr);
+  FormCache::UpdateFormCacheResult forms = UpdateFormCache(form_cache);
 
   EXPECT_THAT(forms.updated_forms,
               UnorderedElementsAre(HasId(FormRendererId()), HasName("form1")));
@@ -261,14 +264,13 @@
   )");
 
   FormCache form_cache(GetMainFrame());
-  FormCache::UpdateFormCacheResult forms =
-      form_cache.UpdateFormCache(/*field_data_manager=*/nullptr);
+  FormCache::UpdateFormCacheResult forms = UpdateFormCache(form_cache);
 
   EXPECT_THAT(forms.updated_forms,
               UnorderedElementsAre(HasId(FormRendererId()), HasName("form1")));
   EXPECT_TRUE(forms.removed_forms.empty());
 
-  forms = form_cache.UpdateFormCache(nullptr);
+  forms = UpdateFormCache(form_cache);
   // As nothing has changed, there are no new or removed forms.
   EXPECT_TRUE(forms.updated_forms.empty());
   EXPECT_TRUE(forms.removed_forms.empty());
@@ -283,14 +285,13 @@
   )");
 
   FormCache form_cache(GetMainFrame());
-  FormCache::UpdateFormCacheResult forms =
-      form_cache.UpdateFormCache(/*field_data_manager=*/nullptr);
+  FormCache::UpdateFormCacheResult forms = UpdateFormCache(form_cache);
 
   EXPECT_THAT(forms.updated_forms,
               UnorderedElementsAre(HasId(FormRendererId()), HasName("form1")));
   EXPECT_TRUE(forms.removed_forms.empty());
 
-  forms = form_cache.UpdateFormCache(nullptr);
+  forms = UpdateFormCache(form_cache);
   // As nothing has changed, there are no new or removed forms.
   EXPECT_TRUE(forms.updated_forms.empty());
   EXPECT_TRUE(forms.removed_forms.empty());
@@ -320,8 +321,7 @@
   ASSERT_LE(GetSize(iframe3), 0);
 
   FormCache form_cache(GetMainFrame());
-  FormCache::UpdateFormCacheResult forms =
-      form_cache.UpdateFormCache(/*field_data_manager=*/nullptr);
+  FormCache::UpdateFormCacheResult forms = UpdateFormCache(form_cache);
   EXPECT_THAT(forms.updated_forms,
               UnorderedElementsAre(HasId(FormRendererId()), HasName("form1")));
   EXPECT_TRUE(forms.removed_forms.empty());
@@ -334,7 +334,7 @@
   ASSERT_GT(GetSize(iframe2), 0);
   ASSERT_GT(GetSize(iframe3), 0);
 
-  forms = form_cache.UpdateFormCache(nullptr);
+  forms = UpdateFormCache(form_cache);
   EXPECT_TRUE(forms.updated_forms.empty());
   EXPECT_TRUE(forms.removed_forms.empty());
 
@@ -345,7 +345,7 @@
   ASSERT_LE(GetSize(iframe2), 0);
   ASSERT_LE(GetSize(iframe3), 0);
 
-  forms = form_cache.UpdateFormCache(nullptr);
+  forms = UpdateFormCache(form_cache);
   EXPECT_TRUE(forms.updated_forms.empty());
   EXPECT_TRUE(forms.removed_forms.empty());
 }
@@ -361,8 +361,7 @@
   )");
 
   FormCache form_cache(GetMainFrame());
-  FormCache::UpdateFormCacheResult forms =
-      form_cache.UpdateFormCache(/*field_data_manager=*/nullptr);
+  FormCache::UpdateFormCacheResult forms = UpdateFormCache(form_cache);
   EXPECT_THAT(forms.updated_forms,
               UnorderedElementsAre(HasId(FormRendererId()), HasName("form1")));
   EXPECT_TRUE(forms.removed_forms.empty());
@@ -382,7 +381,7 @@
     document.body.appendChild(new_input_2);
   )");
 
-  forms = form_cache.UpdateFormCache(nullptr);
+  forms = UpdateFormCache(form_cache);
   EXPECT_THAT(forms.updated_forms,
               UnorderedElementsAre(HasId(FormRendererId()), HasName("form1")));
   EXPECT_TRUE(forms.removed_forms.empty());
@@ -465,8 +464,7 @@
   )");
 
   FormCache form_cache(GetMainFrame());
-  FormCache::UpdateFormCacheResult forms =
-      form_cache.UpdateFormCache(/*field_data_manager=*/nullptr);
+  FormCache::UpdateFormCacheResult forms = UpdateFormCache(form_cache);
 
   EXPECT_THAT(forms.updated_forms, ElementsAre(HasId(FormRendererId())));
   EXPECT_TRUE(forms.removed_forms.empty());
@@ -505,8 +503,7 @@
   focus_test_utils_->FocusElement("fname");
 
   FormCache form_cache(GetMainFrame());
-  FormCache::UpdateFormCacheResult forms =
-      form_cache.UpdateFormCache(/*field_data_manager=*/nullptr);
+  FormCache::UpdateFormCacheResult forms = UpdateFormCache(form_cache);
 
   EXPECT_THAT(forms.updated_forms,
               UnorderedElementsAre(HasId(FormRendererId()), HasName("myForm")));
@@ -563,8 +560,7 @@
   )");
 
   FormCache form_cache(GetMainFrame());
-  FormCache::UpdateFormCacheResult forms =
-      form_cache.UpdateFormCache(/*field_data_manager=*/nullptr);
+  FormCache::UpdateFormCacheResult forms = UpdateFormCache(form_cache);
 
   EXPECT_THAT(forms.updated_forms, ElementsAre(HasId(FormRendererId())));
   EXPECT_TRUE(forms.removed_forms.empty());
@@ -580,7 +576,7 @@
     }
   )");
 
-  forms = form_cache.UpdateFormCache(/*field_data_manager=*/nullptr);
+  forms = UpdateFormCache(form_cache);
   EXPECT_TRUE(forms.updated_forms.empty());
   EXPECT_THAT(forms.removed_forms, ElementsAre(FormRendererId()));
   EXPECT_EQ(0u, test_api(form_cache).initial_select_values_size());
@@ -603,8 +599,7 @@
   auto last_name_element = GetFormControlElementById(doc, "lname");
 
   FormCache form_cache(GetMainFrame());
-  FormCache::UpdateFormCacheResult forms =
-      form_cache.UpdateFormCache(/*field_data_manager=*/nullptr);
+  FormCache::UpdateFormCacheResult forms = UpdateFormCache(form_cache);
 
   EXPECT_THAT(forms.updated_forms, ElementsAre(HasName("myForm")));
   EXPECT_TRUE(forms.removed_forms.empty());
@@ -634,8 +629,7 @@
   LoadHTML(R"(<form></form>)");
 
   FormCache form_cache(GetMainFrame());
-  FormCache::UpdateFormCacheResult forms =
-      form_cache.UpdateFormCache(/*field_data_manager=*/nullptr);
+  FormCache::UpdateFormCacheResult forms = UpdateFormCache(form_cache);
 
   EXPECT_TRUE(forms.updated_forms.empty());
   EXPECT_TRUE(forms.removed_forms.empty());
@@ -656,8 +650,7 @@
   LoadHTML(html.c_str());
 
   FormCache form_cache(GetMainFrame());
-  FormCache::UpdateFormCacheResult forms =
-      form_cache.UpdateFormCache(/*field_data_manager=*/nullptr);
+  FormCache::UpdateFormCacheResult forms = UpdateFormCache(form_cache);
 
   EXPECT_EQ(forms.updated_forms.size(), kMaxExtractableFields);
   EXPECT_TRUE(forms.removed_forms.empty());
@@ -680,8 +673,7 @@
             GetMainFrame()->GetDocument().Forms().size());
 
   FormCache form_cache(GetMainFrame());
-  FormCache::UpdateFormCacheResult forms =
-      form_cache.UpdateFormCache(/*field_data_manager=*/nullptr);
+  FormCache::UpdateFormCacheResult forms = UpdateFormCache(form_cache);
 
   EXPECT_EQ(kMaxExtractableFields, forms.updated_forms.size());
   EXPECT_TRUE(forms.removed_forms.empty());
@@ -700,8 +692,7 @@
             GetMainFrame()->GetDocument().Forms().size());
 
   FormCache form_cache(GetMainFrame());
-  FormCache::UpdateFormCacheResult forms =
-      form_cache.UpdateFormCache(/*field_data_manager=*/nullptr);
+  FormCache::UpdateFormCacheResult forms = UpdateFormCache(form_cache);
 
   EXPECT_EQ(kMaxExtractableChildFrames, forms.updated_forms.size());
   EXPECT_TRUE(forms.removed_forms.empty());
@@ -732,8 +723,7 @@
             GetMainFrame()->GetDocument().Forms().size());
 
   FormCache form_cache(GetMainFrame());
-  FormCache::UpdateFormCacheResult forms =
-      form_cache.UpdateFormCache(/*field_data_manager=*/nullptr);
+  FormCache::UpdateFormCacheResult forms = UpdateFormCache(form_cache);
 
   EXPECT_EQ(forms.updated_forms.size(), kMaxExtractableFields);
   EXPECT_TRUE(base::ranges::none_of(forms.updated_forms,
diff --git a/components/autofill/content/renderer/html_based_username_detector_browsertest.cc b/components/autofill/content/renderer/html_based_username_detector_browsertest.cc
index 9aeeabe3..c9e746e 100644
--- a/components/autofill/content/renderer/html_based_username_detector_browsertest.cc
+++ b/components/autofill/content/renderer/html_based_username_detector_browsertest.cc
@@ -5,6 +5,7 @@
 #include "base/strings/stringprintf.h"
 #include "components/autofill/content/renderer/form_autofill_util.h"
 #include "components/autofill/content/renderer/html_based_username_detector.h"
+#include "components/autofill/core/common/field_data_manager.h"
 #include "content/public/test/render_view_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/web/web_document.h"
@@ -65,7 +66,8 @@
   FormData GetFormDataFromForm(const WebFormElement& form) {
     FormData form_data;
     EXPECT_TRUE(form_util::WebFormElementToFormData(
-        form, WebFormControlElement(), nullptr, /*extract_options=*/{},
+        form, WebFormControlElement(),
+        *base::MakeRefCounted<FieldDataManager>(), /*extract_options=*/{},
         &form_data,
         /*field=*/nullptr));
 
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index cd53511..6809e88 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -676,7 +676,6 @@
     blink::AssociatedInterfaceRegistry* registry)
     : content::RenderFrameObserver(render_frame),
       last_supplied_password_info_iter_(web_input_to_password_info_.end()),
-      field_data_manager_(base::MakeRefCounted<FieldDataManager>()),
       logging_state_active_(false),
       username_autofill_state_(WebAutofillState::kNotFilled),
       password_autofill_state_(WebAutofillState::kNotFilled),
@@ -778,7 +777,7 @@
   WebInputElement mutable_element = element;  // We need a non-const.
 
   const std::u16string element_value = element.Value().Utf16();
-  field_data_manager_->UpdateFieldDataMap(
+  field_data_manager().UpdateFieldDataMap(
       form_util::GetFieldRendererId(element), element_value,
       FieldPropertiesFlags::kUserTyped);
 
@@ -918,7 +917,7 @@
   DCHECK(input);
   DCHECK(!input->IsNull());
   input->SetAutofillValue(WebString::FromUTF16(credential));
-  field_data_manager_->UpdateFieldDataMap(
+  field_data_manager().UpdateFieldDataMap(
       form_util::GetFieldRendererId(*input), credential,
       FieldPropertiesFlags::kAutofilledOnUserTrigger);
   TrackAutofilledElement(*input);
@@ -1521,7 +1520,7 @@
   }
   all_autofilled_elements_.clear();
 
-  field_data_manager_->ClearData();
+  field_data_manager().ClearData();
 }
 
 #if BUILDFLAG(IS_ANDROID)
@@ -1567,7 +1566,7 @@
 
 std::unique_ptr<FormData> PasswordAutofillAgent::GetFormDataFromWebForm(
     const WebFormElement& web_form) {
-  return CreateFormDataFromWebForm(web_form, field_data_manager_.get(),
+  return CreateFormDataFromWebForm(web_form, field_data_manager(),
                                    &username_detector_cache_,
                                    &button_titles_cache_);
 }
@@ -1585,7 +1584,7 @@
   if (!web_frame)
     return nullptr;
   return CreateFormDataFromUnownedInputElements(
-      *web_frame, field_data_manager_.get(), &username_detector_cache_,
+      *web_frame, field_data_manager(), &username_detector_cache_,
       autofill_agent_->is_heavy_form_data_scraping_enabled()
           ? &button_titles_cache_
           : nullptr);
@@ -1612,8 +1611,8 @@
   DCHECK(cleared_element.Value().IsEmpty());
   FieldRendererId field_id = form_util::GetFieldRendererId(cleared_element);
   // Ignore fields that had no user input or autofill on user trigger.
-  if (!field_data_manager_->DidUserType(field_id) &&
-      !field_data_manager_->WasAutofilledOnUserTrigger(field_id)) {
+  if (!field_data_manager().DidUserType(field_id) &&
+      !field_data_manager().WasAutofilledOnUserTrigger(field_id)) {
     return;
   }
 
@@ -1647,8 +1646,7 @@
   FormData form;
   FormFieldData field;
   form_util::FindFormAndFieldForFormControlElement(
-      user_input, field_data_manager_.get(), /*extract_options=*/{}, &form,
-      &field);
+      user_input, field_data_manager(), /*extract_options=*/{}, &form, &field);
 
   int options = 0;
   if (show_all)
@@ -1677,7 +1675,7 @@
   password_to_username_.clear();
   last_supplied_password_info_iter_ = web_input_to_password_info_.end();
   should_show_popup_without_passwords_ = false;
-  field_data_manager_.get()->ClearData();
+  field_data_manager().ClearData();
   username_autofill_state_ = WebAutofillState::kNotFilled;
   password_autofill_state_ = WebAutofillState::kNotFilled;
   sent_request_to_store_ = false;
@@ -1878,20 +1876,14 @@
     const WebFormElement& form,
     const WebFormControlElement& element,
     ElementChangeSource source) {
-  WebInputElement input_element = element.DynamicTo<WebInputElement>();
-  switch (source) {
-    case FormTracker::Observer::ElementChangeSource::TEXTFIELD_CHANGED:
-      // Keeps track of all text changes even if it isn't displaying UI.
-      if (!input_element.IsNull()) {
-        UpdateStateForTextChange(input_element);
-      }
-      return;
-    case FormTracker::Observer::ElementChangeSource::WILL_SEND_SUBMIT_EVENT:
-      InformBrowserAboutUserInput(form, input_element);
-      return;
-    case FormTracker::Observer::ElementChangeSource::SELECT_CHANGED:
-      // PasswordAutofillAgent isn't interested in select control change.
-      return;
+  // ElementChangeSource::TEXTFIELD_CHANGED is handled in
+  // AutofillAgent::OnTextFieldDidChange(). For the sake of code clarity, please
+  // don't add handling for ElementChangeSource::TEXTFIELD_CHANGED here if
+  // possible.
+
+  if (source == ElementChangeSource::WILL_SEND_SUBMIT_EVENT) {
+    WebInputElement input_element = element.DynamicTo<WebInputElement>();
+    InformBrowserAboutUserInput(form, input_element);
   }
 }
 
@@ -1917,7 +1909,7 @@
       SubmissionIndicatorEvent::HTML_FORM_SUBMISSION;
 
   FillNonTypedOrFilledPropertiesMasks(&submitted_form_data->fields,
-                                      *field_data_manager_);
+                                      field_data_manager());
 
   GetPasswordManagerDriver().PasswordFormSubmitted(*submitted_form_data);
 }
@@ -2136,8 +2128,9 @@
                                           WebInputElement field) {
   // Do not autofill on load fields that have any user typed input.
   const FieldRendererId field_id = form_util::GetFieldRendererId(field);
-  if (field_data_manager_->DidUserType(field_id))
+  if (field_data_manager().DidUserType(field_id)) {
     return;
+  }
 
   if (field.Value().Utf16() == value)
     return;
@@ -2148,7 +2141,7 @@
   // not fill in the DOM with a password until we believe the user is
   // intentionally interacting with the page.
   gatekeeper_.RegisterElement(&field);
-  field_data_manager_.get()->UpdateFieldDataMap(
+  field_data_manager().UpdateFieldDataMap(
       field_id, value, FieldPropertiesFlags::kAutofilledOnPageLoad);
   autofilled_elements_cache_.emplace(field_id, WebString::FromUTF16(value));
   all_autofilled_elements_.insert(field_id);
@@ -2173,8 +2166,8 @@
   FieldRendererId element_id = form_util::GetFieldRendererId(element);
   return element.FormControlTypeForAutofill() ==
              blink::mojom::FormControlType::kInputPassword &&
-         (field_data_manager_->DidUserType(element_id) ||
-          field_data_manager_->WasAutofilledOnUserTrigger(element_id));
+         (field_data_manager().DidUserType(element_id) ||
+          field_data_manager().WasAutofilledOnUserTrigger(element_id));
 }
 
 void PasswordAutofillAgent::NotifyPasswordManagerAboutClearedForm(
@@ -2182,7 +2175,7 @@
   const auto extract_options = {ExtractOption::kValue, ExtractOption::kOptions};
   FormData form_data;
   if (WebFormElementToFormData(cleared_form, WebFormControlElement(),
-                               field_data_manager_.get(), extract_options,
+                               field_data_manager(), extract_options,
                                &form_data, /*field=*/nullptr)) {
     GetPasswordManagerDriver().PasswordFormCleared(form_data);
   }
diff --git a/components/autofill/content/renderer/password_autofill_agent.h b/components/autofill/content/renderer/password_autofill_agent.h
index 54b2d1f..cd59101 100644
--- a/components/autofill/content/renderer/password_autofill_agent.h
+++ b/components/autofill/content/renderer/password_autofill_agent.h
@@ -242,10 +242,6 @@
   void DidCommitProvisionalLoad(ui::PageTransition transition) override;
   void OnDestruct() override;
 
-  const scoped_refptr<FieldDataManager> GetFieldDataManager() {
-    return field_data_manager_;
-  }
-
   bool IsPrerendering() const;
 
   // Check if the given element is a username input field.
@@ -473,6 +469,10 @@
   void NotifyPasswordManagerAboutClearedForm(
       const blink::WebFormElement& cleared_form);
 
+  FieldDataManager& field_data_manager() const {
+    return autofill_agent_->field_data_manager();
+  }
+
   // The logins we have filled so far with their associated info.
   WebInputToPasswordInfoMap web_input_to_password_info_;
   // A (sort-of) reverse map to |web_input_to_password_info_|.
@@ -482,14 +482,6 @@
 
   bool should_show_popup_without_passwords_ = false;
 
-  // Map WebFormControlElement to the pair of:
-  // 1) The most recent text that user typed or PasswordManager autofilled in
-  // input elements. Used for storing username/password before JavaScript
-  // changes them.
-  // 2) Field properties mask, i.e. whether the field was autofilled, modified
-  // by user, etc. (see FieldPropertiesMask).
-  const scoped_refptr<FieldDataManager> field_data_manager_;
-
   PasswordValueGatekeeper gatekeeper_;
 
   // True indicates that user debug information should be logged.
@@ -511,7 +503,7 @@
   // Records the username typed before suggestions preview.
   std::u16string username_query_prefix_;
 
-  raw_ptr<AutofillAgent> autofill_agent_;
+  raw_ptr<AutofillAgent> autofill_agent_ = nullptr;
 
   raw_ptr<PasswordGenerationAgent, ExperimentalRenderer>
       password_generation_agent_;  // Weak reference.
diff --git a/components/autofill/content/renderer/password_form_conversion_utils.cc b/components/autofill/content/renderer/password_form_conversion_utils.cc
index 627c3c3..fd6c138 100644
--- a/components/autofill/content/renderer/password_form_conversion_utils.cc
+++ b/components/autofill/content/renderer/password_form_conversion_utils.cc
@@ -124,7 +124,7 @@
 
 std::unique_ptr<FormData> CreateFormDataFromWebForm(
     const WebFormElement& web_form,
-    const FieldDataManager* field_data_manager,
+    const FieldDataManager& field_data_manager,
     UsernameDetectorCache* username_detector_cache,
     form_util::ButtonTitlesCache* button_titles_cache) {
   if (web_form.IsNull())
@@ -156,7 +156,7 @@
 
 std::unique_ptr<FormData> CreateFormDataFromUnownedInputElements(
     const WebLocalFrame& frame,
-    const FieldDataManager* field_data_manager,
+    const FieldDataManager& field_data_manager,
     UsernameDetectorCache* username_detector_cache,
     form_util::ButtonTitlesCache* button_titles_cache) {
   std::vector<WebFormControlElement> control_elements =
diff --git a/components/autofill/content/renderer/password_form_conversion_utils.h b/components/autofill/content/renderer/password_form_conversion_utils.h
index 226da51b..a1bc24a 100644
--- a/components/autofill/content/renderer/password_form_conversion_utils.h
+++ b/components/autofill/content/renderer/password_form_conversion_utils.h
@@ -40,7 +40,7 @@
 
 std::unique_ptr<FormData> CreateFormDataFromWebForm(
     const blink::WebFormElement& web_form,
-    const FieldDataManager* field_data_manager,
+    const FieldDataManager& field_data_manager,
     UsernameDetectorCache* username_detector_cache,
     form_util::ButtonTitlesCache* button_titles_cache);
 
@@ -48,7 +48,7 @@
 // not enclosed in <form> element.
 std::unique_ptr<FormData> CreateFormDataFromUnownedInputElements(
     const blink::WebLocalFrame& frame,
-    const FieldDataManager* field_data_manager,
+    const FieldDataManager& field_data_manager,
     UsernameDetectorCache* username_detector_cache,
     form_util::ButtonTitlesCache* button_titles_cache);
 
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 96d36e5a..a18f3127 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -388,9 +388,9 @@
     "payments/offer_notification_options.h",
     "payments/otp_unmask_delegate.h",
     "payments/otp_unmask_result.h",
-    "payments/payments_client.cc",
-    "payments/payments_client.h",
     "payments/payments_customer_data.h",
+    "payments/payments_network_interface.cc",
+    "payments/payments_network_interface.h",
     "payments/payments_requests/get_details_for_enrollment_request.cc",
     "payments/payments_requests/get_details_for_enrollment_request.h",
     "payments/payments_requests/get_iban_upload_details_request.cc",
@@ -813,8 +813,8 @@
     "mock_merchant_promo_code_manager.h",
     "mock_single_field_form_fill_router.cc",
     "mock_single_field_form_fill_router.h",
-    "payments/mock_test_payments_client.cc",
-    "payments/mock_test_payments_client.h",
+    "payments/mock_test_payments_network_interface.cc",
+    "payments/mock_test_payments_network_interface.h",
     "payments/test/mock_mandatory_reauth_manager.cc",
     "payments/test/mock_mandatory_reauth_manager.h",
     "payments/test/test_credit_card_otp_authenticator.cc",
@@ -826,8 +826,8 @@
     "payments/test_credit_card_save_manager.cc",
     "payments/test_credit_card_save_manager.h",
     "payments/test_legal_message_line.h",
-    "payments/test_payments_client.cc",
-    "payments/test_payments_client.h",
+    "payments/test_payments_network_interface.cc",
+    "payments/test_payments_network_interface.h",
     "payments/test_virtual_card_enrollment_manager.cc",
     "payments/test_virtual_card_enrollment_manager.h",
     "personal_data_manager_test_utils.cc",
@@ -1098,7 +1098,7 @@
     "payments/full_card_request_unittest.cc",
     "payments/iban_save_manager_unittest.cc",
     "payments/legal_message_line_unittest.cc",
-    "payments/payments_client_unittest.cc",
+    "payments/payments_network_interface_unittest.cc",
     "payments/payments_requests/get_details_for_enrollment_request_unittest.cc",
     "payments/payments_requests/get_iban_upload_details_request_unittest.cc",
     "payments/payments_requests/unmask_card_request_unittest.cc",
diff --git a/components/autofill/core/browser/autofill_client.h b/components/autofill/core/browser/autofill_client.h
index d4edeb8..e02490f 100644
--- a/components/autofill/core/browser/autofill_client.h
+++ b/components/autofill/core/browser/autofill_client.h
@@ -116,8 +116,8 @@
 enum class WebauthnDialogState;
 
 namespace payments {
-class PaymentsClient;
 class MandatoryReauthManager;
+class PaymentsNetworkInterface;
 }
 
 // A client interface that needs to be supplied to the Autofill component by the
@@ -478,8 +478,8 @@
   // Gets the FormDataImporter instance owned by the client.
   virtual FormDataImporter* GetFormDataImporter() = 0;
 
-  // Gets the payments::PaymentsClient instance owned by the client.
-  virtual payments::PaymentsClient* GetPaymentsClient() = 0;
+  // Gets the payments::PaymentsNetworkInterface instance owned by the client.
+  virtual payments::PaymentsNetworkInterface* GetPaymentsNetworkInterface() = 0;
 
   // Gets the StrikeDatabase associated with the client. Note: Nullptr may be
   // returned so check before use.
diff --git a/components/autofill/core/browser/autofill_merge_unittest.cc b/components/autofill/core/browser/autofill_merge_unittest.cc
index a2db4459..1aa58ae 100644
--- a/components/autofill/core/browser/autofill_merge_unittest.cc
+++ b/components/autofill/core/browser/autofill_merge_unittest.cc
@@ -156,7 +156,7 @@
   personal_data_.set_auto_accept_address_imports_for_testing(true);
   form_data_importer_ = std::make_unique<FormDataImporter>(
       &autofill_client_,
-      /*payments::PaymentsClient=*/nullptr, &personal_data_, "en");
+      /*payments_network_interface=*/nullptr, &personal_data_, "en");
 }
 
 void AutofillMergeTest::TearDown() {
diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc
index e3f6024..0a97390c 100644
--- a/components/autofill/core/browser/browser_autofill_manager.cc
+++ b/components/autofill/core/browser/browser_autofill_manager.cc
@@ -80,7 +80,6 @@
 #include "components/autofill/core/browser/metrics/quality_metrics.h"
 #include "components/autofill/core/browser/payments/autofill_offer_manager.h"
 #include "components/autofill/core/browser/payments/credit_card_access_manager.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/profile_token_quality.h"
 #include "components/autofill/core/browser/randomized_encoder.h"
diff --git a/components/autofill/core/browser/browser_autofill_manager_unittest.cc b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
index 6447424e..b19fc5c 100644
--- a/components/autofill/core/browser/browser_autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/browser_autofill_manager_unittest.cc
@@ -52,7 +52,7 @@
 #include "components/autofill/core/browser/mock_merchant_promo_code_manager.h"
 #include "components/autofill/core/browser/mock_single_field_form_fill_router.h"
 #include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
-#include "components/autofill/core/browser/payments/test_payments_client.h"
+#include "components/autofill/core/browser/payments/test_payments_network_interface.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/profile_token_quality.h"
 #include "components/autofill/core/browser/strike_databases/payments/test_credit_card_save_strike_database.h"
@@ -609,19 +609,19 @@
                                        /*is_off_the_record=*/false);
 
     autofill_driver_ = std::make_unique<NiceMock<MockAutofillDriver>>();
-    autofill_client_.set_test_payments_client(
-        std::make_unique<payments::TestPaymentsClient>(
+    autofill_client_.set_test_payments_network_interface(
+        std::make_unique<payments::TestPaymentsNetworkInterface>(
             autofill_client_.GetURLLoaderFactory(),
             autofill_client_.GetIdentityManager(), &personal_data()));
     auto credit_card_save_manager = std::make_unique<TestCreditCardSaveManager>(
         autofill_driver_.get(), &autofill_client_,
-        static_cast<payments::TestPaymentsClient*>(
-            autofill_client_.GetPaymentsClient()),
+        static_cast<payments::TestPaymentsNetworkInterface*>(
+            autofill_client_.GetPaymentsNetworkInterface()),
         &personal_data());
     credit_card_save_manager->SetCreditCardUploadEnabled(true);
     autofill_client_.set_test_form_data_importer(
         std::make_unique<autofill::TestFormDataImporter>(
-            &autofill_client_, autofill_client_.GetPaymentsClient(),
+            &autofill_client_, autofill_client_.GetPaymentsNetworkInterface(),
             std::move(credit_card_save_manager),
             /*iban_save_manager=*/nullptr, &personal_data(), "en-US"));
 
@@ -922,8 +922,8 @@
   }
 
   void PrepareForRealPanResponse(FormData* form, CreditCard* card) {
-    // This line silences the warning from PaymentsClient about matching sync
-    // and Payments server types.
+    // This line silences the warning from PaymentsNetworkInterface about
+    // matching sync and Payments server types.
     base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
         "sync-url", "https://google.com");
 
@@ -955,7 +955,7 @@
     full_card_request->OnUnmaskPromptAccepted(details);
 
     // Mock payments response.
-    payments::PaymentsClient::UnmaskResponseDetails response;
+    payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
     response.card_type = is_virtual_card
                              ? AutofillClient::PaymentsRpcCardType::kVirtualCard
                              : AutofillClient::PaymentsRpcCardType::kServerCard;
diff --git a/components/autofill/core/browser/form_data_importer.cc b/components/autofill/core/browser/form_data_importer.cc
index 1cb383e..6511c70 100644
--- a/components/autofill/core/browser/form_data_importer.cc
+++ b/components/autofill/core/browser/form_data_importer.cc
@@ -42,6 +42,7 @@
 #include "components/autofill/core/browser/metrics/profile_import_metrics.h"
 #include "components/autofill/core/browser/payments/credit_card_save_manager.h"
 #include "components/autofill/core/browser/payments/mandatory_reauth_manager.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/virtual_card_enrollment_manager.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/profile_requirement_utils.h"
@@ -142,14 +143,15 @@
 
 FormDataImporter::ExtractedFormData::~ExtractedFormData() = default;
 
-FormDataImporter::FormDataImporter(AutofillClient* client,
-                                   payments::PaymentsClient* payments_client,
-                                   PersonalDataManager* personal_data_manager,
-                                   const std::string& app_locale)
+FormDataImporter::FormDataImporter(
+    AutofillClient* client,
+    payments::PaymentsNetworkInterface* payments_network_interface,
+    PersonalDataManager* personal_data_manager,
+    const std::string& app_locale)
     : client_(client),
       credit_card_save_manager_(
           std::make_unique<CreditCardSaveManager>(client,
-                                                  payments_client,
+                                                  payments_network_interface,
                                                   app_locale,
                                                   personal_data_manager)),
       address_profile_save_manager_(
@@ -158,18 +160,19 @@
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
       iban_save_manager_(
           std::make_unique<IbanSaveManager>(personal_data_manager, client)),
-      local_card_migration_manager_(
-          std::make_unique<LocalCardMigrationManager>(client,
-                                                      payments_client,
-                                                      app_locale,
-                                                      personal_data_manager)),
+      local_card_migration_manager_(std::make_unique<LocalCardMigrationManager>(
+          client,
+          payments_network_interface,
+          app_locale,
+          personal_data_manager)),
 #endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
       personal_data_manager_(personal_data_manager),
       app_locale_(app_locale),
       virtual_card_enrollment_manager_(
-          std::make_unique<VirtualCardEnrollmentManager>(personal_data_manager,
-                                                         payments_client,
-                                                         client)),
+          std::make_unique<VirtualCardEnrollmentManager>(
+              personal_data_manager,
+              payments_network_interface,
+              client)),
       multistep_importer_(app_locale,
                           client_->GetVariationConfigCountryCode()) {
   if (personal_data_manager_)
diff --git a/components/autofill/core/browser/form_data_importer.h b/components/autofill/core/browser/form_data_importer.h
index 7310fca..26a89c9 100644
--- a/components/autofill/core/browser/form_data_importer.h
+++ b/components/autofill/core/browser/form_data_importer.h
@@ -20,7 +20,6 @@
 #include "components/autofill/core/browser/form_structure.h"
 #include "components/autofill/core/browser/payments/iban_save_manager.h"
 #include "components/autofill/core/browser/payments/local_card_migration_manager.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
 #include "components/autofill/core/browser/payments/virtual_card_enrollment_manager.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
@@ -32,6 +31,10 @@
 class AddressProfileSaveManager;
 class CreditCardSaveManager;
 
+namespace payments {
+class PaymentsNetworkInterface;
+}
+
 // Manages logic for importing address profiles and credit card information from
 // web forms into the user's Autofill profile via the PersonalDataManager.
 // Owned by `ChromeAutofillClient`.
@@ -55,10 +58,11 @@
   };
 
   // The parameters should outlive the FormDataImporter.
-  FormDataImporter(AutofillClient* client,
-                   payments::PaymentsClient* payments_client,
-                   PersonalDataManager* personal_data_manager,
-                   const std::string& app_locale);
+  FormDataImporter(
+      AutofillClient* client,
+      payments::PaymentsNetworkInterface* payments_network_interface,
+      PersonalDataManager* personal_data_manager,
+      const std::string& app_locale);
 
   FormDataImporter(const FormDataImporter&) = delete;
   FormDataImporter& operator=(const FormDataImporter&) = delete;
diff --git a/components/autofill/core/browser/form_data_importer_unittest.cc b/components/autofill/core/browser/form_data_importer_unittest.cc
index 8a4447c0..68d3d67b 100644
--- a/components/autofill/core/browser/form_data_importer_unittest.cc
+++ b/components/autofill/core/browser/form_data_importer_unittest.cc
@@ -464,18 +464,18 @@
  public:
   MockVirtualCardEnrollmentManager(
       TestPersonalDataManager* personal_data_manager,
-      payments::TestPaymentsClient* payments_client,
+      payments::TestPaymentsNetworkInterface* payments_network_interface,
       TestAutofillClient* autofill_client)
       : TestVirtualCardEnrollmentManager(personal_data_manager,
-                                         payments_client,
+                                         payments_network_interface,
                                          autofill_client) {}
   MOCK_METHOD(
       void,
       InitVirtualCardEnroll,
       (const CreditCard& credit_card,
        VirtualCardEnrollmentSource virtual_card_enrollment_source,
-       absl::optional<
-           payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails>
+       absl::optional<payments::PaymentsNetworkInterface::
+                          GetDetailsForEnrollmentResponseDetails>
            get_details_for_enrollment_response_details,
        PrefService* user_prefs,
        VirtualCardEnrollmentManager::RiskAssessmentFunction
@@ -489,13 +489,14 @@
 // file.
 class MockCreditCardSaveManager : public TestCreditCardSaveManager {
  public:
-  MockCreditCardSaveManager(AutofillDriver* driver,
-                            AutofillClient* client,
-                            payments::TestPaymentsClient* payments_client,
-                            PersonalDataManager* personal_data_manager)
+  MockCreditCardSaveManager(
+      AutofillDriver* driver,
+      AutofillClient* client,
+      payments::TestPaymentsNetworkInterface* payments_network_interface,
+      PersonalDataManager* personal_data_manager)
       : TestCreditCardSaveManager(driver,
                                   client,
-                                  payments_client,
+                                  payments_network_interface,
                                   personal_data_manager) {}
   MOCK_METHOD(bool,
               AttemptToOfferCvcLocalSave,
@@ -547,10 +548,10 @@
 
     // Init the `form_data_importer()` with `personal_data_manager_`.
     autofill_client_->set_test_form_data_importer(
-        std::make_unique<FormDataImporter>(autofill_client_.get(),
-                                           /*payments_client=*/nullptr,
-                                           personal_data_manager_.get(),
-                                           kLocale));
+        std::make_unique<FormDataImporter>(
+            autofill_client_.get(),
+            /*payments_network_interface=*/nullptr,
+            personal_data_manager_.get(), kLocale));
 
     auto virtual_card_enrollment_manager =
         std::make_unique<MockVirtualCardEnrollmentManager>(
diff --git a/components/autofill/core/browser/metrics/autofill_metrics_test_base.cc b/components/autofill/core/browser/metrics/autofill_metrics_test_base.cc
index 6923883..bfafdb1 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics_test_base.cc
+++ b/components/autofill/core/browser/metrics/autofill_metrics_test_base.cc
@@ -7,6 +7,7 @@
 #include "components/autofill/core/browser/autofill_form_test_utils.h"
 #include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/autofill/core/browser/payments/credit_card_access_manager.h"
+#include "components/autofill/core/browser/payments/test_payments_network_interface.h"
 #include "components/autofill/core/common/autofill_clock.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -49,18 +50,19 @@
   autofill_driver_ = std::make_unique<TestAutofillDriver>();
   autofill_driver_->SetIsInAnyMainFrame(is_in_any_main_frame_);
 
-  payments::TestPaymentsClient* payments_client =
-      new payments::TestPaymentsClient(autofill_client_->GetURLLoaderFactory(),
-                                       autofill_client_->GetIdentityManager(),
-                                       &personal_data());
-  autofill_client_->set_test_payments_client(
-      std::unique_ptr<payments::TestPaymentsClient>(payments_client));
+  payments::TestPaymentsNetworkInterface* payments_network_interface =
+      new payments::TestPaymentsNetworkInterface(
+          autofill_client_->GetURLLoaderFactory(),
+          autofill_client_->GetIdentityManager(), &personal_data());
+  autofill_client_->set_test_payments_network_interface(
+      std::unique_ptr<payments::TestPaymentsNetworkInterface>(
+          payments_network_interface));
   auto credit_card_save_manager = std::make_unique<TestCreditCardSaveManager>(
-      autofill_driver_.get(), autofill_client_.get(), payments_client,
-      &personal_data());
+      autofill_driver_.get(), autofill_client_.get(),
+      payments_network_interface, &personal_data());
   autofill_client_->set_test_form_data_importer(
       std::make_unique<TestFormDataImporter>(
-          autofill_client_.get(), payments_client,
+          autofill_client_.get(), payments_network_interface,
           std::move(credit_card_save_manager),
           /*iban_save_manager=*/nullptr, &personal_data(), "en-US"));
   autofill_client_->set_autofill_offer_manager(
@@ -137,8 +139,8 @@
       access_manager->GetOrCreateFidoAuthenticator())
       ->SetUserVerifiable(is_verifiable);
 #endif
-  static_cast<payments::TestPaymentsClient*>(
-      autofill_client_->GetPaymentsClient())
+  static_cast<payments::TestPaymentsNetworkInterface*>(
+      autofill_client_->GetPaymentsNetworkInterface())
       ->AllowFidoRegistration(true);
   access_manager->is_authentication_in_progress_ = false;
   access_manager->can_fetch_unmask_details_ = true;
@@ -160,7 +162,7 @@
   details.cvc = u"123";
   full_card_request->OnUnmaskPromptAccepted(details);
 
-  payments::PaymentsClient::UnmaskResponseDetails response;
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
   response.card_type = is_virtual_card
                            ? AutofillClient::PaymentsRpcCardType::kVirtualCard
                            : AutofillClient::PaymentsRpcCardType::kServerCard;
@@ -179,7 +181,7 @@
   details.cvc = u"123";
   full_card_request->OnUnmaskPromptAccepted(details);
 
-  payments::PaymentsClient::UnmaskResponseDetails response;
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
   // Don't set |response.card_type|, so that it stays as kUnknown.
   full_card_request->OnDidGetRealPan(
       AutofillClient::PaymentsRpcResult::kPermanentFailure, response);
diff --git a/components/autofill/core/browser/metrics/autofill_metrics_test_base.h b/components/autofill/core/browser/metrics/autofill_metrics_test_base.h
index c976efe..9773095 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics_test_base.h
+++ b/components/autofill/core/browser/metrics/autofill_metrics_test_base.h
@@ -13,7 +13,6 @@
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/browser_autofill_manager_test_api.h"
 #include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
-#include "components/autofill/core/browser/payments/test_payments_client.h"
 #include "components/autofill/core/browser/test_autofill_client.h"
 #include "components/autofill/core/browser/test_autofill_driver.h"
 #include "components/autofill/core/browser/test_browser_autofill_manager.h"
diff --git a/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc b/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
index bc20f1ef..b353424 100644
--- a/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
+++ b/components/autofill/core/browser/metrics/autofill_metrics_unittest.cc
@@ -46,7 +46,6 @@
 #include "components/autofill/core/browser/metrics/ukm_metrics_test_utils.h"
 #include "components/autofill/core/browser/payments/credit_card_access_manager.h"
 #include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
-#include "components/autofill/core/browser/payments/test_payments_client.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/test_autofill_client.h"
 #include "components/autofill/core/browser/test_autofill_driver.h"
diff --git a/components/autofill/core/browser/metrics/payments/better_auth_metrics.h b/components/autofill/core/browser/metrics/payments/better_auth_metrics.h
index 1a774fbb..2f8e9166 100644
--- a/components/autofill/core/browser/metrics/payments/better_auth_metrics.h
+++ b/components/autofill/core/browser/metrics/payments/better_auth_metrics.h
@@ -141,14 +141,14 @@
 // verifiable.
 void LogCardUnmaskPreflightInitiated();
 
-// Logs the count of calls to PaymentsClient::GetUnmaskDetails() (aka
+// Logs the count of calls to PaymentsNetworkInterface::GetUnmaskDetails() (aka
 // GetDetailsForGetRealPan). If `is_user_opted_in` is true, then the user is
 // opted-in to FIDO auth, and if the user is not opted-in to FIDO auth then
 // `is_user_opted_in` is false.
 void LogCardUnmaskPreflightCalled(bool is_user_opted_in);
 
-// Logs the duration of the PaymentsClient::GetUnmaskDetails() call (aka
-// GetDetailsForGetRealPan).
+// Logs the duration of the PaymentsNetworkInterface::GetUnmaskDetails() call
+// (aka GetDetailsForGetRealPan).
 void LogCardUnmaskPreflightDuration(const base::TimeDelta& duration);
 
 // Logs which unmask type was used for a user with FIDO authentication
@@ -174,7 +174,7 @@
 // extremely quick IPC.
 void LogUserVerifiabilityCheckDuration(const base::TimeDelta& duration);
 
-// Logs the count of calls to PaymentsClient::OptChange() (aka
+// Logs the count of calls to PaymentsNetworkInterface::OptChange() (aka
 // UpdateAutofillUserPreference).
 void LogWebauthnOptChangeCalled(bool request_to_opt_in,
                                 bool is_checkout_flow,
diff --git a/components/autofill/core/browser/payments/autofill_offer_manager.cc b/components/autofill/core/browser/payments/autofill_offer_manager.cc
index 05773ef..4576e11 100644
--- a/components/autofill/core/browser/payments/autofill_offer_manager.cc
+++ b/components/autofill/core/browser/payments/autofill_offer_manager.cc
@@ -10,7 +10,6 @@
 #include "components/autofill/core/browser/autofill_client.h"
 #include "components/autofill/core/browser/data_model/autofill_offer_data.h"
 #include "components/autofill/core/browser/data_model/credit_card.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/ui/popup_item_ids.h"
 #include "components/autofill/core/common/autofill_features.h"
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager.cc b/components/autofill/core/browser/payments/credit_card_access_manager.cc
index 5bb8baa..daf127aa0 100644
--- a/components/autofill/core/browser/payments/credit_card_access_manager.cc
+++ b/components/autofill/core/browser/payments/credit_card_access_manager.cc
@@ -31,7 +31,7 @@
 #include "components/autofill/core/browser/payments/autofill_payments_feature_availability.h"
 #include "components/autofill/core/browser/payments/credit_card_risk_based_authenticator.h"
 #include "components/autofill/core/browser/payments/mandatory_reauth_manager.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/payments_util.h"
 #include "components/autofill/core/browser/payments/webauthn_callback_types.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
@@ -65,7 +65,7 @@
     autofill_metrics::CreditCardFormEventLogger* form_event_logger)
     : driver_(driver),
       client_(client),
-      payments_client_(client_->GetPaymentsClient()),
+      payments_network_interface_(client_->GetPaymentsNetworkInterface()),
       personal_data_manager_(personal_data_manager),
       form_event_logger_(form_event_logger) {}
 
@@ -209,7 +209,7 @@
   if (is_user_verifiable_.value_or(false)) {
     unmask_details_request_in_progress_ = true;
     preflight_call_timestamp_ = AutofillTickClock::NowTicks();
-    payments_client_->GetUnmaskDetails(
+    payments_network_interface_->GetUnmaskDetails(
         base::BindOnce(&CreditCardAccessManager::OnDidGetUnmaskDetails,
                        weak_ptr_factory_.GetWeakPtr()),
         personal_data_manager_->app_locale());
@@ -221,7 +221,7 @@
 
 void CreditCardAccessManager::OnDidGetUnmaskDetails(
     AutofillClient::PaymentsRpcResult result,
-    payments::PaymentsClient::UnmaskDetails& unmask_details) {
+    payments::PaymentsNetworkInterface::UnmaskDetails& unmask_details) {
   // Log latency for preflight call.
   if (preflight_call_timestamp_.has_value()) {
     autofill_metrics::LogCardUnmaskPreflightDuration(
@@ -1043,7 +1043,7 @@
     case WebauthnDialogCallbackType::kVerificationCancelled:
       // TODO(crbug.com/949269): Add tests and logging for canceling verify
       // pending dialog.
-      payments_client_->CancelRequest();
+      payments_network_interface_->CancelRequest();
       SignalCanFetchUnmaskDetails();
       ready_to_start_authentication_.Reset();
       unmask_details_request_in_progress_ = false;
@@ -1236,14 +1236,15 @@
 void CreditCardAccessManager::
     OnVirtualCardRiskBasedAuthenticationResponseReceived(
         AutofillClient::PaymentsRpcResult result,
-        payments::PaymentsClient::UnmaskResponseDetails& response_details) {
+        payments::PaymentsNetworkInterface::UnmaskResponseDetails&
+            response_details) {
   selected_challenge_option_ = nullptr;
   virtual_card_unmask_response_details_ = response_details;
   if (result == AutofillClient::PaymentsRpcResult::kSuccess) {
     if (!response_details.real_pan.empty()) {
       // If the real pan is not empty, then complete card information has been
-      // fetched from the server (this is ensured in PaymentsClient). Pass the
-      // unmasked card to `accessor_` and end the session.
+      // fetched from the server (this is ensured in PaymentsNetworkInterface).
+      // Pass the unmasked card to `accessor_` and end the session.
       CHECK_EQ(response_details.card_type,
                AutofillClient::PaymentsRpcCardType::kVirtualCard);
       card_->SetNumber(base::UTF8ToUTF16(response_details.real_pan));
@@ -1483,12 +1484,12 @@
 #if !BUILDFLAG(IS_IOS)
   opt_in_intention_ = UserOptInIntention::kUnspecified;
 #endif
-  unmask_details_ = payments::PaymentsClient::UnmaskDetails();
+  unmask_details_ = payments::PaymentsNetworkInterface::UnmaskDetails();
   virtual_card_unmask_request_details_ =
-      payments::PaymentsClient::UnmaskRequestDetails();
+      payments::PaymentsNetworkInterface::UnmaskRequestDetails();
   selected_challenge_option_ = nullptr;
   virtual_card_unmask_response_details_ =
-      payments::PaymentsClient::UnmaskResponseDetails();
+      payments::PaymentsNetworkInterface::UnmaskResponseDetails();
   ready_to_start_authentication_.Reset();
   can_fetch_unmask_details_ = true;
   card_.reset();
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager.h b/components/autofill/core/browser/payments/credit_card_access_manager.h
index 80f8e62..ffc4e1f8 100644
--- a/components/autofill/core/browser/payments/credit_card_access_manager.h
+++ b/components/autofill/core/browser/payments/credit_card_access_manager.h
@@ -23,7 +23,7 @@
 #include "components/autofill/core/browser/payments/credit_card_otp_authenticator.h"
 #include "components/autofill/core/browser/payments/credit_card_risk_based_authenticator.h"
 #include "components/autofill/core/browser/payments/mandatory_reauth_manager.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/wait_for_signal_or_timeout.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 
@@ -182,8 +182,8 @@
           response) override;
   void OnVirtualCardRiskBasedAuthenticationResponseReceived(
       AutofillClient::PaymentsRpcResult result,
-      payments::PaymentsClient::UnmaskResponseDetails& response_details)
-      override;
+      payments::PaymentsNetworkInterface::UnmaskResponseDetails&
+          response_details) override;
 
   void SetUnmaskDetailsRequestInProgressForTesting(
       bool unmask_details_request_in_progress) {
@@ -281,7 +281,7 @@
   // not opted-in for FIDO auth, or if user does not select a card.
   void OnDidGetUnmaskDetails(
       AutofillClient::PaymentsRpcResult result,
-      payments::PaymentsClient::UnmaskDetails& unmask_details);
+      payments::PaymentsNetworkInterface::UnmaskDetails& unmask_details);
 
   // Determines what type of authentication is required. `fido_auth_enabled`
   // suggests whether the server has offered FIDO auth as an option.
@@ -463,8 +463,8 @@
   // The associated autofill client. Weak reference.
   const raw_ptr<AutofillClient> client_;
 
-  // Client to interact with Payments servers.
-  const raw_ptr<payments::PaymentsClient> payments_client_;
+  // Interface to make HTTP-based requests to Google Payments.
+  const raw_ptr<payments::PaymentsNetworkInterface> payments_network_interface_;
 
   // The personal data manager, used to save and load personal data to/from the
   // web database.
@@ -494,13 +494,13 @@
   // Struct to store necessary information to start an authentication. It is
   // populated before an authentication is offered. It includes suggested
   // authentication methods and other information to facilitate card unmasking.
-  payments::PaymentsClient::UnmaskDetails unmask_details_;
+  payments::PaymentsNetworkInterface::UnmaskDetails unmask_details_;
 
   // Structs to store information passed to and fetched from the server for
   // virtual card unmasking.
-  payments::PaymentsClient::UnmaskRequestDetails
+  payments::PaymentsNetworkInterface::UnmaskRequestDetails
       virtual_card_unmask_request_details_;
-  payments::PaymentsClient::UnmaskResponseDetails
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails
       virtual_card_unmask_response_details_;
 
   // Struct to store response returned by CreditCardRiskBasedAuthenticator.
diff --git a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
index 4621bdb..156585c 100644
--- a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
+++ b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc
@@ -32,7 +32,7 @@
 #include "components/autofill/core/browser/payments/credit_card_cvc_authenticator.h"
 #include "components/autofill/core/browser/payments/credit_card_risk_based_authenticator.h"
 #include "components/autofill/core/browser/payments/test/test_credit_card_otp_authenticator.h"
-#include "components/autofill/core/browser/payments/test_payments_client.h"
+#include "components/autofill/core/browser/payments/test_payments_network_interface.h"
 #include "components/autofill/core/browser/test_autofill_client.h"
 #include "components/autofill/core/browser/test_autofill_driver.h"
 #include "components/autofill/core/browser/test_browser_autofill_manager.h"
@@ -171,8 +171,8 @@
     accessor_ = std::make_unique<TestAccessor>();
     autofill_driver_ = std::make_unique<TestAutofillDriver>();
 
-    autofill_client_.set_test_payments_client(
-        std::make_unique<payments::TestPaymentsClient>(
+    autofill_client_.set_test_payments_network_interface(
+        std::make_unique<payments::TestPaymentsNetworkInterface>(
             autofill_client_.GetURLLoaderFactory(),
             autofill_client_.GetIdentityManager(), &personal_data()));
     autofill_client_.set_test_strike_database(
@@ -268,7 +268,7 @@
 
     MockUserResponseForCvcAuth(kTestCvc16, follow_with_fido_auth);
 
-    payments::PaymentsClient::UnmaskResponseDetails response;
+    payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
     response.card_authorization_token = "dummy_card_authorization_token";
     if (follow_with_fido_auth) {
@@ -335,7 +335,7 @@
     if (!full_card_request)
       return false;
 
-    payments::PaymentsClient::UnmaskResponseDetails response;
+    payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
     response.card_type = is_virtual_card
                              ? AutofillClient::PaymentsRpcCardType::kVirtualCard
                              : AutofillClient::PaymentsRpcCardType::kServerCard;
@@ -344,12 +344,12 @@
     return true;
   }
 
-  // Mocks an OptChange response from Payments Client.
+  // Mocks an OptChange response from the PaymentsNetworkInterface.
   void OptChange(AutofillClient::PaymentsRpcResult result,
                  bool user_is_opted_in,
                  bool include_creation_options = false,
                  bool include_request_options = false) {
-    payments::PaymentsClient::OptChangeResponseDetails response;
+    payments::PaymentsNetworkInterface::OptChangeResponseDetails response;
     response.user_is_opted_in = user_is_opted_in;
     if (include_creation_options) {
       response.fido_creation_options = GetTestCreationOptions();
@@ -376,7 +376,7 @@
   void InvokeDelayedGetUnmaskDetailsResponse() {
     credit_card_access_manager().OnDidGetUnmaskDetails(
         AutofillClient::PaymentsRpcResult::kSuccess,
-        *payments_client().unmask_details());
+        *payments_network_interface().unmask_details());
   }
 
   void InvokeUnmaskDetailsTimeout() {
@@ -424,7 +424,7 @@
     // unmasking flow.
     EXPECT_TRUE(autofill_client_.risk_based_authentication_invoked());
     // Mock server response with information regarding VCN auth.
-    payments::PaymentsClient::UnmaskResponseDetails response;
+    payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
     response.context_token = "fake_context_token";
     response.card_unmask_challenge_options = challenge_options;
 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_ANDROID)
@@ -465,8 +465,9 @@
         CreditCardCvcAuthenticator* cvc_authenticator =
             autofill_client_.GetCvcAuthenticator();
         DCHECK(cvc_authenticator);
-        payments::PaymentsClient::UnmaskRequestDetails* request_details =
-            cvc_authenticator->GetFullCardRequest()->request_.get();
+        payments::PaymentsNetworkInterface::UnmaskRequestDetails*
+            request_details =
+                cvc_authenticator->GetFullCardRequest()->request_.get();
         EXPECT_EQ(request_details->card.record_type(),
                   CreditCard::RecordType::kVirtualCard);
         EXPECT_EQ(request_details->card.number(),
@@ -524,9 +525,9 @@
         *credit_card_access_manager().GetOrCreateFidoAuthenticator());
   }
 #endif
-  payments::TestPaymentsClient& payments_client() {
-    return static_cast<payments::TestPaymentsClient&>(
-        *autofill_client_.GetPaymentsClient());
+  payments::TestPaymentsNetworkInterface& payments_network_interface() {
+    return static_cast<payments::TestPaymentsNetworkInterface&>(
+        *autofill_client_.GetPaymentsNetworkInterface());
   }
   TestPersonalDataManager& personal_data() {
     return *autofill_client_.GetPersonalDataManager();
@@ -537,8 +538,8 @@
     std::string other_server_id = "00000000-0000-0000-0000-000000000034";
     // Add a random FIDO eligible card, it will return RequestOptions in unmask
     // details.
-    payments_client().AddFidoEligibleCard(other_server_id, kCredentialId,
-                                          kGooglePaymentsRpid);
+    payments_network_interface().AddFidoEligibleCard(
+        other_server_id, kCredentialId, kGooglePaymentsRpid);
     GetFIDOAuthenticator()->SetUserVerifiable(true);
     SetCreditCardFIDOAuthEnabled(true);
   }
@@ -780,7 +781,7 @@
   // unmasking flow.
   EXPECT_TRUE(autofill_client_.risk_based_authentication_invoked());
   // Mock server response with valid card information.
-  payments::PaymentsClient::UnmaskResponseDetails response;
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
   response.real_pan = "4111111111111111";
   response.dcvv = "321";
   response.expiration_month = test::NextMonth();
@@ -1152,8 +1153,8 @@
   CreditCard* card = personal_data().GetCreditCardByGUID(kTestGUID);
   GetFIDOAuthenticator()->SetUserVerifiable(true);
   SetCreditCardFIDOAuthEnabled(true);
-  payments_client().AddFidoEligibleCard(card->server_id(), kCredentialId,
-                                        kGooglePaymentsRpid);
+  payments_network_interface().AddFidoEligibleCard(
+      card->server_id(), kCredentialId, kGooglePaymentsRpid);
 
   credit_card_access_manager().PrepareToFetchCreditCard();
   WaitForCallbacks();
@@ -1207,8 +1208,8 @@
   CreditCard* card = personal_data().GetCreditCardByGUID(kTestGUID);
   GetFIDOAuthenticator()->SetUserVerifiable(true);
   SetCreditCardFIDOAuthEnabled(true);
-  payments_client().AddFidoEligibleCard(card->server_id(), kCredentialId,
-                                        kGooglePaymentsRpid);
+  payments_network_interface().AddFidoEligibleCard(
+      card->server_id(), kCredentialId, kGooglePaymentsRpid);
 
   credit_card_access_manager().PrepareToFetchCreditCard();
   WaitForCallbacks();
@@ -1236,8 +1237,8 @@
   CreateServerCard(kTestGUID, kTestNumber);
   CreditCard* card = personal_data().GetCreditCardByGUID(kTestGUID);
   GetFIDOAuthenticator()->SetUserVerifiable(true);
-  payments_client().AddFidoEligibleCard(card->server_id(), kCredentialId,
-                                        kGooglePaymentsRpid);
+  payments_network_interface().AddFidoEligibleCard(
+      card->server_id(), kCredentialId, kGooglePaymentsRpid);
 
   credit_card_access_manager().PrepareToFetchCreditCard();
   WaitForCallbacks();
@@ -1274,8 +1275,8 @@
   CreditCard* card = personal_data().GetCreditCardByGUID(kTestGUID);
   GetFIDOAuthenticator()->SetUserVerifiable(true);
   SetCreditCardFIDOAuthEnabled(true);
-  payments_client().AddFidoEligibleCard(card->server_id(), kCredentialId,
-                                        kGooglePaymentsRpid);
+  payments_network_interface().AddFidoEligibleCard(
+      card->server_id(), kCredentialId, kGooglePaymentsRpid);
 
   credit_card_access_manager().PrepareToFetchCreditCard();
   WaitForCallbacks();
@@ -1332,8 +1333,8 @@
   CreditCard* card = personal_data().GetCreditCardByGUID(kTestGUID);
   GetFIDOAuthenticator()->SetUserVerifiable(true);
   SetCreditCardFIDOAuthEnabled(true);
-  payments_client().AddFidoEligibleCard(card->server_id(), kCredentialId,
-                                        kGooglePaymentsRpid);
+  payments_network_interface().AddFidoEligibleCard(
+      card->server_id(), kCredentialId, kGooglePaymentsRpid);
 
   credit_card_access_manager().PrepareToFetchCreditCard();
   WaitForCallbacks();
@@ -1376,8 +1377,8 @@
   GetFIDOAuthenticator()->SetUserVerifiable(true);
   SetCreditCardFIDOAuthEnabled(true);
   // Don't set Credential ID.
-  payments_client().AddFidoEligibleCard(card->server_id(), /*credential_id=*/"",
-                                        kGooglePaymentsRpid);
+  payments_network_interface().AddFidoEligibleCard(
+      card->server_id(), /*credential_id=*/"", kGooglePaymentsRpid);
 
   credit_card_access_manager().PrepareToFetchCreditCard();
   WaitForCallbacks();
@@ -1457,7 +1458,7 @@
     {
       // Preflight call returned after card was chosen.
       base::HistogramTester histogram_tester;
-      payments_client().ShouldReturnUnmaskDetailsImmediately(false);
+      payments_network_interface().ShouldReturnUnmaskDetailsImmediately(false);
 
       ResetFetchCreditCard();
       credit_card_access_manager().PrepareToFetchCreditCard();
@@ -1486,7 +1487,7 @@
       base::HistogramTester histogram_tester;
       // This is important because CreditCardFidoAuthenticator will update the
       // opted-in pref according to GetDetailsForGetRealPan response.
-      payments_client().AllowFidoRegistration(!user_is_opted_in);
+      payments_network_interface().AllowFidoRegistration(!user_is_opted_in);
 
       ResetFetchCreditCard();
       credit_card_access_manager().PrepareToFetchCreditCard();
@@ -1514,7 +1515,7 @@
   CreditCard* server_card = personal_data().GetCreditCardByGUID(server_guid);
   GetFIDOAuthenticator()->SetUserVerifiable(true);
   SetCreditCardFIDOAuthEnabled(true);
-  payments_client().ShouldReturnUnmaskDetailsImmediately(false);
+  payments_network_interface().ShouldReturnUnmaskDetailsImmediately(false);
 
   std::string existence_perceived_latency_histogram_name =
       "Autofill.BetterAuth.UserPerceivedLatencyOnCardSelection.OptedIn";
@@ -1642,8 +1643,8 @@
   card->SetExpirationYearFromString(u"2010");
   GetFIDOAuthenticator()->SetUserVerifiable(true);
   SetCreditCardFIDOAuthEnabled(true);
-  payments_client().AddFidoEligibleCard(card->server_id(), kCredentialId,
-                                        kGooglePaymentsRpid);
+  payments_network_interface().AddFidoEligibleCard(
+      card->server_id(), kCredentialId, kGooglePaymentsRpid);
 
   credit_card_access_manager().PrepareToFetchCreditCard();
   WaitForCallbacks();
@@ -1833,8 +1834,8 @@
   // has the opt-in state to false - this shows the user opted-in through the
   // settings page.
   SetCreditCardFIDOAuthEnabled(true);
-  payments_client().AllowFidoRegistration(true);
-  payments_client().ShouldReturnUnmaskDetailsImmediately(true);
+  payments_network_interface().AllowFidoRegistration(true);
+  payments_network_interface().ShouldReturnUnmaskDetailsImmediately(true);
 
   credit_card_access_manager().PrepareToFetchCreditCard();
   credit_card_access_manager().FetchCreditCard(card, accessor_->GetWeakPtr());
@@ -1846,8 +1847,9 @@
   // Although the checkbox was hidden and |enable_fido_auth| was set to false in
   // the user request, because of the previous opt-in intention, the client must
   // request to opt-in.
-  EXPECT_TRUE(
-      payments_client().unmask_request()->user_response.enable_fido_auth);
+  EXPECT_TRUE(payments_network_interface()
+                  .unmask_request()
+                  ->user_response.enable_fido_auth);
 }
 
 #else   // BUILDFLAG(IS_ANDROID)
@@ -1871,7 +1873,7 @@
   CreditCard* card = personal_data().GetCreditCardByGUID(kTestGUID);
   GetFIDOAuthenticator()->SetUserVerifiable(true);
   SetCreditCardFIDOAuthEnabled(false);
-  payments_client().AllowFidoRegistration(true);
+  payments_network_interface().AllowFidoRegistration(true);
 
   credit_card_access_manager().PrepareToFetchCreditCard();
   credit_card_access_manager().FetchCreditCard(card, accessor_->GetWeakPtr());
@@ -1930,7 +1932,7 @@
   CreditCard* card = personal_data().GetCreditCardByGUID(kTestGUID);
   GetFIDOAuthenticator()->SetUserVerifiable(true);
   SetCreditCardFIDOAuthEnabled(false);
-  payments_client().AllowFidoRegistration(true);
+  payments_network_interface().AllowFidoRegistration(true);
 
   credit_card_access_manager().PrepareToFetchCreditCard();
   credit_card_access_manager().FetchCreditCard(card, accessor_->GetWeakPtr());
@@ -1967,7 +1969,7 @@
   CreditCard* card = personal_data().GetCreditCardByGUID(kTestGUID);
   GetFIDOAuthenticator()->SetUserVerifiable(true);
   SetCreditCardFIDOAuthEnabled(false);
-  payments_client().AllowFidoRegistration(true);
+  payments_network_interface().AllowFidoRegistration(true);
 
   credit_card_access_manager().PrepareToFetchCreditCard();
   credit_card_access_manager().FetchCreditCard(card, accessor_->GetWeakPtr());
@@ -2005,7 +2007,7 @@
   CreditCard* card = personal_data().GetCreditCardByGUID(kTestGUID);
   GetFIDOAuthenticator()->SetUserVerifiable(true);
   SetCreditCardFIDOAuthEnabled(false);
-  payments_client().AllowFidoRegistration(true);
+  payments_network_interface().AllowFidoRegistration(true);
 
   credit_card_access_manager().PrepareToFetchCreditCard();
   credit_card_access_manager().FetchCreditCard(card, accessor_->GetWeakPtr());
@@ -2052,7 +2054,7 @@
   CreditCard* card = personal_data().GetCreditCardByGUID(kTestGUID);
   GetFIDOAuthenticator()->SetUserVerifiable(true);
   SetCreditCardFIDOAuthEnabled(false);
-  payments_client().AllowFidoRegistration(true);
+  payments_network_interface().AllowFidoRegistration(true);
 
   credit_card_access_manager().PrepareToFetchCreditCard();
   credit_card_access_manager().FetchCreditCard(card, accessor_->GetWeakPtr());
@@ -2193,7 +2195,7 @@
 #else
     SetCreditCardFIDOAuthEnabled(false);
 #endif  // BUILDFLAG(OS_ANDROID)
-    payments_client().AllowFidoRegistration(
+    payments_network_interface().AllowFidoRegistration(
         /*offer_fido_opt_in=*/UnmaskDetailsOfferFidoOptIn());
     if (IsVirtualCard()) {
       GetCreditCard()->set_record_type(CreditCard::RecordType::kVirtualCard);
@@ -2202,8 +2204,8 @@
       // If user and device are already opted into FIDO, then add an eligible
       // card to ensure that the `unmask_details_` contains fido request
       // options.
-      payments_client().AddFidoEligibleCard("random_id", kCredentialId,
-                                            kGooglePaymentsRpid);
+      payments_network_interface().AddFidoEligibleCard(
+          "random_id", kCredentialId, kGooglePaymentsRpid);
     }
 
     credit_card_access_manager().PrepareToFetchCreditCard();
@@ -2362,14 +2364,14 @@
   // The user is FIDO-enabled from Payments.
   GetFIDOAuthenticator()->SetUserVerifiable(true);
   SetCreditCardFIDOAuthEnabled(true);
-  payments_client().AddFidoEligibleCard(card->server_id(), kCredentialId,
-                                        kGooglePaymentsRpid);
+  payments_network_interface().AddFidoEligibleCard(
+      card->server_id(), kCredentialId, kGooglePaymentsRpid);
   // Mock the user manually opt-out from Settings page, and Payments did not
   // update user status in time. The mismatch will set user INTENT_TO_OPT_OUT.
   SetCreditCardFIDOAuthEnabled(/*enabled=*/false);
   // Delay the UnmaskDetailsResponse so that we can't discover the mismatch,
   // which will use local pref and fall back to CVC.
-  payments_client().ShouldReturnUnmaskDetailsImmediately(false);
+  payments_network_interface().ShouldReturnUnmaskDetailsImmediately(false);
 
   credit_card_access_manager().PrepareToFetchCreditCard();
   credit_card_access_manager().FetchCreditCard(card, accessor_->GetWeakPtr());
@@ -2407,8 +2409,8 @@
   // The user is FIDO-enabled from Payments.
   GetFIDOAuthenticator()->SetUserVerifiable(true);
   SetCreditCardFIDOAuthEnabled(true);
-  payments_client().AddFidoEligibleCard(card->server_id(), kCredentialId,
-                                        kGooglePaymentsRpid);
+  payments_network_interface().AddFidoEligibleCard(
+      card->server_id(), kCredentialId, kGooglePaymentsRpid);
   // Mock the user manually opt-out from Settings page, and Payments did not
   // update user status in time. The mismatch will set user INTENT_TO_OPT_OUT.
   SetCreditCardFIDOAuthEnabled(/*enabled=*/false);
@@ -2443,8 +2445,8 @@
   // The user is FIDO-enabled from Payments.
   GetFIDOAuthenticator()->SetUserVerifiable(true);
   SetCreditCardFIDOAuthEnabled(true);
-  payments_client().AddFidoEligibleCard(card->server_id(), kCredentialId,
-                                        kGooglePaymentsRpid);
+  payments_network_interface().AddFidoEligibleCard(
+      card->server_id(), kCredentialId, kGooglePaymentsRpid);
   // Mock the user manually opt-out from Settings page, and Payments did not
   // update user status in time. The mismatch will set user INTENT_TO_OPT_OUT.
   SetCreditCardFIDOAuthEnabled(/*enabled=*/false);
@@ -2478,8 +2480,8 @@
   // The user is FIDO-enabled from Payments.
   GetFIDOAuthenticator()->SetUserVerifiable(true);
   SetCreditCardFIDOAuthEnabled(true);
-  payments_client().AddFidoEligibleCard(card->server_id(), kCredentialId,
-                                        kGooglePaymentsRpid);
+  payments_network_interface().AddFidoEligibleCard(
+      card->server_id(), kCredentialId, kGooglePaymentsRpid);
   // Mock the user manually opt-out from Settings page, and Payments did not
   // update user status in time. The mismatch will set user INTENT_TO_OPT_OUT.
   SetCreditCardFIDOAuthEnabled(/*enabled=*/false);
@@ -2997,7 +2999,7 @@
   // unmasking flow.
   EXPECT_TRUE(autofill_client_.risk_based_authentication_invoked());
   // Mock server response with valid card information.
-  payments::PaymentsClient::UnmaskResponseDetails response;
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
   response.real_pan = "4111111111111111";
   response.dcvv = "321";
   response.expiration_month = test::NextMonth();
@@ -3204,7 +3206,7 @@
   // unmasking flow.
   EXPECT_TRUE(autofill_client_.risk_based_authentication_invoked());
   // Mock server response with information regarding FIDO auth.
-  payments::PaymentsClient::UnmaskResponseDetails response;
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
   response.context_token = "fake_context_token";
   response.fido_request_options = GetTestRequestOptions();
   credit_card_access_manager()
@@ -3262,7 +3264,7 @@
   // unmasking flow.
   EXPECT_TRUE(autofill_client_.risk_based_authentication_invoked());
   // Mock server response with information regarding both FIDO and OTP auth.
-  payments::PaymentsClient::UnmaskResponseDetails response;
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
   response.context_token = "fake_context_token";
   CardUnmaskChallengeOption challenge_option =
       test::GetCardUnmaskChallengeOptions(
@@ -3384,7 +3386,7 @@
   // unmasking flow.
   EXPECT_TRUE(autofill_client_.risk_based_authentication_invoked());
   // Mock server response with information regarding FIDO auth.
-  payments::PaymentsClient::UnmaskResponseDetails response;
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
   response.context_token = "fake_context_token";
   response.fido_request_options = GetTestRequestOptions();
   credit_card_access_manager()
@@ -3432,7 +3434,7 @@
   // unmasking flow.
   EXPECT_TRUE(autofill_client_.risk_based_authentication_invoked());
   // Mock server response with no challenge options.
-  payments::PaymentsClient::UnmaskResponseDetails response;
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
   response.context_token = "fake_context_token";
   credit_card_access_manager()
       .OnVirtualCardRiskBasedAuthenticationResponseReceived(
@@ -3477,7 +3479,7 @@
   // unmasking flow.
   EXPECT_TRUE(autofill_client_.risk_based_authentication_invoked());
   // Mock server response with no challenge options.
-  payments::PaymentsClient::UnmaskResponseDetails response;
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
   credit_card_access_manager()
       .OnVirtualCardRiskBasedAuthenticationResponseReceived(
           AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure,
@@ -3514,7 +3516,7 @@
   autofill_error_dialog_context.server_returned_description =
       "test_server_returned_description";
 
-  payments::PaymentsClient::UnmaskResponseDetails response;
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
   response.autofill_error_dialog_context = autofill_error_dialog_context;
   credit_card_access_manager()
       .OnVirtualCardRiskBasedAuthenticationResponseReceived(
diff --git a/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc b/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc
index 75ce67bb..3cb7bb1 100644
--- a/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc
+++ b/components/autofill/core/browser/payments/credit_card_cvc_authenticator.cc
@@ -39,7 +39,7 @@
         payments::FullCardRequest::FailureType::GENERIC_FAILURE);
   }
   full_card_request_ = std::make_unique<payments::FullCardRequest>(
-      client_, client_->GetPaymentsClient(), personal_data_manager);
+      client_, client_->GetPaymentsNetworkInterface(), personal_data_manager);
 
   CreditCard::RecordType card_record_type = card->record_type();
   autofill_metrics::LogCvcAuthAttempt(card_record_type);
@@ -90,7 +90,7 @@
   if (!requester_)
     return;
 
-  payments::PaymentsClient::UnmaskResponseDetails response =
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response =
       full_card_request.unmask_response_details();
   requester_->OnCvcAuthenticationComplete(
       CvcAuthenticationResponse()
@@ -166,7 +166,7 @@
   // this function directly.
   if (!full_card_request_) {
     full_card_request_ = std::make_unique<payments::FullCardRequest>(
-        client_, client_->GetPaymentsClient(),
+        client_, client_->GetPaymentsNetworkInterface(),
         client_->GetPersonalDataManager());
   }
   return full_card_request_.get();
diff --git a/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc b/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc
index 00141af..0c91dc0 100644
--- a/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc
+++ b/components/autofill/core/browser/payments/credit_card_cvc_authenticator_unittest.cc
@@ -35,7 +35,7 @@
 #include "components/autofill/core/browser/metrics/payments/card_unmask_authentication_metrics.h"
 #include "components/autofill/core/browser/payments/full_card_request.h"
 #include "components/autofill/core/browser/payments/test_authentication_requester.h"
-#include "components/autofill/core/browser/payments/test_payments_client.h"
+#include "components/autofill/core/browser/payments/test_payments_network_interface.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/test_autofill_client.h"
 #include "components/autofill/core/browser/test_autofill_clock.h"
@@ -93,12 +93,13 @@
     autofill_driver_ =
         std::make_unique<testing::NiceMock<TestAutofillDriver>>();
 
-    payments::TestPaymentsClient* payments_client =
-        new payments::TestPaymentsClient(autofill_client_.GetURLLoaderFactory(),
-                                         autofill_client_.GetIdentityManager(),
-                                         &personal_data_manager_);
-    autofill_client_.set_test_payments_client(
-        std::unique_ptr<payments::TestPaymentsClient>(payments_client));
+    payments::TestPaymentsNetworkInterface* payments_network_interface =
+        new payments::TestPaymentsNetworkInterface(
+            autofill_client_.GetURLLoaderFactory(),
+            autofill_client_.GetIdentityManager(), &personal_data_manager_);
+    autofill_client_.set_test_payments_network_interface(
+        std::unique_ptr<payments::TestPaymentsNetworkInterface>(
+            payments_network_interface));
     cvc_authenticator_ =
         std::make_unique<CreditCardCvcAuthenticator>(&autofill_client_);
   }
@@ -139,7 +140,7 @@
     full_card_request->OnUnmaskPromptAccepted(details);
 
     // Mock payments response.
-    payments::PaymentsClient::UnmaskResponseDetails response;
+    payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
     response.card_type = is_virtual_card
                              ? AutofillClient::PaymentsRpcCardType::kVirtualCard
                              : AutofillClient::PaymentsRpcCardType::kServerCard;
diff --git a/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc b/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
index 7f98d22..8173861 100644
--- a/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
+++ b/components/autofill/core/browser/payments/credit_card_fido_authenticator.cc
@@ -24,7 +24,7 @@
 #include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/autofill/core/browser/metrics/autofill_metrics.h"
 #include "components/autofill/core/browser/metrics/payments/better_auth_metrics.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/payments_service_url.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/strike_databases/payments/fido_authentication_strike_database.h"
@@ -58,7 +58,7 @@
                                                          AutofillClient* client)
     : autofill_driver_(driver),
       autofill_client_(client),
-      payments_client_(client->GetPaymentsClient()),
+      payments_network_interface_(client->GetPaymentsNetworkInterface()),
       user_is_verifiable_callback_received_(
           base::WaitableEvent::ResetPolicy::AUTOMATIC,
           base::WaitableEvent::InitialState::NOT_SIGNALED) {
@@ -173,7 +173,7 @@
 }
 
 UserOptInIntention CreditCardFidoAuthenticator::GetUserOptInIntention(
-    payments::PaymentsClient::UnmaskDetails& unmask_details) {
+    payments::PaymentsNetworkInterface::UnmaskDetails& unmask_details) {
   // This local pref can be affected by the user toggling on the settings page.
   // And payments might not update in time. We derive user opt in/out intention
   // when we see the mismatch.
@@ -259,7 +259,7 @@
                   kDeclinedAfterAccepting
             : autofill_metrics::WebauthnOptInPromoUserDecisionMetric::
                   kDeclinedImmediately);
-    payments_client_->CancelRequest();
+    payments_network_interface_->CancelRequest();
     card_authorization_token_ = std::string();
     current_flow_ = NONE_FLOW;
     if (auto* strike_database = GetOrCreateFidoAuthenticationStrikeDatabase()) {
@@ -336,22 +336,22 @@
 
 void CreditCardFidoAuthenticator::OptChange(
     base::Value::Dict authenticator_response) {
-  payments::PaymentsClient::OptChangeRequestDetails request_details;
+  payments::PaymentsNetworkInterface::OptChangeRequestDetails request_details;
   request_details.app_locale =
       autofill_client_->GetPersonalDataManager()->app_locale();
 
   switch (current_flow_) {
     case OPT_IN_WITH_CHALLENGE_FLOW:
     case OPT_IN_FETCH_CHALLENGE_FLOW:
-      request_details.reason =
-          payments::PaymentsClient::OptChangeRequestDetails::ENABLE_FIDO_AUTH;
+      request_details.reason = payments::PaymentsNetworkInterface::
+          OptChangeRequestDetails::ENABLE_FIDO_AUTH;
       break;
     case OPT_OUT_FLOW:
-      request_details.reason =
-          payments::PaymentsClient::OptChangeRequestDetails::DISABLE_FIDO_AUTH;
+      request_details.reason = payments::PaymentsNetworkInterface::
+          OptChangeRequestDetails::DISABLE_FIDO_AUTH;
       break;
     case FOLLOWUP_AFTER_CVC_AUTH_FLOW:
-      request_details.reason = payments::PaymentsClient::
+      request_details.reason = payments::PaymentsNetworkInterface::
           OptChangeRequestDetails::ADD_CARD_FOR_FIDO_AUTH;
       break;
     default:
@@ -385,7 +385,7 @@
     opt_change_metric =
         autofill_metrics::WebauthnOptInParameters::kFetchingChallenge;
   }
-  payments_client_->OptChange(
+  payments_network_interface_->OptChange(
       request_details,
       base::BindOnce(&CreditCardFidoAuthenticator::OnDidGetOptChangeResult,
                      weak_ptr_factory_.GetWeakPtr()));
@@ -441,7 +441,7 @@
 
 void CreditCardFidoAuthenticator::OnDidGetOptChangeResult(
     AutofillClient::PaymentsRpcResult result,
-    payments::PaymentsClient::OptChangeResponseDetails& response) {
+    payments::PaymentsNetworkInterface::OptChangeResponseDetails& response) {
   DCHECK(current_flow_ == OPT_IN_FETCH_CHALLENGE_FLOW ||
          current_flow_ == OPT_OUT_FLOW ||
          current_flow_ == OPT_IN_WITH_CHALLENGE_FLOW ||
@@ -752,7 +752,7 @@
       base::Value::Dict response =
           ParseAssertionResponse(std::move(assertion_response));
       full_card_request_ = std::make_unique<payments::FullCardRequest>(
-          autofill_client_, autofill_client_->GetPaymentsClient(),
+          autofill_client_, autofill_client_->GetPaymentsNetworkInterface(),
           autofill_client_->GetPersonalDataManager());
 
       absl::optional<GURL> last_committed_primary_main_frame_origin;
diff --git a/components/autofill/core/browser/payments/credit_card_fido_authenticator.h b/components/autofill/core/browser/payments/credit_card_fido_authenticator.h
index 0d3fbce..8711831 100644
--- a/components/autofill/core/browser/payments/credit_card_fido_authenticator.h
+++ b/components/autofill/core/browser/payments/credit_card_fido_authenticator.h
@@ -16,7 +16,7 @@
 #include "components/autofill/core/browser/autofill_driver.h"
 #include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/autofill/core/browser/payments/full_card_request.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/strike_databases/payments/fido_authentication_strike_database.h"
 #include "components/webauthn/core/browser/internal_authenticator.h"
 #include "device/fido/fido_constants.h"
@@ -128,7 +128,7 @@
   // Return user's opt in/out intention based on unmask detail response and
   // local pref.
   UserOptInIntention GetUserOptInIntention(
-      payments::PaymentsClient::UnmaskDetails& unmask_details);
+      payments::PaymentsNetworkInterface::UnmaskDetails& unmask_details);
 
   // Cancel the ongoing verification process. Used to reset states in this class
   // and in the FullCardRequest if any.
@@ -197,7 +197,7 @@
   // Sets prefstore to enable credit card authentication if rpc was successful.
   void OnDidGetOptChangeResult(
       AutofillClient::PaymentsRpcResult result,
-      payments::PaymentsClient::OptChangeResponseDetails& response);
+      payments::PaymentsNetworkInterface::OptChangeResponseDetails& response);
 
   // payments::FullCardRequest::ResultDelegate:
   void OnFullCardRequestSucceeded(
@@ -267,8 +267,8 @@
   // The associated autofill client. Weak reference.
   const raw_ptr<AutofillClient> autofill_client_;
 
-  // Payments client to make requests to Google Payments.
-  const raw_ptr<payments::PaymentsClient> payments_client_;
+  // Interface to make HTTP-based requests to Google Payments.
+  const raw_ptr<payments::PaymentsNetworkInterface> payments_network_interface_;
 
   // Authenticator pointer to facilitate WebAuthn.
   std::unique_ptr<webauthn::InternalAuthenticator> authenticator_;
diff --git a/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc b/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc
index 46446b9..b73f865 100644
--- a/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc
+++ b/components/autofill/core/browser/payments/credit_card_fido_authenticator_unittest.cc
@@ -37,7 +37,7 @@
 #include "components/autofill/core/browser/payments/test_authentication_requester.h"
 #include "components/autofill/core/browser/payments/test_credit_card_fido_authenticator.h"
 #include "components/autofill/core/browser/payments/test_internal_authenticator.h"
-#include "components/autofill/core/browser/payments/test_payments_client.h"
+#include "components/autofill/core/browser/payments/test_payments_network_interface.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/test_autofill_client.h"
 #include "components/autofill/core/browser/test_autofill_clock.h"
@@ -111,8 +111,8 @@
 
     autofill_driver_.SetAuthenticator(new TestInternalAuthenticator());
 
-    autofill_client_.set_test_payments_client(
-        std::make_unique<payments::TestPaymentsClient>(
+    autofill_client_.set_test_payments_network_interface(
+        std::make_unique<payments::TestPaymentsNetworkInterface>(
             autofill_client_.GetURLLoaderFactory(),
             autofill_client_.GetIdentityManager(), &personal_data_manager()));
     autofill_client_.set_test_strike_database(
@@ -178,7 +178,7 @@
                   const std::string& real_pan,
                   bool is_virtual_card = false) {
     DCHECK(fido_authenticator().full_card_request_);
-    payments::PaymentsClient::UnmaskResponseDetails response;
+    payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
     response.card_type = is_virtual_card
                              ? AutofillClient::PaymentsRpcCardType::kVirtualCard
                              : AutofillClient::PaymentsRpcCardType::kServerCard;
@@ -186,12 +186,12 @@
         result, response.with_real_pan(real_pan));
   }
 
-  // Mocks an OptChange response from Payments Client.
+  // Mocks an OptChange response from the PaymentsNetworkInterface.
   void OptChange(AutofillClient::PaymentsRpcResult result,
                  bool user_is_opted_in,
                  bool include_creation_options = false,
                  bool include_request_options = false) {
-    payments::PaymentsClient::OptChangeResponseDetails response;
+    payments::PaymentsNetworkInterface::OptChangeResponseDetails response;
     response.user_is_opted_in = user_is_opted_in;
     if (include_creation_options) {
       response.fido_creation_options =
@@ -247,7 +247,7 @@
        GetUserOptInIntention_IntentToOptIn_Android) {
   // If payments is offering to opt-in, then that means user is not opted in
   // from payments.
-  payments::PaymentsClient::UnmaskDetails unmask_details;
+  payments::PaymentsNetworkInterface::UnmaskDetails unmask_details;
   unmask_details.offer_fido_opt_in = true;
   // Set the local preference to be enabled, which denotes user manually opted
   // in from settings page, and Payments did not update the status in time.
@@ -265,7 +265,7 @@
        GetUserOptInIntention_IntentToOptIn_Desktop) {
   // If payments is offering to opt-in, then that means user is not opted in
   // from payments.
-  payments::PaymentsClient::UnmaskDetails unmask_details;
+  payments::PaymentsNetworkInterface::UnmaskDetails unmask_details;
   unmask_details.offer_fido_opt_in = true;
   // Set the local preference to be enabled, which denotes user manually opted
   // in from settings page and Payments did not update the status in time, or
@@ -285,7 +285,7 @@
 TEST_F(CreditCardFidoAuthenticatorTest, GetUserOptInIntention_IntentToOptOut) {
   // If payments is requesting a FIDO auth, then that means user is opted in
   // from payments.
-  payments::PaymentsClient::UnmaskDetails unmask_details;
+  payments::PaymentsNetworkInterface::UnmaskDetails unmask_details;
   unmask_details.unmask_auth_method = AutofillClient::UnmaskAuthMethod::kFido;
   // Set the local preference to be disabled, which denotes user manually opted
   // out from settings page, and Payments did not update the status in time.
diff --git a/components/autofill/core/browser/payments/credit_card_otp_authenticator.cc b/components/autofill/core/browser/payments/credit_card_otp_authenticator.cc
index ea3a201..ce472b9 100644
--- a/components/autofill/core/browser/payments/credit_card_otp_authenticator.cc
+++ b/components/autofill/core/browser/payments/credit_card_otp_authenticator.cc
@@ -18,7 +18,8 @@
     ~OtpAuthenticationResponse() = default;
 
 CreditCardOtpAuthenticator::CreditCardOtpAuthenticator(AutofillClient* client)
-    : autofill_client_(client), payments_client_(client->GetPaymentsClient()) {}
+    : autofill_client_(client),
+      payments_network_interface_(client->GetPaymentsNetworkInterface()) {}
 
 CreditCardOtpAuthenticator::~CreditCardOtpAuthenticator() = default;
 
@@ -26,8 +27,8 @@
     const std::u16string& otp) {
   otp_ = otp;
 
-  unmask_request_ =
-      std::make_unique<payments::PaymentsClient::UnmaskRequestDetails>();
+  unmask_request_ = std::make_unique<
+      payments::PaymentsNetworkInterface::UnmaskRequestDetails>();
   unmask_request_->card = *card_;
   unmask_request_->billing_customer_number = billing_customer_number_;
   unmask_request_->context_token = context_token_;
@@ -121,10 +122,10 @@
 
   autofill_metrics::LogOtpAuthAttempt(selected_challenge_option_.type);
 
-  // Asynchronously prepare payments_client. This is only needed once per
-  // session.
-  CHECK(payments_client_);
-  payments_client_->Prepare();
+  // Asynchronously prepare `payments_network_interface`. This is only needed
+  // once per session.
+  CHECK(payments_network_interface_);
+  payments_network_interface_->Prepare();
 
   // Send user selected challenge option to server.
   SendSelectChallengeOptionRequest();
@@ -133,8 +134,9 @@
 void CreditCardOtpAuthenticator::SendSelectChallengeOptionRequest() {
   selected_challenge_option_request_ongoing_ = true;
   // Prepare SelectChallengeOption request.
-  select_challenge_option_request_ = std::make_unique<
-      payments::PaymentsClient::SelectChallengeOptionRequestDetails>();
+  select_challenge_option_request_ =
+      std::make_unique<payments::PaymentsNetworkInterface::
+                           SelectChallengeOptionRequestDetails>();
   select_challenge_option_request_->selected_challenge_option =
       selected_challenge_option_;
   select_challenge_option_request_->billing_customer_number =
@@ -145,7 +147,7 @@
 
   // Send SelectChallengeOption request to server, the callback is
   // |OnDidSelectChallengeOption|.
-  payments_client_->SelectChallengeOption(
+  payments_network_interface_->SelectChallengeOption(
       *select_challenge_option_request_,
       base::BindOnce(&CreditCardOtpAuthenticator::OnDidSelectChallengeOption,
                      weak_ptr_factory_.GetWeakPtr()));
@@ -241,7 +243,7 @@
 void CreditCardOtpAuthenticator::SendUnmaskCardRequest() {
   unmask_request_->risk_data = risk_data_;
   unmask_card_request_timestamp_ = AutofillTickClock::NowTicks();
-  payments_client_->UnmaskCard(
+  payments_network_interface_->UnmaskCard(
       *unmask_request_,
       base::BindOnce(&CreditCardOtpAuthenticator::OnDidGetRealPan,
                      weak_ptr_factory_.GetWeakPtr()));
@@ -249,7 +251,8 @@
 
 void CreditCardOtpAuthenticator::OnDidGetRealPan(
     AutofillClient::PaymentsRpcResult result,
-    payments::PaymentsClient::UnmaskResponseDetails& response_details) {
+    payments::PaymentsNetworkInterface::UnmaskResponseDetails&
+        response_details) {
   if (unmask_card_request_timestamp_.has_value()) {
     autofill_metrics::LogOtpAuthUnmaskCardRequestLatency(
         AutofillTickClock::NowTicks() - *unmask_card_request_timestamp_,
@@ -299,7 +302,8 @@
       return;
     }
 
-    // The following prerequisites should be ensured in the PaymentsClient.
+    // The following prerequisites should be ensured in the
+    // PaymentsNetworkInterface.
     CHECK(!response_details.real_pan.empty());
     CHECK(!response_details.dcvv.empty());
     CHECK(!response_details.expiration_month.empty());
@@ -372,7 +376,7 @@
 
 void CreditCardOtpAuthenticator::Reset() {
   weak_ptr_factory_.InvalidateWeakPtrs();
-  payments_client_->CancelRequest();
+  payments_network_interface_->CancelRequest();
   card_ = nullptr;
   selected_challenge_option_ = CardUnmaskChallengeOption();
   otp_ = std::u16string();
diff --git a/components/autofill/core/browser/payments/credit_card_otp_authenticator.h b/components/autofill/core/browser/payments/credit_card_otp_authenticator.h
index edf3cd2..bac3079 100644
--- a/components/autofill/core/browser/payments/credit_card_otp_authenticator.h
+++ b/components/autofill/core/browser/payments/credit_card_otp_authenticator.h
@@ -13,7 +13,7 @@
 #include "components/autofill/core/browser/autofill_client.h"
 #include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/autofill/core/browser/payments/otp_unmask_delegate.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 
 namespace autofill {
 
@@ -94,9 +94,10 @@
       const std::string& context_token,
       int64_t billing_customer_number);
 
-  // Have PaymentsClient send a SelectChallengeOptionRequest. This will also be
-  // invoked when user requests to get a new OTP code. The response's callback
-  // function is |OnDidSelectChallengeOption()| when server response returns.
+  // Have PaymentsNetworkInterface send a SelectChallengeOptionRequest. This
+  // will also be invoked when user requests to get a new OTP code. The
+  // response's callback function is |OnDidSelectChallengeOption()| when server
+  // response returns.
   void SendSelectChallengeOptionRequest();
 
   // Callback function invoked when the client receives the select challenge
@@ -114,7 +115,8 @@
   // the correct error message and end the session.
   void OnDidGetRealPan(
       AutofillClient::PaymentsRpcResult result,
-      payments::PaymentsClient::UnmaskResponseDetails& response_details);
+      payments::PaymentsNetworkInterface::UnmaskResponseDetails&
+          response_details);
 
   // Reset the authenticator to initial states.
   virtual void Reset();
@@ -131,8 +133,8 @@
   // Invoked when risk data is fetched.
   void OnDidGetUnmaskRiskData(const std::string& risk_data);
 
-  // Have PaymentsClient send a UnmaskCardRequest for this card. The response's
-  // callback function is |OnDidGetRealPan()|.
+  // Have PaymentsNetworkInterface send a UnmaskCardRequest for this card. The
+  // response's callback function is |OnDidGetRealPan()|.
   void SendUnmaskCardRequest();
 
   // Card being unmasked.
@@ -158,19 +160,20 @@
   // The associated autofill client.
   raw_ptr<AutofillClient> autofill_client_;
 
-  // The associated payments client.
-  raw_ptr<payments::PaymentsClient> payments_client_;
+  // The associated PaymentsNetworkInterface.
+  raw_ptr<payments::PaymentsNetworkInterface> payments_network_interface_;
 
   // Weak pointer to object that is requesting authentication.
   base::WeakPtr<Requester> requester_;
 
   // This contains the details of the SelectChallengeOption request to be sent
   // to the server.
-  std::unique_ptr<payments::PaymentsClient::SelectChallengeOptionRequestDetails>
+  std::unique_ptr<
+      payments::PaymentsNetworkInterface::SelectChallengeOptionRequestDetails>
       select_challenge_option_request_;
 
   // This contains the details of the Unmask request to be sent to the server.
-  std::unique_ptr<payments::PaymentsClient::UnmaskRequestDetails>
+  std::unique_ptr<payments::PaymentsNetworkInterface::UnmaskRequestDetails>
       unmask_request_;
 
   // The timestamps when the requests are sent. Used for logging.
diff --git a/components/autofill/core/browser/payments/credit_card_otp_authenticator_unittest.cc b/components/autofill/core/browser/payments/credit_card_otp_authenticator_unittest.cc
index 81d5776..e164431 100644
--- a/components/autofill/core/browser/payments/credit_card_otp_authenticator_unittest.cc
+++ b/components/autofill/core/browser/payments/credit_card_otp_authenticator_unittest.cc
@@ -12,7 +12,7 @@
 #include "components/autofill/core/browser/metrics/payments/card_unmask_authentication_metrics.h"
 #include "components/autofill/core/browser/payments/autofill_error_dialog_context.h"
 #include "components/autofill/core/browser/payments/test_authentication_requester.h"
-#include "components/autofill/core/browser/payments/test_payments_client.h"
+#include "components/autofill/core/browser/payments/test_payments_network_interface.h"
 #include "components/autofill/core/browser/test_autofill_client.h"
 #include "components/autofill/core/browser/test_autofill_driver.h"
 #include "components/autofill/core/browser/test_personal_data_manager.h"
@@ -51,11 +51,12 @@
 
     requester_ = std::make_unique<TestAuthenticationRequester>();
 
-    payments_client_ = new payments::TestPaymentsClient(
+    payments_network_interface_ = new payments::TestPaymentsNetworkInterface(
         autofill_client_.GetURLLoaderFactory(),
         autofill_client_.GetIdentityManager(), &personal_data_manager_);
-    autofill_client_.set_test_payments_client(
-        std::unique_ptr<payments::TestPaymentsClient>(payments_client_));
+    autofill_client_.set_test_payments_network_interface(
+        std::unique_ptr<payments::TestPaymentsNetworkInterface>(
+            payments_network_interface_));
     authenticator_ =
         std::make_unique<CreditCardOtpAuthenticator>(&autofill_client_);
 
@@ -72,7 +73,7 @@
   void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
                        const std::string& real_pan,
                        bool server_returned_decline_details = false) {
-    payments::PaymentsClient::UnmaskResponseDetails response;
+    payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
     if (result != AutofillClient::PaymentsRpcResult::kSuccess) {
       if (server_returned_decline_details) {
         AutofillErrorDialogContext context;
@@ -95,7 +96,7 @@
 
   void OnDidGetRealPanWithFlowStatus(const std::string& flow_status,
                                      const std::string& context_token) {
-    payments::PaymentsClient::UnmaskResponseDetails response;
+    payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
     response.flow_status = flow_status;
     response.context_token = context_token;
     response.card_type = AutofillClient::PaymentsRpcCardType::kVirtualCard;
@@ -109,8 +110,9 @@
 
   void verifySelectChallengeOptionRequest(const std::string& context_token,
                                           int64_t billing_customer_number) {
-    const payments::PaymentsClient::SelectChallengeOptionRequestDetails*
-        request = payments_client_->select_challenge_option_request();
+    const payments::PaymentsNetworkInterface::
+        SelectChallengeOptionRequestDetails* request =
+            payments_network_interface_->select_challenge_option_request();
     EXPECT_EQ(request->context_token, context_token);
     EXPECT_EQ(request->billing_customer_number, billing_customer_number);
     // Selected challenge option should stay the same for the entire session.
@@ -134,7 +136,7 @@
   base::test::TaskEnvironment task_environment_;
   TestAutofillClient autofill_client_;
   TestPersonalDataManager personal_data_manager_;
-  raw_ptr<payments::TestPaymentsClient> payments_client_;
+  raw_ptr<payments::TestPaymentsNetworkInterface> payments_network_interface_;
   std::unique_ptr<CreditCardOtpAuthenticator> authenticator_;
   CreditCard card_;
   CardUnmaskChallengeOption selected_otp_challenge_option_;
@@ -160,8 +162,8 @@
 TEST_P(CreditCardOtpAuthenticatorTest, AuthenticateServerCardSuccess) {
   base::HistogramTester histogram_tester;
   // Simulate user selects OTP challenge option. Current context_token is from
-  // previous unmask response. TestPaymentsClient will ack the select challenge
-  // option request and directly invoke the callback.
+  // previous unmask response. TestPaymentsNetworkInterface will ack the select
+  // challenge option request and directly invoke the callback.
   authenticator_->OnChallengeOptionSelected(
       &card_, selected_otp_challenge_option_, requester_->GetWeakPtr(),
       /*context_token=*/"context_token_from_previous_unmask_response",
@@ -176,17 +178,20 @@
             "context_token_from_previous_unmask_response");
 
   // Simulate user provides the OTP and clicks 'Confirm' in the OTP dialog.
-  // TestPaymentsClient just stores the unmask request detail, won't invoke the
-  // callback. OnDidGetRealPan below will manually invoke the callback.
+  // TestPaymentsNetworkInterface just stores the unmask request detail, won't
+  // invoke the callback. OnDidGetRealPan below will manually invoke the
+  // callback.
   authenticator_->OnUnmaskPromptAccepted(/*otp=*/u"111111");
   // Verify the selected challenge option is correctly set in
   // UnmaskRequestDetails.
-  EXPECT_EQ(payments_client_->unmask_request()->selected_challenge_option->id,
+  EXPECT_EQ(payments_network_interface_->unmask_request()
+                ->selected_challenge_option->id,
             selected_otp_challenge_option_.id);
   // Verify that the otp is correctly set in UnmaskRequestDetails.
-  EXPECT_EQ(payments_client_->unmask_request()->otp, u"111111");
+  EXPECT_EQ(payments_network_interface_->unmask_request()->otp, u"111111");
   // Also verify that risk data is set in UnmaskRequestDetails.
-  EXPECT_FALSE(payments_client_->unmask_request()->risk_data.empty());
+  EXPECT_FALSE(
+      payments_network_interface_->unmask_request()->risk_data.empty());
 
   // Simulate server returns success and invoke the callback.
   OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess, kTestNumber);
@@ -212,12 +217,12 @@
 TEST_P(CreditCardOtpAuthenticatorTest, SelectChallengeOptionFailsWithVcnError) {
   base::HistogramTester histogram_tester;
   // Simulate server returns virtual card permanent failure.
-  payments_client_->set_select_challenge_option_result(
+  payments_network_interface_->set_select_challenge_option_result(
       AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure);
 
   // Simulate user selects OTP challenge option. Current context_token is from
-  // previous unmask response. TestPaymentsClient will ack the select challenge
-  // option request and directly invoke the callback.
+  // previous unmask response. TestPaymentsNetworkInterface will ack the select
+  // challenge option request and directly invoke the callback.
   authenticator_->OnChallengeOptionSelected(
       &card_, selected_otp_challenge_option_, requester_->GetWeakPtr(),
       /*context_token=*/"context_token_from_previous_unmask_response",
@@ -252,12 +257,12 @@
   base::HistogramTester histogram_tester;
   // Simulate server returns non-virtual card permanent failure, e.g. response
   // not complete.
-  payments_client_->set_select_challenge_option_result(
+  payments_network_interface_->set_select_challenge_option_result(
       AutofillClient::PaymentsRpcResult::kPermanentFailure);
 
   // Simulate user selects OTP challenge option. Current context_token is from
-  // previous unmask response. TestPaymentsClient will ack the select challenge
-  // option request and directly invoke the callback.
+  // previous unmask response. TestPaymentsNetworkInterface will ack the select
+  // challenge option request and directly invoke the callback.
   authenticator_->OnChallengeOptionSelected(
       &card_, selected_otp_challenge_option_, requester_->GetWeakPtr(),
       /*context_token=*/"context_token_from_previous_unmask_response",
@@ -289,8 +294,8 @@
   for (bool server_returned_decline_details : {true, false}) {
     base::HistogramTester histogram_tester;
     // Simulate user selects OTP challenge option. Current context_token is from
-    // previous unmask response. TestPaymentsClient will ack the select
-    // challenge option request and directly invoke the callback.
+    // previous unmask response. TestPaymentsNetworkInterface will ack the
+    // select challenge option request and directly invoke the callback.
     authenticator_->OnChallengeOptionSelected(
         &card_, selected_otp_challenge_option_, requester_->GetWeakPtr(),
         /*context_token=*/"context_token_from_previous_unmask_response",
@@ -302,8 +307,9 @@
     // TODO(crbug.com/1243475): Verify the otp dialog is shown.
 
     // Simulate user provides the OTP and clicks 'Confirm' in the OTP dialog.
-    // TestPaymentsClient just stores the unmask request detail, won't invoke
-    // the callback. OnDidGetRealPan below will manually invoke the callback.
+    // TestPaymentsNetworkInterface just stores the unmask request detail, won't
+    // invoke the callback. OnDidGetRealPan below will manually invoke the
+    // callback.
     authenticator_->OnUnmaskPromptAccepted(/*otp=*/u"111111");
     // Simulate server returns virtual card retrieval try again failure. We will
     // show the error dialog and end session.
@@ -346,8 +352,8 @@
 TEST_P(CreditCardOtpAuthenticatorTest, OtpAuthServerNonVcnError) {
   base::HistogramTester histogram_tester;
   // Simulate user selects OTP challenge option. Current context_token is from
-  // previous unmask response. TestPaymentsClient will ack the select challenge
-  // option request and directly invoke the callback.
+  // previous unmask response. TestPaymentsNetworkInterface will ack the select
+  // challenge option request and directly invoke the callback.
   authenticator_->OnChallengeOptionSelected(
       &card_, selected_otp_challenge_option_, requester_->GetWeakPtr(),
       /*context_token=*/"context_token_from_previous_unmask_response",
@@ -359,8 +365,9 @@
   // TODO(crbug.com/1243475): Verify the otp dialog is shown.
 
   // Simulate user provides the OTP and clicks 'Confirm' in the OTP dialog.
-  // TestPaymentsClient just stores the unmask request detail, won't invoke the
-  // callback. OnDidGetRealPan below will manually invoke the callback.
+  // TestPaymentsNetworkInterface just stores the unmask request detail, won't
+  // invoke the callback. OnDidGetRealPan below will manually invoke the
+  // callback.
   authenticator_->OnUnmaskPromptAccepted(/*otp=*/u"111111");
   // Simulate server returns non-Vcn try again failure. We will reuse virtual
   // card error dialog and end session.
@@ -391,8 +398,8 @@
 TEST_P(CreditCardOtpAuthenticatorTest, OtpAuthMismatchThenRetry) {
   base::HistogramTester histogram_tester;
   // Simulate user selects OTP challenge option. Current context_token is from
-  // previous unmask response. TestPaymentsClient will ack the select challenge
-  // option request and directly invoke the callback.
+  // previous unmask response. TestPaymentsNetworkInterface will ack the select
+  // challenge option request and directly invoke the callback.
   authenticator_->OnChallengeOptionSelected(
       &card_, selected_otp_challenge_option_, requester_->GetWeakPtr(),
       /*context_token=*/"context_token_from_previous_unmask_response",
@@ -404,17 +411,20 @@
   // TODO(crbug.com/1243475): Verify the otp dialog is shown.
 
   // Simulate user provides the OTP and clicks 'Confirm' in the OTP dialog.
-  // TestPaymentsClient just stores the unmask request detail, won't invoke the
-  // callback. OnDidGetRealPan below will manually invoke the callback.
+  // TestPaymentsNetworkInterface just stores the unmask request detail, won't
+  // invoke the callback. OnDidGetRealPan below will manually invoke the
+  // callback.
   authenticator_->OnUnmaskPromptAccepted(/*otp=*/u"222222");
   // Verify the selected challenge option is correctly set in
   // UnmaskRequestDetails.
-  EXPECT_EQ(payments_client_->unmask_request()->selected_challenge_option->id,
+  EXPECT_EQ(payments_network_interface_->unmask_request()
+                ->selected_challenge_option->id,
             selected_otp_challenge_option_.id);
   // Verify that the otp is correctly set in UnmaskRequestDetails.
-  EXPECT_EQ(payments_client_->unmask_request()->otp, u"222222");
+  EXPECT_EQ(payments_network_interface_->unmask_request()->otp, u"222222");
   // Also verify that risk data is set in UnmaskRequestDetails.
-  EXPECT_FALSE(payments_client_->unmask_request()->risk_data.empty());
+  EXPECT_FALSE(
+      payments_network_interface_->unmask_request()->risk_data.empty());
 
   // Simulate otp mismatch, server returns flow_status indicating incorrect otp.
   OnDidGetRealPanWithFlowStatus(
@@ -429,11 +439,12 @@
   authenticator_->OnUnmaskPromptAccepted(/*otp=*/u"333333");
   // Verify that the new otp is correctly set in UnmaskRequestDetails together
   // with the latest context token.
-  EXPECT_EQ(payments_client_->unmask_request()->otp, u"333333");
-  EXPECT_EQ(payments_client_->unmask_request()->context_token,
+  EXPECT_EQ(payments_network_interface_->unmask_request()->otp, u"333333");
+  EXPECT_EQ(payments_network_interface_->unmask_request()->context_token,
             "context_token_from_incorrect_otp");
   // Also verify that risk data is still set in UnmaskRequestDetails.
-  EXPECT_FALSE(payments_client_->unmask_request()->risk_data.empty());
+  EXPECT_FALSE(
+      payments_network_interface_->unmask_request()->risk_data.empty());
 
   // Simulate server returns success for the second try and invoke the callback.
   OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess, kTestNumber);
@@ -462,8 +473,8 @@
 TEST_P(CreditCardOtpAuthenticatorTest, OtpAuthExpiredThenResendOtp) {
   base::HistogramTester histogram_tester;
   // Simulate user selects OTP challenge option. Current context_token is from
-  // previous unmask response. TestPaymentsClient will ack the select challenge
-  // option request and directly invoke the callback.
+  // previous unmask response. TestPaymentsNetworkInterface will ack the select
+  // challenge option request and directly invoke the callback.
   authenticator_->OnChallengeOptionSelected(
       &card_, selected_otp_challenge_option_, requester_->GetWeakPtr(),
       /*context_token=*/"context_token_from_previous_unmask_response",
@@ -479,17 +490,20 @@
   // TODO(crbug.com/1243475): Verify the otp dialog is shown.
 
   // Simulate user provides the OTP and clicks 'Confirm' in the OTP dialog.
-  // TestPaymentsClient just stores the unmask request detail, won't invoke the
-  // callback. OnDidGetRealPan below will manually invoke the callback.
+  // TestPaymentsNetworkInterface just stores the unmask request detail, won't
+  // invoke the callback. OnDidGetRealPan below will manually invoke the
+  // callback.
   authenticator_->OnUnmaskPromptAccepted(/*otp=*/u"4444444");
   // Verify the selected challenge option is correctly set in
   // UnmaskRequestDetails.
-  EXPECT_EQ(payments_client_->unmask_request()->selected_challenge_option->id,
+  EXPECT_EQ(payments_network_interface_->unmask_request()
+                ->selected_challenge_option->id,
             selected_otp_challenge_option_.id);
   // Verify that the otp is correctly set in UnmaskRequestDetails.
-  EXPECT_EQ(payments_client_->unmask_request()->otp, u"4444444");
+  EXPECT_EQ(payments_network_interface_->unmask_request()->otp, u"4444444");
   // Also verify that risk data is set in UnmaskRequestDetails.
-  EXPECT_FALSE(payments_client_->unmask_request()->risk_data.empty());
+  EXPECT_FALSE(
+      payments_network_interface_->unmask_request()->risk_data.empty());
 
   // Simulate otp expired, server returns flow_status indicating expired otp.
   OnDidGetRealPanWithFlowStatus(
@@ -514,13 +528,14 @@
   authenticator_->OnUnmaskPromptAccepted(/*otp=*/u"555555");
   // Verify that the new otp is correctly set in UnmaskRequestDetails together
   // with the latest context token.
-  EXPECT_EQ(payments_client_->unmask_request()->otp, u"555555");
+  EXPECT_EQ(payments_network_interface_->unmask_request()->otp, u"555555");
   // Note here is NOT EQUAL. The context token is from the new select challenge
   // option response.
-  EXPECT_NE(payments_client_->unmask_request()->context_token,
+  EXPECT_NE(payments_network_interface_->unmask_request()->context_token,
             "context_token_from_expired_otp");
   // Also verify that risk data is still set in UnmaskRequestDetails.
-  EXPECT_FALSE(payments_client_->unmask_request()->risk_data.empty());
+  EXPECT_FALSE(
+      payments_network_interface_->unmask_request()->risk_data.empty());
 
   // Simulate server returns success for the second try and invoke the callback.
   OnDidGetRealPan(AutofillClient::PaymentsRpcResult::kSuccess, kTestNumber);
@@ -549,8 +564,8 @@
 TEST_P(CreditCardOtpAuthenticatorTest, OtpAuthCancelled) {
   base::HistogramTester histogram_tester;
   // Simulate user selects OTP challenge option. Current context_token is from
-  // previous unmask response. TestPaymentsClient will ack the select challenge
-  // option request and directly invoke the callback.
+  // previous unmask response. TestPaymentsNetworkInterface will ack the select
+  // challenge option request and directly invoke the callback.
   authenticator_->OnChallengeOptionSelected(
       &card_, selected_otp_challenge_option_, requester_->GetWeakPtr(),
       /*context_token=*/"context_token_from_previous_unmask_response",
@@ -638,7 +653,7 @@
   }
 
   // Simulate user selects OTP challenge option. Current context_token is from
-  // previous unmask response. TestPaymentsClient will ack the select
+  // previous unmask response. TestPaymentsNetworkInterface will ack the select
   // challenge option request and directly invoke the callback.
   authenticator_->OnChallengeOptionSelected(
       &card_, selected_otp_challenge_option_, requester_->GetWeakPtr(),
@@ -646,19 +661,22 @@
       /*billing_customer_number=*/kTestBillingCustomerNumber);
 
   // Simulate user provides the OTP and clicks 'Confirm' in the OTP dialog.
-  // TestPaymentsClient just stores the unmask request detail, won't invoke
-  // the callback. OnDidGetRealPan below will manually invoke the callback.
+  // TestPaymentsNetworkInterface just stores the unmask request detail, won't
+  // invoke the callback. OnDidGetRealPan below will manually invoke the
+  // callback.
   authenticator_->OnUnmaskPromptAccepted(/*otp=*/u"111111");
   // Verify the selected challenge option is correctly set in
   // UnmaskRequestDetails.
-  EXPECT_EQ(payments_client_->unmask_request()->selected_challenge_option->id,
+  EXPECT_EQ(payments_network_interface_->unmask_request()
+                ->selected_challenge_option->id,
             selected_otp_challenge_option_.id);
   // Verify that the otp is correctly set in UnmaskRequestDetails.
-  EXPECT_EQ(payments_client_->unmask_request()->otp, u"111111");
+  EXPECT_EQ(payments_network_interface_->unmask_request()->otp, u"111111");
   // Also verify that risk data is set in UnmaskRequestDetails.
-  EXPECT_FALSE(payments_client_->unmask_request()->risk_data.empty());
+  EXPECT_FALSE(
+      payments_network_interface_->unmask_request()->risk_data.empty());
   std::vector<ClientBehaviorConstants> signals =
-      payments_client_->unmask_request()->client_behavior_signals;
+      payments_network_interface_->unmask_request()->client_behavior_signals;
   if (MetadataEnabled() && CardNameAvailable() && CardArtAvailable()) {
     EXPECT_NE(
         signals.end(),
diff --git a/components/autofill/core/browser/payments/credit_card_risk_based_authenticator.cc b/components/autofill/core/browser/payments/credit_card_risk_based_authenticator.cc
index 13f69eef..c8d8bc3 100644
--- a/components/autofill/core/browser/payments/credit_card_risk_based_authenticator.cc
+++ b/components/autofill/core/browser/payments/credit_card_risk_based_authenticator.cc
@@ -43,8 +43,8 @@
   // Authenticate should not be called while there is an existing authentication
   // underway.
   DCHECK(!requester_);
-  unmask_request_details_ =
-      std::make_unique<payments::PaymentsClient::UnmaskRequestDetails>();
+  unmask_request_details_ = std::make_unique<
+      payments::PaymentsNetworkInterface::UnmaskRequestDetails>();
   card_ = std::move(card);
   requester_ = requester;
 
@@ -66,7 +66,7 @@
       payments::GetBillingCustomerId(
           autofill_client_->GetPersonalDataManager());
 
-  autofill_client_->GetPaymentsClient()->Prepare();
+  autofill_client_->GetPaymentsNetworkInterface()->Prepare();
   autofill_client_->LoadRiskData(
       base::BindOnce(&CreditCardRiskBasedAuthenticator::OnDidGetUnmaskRiskData,
                      weak_ptr_factory_.GetWeakPtr()));
@@ -75,7 +75,7 @@
 void CreditCardRiskBasedAuthenticator::OnDidGetUnmaskRiskData(
     const std::string& risk_data) {
   unmask_request_details_->risk_data = risk_data;
-  autofill_client_->GetPaymentsClient()->UnmaskCard(
+  autofill_client_->GetPaymentsNetworkInterface()->UnmaskCard(
       *unmask_request_details_,
       base::BindOnce(
           &CreditCardRiskBasedAuthenticator::OnUnmaskResponseReceived,
@@ -84,7 +84,8 @@
 
 void CreditCardRiskBasedAuthenticator::OnUnmaskResponseReceived(
     AutofillClient::PaymentsRpcResult result,
-    payments::PaymentsClient::UnmaskResponseDetails& response_details) {
+    payments::PaymentsNetworkInterface::UnmaskResponseDetails&
+        response_details) {
   if (!requester_) {
     Reset();
     return;
@@ -136,7 +137,7 @@
 
 void CreditCardRiskBasedAuthenticator::Reset() {
   weak_ptr_factory_.InvalidateWeakPtrs();
-  autofill_client_->GetPaymentsClient()->CancelRequest();
+  autofill_client_->GetPaymentsNetworkInterface()->CancelRequest();
   unmask_request_details_.reset();
   requester_.reset();
 }
diff --git a/components/autofill/core/browser/payments/credit_card_risk_based_authenticator.h b/components/autofill/core/browser/payments/credit_card_risk_based_authenticator.h
index 4a2387d1..12ee8e76 100644
--- a/components/autofill/core/browser/payments/credit_card_risk_based_authenticator.h
+++ b/components/autofill/core/browser/payments/credit_card_risk_based_authenticator.h
@@ -10,7 +10,7 @@
 
 #include "components/autofill/core/browser/autofill_client.h"
 #include "components/autofill/core/browser/payments/autofill_error_dialog_context.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 
 namespace autofill {
 
@@ -87,7 +87,8 @@
     // handling logic with OnRiskBasedAuthenticationResponseReceived().
     virtual void OnVirtualCardRiskBasedAuthenticationResponseReceived(
         AutofillClient::PaymentsRpcResult result,
-        payments::PaymentsClient::UnmaskResponseDetails& response_details) = 0;
+        payments::PaymentsNetworkInterface::UnmaskResponseDetails&
+            response_details) = 0;
   };
 
   explicit CreditCardRiskBasedAuthenticator(AutofillClient* client);
@@ -108,7 +109,8 @@
 
   void OnUnmaskResponseReceivedForTesting(
       AutofillClient::PaymentsRpcResult result,
-      payments::PaymentsClient::UnmaskResponseDetails& response_details) {
+      payments::PaymentsNetworkInterface::UnmaskResponseDetails&
+          response_details) {
     OnUnmaskResponseReceived(result, response_details);
   }
 
@@ -119,7 +121,8 @@
   // Callback function invoked when an unmask response has been received.
   void OnUnmaskResponseReceived(
       AutofillClient::PaymentsRpcResult result,
-      payments::PaymentsClient::UnmaskResponseDetails& response_details);
+      payments::PaymentsNetworkInterface::UnmaskResponseDetails&
+          response_details);
 
   // Reset the authenticator to its initial state.
   virtual void Reset();
@@ -135,7 +138,7 @@
 
   // This contains the details of the card unmask request to be sent to the
   // server.
-  std::unique_ptr<payments::PaymentsClient::UnmaskRequestDetails>
+  std::unique_ptr<payments::PaymentsNetworkInterface::UnmaskRequestDetails>
       unmask_request_details_;
 
   base::WeakPtrFactory<CreditCardRiskBasedAuthenticator> weak_ptr_factory_{
diff --git a/components/autofill/core/browser/payments/credit_card_risk_based_authenticator_unittest.cc b/components/autofill/core/browser/payments/credit_card_risk_based_authenticator_unittest.cc
index 4b83b463..327cccc 100644
--- a/components/autofill/core/browser/payments/credit_card_risk_based_authenticator_unittest.cc
+++ b/components/autofill/core/browser/payments/credit_card_risk_based_authenticator_unittest.cc
@@ -11,7 +11,7 @@
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/autofill/core/browser/payments/test_authentication_requester.h"
-#include "components/autofill/core/browser/payments/test_payments_client.h"
+#include "components/autofill/core/browser/payments/test_payments_network_interface.h"
 #include "components/autofill/core/browser/test_autofill_client.h"
 #include "components/autofill/core/browser/test_personal_data_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -35,8 +35,8 @@
 
   void SetUp() override {
     requester_ = std::make_unique<TestAuthenticationRequester>();
-    autofill_client_.set_test_payments_client(
-        std::make_unique<payments::TestPaymentsClient>(
+    autofill_client_.set_test_payments_network_interface(
+        std::make_unique<payments::TestPaymentsNetworkInterface>(
             autofill_client_.GetURLLoaderFactory(),
             autofill_client_.GetIdentityManager(), &personal_data_manager_));
     authenticator_ =
@@ -57,9 +57,9 @@
   }
 
  protected:
-  payments::TestPaymentsClient* payments_client() {
-    return static_cast<payments::TestPaymentsClient*>(
-        autofill_client_.GetPaymentsClient());
+  payments::TestPaymentsNetworkInterface* payments_network_interface() {
+    return static_cast<payments::TestPaymentsNetworkInterface*>(
+        autofill_client_.GetPaymentsNetworkInterface());
   }
 
   std::unique_ptr<TestAuthenticationRequester> requester_;
@@ -75,8 +75,10 @@
 TEST_F(CreditCardRiskBasedAuthenticatorTest, UnmaskRequestSetCorrectly) {
   authenticator_->Authenticate(card_, requester_->GetWeakPtr());
 
-  EXPECT_TRUE(payments_client()->unmask_request()->context_token.empty());
-  EXPECT_FALSE(payments_client()->unmask_request()->risk_data.empty());
+  EXPECT_TRUE(
+      payments_network_interface()->unmask_request()->context_token.empty());
+  EXPECT_FALSE(
+      payments_network_interface()->unmask_request()->risk_data.empty());
 }
 
 // Test that risk-based authentication returns the full PAN upon success.
@@ -84,7 +86,7 @@
   authenticator_->Authenticate(card_, requester_->GetWeakPtr());
 
   // Mock server response with valid masked server card information.
-  payments::PaymentsClient::UnmaskResponseDetails response;
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
   response.card_type = AutofillClient::PaymentsRpcCardType::kServerCard;
   response.real_pan = kTestNumber;
 
@@ -105,7 +107,7 @@
   authenticator_->Authenticate(card_, requester_->GetWeakPtr());
 
   // Payment server response when unmask request fails is empty.
-  payments::PaymentsClient::UnmaskResponseDetails response;
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
 
   authenticator_->OnUnmaskResponseReceivedForTesting(
       AutofillClient::PaymentsRpcResult::kPermanentFailure, response);
@@ -121,7 +123,7 @@
   authenticator_->Authenticate(card_, requester_->GetWeakPtr());
 
   // Mock server response with context token.
-  payments::PaymentsClient::UnmaskResponseDetails response;
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
   response.context_token = "fake_context_token";
 
   authenticator_->OnUnmaskResponseReceivedForTesting(
@@ -140,7 +142,7 @@
   authenticator_->Authenticate(card_, requester_->GetWeakPtr());
 
   // Mock server response with FIDO request options.
-  payments::PaymentsClient::UnmaskResponseDetails response;
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
   response.fido_request_options = GetTestRequestOptions();
 
   authenticator_->OnUnmaskResponseReceivedForTesting(
@@ -166,14 +168,16 @@
   card.set_cvc(u"123");
   card.SetExpirationYearFromString(base::UTF8ToUTF16(test::NextYear()));
   authenticator_->Authenticate(card, requester_->GetWeakPtr());
-  EXPECT_TRUE(payments_client()->unmask_request()->context_token.empty());
-  EXPECT_FALSE(payments_client()->unmask_request()->risk_data.empty());
-  EXPECT_TRUE(payments_client()
+  EXPECT_TRUE(
+      payments_network_interface()->unmask_request()->context_token.empty());
+  EXPECT_FALSE(
+      payments_network_interface()->unmask_request()->risk_data.empty());
+  EXPECT_TRUE(payments_network_interface()
                   ->unmask_request()
                   ->last_committed_primary_main_frame_origin.has_value());
 
   // Mock server response with valid virtual card information.
-  payments::PaymentsClient::UnmaskResponseDetails mocked_response;
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails mocked_response;
   mocked_response.real_pan = kTestVirtualCardNumber;
   mocked_response.card_type = AutofillClient::PaymentsRpcCardType::kVirtualCard;
   mocked_response.expiration_year = test::NextYear();
@@ -205,13 +209,15 @@
   card.set_cvc(u"123");
   card.SetExpirationYearFromString(base::UTF8ToUTF16(test::NextYear()));
   authenticator_->Authenticate(card, requester_->GetWeakPtr());
-  EXPECT_TRUE(payments_client()->unmask_request()->context_token.empty());
-  EXPECT_FALSE(payments_client()->unmask_request()->risk_data.empty());
-  EXPECT_TRUE(payments_client()
+  EXPECT_TRUE(
+      payments_network_interface()->unmask_request()->context_token.empty());
+  EXPECT_FALSE(
+      payments_network_interface()->unmask_request()->risk_data.empty());
+  EXPECT_TRUE(payments_network_interface()
                   ->unmask_request()
                   ->last_committed_primary_main_frame_origin.has_value());
   // Payment server response when unmask request fails is empty.
-  payments::PaymentsClient::UnmaskResponseDetails mocked_response;
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails mocked_response;
 
   authenticator_->OnUnmaskResponseReceivedForTesting(
       AutofillClient::PaymentsRpcResult::kPermanentFailure, mocked_response);
@@ -271,13 +277,15 @@
   authenticator_->Authenticate(virtual_card, requester_->GetWeakPtr());
 
   // Ensures the UnmaskRequestDetails is populated with correct contents.
-  EXPECT_TRUE(payments_client()->unmask_request()->context_token.empty());
-  EXPECT_FALSE(payments_client()->unmask_request()->risk_data.empty());
-  EXPECT_TRUE(payments_client()
+  EXPECT_TRUE(
+      payments_network_interface()->unmask_request()->context_token.empty());
+  EXPECT_FALSE(
+      payments_network_interface()->unmask_request()->risk_data.empty());
+  EXPECT_TRUE(payments_network_interface()
                   ->unmask_request()
                   ->last_committed_primary_main_frame_origin.has_value());
   std::vector<ClientBehaviorConstants> signals =
-      payments_client()->unmask_request()->client_behavior_signals;
+      payments_network_interface()->unmask_request()->client_behavior_signals;
   if (MetadataEnabled() && CardNameAvailable() && CardArtAvailable()) {
     EXPECT_NE(
         signals.end(),
diff --git a/components/autofill/core/browser/payments/credit_card_save_manager.cc b/components/autofill/core/browser/payments/credit_card_save_manager.cc
index cc1a354..4cae6fe 100644
--- a/components/autofill/core/browser/payments/credit_card_save_manager.cc
+++ b/components/autofill/core/browser/payments/credit_card_save_manager.cc
@@ -36,7 +36,7 @@
 #include "components/autofill/core/browser/logging/log_manager.h"
 #include "components/autofill/core/browser/metrics/autofill_metrics.h"
 #include "components/autofill/core/browser/payments/client_behavior_constants.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/payments_util.h"
 #include "components/autofill/core/browser/payments/virtual_card_enrollment_manager.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
@@ -85,11 +85,11 @@
 
 CreditCardSaveManager::CreditCardSaveManager(
     AutofillClient* client,
-    payments::PaymentsClient* payments_client,
+    payments::PaymentsNetworkInterface* payments_network_interface,
     const std::string& app_locale,
     PersonalDataManager* personal_data_manager)
     : client_(client),
-      payments_client_(payments_client),
+      payments_network_interface_(payments_network_interface),
       app_locale_(app_locale),
       personal_data_manager_(personal_data_manager) {}
 
@@ -219,10 +219,11 @@
     const FormStructure& submitted_form,
     const CreditCard& card,
     const bool uploading_local_card) {
-  // Abort the uploading if |payments_client_| is nullptr.
-  if (!payments_client_)
+  // Abort the uploading if `payments_network_interface_` is nullptr.
+  if (!payments_network_interface_) {
     return;
-  upload_request_ = payments::PaymentsClient::UploadRequestDetails();
+  }
+  upload_request_ = payments::PaymentsNetworkInterface::UploadRequestDetails();
   upload_request_.card = card;
   uploading_local_card_ = uploading_local_card;
   show_save_prompt_.reset();
@@ -368,14 +369,15 @@
         ClientBehaviorConstants::kOfferingToSaveCvc);
   }
 
-  payments_client_->GetUploadDetails(
+  payments_network_interface_->GetUploadDetails(
       country_only_profiles, upload_request_.detected_values,
       upload_request_.client_behavior_signals, app_locale_,
       base::BindOnce(&CreditCardSaveManager::OnDidGetUploadDetails,
                      weak_ptr_factory_.GetWeakPtr()),
       payments::kUploadPaymentMethodBillableServiceNumber,
       payments::GetBillingCustomerId(personal_data_manager_),
-      payments::PaymentsClient::UploadCardSource::UPSTREAM_CHECKOUT_FLOW);
+      payments::PaymentsNetworkInterface::UploadCardSource::
+          UPSTREAM_CHECKOUT_FLOW);
 }
 
 void CreditCardSaveManager::AttemptToOfferCvcUploadSave(
@@ -425,7 +427,7 @@
 
 void CreditCardSaveManager::OnDidUploadCard(
     AutofillClient::PaymentsRpcResult result,
-    const payments::PaymentsClient::UploadCardResponseDetails&
+    const payments::PaymentsNetworkInterface::UploadCardResponseDetails&
         upload_card_response_details) {
   if (observer_for_testing_) {
     observer_for_testing_->OnReceivedUploadCardResponse();
@@ -557,8 +559,9 @@
       return;
     }
 
-    // Do *not* call payments_client_->Prepare() here. We shouldn't send
-    // credentials until the user has explicitly accepted a prompt to upload.
+    // Do *not* call payments_network_interface_->Prepare() here. We shouldn't
+    // send credentials until the user has explicitly accepted a prompt to
+    // upload.
     if (!supported_card_bin_ranges.empty() &&
         !payments::IsCreditCardNumberSupported(upload_request_.card.number(),
                                                supported_card_bin_ranges)) {
@@ -618,11 +621,19 @@
     if (observer_for_testing_) {
       observer_for_testing_->OnOfferLocalSave();
     }
+    AutofillClient::CardSaveType card_save_type =
+        AutofillClient::CardSaveType::kCardSaveOnly;
+    // Show `kCardSaveWithCvc` prompt if flag is on and CVC is not empty.
+    if (!card_save_candidate_.cvc().empty() &&
+        personal_data_manager_->IsPaymentCvcStorageEnabled()) {
+      card_save_type = AutofillClient::CardSaveType::kCardSaveWithCvc;
+    }
     client_->ConfirmSaveCreditCardLocally(
         card_save_candidate_,
         AutofillClient::SaveCreditCardOptions()
             // TODO(crbug.com/1479239): Refactor SaveCreditCardOptions.
-            .with_show_prompt(show_save_prompt_.value_or(true)),
+            .with_show_prompt(show_save_prompt_.value_or(true))
+            .with_card_save_type(card_save_type),
         base::BindOnce(&CreditCardSaveManager::OnUserDidDecideOnLocalSave,
                        weak_ptr_factory_.GetWeakPtr()));
   }
@@ -670,6 +681,13 @@
           return server_card->HasSameNumberAs(upload_request_.card) &&
                  !server_card->HasSameExpirationDateAs(upload_request_.card);
         });
+    AutofillClient::CardSaveType card_save_type =
+        AutofillClient::CardSaveType::kCardSaveOnly;
+    // Show `kCardSaveWithCvc` prompt if flag is on and CVC is not empty.
+    if (!upload_request_.card.cvc().empty() &&
+        personal_data_manager_->IsPaymentCvcStorageEnabled()) {
+      card_save_type = AutofillClient::CardSaveType::kCardSaveWithCvc;
+    }
     client_->ConfirmSaveCreditCardToCloud(
         upload_request_.card, legal_message_lines_,
         AutofillClient::SaveCreditCardOptions()
@@ -679,7 +697,8 @@
                 should_request_expiration_date_from_user_)
             .with_show_prompt(show_save_prompt_.value_or(true))
             .with_same_last_four_as_server_card_but_different_expiration_date(
-                found_server_card_with_same_last_four_but_different_expiration),
+                found_server_card_with_same_last_four_but_different_expiration)
+            .with_card_save_type(card_save_type),
         base::BindOnce(&CreditCardSaveManager::OnUserDidDecideOnUploadSave,
                        weak_ptr_factory_.GetWeakPtr()));
     client_->LoadRiskData(
@@ -771,7 +790,7 @@
 
 void CreditCardSaveManager::SetProfilesForCreditCardUpload(
     const CreditCard& card,
-    payments::PaymentsClient::UploadRequestDetails* upload_request) {
+    payments::PaymentsNetworkInterface::UploadRequestDetails* upload_request) {
   std::vector<AutofillProfile> candidate_profiles;
   const base::Time now = AutofillClock::Now();
   const base::TimeDelta fifteen_minutes = base::Minutes(15);
@@ -1155,7 +1174,7 @@
       uploading_local_card_
           ? AutofillMetrics::USER_ACCEPTED_UPLOAD_OF_LOCAL_CARD
           : AutofillMetrics::USER_ACCEPTED_UPLOAD_OF_NEW_CARD);
-  payments_client_->UploadCard(
+  payments_network_interface_->UploadCard(
       upload_request_, base::BindOnce(&CreditCardSaveManager::OnDidUploadCard,
                                       weak_ptr_factory_.GetWeakPtr()));
 }
diff --git a/components/autofill/core/browser/payments/credit_card_save_manager.h b/components/autofill/core/browser/payments/credit_card_save_manager.h
index 1fc03a5..c22e855 100644
--- a/components/autofill/core/browser/payments/credit_card_save_manager.h
+++ b/components/autofill/core/browser/payments/credit_card_save_manager.h
@@ -21,7 +21,7 @@
 #include "components/autofill/core/browser/metrics/autofill_metrics.h"
 #include "components/autofill/core/browser/metrics/payments/credit_card_save_metrics.h"
 #include "components/autofill/core/browser/payments/legal_message_line.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/strike_databases/payments/credit_card_save_strike_database.h"
 #include "components/autofill/core/browser/strike_databases/payments/cvc_storage_strike_database.h"
@@ -98,10 +98,11 @@
   };
 
   // The parameters should outlive the CreditCardSaveManager.
-  CreditCardSaveManager(AutofillClient* client,
-                        payments::PaymentsClient* payments_client,
-                        const std::string& app_locale,
-                        PersonalDataManager* personal_data_manager);
+  CreditCardSaveManager(
+      AutofillClient* client,
+      payments::PaymentsNetworkInterface* payments_network_interface,
+      const std::string& app_locale,
+      PersonalDataManager* personal_data_manager);
 
   CreditCardSaveManager(const CreditCardSaveManager&) = delete;
   CreditCardSaveManager& operator=(const CreditCardSaveManager&) = delete;
@@ -175,7 +176,7 @@
   // identifier for the card on the server. Exposed for testing.
   virtual void OnDidUploadCard(
       AutofillClient::PaymentsRpcResult result,
-      const payments::PaymentsClient::UploadCardResponseDetails&
+      const payments::PaymentsNetworkInterface::UploadCardResponseDetails&
           upload_card_response_details);
 
  private:
@@ -229,7 +230,7 @@
   // contain countries.
   void SetProfilesForCreditCardUpload(
       const CreditCard& card,
-      payments::PaymentsClient::UploadRequestDetails* upload_request);
+      payments::PaymentsNetworkInterface::UploadRequestDetails* upload_request);
 
   // Analyzes the decisions made while importing address profile and credit card
   // data in preparation for upload credit card save, in order to determine what
@@ -305,7 +306,8 @@
   // if the user has accepted the prompt.
   void OnDidGetUploadRiskData(const std::string& risk_data);
 
-  // Finalizes the upload request and calls PaymentsClient::UploadCard().
+  // Finalizes the upload request and calls
+  // PaymentsNetworkInterface::UploadCard().
   void SendUploadCardRequest();
 
   // Called when the user ignored or declined the credit card save prompt. Logs
@@ -344,7 +346,7 @@
 
   // Handles Payments service requests. Weak ref. In Chrome, it's owned by
   // ChromeAutofillClient and ChromeAutofillClientIOS.
-  raw_ptr<payments::PaymentsClient> payments_client_;
+  raw_ptr<payments::PaymentsNetworkInterface> payments_network_interface_;
 
   std::string app_locale_;
 
@@ -358,7 +360,7 @@
   CreditCard card_save_candidate_;
 
   // Collected information about a pending upload request.
-  payments::PaymentsClient::UploadRequestDetails upload_request_;
+  payments::PaymentsNetworkInterface::UploadRequestDetails upload_request_;
 
   // A bitmask of |AutofillMetrics::CardUploadDecisionMetric| representing the
   // decisions made when determining if credit card upload save should be
diff --git a/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc b/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
index a2d3f56..0fe86e1 100644
--- a/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
+++ b/components/autofill/core/browser/payments/credit_card_save_manager_unittest.cc
@@ -35,7 +35,7 @@
 #include "components/autofill/core/browser/payments/payments_util.h"
 #include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
 #include "components/autofill/core/browser/payments/test_legal_message_line.h"
-#include "components/autofill/core/browser/payments/test_payments_client.h"
+#include "components/autofill/core/browser/payments/test_payments_network_interface.h"
 #include "components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/strike_databases/payments/test_credit_card_save_strike_database.h"
@@ -162,18 +162,18 @@
  public:
   MockVirtualCardEnrollmentManager(
       TestPersonalDataManager* personal_data_manager,
-      payments::TestPaymentsClient* payments_client,
+      payments::TestPaymentsNetworkInterface* payments_network_interface,
       TestAutofillClient* autofill_client)
       : TestVirtualCardEnrollmentManager(personal_data_manager,
-                                         payments_client,
+                                         payments_network_interface,
                                          autofill_client) {}
   MOCK_METHOD(
       void,
       InitVirtualCardEnroll,
       (const CreditCard& credit_card,
        VirtualCardEnrollmentSource virtual_card_enrollment_source,
-       absl::optional<
-           payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails>
+       absl::optional<payments::PaymentsNetworkInterface::
+                          GetDetailsForEnrollmentResponseDetails>
            get_details_for_enrollment_response_details,
        PrefService* user_prefs,
        VirtualCardEnrollmentManager::RiskAssessmentFunction
@@ -204,23 +204,23 @@
                          /*strike_database=*/nullptr,
                          /*image_fetcher=*/nullptr);
     autofill_driver_ = std::make_unique<TestAutofillDriver>();
-    autofill_client_.set_test_payments_client(
-        std::make_unique<payments::TestPaymentsClient>(
+    autofill_client_.set_test_payments_network_interface(
+        std::make_unique<payments::TestPaymentsNetworkInterface>(
             autofill_client_.GetURLLoaderFactory(),
             autofill_client_.GetIdentityManager(), &personal_data()));
     virtual_card_enrollment_manager_ =
         std::make_unique<MockVirtualCardEnrollmentManager>(
-            autofill_client_.GetPersonalDataManager(), &payments_client(),
-            &autofill_client_);
+            autofill_client_.GetPersonalDataManager(),
+            &payments_network_interface(), &autofill_client_);
     ON_CALL(autofill_client_, GetVirtualCardEnrollmentManager())
         .WillByDefault(testing::Return(virtual_card_enrollment_manager_.get()));
-    credit_card_save_manager_ =
-        new TestCreditCardSaveManager(autofill_driver_.get(), &autofill_client_,
-                                      &payments_client(), &personal_data());
+    credit_card_save_manager_ = new TestCreditCardSaveManager(
+        autofill_driver_.get(), &autofill_client_,
+        &payments_network_interface(), &personal_data());
     credit_card_save_manager_->SetCreditCardUploadEnabled(true);
     autofill_client_.set_test_form_data_importer(
         std::make_unique<TestFormDataImporter>(
-            &autofill_client_, &payments_client(),
+            &autofill_client_, &payments_network_interface(),
             std::unique_ptr<CreditCardSaveManager>(credit_card_save_manager_),
             /*iban_save_manager=*/nullptr, &personal_data(), "en-US"));
     autofill_client_.GetStrikeDatabase();
@@ -412,9 +412,9 @@
     return static_cast<MockPersonalDataManager&>(
         *autofill_client_.GetPersonalDataManager());
   }
-  payments::TestPaymentsClient& payments_client() {
-    return static_cast<payments::TestPaymentsClient&>(
-        *autofill_client_.GetPaymentsClient());
+  payments::TestPaymentsNetworkInterface& payments_network_interface() {
+    return static_cast<payments::TestPaymentsNetworkInterface&>(
+        *autofill_client_.GetPaymentsNetworkInterface());
   }
   TestStrikeDatabase& strike_database() {
     return static_cast<TestStrikeDatabase&>(
@@ -584,17 +584,21 @@
   FormSubmitted(credit_card_form);
   EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
   EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
-  EXPECT_TRUE(payments_client().client_behavior_signals_in_request().empty());
+  EXPECT_TRUE(payments_network_interface()
+                  .client_behavior_signals_in_request()
+                  .empty());
 
   // Verify that even though the full address profile was saved, only the
   // country was included in the upload details request to payments.
   EXPECT_EQ(1U, personal_data().GetProfiles().size());
   AutofillProfile only_country(AddressCountryCode("US"));
-  EXPECT_EQ(1U, payments_client().addresses_in_upload_details().size());
+  EXPECT_EQ(1U,
+            payments_network_interface().addresses_in_upload_details().size());
   // AutofillProfile::Compare will ignore the difference in guid between our
   // actual profile being sent and the expected one constructed here.
-  EXPECT_EQ(0, payments_client().addresses_in_upload_details()[0].Compare(
-                   only_country));
+  EXPECT_EQ(
+      0, payments_network_interface().addresses_in_upload_details()[0].Compare(
+             only_country));
 
   // Server did not send a server_id, expect copy of card is not stored.
   EXPECT_TRUE(personal_data().GetCreditCards().empty());
@@ -610,7 +614,7 @@
   // We should find that full addresses are included in the UploadCard request,
   // even though only countries were included in GetUploadDetails.
   EXPECT_THAT(
-      payments_client().addresses_in_upload_card(),
+      payments_network_interface().addresses_in_upload_card(),
       testing::UnorderedElementsAreArray({*personal_data().GetProfiles()[0]}));
 }
 #endif
@@ -920,9 +924,9 @@
 
   credit_card_save_manager_->SetCreditCardUploadEnabled(true);
 
-  payments::PaymentsClient::UploadCardResponseDetails
+  payments::PaymentsNetworkInterface::UploadCardResponseDetails
       upload_card_response_details;
-  payments_client().SetUploadCardResponseDetailsForUploadCard(
+  payments_network_interface().SetUploadCardResponseDetailsForUploadCard(
       upload_card_response_details);
 
   // Create, fill and submit an address form in order to establish a recent
@@ -1547,7 +1551,7 @@
   // Confirm that client_behavior_signals vector does contain the
   // FasterAndProtected signal.
   std::vector<ClientBehaviorConstants> client_behavior_signals_in_request =
-      payments_client().client_behavior_signals_in_request();
+      payments_network_interface().client_behavior_signals_in_request();
   EXPECT_THAT(
       client_behavior_signals_in_request,
       testing::Contains(ClientBehaviorConstants::kUsingFasterAndProtectedUi));
@@ -1576,7 +1580,7 @@
   // Confirm that client_behavior_signals vector does not contain the
   // FasterAndProtected signal.
   std::vector<ClientBehaviorConstants> client_behavior_signals_in_request =
-      payments_client().client_behavior_signals_in_request();
+      payments_network_interface().client_behavior_signals_in_request();
   EXPECT_THAT(client_behavior_signals_in_request,
               testing::Not(testing::Contains(
                   ClientBehaviorConstants::kUsingFasterAndProtectedUi)));
@@ -1608,7 +1612,7 @@
   // Confirm that client_behavior_signals vector does contain the
   // OfferingToSaveCvc signal.
   std::vector<ClientBehaviorConstants> client_behavior_signals_in_request =
-      payments_client().client_behavior_signals_in_request();
+      payments_network_interface().client_behavior_signals_in_request();
   EXPECT_THAT(client_behavior_signals_in_request,
               testing::Contains(ClientBehaviorConstants::kOfferingToSaveCvc));
 }
@@ -1638,7 +1642,7 @@
   // Confirm that client_behavior_signals vector does not contain the
   // OfferingToSaveCvc signal.
   std::vector<ClientBehaviorConstants> client_behavior_signals_in_request =
-      payments_client().client_behavior_signals_in_request();
+      payments_network_interface().client_behavior_signals_in_request();
   EXPECT_THAT(client_behavior_signals_in_request,
               testing::Not(testing::Contains(
                   ClientBehaviorConstants::kOfferingToSaveCvc)));
@@ -1668,7 +1672,7 @@
   // Confirm that client_behavior_signals vector does not contain the
   // OfferingToSaveCvc signal.
   std::vector<ClientBehaviorConstants> client_behavior_signals_in_request =
-      payments_client().client_behavior_signals_in_request();
+      payments_network_interface().client_behavior_signals_in_request();
   EXPECT_THAT(client_behavior_signals_in_request,
               testing::Not(testing::Contains(
                   ClientBehaviorConstants::kOfferingToSaveCvc)));
@@ -1698,7 +1702,7 @@
   // Confirm that client_behavior_signals vector does not contain the
   // OfferingToSaveCvc signal.
   std::vector<ClientBehaviorConstants> client_behavior_signals_in_request =
-      payments_client().client_behavior_signals_in_request();
+      payments_network_interface().client_behavior_signals_in_request();
   EXPECT_THAT(client_behavior_signals_in_request,
               testing::Not(testing::Contains(
                   ClientBehaviorConstants::kOfferingToSaveCvc)));
@@ -1733,7 +1737,7 @@
   // Confirm that client_behavior_signals vector does not contain the
   // OfferingToSaveCvc signal.
   std::vector<ClientBehaviorConstants> client_behavior_signals_in_request =
-      payments_client().client_behavior_signals_in_request();
+      payments_network_interface().client_behavior_signals_in_request();
   EXPECT_THAT(client_behavior_signals_in_request,
               testing::Not(testing::Contains(
                   ClientBehaviorConstants::kOfferingToSaveCvc)));
@@ -2289,7 +2293,7 @@
   ExpectCardUploadDecision(
       histogram_tester,
       autofill_metrics::USER_REQUESTED_TO_PROVIDE_CARDHOLDER_NAME);
-  EXPECT_TRUE(payments_client().detected_values_in_upload_details() &
+  EXPECT_TRUE(payments_network_interface().detected_values_in_upload_details() &
               CreditCardSaveManager::DetectedValue::USER_PROVIDED_NAME);
 }
 
@@ -2327,7 +2331,7 @@
   ExpectCardUploadDecision(
       histogram_tester,
       autofill_metrics::USER_REQUESTED_TO_PROVIDE_CARDHOLDER_NAME);
-  EXPECT_TRUE(payments_client().detected_values_in_upload_details() &
+  EXPECT_TRUE(payments_network_interface().detected_values_in_upload_details() &
               CreditCardSaveManager::DetectedValue::USER_PROVIDED_NAME);
 }
 
@@ -2428,8 +2432,9 @@
   ExpectNoCardUploadDecision(
       histogram_tester,
       autofill_metrics::USER_REQUESTED_TO_PROVIDE_CARDHOLDER_NAME);
-  EXPECT_FALSE(payments_client().detected_values_in_upload_details() &
-               CreditCardSaveManager::DetectedValue::USER_PROVIDED_NAME);
+  EXPECT_FALSE(
+      payments_network_interface().detected_values_in_upload_details() &
+      CreditCardSaveManager::DetectedValue::USER_PROVIDED_NAME);
 #endif
 }
 
@@ -2476,8 +2481,9 @@
   ExpectNoCardUploadDecision(
       histogram_tester,
       autofill_metrics::USER_REQUESTED_TO_PROVIDE_CARDHOLDER_NAME);
-  EXPECT_FALSE(payments_client().detected_values_in_upload_details() &
-               CreditCardSaveManager::DetectedValue::USER_PROVIDED_NAME);
+  EXPECT_FALSE(
+      payments_network_interface().detected_values_in_upload_details() &
+      CreditCardSaveManager::DetectedValue::USER_PROVIDED_NAME);
 #endif
 }
 
@@ -2524,8 +2530,9 @@
   ExpectNoCardUploadDecision(
       histogram_tester,
       autofill_metrics::USER_REQUESTED_TO_PROVIDE_CARDHOLDER_NAME);
-  EXPECT_FALSE(payments_client().detected_values_in_upload_details() &
-               CreditCardSaveManager::DetectedValue::USER_PROVIDED_NAME);
+  EXPECT_FALSE(
+      payments_network_interface().detected_values_in_upload_details() &
+      CreditCardSaveManager::DetectedValue::USER_PROVIDED_NAME);
 #endif
 }
 
@@ -2776,9 +2783,9 @@
   EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
   EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
   EXPECT_TRUE(
-      payments_client().detected_values_in_upload_details() &
+      payments_network_interface().detected_values_in_upload_details() &
       CreditCardSaveManager::DetectedValue::USER_PROVIDED_EXPIRATION_DATE);
-  EXPECT_TRUE(payments_client().detected_values_in_upload_details() &
+  EXPECT_TRUE(payments_network_interface().detected_values_in_upload_details() &
               CreditCardSaveManager::DetectedValue::USER_PROVIDED_NAME);
 
 #endif
@@ -2824,7 +2831,7 @@
   EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
   EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
   EXPECT_TRUE(
-      payments_client().detected_values_in_upload_details() &
+      payments_network_interface().detected_values_in_upload_details() &
       CreditCardSaveManager::DetectedValue::USER_PROVIDED_EXPIRATION_DATE);
 }
 
@@ -2862,7 +2869,7 @@
   EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
   EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
   EXPECT_TRUE(
-      payments_client().detected_values_in_upload_details() &
+      payments_network_interface().detected_values_in_upload_details() &
       CreditCardSaveManager::DetectedValue::USER_PROVIDED_EXPIRATION_DATE);
 }
 
@@ -2900,7 +2907,7 @@
   EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
   EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
   EXPECT_TRUE(
-      payments_client().detected_values_in_upload_details() &
+      payments_network_interface().detected_values_in_upload_details() &
       CreditCardSaveManager::DetectedValue::USER_PROVIDED_EXPIRATION_DATE);
 }
 
@@ -2939,7 +2946,7 @@
   EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
   EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
   EXPECT_TRUE(
-      payments_client().detected_values_in_upload_details() &
+      payments_network_interface().detected_values_in_upload_details() &
       CreditCardSaveManager::DetectedValue::USER_PROVIDED_EXPIRATION_DATE);
 }
 
@@ -2979,7 +2986,7 @@
   EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
   EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
   EXPECT_TRUE(
-      payments_client().detected_values_in_upload_details() &
+      payments_network_interface().detected_values_in_upload_details() &
       CreditCardSaveManager::DetectedValue::USER_PROVIDED_EXPIRATION_DATE);
 }
 
@@ -3075,7 +3082,8 @@
 
   // Submit the form and check what detected_values for an upload save would be.
   FormSubmitted(credit_card_form);
-  int detected_values = payments_client().detected_values_in_upload_details();
+  int detected_values =
+      payments_network_interface().detected_values_in_upload_details();
   EXPECT_FALSE(detected_values & CreditCardSaveManager::DetectedValue::CVC);
   EXPECT_FALSE(detected_values &
                CreditCardSaveManager::DetectedValue::CARDHOLDER_NAME);
@@ -3106,7 +3114,7 @@
   // the expected bit.
   FormSubmitted(credit_card_form);
   int expected_detected_value = CreditCardSaveManager::DetectedValue::CVC;
-  EXPECT_EQ(payments_client().detected_values_in_upload_details() &
+  EXPECT_EQ(payments_network_interface().detected_values_in_upload_details() &
                 expected_detected_value,
             expected_detected_value);
 }
@@ -3128,7 +3136,7 @@
   FormSubmitted(credit_card_form);
   int expected_detected_value =
       CreditCardSaveManager::DetectedValue::CARDHOLDER_NAME;
-  EXPECT_EQ(payments_client().detected_values_in_upload_details() &
+  EXPECT_EQ(payments_network_interface().detected_values_in_upload_details() &
                 expected_detected_value,
             expected_detected_value);
 }
@@ -3156,7 +3164,7 @@
   FormSubmitted(credit_card_form);
   int expected_detected_value =
       CreditCardSaveManager::DetectedValue::ADDRESS_NAME;
-  EXPECT_EQ(payments_client().detected_values_in_upload_details() &
+  EXPECT_EQ(payments_network_interface().detected_values_in_upload_details() &
                 expected_detected_value,
             expected_detected_value);
 }
@@ -3185,7 +3193,7 @@
   int expected_detected_values =
       CreditCardSaveManager::DetectedValue::CARDHOLDER_NAME |
       CreditCardSaveManager::DetectedValue::ADDRESS_NAME;
-  EXPECT_EQ(payments_client().detected_values_in_upload_details() &
+  EXPECT_EQ(payments_network_interface().detected_values_in_upload_details() &
                 expected_detected_values,
             expected_detected_values);
 }
@@ -3210,7 +3218,8 @@
 
   // Submit the form and check what detected_values for an upload save would be.
   FormSubmitted(credit_card_form);
-  int detected_values = payments_client().detected_values_in_upload_details();
+  int detected_values =
+      payments_network_interface().detected_values_in_upload_details();
   EXPECT_FALSE(detected_values &
                CreditCardSaveManager::DetectedValue::CARDHOLDER_NAME);
   EXPECT_FALSE(detected_values &
@@ -3240,7 +3249,7 @@
   FormSubmitted(credit_card_form);
   int expected_detected_value =
       CreditCardSaveManager::DetectedValue::POSTAL_CODE;
-  EXPECT_EQ(payments_client().detected_values_in_upload_details() &
+  EXPECT_EQ(payments_network_interface().detected_values_in_upload_details() &
                 expected_detected_value,
             expected_detected_value);
 }
@@ -3269,8 +3278,9 @@
 
   // Submit the form and check what detected_values for an upload save would be.
   FormSubmitted(credit_card_form);
-  EXPECT_FALSE(payments_client().detected_values_in_upload_details() &
-               CreditCardSaveManager::DetectedValue::POSTAL_CODE);
+  EXPECT_FALSE(
+      payments_network_interface().detected_values_in_upload_details() &
+      CreditCardSaveManager::DetectedValue::POSTAL_CODE);
 }
 
 TEST_F(CreditCardSaveManagerTest, DetectAddressLine) {
@@ -3296,7 +3306,7 @@
   FormSubmitted(credit_card_form);
   int expected_detected_value =
       CreditCardSaveManager::DetectedValue::ADDRESS_LINE;
-  EXPECT_EQ(payments_client().detected_values_in_upload_details() &
+  EXPECT_EQ(payments_network_interface().detected_values_in_upload_details() &
                 expected_detected_value,
             expected_detected_value);
 }
@@ -3323,7 +3333,7 @@
   // the expected bit.
   FormSubmitted(credit_card_form);
   int expected_detected_value = CreditCardSaveManager::DetectedValue::LOCALITY;
-  EXPECT_EQ(payments_client().detected_values_in_upload_details() &
+  EXPECT_EQ(payments_network_interface().detected_values_in_upload_details() &
                 expected_detected_value,
             expected_detected_value);
 }
@@ -3351,7 +3361,7 @@
   FormSubmitted(credit_card_form);
   int expected_detected_value =
       CreditCardSaveManager::DetectedValue::ADMINISTRATIVE_AREA;
-  EXPECT_EQ(payments_client().detected_values_in_upload_details() &
+  EXPECT_EQ(payments_network_interface().detected_values_in_upload_details() &
                 expected_detected_value,
             expected_detected_value);
 }
@@ -3379,7 +3389,7 @@
   FormSubmitted(credit_card_form);
   int expected_detected_value =
       CreditCardSaveManager::DetectedValue::COUNTRY_CODE;
-  EXPECT_EQ(payments_client().detected_values_in_upload_details() &
+  EXPECT_EQ(payments_network_interface().detected_values_in_upload_details() &
                 expected_detected_value,
             expected_detected_value);
 }
@@ -3406,7 +3416,7 @@
   FormSubmitted(credit_card_form);
   int expected_detected_value =
       CreditCardSaveManager::DetectedValue::HAS_GOOGLE_PAYMENTS_ACCOUNT;
-  EXPECT_EQ(payments_client().detected_values_in_upload_details() &
+  EXPECT_EQ(payments_network_interface().detected_values_in_upload_details() &
                 expected_detected_value,
             expected_detected_value);
 }
@@ -3445,7 +3455,7 @@
       CreditCardSaveManager::DetectedValue::ADMINISTRATIVE_AREA |
       CreditCardSaveManager::DetectedValue::POSTAL_CODE |
       CreditCardSaveManager::DetectedValue::COUNTRY_CODE;
-  EXPECT_EQ(payments_client().detected_values_in_upload_details() &
+  EXPECT_EQ(payments_network_interface().detected_values_in_upload_details() &
                 expected_detected_values,
             expected_detected_values);
 }
@@ -3478,7 +3488,7 @@
       CreditCardSaveManager::DetectedValue::LOCALITY |
       CreditCardSaveManager::DetectedValue::POSTAL_CODE |
       CreditCardSaveManager::DetectedValue::COUNTRY_CODE;
-  EXPECT_EQ(payments_client().detected_values_in_upload_details() &
+  EXPECT_EQ(payments_network_interface().detected_values_in_upload_details() &
                 expected_detected_values,
             expected_detected_values);
 }
@@ -3524,7 +3534,7 @@
       CreditCardSaveManager::DetectedValue::LOCALITY |
       CreditCardSaveManager::DetectedValue::ADMINISTRATIVE_AREA |
       CreditCardSaveManager::DetectedValue::COUNTRY_CODE;
-  EXPECT_EQ(payments_client().detected_values_in_upload_details() &
+  EXPECT_EQ(payments_network_interface().detected_values_in_upload_details() &
                 expected_detected_values,
             expected_detected_values);
 }
@@ -4116,7 +4126,9 @@
   FormSubmitted(credit_card_form);
   EXPECT_FALSE(autofill_client_.ConfirmSaveCardLocallyWasCalled());
   EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
-  EXPECT_TRUE(payments_client().client_behavior_signals_in_request().empty());
+  EXPECT_TRUE(payments_network_interface()
+                  .client_behavior_signals_in_request()
+                  .empty());
 }
 
 TEST_F(CreditCardSaveManagerTest,
@@ -4143,7 +4155,7 @@
   // kUploadPaymentMethodBillableServiceNumber in the request.
   FormSubmitted(credit_card_form);
   EXPECT_EQ(payments::kUploadPaymentMethodBillableServiceNumber,
-            payments_client().billable_service_number_in_request());
+            payments_network_interface().billable_service_number_in_request());
 }
 
 TEST_F(CreditCardSaveManagerTest,
@@ -4174,7 +4186,8 @@
   // Confirm that the preflight request contained billing customer number in the
   // request.
   FormSubmitted(credit_card_form);
-  EXPECT_EQ(123456L, payments_client().billing_customer_number_in_request());
+  EXPECT_EQ(123456L,
+            payments_network_interface().billing_customer_number_in_request());
 }
 
 TEST_F(CreditCardSaveManagerTest,
@@ -4199,8 +4212,9 @@
 
   // Confirm that the preflight request contained the correct UploadCardSource.
   FormSubmitted(credit_card_form);
-  EXPECT_EQ(payments::PaymentsClient::UploadCardSource::UPSTREAM_CHECKOUT_FLOW,
-            payments_client().upload_card_source_in_request());
+  EXPECT_EQ(payments::PaymentsNetworkInterface::UploadCardSource::
+                UPSTREAM_CHECKOUT_FLOW,
+            payments_network_interface().upload_card_source_in_request());
 }
 
 // Tests that a card with some strikes (but not max strikes) should still show
@@ -4721,9 +4735,9 @@
 // bubble is shown.
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_NumStrikesLoggedOnUploadNotSuccess) {
-  payments::PaymentsClient::UploadCardResponseDetails
+  payments::PaymentsNetworkInterface::UploadCardResponseDetails
       upload_card_response_details;
-  payments_client().SetUploadCardResponseDetailsForUploadCard(
+  payments_network_interface().SetUploadCardResponseDetailsForUploadCard(
       upload_card_response_details);
   TestCreditCardSaveStrikeDatabase credit_card_save_strike_database =
       TestCreditCardSaveStrikeDatabase(&strike_database());
@@ -4755,7 +4769,7 @@
   std::vector<std::pair<int, int>> supported_card_bin_ranges{
       std::make_pair(4111, 4113), std::make_pair(34, 34),
       std::make_pair(300, 305)};
-  payments_client().SetSupportedBINRanges(supported_card_bin_ranges);
+  payments_network_interface().SetSupportedBINRanges(supported_card_bin_ranges);
   // Set up our credit card form data.
   FormData credit_card_form = CreateTestCreditCardFormData();
   FormsSeen(std::vector<FormData>(1, credit_card_form));
@@ -4780,7 +4794,7 @@
   std::vector<std::pair<int, int>> supported_card_bin_ranges{
       std::make_pair(4111, 4113), std::make_pair(34, 34),
       std::make_pair(300, 305)};
-  payments_client().SetSupportedBINRanges(supported_card_bin_ranges);
+  payments_network_interface().SetSupportedBINRanges(supported_card_bin_ranges);
   // Set up our credit card form data.
   FormData credit_card_form = CreateTestCreditCardFormData();
   FormsSeen(std::vector<FormData>(1, credit_card_form));
@@ -4812,7 +4826,7 @@
   // Set supported BIN ranges.
   std::vector<std::pair<int, int>> supported_card_bin_ranges{
       std::make_pair(4111, 4113)};
-  payments_client().SetSupportedBINRanges(supported_card_bin_ranges);
+  payments_network_interface().SetSupportedBINRanges(supported_card_bin_ranges);
 
   // Set up our credit card form data.
   FormData credit_card_form = CreateTestCreditCardFormData();
@@ -4832,10 +4846,11 @@
   EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
 }
 
-// Tests that if payment client returns an invalid legal message upload should
-// not be offered.
+// Tests that if the PaymentsNetworkInterface returns an invalid legal message,
+// upload should not be offered.
 TEST_F(CreditCardSaveManagerTest, InvalidLegalMessageInOnDidGetUploadDetails) {
-  payments_client().SetUseInvalidLegalMessageInGetUploadDetails(true);
+  payments_network_interface().SetUseInvalidLegalMessageInGetUploadDetails(
+      true);
 
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
@@ -4871,7 +4886,8 @@
 // Tests that has_multiple_legal_lines is set correctly in
 // SaveCreditCardOptions.
 TEST_F(CreditCardSaveManagerTest, LegalMessageInOnDidGetUploadDetails) {
-  payments_client().SetUseLegalMessageWithMultipleLinesInGetUploadDetails(true);
+  payments_network_interface()
+      .SetUseLegalMessageWithMultipleLinesInGetUploadDetails(true);
 
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
@@ -4979,7 +4995,7 @@
 
   // Set up upload card response and upload.
   const int64_t kInstrumentId = 12345L;
-  payments::PaymentsClient::UploadCardResponseDetails
+  payments::PaymentsNetworkInterface::UploadCardResponseDetails
       upload_card_response_details;
   upload_card_response_details.instrument_id = kInstrumentId;
 
@@ -5118,6 +5134,33 @@
   base::test::ScopedFeatureList feature_list_;
 };
 
+// Tests that the correct SaveCardOption is passed.
+TEST_P(ProceedWithSavingIfApplicableTest, CardWithCorrectSaveCardOption) {
+  prefs::SetPaymentCvcStorage(autofill_client_.GetPrefs(),
+                              IsSaveCvcPrefEnabled());
+  credit_card_save_manager_->SetCreditCardUploadEnabled(
+      IsCreditCardUpstreamEnabled());
+
+  // Set up our credit card form data.
+  FormData credit_card_form = CreateTestCreditCardFormData();
+  FormsSeen({credit_card_form});
+
+  // Edit the data, and submit.
+  credit_card_form.fields[0].value = u"Jane Doe";
+  credit_card_form.fields[1].value = u"4111111111111111";
+  credit_card_form.fields[2].value = ASCIIToUTF16(test::NextMonth());
+  credit_card_form.fields[3].value = ASCIIToUTF16(test::NextYear());
+  credit_card_form.fields[4].value = u"123";
+  FormSubmitted(credit_card_form);
+
+  EXPECT_EQ(autofill_client_.get_save_credit_card_options().card_save_type ==
+                AutofillClient::CardSaveType::kCardSaveWithCvc,
+            IsSaveCvcFeatureEnabled() && IsSaveCvcPrefEnabled());
+  EXPECT_EQ(autofill_client_.get_save_credit_card_options().card_save_type ==
+                AutofillClient::CardSaveType::kCardSaveOnly,
+            !IsSaveCvcFeatureEnabled() || !IsSaveCvcPrefEnabled());
+}
+
 // Tests that ProceedWithSavingIfApplicable should initiate card save or upload
 // flow with expected input.
 TEST_P(ProceedWithSavingIfApplicableTest, ProceedWithSavingIfApplicable_Card) {
@@ -5194,7 +5237,7 @@
   credit_card_save_manager_->set_upload_request_card(card);
 
   // Set up upload card response and upload.
-  payments::PaymentsClient::UploadCardResponseDetails
+  payments::PaymentsNetworkInterface::UploadCardResponseDetails
       upload_card_response_details;
   upload_card_response_details.instrument_id = 12345L;
 
@@ -5221,7 +5264,7 @@
   credit_card_save_manager_->set_upload_request_card(card);
 
   // Set up upload card response without instrument_id and upload.
-  payments::PaymentsClient::UploadCardResponseDetails
+  payments::PaymentsNetworkInterface::UploadCardResponseDetails
       upload_card_response_details_without_instrument_id;
 
   // Confirm CVC is not added to AutofillTable if instrument_id was empty.
@@ -5248,7 +5291,7 @@
         feature_list.InitAndDisableFeature(
             features::kAutofillEnableUpdateVirtualCardEnrollment);
       }
-      payments::PaymentsClient::UploadCardResponseDetails
+      payments::PaymentsNetworkInterface::UploadCardResponseDetails
           upload_card_response_details;
       upload_card_response_details.card_art_url =
           GURL("https://www.example.com/");
@@ -5302,14 +5345,14 @@
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
       features::kAutofillEnableUpdateVirtualCardEnrollment);
-  payments::PaymentsClient::UploadCardResponseDetails
+  payments::PaymentsNetworkInterface::UploadCardResponseDetails
       upload_card_response_details;
   upload_card_response_details.card_art_url = GURL("https://example.com/");
   upload_card_response_details.instrument_id = 9223372036854775807;
   upload_card_response_details.virtual_card_enrollment_state =
       CreditCard::VirtualCardEnrollmentState::kUnenrolledAndEligible;
 
-  payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails
+  payments::PaymentsNetworkInterface::GetDetailsForEnrollmentResponseDetails
       get_details_for_enrollment_response_details;
   get_details_for_enrollment_response_details.vcn_context_token =
       "test_context_token";
@@ -5323,8 +5366,8 @@
 
   CreditCard arg_credit_card;
   VirtualCardEnrollmentSource arg_virtual_card_enrollment_source;
-  absl::optional<
-      payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails>
+  absl::optional<payments::PaymentsNetworkInterface::
+                     GetDetailsForEnrollmentResponseDetails>
       arg_get_details_for_enrollment_response_details;
   EXPECT_CALL(autofill_client_, GetVirtualCardEnrollmentManager).Times(1);
   EXPECT_CALL(*virtual_card_enrollment_manager_,
diff --git a/components/autofill/core/browser/payments/full_card_request.cc b/components/autofill/core/browser/payments/full_card_request.cc
index c5fbc721..5a69cbc 100644
--- a/components/autofill/core/browser/payments/full_card_request.cc
+++ b/components/autofill/core/browser/payments/full_card_request.cc
@@ -28,16 +28,17 @@
 namespace autofill {
 namespace payments {
 
-FullCardRequest::FullCardRequest(AutofillClient* autofill_client,
-                                 payments::PaymentsClient* payments_client,
-                                 PersonalDataManager* personal_data_manager)
+FullCardRequest::FullCardRequest(
+    AutofillClient* autofill_client,
+    payments::PaymentsNetworkInterface* payments_network_interface,
+    PersonalDataManager* personal_data_manager)
     : autofill_client_(CHECK_DEREF(autofill_client)),
-      payments_client_(payments_client),
+      payments_network_interface_(payments_network_interface),
       personal_data_manager_(personal_data_manager),
       result_delegate_(nullptr),
       ui_delegate_(nullptr),
       should_unmask_card_(false) {
-  DCHECK(payments_client_);
+  DCHECK(payments_network_interface_);
   DCHECK(personal_data_manager_);
 }
 
@@ -141,7 +142,8 @@
     return;
   }
 
-  request_ = std::make_unique<payments::PaymentsClient::UnmaskRequestDetails>();
+  request_ = std::make_unique<
+      payments::PaymentsNetworkInterface::UnmaskRequestDetails>();
   request_->card = card;
   request_->last_committed_primary_main_frame_origin =
       last_committed_primary_main_frame_origin;
@@ -158,7 +160,7 @@
                          card.ShouldUpdateExpiration()) ||
                         (card_type == CreditCard::RecordType::kVirtualCard);
   if (should_unmask_card_) {
-    payments_client_->Prepare();
+    payments_network_interface_->Prepare();
     request_->billing_customer_number =
         GetBillingCustomerId(personal_data_manager_);
   }
@@ -258,14 +260,15 @@
 
 void FullCardRequest::SendUnmaskCardRequest() {
   real_pan_request_timestamp_ = AutofillTickClock::NowTicks();
-  payments_client_->UnmaskCard(*request_,
-                               base::BindOnce(&FullCardRequest::OnDidGetRealPan,
-                                              weak_ptr_factory_.GetWeakPtr()));
+  payments_network_interface_->UnmaskCard(
+      *request_, base::BindOnce(&FullCardRequest::OnDidGetRealPan,
+                                weak_ptr_factory_.GetWeakPtr()));
 }
 
 void FullCardRequest::OnDidGetRealPan(
     AutofillClient::PaymentsRpcResult result,
-    payments::PaymentsClient::UnmaskResponseDetails& response_details) {
+    payments::PaymentsNetworkInterface::UnmaskResponseDetails&
+        response_details) {
   // If the CVC field is populated, that means the user performed a CVC check.
   // If FIDO AssertionInfo is populated, then the user must have performed FIDO
   // authentication. Exactly one of these fields must be populated.
@@ -392,12 +395,13 @@
 
 void FullCardRequest::Reset() {
   weak_ptr_factory_.InvalidateWeakPtrs();
-  payments_client_->CancelRequest();
+  payments_network_interface_->CancelRequest();
   result_delegate_ = nullptr;
   ui_delegate_ = nullptr;
   request_.reset();
   should_unmask_card_ = false;
-  unmask_response_details_ = payments::PaymentsClient::UnmaskResponseDetails();
+  unmask_response_details_ =
+      payments::PaymentsNetworkInterface::UnmaskResponseDetails();
 }
 
 }  // namespace payments
diff --git a/components/autofill/core/browser/payments/full_card_request.h b/components/autofill/core/browser/payments/full_card_request.h
index c79a617..3a794b8 100644
--- a/components/autofill/core/browser/payments/full_card_request.h
+++ b/components/autofill/core/browser/payments/full_card_request.h
@@ -15,7 +15,7 @@
 #include "build/build_config.h"
 #include "components/autofill/core/browser/autofill_client.h"
 #include "components/autofill/core/browser/payments/card_unmask_delegate.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/ui/payments/card_unmask_prompt_options.h"
 #include "url/origin.h"
 
@@ -107,9 +107,10 @@
   };
 
   // The parameters should outlive the FullCardRequest.
-  FullCardRequest(AutofillClient* autofill_client,
-                  payments::PaymentsClient* payments_client,
-                  PersonalDataManager* personal_data_manager);
+  FullCardRequest(
+      AutofillClient* autofill_client,
+      payments::PaymentsNetworkInterface* payments_network_interface,
+      PersonalDataManager* personal_data_manager);
 
   FullCardRequest(const FullCardRequest&) = delete;
   FullCardRequest& operator=(const FullCardRequest&) = delete;
@@ -169,21 +170,22 @@
           absl::nullopt,
       absl::optional<std::string> context_token = absl::nullopt);
 
-  // Called by the payments client when a card has been unmasked.
+  // Called by the PaymentsNetworkInterface when a card has been unmasked.
   void OnDidGetRealPan(
       AutofillClient::PaymentsRpcResult result,
-      payments::PaymentsClient::UnmaskResponseDetails& response_details);
+      payments::PaymentsNetworkInterface::UnmaskResponseDetails&
+          response_details);
 
   // Called when verification is cancelled. This is used only by
   // CreditCardFidoAuthenticator to cancel the flow for opted-in users.
   void OnFIDOVerificationCancelled();
 
-  payments::PaymentsClient::UnmaskResponseDetails unmask_response_details()
-      const {
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails
+  unmask_response_details() const {
     return unmask_response_details_;
   }
 
-  payments::PaymentsClient::UnmaskRequestDetails*
+  payments::PaymentsNetworkInterface::UnmaskRequestDetails*
   GetUnmaskRequestDetailsForTesting() const {
     return request_.get();
   }
@@ -240,7 +242,7 @@
   void OnDidGetUnmaskRiskData(const std::string& risk_data);
 
   // Makes final preparations for the unmask request and calls
-  // PaymentsClient::UnmaskCard().
+  // PaymentsNetworkInterface::UnmaskCard().
   void SendUnmaskCardRequest();
 
   // Resets the state of the request.
@@ -250,7 +252,7 @@
   const raw_ref<AutofillClient> autofill_client_;
 
   // Responsible for unmasking a masked server card.
-  const raw_ptr<payments::PaymentsClient> payments_client_;
+  const raw_ptr<payments::PaymentsNetworkInterface> payments_network_interface_;
 
   // Responsible for updating the server card on disk after it's been unmasked.
   const raw_ptr<PersonalDataManager> personal_data_manager_;
@@ -262,7 +264,8 @@
   base::WeakPtr<UIDelegate> ui_delegate_;
 
   // The pending request to get a card's full PAN and CVC.
-  std::unique_ptr<payments::PaymentsClient::UnmaskRequestDetails> request_;
+  std::unique_ptr<payments::PaymentsNetworkInterface::UnmaskRequestDetails>
+      request_;
 
   // Whether the card unmask request should be sent to the payment server.
   bool should_unmask_card_;
@@ -272,7 +275,8 @@
   base::TimeTicks real_pan_request_timestamp_;
 
   // Includes all details from GetRealPan response.
-  payments::PaymentsClient::UnmaskResponseDetails unmask_response_details_;
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails
+      unmask_response_details_;
 
   // Enables destroying FullCardRequest while CVC prompt is showing or a server
   // communication is pending.
diff --git a/components/autofill/core/browser/payments/full_card_request_unittest.cc b/components/autofill/core/browser/payments/full_card_request_unittest.cc
index 477bab45..051fb8c 100644
--- a/components/autofill/core/browser/payments/full_card_request_unittest.cc
+++ b/components/autofill/core/browser/payments/full_card_request_unittest.cc
@@ -15,7 +15,7 @@
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/autofill/core/browser/metrics/payments/card_unmask_authentication_metrics.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/test_autofill_client.h"
 #include "components/autofill/core/browser/test_autofill_driver.h"
@@ -129,16 +129,16 @@
       : test_shared_loader_factory_(
             base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
                 &test_url_loader_factory_)) {
-    payments_client_ = std::make_unique<PaymentsClient>(
+    payments_network_interface_ = std::make_unique<PaymentsNetworkInterface>(
         test_shared_loader_factory_, autofill_client_.GetIdentityManager(),
         &personal_data_);
     request_ = std::make_unique<FullCardRequest>(
-        &autofill_client_, payments_client_.get(), &personal_data_);
+        &autofill_client_, payments_network_interface_.get(), &personal_data_);
     personal_data_.SetAccountInfoForPayments(
         autofill_client_.GetIdentityManager()->GetPrimaryAccountInfo(
             signin::ConsentLevel::kSync));
-    // Silence the warning from PaymentsClient about matching sync and Payments
-    // server types.
+    // Silence the warning from PaymentsNetworkInterface about matching sync and
+    // Payments server types.
     base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
         "sync-url", "https://google.com");
   }
@@ -165,7 +165,7 @@
   void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
                        const std::string& real_pan,
                        bool is_virtual_card = false) {
-    payments::PaymentsClient::UnmaskResponseDetails response;
+    payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
     response.card_type = is_virtual_card
                              ? AutofillClient::PaymentsRpcCardType::kVirtualCard
                              : AutofillClient::PaymentsRpcCardType::kServerCard;
@@ -176,7 +176,7 @@
                                const std::string& real_pan,
                                const std::string& dcvv,
                                bool is_virtual_card = false) {
-    payments::PaymentsClient::UnmaskResponseDetails response;
+    payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
     response.card_type = is_virtual_card
                              ? AutofillClient::PaymentsRpcCardType::kVirtualCard
                              : AutofillClient::PaymentsRpcCardType::kServerCard;
@@ -201,7 +201,7 @@
   TestAutofillClient autofill_client_;
   network::TestURLLoaderFactory test_url_loader_factory_;
   scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
-  std::unique_ptr<PaymentsClient> payments_client_;
+  std::unique_ptr<PaymentsNetworkInterface> payments_network_interface_;
   std::unique_ptr<FullCardRequest> request_;
 };
 
@@ -285,7 +285,7 @@
       result_delegate()->AsWeakPtr(), base::Value::Dict(),
       url::Origin::Create(GURL("https://example.com")),
       GURL("https://example.com"));
-  payments::PaymentsClient::UnmaskRequestDetails* request_details =
+  payments::PaymentsNetworkInterface::UnmaskRequestDetails* request_details =
       request()->GetUnmaskRequestDetailsForTesting();
   EXPECT_EQ(request_details->last_committed_primary_main_frame_origin->spec(),
             GURL("https://example.com/").spec());
@@ -430,7 +430,7 @@
       GURL("https://example.com/"), "test_context_token", challenge_option,
       url::Origin::Create(GURL("https://example.com")));
   ASSERT_TRUE(request()->GetShouldUnmaskCardForTesting());
-  payments::PaymentsClient::UnmaskRequestDetails* request_details =
+  payments::PaymentsNetworkInterface::UnmaskRequestDetails* request_details =
       request()->GetUnmaskRequestDetailsForTesting();
   EXPECT_EQ(request_details->selected_challenge_option->type,
             CardUnmaskChallengeOptionType::kCvc);
@@ -448,7 +448,7 @@
   details.exp_year = base::UTF8ToUTF16(test::NextYear());
   details.enable_fido_auth = false;
   card_unmask_delegate()->OnUnmaskPromptAccepted(details);
-  payments::PaymentsClient::UnmaskResponseDetails response;
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response;
   response.real_pan = "4111";
   response.dcvv = "123";
   response.expiration_month = "12";
@@ -469,7 +469,7 @@
               CreditCard::RecordType::kMaskedServerCard, "server_id"))
           .with_merchant_domain_for_footprints(
               url::Origin::Create(GURL("http://example.com"))));
-  payments::PaymentsClient::UnmaskRequestDetails* request_details =
+  payments::PaymentsNetworkInterface::UnmaskRequestDetails* request_details =
       request()->GetUnmaskRequestDetailsForTesting();
   ASSERT_EQ(request_details->merchant_domain_for_footprints, absl::nullopt);
 
@@ -753,7 +753,7 @@
   CardUnmaskDelegate::UserProvidedUnmaskDetails user_provided_details;
   user_provided_details.cvc = u"321";
   card_unmask_delegate()->OnUnmaskPromptAccepted(user_provided_details);
-  PaymentsClient::UnmaskResponseDetails response_details;
+  PaymentsNetworkInterface::UnmaskResponseDetails response_details;
   response_details.card_type =
       AutofillClient::PaymentsRpcCardType::kVirtualCard;
   response_details.context_token = "test_context_token";
diff --git a/components/autofill/core/browser/payments/iban_save_manager.cc b/components/autofill/core/browser/payments/iban_save_manager.cc
index b4c8146..367e927 100644
--- a/components/autofill/core/browser/payments/iban_save_manager.cc
+++ b/components/autofill/core/browser/payments/iban_save_manager.cc
@@ -11,7 +11,7 @@
 #include "components/autofill/core/browser/metrics/autofill_metrics.h"
 #include "components/autofill/core/browser/metrics/payments/iban_metrics.h"
 #include "components/autofill/core/browser/payments/legal_message_line.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/payments_util.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/strike_databases/payments/iban_save_strike_database.h"
@@ -155,7 +155,7 @@
   bool show_save_prompt =
       !GetIbanSaveStrikeDatabase()->ShouldBlockFeature(GetPartialIbanHashString(
           base::UTF16ToUTF8(iban_save_candidate_.value())));
-  client_->GetPaymentsClient()->GetIbanUploadDetails(
+  client_->GetPaymentsNetworkInterface()->GetIbanUploadDetails(
       personal_data_manager_->app_locale(),
       payments::GetBillingCustomerId(personal_data_manager_),
       payments::kUploadPaymentMethodBillableServiceNumber,
diff --git a/components/autofill/core/browser/payments/iban_save_manager_unittest.cc b/components/autofill/core/browser/payments/iban_save_manager_unittest.cc
index 4ee70ea..4264b0fd 100644
--- a/components/autofill/core/browser/payments/iban_save_manager_unittest.cc
+++ b/components/autofill/core/browser/payments/iban_save_manager_unittest.cc
@@ -11,8 +11,8 @@
 #include "base/uuid.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/data_model/iban.h"
-#include "components/autofill/core/browser/payments/mock_test_payments_client.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/mock_test_payments_network_interface.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/strike_databases/payments/iban_save_strike_database.h"
 #include "components/autofill/core/browser/test_autofill_client.h"
 #include "components/autofill/core/browser/test_personal_data_manager.h"
@@ -59,8 +59,8 @@
     autofill_client_.SetPrefs(test::PrefServiceForTesting());
     autofill_client_.set_personal_data_manager(
         std::make_unique<TestPersonalDataManager>());
-    autofill_client_.set_test_payments_client(
-        std::make_unique<MockTestPaymentsClient>());
+    autofill_client_.set_test_payments_network_interface(
+        std::make_unique<MockTestPaymentsNetworkInterface>());
     autofill_client_.set_sync_service(&sync_service_);
     std::unique_ptr<TestStrikeDatabase> test_strike_database =
         std::make_unique<TestStrikeDatabase>();
@@ -85,7 +85,7 @@
   void SetUpGetIbanUploadDetailsResponse(
       bool is_successful,
       bool includes_invalid_legal_message = false) {
-    ON_CALL(*payments_client(), GetIbanUploadDetails)
+    ON_CALL(*payments_network_interface(), GetIbanUploadDetails)
         .WillByDefault(
             [is_successful, includes_invalid_legal_message](
                 const std::string& app_locale, int64_t billing_customer_number,
@@ -115,9 +115,9 @@
         *autofill_client_.GetPersonalDataManager());
   }
 
-  MockTestPaymentsClient* payments_client() {
-    return static_cast<MockTestPaymentsClient*>(
-        autofill_client_.GetPaymentsClient());
+  MockTestPaymentsNetworkInterface* payments_network_interface() {
+    return static_cast<MockTestPaymentsNetworkInterface*>(
+        autofill_client_.GetPaymentsNetworkInterface());
   }
 
   base::test::TaskEnvironment task_environment_;
diff --git a/components/autofill/core/browser/payments/local_card_migration_manager.cc b/components/autofill/core/browser/payments/local_card_migration_manager.cc
index 9a620d41..04b264f 100644
--- a/components/autofill/core/browser/payments/local_card_migration_manager.cc
+++ b/components/autofill/core/browser/payments/local_card_migration_manager.cc
@@ -22,7 +22,7 @@
 #include "components/autofill/core/browser/metrics/payments/local_card_migration_metrics.h"
 #include "components/autofill/core/browser/payments/client_behavior_constants.h"
 #include "components/autofill/core/browser/payments/credit_card_save_manager.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/payments_util.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/common/autofill_features.h"
@@ -49,14 +49,13 @@
 
 LocalCardMigrationManager::LocalCardMigrationManager(
     AutofillClient* client,
-    payments::PaymentsClient* payments_client,
+    payments::PaymentsNetworkInterface* payments_network_interface,
     const std::string& app_locale,
     PersonalDataManager* personal_data_manager)
     : client_(client),
-      payments_client_(payments_client),
+      payments_network_interface_(payments_network_interface),
       app_locale_(app_locale),
-      personal_data_manager_(personal_data_manager) {
-}
+      personal_data_manager_(personal_data_manager) {}
 
 LocalCardMigrationManager::~LocalCardMigrationManager() {}
 
@@ -143,15 +142,17 @@
 
 void LocalCardMigrationManager::AttemptToOfferLocalCardMigration(
     bool is_from_settings_page) {
-  // Abort the migration if |payments_client_| is nullptr.
-  if (!payments_client_)
+  // Abort the migration if `payments_network_interface_` is nullptr.
+  if (!payments_network_interface_) {
     return;
-  migration_request_ = payments::PaymentsClient::MigrationRequestDetails();
+  }
+  migration_request_ =
+      payments::PaymentsNetworkInterface::MigrationRequestDetails();
 
   if (observer_for_testing_)
     observer_for_testing_->OnDecideToRequestLocalCardMigration();
 
-  payments_client_->GetUploadDetails(
+  payments_network_interface_->GetUploadDetails(
       std::vector<AutofillProfile>(), GetDetectedValues(),
       /*client_behavior_signals=*/std::vector<ClientBehaviorConstants>(),
       app_locale_,
@@ -159,10 +160,11 @@
                      weak_ptr_factory_.GetWeakPtr(), is_from_settings_page),
       payments::kMigrateCardsBillableServiceNumber,
       payments::GetBillingCustomerId(personal_data_manager_),
-      is_from_settings_page ? payments::PaymentsClient::UploadCardSource::
-                                  LOCAL_CARD_MIGRATION_SETTINGS_PAGE
-                            : payments::PaymentsClient::UploadCardSource::
-                                  LOCAL_CARD_MIGRATION_CHECKOUT_FLOW);
+      is_from_settings_page
+          ? payments::PaymentsNetworkInterface::UploadCardSource::
+                LOCAL_CARD_MIGRATION_SETTINGS_PAGE
+          : payments::PaymentsNetworkInterface::UploadCardSource::
+                LOCAL_CARD_MIGRATION_CHECKOUT_FLOW);
 }
 
 // Callback function when user agrees to migration on the intermediate dialog.
@@ -363,8 +365,9 @@
     SendMigrateLocalCardsRequest();
 }
 
-// Send the migration request. Will call payments_client to create a new
-// PaymentsRequest. Also create a new callback function OnDidMigrateLocalCards.
+// Send the migration request. Will call `payments_network_interface` to create
+// a new PaymentsRequest. Also create a new callback function
+// OnDidMigrateLocalCards.
 void LocalCardMigrationManager::SendMigrateLocalCardsRequest() {
   if (observer_for_testing_)
     observer_for_testing_->OnSentMigrateCardsRequest();
@@ -372,7 +375,7 @@
   migration_request_.app_locale = app_locale_;
   migration_request_.billing_customer_number =
       payments::GetBillingCustomerId(personal_data_manager_);
-  payments_client_->MigrateCards(
+  payments_network_interface_->MigrateCards(
       migration_request_, migratable_credit_cards_,
       base::BindOnce(&LocalCardMigrationManager::OnDidMigrateLocalCards,
                      weak_ptr_factory_.GetWeakPtr()));
diff --git a/components/autofill/core/browser/payments/local_card_migration_manager.h b/components/autofill/core/browser/payments/local_card_migration_manager.h
index 321e81c..6da69f2b 100644
--- a/components/autofill/core/browser/payments/local_card_migration_manager.h
+++ b/components/autofill/core/browser/payments/local_card_migration_manager.h
@@ -17,7 +17,7 @@
 #include "components/autofill/core/browser/metrics/autofill_metrics.h"
 #include "components/autofill/core/browser/metrics/payments/local_card_migration_metrics.h"
 #include "components/autofill/core/browser/payments/legal_message_line.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/strike_databases/payments/local_card_migration_strike_database.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -88,10 +88,11 @@
   };
 
   // The parameters should outlive the LocalCardMigrationManager.
-  LocalCardMigrationManager(AutofillClient* client,
-                            payments::PaymentsClient* payments_client,
-                            const std::string& app_locale,
-                            PersonalDataManager* personal_data_manager);
+  LocalCardMigrationManager(
+      AutofillClient* client,
+      payments::PaymentsNetworkInterface* payments_network_interface,
+      const std::string& app_locale,
+      PersonalDataManager* personal_data_manager);
 
   LocalCardMigrationManager(const LocalCardMigrationManager&) = delete;
   LocalCardMigrationManager& operator=(const LocalCardMigrationManager&) =
@@ -183,7 +184,7 @@
 
   // Handles Payments service requests.
   // Owned by BrowserAutofillManager.
-  raw_ptr<payments::PaymentsClient> payments_client_;
+  raw_ptr<payments::PaymentsNetworkInterface> payments_network_interface_;
 
  private:
   friend class LocalCardMigrationBrowserTest;
@@ -216,7 +217,7 @@
   // has accepted the main migration dialog.
   void OnDidGetMigrationRiskData(const std::string& risk_data);
 
-  // Finalizes the migration request and calls PaymentsClient.
+  // Finalizes the migration request and calls the PaymentsNetworkInterface.
   void SendMigrateLocalCardsRequest();
 
   // For testing.
@@ -241,7 +242,8 @@
   int credit_card_import_type_;
 
   // Collected information about a pending migration request.
-  payments::PaymentsClient::MigrationRequestDetails migration_request_;
+  payments::PaymentsNetworkInterface::MigrationRequestDetails
+      migration_request_;
 
   // The local credit cards to be uploaded. Owned by LocalCardMigrationManager.
   // The order of cards should not be changed.
diff --git a/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc b/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc
index 77a7345..4d36882 100644
--- a/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc
+++ b/components/autofill/core/browser/payments/local_card_migration_manager_unittest.cc
@@ -32,7 +32,7 @@
 #include "components/autofill/core/browser/payments/payments_util.h"
 #include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
 #include "components/autofill/core/browser/payments/test_local_card_migration_manager.h"
-#include "components/autofill/core/browser/payments/test_payments_client.h"
+#include "components/autofill/core/browser/payments/test_payments_network_interface.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/test_autofill_client.h"
 #include "components/autofill/core/browser/test_autofill_clock.h"
@@ -69,17 +69,18 @@
     personal_data().SetPrefService(autofill_client_.GetPrefs());
     personal_data().SetSyncServiceForTest(&sync_service_);
     autofill_driver_ = std::make_unique<TestAutofillDriver>();
-    payments_client_ = new payments::TestPaymentsClient(
+    payments_network_interface_ = new payments::TestPaymentsNetworkInterface(
         autofill_client_.GetURLLoaderFactory(),
         autofill_client_.GetIdentityManager(), &personal_data());
-    autofill_client_.set_test_payments_client(
-        std::unique_ptr<payments::TestPaymentsClient>(payments_client_));
-    credit_card_save_manager_ =
-        new TestCreditCardSaveManager(autofill_driver_.get(), &autofill_client_,
-                                      payments_client_, &personal_data());
+    autofill_client_.set_test_payments_network_interface(
+        std::unique_ptr<payments::TestPaymentsNetworkInterface>(
+            payments_network_interface_));
+    credit_card_save_manager_ = new TestCreditCardSaveManager(
+        autofill_driver_.get(), &autofill_client_, payments_network_interface_,
+        &personal_data());
     credit_card_save_manager_->SetCreditCardUploadEnabled(true);
     local_card_migration_manager_ = new TestLocalCardMigrationManager(
-        autofill_driver_.get(), &autofill_client_, payments_client_,
+        autofill_driver_.get(), &autofill_client_, payments_network_interface_,
         &personal_data());
     std::unique_ptr<TestStrikeDatabase> test_strike_database =
         std::make_unique<TestStrikeDatabase>();
@@ -87,7 +88,7 @@
     autofill_client_.set_test_strike_database(std::move(test_strike_database));
     autofill::TestFormDataImporter* test_form_data_importer =
         new TestFormDataImporter(
-            &autofill_client_, payments_client_,
+            &autofill_client_, payments_network_interface_,
             std::unique_ptr<CreditCardSaveManager>(credit_card_save_manager_),
             /*iban_save_manager=*/nullptr, &personal_data(), "en-US",
             std::unique_ptr<LocalCardMigrationManager>(
@@ -155,7 +156,8 @@
     std::unique_ptr<std::unordered_map<std::string, std::string>> save_result =
         std::make_unique<std::unordered_map<std::string, std::string>>();
     save_result->insert(std::make_pair(guid, result));
-    payments_client_->SetSaveResultForCardsMigration(std::move(save_result));
+    payments_network_interface_->SetSaveResultForCardsMigration(
+        std::move(save_result));
   }
 
   // Verify that the correct histogram entry (and only that) was logged.
@@ -328,7 +330,7 @@
   // Ends up getting owned (and destroyed) by TestFormDataImporter:
   raw_ptr<TestLocalCardMigrationManager> local_card_migration_manager_;
   // Ends up getting owned (and destroyed) by TestAutofillClient:
-  raw_ptr<payments::TestPaymentsClient> payments_client_;
+  raw_ptr<payments::TestPaymentsNetworkInterface> payments_network_interface_;
 };
 
 // Having one local card on file and using it will not trigger migration.
@@ -590,7 +592,7 @@
   // Confirm that the preflight request contained
   // kMigrateCardsBillableServiceNumber in the request.
   EXPECT_EQ(payments::kMigrateCardsBillableServiceNumber,
-            payments_client_->billable_service_number_in_request());
+            payments_network_interface_->billable_service_number_in_request());
 }
 
 TEST_F(LocalCardMigrationManagerTest,
@@ -605,7 +607,8 @@
 
   // Confirm that the preflight request contained
   // billing customer number in the request.
-  EXPECT_EQ(123456L, payments_client_->billing_customer_number_in_request());
+  EXPECT_EQ(123456L,
+            payments_network_interface_->billing_customer_number_in_request());
 }
 
 TEST_F(LocalCardMigrationManagerTest,
@@ -614,9 +617,9 @@
   UseLocalCardWithOtherLocalCardsOnFile();
 
   // Confirm that the preflight request contained the correct UploadCardSource.
-  EXPECT_EQ(payments::PaymentsClient::UploadCardSource::
+  EXPECT_EQ(payments::PaymentsNetworkInterface::UploadCardSource::
                 LOCAL_CARD_MIGRATION_CHECKOUT_FLOW,
-            payments_client_->upload_card_source_in_request());
+            payments_network_interface_->upload_card_source_in_request());
 }
 
 TEST_F(LocalCardMigrationManagerTest,
@@ -640,9 +643,9 @@
   EXPECT_TRUE(local_card_migration_manager_->MainPromptWasShown());
 
   // Confirm that the preflight request contained the correct UploadCardSource.
-  EXPECT_EQ(payments::PaymentsClient::UploadCardSource::
+  EXPECT_EQ(payments::PaymentsNetworkInterface::UploadCardSource::
                 LOCAL_CARD_MIGRATION_SETTINGS_PAGE,
-            payments_client_->upload_card_source_in_request());
+            payments_network_interface_->upload_card_source_in_request());
 }
 
 // Verify that when triggering from settings page, intermediate prompt will not
@@ -679,8 +682,8 @@
   EXPECT_TRUE(local_card_migration_manager_->MainPromptWasShown());
 }
 
-// Verify that given the parsed response from the payments client, the migration
-// status is correctly set.
+// Verify that given the parsed response from the PaymentsNetworkInterface, the
+// migration status is correctly set.
 TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_MigrationSuccess) {
   // Set the billing_customer_number to designate existence of a Payments
   // account.
@@ -719,8 +722,8 @@
   EXPECT_FALSE(personal_data().GetCreditCardByNumber("4111111111111111"));
 }
 
-// Verify that given the parsed response from the payments client, the migration
-// status is correctly set.
+// Verify that given the parsed response from the PaymentsNetworkInterface, the
+// migration status is correctly set.
 TEST_F(LocalCardMigrationManagerTest,
        MigrateCreditCard_MigrationTemporaryFailure) {
   // Set the billing_customer_number to designate existence of a Payments
@@ -762,8 +765,8 @@
   EXPECT_TRUE(personal_data().GetCreditCardByNumber("4111111111111111"));
 }
 
-// Verify that given the parsed response from the payments client, the migration
-// status is correctly set.
+// Verify that given the parsed response from the PaymentsNetworkInterface, the
+// migration status is correctly set.
 TEST_F(LocalCardMigrationManagerTest,
        MigrateCreditCard_MigrationPermanentFailure) {
   // Set the billing_customer_number to designate existence of a Payments
@@ -962,7 +965,7 @@
   // supported but the one left is supported.
   std::vector<std::pair<int, int>> supported_card_bin_ranges{
       std::make_pair(300, 305), std::make_pair(555, 555)};
-  payments_client_->SetSupportedBINRanges(supported_card_bin_ranges);
+  payments_network_interface_->SetSupportedBINRanges(supported_card_bin_ranges);
 
   // Edit the data, and submit.
   EditCreditCardForm(credit_card_form, "Jane Doe", "4111111111111111", "11",
@@ -994,7 +997,7 @@
   // only supported card.
   std::vector<std::pair<int, int>> supported_card_bin_ranges{
       std::make_pair(300, 305), std::make_pair(411, 412)};
-  payments_client_->SetSupportedBINRanges(supported_card_bin_ranges);
+  payments_network_interface_->SetSupportedBINRanges(supported_card_bin_ranges);
 
   // Set up our credit card form data.
   FormData credit_card_form = CreateTestCreditCardFormData(true, false);
@@ -1041,7 +1044,7 @@
   // unsupported but the one left is supported.
   std::vector<std::pair<int, int>> supported_card_bin_ranges{
       std::make_pair(300, 305), std::make_pair(555, 555)};
-  payments_client_->SetSupportedBINRanges(supported_card_bin_ranges);
+  payments_network_interface_->SetSupportedBINRanges(supported_card_bin_ranges);
 
   // Set up our credit card form data.
   FormData credit_card_form = CreateTestCreditCardFormData(true, false);
@@ -1081,7 +1084,7 @@
   // supported while the one left is unsupported.
   std::vector<std::pair<int, int>> supported_card_bin_ranges{
       std::make_pair(300, 305), std::make_pair(411, 411)};
-  payments_client_->SetSupportedBINRanges(supported_card_bin_ranges);
+  payments_network_interface_->SetSupportedBINRanges(supported_card_bin_ranges);
 
   // Set up our credit card form data.
   FormData credit_card_form = CreateTestCreditCardFormData(true, false);
@@ -1336,7 +1339,7 @@
   // supported but the one left is supported.
   std::vector<std::pair<int, int>> supported_card_bin_ranges{
       std::make_pair(300, 305), std::make_pair(555, 555)};
-  payments_client_->SetSupportedBINRanges(supported_card_bin_ranges);
+  payments_network_interface_->SetSupportedBINRanges(supported_card_bin_ranges);
 
   // Edit the data, and submit.
   EditCreditCardForm(credit_card_form, "Jane Doe", "4111111111111111", "11",
@@ -1374,7 +1377,7 @@
   // supported while the one left is unsupported.
   std::vector<std::pair<int, int>> supported_card_bin_ranges{
       std::make_pair(300, 305), std::make_pair(411, 411)};
-  payments_client_->SetSupportedBINRanges(supported_card_bin_ranges);
+  payments_network_interface_->SetSupportedBINRanges(supported_card_bin_ranges);
 
   base::HistogramTester histogram_tester;
   // Set up our credit card form data.
@@ -1417,7 +1420,7 @@
   // cards are all unsupported.
   std::vector<std::pair<int, int>> supported_card_bin_ranges{
       std::make_pair(300, 305), std::make_pair(400, 400)};
-  payments_client_->SetSupportedBINRanges(supported_card_bin_ranges);
+  payments_network_interface_->SetSupportedBINRanges(supported_card_bin_ranges);
 
   base::HistogramTester histogram_tester;
   // Set up our credit card form data.
@@ -1446,11 +1449,12 @@
       autofill_metrics::LocalCardMigrationDecisionMetric::OFFERED);
 }
 
-// Tests that if payment client returns an invalid legal message migration
-// should not be offered.
+// Tests that if the PaymentsNetworkInterface returns an invalid legal message,
+// migration should not be offered.
 TEST_F(LocalCardMigrationManagerTest,
        InvalidLegalMessageInOnDidGetUploadDetails) {
-  payments_client_->SetUseInvalidLegalMessageInGetUploadDetails(true);
+  payments_network_interface_->SetUseInvalidLegalMessageInGetUploadDetails(
+      true);
 
   base::HistogramTester histogram_tester;
   UseLocalCardWithOtherLocalCardsOnFile();
diff --git a/components/autofill/core/browser/payments/mock_test_payments_client.cc b/components/autofill/core/browser/payments/mock_test_payments_network_interface.cc
similarity index 63%
rename from components/autofill/core/browser/payments/mock_test_payments_client.cc
rename to components/autofill/core/browser/payments/mock_test_payments_network_interface.cc
index a2a731b5..ae60111 100644
--- a/components/autofill/core/browser/payments/mock_test_payments_client.cc
+++ b/components/autofill/core/browser/payments/mock_test_payments_network_interface.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/autofill/core/browser/payments/mock_test_payments_client.h"
+#include "components/autofill/core/browser/payments/mock_test_payments_network_interface.h"
 
 namespace autofill {
 
-MockTestPaymentsClient::MockTestPaymentsClient()
-    : payments::TestPaymentsClient(
+MockTestPaymentsNetworkInterface::MockTestPaymentsNetworkInterface()
+    : payments::TestPaymentsNetworkInterface(
           /*url_loader_factory=*/nullptr,
           /*identity_manager=*/nullptr,
           /*personal_data_manager=*/nullptr) {}
 
-MockTestPaymentsClient::~MockTestPaymentsClient() = default;
+MockTestPaymentsNetworkInterface::~MockTestPaymentsNetworkInterface() = default;
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/payments/mock_test_payments_client.h b/components/autofill/core/browser/payments/mock_test_payments_network_interface.h
similarity index 65%
rename from components/autofill/core/browser/payments/mock_test_payments_client.h
rename to components/autofill/core/browser/payments/mock_test_payments_network_interface.h
index 5043b968..fcbd54e 100644
--- a/components/autofill/core/browser/payments/mock_test_payments_client.h
+++ b/components/autofill/core/browser/payments/mock_test_payments_network_interface.h
@@ -2,21 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_MOCK_TEST_PAYMENTS_CLIENT_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_MOCK_TEST_PAYMENTS_CLIENT_H_
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_MOCK_TEST_PAYMENTS_NETWORK_INTERFACE_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_MOCK_TEST_PAYMENTS_NETWORK_INTERFACE_H_
 
-#include "components/autofill/core/browser/payments/payments_client.h"
-#include "components/autofill/core/browser/payments/test_payments_client.h"
+#include "components/autofill/core/browser/payments/test_payments_network_interface.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace autofill {
 
-class MockTestPaymentsClient : public payments::TestPaymentsClient {
+class MockTestPaymentsNetworkInterface : public payments::TestPaymentsNetworkInterface {
  public:
-  MockTestPaymentsClient();
-  MockTestPaymentsClient(const MockTestPaymentsClient&) = delete;
-  MockTestPaymentsClient& operator=(const MockTestPaymentsClient&) = delete;
-  ~MockTestPaymentsClient() override;
+  MockTestPaymentsNetworkInterface();
+  MockTestPaymentsNetworkInterface(const MockTestPaymentsNetworkInterface&) = delete;
+  MockTestPaymentsNetworkInterface& operator=(const MockTestPaymentsNetworkInterface&) = delete;
+  ~MockTestPaymentsNetworkInterface() override;
 
   MOCK_METHOD(void,
               GetIbanUploadDetails,
@@ -31,4 +30,4 @@
 
 }  // namespace autofill
 
-#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_MOCK_TEST_PAYMENTS_CLIENT_H_
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_MOCK_TEST_PAYMENTS_NETWORK_INTERFACE_H_
diff --git a/components/autofill/core/browser/payments/payments_client.cc b/components/autofill/core/browser/payments/payments_network_interface.cc
similarity index 76%
rename from components/autofill/core/browser/payments/payments_client.cc
rename to components/autofill/core/browser/payments/payments_network_interface.cc
index 970b006..53bd6eda 100644
--- a/components/autofill/core/browser/payments/payments_client.cc
+++ b/components/autofill/core/browser/payments/payments_network_interface.cc
@@ -1,8 +1,8 @@
-// Copyright 2015 The Chromium Authors
+// Copyright 2023 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 
 #include <memory>
 #include <set>
@@ -85,16 +85,16 @@
 
 }  // namespace
 
-PaymentsClient::UnmaskDetails::UnmaskDetails() = default;
+PaymentsNetworkInterface::UnmaskDetails::UnmaskDetails() = default;
 
-PaymentsClient::UnmaskDetails::UnmaskDetails(const UnmaskDetails& other) {
+PaymentsNetworkInterface::UnmaskDetails::UnmaskDetails(const UnmaskDetails& other) {
   *this = other;
 }
 
-PaymentsClient::UnmaskDetails::UnmaskDetails(UnmaskDetails&&) = default;
+PaymentsNetworkInterface::UnmaskDetails::UnmaskDetails(UnmaskDetails&&) = default;
 
-PaymentsClient::UnmaskDetails& PaymentsClient::UnmaskDetails::operator=(
-    const PaymentsClient::UnmaskDetails& other) {
+PaymentsNetworkInterface::UnmaskDetails& PaymentsNetworkInterface::UnmaskDetails::operator=(
+    const PaymentsNetworkInterface::UnmaskDetails& other) {
   unmask_auth_method = other.unmask_auth_method;
   offer_fido_opt_in = other.offer_fido_opt_in;
   if (other.fido_request_options.has_value()) {
@@ -106,19 +106,19 @@
   return *this;
 }
 
-PaymentsClient::UnmaskDetails& PaymentsClient::UnmaskDetails::operator=(
+PaymentsNetworkInterface::UnmaskDetails& PaymentsNetworkInterface::UnmaskDetails::operator=(
     UnmaskDetails&&) = default;
 
-PaymentsClient::UnmaskDetails::~UnmaskDetails() = default;
+PaymentsNetworkInterface::UnmaskDetails::~UnmaskDetails() = default;
 
-PaymentsClient::UnmaskRequestDetails::UnmaskRequestDetails() = default;
-PaymentsClient::UnmaskRequestDetails::UnmaskRequestDetails(
+PaymentsNetworkInterface::UnmaskRequestDetails::UnmaskRequestDetails() = default;
+PaymentsNetworkInterface::UnmaskRequestDetails::UnmaskRequestDetails(
     const UnmaskRequestDetails& other) {
   *this = other;
 }
-PaymentsClient::UnmaskRequestDetails&
-PaymentsClient::UnmaskRequestDetails::operator=(
-    const PaymentsClient::UnmaskRequestDetails& other) {
+PaymentsNetworkInterface::UnmaskRequestDetails&
+PaymentsNetworkInterface::UnmaskRequestDetails::operator=(
+    const PaymentsNetworkInterface::UnmaskRequestDetails& other) {
   billing_customer_number = other.billing_customer_number;
   card = other.card;
   risk_data = other.risk_data;
@@ -137,20 +137,20 @@
   client_behavior_signals = other.client_behavior_signals;
   return *this;
 }
-PaymentsClient::UnmaskRequestDetails::~UnmaskRequestDetails() = default;
+PaymentsNetworkInterface::UnmaskRequestDetails::~UnmaskRequestDetails() = default;
 
-PaymentsClient::UnmaskResponseDetails::UnmaskResponseDetails() = default;
+PaymentsNetworkInterface::UnmaskResponseDetails::UnmaskResponseDetails() = default;
 
-PaymentsClient::UnmaskResponseDetails::UnmaskResponseDetails(
+PaymentsNetworkInterface::UnmaskResponseDetails::UnmaskResponseDetails(
     const UnmaskResponseDetails& other) {
   *this = other;
 }
 
-PaymentsClient::UnmaskResponseDetails::UnmaskResponseDetails(
+PaymentsNetworkInterface::UnmaskResponseDetails::UnmaskResponseDetails(
     UnmaskResponseDetails&&) = default;
 
-PaymentsClient::UnmaskResponseDetails&
-PaymentsClient::UnmaskResponseDetails::operator=(
+PaymentsNetworkInterface::UnmaskResponseDetails&
+PaymentsNetworkInterface::UnmaskResponseDetails::operator=(
     const UnmaskResponseDetails& other) {
   real_pan = other.real_pan;
   dcvv = other.dcvv;
@@ -170,19 +170,19 @@
   return *this;
 }
 
-PaymentsClient::UnmaskResponseDetails&
-PaymentsClient::UnmaskResponseDetails::operator=(UnmaskResponseDetails&&) =
+PaymentsNetworkInterface::UnmaskResponseDetails&
+PaymentsNetworkInterface::UnmaskResponseDetails::operator=(UnmaskResponseDetails&&) =
     default;
 
-PaymentsClient::UnmaskResponseDetails::~UnmaskResponseDetails() = default;
+PaymentsNetworkInterface::UnmaskResponseDetails::~UnmaskResponseDetails() = default;
 
-PaymentsClient::UnmaskIbanRequestDetails::UnmaskIbanRequestDetails() = default;
-PaymentsClient::UnmaskIbanRequestDetails::UnmaskIbanRequestDetails(
+PaymentsNetworkInterface::UnmaskIbanRequestDetails::UnmaskIbanRequestDetails() = default;
+PaymentsNetworkInterface::UnmaskIbanRequestDetails::UnmaskIbanRequestDetails(
     const UnmaskIbanRequestDetails& other) = default;
-PaymentsClient::UnmaskIbanRequestDetails::~UnmaskIbanRequestDetails() = default;
+PaymentsNetworkInterface::UnmaskIbanRequestDetails::~UnmaskIbanRequestDetails() = default;
 
-PaymentsClient::OptChangeRequestDetails::OptChangeRequestDetails() = default;
-PaymentsClient::OptChangeRequestDetails::OptChangeRequestDetails(
+PaymentsNetworkInterface::OptChangeRequestDetails::OptChangeRequestDetails() = default;
+PaymentsNetworkInterface::OptChangeRequestDetails::OptChangeRequestDetails(
     const OptChangeRequestDetails& other) {
   app_locale = other.app_locale;
   reason = other.reason;
@@ -193,10 +193,10 @@
   }
   card_authorization_token = other.card_authorization_token;
 }
-PaymentsClient::OptChangeRequestDetails::~OptChangeRequestDetails() = default;
+PaymentsNetworkInterface::OptChangeRequestDetails::~OptChangeRequestDetails() = default;
 
-PaymentsClient::OptChangeResponseDetails::OptChangeResponseDetails() = default;
-PaymentsClient::OptChangeResponseDetails::OptChangeResponseDetails(
+PaymentsNetworkInterface::OptChangeResponseDetails::OptChangeResponseDetails() = default;
+PaymentsNetworkInterface::OptChangeResponseDetails::OptChangeResponseDetails(
     const OptChangeResponseDetails& other) {
   user_is_opted_in = other.user_is_opted_in;
 
@@ -211,64 +211,64 @@
     fido_request_options.reset();
   }
 }
-PaymentsClient::OptChangeResponseDetails::~OptChangeResponseDetails() = default;
+PaymentsNetworkInterface::OptChangeResponseDetails::~OptChangeResponseDetails() = default;
 
-PaymentsClient::UploadRequestDetails::UploadRequestDetails() = default;
-PaymentsClient::UploadRequestDetails::UploadRequestDetails(
+PaymentsNetworkInterface::UploadRequestDetails::UploadRequestDetails() = default;
+PaymentsNetworkInterface::UploadRequestDetails::UploadRequestDetails(
     const UploadRequestDetails& other) = default;
-PaymentsClient::UploadRequestDetails::~UploadRequestDetails() = default;
+PaymentsNetworkInterface::UploadRequestDetails::~UploadRequestDetails() = default;
 
-PaymentsClient::UploadIbanRequestDetails::UploadIbanRequestDetails() = default;
-PaymentsClient::UploadIbanRequestDetails::UploadIbanRequestDetails(
+PaymentsNetworkInterface::UploadIbanRequestDetails::UploadIbanRequestDetails() = default;
+PaymentsNetworkInterface::UploadIbanRequestDetails::UploadIbanRequestDetails(
     const UploadIbanRequestDetails& other) = default;
-PaymentsClient::UploadIbanRequestDetails::~UploadIbanRequestDetails() = default;
+PaymentsNetworkInterface::UploadIbanRequestDetails::~UploadIbanRequestDetails() = default;
 
-PaymentsClient::MigrationRequestDetails::MigrationRequestDetails() = default;
-PaymentsClient::MigrationRequestDetails::MigrationRequestDetails(
+PaymentsNetworkInterface::MigrationRequestDetails::MigrationRequestDetails() = default;
+PaymentsNetworkInterface::MigrationRequestDetails::MigrationRequestDetails(
     const MigrationRequestDetails& other) = default;
-PaymentsClient::MigrationRequestDetails::~MigrationRequestDetails() = default;
+PaymentsNetworkInterface::MigrationRequestDetails::~MigrationRequestDetails() = default;
 
-PaymentsClient::SelectChallengeOptionRequestDetails::
+PaymentsNetworkInterface::SelectChallengeOptionRequestDetails::
     SelectChallengeOptionRequestDetails() = default;
-PaymentsClient::SelectChallengeOptionRequestDetails::
+PaymentsNetworkInterface::SelectChallengeOptionRequestDetails::
     SelectChallengeOptionRequestDetails(
         const SelectChallengeOptionRequestDetails& other) = default;
-PaymentsClient::SelectChallengeOptionRequestDetails::
+PaymentsNetworkInterface::SelectChallengeOptionRequestDetails::
     ~SelectChallengeOptionRequestDetails() = default;
 
-PaymentsClient::GetDetailsForEnrollmentRequestDetails::
+PaymentsNetworkInterface::GetDetailsForEnrollmentRequestDetails::
     GetDetailsForEnrollmentRequestDetails() = default;
-PaymentsClient::GetDetailsForEnrollmentRequestDetails::
+PaymentsNetworkInterface::GetDetailsForEnrollmentRequestDetails::
     GetDetailsForEnrollmentRequestDetails(
         const GetDetailsForEnrollmentRequestDetails& other) = default;
-PaymentsClient::GetDetailsForEnrollmentRequestDetails::
+PaymentsNetworkInterface::GetDetailsForEnrollmentRequestDetails::
     ~GetDetailsForEnrollmentRequestDetails() = default;
 
-PaymentsClient::GetDetailsForEnrollmentResponseDetails::
+PaymentsNetworkInterface::GetDetailsForEnrollmentResponseDetails::
     GetDetailsForEnrollmentResponseDetails() = default;
-PaymentsClient::GetDetailsForEnrollmentResponseDetails::
+PaymentsNetworkInterface::GetDetailsForEnrollmentResponseDetails::
     GetDetailsForEnrollmentResponseDetails(
         const GetDetailsForEnrollmentResponseDetails& other) = default;
-PaymentsClient::GetDetailsForEnrollmentResponseDetails::
+PaymentsNetworkInterface::GetDetailsForEnrollmentResponseDetails::
     ~GetDetailsForEnrollmentResponseDetails() = default;
 
-PaymentsClient::UploadCardResponseDetails::UploadCardResponseDetails() =
+PaymentsNetworkInterface::UploadCardResponseDetails::UploadCardResponseDetails() =
     default;
-PaymentsClient::UploadCardResponseDetails::~UploadCardResponseDetails() =
+PaymentsNetworkInterface::UploadCardResponseDetails::~UploadCardResponseDetails() =
     default;
 
-PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails::
+PaymentsNetworkInterface::UpdateVirtualCardEnrollmentRequestDetails::
     UpdateVirtualCardEnrollmentRequestDetails() = default;
-PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails::
+PaymentsNetworkInterface::UpdateVirtualCardEnrollmentRequestDetails::
     UpdateVirtualCardEnrollmentRequestDetails(
         const UpdateVirtualCardEnrollmentRequestDetails&) = default;
-PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails&
-PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails::operator=(
+PaymentsNetworkInterface::UpdateVirtualCardEnrollmentRequestDetails&
+PaymentsNetworkInterface::UpdateVirtualCardEnrollmentRequestDetails::operator=(
     const UpdateVirtualCardEnrollmentRequestDetails&) = default;
-PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails::
+PaymentsNetworkInterface::UpdateVirtualCardEnrollmentRequestDetails::
     ~UpdateVirtualCardEnrollmentRequestDetails() = default;
 
-PaymentsClient::PaymentsClient(
+PaymentsNetworkInterface::PaymentsNetworkInterface(
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     signin::IdentityManager* identity_manager,
     AccountInfoGetter* account_info_getter,
@@ -279,33 +279,33 @@
       is_off_the_record_(is_off_the_record),
       has_retried_authorization_(false) {}
 
-PaymentsClient::~PaymentsClient() = default;
+PaymentsNetworkInterface::~PaymentsNetworkInterface() = default;
 
-void PaymentsClient::Prepare() {
+void PaymentsNetworkInterface::Prepare() {
   if (access_token_.empty())
     StartTokenFetch(false);
 }
 
-void PaymentsClient::GetUnmaskDetails(
+void PaymentsNetworkInterface::GetUnmaskDetails(
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                            PaymentsClient::UnmaskDetails&)> callback,
+                            PaymentsNetworkInterface::UnmaskDetails&)> callback,
     const std::string& app_locale) {
   IssueRequest(std::make_unique<GetUnmaskDetailsRequest>(
       std::move(callback), app_locale,
       account_info_getter_->IsSyncFeatureEnabledForPaymentsServerMetrics()));
 }
 
-void PaymentsClient::UnmaskCard(
-    const PaymentsClient::UnmaskRequestDetails& request_details,
+void PaymentsNetworkInterface::UnmaskCard(
+    const PaymentsNetworkInterface::UnmaskRequestDetails& request_details,
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                            PaymentsClient::UnmaskResponseDetails&)> callback) {
+                            PaymentsNetworkInterface::UnmaskResponseDetails&)> callback) {
   IssueRequest(std::make_unique<UnmaskCardRequest>(
       request_details,
       account_info_getter_->IsSyncFeatureEnabledForPaymentsServerMetrics(),
       std::move(callback)));
 }
 
-void PaymentsClient::UnmaskIban(
+void PaymentsNetworkInterface::UnmaskIban(
     const UnmaskIbanRequestDetails& request_details,
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                             const std::u16string&)> callback) {
@@ -315,17 +315,17 @@
       std::move(callback)));
 }
 
-void PaymentsClient::OptChange(
+void PaymentsNetworkInterface::OptChange(
     const OptChangeRequestDetails request_details,
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                            PaymentsClient::OptChangeResponseDetails&)>
+                            PaymentsNetworkInterface::OptChangeResponseDetails&)>
         callback) {
   IssueRequest(std::make_unique<OptChangeRequest>(
       request_details, std::move(callback),
       account_info_getter_->IsSyncFeatureEnabledForPaymentsServerMetrics()));
 }
 
-void PaymentsClient::GetUploadDetails(
+void PaymentsNetworkInterface::GetUploadDetails(
     const std::vector<AutofillProfile>& addresses,
     const int detected_values,
     const std::vector<ClientBehaviorConstants>& client_behavior_signals,
@@ -344,8 +344,8 @@
       billing_customer_number, upload_card_source));
 }
 
-void PaymentsClient::UploadCard(
-    const PaymentsClient::UploadRequestDetails& request_details,
+void PaymentsNetworkInterface::UploadCard(
+    const PaymentsNetworkInterface::UploadRequestDetails& request_details,
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                             const UploadCardResponseDetails&)> callback) {
   IssueRequest(std::make_unique<UploadCardRequest>(
@@ -354,7 +354,7 @@
       std::move(callback)));
 }
 
-void PaymentsClient::GetIbanUploadDetails(
+void PaymentsNetworkInterface::GetIbanUploadDetails(
     const std::string& app_locale,
     int64_t billing_customer_number,
     int billable_service_number,
@@ -367,7 +367,7 @@
       std::move(callback)));
 }
 
-void PaymentsClient::UploadIban(
+void PaymentsNetworkInterface::UploadIban(
     const UploadIbanRequestDetails& details,
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult)> callback) {
   IssueRequest(std::make_unique<UploadIbanRequest>(
@@ -377,7 +377,7 @@
 }
 
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-void PaymentsClient::MigrateCards(
+void PaymentsNetworkInterface::MigrateCards(
     const MigrationRequestDetails& request_details,
     const std::vector<MigratableCreditCard>& migratable_credit_cards,
     MigrateCardsCallback callback) {
@@ -388,7 +388,7 @@
 }
 #endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 
-void PaymentsClient::SelectChallengeOption(
+void PaymentsNetworkInterface::SelectChallengeOption(
     const SelectChallengeOptionRequestDetails& request_details,
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                             const std::string&)> callback) {
@@ -396,24 +396,24 @@
       request_details, std::move(callback)));
 }
 
-void PaymentsClient::GetVirtualCardEnrollmentDetails(
+void PaymentsNetworkInterface::GetVirtualCardEnrollmentDetails(
     const GetDetailsForEnrollmentRequestDetails& request_details,
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                            const payments::PaymentsClient::
+                            const PaymentsNetworkInterface::
                                 GetDetailsForEnrollmentResponseDetails&)>
         callback) {
   IssueRequest(std::make_unique<GetDetailsForEnrollmentRequest>(
       request_details, std::move(callback)));
 }
 
-void PaymentsClient::UpdateVirtualCardEnrollment(
+void PaymentsNetworkInterface::UpdateVirtualCardEnrollment(
     const UpdateVirtualCardEnrollmentRequestDetails& request_details,
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult)> callback) {
   IssueRequest(std::make_unique<UpdateVirtualCardEnrollmentRequest>(
       request_details, std::move(callback)));
 }
 
-void PaymentsClient::CancelRequest() {
+void PaymentsNetworkInterface::CancelRequest() {
   request_.reset();
   resource_request_.reset();
   simple_url_loader_.reset();
@@ -422,16 +422,16 @@
   has_retried_authorization_ = false;
 }
 
-void PaymentsClient::set_url_loader_factory_for_testing(
+void PaymentsNetworkInterface::set_url_loader_factory_for_testing(
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
   url_loader_factory_ = std::move(url_loader_factory);
 }
 
-void PaymentsClient::set_access_token_for_testing(std::string access_token) {
+void PaymentsNetworkInterface::set_access_token_for_testing(std::string access_token) {
   access_token_ = access_token;
 }
 
-void PaymentsClient::IssueRequest(std::unique_ptr<PaymentsRequest> request) {
+void PaymentsNetworkInterface::IssueRequest(std::unique_ptr<PaymentsRequest> request) {
   request_ = std::move(request);
   has_retried_authorization_ = false;
 
@@ -444,7 +444,7 @@
   }
 }
 
-void PaymentsClient::InitializeResourceRequest() {
+void PaymentsNetworkInterface::InitializeResourceRequest() {
   resource_request_ = std::make_unique<network::ResourceRequest>();
   resource_request_->url = GetRequestUrl(request_->GetRequestUrlPath());
   resource_request_->load_flags = net::LOAD_DISABLE_CACHE;
@@ -461,7 +461,7 @@
       variations::SignedIn::kYes, resource_request_.get());
 }
 
-void PaymentsClient::OnSimpleLoaderComplete(
+void PaymentsNetworkInterface::OnSimpleLoaderComplete(
     std::unique_ptr<std::string> response_body) {
   int response_code = -1;
   if (simple_url_loader_->ResponseInfo() &&
@@ -475,7 +475,7 @@
   OnSimpleLoaderCompleteInternal(response_code, data);
 }
 
-void PaymentsClient::OnSimpleLoaderCompleteInternal(int response_code,
+void PaymentsNetworkInterface::OnSimpleLoaderCompleteInternal(int response_code,
                                                     const std::string& data) {
   VLOG(2) << "Got data: " << data;
 
@@ -557,7 +557,7 @@
   request_->RespondToDelegate(result);
 }
 
-void PaymentsClient::AccessTokenFetchFinished(
+void PaymentsNetworkInterface::AccessTokenFetchFinished(
     GoogleServiceAuthError error,
     signin::AccessTokenInfo access_token_info) {
   DCHECK(token_fetcher_);
@@ -573,7 +573,7 @@
     SetOAuth2TokenAndStartRequest();
 }
 
-void PaymentsClient::AccessTokenError(const GoogleServiceAuthError& error) {
+void PaymentsNetworkInterface::AccessTokenError(const GoogleServiceAuthError& error) {
   VLOG(1) << "Unhandled OAuth2 error: " << error.ToString();
   if (simple_url_loader_)
     simple_url_loader_.reset();
@@ -582,7 +582,7 @@
         AutofillClient::PaymentsRpcResult::kPermanentFailure);
 }
 
-void PaymentsClient::StartTokenFetch(bool invalidate_old) {
+void PaymentsNetworkInterface::StartTokenFetch(bool invalidate_old) {
   // We're still waiting for the last request to come back.
   if (!invalidate_old && token_fetcher_)
     return;
@@ -601,12 +601,12 @@
   access_token_.clear();
   token_fetcher_ = identity_manager_->CreateAccessTokenFetcherForAccount(
       account_id, kTokenFetchId, payments_scopes,
-      base::BindOnce(&PaymentsClient::AccessTokenFetchFinished,
+      base::BindOnce(&PaymentsNetworkInterface::AccessTokenFetchFinished,
                      base::Unretained(this)),
       signin::AccessTokenFetcher::Mode::kImmediate);
 }
 
-void PaymentsClient::SetOAuth2TokenAndStartRequest() {
+void PaymentsNetworkInterface::SetOAuth2TokenAndStartRequest() {
   // Set OAuth2 token:
   DCHECK(resource_request_);
   resource_request_->headers.SetHeader(net::HttpRequestHeaders::kAuthorization,
@@ -655,7 +655,7 @@
 
   simple_url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
       url_loader_factory_.get(),
-      base::BindOnce(&PaymentsClient::OnSimpleLoaderComplete,
+      base::BindOnce(&PaymentsNetworkInterface::OnSimpleLoaderComplete,
                      base::Unretained(this)));
 }
 
diff --git a/components/autofill/core/browser/payments/payments_client.h b/components/autofill/core/browser/payments/payments_network_interface.h
similarity index 95%
rename from components/autofill/core/browser/payments/payments_client.h
rename to components/autofill/core/browser/payments/payments_network_interface.h
index a48110c..f79b1c7 100644
--- a/components/autofill/core/browser/payments/payments_client.h
+++ b/components/autofill/core/browser/payments/payments_network_interface.h
@@ -1,9 +1,9 @@
-// Copyright 2015 The Chromium Authors
+// Copyright 2023 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_CLIENT_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_CLIENT_H_
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_NETWORK_INTERFACE_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_NETWORK_INTERFACE_H_
 
 #include <memory>
 #include <set>
@@ -71,12 +71,12 @@
 
 class PaymentsRequest;
 
-// PaymentsClient issues Payments RPCs and manages responses and failure
+// PaymentsNetworkInterface issues Payments RPCs and manages responses and failure
 // conditions. Only one request may be active at a time. Initiating a new
 // request will cancel a pending request.
 // Tests are located in
-// src/components/autofill/content/browser/payments/payments_client_unittest.cc.
-class PaymentsClient {
+// src/components/autofill/content/browser/payments/payments_network_interface_unittest.cc.
+class PaymentsNetworkInterface {
  public:
   // The names of the fields used to send non-location elements as part of an
   // address. Used in the implementation and in tests which verify that these
@@ -451,16 +451,16 @@
   // ownership requirements. |identity_manager| and |account_info_getter| must
   // all outlive |this|. Either delegate might be nullptr. |is_off_the_record|
   // denotes incognito mode.
-  PaymentsClient(
+  PaymentsNetworkInterface(
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       signin::IdentityManager* const identity_manager,
       AccountInfoGetter* const account_info_getter,
       bool is_off_the_record = false);
 
-  PaymentsClient(const PaymentsClient&) = delete;
-  PaymentsClient& operator=(const PaymentsClient&) = delete;
+  PaymentsNetworkInterface(const PaymentsNetworkInterface&) = delete;
+  PaymentsNetworkInterface& operator=(const PaymentsNetworkInterface&) = delete;
 
-  virtual ~PaymentsClient();
+  virtual ~PaymentsNetworkInterface();
 
   // Starts fetching the OAuth2 token in anticipation of future Payments
   // requests. Called as an optimization, but not strictly necessary. Should
@@ -529,7 +529,7 @@
   virtual void UploadCard(
       const UploadRequestDetails& details,
       base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                              const PaymentsClient::UploadCardResponseDetails&)>
+                              const PaymentsNetworkInterface::UploadCardResponseDetails&)>
           callback);
 
   // Determine if the user meets the Payments service conditions for upload.
@@ -583,7 +583,7 @@
   virtual void GetVirtualCardEnrollmentDetails(
       const GetDetailsForEnrollmentRequestDetails& request_details,
       base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                              const payments::PaymentsClient::
+                              const PaymentsNetworkInterface::
                                   GetDetailsForEnrollmentResponseDetails&)>
           callback);
 
@@ -604,7 +604,7 @@
   void set_access_token_for_testing(std::string access_token);
 
  private:
-  friend class PaymentsClientTest;
+  friend class PaymentsNetworkInterfaceTest;
 
   // Initiates a Payments request using the state in `request`, ensuring that an
   // OAuth token is available first. Takes ownership of `request`.
@@ -635,10 +635,10 @@
   // The URL loader factory for the request.
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
 
-  // Provided in constructor; not owned by PaymentsClient.
+  // Provided in constructor; not owned by PaymentsNetworkInterface.
   const raw_ptr<signin::IdentityManager> identity_manager_;
 
-  // Provided in constructor; not owned by PaymentsClient.
+  // Provided in constructor; not owned by PaymentsNetworkInterface.
   const raw_ptr<AccountInfoGetter> account_info_getter_;
 
   // The current request.
@@ -658,19 +658,19 @@
 
   // Denotes incognito mode.
   // TODO(crbug.com/1409158): Remove this variable, as it should not be the
-  // PaymentsClient's responsibility to check if the user is off the record. The
-  // sole responsibility of the PaymentsClient is to send requests to the Google
-  // payments server.
+  // PaymentsNetworkInterface's responsibility to check if the user is off the record. The
+  // sole responsibility of the PaymentsNetworkInterface is to send requests to the Google
+  // Payments server.
   bool is_off_the_record_;
 
   // True if |request_| has already retried due to a 401 response from the
   // server.
   bool has_retried_authorization_;
 
-  base::WeakPtrFactory<PaymentsClient> weak_ptr_factory_{this};
+  base::WeakPtrFactory<PaymentsNetworkInterface> weak_ptr_factory_{this};
 };
 
 }  // namespace payments
 }  // namespace autofill
 
-#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_CLIENT_H_
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_NETWORK_INTERFACE_H_
diff --git a/components/autofill/core/browser/payments/payments_client_unittest.cc b/components/autofill/core/browser/payments/payments_network_interface_unittest.cc
similarity index 87%
rename from components/autofill/core/browser/payments/payments_client_unittest.cc
rename to components/autofill/core/browser/payments/payments_network_interface_unittest.cc
index 81defbab..d589efd 100644
--- a/components/autofill/core/browser/payments/payments_client_unittest.cc
+++ b/components/autofill/core/browser/payments/payments_network_interface_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors
+// Copyright 2023 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -25,7 +25,7 @@
 #include "components/autofill/core/browser/payments/client_behavior_constants.h"
 #include "components/autofill/core/browser/payments/credit_card_save_manager.h"
 #include "components/autofill/core/browser/payments/local_card_migration_manager.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/virtual_card_enrollment_flow.h"
 #include "components/autofill/core/browser/test_personal_data_manager.h"
 #include "components/autofill/core/common/autofill_clock.h"
@@ -134,7 +134,7 @@
 
 struct GetUploadDetailsOptions {
   GetUploadDetailsOptions& with_upload_card_source(
-      PaymentsClient::UploadCardSource u) {
+      PaymentsNetworkInterface::UploadCardSource u) {
     upload_card_source = u;
     return *this;
   }
@@ -150,8 +150,8 @@
     return *this;
   }
 
-  PaymentsClient::UploadCardSource upload_card_source =
-      PaymentsClient::UploadCardSource::UNKNOWN_UPLOAD_CARD_SOURCE;
+  PaymentsNetworkInterface::UploadCardSource upload_card_source =
+      PaymentsNetworkInterface::UploadCardSource::UNKNOWN_UPLOAD_CARD_SOURCE;
   int64_t billing_customer_number = 111222333444L;
   std::vector<ClientBehaviorConstants> client_behavior_signals;
 };
@@ -186,14 +186,14 @@
 
 }  // namespace
 
-class PaymentsClientTest : public testing::Test {
+class PaymentsNetworkInterfaceTest : public testing::Test {
  public:
-  PaymentsClientTest() = default;
+  PaymentsNetworkInterfaceTest() = default;
 
-  PaymentsClientTest(const PaymentsClientTest&) = delete;
-  PaymentsClientTest& operator=(const PaymentsClientTest&) = delete;
+  PaymentsNetworkInterfaceTest(const PaymentsNetworkInterfaceTest&) = delete;
+  PaymentsNetworkInterfaceTest& operator=(const PaymentsNetworkInterfaceTest&) = delete;
 
-  ~PaymentsClientTest() override = default;
+  ~PaymentsNetworkInterfaceTest() override = default;
 
   void SetUp() override {
     // Silence the warning for mismatching sync and Payments servers.
@@ -213,7 +213,7 @@
     test_shared_loader_factory_ =
         base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
             &test_url_loader_factory_);
-    client_ = std::make_unique<PaymentsClient>(
+    payments_network_interface_ = std::make_unique<PaymentsNetworkInterface>(
         test_shared_loader_factory_, identity_test_env_.identity_manager(),
         &test_personal_data_);
     test_personal_data_.SetAccountInfoForPayments(
@@ -221,7 +221,7 @@
             "example@gmail.com", signin::ConsentLevel::kSync));
   }
 
-  void TearDown() override { client_.reset(); }
+  void TearDown() override { payments_network_interface_.reset(); }
 
   // Registers a field trial with the specified name and group and an associated
   // google web property variation id.
@@ -236,20 +236,20 @@
 
   void OnDidGetUnmaskDetails(
       AutofillClient::PaymentsRpcResult result,
-      payments::PaymentsClient::UnmaskDetails& unmask_details) {
+      payments::PaymentsNetworkInterface::UnmaskDetails& unmask_details) {
     result_ = result;
     unmask_details_ = unmask_details;
   }
 
   void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
-                       PaymentsClient::UnmaskResponseDetails& response) {
+                       PaymentsNetworkInterface::UnmaskResponseDetails& response) {
     result_ = result;
     unmask_response_details_ = response;
   }
 
   void OnDidGetOptChangeResult(
       AutofillClient::PaymentsRpcResult result,
-      PaymentsClient::OptChangeResponseDetails& response) {
+      PaymentsNetworkInterface::OptChangeResponseDetails& response) {
     result_ = result;
     opt_change_response_.user_is_opted_in = response.user_is_opted_in;
     opt_change_response_.fido_creation_options =
@@ -269,7 +269,7 @@
   }
 
   void OnDidUploadCard(AutofillClient::PaymentsRpcResult result,
-                       const PaymentsClient::UploadCardResponseDetails&
+                       const PaymentsNetworkInterface::UploadCardResponseDetails&
                            upload_card_respone_details) {
     result_ = result;
     upload_card_response_details_ = upload_card_respone_details;
@@ -295,7 +295,7 @@
 
   void OnDidGetVirtualCardEnrollmentDetails(
       AutofillClient::PaymentsRpcResult result,
-      const payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails&
+      const payments::PaymentsNetworkInterface::GetDetailsForEnrollmentResponseDetails&
           get_details_for_enrollment_response_fields) {
     result_ = result;
     get_details_for_enrollment_response_fields_ =
@@ -311,8 +311,8 @@
   // Issue a GetUnmaskDetails request. This requires an OAuth token before
   // starting the request.
   void StartGettingUnmaskDetails() {
-    client_->GetUnmaskDetails(
-        base::BindOnce(&PaymentsClientTest::OnDidGetUnmaskDetails,
+    payments_network_interface_->GetUnmaskDetails(
+        base::BindOnce(&PaymentsNetworkInterfaceTest::OnDidGetUnmaskDetails,
                        GetWeakPtr()),
         "language-LOCALE");
   }
@@ -320,7 +320,7 @@
   // Issue an UnmaskCard request. This requires an OAuth token before starting
   // the request.
   void StartUnmasking(CardUnmaskOptions options) {
-    PaymentsClient::UnmaskRequestDetails request_details;
+    PaymentsNetworkInterface::UnmaskRequestDetails request_details;
     request_details.billing_customer_number = 111222333444;
 
     request_details.card = options.use_only_non_legacy_id
@@ -350,20 +350,20 @@
       request_details.context_token = "fake context token";
     if (options.use_otp)
       request_details.otp = base::ASCIIToUTF16(options.otp);
-    client_->UnmaskCard(
+    payments_network_interface_->UnmaskCard(
         request_details,
-        base::BindOnce(&PaymentsClientTest::OnDidGetRealPan, GetWeakPtr()));
+        base::BindOnce(&PaymentsNetworkInterfaceTest::OnDidGetRealPan, GetWeakPtr()));
   }
 
   // If |opt_in| is set to true, then opts the user in to use FIDO
   // authentication for card unmasking. Otherwise opts the user out.
   void StartOptChangeRequest(
-      PaymentsClient::OptChangeRequestDetails::Reason reason) {
-    PaymentsClient::OptChangeRequestDetails request_details;
+      PaymentsNetworkInterface::OptChangeRequestDetails::Reason reason) {
+    PaymentsNetworkInterface::OptChangeRequestDetails request_details;
     request_details.reason = reason;
-    client_->OptChange(
+    payments_network_interface_->OptChange(
         request_details,
-        base::BindOnce(&PaymentsClientTest::OnDidGetOptChangeResult,
+        base::BindOnce(&PaymentsNetworkInterfaceTest::OnDidGetOptChangeResult,
                        GetWeakPtr()));
   }
 
@@ -371,10 +371,10 @@
   // starting the request.
   void StartGettingUploadDetails(
       GetUploadDetailsOptions get_upload_details_options) {
-    client_->GetUploadDetails(
+    payments_network_interface_->GetUploadDetails(
         BuildTestProfiles(), kAllDetectableValues,
         get_upload_details_options.client_behavior_signals, "language-LOCALE",
-        base::BindOnce(&PaymentsClientTest::OnDidGetUploadDetails,
+        base::BindOnce(&PaymentsNetworkInterfaceTest::OnDidGetUploadDetails,
                        GetWeakPtr()),
         /*billable_service_number=*/12345,
         get_upload_details_options.billing_customer_number,
@@ -384,7 +384,7 @@
   // Issue an UploadCard request. This requires an OAuth token before starting
   // the request.
   void StartUploading(UploadCardOptions upload_card_options) {
-    PaymentsClient::UploadRequestDetails request_details;
+    PaymentsNetworkInterface::UploadRequestDetails request_details;
     request_details.billing_customer_number =
         upload_card_options.billing_customer_number;
     request_details.card = test::GetCreditCard();
@@ -402,15 +402,15 @@
     request_details.risk_data = "some risk data";
     request_details.app_locale = "language-LOCALE";
     request_details.profiles = BuildTestProfiles();
-    client_->UploadCard(
+    payments_network_interface_->UploadCard(
         request_details,
-        base::BindOnce(&PaymentsClientTest::OnDidUploadCard, GetWeakPtr()));
+        base::BindOnce(&PaymentsNetworkInterfaceTest::OnDidUploadCard, GetWeakPtr()));
   }
 
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
   void StartMigrating(bool has_cardholder_name,
                       bool set_nickname_for_first_card = false) {
-    PaymentsClient::MigrationRequestDetails request_details;
+    PaymentsNetworkInterface::MigrationRequestDetails request_details;
     request_details.context_token = u"context token";
     request_details.risk_data = "some risk data";
     request_details.app_locale = "language-LOCALE";
@@ -426,9 +426,9 @@
     }
     migratable_credit_cards_.emplace_back(card1);
     migratable_credit_cards_.emplace_back(card2);
-    client_->MigrateCards(
+    payments_network_interface_->MigrateCards(
         request_details, migratable_credit_cards_,
-        base::BindOnce(&PaymentsClientTest::OnDidMigrateLocalCards,
+        base::BindOnce(&PaymentsNetworkInterfaceTest::OnDidMigrateLocalCards,
                        GetWeakPtr()));
   }
 #endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
@@ -437,7 +437,7 @@
       CardUnmaskChallengeOptionType challenge_type =
           CardUnmaskChallengeOptionType::kSmsOtp,
       std::string challenge_id = "arbitrary id") {
-    PaymentsClient::SelectChallengeOptionRequestDetails request_details;
+    PaymentsNetworkInterface::SelectChallengeOptionRequestDetails request_details;
     request_details.billing_customer_number = 555666777888;
     request_details.context_token = "fake context token";
 
@@ -448,9 +448,9 @@
     selected_challenge_option.challenge_info = u"(***)-***-5678";
     request_details.selected_challenge_option = selected_challenge_option;
 
-    client_->SelectChallengeOption(
+    payments_network_interface_->SelectChallengeOption(
         request_details,
-        base::BindOnce(&PaymentsClientTest::OnDidSelectChallengeOption,
+        base::BindOnce(&PaymentsNetworkInterfaceTest::OnDidSelectChallengeOption,
                        GetWeakPtr()));
   }
 
@@ -476,7 +476,7 @@
 
   void ReturnResponse(net::HttpStatusCode response_code,
                       const std::string& response_body) {
-    client_->OnSimpleLoaderCompleteInternal(response_code, response_body);
+    payments_network_interface_->OnSimpleLoaderCompleteInternal(response_code, response_body);
   }
 
   void assertCvcIncludedInRequest(std::string cvc) {
@@ -529,16 +529,16 @@
     EXPECT_TRUE(GetUploadData().find(field_name_or_value) == std::string::npos);
   }
 
-  const PaymentsClient::UnmaskDetails* unmask_details() const {
+  const PaymentsNetworkInterface::UnmaskDetails* unmask_details() const {
     return unmask_details_ ? &unmask_details_.value() : nullptr;
   }
-  const PaymentsClient::UnmaskResponseDetails* unmask_response_details() const {
+  const PaymentsNetworkInterface::UnmaskResponseDetails* unmask_response_details() const {
     return unmask_response_details_ ? &unmask_response_details_.value()
                                     : nullptr;
   }
   void ResetUnmaskResponseDetails() { unmask_response_details_.reset(); }
 
-  base::WeakPtr<PaymentsClientTest> GetWeakPtr() {
+  base::WeakPtr<PaymentsNetworkInterfaceTest> GetWeakPtr() {
     return weak_ptr_factory_.GetWeakPtr();
   }
 
@@ -546,11 +546,11 @@
       AutofillClient::PaymentsRpcResult::kNone;
 
   // Server ID of a saved card via credit card upload save.
-  PaymentsClient::UploadCardResponseDetails upload_card_response_details_;
+  PaymentsNetworkInterface::UploadCardResponseDetails upload_card_response_details_;
   // The OptChangeResponseDetails retrieved from an OptChangeRequest.
-  PaymentsClient::OptChangeResponseDetails opt_change_response_;
+  PaymentsNetworkInterface::OptChangeResponseDetails opt_change_response_;
   // The response details retrieved from an GetDetailsForEnrollmentRequest.
-  PaymentsClient::GetDetailsForEnrollmentResponseDetails
+  PaymentsNetworkInterface::GetDetailsForEnrollmentResponseDetails
       get_details_for_enrollment_response_fields_;
   // The legal message returned from a GetDetails upload save preflight call.
   std::unique_ptr<base::Value::Dict> legal_message_;
@@ -578,7 +578,7 @@
   network::TestURLLoaderFactory test_url_loader_factory_;
   scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
   TestPersonalDataManager test_personal_data_;
-  std::unique_ptr<PaymentsClient> client_;
+  std::unique_ptr<PaymentsNetworkInterface> payments_network_interface_;
   signin::IdentityTestEnvironment identity_test_env_;
 
   net::HttpRequestHeaders intercepted_headers_;
@@ -616,14 +616,14 @@
     return profile;
   }
 
-  absl::optional<PaymentsClient::UnmaskDetails> unmask_details_;
+  absl::optional<PaymentsNetworkInterface::UnmaskDetails> unmask_details_;
   // The UnmaskResponseDetails retrieved from an UnmaskRequest.  Includes PAN.
-  absl::optional<PaymentsClient::UnmaskResponseDetails>
+  absl::optional<PaymentsNetworkInterface::UnmaskResponseDetails>
       unmask_response_details_;
-  base::WeakPtrFactory<PaymentsClientTest> weak_ptr_factory_{this};
+  base::WeakPtrFactory<PaymentsNetworkInterfaceTest> weak_ptr_factory_{this};
 };
 
-TEST_F(PaymentsClientTest, GetUnmaskDetailsSuccess) {
+TEST_F(PaymentsNetworkInterfaceTest, GetUnmaskDetailsSuccess) {
   StartGettingUnmaskDetails();
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
@@ -635,7 +635,7 @@
             unmask_details()->unmask_auth_method);
 }
 
-TEST_F(PaymentsClientTest, GetUnmaskDetailsIncludesChromeUserContext) {
+TEST_F(PaymentsNetworkInterfaceTest, GetUnmaskDetailsIncludesChromeUserContext) {
   StartGettingUnmaskDetails();
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK, "{}");
@@ -645,7 +645,7 @@
   EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, OAuthError) {
+TEST_F(PaymentsNetworkInterfaceTest, OAuthError) {
   StartUnmasking(CardUnmaskOptions());
   identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
       GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE));
@@ -653,7 +653,7 @@
   EXPECT_TRUE(unmask_response_details()->real_pan.empty());
 }
 
-TEST_F(PaymentsClientTest,
+TEST_F(PaymentsNetworkInterfaceTest,
        UnmaskRequestIncludesBillingCustomerNumberInRequest) {
   StartUnmasking(CardUnmaskOptions());
   IssueOAuthToken();
@@ -664,7 +664,7 @@
       std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, UnmaskSuccessViaCVC) {
+TEST_F(PaymentsNetworkInterfaceTest, UnmaskSuccessViaCVC) {
   StartUnmasking(CardUnmaskOptions().with_cvc("111"));
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK, "{ \"pan\": \"1234\" }");
@@ -674,7 +674,7 @@
   EXPECT_EQ("1234", unmask_response_details()->real_pan);
 }
 
-TEST_F(PaymentsClientTest, UnmaskSuccessViaFIDO) {
+TEST_F(PaymentsNetworkInterfaceTest, UnmaskSuccessViaFIDO) {
   StartUnmasking(CardUnmaskOptions().with_fido());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK, "{ \"pan\": \"1234\" }");
@@ -684,7 +684,7 @@
   EXPECT_EQ("1234", unmask_response_details()->real_pan);
 }
 
-TEST_F(PaymentsClientTest, UnmaskSuccessViaCVCWithCreationOptions) {
+TEST_F(PaymentsNetworkInterfaceTest, UnmaskSuccessViaCVCWithCreationOptions) {
   StartUnmasking(CardUnmaskOptions().with_cvc("111"));
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK, "{ \"pan\": \"1234\", \"dcvv\": \"321\"}");
@@ -693,7 +693,7 @@
   EXPECT_EQ("321", unmask_response_details()->dcvv);
 }
 
-TEST_F(PaymentsClientTest, UnmaskSuccessAccountFromSyncTest) {
+TEST_F(PaymentsNetworkInterfaceTest, UnmaskSuccessAccountFromSyncTest) {
   StartUnmasking(CardUnmaskOptions());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK, "{ \"pan\": \"1234\" }");
@@ -701,7 +701,7 @@
   EXPECT_EQ("1234", unmask_response_details()->real_pan);
 }
 
-TEST_F(PaymentsClientTest, UnmaskSuccessWithVirtualCardCvcAuth) {
+TEST_F(PaymentsNetworkInterfaceTest, UnmaskSuccessWithVirtualCardCvcAuth) {
   StartUnmasking(CardUnmaskOptions().with_virtual_card().with_cvc("222"));
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
@@ -720,7 +720,7 @@
   EXPECT_EQ("2099", unmask_response_details()->expiration_year);
 }
 
-TEST_F(PaymentsClientTest, UnmaskSuccessWithVirtualCardFidoAuth) {
+TEST_F(PaymentsNetworkInterfaceTest, UnmaskSuccessWithVirtualCardFidoAuth) {
   StartUnmasking(CardUnmaskOptions().with_virtual_card().with_fido());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
@@ -736,7 +736,7 @@
   EXPECT_EQ("2099", unmask_response_details()->expiration_year);
 }
 
-TEST_F(PaymentsClientTest, VirtualCardRiskBasedGreenPathResponse) {
+TEST_F(PaymentsNetworkInterfaceTest, VirtualCardRiskBasedGreenPathResponse) {
   StartUnmasking(CardUnmaskOptions().with_virtual_card_risk_based());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
@@ -759,7 +759,7 @@
   EXPECT_TRUE(unmask_response_details()->card_unmask_challenge_options.empty());
 }
 
-TEST_F(PaymentsClientTest, VirtualCardRiskBasedRedPathResponse_Error) {
+TEST_F(PaymentsNetworkInterfaceTest, VirtualCardRiskBasedRedPathResponse_Error) {
   StartUnmasking(CardUnmaskOptions().with_virtual_card_risk_based());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
@@ -769,7 +769,7 @@
             result_);
 }
 
-TEST_F(PaymentsClientTest,
+TEST_F(PaymentsNetworkInterfaceTest,
        VirtualCardRiskBasedRedPathResponse_NoOptionProvided) {
   StartUnmasking(CardUnmaskOptions().with_virtual_card_risk_based());
   IssueOAuthToken();
@@ -777,7 +777,7 @@
   EXPECT_EQ(AutofillClient::PaymentsRpcResult::kPermanentFailure, result_);
 }
 
-TEST_F(PaymentsClientTest, VirtualCardRiskBasedYellowPathResponse) {
+TEST_F(PaymentsNetworkInterfaceTest, VirtualCardRiskBasedYellowPathResponse) {
   StartUnmasking(CardUnmaskOptions().with_virtual_card_risk_based());
   IssueOAuthToken();
   ReturnResponse(
@@ -823,7 +823,7 @@
   EXPECT_EQ(CvcPosition::kBackOfCard, challenge_option_3.cvc_position);
 }
 
-TEST_F(PaymentsClientTest, VirtualCardCvcRetrieval_FlowStatusPresent) {
+TEST_F(PaymentsNetworkInterfaceTest, VirtualCardCvcRetrieval_FlowStatusPresent) {
   StartUnmasking(
       CardUnmaskOptions().with_virtual_card_risk_based().with_cvc("123"));
   IssueOAuthToken();
@@ -836,7 +836,7 @@
   EXPECT_EQ(AutofillClient::PaymentsRpcResult::kTryAgainFailure, result_);
 }
 
-TEST_F(PaymentsClientTest,
+TEST_F(PaymentsNetworkInterfaceTest,
        VirtualCardRiskBasedYellowPathResponseWithUnknownType) {
   StartUnmasking(CardUnmaskOptions().with_virtual_card_risk_based());
   IssueOAuthToken();
@@ -868,7 +868,7 @@
   EXPECT_EQ(u"(***)-***-1234", sms_challenge_option.challenge_info);
 }
 
-TEST_F(PaymentsClientTest, VirtualCardRiskBasedThenFido) {
+TEST_F(PaymentsNetworkInterfaceTest, VirtualCardRiskBasedThenFido) {
   StartUnmasking(CardUnmaskOptions().with_virtual_card_risk_based_then_fido());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
@@ -891,7 +891,7 @@
   EXPECT_EQ("2099", unmask_response_details()->expiration_year);
 }
 
-TEST_F(PaymentsClientTest, VirtualCardRiskBasedThenOtpSuccess) {
+TEST_F(PaymentsNetworkInterfaceTest, VirtualCardRiskBasedThenOtpSuccess) {
   const std::string otp = "111111";
   StartUnmasking(
       CardUnmaskOptions().with_virtual_card_risk_based_then_otp(otp));
@@ -916,7 +916,7 @@
   EXPECT_EQ("2099", unmask_response_details()->expiration_year);
 }
 
-TEST_F(PaymentsClientTest, ExpiredOtp) {
+TEST_F(PaymentsNetworkInterfaceTest, ExpiredOtp) {
   const std::string otp = "222222";
   StartUnmasking(
       CardUnmaskOptions().with_virtual_card_risk_based_then_otp(otp));
@@ -936,7 +936,7 @@
   EXPECT_EQ("FLOW_STATUS_EXPIRED_OTP", unmask_response_details()->flow_status);
 }
 
-TEST_F(PaymentsClientTest, IncorrectOtp) {
+TEST_F(PaymentsNetworkInterfaceTest, IncorrectOtp) {
   const std::string otp = "333333";
   StartUnmasking(
       CardUnmaskOptions().with_virtual_card_risk_based_then_otp(otp));
@@ -957,7 +957,7 @@
             unmask_response_details()->flow_status);
 }
 
-TEST_F(PaymentsClientTest, UnmaskIncludesLegacyAndNonLegacyId) {
+TEST_F(PaymentsNetworkInterfaceTest, UnmaskIncludesLegacyAndNonLegacyId) {
   StartUnmasking(CardUnmaskOptions());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK, "{}");
@@ -969,7 +969,7 @@
               std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, UnmaskIncludesOnlyLegacyId) {
+TEST_F(PaymentsNetworkInterfaceTest, UnmaskIncludesOnlyLegacyId) {
   StartUnmasking(CardUnmaskOptions().with_only_legacy_id());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK, "{}");
@@ -980,7 +980,7 @@
               std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, UnmaskIncludesOnlyNonLegacyId) {
+TEST_F(PaymentsNetworkInterfaceTest, UnmaskIncludesOnlyNonLegacyId) {
   StartUnmasking(CardUnmaskOptions().with_only_non_legacy_id());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK, "{}");
@@ -991,7 +991,7 @@
   EXPECT_TRUE(GetUploadData().find("credit_card_id") == std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, UnmaskIncludesChromeUserContext) {
+TEST_F(PaymentsNetworkInterfaceTest, UnmaskIncludesChromeUserContext) {
   StartUnmasking(CardUnmaskOptions());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK, "{}");
@@ -1001,7 +1001,7 @@
   EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, UnmaskIncludesMerchantDomain) {
+TEST_F(PaymentsNetworkInterfaceTest, UnmaskIncludesMerchantDomain) {
   StartUnmasking(CardUnmaskOptions().with_virtual_card());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK, "{}");
@@ -1010,7 +1010,7 @@
   EXPECT_TRUE(GetUploadData().find("merchant_domain") != std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, UnmaskResponseIncludesDeclineDetails) {
+TEST_F(PaymentsNetworkInterfaceTest, UnmaskResponseIncludesDeclineDetails) {
   StartUnmasking(CardUnmaskOptions().with_virtual_card());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
@@ -1032,7 +1032,7 @@
             "test_user_message_description");
 }
 
-TEST_F(PaymentsClientTest, UnmaskResponseIncludesEmptyDeclineDetails) {
+TEST_F(PaymentsNetworkInterfaceTest, UnmaskResponseIncludesEmptyDeclineDetails) {
   StartUnmasking(CardUnmaskOptions().with_virtual_card());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
@@ -1048,9 +1048,9 @@
       unmask_response_details()->autofill_error_dialog_context.has_value());
 }
 
-TEST_F(PaymentsClientTest, OptInSuccess) {
+TEST_F(PaymentsNetworkInterfaceTest, OptInSuccess) {
   StartOptChangeRequest(
-      PaymentsClient::OptChangeRequestDetails::ENABLE_FIDO_AUTH);
+      PaymentsNetworkInterface::OptChangeRequestDetails::ENABLE_FIDO_AUTH);
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
                  "{ \"fido_authentication_info\": { \"user_status\": "
@@ -1059,18 +1059,18 @@
   EXPECT_TRUE(opt_change_response_.user_is_opted_in.value());
 }
 
-TEST_F(PaymentsClientTest, OptInServerUnresponsive) {
+TEST_F(PaymentsNetworkInterfaceTest, OptInServerUnresponsive) {
   StartOptChangeRequest(
-      PaymentsClient::OptChangeRequestDetails::ENABLE_FIDO_AUTH);
+      PaymentsNetworkInterface::OptChangeRequestDetails::ENABLE_FIDO_AUTH);
   IssueOAuthToken();
   ReturnResponse(net::HTTP_REQUEST_TIMEOUT, "");
   EXPECT_EQ(AutofillClient::PaymentsRpcResult::kNetworkError, result_);
   EXPECT_FALSE(opt_change_response_.user_is_opted_in.has_value());
 }
 
-TEST_F(PaymentsClientTest, OptOutSuccess) {
+TEST_F(PaymentsNetworkInterfaceTest, OptOutSuccess) {
   StartOptChangeRequest(
-      PaymentsClient::OptChangeRequestDetails::DISABLE_FIDO_AUTH);
+      PaymentsNetworkInterface::OptChangeRequestDetails::DISABLE_FIDO_AUTH);
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
                  "{ \"fido_authentication_info\": { \"user_status\": "
@@ -1079,9 +1079,9 @@
   EXPECT_FALSE(opt_change_response_.user_is_opted_in.value());
 }
 
-TEST_F(PaymentsClientTest, EnrollAttemptReturnsCreationOptions) {
+TEST_F(PaymentsNetworkInterfaceTest, EnrollAttemptReturnsCreationOptions) {
   StartOptChangeRequest(
-      PaymentsClient::OptChangeRequestDetails::ENABLE_FIDO_AUTH);
+      PaymentsNetworkInterface::OptChangeRequestDetails::ENABLE_FIDO_AUTH);
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
                  "{ \"fido_authentication_info\": { \"user_status\": "
@@ -1095,7 +1095,7 @@
                 "relying_party_id"));
 }
 
-TEST_F(PaymentsClientTest, GetDetailsSuccess) {
+TEST_F(PaymentsNetworkInterfaceTest, GetDetailsSuccess) {
   StartGettingUploadDetails(GetUploadDetailsOptions());
   IssueOAuthToken();
   ReturnResponse(
@@ -1105,13 +1105,13 @@
   EXPECT_NE(nullptr, legal_message_.get());
 }
 
-TEST_F(PaymentsClientTest, GetDetailsRemovesNonLocationData) {
+TEST_F(PaymentsNetworkInterfaceTest, GetDetailsRemovesNonLocationData) {
   StartGettingUploadDetails(GetUploadDetailsOptions());
   IssueOAuthToken();
 
   // Verify that the recipient name field and test names appear nowhere in the
   // upload data.
-  EXPECT_TRUE(GetUploadData().find(PaymentsClient::kRecipientName) ==
+  EXPECT_TRUE(GetUploadData().find(PaymentsNetworkInterface::kRecipientName) ==
               std::string::npos);
   EXPECT_TRUE(GetUploadData().find("John") == std::string::npos);
   EXPECT_TRUE(GetUploadData().find("Smith") == std::string::npos);
@@ -1120,7 +1120,7 @@
 
   // Verify that the phone number field and test numbers appear nowhere in the
   // upload data.
-  EXPECT_TRUE(GetUploadData().find(PaymentsClient::kPhoneNumber) ==
+  EXPECT_TRUE(GetUploadData().find(PaymentsNetworkInterface::kPhoneNumber) ==
               std::string::npos);
   EXPECT_TRUE(GetUploadData().find("212") == std::string::npos);
   EXPECT_TRUE(GetUploadData().find("555") == std::string::npos);
@@ -1129,7 +1129,7 @@
   EXPECT_TRUE(GetUploadData().find("0090") == std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, GetDetailsIncludesDetectedValuesInRequest) {
+TEST_F(PaymentsNetworkInterfaceTest, GetDetailsIncludesDetectedValuesInRequest) {
   StartGettingUploadDetails(GetUploadDetailsOptions());
   IssueOAuthToken();
 
@@ -1140,7 +1140,7 @@
               std::string::npos);
 }
 
-TEST_F(PaymentsClientTest,
+TEST_F(PaymentsNetworkInterfaceTest,
        GetDetailsIncludesIncludesClientBehaviorSignalsInChromeUserContext) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
@@ -1162,7 +1162,7 @@
   EXPECT_THAT(GetUploadData(), HasSubstr("\"client_behavior_signals\":[1]"));
 }
 
-TEST_F(PaymentsClientTest, GetDetailsIncludesChromeUserContext) {
+TEST_F(PaymentsNetworkInterfaceTest, GetDetailsIncludesChromeUserContext) {
   StartGettingUploadDetails(GetUploadDetailsOptions());
   IssueOAuthToken();
 
@@ -1171,10 +1171,10 @@
   EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
 }
 
-TEST_F(PaymentsClientTest,
+TEST_F(PaymentsNetworkInterfaceTest,
        GetDetailsIncludesUpstreamCheckoutFlowUploadCardSourceInRequest) {
   StartGettingUploadDetails(GetUploadDetailsOptions().with_upload_card_source(
-      PaymentsClient::UploadCardSource::UPSTREAM_CHECKOUT_FLOW));
+      PaymentsNetworkInterface::UploadCardSource::UPSTREAM_CHECKOUT_FLOW));
   IssueOAuthToken();
 
   // Verify that the correct upload card source was included in the request.
@@ -1182,10 +1182,10 @@
               std::string::npos);
 }
 
-TEST_F(PaymentsClientTest,
+TEST_F(PaymentsNetworkInterfaceTest,
        GetDetailsIncludesUpstreamSettingsPageUploadCardSourceInRequest) {
   StartGettingUploadDetails(GetUploadDetailsOptions().with_upload_card_source(
-      PaymentsClient::UploadCardSource::UPSTREAM_SETTINGS_PAGE));
+      PaymentsNetworkInterface::UploadCardSource::UPSTREAM_SETTINGS_PAGE));
   IssueOAuthToken();
 
   // Verify that the correct upload card source was included in the request.
@@ -1193,10 +1193,10 @@
               std::string::npos);
 }
 
-TEST_F(PaymentsClientTest,
+TEST_F(PaymentsNetworkInterfaceTest,
        GetDetailsIncludesUpstreamCardOcrUploadCardSourceInRequest) {
   StartGettingUploadDetails(GetUploadDetailsOptions().with_upload_card_source(
-      PaymentsClient::UploadCardSource::UPSTREAM_CARD_OCR));
+      PaymentsNetworkInterface::UploadCardSource::UPSTREAM_CARD_OCR));
   IssueOAuthToken();
 
   // Verify that the correct upload card source was included in the request.
@@ -1204,10 +1204,10 @@
 }
 
 TEST_F(
-    PaymentsClientTest,
+    PaymentsNetworkInterfaceTest,
     GetDetailsIncludesLocalCardMigrationCheckoutFlowUploadCardSourceInRequest) {
   StartGettingUploadDetails(GetUploadDetailsOptions().with_upload_card_source(
-      PaymentsClient::UploadCardSource::LOCAL_CARD_MIGRATION_CHECKOUT_FLOW));
+      PaymentsNetworkInterface::UploadCardSource::LOCAL_CARD_MIGRATION_CHECKOUT_FLOW));
   IssueOAuthToken();
 
   // Verify that the correct upload card source was included in the request.
@@ -1216,10 +1216,10 @@
 }
 
 TEST_F(
-    PaymentsClientTest,
+    PaymentsNetworkInterfaceTest,
     GetDetailsIncludesLocalCardMigrationSettingsPageUploadCardSourceInRequest) {
   StartGettingUploadDetails(GetUploadDetailsOptions().with_upload_card_source(
-      PaymentsClient::UploadCardSource::LOCAL_CARD_MIGRATION_SETTINGS_PAGE));
+      PaymentsNetworkInterface::UploadCardSource::LOCAL_CARD_MIGRATION_SETTINGS_PAGE));
   IssueOAuthToken();
 
   // Verify that the correct upload card source was included in the request.
@@ -1227,7 +1227,7 @@
               std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, GetDetailsIncludesUnknownUploadCardSourceInRequest) {
+TEST_F(PaymentsNetworkInterfaceTest, GetDetailsIncludesUnknownUploadCardSourceInRequest) {
   StartGettingUploadDetails(GetUploadDetailsOptions());
   IssueOAuthToken();
 
@@ -1236,7 +1236,7 @@
               std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, GetUploadDetailsVariationsTest) {
+TEST_F(PaymentsNetworkInterfaceTest, GetUploadDetailsVariationsTest) {
   // Register a trial and variation id, so that there is data in variations
   // headers.
   CreateFieldTrialWithId("AutofillTest", "Group", 369);
@@ -1247,7 +1247,7 @@
   EXPECT_TRUE(HasVariationsHeader());
 }
 
-TEST_F(PaymentsClientTest, GetDetailsIncludeBillableServiceNumber) {
+TEST_F(PaymentsNetworkInterfaceTest, GetDetailsIncludeBillableServiceNumber) {
   StartGettingUploadDetails(GetUploadDetailsOptions());
   IssueOAuthToken();
 
@@ -1256,7 +1256,7 @@
               std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, GetDetailsIncludeBillingCustomerNumber) {
+TEST_F(PaymentsNetworkInterfaceTest, GetDetailsIncludeBillingCustomerNumber) {
   StartGettingUploadDetails(GetUploadDetailsOptions());
   IssueOAuthToken();
 
@@ -1267,7 +1267,7 @@
       std::string::npos);
 }
 
-TEST_F(PaymentsClientTest,
+TEST_F(PaymentsNetworkInterfaceTest,
        GetDetailsExcludesBillingCustomerNumberIfNoBcnExists) {
   // A value of zero is treated as a non-existent BCN.
   StartGettingUploadDetails(
@@ -1282,7 +1282,7 @@
               std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, GetDetailsFollowedByUploadSuccess) {
+TEST_F(PaymentsNetworkInterfaceTest, GetDetailsFollowedByUploadSuccess) {
   StartGettingUploadDetails(GetUploadDetailsOptions());
   IssueOAuthToken();
   ReturnResponse(
@@ -1297,14 +1297,14 @@
   EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
 }
 
-TEST_F(PaymentsClientTest, GetDetailsMissingContextToken) {
+TEST_F(PaymentsNetworkInterfaceTest, GetDetailsMissingContextToken) {
   StartGettingUploadDetails(GetUploadDetailsOptions());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK, "{ \"legal_message\": {} }");
   EXPECT_EQ(AutofillClient::PaymentsRpcResult::kPermanentFailure, result_);
 }
 
-TEST_F(PaymentsClientTest, GetDetailsMissingLegalMessage) {
+TEST_F(PaymentsNetworkInterfaceTest, GetDetailsMissingLegalMessage) {
   StartGettingUploadDetails(GetUploadDetailsOptions());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK, "{ \"context_token\": \"some_token\" }");
@@ -1312,7 +1312,7 @@
   EXPECT_EQ(nullptr, legal_message_.get());
 }
 
-TEST_F(PaymentsClientTest, SupportedCardBinRangesParsesCorrectly) {
+TEST_F(PaymentsNetworkInterfaceTest, SupportedCardBinRangesParsesCorrectly) {
   StartGettingUploadDetails(GetUploadDetailsOptions());
   IssueOAuthToken();
   ReturnResponse(
@@ -1334,7 +1334,7 @@
   EXPECT_EQ(765, supported_card_bin_ranges_[2].second);
 }
 
-TEST_F(PaymentsClientTest, GetUploadAccountFromSyncTest) {
+TEST_F(PaymentsNetworkInterfaceTest, GetUploadAccountFromSyncTest) {
   // Set up a different account.
   const AccountInfo& secondary_account_info =
       identity_test_env_.MakeAccountAvailable("secondary@gmail.com");
@@ -1356,7 +1356,7 @@
   EXPECT_EQ("Bearer secondary_account_token", auth_header_value);
 }
 
-TEST_F(PaymentsClientTest, UploadCardVariationsTest) {
+TEST_F(PaymentsNetworkInterfaceTest, UploadCardVariationsTest) {
   // Register a trial and variation id, so that there is data in variations
   // headers.
   CreateFieldTrialWithId("AutofillTest", "Group", 369);
@@ -1367,7 +1367,7 @@
   EXPECT_TRUE(HasVariationsHeader());
 }
 
-TEST_F(PaymentsClientTest, UnmaskCardVariationsTest) {
+TEST_F(PaymentsNetworkInterfaceTest, UnmaskCardVariationsTest) {
   // Register a trial and variation id, so that there is data in variations
   // headers.
   CreateFieldTrialWithId("AutofillTest", "Group", 369);
@@ -1378,7 +1378,7 @@
   EXPECT_TRUE(HasVariationsHeader());
 }
 
-TEST_F(PaymentsClientTest, UploadSuccessEmptyResponse) {
+TEST_F(PaymentsNetworkInterfaceTest, UploadSuccessEmptyResponse) {
   StartUploading(UploadCardOptions());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK, "{}");
@@ -1389,7 +1389,7 @@
   EXPECT_TRUE(upload_card_response_details_.card_art_url.is_empty());
 }
 
-TEST_F(PaymentsClientTest, UploadSuccessInstrumentIdPresent) {
+TEST_F(PaymentsNetworkInterfaceTest, UploadSuccessInstrumentIdPresent) {
   StartUploading(UploadCardOptions());
   IssueOAuthToken();
   upload_card_response_details_.instrument_id = absl::nullopt;
@@ -1401,7 +1401,7 @@
   EXPECT_EQ(upload_card_response_details_.instrument_id, 9223372036854775807);
 }
 
-TEST_F(PaymentsClientTest, UploadSuccessVirtualCardEnrollmentStatePresent) {
+TEST_F(PaymentsNetworkInterfaceTest, UploadSuccessVirtualCardEnrollmentStatePresent) {
   bool oauth_token_issued = false;
   for (CreditCard::VirtualCardEnrollmentState virtual_card_enrollment_state :
        {CreditCard::VirtualCardEnrollmentState::kUnenrolledAndNotEligible,
@@ -1409,7 +1409,7 @@
         CreditCard::VirtualCardEnrollmentState::kEnrolled}) {
     StartUploading(UploadCardOptions());
     // An OAuthToken needs to be issued to initiate the first UploadCard call
-    // from PaymentsClientTest::StartUploading(), but only for the first call.
+    // from PaymentsNetworkInterfaceTest::StartUploading(), but only for the first call.
     // All future calls will use the first OAuthToken. If multiple OAuthTokens
     // are issued this test will time out.
     if (!oauth_token_issued) {
@@ -1442,7 +1442,7 @@
   }
 }
 
-TEST_F(PaymentsClientTest,
+TEST_F(PaymentsNetworkInterfaceTest,
        UploadSuccessGetDetailsForEnrollmentResponseDetailsPresent) {
   StartUploading(UploadCardOptions());
   IssueOAuthToken();
@@ -1474,7 +1474,7 @@
       "some_token");
 }
 
-TEST_F(PaymentsClientTest, UploadSuccessCardArtUrlPresent) {
+TEST_F(PaymentsNetworkInterfaceTest, UploadSuccessCardArtUrlPresent) {
   StartUploading(UploadCardOptions());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
@@ -1484,13 +1484,13 @@
             "https://www.example.com/");
 }
 
-TEST_F(PaymentsClientTest, UploadIncludesNonLocationData) {
+TEST_F(PaymentsNetworkInterfaceTest, UploadIncludesNonLocationData) {
   StartUploading(UploadCardOptions());
   IssueOAuthToken();
 
   // Verify that the recipient name field and test names do appear in the upload
   // data.
-  EXPECT_TRUE(GetUploadData().find(PaymentsClient::kRecipientName) !=
+  EXPECT_TRUE(GetUploadData().find(PaymentsNetworkInterface::kRecipientName) !=
               std::string::npos);
   EXPECT_TRUE(GetUploadData().find("John") != std::string::npos);
   EXPECT_TRUE(GetUploadData().find("Smith") != std::string::npos);
@@ -1499,7 +1499,7 @@
 
   // Verify that the phone number field and test numbers do appear in the upload
   // data.
-  EXPECT_TRUE(GetUploadData().find(PaymentsClient::kPhoneNumber) !=
+  EXPECT_TRUE(GetUploadData().find(PaymentsNetworkInterface::kPhoneNumber) !=
               std::string::npos);
   EXPECT_TRUE(GetUploadData().find("212") != std::string::npos);
   EXPECT_TRUE(GetUploadData().find("555") != std::string::npos);
@@ -1508,7 +1508,7 @@
   EXPECT_TRUE(GetUploadData().find("0090") != std::string::npos);
 }
 
-TEST_F(PaymentsClientTest,
+TEST_F(PaymentsNetworkInterfaceTest,
        UploadRequestIncludesBillingCustomerNumberInRequest) {
   StartUploading(UploadCardOptions().with_billing_customer_number(1234L));
   IssueOAuthToken();
@@ -1518,7 +1518,7 @@
               std::string::npos);
 }
 
-TEST_F(PaymentsClientTest,
+TEST_F(PaymentsNetworkInterfaceTest,
        UploadRequestExcludesBillingCustomerNumberIfNoBcnExists) {
   // A value of zero is treated as a non-existent BCN.
   StartUploading(UploadCardOptions().with_billing_customer_number(0L));
@@ -1530,7 +1530,7 @@
               std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, UploadRequestIncludesClientBehaviorSignals) {
+TEST_F(PaymentsNetworkInterfaceTest, UploadRequestIncludesClientBehaviorSignals) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(
       features::kAutofillEnableNewSaveCardBubbleUi);
@@ -1551,7 +1551,7 @@
               HasSubstr("%22client_behavior_signals%22:%5B1%5D"));
 }
 
-TEST_F(PaymentsClientTest, UploadRequestIncludesPan) {
+TEST_F(PaymentsNetworkInterfaceTest, UploadRequestIncludesPan) {
   StartUploading(UploadCardOptions());
   IssueOAuthToken();
 
@@ -1564,7 +1564,7 @@
               std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, UploadIncludesCvcInRequestIfProvided) {
+TEST_F(PaymentsNetworkInterfaceTest, UploadIncludesCvcInRequestIfProvided) {
   StartUploading(UploadCardOptions().with_cvc_in_request(true));
   IssueOAuthToken();
 
@@ -1575,7 +1575,7 @@
   EXPECT_TRUE(GetUploadData().find("&s7e_13_cvc=") != std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, UploadDoesNotIncludeCvcInRequestIfNotProvided) {
+TEST_F(PaymentsNetworkInterfaceTest, UploadDoesNotIncludeCvcInRequestIfNotProvided) {
   StartUploading(UploadCardOptions().with_cvc_in_request(false));
   IssueOAuthToken();
 
@@ -1587,7 +1587,7 @@
   EXPECT_TRUE(GetUploadData().find("&s7e_13_cvc=") == std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, UploadIncludesChromeUserContext) {
+TEST_F(PaymentsNetworkInterfaceTest, UploadIncludesChromeUserContext) {
   StartUploading(UploadCardOptions());
   IssueOAuthToken();
 
@@ -1596,7 +1596,7 @@
   EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, UploadIncludesCardNickname) {
+TEST_F(PaymentsNetworkInterfaceTest, UploadIncludesCardNickname) {
   StartUploading(UploadCardOptions().with_nickname_in_request(true));
   IssueOAuthToken();
 
@@ -1606,7 +1606,7 @@
               std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, UploadDoesNotIncludeCardNicknameEmptyNickname) {
+TEST_F(PaymentsNetworkInterfaceTest, UploadDoesNotIncludeCardNicknameEmptyNickname) {
   StartUploading(UploadCardOptions().with_nickname_in_request(false));
   IssueOAuthToken();
 
@@ -1614,13 +1614,13 @@
   EXPECT_FALSE(GetUploadData().find("nickname") != std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, UnmaskMissingPan) {
+TEST_F(PaymentsNetworkInterfaceTest, UnmaskMissingPan) {
   StartUnmasking(CardUnmaskOptions());
   ReturnResponse(net::HTTP_OK, "{}");
   EXPECT_EQ(AutofillClient::PaymentsRpcResult::kPermanentFailure, result_);
 }
 
-TEST_F(PaymentsClientTest, UnmaskRetryFailure) {
+TEST_F(PaymentsNetworkInterfaceTest, UnmaskRetryFailure) {
   StartUnmasking(CardUnmaskOptions());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK, "{ \"error\": { \"code\": \"INTERNAL\" } }");
@@ -1628,7 +1628,7 @@
   EXPECT_EQ("", unmask_response_details()->real_pan);
 }
 
-TEST_F(PaymentsClientTest, UnmaskPermanentFailure) {
+TEST_F(PaymentsNetworkInterfaceTest, UnmaskPermanentFailure) {
   StartUnmasking(CardUnmaskOptions());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
@@ -1637,7 +1637,7 @@
   EXPECT_EQ("", unmask_response_details()->real_pan);
 }
 
-TEST_F(PaymentsClientTest, UnmaskMalformedResponse) {
+TEST_F(PaymentsNetworkInterfaceTest, UnmaskMalformedResponse) {
   StartUnmasking(CardUnmaskOptions());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK, "{ \"error_code\": \"WRONG_JSON_FORMAT\" }");
@@ -1645,7 +1645,7 @@
   EXPECT_EQ("", unmask_response_details()->real_pan);
 }
 
-TEST_F(PaymentsClientTest, ReauthNeeded) {
+TEST_F(PaymentsNetworkInterfaceTest, ReauthNeeded) {
   {
     StartUnmasking(CardUnmaskOptions());
     IssueOAuthToken();
@@ -1668,7 +1668,7 @@
     StartUnmasking(CardUnmaskOptions());
     // NOTE: Don't issue an access token here: the issuing of an access token
     // first waits for the access token request to be received, but here there
-    // should be no access token request because PaymentsClient should reuse the
+    // should be no access token request because PaymentsNetworkInterface should reuse the
     // access token from the previous request.
     ReturnResponse(net::HTTP_UNAUTHORIZED, "");
     // No response yet.
@@ -1683,7 +1683,7 @@
   }
 }
 
-TEST_F(PaymentsClientTest, NetworkError) {
+TEST_F(PaymentsNetworkInterfaceTest, NetworkError) {
   StartUnmasking(CardUnmaskOptions());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_REQUEST_TIMEOUT, std::string());
@@ -1691,7 +1691,7 @@
   EXPECT_EQ("", unmask_response_details()->real_pan);
 }
 
-TEST_F(PaymentsClientTest, OtherError) {
+TEST_F(PaymentsNetworkInterfaceTest, OtherError) {
   StartUnmasking(CardUnmaskOptions());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_FORBIDDEN, std::string());
@@ -1699,7 +1699,7 @@
   EXPECT_EQ("", unmask_response_details()->real_pan);
 }
 
-TEST_F(PaymentsClientTest, VcnRetrievalTryAgainFailure) {
+TEST_F(PaymentsNetworkInterfaceTest, VcnRetrievalTryAgainFailure) {
   StartUnmasking(CardUnmaskOptions().with_virtual_card());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
@@ -1709,7 +1709,7 @@
             result_);
 }
 
-TEST_F(PaymentsClientTest, VcnRetrievalPermanentFailure) {
+TEST_F(PaymentsNetworkInterfaceTest, VcnRetrievalPermanentFailure) {
   StartUnmasking(CardUnmaskOptions().with_virtual_card());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
@@ -1719,7 +1719,7 @@
             result_);
 }
 
-TEST_F(PaymentsClientTest, UnmaskPermanentFailureWhenVcnMissingExpiration) {
+TEST_F(PaymentsNetworkInterfaceTest, UnmaskPermanentFailureWhenVcnMissingExpiration) {
   StartUnmasking(CardUnmaskOptions().with_virtual_card());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
@@ -1729,7 +1729,7 @@
   EXPECT_EQ(AutofillClient::PaymentsRpcResult::kPermanentFailure, result_);
 }
 
-TEST_F(PaymentsClientTest, UnmaskPermanentFailureWhenVcnMissingCvv) {
+TEST_F(PaymentsNetworkInterfaceTest, UnmaskPermanentFailureWhenVcnMissingCvv) {
   StartUnmasking(CardUnmaskOptions().with_virtual_card());
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
@@ -1742,7 +1742,7 @@
 
 // Tests for the local card migration flow. Desktop only.
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-TEST_F(PaymentsClientTest, GetDetailsFollowedByMigrationSuccess) {
+TEST_F(PaymentsNetworkInterfaceTest, GetDetailsFollowedByMigrationSuccess) {
   StartGettingUploadDetails(GetUploadDetailsOptions());
   IssueOAuthToken();
   ReturnResponse(
@@ -1762,7 +1762,7 @@
 
 // Tests for the local card migration flow. Desktop only.
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-TEST_F(PaymentsClientTest, MigrateCardsVariationsTest) {
+TEST_F(PaymentsNetworkInterfaceTest, MigrateCardsVariationsTest) {
   // Register a trial and variation id, so that there is data in variations
   // headers.
   CreateFieldTrialWithId("AutofillTest", "Group", 369);
@@ -1773,7 +1773,7 @@
   EXPECT_TRUE(HasVariationsHeader());
 }
 
-TEST_F(PaymentsClientTest, MigrationRequestIncludesUniqueId) {
+TEST_F(PaymentsNetworkInterfaceTest, MigrationRequestIncludesUniqueId) {
   StartMigrating(/*has_cardholder_name=*/true);
   IssueOAuthToken();
 
@@ -1787,7 +1787,7 @@
       std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, MigrationRequestIncludesEncryptedPan) {
+TEST_F(PaymentsNetworkInterfaceTest, MigrationRequestIncludesEncryptedPan) {
   StartMigrating(/*has_cardholder_name=*/true);
   IssueOAuthToken();
 
@@ -1802,7 +1802,7 @@
               std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, MigrationRequestIncludesCardholderNameWhenItExists) {
+TEST_F(PaymentsNetworkInterfaceTest, MigrationRequestIncludesCardholderNameWhenItExists) {
   StartMigrating(/*has_cardholder_name=*/true);
   IssueOAuthToken();
 
@@ -1811,7 +1811,7 @@
   EXPECT_TRUE(GetUploadData().find("cardholder_name") != std::string::npos);
 }
 
-TEST_F(PaymentsClientTest,
+TEST_F(PaymentsNetworkInterfaceTest,
        MigrationRequestExcludesCardholderNameWhenItDoesNotExist) {
   StartMigrating(/*has_cardholder_name=*/false);
   IssueOAuthToken();
@@ -1821,7 +1821,7 @@
   EXPECT_TRUE(GetUploadData().find("cardholder_name") == std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, MigrationRequestIncludesChromeUserContext) {
+TEST_F(PaymentsNetworkInterfaceTest, MigrationRequestIncludesChromeUserContext) {
   StartMigrating(/*has_cardholder_name=*/true);
   IssueOAuthToken();
 
@@ -1830,7 +1830,7 @@
   EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, MigrationRequestIncludesCardNickname) {
+TEST_F(PaymentsNetworkInterfaceTest, MigrationRequestIncludesCardNickname) {
   StartMigrating(/*has_cardholder_name=*/true,
                  /*set_nickname_for_first_card=*/true);
   IssueOAuthToken();
@@ -1846,7 +1846,7 @@
   EXPECT_FALSE(GetUploadData().find("nickname", pos + 1) != std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, MigrationSuccessWithSaveResult) {
+TEST_F(PaymentsNetworkInterfaceTest, MigrationSuccessWithSaveResult) {
   StartMigrating(/*has_cardholder_name=*/true);
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
@@ -1864,7 +1864,7 @@
   EXPECT_TRUE(migration_save_results_->at("1") == "TEMPORARY_FAILURE");
 }
 
-TEST_F(PaymentsClientTest, MigrationMissingSaveResult) {
+TEST_F(PaymentsNetworkInterfaceTest, MigrationMissingSaveResult) {
   StartMigrating(/*has_cardholder_name=*/true);
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
@@ -1873,7 +1873,7 @@
   EXPECT_EQ(nullptr, migration_save_results_.get());
 }
 
-TEST_F(PaymentsClientTest, MigrationSuccessWithDisplayText) {
+TEST_F(PaymentsNetworkInterfaceTest, MigrationSuccessWithDisplayText) {
   StartMigrating(/*has_cardholder_name=*/true);
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
@@ -1884,7 +1884,7 @@
 }
 #endif
 
-TEST_F(PaymentsClientTest, SelectChallengeOptionWithSmsOtpMethod) {
+TEST_F(PaymentsNetworkInterfaceTest, SelectChallengeOptionWithSmsOtpMethod) {
   StartSelectingChallengeOption(CardUnmaskChallengeOptionType::kSmsOtp,
                                 "arbitrary id for sms otp");
   IssueOAuthToken();
@@ -1902,7 +1902,7 @@
   assertNotIncludedInRequest("masked_phone_number");
 }
 
-TEST_F(PaymentsClientTest, SelectChallengeOptionSuccess) {
+TEST_F(PaymentsNetworkInterfaceTest, SelectChallengeOptionSuccess) {
   StartSelectingChallengeOption();
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK, "{ \"context_token\": \"new context token\" }");
@@ -1911,7 +1911,7 @@
   EXPECT_EQ("new context token", context_token_);
 }
 
-TEST_F(PaymentsClientTest, SelectChallengeOptionTemporaryFailure) {
+TEST_F(PaymentsNetworkInterfaceTest, SelectChallengeOptionTemporaryFailure) {
   StartSelectingChallengeOption();
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
@@ -1922,7 +1922,7 @@
             result_);
 }
 
-TEST_F(PaymentsClientTest, SelectChallengeOptionVcnFlowPermanentFailure) {
+TEST_F(PaymentsNetworkInterfaceTest, SelectChallengeOptionVcnFlowPermanentFailure) {
   StartSelectingChallengeOption();
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK,
@@ -1933,7 +1933,7 @@
             result_);
 }
 
-TEST_F(PaymentsClientTest, SelectChallengeOptionResponseMissingContextToken) {
+TEST_F(PaymentsNetworkInterfaceTest, SelectChallengeOptionResponseMissingContextToken) {
   StartSelectingChallengeOption();
   IssueOAuthToken();
   ReturnResponse(net::HTTP_OK, "{}");
@@ -1947,7 +1947,7 @@
     UpdateVirtualCardEnrollmentTestData;
 
 class UpdateVirtualCardEnrollmentTest
-    : public PaymentsClientTest,
+    : public PaymentsNetworkInterfaceTest,
       public ::testing::WithParamInterface<
           UpdateVirtualCardEnrollmentTestData> {
  public:
@@ -2015,7 +2015,7 @@
   void StartUpdateVirtualCardEnrollment(
       VirtualCardEnrollmentSource virtual_card_enrollment_source,
       VirtualCardEnrollmentRequestType virtual_card_enrollment_request_type) {
-    PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails request_details;
+    PaymentsNetworkInterface::UpdateVirtualCardEnrollmentRequestDetails request_details;
     request_details.virtual_card_enrollment_request_type =
         virtual_card_enrollment_request_type;
     request_details.virtual_card_enrollment_source =
@@ -2026,10 +2026,10 @@
       request_details.vcn_context_token = "fake context token";
     }
     request_details.instrument_id = 12345678;
-    client_->UpdateVirtualCardEnrollment(
+    payments_network_interface_->UpdateVirtualCardEnrollment(
         request_details,
         base::BindOnce(
-            &PaymentsClientTest::OnDidGetUpdateVirtualCardEnrollmentResponse,
+            &PaymentsNetworkInterfaceTest::OnDidGetUpdateVirtualCardEnrollmentResponse,
             GetWeakPtr()));
   }
 };
@@ -2064,7 +2064,7 @@
 }
 
 class GetVirtualCardEnrollmentDetailsTest
-    : public PaymentsClientTest,
+    : public PaymentsNetworkInterfaceTest,
       public ::testing::WithParamInterface<
           std::tuple<VirtualCardEnrollmentSource,
                      AutofillClient::PaymentsRpcResult>> {
@@ -2097,16 +2097,16 @@
        GetVirtualCardEnrollmentDetailsTest_TestAllFlows) {
   VirtualCardEnrollmentSource source = std::get<0>(GetParam());
 
-  PaymentsClient::GetDetailsForEnrollmentRequestDetails request_details;
+  PaymentsNetworkInterface::GetDetailsForEnrollmentRequestDetails request_details;
   request_details.source = source;
   request_details.instrument_id = 12345678;
   request_details.billing_customer_number = 555666777888;
   request_details.risk_data = "fake risk data";
   request_details.app_locale = "en";
 
-  client_->GetVirtualCardEnrollmentDetails(
+  payments_network_interface_->GetVirtualCardEnrollmentDetails(
       request_details,
-      base::BindOnce(&PaymentsClientTest::OnDidGetVirtualCardEnrollmentDetails,
+      base::BindOnce(&PaymentsNetworkInterfaceTest::OnDidGetVirtualCardEnrollmentDetails,
                      GetWeakPtr()));
   IssueOAuthToken();
 
diff --git a/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request.cc b/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request.cc
index b9b7233f..2735955 100644
--- a/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request.cc
+++ b/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request.cc
@@ -28,11 +28,11 @@
 }  // namespace
 
 GetDetailsForEnrollmentRequest::GetDetailsForEnrollmentRequest(
-    const PaymentsClient::GetDetailsForEnrollmentRequestDetails&
+    const PaymentsNetworkInterface::GetDetailsForEnrollmentRequestDetails&
         request_details,
-    base::OnceCallback<
-        void(AutofillClient::PaymentsRpcResult,
-             const PaymentsClient::GetDetailsForEnrollmentResponseDetails&)>
+    base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+                            const PaymentsNetworkInterface::
+                                GetDetailsForEnrollmentResponseDetails&)>
         callback)
     : request_details_(request_details), callback_(std::move(callback)) {}
 
diff --git a/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request.h b/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request.h
index 92db6b5..718c9dd3 100644
--- a/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request.h
+++ b/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request.h
@@ -5,7 +5,7 @@
 #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_REQUESTS_GET_DETAILS_FOR_ENROLLMENT_REQUEST_H_
 #define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_REQUESTS_GET_DETAILS_FOR_ENROLLMENT_REQUEST_H_
 
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/payments_requests/payments_request.h"
 
 namespace autofill::payments {
@@ -15,11 +15,11 @@
 class GetDetailsForEnrollmentRequest : public PaymentsRequest {
  public:
   GetDetailsForEnrollmentRequest(
-      const PaymentsClient::GetDetailsForEnrollmentRequestDetails&
+      const PaymentsNetworkInterface::GetDetailsForEnrollmentRequestDetails&
           request_details,
-      base::OnceCallback<
-          void(AutofillClient::PaymentsRpcResult,
-               const PaymentsClient::GetDetailsForEnrollmentResponseDetails&)>
+      base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
+                              const PaymentsNetworkInterface::
+                                  GetDetailsForEnrollmentResponseDetails&)>
           callback);
   GetDetailsForEnrollmentRequest(const GetDetailsForEnrollmentRequest&) =
       delete;
@@ -39,16 +39,18 @@
   friend class GetDetailsForEnrollmentRequestTest;
 
   // Used to store information to be populated to the request.
-  PaymentsClient::GetDetailsForEnrollmentRequestDetails request_details_;
+  PaymentsNetworkInterface::GetDetailsForEnrollmentRequestDetails
+      request_details_;
 
   // Used to store information parsed from the response. Will be passed into the
   // |callback_| function as a param.
-  PaymentsClient::GetDetailsForEnrollmentResponseDetails response_details_;
+  PaymentsNetworkInterface::GetDetailsForEnrollmentResponseDetails
+      response_details_;
 
   // The callback function to be invoked when the response is received.
   base::OnceCallback<void(
       AutofillClient::PaymentsRpcResult,
-      const PaymentsClient::GetDetailsForEnrollmentResponseDetails&)>
+      const PaymentsNetworkInterface::GetDetailsForEnrollmentResponseDetails&)>
       callback_;
 };
 
diff --git a/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request_unittest.cc b/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request_unittest.cc
index c78aa53..4726c1c8 100644
--- a/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request_unittest.cc
+++ b/components/autofill/core/browser/payments/payments_requests/get_details_for_enrollment_request_unittest.cc
@@ -24,7 +24,8 @@
   ~GetDetailsForEnrollmentRequestTest() override = default;
 
   void SetUp() override {
-    PaymentsClient::GetDetailsForEnrollmentRequestDetails request_details;
+    PaymentsNetworkInterface::GetDetailsForEnrollmentRequestDetails
+        request_details;
     request_details.instrument_id = 11223344;
     request_details.app_locale = "en";
     request_details.billing_customer_number = 55667788;
@@ -36,7 +37,7 @@
 
   GetDetailsForEnrollmentRequest* GetRequest() const { return request_.get(); }
 
-  const PaymentsClient::GetDetailsForEnrollmentResponseDetails&
+  const PaymentsNetworkInterface::GetDetailsForEnrollmentResponseDetails&
   GetParsedResponse() const {
     return request_->response_details_;
   }
diff --git a/components/autofill/core/browser/payments/payments_requests/get_unmask_details_request.cc b/components/autofill/core/browser/payments/payments_requests/get_unmask_details_request.cc
index c5cec02..bc7ca1c 100644
--- a/components/autofill/core/browser/payments/payments_requests/get_unmask_details_request.cc
+++ b/components/autofill/core/browser/payments/payments_requests/get_unmask_details_request.cc
@@ -17,7 +17,7 @@
 
 GetUnmaskDetailsRequest::GetUnmaskDetailsRequest(
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                            PaymentsClient::UnmaskDetails&)> callback,
+                            PaymentsNetworkInterface::UnmaskDetails&)> callback,
     const std::string& app_locale,
     const bool full_sync_enabled)
     : callback_(std::move(callback)),
diff --git a/components/autofill/core/browser/payments/payments_requests/get_unmask_details_request.h b/components/autofill/core/browser/payments/payments_requests/get_unmask_details_request.h
index fe5c97c..1d13402a 100644
--- a/components/autofill/core/browser/payments/payments_requests/get_unmask_details_request.h
+++ b/components/autofill/core/browser/payments/payments_requests/get_unmask_details_request.h
@@ -9,7 +9,7 @@
 
 #include "base/functional/callback.h"
 #include "components/autofill/core/browser/autofill_client.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/payments_requests/payments_request.h"
 
 namespace base {
@@ -22,7 +22,8 @@
  public:
   GetUnmaskDetailsRequest(
       base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                              PaymentsClient::UnmaskDetails&)> callback,
+                              PaymentsNetworkInterface::UnmaskDetails&)>
+          callback,
       const std::string& app_locale,
       const bool full_sync_enabled);
   GetUnmaskDetailsRequest(const GetUnmaskDetailsRequest&) = delete;
@@ -39,14 +40,14 @@
 
  private:
   base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                          PaymentsClient::UnmaskDetails&)>
+                          PaymentsNetworkInterface::UnmaskDetails&)>
       callback_;
   std::string app_locale_;
   const bool full_sync_enabled_;
 
   // Suggested authentication method and other information to facilitate card
   // unmasking.
-  payments::PaymentsClient::UnmaskDetails unmask_details_;
+  payments::PaymentsNetworkInterface::UnmaskDetails unmask_details_;
 };
 
 }  // namespace autofill::payments
diff --git a/components/autofill/core/browser/payments/payments_requests/get_upload_details_request.cc b/components/autofill/core/browser/payments/payments_requests/get_upload_details_request.cc
index 934cd62..507aa69 100644
--- a/components/autofill/core/browser/payments/payments_requests/get_upload_details_request.cc
+++ b/components/autofill/core/browser/payments/payments_requests/get_upload_details_request.cc
@@ -32,7 +32,7 @@
                             std::vector<std::pair<int, int>>)> callback,
     const int billable_service_number,
     const int64_t billing_customer_number,
-    PaymentsClient::UploadCardSource upload_card_source)
+    PaymentsNetworkInterface::UploadCardSource upload_card_source)
     : addresses_(addresses),
       detected_values_(detected_values),
       client_behavior_signals_(client_behavior_signals),
@@ -86,23 +86,25 @@
   request_dict.Set("detected_values", detected_values_);
 
   switch (upload_card_source_) {
-    case PaymentsClient::UploadCardSource::UNKNOWN_UPLOAD_CARD_SOURCE:
+    case PaymentsNetworkInterface::UploadCardSource::UNKNOWN_UPLOAD_CARD_SOURCE:
       request_dict.Set("upload_card_source", "UNKNOWN_UPLOAD_CARD_SOURCE");
       break;
-    case PaymentsClient::UploadCardSource::UPSTREAM_CHECKOUT_FLOW:
+    case PaymentsNetworkInterface::UploadCardSource::UPSTREAM_CHECKOUT_FLOW:
       request_dict.Set("upload_card_source", "UPSTREAM_CHECKOUT_FLOW");
       break;
-    case PaymentsClient::UploadCardSource::UPSTREAM_SETTINGS_PAGE:
+    case PaymentsNetworkInterface::UploadCardSource::UPSTREAM_SETTINGS_PAGE:
       request_dict.Set("upload_card_source", "UPSTREAM_SETTINGS_PAGE");
       break;
-    case PaymentsClient::UploadCardSource::UPSTREAM_CARD_OCR:
+    case PaymentsNetworkInterface::UploadCardSource::UPSTREAM_CARD_OCR:
       request_dict.Set("upload_card_source", "UPSTREAM_CARD_OCR");
       break;
-    case PaymentsClient::UploadCardSource::LOCAL_CARD_MIGRATION_CHECKOUT_FLOW:
+    case PaymentsNetworkInterface::UploadCardSource::
+        LOCAL_CARD_MIGRATION_CHECKOUT_FLOW:
       request_dict.Set("upload_card_source",
                        "LOCAL_CARD_MIGRATION_CHECKOUT_FLOW");
       break;
-    case PaymentsClient::UploadCardSource::LOCAL_CARD_MIGRATION_SETTINGS_PAGE:
+    case PaymentsNetworkInterface::UploadCardSource::
+        LOCAL_CARD_MIGRATION_SETTINGS_PAGE:
       request_dict.Set("upload_card_source",
                        "LOCAL_CARD_MIGRATION_SETTINGS_PAGE");
       break;
diff --git a/components/autofill/core/browser/payments/payments_requests/get_upload_details_request.h b/components/autofill/core/browser/payments/payments_requests/get_upload_details_request.h
index 1023845..9d37f64 100644
--- a/components/autofill/core/browser/payments/payments_requests/get_upload_details_request.h
+++ b/components/autofill/core/browser/payments/payments_requests/get_upload_details_request.h
@@ -11,7 +11,7 @@
 #include "base/values.h"
 #include "components/autofill/core/browser/autofill_client.h"
 #include "components/autofill/core/browser/payments/client_behavior_constants.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/payments_requests/payments_request.h"
 
 namespace autofill::payments {
@@ -30,7 +30,7 @@
                               std::vector<std::pair<int, int>>)> callback,
       const int billable_service_number,
       const int64_t billing_customer_number,
-      PaymentsClient::UploadCardSource upload_card_source);
+      PaymentsNetworkInterface::UploadCardSource upload_card_source);
   GetUploadDetailsRequest(const GetUploadDetailsRequest&) = delete;
   GetUploadDetailsRequest& operator=(const GetUploadDetailsRequest&) = delete;
   ~GetUploadDetailsRequest() override;
@@ -65,7 +65,7 @@
   std::unique_ptr<base::Value::Dict> legal_message_;
   std::vector<std::pair<int, int>> supported_card_bin_ranges_;
   const int billable_service_number_;
-  PaymentsClient::UploadCardSource upload_card_source_;
+  PaymentsNetworkInterface::UploadCardSource upload_card_source_;
   const int64_t billing_customer_number_;
 };
 
diff --git a/components/autofill/core/browser/payments/payments_requests/migrate_cards_request.cc b/components/autofill/core/browser/payments/payments_requests/migrate_cards_request.cc
index 8e5a1e3..d3aec27 100644
--- a/components/autofill/core/browser/payments/payments_requests/migrate_cards_request.cc
+++ b/components/autofill/core/browser/payments/payments_requests/migrate_cards_request.cc
@@ -24,7 +24,7 @@
 }  // namespace
 
 MigrateCardsRequest::MigrateCardsRequest(
-    const PaymentsClient::MigrationRequestDetails& request_details,
+    const PaymentsNetworkInterface::MigrationRequestDetails& request_details,
     base::span<const MigratableCreditCard> migratable_credit_cards,
     const bool full_sync_enabled,
     MigrateCardsCallback callback)
diff --git a/components/autofill/core/browser/payments/payments_requests/migrate_cards_request.h b/components/autofill/core/browser/payments/payments_requests/migrate_cards_request.h
index fe8075d..b5d8ed1 100644
--- a/components/autofill/core/browser/payments/payments_requests/migrate_cards_request.h
+++ b/components/autofill/core/browser/payments/payments_requests/migrate_cards_request.h
@@ -11,7 +11,7 @@
 #include "base/functional/callback.h"
 #include "base/memory/raw_ref.h"
 #include "components/autofill/core/browser/autofill_client.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/payments_requests/payments_request.h"
 
 namespace base {
@@ -23,7 +23,7 @@
 class MigrateCardsRequest : public PaymentsRequest {
  public:
   MigrateCardsRequest(
-      const PaymentsClient::MigrationRequestDetails& request_details,
+      const PaymentsNetworkInterface::MigrationRequestDetails& request_details,
       base::span<const MigratableCreditCard> migratable_credit_cards,
       const bool full_sync_enabled,
       MigrateCardsCallback callback);
@@ -48,7 +48,7 @@
                            const std::string& app_locale,
                            const std::string& pan_field_name);
 
-  const PaymentsClient::MigrationRequestDetails request_details_;
+  const PaymentsNetworkInterface::MigrationRequestDetails request_details_;
   const std::vector<MigratableCreditCard> migratable_credit_cards_;
   const bool full_sync_enabled_;
   MigrateCardsCallback callback_;
diff --git a/components/autofill/core/browser/payments/payments_requests/opt_change_request.cc b/components/autofill/core/browser/payments/payments_requests/opt_change_request.cc
index aefb325..d06ce40 100644
--- a/components/autofill/core/browser/payments/payments_requests/opt_change_request.cc
+++ b/components/autofill/core/browser/payments/payments_requests/opt_change_request.cc
@@ -16,10 +16,10 @@
 }  // namespace
 
 OptChangeRequest::OptChangeRequest(
-    const PaymentsClient::OptChangeRequestDetails& request_details,
-    base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                            PaymentsClient::OptChangeResponseDetails&)>
-        callback,
+    const PaymentsNetworkInterface::OptChangeRequestDetails& request_details,
+    base::OnceCallback<
+        void(AutofillClient::PaymentsRpcResult,
+             PaymentsNetworkInterface::OptChangeResponseDetails&)> callback,
     const bool full_sync_enabled)
     : request_details_(request_details),
       callback_(std::move(callback)),
@@ -48,13 +48,14 @@
 
   std::string reason;
   switch (request_details_.reason) {
-    case PaymentsClient::OptChangeRequestDetails::ENABLE_FIDO_AUTH:
+    case PaymentsNetworkInterface::OptChangeRequestDetails::ENABLE_FIDO_AUTH:
       reason = "ENABLE_FIDO_AUTH";
       break;
-    case PaymentsClient::OptChangeRequestDetails::DISABLE_FIDO_AUTH:
+    case PaymentsNetworkInterface::OptChangeRequestDetails::DISABLE_FIDO_AUTH:
       reason = "DISABLE_FIDO_AUTH";
       break;
-    case PaymentsClient::OptChangeRequestDetails::ADD_CARD_FOR_FIDO_AUTH:
+    case PaymentsNetworkInterface::OptChangeRequestDetails::
+        ADD_CARD_FOR_FIDO_AUTH:
       reason = "ADD_CARD_FOR_FIDO_AUTH";
       break;
     default:
diff --git a/components/autofill/core/browser/payments/payments_requests/opt_change_request.h b/components/autofill/core/browser/payments/payments_requests/opt_change_request.h
index 3ec53a5..6b9da6e 100644
--- a/components/autofill/core/browser/payments/payments_requests/opt_change_request.h
+++ b/components/autofill/core/browser/payments/payments_requests/opt_change_request.h
@@ -9,7 +9,7 @@
 
 #include "base/functional/callback.h"
 #include "components/autofill/core/browser/autofill_client.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/payments_requests/payments_request.h"
 
 namespace base {
@@ -21,10 +21,10 @@
 class OptChangeRequest : public PaymentsRequest {
  public:
   OptChangeRequest(
-      const PaymentsClient::OptChangeRequestDetails& request_details,
-      base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                              PaymentsClient::OptChangeResponseDetails&)>
-          callback,
+      const PaymentsNetworkInterface::OptChangeRequestDetails& request_details,
+      base::OnceCallback<
+          void(AutofillClient::PaymentsRpcResult,
+               PaymentsNetworkInterface::OptChangeResponseDetails&)> callback,
       const bool full_sync_enabled);
   OptChangeRequest(const OptChangeRequest&) = delete;
   OptChangeRequest& operator=(const OptChangeRequest&) = delete;
@@ -39,12 +39,12 @@
   void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override;
 
  private:
-  PaymentsClient::OptChangeRequestDetails request_details_;
+  PaymentsNetworkInterface::OptChangeRequestDetails request_details_;
   base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                          PaymentsClient::OptChangeResponseDetails&)>
+                          PaymentsNetworkInterface::OptChangeResponseDetails&)>
       callback_;
   const bool full_sync_enabled_;
-  PaymentsClient::OptChangeResponseDetails response_details_;
+  PaymentsNetworkInterface::OptChangeResponseDetails response_details_;
 };
 
 }  // namespace autofill::payments
diff --git a/components/autofill/core/browser/payments/payments_requests/payments_request.cc b/components/autofill/core/browser/payments/payments_requests/payments_request.cc
index f1fb1429..17e141d2 100644
--- a/components/autofill/core/browser/payments/payments_requests/payments_request.cc
+++ b/components/autofill/core/browser/payments/payments_requests/payments_request.cc
@@ -11,7 +11,7 @@
 #include "base/values.h"
 #include "build/build_config.h"
 #include "components/autofill/core/browser/payments/client_behavior_constants.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 
 namespace autofill::payments {
 
@@ -80,7 +80,8 @@
 
   if (include_non_location_data) {
     SetStringIfNotEmpty(profile, NAME_FULL, app_locale,
-                        PaymentsClient::kRecipientName, postal_address);
+                        PaymentsNetworkInterface::kRecipientName,
+                        postal_address);
   }
 
   base::Value::List address_lines;
@@ -110,7 +111,7 @@
 
   if (include_non_location_data) {
     SetStringIfNotEmpty(profile, PHONE_HOME_WHOLE_NUMBER, app_locale,
-                        PaymentsClient::kPhoneNumber, address);
+                        PaymentsNetworkInterface::kPhoneNumber, address);
   }
 
   return address;
diff --git a/components/autofill/core/browser/payments/payments_requests/select_challenge_option_request.cc b/components/autofill/core/browser/payments/payments_requests/select_challenge_option_request.cc
index cc2d02c..c7c8762 100644
--- a/components/autofill/core/browser/payments/payments_requests/select_challenge_option_request.cc
+++ b/components/autofill/core/browser/payments/payments_requests/select_challenge_option_request.cc
@@ -8,7 +8,7 @@
 #include "base/json/json_writer.h"
 #include "base/values.h"
 #include "components/autofill/core/browser/autofill_client.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 
 namespace autofill {
 namespace payments {
@@ -19,7 +19,8 @@
 }  // namespace
 
 SelectChallengeOptionRequest::SelectChallengeOptionRequest(
-    PaymentsClient::SelectChallengeOptionRequestDetails request_details,
+    PaymentsNetworkInterface::SelectChallengeOptionRequestDetails
+        request_details,
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                             const std::string&)> callback)
     : request_details_(request_details), callback_(std::move(callback)) {}
diff --git a/components/autofill/core/browser/payments/payments_requests/select_challenge_option_request.h b/components/autofill/core/browser/payments/payments_requests/select_challenge_option_request.h
index 9bf8d39..a3ef756 100644
--- a/components/autofill/core/browser/payments/payments_requests/select_challenge_option_request.h
+++ b/components/autofill/core/browser/payments/payments_requests/select_challenge_option_request.h
@@ -5,7 +5,7 @@
 #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_REQUESTS_SELECT_CHALLENGE_OPTION_REQUEST_H_
 #define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_REQUESTS_SELECT_CHALLENGE_OPTION_REQUEST_H_
 
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/payments_requests/payments_request.h"
 
 namespace autofill {
@@ -14,7 +14,8 @@
 class SelectChallengeOptionRequest : public PaymentsRequest {
  public:
   SelectChallengeOptionRequest(
-      PaymentsClient::SelectChallengeOptionRequestDetails request_details,
+      PaymentsNetworkInterface::SelectChallengeOptionRequestDetails
+          request_details,
       base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                               const std::string&)> callback);
   ~SelectChallengeOptionRequest() override;
@@ -31,7 +32,8 @@
   void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override;
 
  private:
-  PaymentsClient::SelectChallengeOptionRequestDetails request_details_;
+  PaymentsNetworkInterface::SelectChallengeOptionRequestDetails
+      request_details_;
   base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                           const std::string&)>
       callback_;
diff --git a/components/autofill/core/browser/payments/payments_requests/unmask_card_request.cc b/components/autofill/core/browser/payments/payments_requests/unmask_card_request.cc
index 7b8b8daa..a546742 100644
--- a/components/autofill/core/browser/payments/payments_requests/unmask_card_request.cc
+++ b/components/autofill/core/browser/payments/payments_requests/unmask_card_request.cc
@@ -175,10 +175,11 @@
 }  // namespace
 
 UnmaskCardRequest::UnmaskCardRequest(
-    const PaymentsClient::UnmaskRequestDetails& request_details,
+    const PaymentsNetworkInterface::UnmaskRequestDetails& request_details,
     const bool full_sync_enabled,
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                            PaymentsClient::UnmaskResponseDetails&)> callback)
+                            PaymentsNetworkInterface::UnmaskResponseDetails&)>
+        callback)
     : request_details_(request_details),
       full_sync_enabled_(full_sync_enabled),
       callback_(std::move(callback)) {
diff --git a/components/autofill/core/browser/payments/payments_requests/unmask_card_request.h b/components/autofill/core/browser/payments/payments_requests/unmask_card_request.h
index 032a6ad..1374d8a 100644
--- a/components/autofill/core/browser/payments/payments_requests/unmask_card_request.h
+++ b/components/autofill/core/browser/payments/payments_requests/unmask_card_request.h
@@ -5,7 +5,7 @@
 #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_REQUESTS_UNMASK_CARD_REQUEST_H_
 #define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_REQUESTS_UNMASK_CARD_REQUEST_H_
 
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/payments_requests/payments_request.h"
 
 namespace autofill {
@@ -14,16 +14,17 @@
 class UnmaskCardRequest : public PaymentsRequest {
  public:
   UnmaskCardRequest(
-      const PaymentsClient::UnmaskRequestDetails& request_details,
+      const PaymentsNetworkInterface::UnmaskRequestDetails& request_details,
       const bool full_sync_enabled,
       base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                              PaymentsClient::UnmaskResponseDetails&)>
+                              PaymentsNetworkInterface::UnmaskResponseDetails&)>
           callback);
   UnmaskCardRequest(const UnmaskCardRequest&) = delete;
   UnmaskCardRequest& operator=(const UnmaskCardRequest&) = delete;
   ~UnmaskCardRequest() override;
 
-  const PaymentsClient::UnmaskResponseDetails& GetResponseDetailsForTesting() {
+  const PaymentsNetworkInterface::UnmaskResponseDetails&
+  GetResponseDetailsForTesting() {
     return response_details_;
   }
 
@@ -45,12 +46,12 @@
   // perform an authentication for a virtual card.
   bool CanPerformVirtualCardAuth();
 
-  PaymentsClient::UnmaskRequestDetails request_details_;
+  PaymentsNetworkInterface::UnmaskRequestDetails request_details_;
   const bool full_sync_enabled_;
   base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                          PaymentsClient::UnmaskResponseDetails&)>
+                          PaymentsNetworkInterface::UnmaskResponseDetails&)>
       callback_;
-  PaymentsClient::UnmaskResponseDetails response_details_;
+  PaymentsNetworkInterface::UnmaskResponseDetails response_details_;
 };
 
 }  // namespace payments
diff --git a/components/autofill/core/browser/payments/payments_requests/unmask_card_request_unittest.cc b/components/autofill/core/browser/payments/payments_requests/unmask_card_request_unittest.cc
index f34c07c..ce408fd 100644
--- a/components/autofill/core/browser/payments/payments_requests/unmask_card_request_unittest.cc
+++ b/components/autofill/core/browser/payments/payments_requests/unmask_card_request_unittest.cc
@@ -20,7 +20,8 @@
 
 // TODO(crbug/1372613): Extend tests in this file to all of the possible card
 // unmasking test cases. The cases that are not in this file are currently
-// tested in Payments Client tests, but they should be tested here as well.
+// tested in PaymentsNetworkInterface tests, but they should be tested here as
+// well.
 class UnmaskCardRequestTest : public testing::Test {
  public:
   UnmaskCardRequestTest() { SetUpUnmaskCardRequest(); }
@@ -55,7 +56,8 @@
 
   // Returns the response details that was created for the current test
   // instance.
-  const PaymentsClient::UnmaskResponseDetails& GetParsedResponse() const {
+  const PaymentsNetworkInterface::UnmaskResponseDetails& GetParsedResponse()
+      const {
     return request_->GetResponseDetailsForTesting();
   }
 
@@ -65,8 +67,9 @@
   // initial test set up.
   std::unique_ptr<UnmaskCardRequest> request_;
 
-  PaymentsClient::UnmaskRequestDetails GetDefaultUnmaskRequestDetails() {
-    PaymentsClient::UnmaskRequestDetails request_details;
+  PaymentsNetworkInterface::UnmaskRequestDetails
+  GetDefaultUnmaskRequestDetails() {
+    PaymentsNetworkInterface::UnmaskRequestDetails request_details;
     request_details.billing_customer_number = 111222333444;
     request_details.card = test::GetMaskedServerCard();
     request_details.card.set_server_id("test server id");
@@ -128,7 +131,7 @@
 TEST_F(UnmaskCardRequestTest, DoesNotIncludeMerchantDomainWhenMissingField) {
   feature_list_.InitAndEnableFeature(
       features::kAutofillEnableMerchantDomainInUnmaskCardRequest);
-  PaymentsClient::UnmaskRequestDetails request_details =
+  PaymentsNetworkInterface::UnmaskRequestDetails request_details =
       GetDefaultUnmaskRequestDetails();
   request_details.merchant_domain_for_footprints = absl::nullopt;
   request_ = std::make_unique<UnmaskCardRequest>(
@@ -146,7 +149,7 @@
   ASSERT_TRUE(response.has_value());
   GetRequest()->ParseResponse(response->GetDict());
 
-  const PaymentsClient::UnmaskResponseDetails& response_details =
+  const PaymentsNetworkInterface::UnmaskResponseDetails& response_details =
       GetParsedResponse();
   EXPECT_EQ("fake_context_token", response_details.context_token);
   // Verify the FIDO request challenge is correctly parsed.
@@ -214,7 +217,7 @@
   // Sets up `request_` specifically for the Virtual Card CVC Unmask Card
   // Request test case.
   void SetUpVirtualCardCvcUnmaskCardRequestTest() {
-    PaymentsClient::UnmaskRequestDetails request_details;
+    PaymentsNetworkInterface::UnmaskRequestDetails request_details;
     request_details.billing_customer_number = 111222333444;
     request_details.card = test::GetVirtualCard();
     request_details.card.set_server_id("test server id");
@@ -299,7 +302,7 @@
   ASSERT_TRUE(response.has_value());
   GetRequest()->ParseResponse(response->GetDict());
 
-  const PaymentsClient::UnmaskResponseDetails& response_details =
+  const PaymentsNetworkInterface::UnmaskResponseDetails& response_details =
       GetParsedResponse();
   EXPECT_EQ("fake_context_token", response_details.context_token);
   // Verify the FIDO request challenge is correctly parsed.
diff --git a/components/autofill/core/browser/payments/payments_requests/unmask_iban_request.cc b/components/autofill/core/browser/payments/payments_requests/unmask_iban_request.cc
index 8ffb9e3..d7846ac 100644
--- a/components/autofill/core/browser/payments/payments_requests/unmask_iban_request.cc
+++ b/components/autofill/core/browser/payments/payments_requests/unmask_iban_request.cc
@@ -19,7 +19,7 @@
 }  // namespace
 
 UnmaskIbanRequest::UnmaskIbanRequest(
-    const PaymentsClient::UnmaskIbanRequestDetails& request_details,
+    const PaymentsNetworkInterface::UnmaskIbanRequestDetails& request_details,
     bool full_sync_enabled,
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                             const std::u16string&)> callback)
diff --git a/components/autofill/core/browser/payments/payments_requests/unmask_iban_request.h b/components/autofill/core/browser/payments/payments_requests/unmask_iban_request.h
index d67ccbc..9028c964 100644
--- a/components/autofill/core/browser/payments/payments_requests/unmask_iban_request.h
+++ b/components/autofill/core/browser/payments/payments_requests/unmask_iban_request.h
@@ -10,7 +10,7 @@
 #include "base/functional/callback.h"
 #include "base/values.h"
 #include "components/autofill/core/browser/autofill_client.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/payments_requests/payments_request.h"
 
 namespace autofill::payments {
@@ -18,7 +18,7 @@
 class UnmaskIbanRequest : public PaymentsRequest {
  public:
   UnmaskIbanRequest(
-      const PaymentsClient::UnmaskIbanRequestDetails& request_details,
+      const PaymentsNetworkInterface::UnmaskIbanRequestDetails& request_details,
       bool full_sync_enabled,
       base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                               const std::u16string&)> callback);
@@ -37,7 +37,7 @@
   const std::u16string& value_for_testing() const { return value_; }
 
  private:
-  const PaymentsClient::UnmaskIbanRequestDetails request_details_;
+  const PaymentsNetworkInterface::UnmaskIbanRequestDetails request_details_;
   const bool full_sync_enabled_;
   std::u16string value_;
   base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
diff --git a/components/autofill/core/browser/payments/payments_requests/unmask_iban_request_unittest.cc b/components/autofill/core/browser/payments/payments_requests/unmask_iban_request_unittest.cc
index 5de17e59..fbc1de5 100644
--- a/components/autofill/core/browser/payments/payments_requests/unmask_iban_request_unittest.cc
+++ b/components/autofill/core/browser/payments/payments_requests/unmask_iban_request_unittest.cc
@@ -21,7 +21,7 @@
 class UnmaskIbanRequestTest : public testing::Test {
  public:
   void SetUp() override {
-    PaymentsClient::UnmaskIbanRequestDetails request_details;
+    PaymentsNetworkInterface::UnmaskIbanRequestDetails request_details;
     request_details.billable_service_number = kBillableServiceNumber;
     request_details.billing_customer_number = kBillingCustomerNumber;
     request_details.instrument_id = kInstrumentId;
diff --git a/components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.cc b/components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.cc
index 79d6d2f..a5306b8 100644
--- a/components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.cc
+++ b/components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.cc
@@ -20,7 +20,7 @@
 }  // namespace
 
 UpdateVirtualCardEnrollmentRequest::UpdateVirtualCardEnrollmentRequest(
-    const PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails&
+    const PaymentsNetworkInterface::UpdateVirtualCardEnrollmentRequestDetails&
         request_details,
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult)> callback)
     : request_details_(request_details), callback_(std::move(callback)) {}
@@ -63,7 +63,8 @@
 void UpdateVirtualCardEnrollmentRequest::ParseResponse(
     const base::Value::Dict& response) {
   // Only enroll requests have a response to parse, unenroll request responses
-  // are empty except for possible errors which are parsed in PaymentsClient.
+  // are empty except for possible errors which are parsed in
+  // PaymentsNetworkInterface.
   if (request_details_.virtual_card_enrollment_request_type ==
       VirtualCardEnrollmentRequestType::kEnroll) {
     auto* enroll_result = response.FindString("enroll_result");
@@ -82,10 +83,10 @@
       return enroll_result_.has_value() && enroll_result_ == "ENROLL_SUCCESS";
     case VirtualCardEnrollmentRequestType::kUnenroll:
       // Unenroll responses are empty except for having an error. In
-      // PaymentsClient, if the response has an error it will be handled before
-      // we check IsResponseComplete(), so if we ever reach this branch we know
-      // the response completed successfully as there is no error. Thus, we
-      // always return true.
+      // PaymentsNetworkInterface, if the response has an error it will be
+      // handled before we check IsResponseComplete(), so if we ever reach this
+      // branch we know the response completed successfully as there is no
+      // error. Thus, we always return true.
       return true;
     case VirtualCardEnrollmentRequestType::kNone:
       NOTREACHED();
diff --git a/components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.h b/components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.h
index fe8611e..1e0a219 100644
--- a/components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.h
+++ b/components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.h
@@ -9,7 +9,7 @@
 
 #include "base/functional/callback.h"
 #include "components/autofill/core/browser/autofill_client.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/payments_requests/payments_request.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -27,7 +27,7 @@
 class UpdateVirtualCardEnrollmentRequest : public PaymentsRequest {
  public:
   UpdateVirtualCardEnrollmentRequest(
-      const PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails&
+      const PaymentsNetworkInterface::UpdateVirtualCardEnrollmentRequestDetails&
           request_details,
       base::OnceCallback<void(AutofillClient::PaymentsRpcResult)> callback);
   UpdateVirtualCardEnrollmentRequest(
@@ -55,7 +55,8 @@
   // the fields needed for an Unenroll request.
   void BuildUnenrollRequestDictionary(base::Value::Dict* request_dict);
 
-  PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails request_details_;
+  PaymentsNetworkInterface::UpdateVirtualCardEnrollmentRequestDetails
+      request_details_;
   base::OnceCallback<void(AutofillClient::PaymentsRpcResult)> callback_;
   absl::optional<std::string> enroll_result_;
 };
diff --git a/components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request_unittest.cc b/components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request_unittest.cc
index b54b71d..881db2d 100644
--- a/components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request_unittest.cc
+++ b/components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request_unittest.cc
@@ -28,7 +28,8 @@
   ~UpdateVirtualCardEnrollmentRequestTest() override = default;
 
   void SetUp() override {
-    PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails request_details;
+    PaymentsNetworkInterface::UpdateVirtualCardEnrollmentRequestDetails
+        request_details;
     request_details.virtual_card_enrollment_request_type =
         std::get<0>(GetParam());
     request_details.virtual_card_enrollment_source = std::get<1>(GetParam());
diff --git a/components/autofill/core/browser/payments/payments_requests/upload_card_request.cc b/components/autofill/core/browser/payments/payments_requests/upload_card_request.cc
index abe979b..fc5d412fd7 100644
--- a/components/autofill/core/browser/payments/payments_requests/upload_card_request.cc
+++ b/components/autofill/core/browser/payments/payments_requests/upload_card_request.cc
@@ -27,11 +27,11 @@
 }  // namespace
 
 UploadCardRequest::UploadCardRequest(
-    const PaymentsClient::UploadRequestDetails& request_details,
+    const PaymentsNetworkInterface::UploadRequestDetails& request_details,
     const bool full_sync_enabled,
-    base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                            const PaymentsClient::UploadCardResponseDetails&)>
-        callback)
+    base::OnceCallback<void(
+        AutofillClient::PaymentsRpcResult,
+        const PaymentsNetworkInterface::UploadCardResponseDetails&)> callback)
     : request_details_(request_details),
       full_sync_enabled_(full_sync_enabled),
       callback_(std::move(callback)) {}
@@ -155,7 +155,7 @@
       const auto* virtual_card_enrollment_data =
           virtual_card_metadata->FindDict("virtual_card_enrollment_data");
       if (virtual_card_enrollment_data) {
-        PaymentsClient::GetDetailsForEnrollmentResponseDetails
+        PaymentsNetworkInterface::GetDetailsForEnrollmentResponseDetails
             get_details_for_enrollment_response_details;
         const base::Value::Dict* google_legal_message =
             virtual_card_enrollment_data->FindDict("google_legal_message");
diff --git a/components/autofill/core/browser/payments/payments_requests/upload_card_request.h b/components/autofill/core/browser/payments/payments_requests/upload_card_request.h
index 1df99b47..5eebc86 100644
--- a/components/autofill/core/browser/payments/payments_requests/upload_card_request.h
+++ b/components/autofill/core/browser/payments/payments_requests/upload_card_request.h
@@ -9,7 +9,7 @@
 
 #include "base/functional/callback.h"
 #include "components/autofill/core/browser/autofill_client.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/payments_requests/payments_request.h"
 
 namespace base {
@@ -21,10 +21,11 @@
 class UploadCardRequest : public PaymentsRequest {
  public:
   UploadCardRequest(
-      const PaymentsClient::UploadRequestDetails& request_details,
+      const PaymentsNetworkInterface::UploadRequestDetails& request_details,
       const bool full_sync_enabled,
-      base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                              const PaymentsClient::UploadCardResponseDetails&)>
+      base::OnceCallback<
+          void(AutofillClient::PaymentsRpcResult,
+               const PaymentsNetworkInterface::UploadCardResponseDetails&)>
           callback);
   UploadCardRequest(const UploadCardRequest&) = delete;
   UploadCardRequest& operator=(const UploadCardRequest&) = delete;
@@ -39,12 +40,14 @@
   void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override;
 
  private:
-  const PaymentsClient::UploadRequestDetails request_details_;
+  const PaymentsNetworkInterface::UploadRequestDetails request_details_;
   const bool full_sync_enabled_;
-  base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                          const PaymentsClient::UploadCardResponseDetails&)>
+  base::OnceCallback<void(
+      AutofillClient::PaymentsRpcResult,
+      const PaymentsNetworkInterface::UploadCardResponseDetails&)>
       callback_;
-  PaymentsClient::UploadCardResponseDetails upload_card_response_details_;
+  PaymentsNetworkInterface::UploadCardResponseDetails
+      upload_card_response_details_;
 };
 
 }  // namespace autofill::payments
diff --git a/components/autofill/core/browser/payments/payments_requests/upload_iban_request.cc b/components/autofill/core/browser/payments/payments_requests/upload_iban_request.cc
index ba598ec..0980f5a 100644
--- a/components/autofill/core/browser/payments/payments_requests/upload_iban_request.cc
+++ b/components/autofill/core/browser/payments/payments_requests/upload_iban_request.cc
@@ -21,7 +21,7 @@
 }  // namespace
 
 UploadIbanRequest::UploadIbanRequest(
-    const PaymentsClient::UploadIbanRequestDetails& details,
+    const PaymentsNetworkInterface::UploadIbanRequestDetails& details,
     bool full_sync_enabled,
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult)> callback)
     : request_details_(details),
diff --git a/components/autofill/core/browser/payments/payments_requests/upload_iban_request.h b/components/autofill/core/browser/payments/payments_requests/upload_iban_request.h
index e375779..7fe3feb 100644
--- a/components/autofill/core/browser/payments/payments_requests/upload_iban_request.h
+++ b/components/autofill/core/browser/payments/payments_requests/upload_iban_request.h
@@ -11,7 +11,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "components/autofill/core/browser/autofill_client.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/payments_requests/payments_request.h"
 
 namespace autofill::payments {
@@ -19,7 +19,7 @@
 class UploadIbanRequest : public PaymentsRequest {
  public:
   UploadIbanRequest(
-      const PaymentsClient::UploadIbanRequestDetails& details,
+      const PaymentsNetworkInterface::UploadIbanRequestDetails& details,
       bool full_sync_enabled,
       base::OnceCallback<void(AutofillClient::PaymentsRpcResult)> callback);
   UploadIbanRequest(const UploadIbanRequest&) = delete;
@@ -35,7 +35,7 @@
   void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override;
 
  private:
-  const PaymentsClient::UploadIbanRequestDetails request_details_;
+  const PaymentsNetworkInterface::UploadIbanRequestDetails request_details_;
   // True when the user is both signed-in and has enabled sync.
   const bool full_sync_enabled_;
   base::OnceCallback<void(AutofillClient::PaymentsRpcResult)> callback_;
diff --git a/components/autofill/core/browser/payments/payments_requests/upload_iban_request_unittest.cc b/components/autofill/core/browser/payments/payments_requests/upload_iban_request_unittest.cc
index 6cce9b6..97c34eab 100644
--- a/components/autofill/core/browser/payments/payments_requests/upload_iban_request_unittest.cc
+++ b/components/autofill/core/browser/payments/payments_requests/upload_iban_request_unittest.cc
@@ -24,7 +24,7 @@
 class UploadIbanRequestTest : public testing::Test {
  public:
   void SetUp() override {
-    PaymentsClient::UploadIbanRequestDetails request_details;
+    PaymentsNetworkInterface::UploadIbanRequestDetails request_details;
     request_details.app_locale = kAppLocale;
     request_details.billable_service_number = kBillableServiceNumber;
     request_details.billing_customer_number = kBillingCustomerNumber;
diff --git a/components/autofill/core/browser/payments/test_authentication_requester.cc b/components/autofill/core/browser/payments/test_authentication_requester.cc
index 0b5a26f..fe21b36 100644
--- a/components/autofill/core/browser/payments/test_authentication_requester.cc
+++ b/components/autofill/core/browser/payments/test_authentication_requester.cc
@@ -82,7 +82,8 @@
 void TestAuthenticationRequester::
     OnVirtualCardRiskBasedAuthenticationResponseReceived(
         AutofillClient::PaymentsRpcResult result,
-        payments::PaymentsClient::UnmaskResponseDetails& response_details) {
+        payments::PaymentsNetworkInterface::UnmaskResponseDetails&
+            response_details) {
   did_succeed_ = (result == AutofillClient::PaymentsRpcResult::kSuccess);
   if (*did_succeed_) {
     response_details_ = response_details;
diff --git a/components/autofill/core/browser/payments/test_authentication_requester.h b/components/autofill/core/browser/payments/test_authentication_requester.h
index eb3ef230..a7d7f65e 100644
--- a/components/autofill/core/browser/payments/test_authentication_requester.h
+++ b/components/autofill/core/browser/payments/test_authentication_requester.h
@@ -67,8 +67,8 @@
           response) override;
   void OnVirtualCardRiskBasedAuthenticationResponseReceived(
       AutofillClient::PaymentsRpcResult result,
-      payments::PaymentsClient::UnmaskResponseDetails& response_details)
-      override;
+      payments::PaymentsNetworkInterface::UnmaskResponseDetails&
+          response_details) override;
 
   base::WeakPtr<TestAuthenticationRequester> GetWeakPtr();
 
@@ -78,7 +78,8 @@
 
   std::u16string number() { return number_; }
 
-  payments::PaymentsClient::UnmaskResponseDetails response_details() const {
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response_details()
+      const {
     return response_details_;
   }
 
@@ -107,7 +108,7 @@
   std::u16string number_;
 
   // Unmask response returned from UnmaskCard request.
-  payments::PaymentsClient::UnmaskResponseDetails response_details_;
+  payments::PaymentsNetworkInterface::UnmaskResponseDetails response_details_;
 
   // Authentication response returned from CreditCardRiskBasedAuthenticator.
   CreditCardRiskBasedAuthenticator::RiskBasedAuthenticationResponse
diff --git a/components/autofill/core/browser/payments/test_credit_card_fido_authenticator.h b/components/autofill/core/browser/payments/test_credit_card_fido_authenticator.h
index 3b91ba4..3190d869 100644
--- a/components/autofill/core/browser/payments/test_credit_card_fido_authenticator.h
+++ b/components/autofill/core/browser/payments/test_credit_card_fido_authenticator.h
@@ -13,7 +13,6 @@
 #include "components/autofill/core/browser/autofill_driver.h"
 #include "components/autofill/core/browser/data_model/credit_card.h"
 #include "components/autofill/core/browser/payments/credit_card_fido_authenticator.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace autofill {
diff --git a/components/autofill/core/browser/payments/test_credit_card_save_manager.cc b/components/autofill/core/browser/payments/test_credit_card_save_manager.cc
index 65f74e6..b942c3b 100644
--- a/components/autofill/core/browser/payments/test_credit_card_save_manager.cc
+++ b/components/autofill/core/browser/payments/test_credit_card_save_manager.cc
@@ -4,17 +4,17 @@
 
 #include "components/autofill/core/browser/payments/test_credit_card_save_manager.h"
 
-#include "components/autofill/core/browser/payments/test_payments_client.h"
+#include "components/autofill/core/browser/payments/test_payments_network_interface.h"
 
 namespace autofill {
 
 TestCreditCardSaveManager::TestCreditCardSaveManager(
     AutofillDriver* driver,
     AutofillClient* client,
-    payments::TestPaymentsClient* payments_client,
+    payments::TestPaymentsNetworkInterface* payments_network_interface,
     PersonalDataManager* personal_data_manager)
     : CreditCardSaveManager(client,
-                            payments_client,
+                            payments_network_interface,
                             "en-US",
                             personal_data_manager) {}
 
@@ -77,14 +77,14 @@
   upload_request_.card = std::move(card);
 }
 
-payments::PaymentsClient::UploadRequestDetails*
+payments::PaymentsNetworkInterface::UploadRequestDetails*
 TestCreditCardSaveManager::upload_request() {
   return &upload_request_;
 }
 
 void TestCreditCardSaveManager::OnDidUploadCard(
     AutofillClient::PaymentsRpcResult result,
-    const payments::PaymentsClient::UploadCardResponseDetails&
+    const payments::PaymentsNetworkInterface::UploadCardResponseDetails&
         upload_card_response_details) {
   credit_card_was_uploaded_ = true;
   CreditCardSaveManager::OnDidUploadCard(result, upload_card_response_details);
diff --git a/components/autofill/core/browser/payments/test_credit_card_save_manager.h b/components/autofill/core/browser/payments/test_credit_card_save_manager.h
index bd2da99..4894c6a 100644
--- a/components/autofill/core/browser/payments/test_credit_card_save_manager.h
+++ b/components/autofill/core/browser/payments/test_credit_card_save_manager.h
@@ -13,7 +13,7 @@
 namespace autofill {
 
 namespace payments {
-class TestPaymentsClient;
+class TestPaymentsNetworkInterface;
 }  // namespace payments
 
 class AutofillClient;
@@ -22,10 +22,11 @@
 
 class TestCreditCardSaveManager : public CreditCardSaveManager {
  public:
-  TestCreditCardSaveManager(AutofillDriver* driver,
-                            AutofillClient* client,
-                            payments::TestPaymentsClient* payments_client,
-                            PersonalDataManager* personal_data_manager);
+  TestCreditCardSaveManager(
+      AutofillDriver* driver,
+      AutofillClient* client,
+      payments::TestPaymentsNetworkInterface* payments_network_interface,
+      PersonalDataManager* personal_data_manager);
 
   TestCreditCardSaveManager(const TestCreditCardSaveManager&) = delete;
   TestCreditCardSaveManager& operator=(const TestCreditCardSaveManager&) =
@@ -58,12 +59,12 @@
 
   void set_upload_request_card(const CreditCard& card);
 
-  payments::PaymentsClient::UploadRequestDetails* upload_request();
+  payments::PaymentsNetworkInterface::UploadRequestDetails* upload_request();
 
  private:
   void OnDidUploadCard(
       AutofillClient::PaymentsRpcResult result,
-      const payments::PaymentsClient::UploadCardResponseDetails&
+      const payments::PaymentsNetworkInterface::UploadCardResponseDetails&
           upload_card_response_details) override;
 
   bool credit_card_upload_enabled_ = false;
diff --git a/components/autofill/core/browser/payments/test_local_card_migration_manager.cc b/components/autofill/core/browser/payments/test_local_card_migration_manager.cc
index 7676c613..c9e3cc3 100644
--- a/components/autofill/core/browser/payments/test_local_card_migration_manager.cc
+++ b/components/autofill/core/browser/payments/test_local_card_migration_manager.cc
@@ -6,7 +6,7 @@
 
 #include "components/autofill/core/browser/metrics/autofill_metrics.h"
 #include "components/autofill/core/browser/payments/payments_util.h"
-#include "components/autofill/core/browser/payments/test_payments_client.h"
+#include "components/autofill/core/browser/payments/test_payments_network_interface.h"
 #include "components/autofill/core/common/autofill_payments_features.h"
 
 namespace autofill {
@@ -14,10 +14,10 @@
 TestLocalCardMigrationManager::TestLocalCardMigrationManager(
     AutofillDriver* driver,
     AutofillClient* client,
-    payments::TestPaymentsClient* payments_client,
+    payments::TestPaymentsNetworkInterface* payments_network_interface,
     TestPersonalDataManager* personal_data_manager)
     : LocalCardMigrationManager(client,
-                                payments_client,
+                                payments_network_interface,
                                 "en-US",
                                 personal_data_manager),
       personal_data_manager_(personal_data_manager) {}
diff --git a/components/autofill/core/browser/payments/test_local_card_migration_manager.h b/components/autofill/core/browser/payments/test_local_card_migration_manager.h
index b440626c..86c5404 100644
--- a/components/autofill/core/browser/payments/test_local_card_migration_manager.h
+++ b/components/autofill/core/browser/payments/test_local_card_migration_manager.h
@@ -17,7 +17,7 @@
 namespace autofill {
 
 namespace payments {
-class TestPaymentsClient;
+class TestPaymentsNetworkInterface;
 }  // namespace payments
 
 class AutofillClient;
@@ -25,10 +25,11 @@
 
 class TestLocalCardMigrationManager : public LocalCardMigrationManager {
  public:
-  TestLocalCardMigrationManager(AutofillDriver* driver,
-                                AutofillClient* client,
-                                payments::TestPaymentsClient* payments_client,
-                                TestPersonalDataManager* personal_data_manager);
+  TestLocalCardMigrationManager(
+      AutofillDriver* driver,
+      AutofillClient* client,
+      payments::TestPaymentsNetworkInterface* payments_network_interface,
+      TestPersonalDataManager* personal_data_manager);
 
   TestLocalCardMigrationManager(const TestLocalCardMigrationManager&) = delete;
   TestLocalCardMigrationManager& operator=(
diff --git a/components/autofill/core/browser/payments/test_payments_client.cc b/components/autofill/core/browser/payments/test_payments_network_interface.cc
similarity index 82%
rename from components/autofill/core/browser/payments/test_payments_client.cc
rename to components/autofill/core/browser/payments/test_payments_network_interface.cc
index e4977af..a0a6535 100644
--- a/components/autofill/core/browser/payments/test_payments_client.cc
+++ b/components/autofill/core/browser/payments/test_payments_network_interface.cc
@@ -1,8 +1,8 @@
-// Copyright 2017 The Chromium Authors
+// Copyright 2023 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/autofill/core/browser/payments/test_payments_client.h"
+#include "components/autofill/core/browser/payments/test_payments_network_interface.h"
 
 #include <memory>
 #include <unordered_map>
@@ -25,36 +25,36 @@
 constexpr int kTestTimeoutSeconds = 180;
 }  // namespace
 
-TestPaymentsClient::TestPaymentsClient(
+TestPaymentsNetworkInterface::TestPaymentsNetworkInterface(
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_,
     signin::IdentityManager* identity_manager,
     PersonalDataManager* personal_data_manager)
-    : PaymentsClient(url_loader_factory_,
+    : PaymentsNetworkInterface(url_loader_factory_,
                      identity_manager,
                      personal_data_manager) {
   // Default value should be CVC.
   unmask_details_.unmask_auth_method = AutofillClient::UnmaskAuthMethod::kCvc;
 }
 
-TestPaymentsClient::~TestPaymentsClient() = default;
+TestPaymentsNetworkInterface::~TestPaymentsNetworkInterface() = default;
 
-void TestPaymentsClient::GetUnmaskDetails(
+void TestPaymentsNetworkInterface::GetUnmaskDetails(
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                            PaymentsClient::UnmaskDetails&)> callback,
+                            PaymentsNetworkInterface::UnmaskDetails&)> callback,
     const std::string& app_locale) {
   if (should_return_unmask_details_)
     std::move(callback).Run(AutofillClient::PaymentsRpcResult::kSuccess,
                             unmask_details_);
 }
 
-void TestPaymentsClient::UnmaskCard(
+void TestPaymentsNetworkInterface::UnmaskCard(
     const UnmaskRequestDetails& unmask_request,
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                             UnmaskResponseDetails&)> callback) {
   unmask_request_ = unmask_request;
 }
 
-void TestPaymentsClient::GetUploadDetails(
+void TestPaymentsNetworkInterface::GetUploadDetails(
     const std::vector<AutofillProfile>& addresses,
     const int detected_values,
     const std::vector<ClientBehaviorConstants>& client_behavior_signals,
@@ -65,7 +65,7 @@
                             std::vector<std::pair<int, int>>)> callback,
     const int billable_service_number,
     const int64_t billing_customer_number,
-    PaymentsClient::UploadCardSource upload_card_source) {
+    PaymentsNetworkInterface::UploadCardSource upload_card_source) {
   upload_details_addresses_ = addresses;
   detected_values_ = detected_values;
   client_behavior_signals_ = client_behavior_signals;
@@ -76,14 +76,14 @@
       app_locale == "en-US"
           ? AutofillClient::PaymentsRpcResult::kSuccess
           : AutofillClient::PaymentsRpcResult::kPermanentFailure,
-      u"this is a context token", TestPaymentsClient::LegalMessage(),
+      u"this is a context token", TestPaymentsNetworkInterface::LegalMessage(),
       supported_card_bin_ranges_);
 }
 
-void TestPaymentsClient::UploadCard(
-    const payments::PaymentsClient::UploadRequestDetails& request_details,
+void TestPaymentsNetworkInterface::UploadCard(
+    const payments::PaymentsNetworkInterface::UploadRequestDetails& request_details,
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                            const PaymentsClient::UploadCardResponseDetails&)>
+                            const PaymentsNetworkInterface::UploadCardResponseDetails&)>
         callback) {
   upload_card_addresses_ = request_details.profiles;
   client_behavior_signals_ = request_details.client_behavior_signals;
@@ -92,7 +92,7 @@
 }
 
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
-void TestPaymentsClient::MigrateCards(
+void TestPaymentsNetworkInterface::MigrateCards(
     const MigrationRequestDetails& details,
     const std::vector<MigratableCreditCard>& migratable_credit_cards,
     MigrateCardsCallback callback) {
@@ -101,7 +101,7 @@
 }
 #endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
 
-void TestPaymentsClient::SelectChallengeOption(
+void TestPaymentsNetworkInterface::SelectChallengeOption(
     const SelectChallengeOptionRequestDetails& details,
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                             const std::string&)> callback) {
@@ -117,17 +117,17 @@
                           "context_token from SelectChallengeOption");
 }
 
-void TestPaymentsClient::GetVirtualCardEnrollmentDetails(
+void TestPaymentsNetworkInterface::GetVirtualCardEnrollmentDetails(
     const GetDetailsForEnrollmentRequestDetails& request_details,
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                            const payments::PaymentsClient::
+                            const payments::PaymentsNetworkInterface::
                                 GetDetailsForEnrollmentResponseDetails&)>
         callback) {
   get_details_for_enrollment_request_details_ = std::move(request_details);
 }
 
-void TestPaymentsClient::UpdateVirtualCardEnrollment(
-    const TestPaymentsClient::UpdateVirtualCardEnrollmentRequestDetails&
+void TestPaymentsNetworkInterface::UpdateVirtualCardEnrollment(
+    const TestPaymentsNetworkInterface::UpdateVirtualCardEnrollmentRequestDetails&
         request_details,
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult)> callback) {
   update_virtual_card_enrollment_request_details_ = std::move(request_details);
@@ -135,17 +135,17 @@
       AutofillClient::PaymentsRpcResult::kSuccess));
 }
 
-void TestPaymentsClient::ShouldReturnUnmaskDetailsImmediately(
+void TestPaymentsNetworkInterface::ShouldReturnUnmaskDetailsImmediately(
     bool should_return_unmask_details) {
   should_return_unmask_details_ = should_return_unmask_details;
 }
 
-void TestPaymentsClient::AllowFidoRegistration(bool offer_fido_opt_in) {
+void TestPaymentsNetworkInterface::AllowFidoRegistration(bool offer_fido_opt_in) {
   should_return_unmask_details_ = true;
   unmask_details_.offer_fido_opt_in = offer_fido_opt_in;
 }
 
-void TestPaymentsClient::AddFidoEligibleCard(std::string server_id,
+void TestPaymentsNetworkInterface::AddFidoEligibleCard(std::string server_id,
                                              std::string credential_id,
                                              std::string relying_party_id) {
   should_return_unmask_details_ = true;
@@ -178,34 +178,34 @@
           .Set("key_info", base::Value::List().Append(std::move(key_info)));
 }
 
-void TestPaymentsClient::SetUploadCardResponseDetailsForUploadCard(
-    const PaymentsClient::UploadCardResponseDetails&
+void TestPaymentsNetworkInterface::SetUploadCardResponseDetailsForUploadCard(
+    const PaymentsNetworkInterface::UploadCardResponseDetails&
         upload_card_response_details) {
   upload_card_response_details_ = upload_card_response_details;
 }
 
-void TestPaymentsClient::SetSaveResultForCardsMigration(
+void TestPaymentsNetworkInterface::SetSaveResultForCardsMigration(
     std::unique_ptr<std::unordered_map<std::string, std::string>> save_result) {
   save_result_ = std::move(save_result);
 }
 
-void TestPaymentsClient::SetSupportedBINRanges(
+void TestPaymentsNetworkInterface::SetSupportedBINRanges(
     std::vector<std::pair<int, int>> bin_ranges) {
   supported_card_bin_ranges_ = bin_ranges;
 }
 
-void TestPaymentsClient::SetUseInvalidLegalMessageInGetUploadDetails(
+void TestPaymentsNetworkInterface::SetUseInvalidLegalMessageInGetUploadDetails(
     bool use_invalid_legal_message) {
   use_invalid_legal_message_ = use_invalid_legal_message;
 }
 
-void TestPaymentsClient::SetUseLegalMessageWithMultipleLinesInGetUploadDetails(
+void TestPaymentsNetworkInterface::SetUseLegalMessageWithMultipleLinesInGetUploadDetails(
     bool use_legal_message_with_multiple_lines) {
   use_legal_message_with_multiple_lines_ =
       use_legal_message_with_multiple_lines;
 }
 
-std::unique_ptr<base::Value::Dict> TestPaymentsClient::LegalMessage() {
+std::unique_ptr<base::Value::Dict> TestPaymentsNetworkInterface::LegalMessage() {
   absl::optional<base::Value> parsed_json;
   if (use_invalid_legal_message_) {
     // Legal message is invalid because it's missing the url.
diff --git a/components/autofill/core/browser/payments/test_payments_client.h b/components/autofill/core/browser/payments/test_payments_network_interface.h
similarity index 79%
rename from components/autofill/core/browser/payments/test_payments_client.h
rename to components/autofill/core/browser/payments/test_payments_network_interface.h
index c808a9a..377127d 100644
--- a/components/autofill/core/browser/payments/test_payments_client.h
+++ b/components/autofill/core/browser/payments/test_payments_network_interface.h
@@ -1,9 +1,9 @@
-// Copyright 2017 The Chromium Authors
+// Copyright 2023 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_PAYMENTS_CLIENT_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_PAYMENTS_CLIENT_H_
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_PAYMENTS_NETWORK_INTERFACE_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_PAYMENTS_NETWORK_INTERFACE_H_
 
 #include <memory>
 #include <set>
@@ -14,7 +14,7 @@
 
 #include "base/memory/raw_ptr.h"
 #include "build/build_config.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
@@ -24,21 +24,21 @@
 
 namespace autofill::payments {
 
-class TestPaymentsClient : public payments::PaymentsClient {
+class TestPaymentsNetworkInterface : public payments::PaymentsNetworkInterface {
  public:
-  TestPaymentsClient(
+  TestPaymentsNetworkInterface(
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_,
       signin::IdentityManager* identity_manager,
       PersonalDataManager* personal_data_manager);
 
-  TestPaymentsClient(const TestPaymentsClient&) = delete;
-  TestPaymentsClient& operator=(const TestPaymentsClient&) = delete;
+  TestPaymentsNetworkInterface(const TestPaymentsNetworkInterface&) = delete;
+  TestPaymentsNetworkInterface& operator=(const TestPaymentsNetworkInterface&) = delete;
 
-  ~TestPaymentsClient() override;
+  ~TestPaymentsNetworkInterface() override;
 
   void GetUnmaskDetails(
       base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                              PaymentsClient::UnmaskDetails&)> callback,
+                              PaymentsNetworkInterface::UnmaskDetails&)> callback,
       const std::string& app_locale) override;
 
   void UnmaskCard(
@@ -61,9 +61,9 @@
           UploadCardSource::UNKNOWN_UPLOAD_CARD_SOURCE) override;
 
   void UploadCard(
-      const payments::PaymentsClient::UploadRequestDetails& request_details,
+      const payments::PaymentsNetworkInterface::UploadRequestDetails& request_details,
       base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                              const PaymentsClient::UploadCardResponseDetails&)>
+                              const PaymentsNetworkInterface::UploadCardResponseDetails&)>
           callback) override;
 
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
@@ -81,7 +81,7 @@
   void GetVirtualCardEnrollmentDetails(
       const GetDetailsForEnrollmentRequestDetails& request_details,
       base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
-                              const payments::PaymentsClient::
+                              const payments::PaymentsNetworkInterface::
                                   GetDetailsForEnrollmentResponseDetails&)>
           callback) override;
 
@@ -101,7 +101,7 @@
                            std::string relying_party_id);
 
   void SetUploadCardResponseDetailsForUploadCard(
-      const PaymentsClient::UploadCardResponseDetails&
+      const PaymentsNetworkInterface::UploadCardResponseDetails&
           upload_card_response_details);
 
   void SetSaveResultForCardsMigration(
@@ -126,14 +126,14 @@
     update_virtual_card_enrollment_result_ = result;
   }
 
-  payments::PaymentsClient::UnmaskDetails* unmask_details() {
+  payments::PaymentsNetworkInterface::UnmaskDetails* unmask_details() {
     return &unmask_details_;
   }
-  const absl::optional<payments::PaymentsClient::UnmaskRequestDetails>&
+  const absl::optional<payments::PaymentsNetworkInterface::UnmaskRequestDetails>&
   unmask_request() const {
     return unmask_request_;
   }
-  const payments::PaymentsClient::SelectChallengeOptionRequestDetails*
+  const payments::PaymentsNetworkInterface::SelectChallengeOptionRequestDetails*
   select_challenge_option_request() {
     return &select_challenge_option_request_;
   }
@@ -154,7 +154,7 @@
   int64_t billing_customer_number_in_request() const {
     return billing_customer_number_;
   }
-  PaymentsClient::UploadCardSource upload_card_source_in_request() const {
+  PaymentsNetworkInterface::UploadCardSource upload_card_source_in_request() const {
     return upload_card_source_;
   }
 
@@ -169,14 +169,14 @@
   }
 
  private:
-  PaymentsClient::UploadCardResponseDetails upload_card_response_details_;
+  PaymentsNetworkInterface::UploadCardResponseDetails upload_card_response_details_;
   // Some metrics are affected by the latency of GetUnmaskDetails, so it is
   // useful to control whether or not GetUnmaskDetails() is responded to.
   bool should_return_unmask_details_ = true;
-  payments::PaymentsClient::UnmaskDetails unmask_details_;
-  absl::optional<payments::PaymentsClient::UnmaskRequestDetails>
+  payments::PaymentsNetworkInterface::UnmaskDetails unmask_details_;
+  absl::optional<payments::PaymentsNetworkInterface::UnmaskRequestDetails>
       unmask_request_;
-  payments::PaymentsClient::SelectChallengeOptionRequestDetails
+  payments::PaymentsNetworkInterface::SelectChallengeOptionRequestDetails
       select_challenge_option_request_;
   std::vector<std::pair<int, int>> supported_card_bin_ranges_;
   std::vector<AutofillProfile> upload_details_addresses_;
@@ -186,7 +186,7 @@
   std::vector<ClientBehaviorConstants> client_behavior_signals_;
   int billable_service_number_;
   int64_t billing_customer_number_;
-  PaymentsClient::UploadCardSource upload_card_source_;
+  PaymentsNetworkInterface::UploadCardSource upload_card_source_;
   std::unique_ptr<std::unordered_map<std::string, std::string>> save_result_;
   bool use_invalid_legal_message_ = false;
   bool use_legal_message_with_multiple_lines_ = false;
@@ -195,12 +195,12 @@
       select_challenge_option_result_;
   absl::optional<AutofillClient::PaymentsRpcResult>
       update_virtual_card_enrollment_result_;
-  payments::PaymentsClient::GetDetailsForEnrollmentRequestDetails
+  payments::PaymentsNetworkInterface::GetDetailsForEnrollmentRequestDetails
       get_details_for_enrollment_request_details_;
-  payments::PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails
+  payments::PaymentsNetworkInterface::UpdateVirtualCardEnrollmentRequestDetails
       update_virtual_card_enrollment_request_details_;
 };
 
 }  // namespace autofill::payments
 
-#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_PAYMENTS_CLIENT_H_
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_PAYMENTS_NETWORK_INTERFACE_H_
diff --git a/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.cc b/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.cc
index f58e04af..c30cc59 100644
--- a/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.cc
+++ b/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.cc
@@ -10,10 +10,10 @@
 
 TestVirtualCardEnrollmentManager::TestVirtualCardEnrollmentManager(
     TestPersonalDataManager* personal_data_manager,
-    payments::TestPaymentsClient* payments_client,
+    payments::TestPaymentsNetworkInterface* payments_network_interface,
     TestAutofillClient* autofill_client = nullptr)
     : VirtualCardEnrollmentManager(personal_data_manager,
-                                   payments_client,
+                                   payments_network_interface,
                                    autofill_client) {}
 
 TestVirtualCardEnrollmentManager::~TestVirtualCardEnrollmentManager() = default;
diff --git a/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h b/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h
index 68b8041d..0536e64 100644
--- a/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h
+++ b/components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h
@@ -16,7 +16,7 @@
  public:
   TestVirtualCardEnrollmentManager(
       TestPersonalDataManager* personal_data_manager,
-      payments::TestPaymentsClient* payments_client,
+      payments::TestPaymentsNetworkInterface* payments_network_interface,
       TestAutofillClient* autofill_client);
   TestVirtualCardEnrollmentManager(const TestVirtualCardEnrollmentManager&) =
       delete;
diff --git a/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc b/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc
index b6261525..aefc912 100644
--- a/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc
+++ b/components/autofill/core/browser/payments/virtual_card_enrollment_manager.cc
@@ -45,11 +45,11 @@
 
 VirtualCardEnrollmentManager::VirtualCardEnrollmentManager(
     PersonalDataManager* personal_data_manager,
-    payments::PaymentsClient* payments_client,
+    payments::PaymentsNetworkInterface* payments_network_interface,
     AutofillClient* autofill_client)
     : autofill_client_(autofill_client),
       personal_data_manager_(personal_data_manager),
-      payments_client_(payments_client) {
+      payments_network_interface_(payments_network_interface) {
   // |autofill_client_| does not exist on Clank settings page where this flow
   // can also be triggered.
   if (base::FeatureList::IsEnabled(
@@ -66,8 +66,8 @@
 void VirtualCardEnrollmentManager::InitVirtualCardEnroll(
     const CreditCard& credit_card,
     VirtualCardEnrollmentSource virtual_card_enrollment_source,
-    absl::optional<
-        payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails>
+    absl::optional<payments::PaymentsNetworkInterface::
+                       GetDetailsForEnrollmentResponseDetails>
         get_details_for_enrollment_response_details,
     PrefService* user_prefs,
     RiskAssessmentFunction risk_assessment_function,
@@ -129,7 +129,7 @@
   LogUpdateVirtualCardEnrollmentRequestAttempt(
       state_.virtual_card_enrollment_fields.virtual_card_enrollment_source,
       VirtualCardEnrollmentRequestType::kEnroll);
-  payments::PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails
+  payments::PaymentsNetworkInterface::UpdateVirtualCardEnrollmentRequestDetails
       request_details;
   request_details.virtual_card_enrollment_source =
       state_.virtual_card_enrollment_fields.virtual_card_enrollment_source;
@@ -144,7 +144,7 @@
   virtual_card_enrollment_update_response_callback_ =
       std::move(virtual_card_enrollment_update_response_callback);
 
-  payments_client_->UpdateVirtualCardEnrollment(
+  payments_network_interface_->UpdateVirtualCardEnrollment(
       request_details,
       base::BindOnce(&VirtualCardEnrollmentManager::
                          OnDidGetUpdateVirtualCardEnrollmentResponse,
@@ -165,7 +165,7 @@
       VirtualCardEnrollmentSource::kSettingsPage,
       VirtualCardEnrollmentRequestType::kUnenroll);
 
-  payments::PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails
+  payments::PaymentsNetworkInterface::UpdateVirtualCardEnrollmentRequestDetails
       request_details;
   state_.virtual_card_enrollment_fields.virtual_card_enrollment_source =
       VirtualCardEnrollmentSource::kSettingsPage;
@@ -183,7 +183,7 @@
   virtual_card_enrollment_update_response_callback_ =
       std::move(virtual_card_enrollment_update_response_callback);
 
-  payments_client_->UpdateVirtualCardEnrollment(
+  payments_network_interface_->UpdateVirtualCardEnrollment(
       request_details,
       base::BindOnce(&VirtualCardEnrollmentManager::
                          OnDidGetUpdateVirtualCardEnrollmentResponse,
@@ -294,7 +294,7 @@
 }
 
 void VirtualCardEnrollmentManager::Reset() {
-  payments_client_->CancelRequest();
+  payments_network_interface_->CancelRequest();
   weak_ptr_factory_.InvalidateWeakPtrs();
   state_ = VirtualCardEnrollmentProcessState();
   avatar_animation_complete_ = false;
@@ -395,7 +395,7 @@
 }
 
 void VirtualCardEnrollmentManager::GetDetailsForEnroll() {
-  payments::PaymentsClient::GetDetailsForEnrollmentRequestDetails
+  payments::PaymentsNetworkInterface::GetDetailsForEnrollmentRequestDetails
       request_details;
   request_details.app_locale = personal_data_manager_->app_locale();
   request_details.risk_data = state_.risk_data.value_or("");
@@ -408,7 +408,7 @@
 
   get_details_for_enrollment_request_sent_timestamp_ = AutofillClock::Now();
 
-  payments_client_->GetVirtualCardEnrollmentDetails(
+  payments_network_interface_->GetVirtualCardEnrollmentDetails(
       request_details,
       base::BindOnce(
           &VirtualCardEnrollmentManager::OnDidGetDetailsForEnrollResponse,
@@ -419,8 +419,8 @@
 
 void VirtualCardEnrollmentManager::OnDidGetDetailsForEnrollResponse(
     AutofillClient::PaymentsRpcResult result,
-    const payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails&
-        response) {
+    const payments::PaymentsNetworkInterface::
+        GetDetailsForEnrollmentResponseDetails& response) {
   if (get_details_for_enrollment_request_sent_timestamp_.has_value()) {
     LogGetDetailsForEnrollmentRequestLatency(
         state_.virtual_card_enrollment_fields.virtual_card_enrollment_source,
@@ -468,8 +468,8 @@
 }
 
 void VirtualCardEnrollmentManager::SetGetDetailsForEnrollmentResponseDetails(
-    const payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails&
-        response) {
+    const payments::PaymentsNetworkInterface::
+        GetDetailsForEnrollmentResponseDetails& response) {
   enroll_response_details_received_ = true;
   state_.virtual_card_enrollment_fields.google_legal_message =
       std::move(response.google_legal_message);
@@ -551,8 +551,9 @@
 
 bool VirtualCardEnrollmentManager::
     IsValidGetDetailsForEnrollmentResponseDetails(
-        const payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails&
-            get_details_for_enrollment_response_details) {
+        const payments::PaymentsNetworkInterface::
+            GetDetailsForEnrollmentResponseDetails&
+                get_details_for_enrollment_response_details) {
   if (get_details_for_enrollment_response_details.google_legal_message.empty())
     return false;
 
diff --git a/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h b/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h
index ce4d581..e45a471 100644
--- a/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h
+++ b/components/autofill/core/browser/payments/virtual_card_enrollment_manager.h
@@ -11,7 +11,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/time/time.h"
 #include "components/autofill/core/browser/autofill_client.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/payments/virtual_card_enrollment_flow.h"
 #include "components/autofill/core/browser/strike_databases/payments/virtual_card_enrollment_strike_database.h"
 #include "ui/gfx/geometry/rect.h"
@@ -94,9 +94,10 @@
 class VirtualCardEnrollmentManager {
  public:
   // The parameters should outlive the VirtualCardEnrollmentManager.
-  VirtualCardEnrollmentManager(PersonalDataManager* personal_data_manager,
-                               payments::PaymentsClient* payments_client,
-                               AutofillClient* autofill_client = nullptr);
+  VirtualCardEnrollmentManager(
+      PersonalDataManager* personal_data_manager,
+      payments::PaymentsNetworkInterface* payments_network_interface,
+      AutofillClient* autofill_client = nullptr);
   VirtualCardEnrollmentManager(const VirtualCardEnrollmentManager&) = delete;
   VirtualCardEnrollmentManager& operator=(const VirtualCardEnrollmentManager&) =
       delete;
@@ -129,8 +130,8 @@
       // GetDetailsForEnrollmentResponseDetails from the
       // UploadCardResponseDetails, so we can then skip the
       // GetDetailsForEnroll request in the Virtual Card Enrollment flow.
-      absl::optional<
-          payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails>
+      absl::optional<payments::PaymentsNetworkInterface::
+                         GetDetailsForEnrollmentResponseDetails>
           get_details_for_enrollment_response_details = absl::nullopt,
       // |user_prefs| will be populated if we are in the Android settings page,
       // to then be used for loading risk data. Otherwise it will always be
@@ -152,8 +153,8 @@
   // bubble.
   void OnCardSavedAnimationComplete();
 
-  // Uses |payments_client_| to send the enroll request. |state_|'s
-  // |vcn_context_token_|, which should be set when we receive the
+  // Uses `payments_network_interface_` to send the enroll request. `state_`'s
+  // `vcn_context_token_`, which should be set when we receive the
   // GetDetailsForEnrollResponse, is used in the
   // UpdateVirtualCardEnrollmentRequest to enroll the correct card.
   void Enroll(
@@ -287,13 +288,13 @@
   // show the bubble so that we show the correct bubble version.
   void OnRiskDataLoadedForVirtualCard(const std::string& risk_data);
 
-  // Sends the GetDetailsForEnrollRequest using |payments_client_|. |state_|'s
-  // |risk_data| and its |virtual_card_enrollment_fields|'s |credit_card|'s
-  // |instrument_id| are the fields the server requires for the
-  // GetDetailsForEnrollRequest, and will be used by |payments_client_|.
-  // |state_|'s |virtual_card_enrollment_fields_|'s
-  // |virtual_card_enrollment_source| is passed here so that it can be forwarded
-  // to ShowVirtualCardEnrollBubble.
+  // Sends the GetDetailsForEnrollRequest using `payments_network_interface_`.
+  // `state_`'s `risk_data` and its `virtual_card_enrollment_fields`'s
+  // `credit_card`'s `instrument_id` are the fields the server requires for the
+  // GetDetailsForEnrollRequest, and will be used by
+  // `payments_network_interface_`. `state_`'s
+  // `virtual_card_enrollment_fields_`'s `virtual_card_enrollment_source` is
+  // passed here so that it can be forwarded to ShowVirtualCardEnrollBubble.
   void GetDetailsForEnroll();
 
   // Handles the response from the GetDetailsForEnrollRequest. |result| and
@@ -302,8 +303,8 @@
   // current process' state.
   void OnDidGetDetailsForEnrollResponse(
       AutofillClient::PaymentsRpcResult result,
-      const payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails&
-          response);
+      const payments::PaymentsNetworkInterface::
+          GetDetailsForEnrollmentResponseDetails& response);
 
   // Sets the corresponding fields in |state_| from the
   // GetDetailsForEnrollmentResponseDetails in |response|. This function is used
@@ -312,8 +313,8 @@
   // GetDetailsForEnrollmentResponseDetails is returned in the upload card
   // response.
   void SetGetDetailsForEnrollmentResponseDetails(
-      const payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails&
-          response);
+      const payments::PaymentsNetworkInterface::
+          GetDetailsForEnrollmentResponseDetails& response);
 
   // Should always be called right before showing virtual card enrollment UI.
   // This function attempts to set the card art image in |state_|, and if the
@@ -329,8 +330,9 @@
   // Returns true if the passed in GetDetailsForEnrollmentResponseDetails is
   // valid.
   bool IsValidGetDetailsForEnrollmentResponseDetails(
-      const payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails&
-          get_details_for_enrollment_response_details);
+      const payments::PaymentsNetworkInterface::
+          GetDetailsForEnrollmentResponseDetails&
+              get_details_for_enrollment_response_details);
 
   FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest, Enroll);
   FRIEND_TEST_ALL_PREFIXES(VirtualCardEnrollmentManagerTest,
@@ -350,9 +352,9 @@
   // to/from the web database.
   const raw_ptr<PersonalDataManager> personal_data_manager_;
 
-  // The associated |payments_client_| that is used for all requests to the
-  // server.
-  const raw_ptr<payments::PaymentsClient> payments_client_;
+  // The associated `payments_network_interface_` that is used for all requests
+  // to the server.
+  const raw_ptr<payments::PaymentsNetworkInterface> payments_network_interface_;
 
   // The database that is used to count instrument_id-keyed strikes to suppress
   // prompting users to enroll in virtual cards.
diff --git a/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc b/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc
index aa6e05ea..3b344ac4 100644
--- a/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc
+++ b/components/autofill/core/browser/payments/virtual_card_enrollment_manager_unittest.cc
@@ -19,7 +19,7 @@
 #include "components/autofill/core/browser/payments/payments_requests/update_virtual_card_enrollment_request.h"
 #include "components/autofill/core/browser/payments/payments_util.h"
 #include "components/autofill/core/browser/payments/test_legal_message_line.h"
-#include "components/autofill/core/browser/payments/test_payments_client.h"
+#include "components/autofill/core/browser/payments/test_payments_network_interface.h"
 #include "components/autofill/core/browser/payments/test_virtual_card_enrollment_manager.h"
 #include "components/autofill/core/browser/payments/virtual_card_enrollment_flow.h"
 #include "components/autofill/core/browser/strike_databases/payments/test_strike_database.h"
@@ -65,15 +65,15 @@
         /*sync_service=*/&sync_service_,
         /*strike_database=*/nullptr,
         /*image_fetcher=*/nullptr);
-    autofill_client_->set_test_payments_client(
-        std::make_unique<payments::TestPaymentsClient>(
+    autofill_client_->set_test_payments_network_interface(
+        std::make_unique<payments::TestPaymentsNetworkInterface>(
             autofill_client_->GetURLLoaderFactory(),
             autofill_client_->GetIdentityManager(), &personal_data_manager()));
     autofill_client_->set_test_strike_database(
         std::make_unique<TestStrikeDatabase>());
     virtual_card_enrollment_manager_ =
         std::make_unique<TestVirtualCardEnrollmentManager>(
-            &personal_data_manager(), &payments_client(),
+            &personal_data_manager(), &payments_network_interface(),
             autofill_client_.get());
   }
 
@@ -109,7 +109,7 @@
     ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id);
   }
 
-  payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails
+  payments::PaymentsNetworkInterface::GetDetailsForEnrollmentResponseDetails
   SetUpOnDidGetDetailsForEnrollResponse(
       const TestLegalMessageLine& google_legal_message,
       const TestLegalMessageLine& issuer_legal_message,
@@ -125,7 +125,8 @@
     }
     state->virtual_card_enrollment_fields.credit_card = *card_;
 
-    payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails response;
+    payments::PaymentsNetworkInterface::GetDetailsForEnrollmentResponseDetails
+        response;
     response.vcn_context_token = kTestVcnContextToken;
     response.google_legal_message = {google_legal_message};
     response.issuer_legal_message = {issuer_legal_message};
@@ -154,9 +155,9 @@
   }
 
  protected:
-  payments::TestPaymentsClient& payments_client() {
-    return *static_cast<payments::TestPaymentsClient*>(
-        autofill_client_->GetPaymentsClient());
+  payments::TestPaymentsNetworkInterface& payments_network_interface() {
+    return *static_cast<payments::TestPaymentsNetworkInterface*>(
+        autofill_client_->GetPaymentsNetworkInterface());
   }
   TestPersonalDataManager& personal_data_manager() {
     return *autofill_client_->GetPersonalDataManager();
@@ -229,7 +230,7 @@
       virtual_card_enrollment_manager_->GetVirtualCardEnrollmentProcessState();
   state->risk_data.reset();
   SetValidCardArtImageForCard(*card_);
-  payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails
+  payments::PaymentsNetworkInterface::GetDetailsForEnrollmentResponseDetails
       get_details_for_enrollment_response_details;
   TestLegalMessageLine google_test_legal_message_line{
       "google_test_legal_message"};
@@ -241,8 +242,8 @@
       issuer_test_legal_message_line};
   get_details_for_enrollment_response_details.vcn_context_token =
       "vcn_context_token";
-  absl::optional<
-      payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails>
+  absl::optional<payments::PaymentsNetworkInterface::
+                     GetDetailsForEnrollmentResponseDetails>
       get_details_for_enrollment_response_details_optional =
           get_details_for_enrollment_response_details;
   virtual_card_enrollment_manager_->InitVirtualCardEnroll(
@@ -278,9 +279,9 @@
   virtual_card_enrollment_manager_->OnRiskDataLoadedForVirtualCard(
       kTestRiskData);
 
-  payments::PaymentsClient::GetDetailsForEnrollmentRequestDetails
-      request_details =
-          payments_client().get_details_for_enrollment_request_details();
+  payments::PaymentsNetworkInterface::GetDetailsForEnrollmentRequestDetails
+      request_details = payments_network_interface()
+                            .get_details_for_enrollment_request_details();
 
   EXPECT_EQ(request_details.risk_data, state->risk_data.value_or(""));
   EXPECT_EQ(request_details.app_locale, personal_data_manager().app_locale());
@@ -318,7 +319,7 @@
       virtual_card_enrollment_manager_
           ->get_details_for_enrollment_request_sent_timestamp_ =
           AutofillClock::Now();
-      payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails
+      payments::PaymentsNetworkInterface::GetDetailsForEnrollmentResponseDetails
           response = std::move(SetUpOnDidGetDetailsForEnrollResponse(
               google_legal_message, issuer_legal_message, make_image_present));
       auto* state = virtual_card_enrollment_manager_
@@ -395,8 +396,8 @@
       TestLegalMessageLine("google_test_legal_message");
   const TestLegalMessageLine issuer_legal_message =
       TestLegalMessageLine("issuer_test_legal_message");
-  payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails response =
-      std::move(SetUpOnDidGetDetailsForEnrollResponse(
+  payments::PaymentsNetworkInterface::GetDetailsForEnrollmentResponseDetails
+      response = std::move(SetUpOnDidGetDetailsForEnrollResponse(
           google_legal_message, issuer_legal_message,
           /*make_image_present=*/true));
   auto* state =
@@ -443,8 +444,8 @@
     virtual_card_enrollment_manager_->SetResetCalled(false);
 
     virtual_card_enrollment_manager_->OnDidGetDetailsForEnrollResponse(
-        result,
-        payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails());
+        result, payments::PaymentsNetworkInterface::
+                    GetDetailsForEnrollmentResponseDetails());
 
     EXPECT_TRUE(virtual_card_enrollment_manager_->GetResetCalled());
   }
@@ -457,8 +458,8 @@
     virtual_card_enrollment_manager_->SetResetCalled(false);
 
     virtual_card_enrollment_manager_->OnDidGetDetailsForEnrollResponse(
-        result,
-        payments::PaymentsClient::GetDetailsForEnrollmentResponseDetails());
+        result, payments::PaymentsNetworkInterface::
+                    GetDetailsForEnrollmentResponseDetails());
 
     EXPECT_TRUE(virtual_card_enrollment_manager_->GetResetCalled());
   }
@@ -489,14 +490,15 @@
     virtual_card_enrollment_manager_->SetPaymentsRpcResult(
         AutofillClient::PaymentsRpcResult::kNone);
 
-    payments_client().set_update_virtual_card_enrollment_result(
+    payments_network_interface().set_update_virtual_card_enrollment_result(
         AutofillClient::PaymentsRpcResult::kSuccess);
     virtual_card_enrollment_manager_->Enroll(
         /*virtual_card_enrollment_update_response_callback=*/absl::nullopt);
 
-    payments::PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails
-        request_details =
-            payments_client().update_virtual_card_enrollment_request_details();
+    payments::PaymentsNetworkInterface::
+        UpdateVirtualCardEnrollmentRequestDetails request_details =
+            payments_network_interface()
+                .update_virtual_card_enrollment_request_details();
     EXPECT_TRUE(request_details.vcn_context_token.has_value());
     EXPECT_EQ(request_details.vcn_context_token, kTestVcnContextToken);
     EXPECT_EQ(request_details.virtual_card_enrollment_source,
@@ -531,7 +533,7 @@
         /*sample=*/true, 1);
 
     // Starts another request and makes sure it fails.
-    payments_client().set_update_virtual_card_enrollment_result(
+    payments_network_interface().set_update_virtual_card_enrollment_result(
         AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure);
     virtual_card_enrollment_manager_->Enroll(
         /*virtual_card_enrollment_update_response_callback=*/absl::nullopt);
@@ -557,9 +559,9 @@
       /*instrument_id=*/9223372036854775807,
       /*virtual_card_enrollment_update_response_callback=*/absl::nullopt);
 
-  payments::PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails
-      request_details =
-          payments_client().update_virtual_card_enrollment_request_details();
+  payments::PaymentsNetworkInterface::UpdateVirtualCardEnrollmentRequestDetails
+      request_details = payments_network_interface()
+                            .update_virtual_card_enrollment_request_details();
   EXPECT_EQ(request_details.virtual_card_enrollment_source,
             VirtualCardEnrollmentSource::kSettingsPage);
   EXPECT_EQ(request_details.virtual_card_enrollment_request_type,
@@ -581,7 +583,7 @@
       /*sample=*/true, 1);
 
   // Starts another request and make sure it fails.
-  payments_client().set_update_virtual_card_enrollment_result(
+  payments_network_interface().set_update_virtual_card_enrollment_result(
       AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure);
   virtual_card_enrollment_manager_->Unenroll(
       /*instrument_id=*/9223372036854775807,
diff --git a/components/autofill/core/browser/test_autofill_client.h b/components/autofill/core/browser/test_autofill_client.h
index a2002767..20b7559c 100644
--- a/components/autofill/core/browser/test_autofill_client.h
+++ b/components/autofill/core/browser/test_autofill_client.h
@@ -40,7 +40,7 @@
 #include "components/autofill/core/browser/payments/local_card_migration_manager.h"
 #include "components/autofill/core/browser/payments/test/mock_mandatory_reauth_manager.h"
 #include "components/autofill/core/browser/payments/test/test_credit_card_risk_based_authenticator.h"
-#include "components/autofill/core/browser/payments/test_payments_client.h"
+#include "components/autofill/core/browser/payments/test_payments_network_interface.h"
 #include "components/autofill/core/browser/strike_databases/payments/test_strike_database.h"
 #include "components/autofill/core/browser/test_address_normalizer.h"
 #include "components/autofill/core/browser/test_form_data_importer.h"
@@ -187,15 +187,15 @@
   FormDataImporter* GetFormDataImporter() override {
     if (!form_data_importer_) {
       set_test_form_data_importer(std::make_unique<FormDataImporter>(
-          /*client=*/this, /*payments_client=*/nullptr,
+          /*client=*/this, /*payments_network_interface=*/nullptr,
           /*personal_data_manager=*/nullptr, /*app_locale=*/"en-US"));
     }
 
     return form_data_importer_.get();
   }
 
-  payments::PaymentsClient* GetPaymentsClient() override {
-    return payments_client_.get();
+  payments::PaymentsNetworkInterface* GetPaymentsNetworkInterface() override {
+    return payments_network_interface_.get();
   }
 
   StrikeDatabase* GetStrikeDatabase() override {
@@ -566,9 +566,10 @@
     test_strike_database_ = std::move(test_strike_database);
   }
 
-  void set_test_payments_client(
-      std::unique_ptr<payments::TestPaymentsClient> payments_client) {
-    payments_client_ = std::move(payments_client);
+  void set_test_payments_network_interface(
+      std::unique_ptr<payments::TestPaymentsNetworkInterface>
+          payments_network_interface) {
+    payments_network_interface_ = std::move(payments_network_interface);
   }
 
   void set_test_form_data_importer(
@@ -750,11 +751,12 @@
   // The below objects must be destroyed before `TestPersonalDataManager`
   // because they keep a reference to it.
   std::unique_ptr<AutofillOfferManager> autofill_offer_manager_;
-  std::unique_ptr<payments::PaymentsClient> payments_client_;
+  std::unique_ptr<payments::PaymentsNetworkInterface>
+      payments_network_interface_;
   std::unique_ptr<testing::NiceMock<MockIbanManager>> mock_iban_manager_;
 
-  // The below objects must be destroyed before `PaymentsClient` because they
-  // (or their members) keep a reference to it.
+  // The below objects must be destroyed before `PaymentsNetworkInterface`
+  // because they (or their members) keep a reference to it.
   std::unique_ptr<CreditCardCvcAuthenticator> cvc_authenticator_;
   std::unique_ptr<CreditCardOtpAuthenticator> otp_authenticator_;
   std::unique_ptr<TestCreditCardRiskBasedAuthenticator>
diff --git a/components/autofill/core/browser/test_form_data_importer.cc b/components/autofill/core/browser/test_form_data_importer.cc
index c3cfc68c..d22405a 100644
--- a/components/autofill/core/browser/test_form_data_importer.cc
+++ b/components/autofill/core/browser/test_form_data_importer.cc
@@ -11,14 +11,14 @@
 
 TestFormDataImporter::TestFormDataImporter(
     AutofillClient* client,
-    payments::PaymentsClient* payments_client,
+    payments::PaymentsNetworkInterface* payments_network_interface,
     std::unique_ptr<CreditCardSaveManager> credit_card_save_manager,
     std::unique_ptr<IbanSaveManager> iban_save_manager,
     PersonalDataManager* personal_data_manager,
     const std::string& app_locale,
     std::unique_ptr<LocalCardMigrationManager> local_card_migration_manager)
     : FormDataImporter(client,
-                       payments_client,
+                       payments_network_interface,
                        personal_data_manager,
                        app_locale) {
   set_credit_card_save_manager_for_testing(std::move(credit_card_save_manager));
diff --git a/components/autofill/core/browser/test_form_data_importer.h b/components/autofill/core/browser/test_form_data_importer.h
index 60537b5..1f4dd0f 100644
--- a/components/autofill/core/browser/test_form_data_importer.h
+++ b/components/autofill/core/browser/test_form_data_importer.h
@@ -16,7 +16,7 @@
  public:
   TestFormDataImporter(
       AutofillClient* client,
-      payments::PaymentsClient* payments_client,
+      payments::PaymentsNetworkInterface* payments_network_interface,
       std::unique_ptr<CreditCardSaveManager> credit_card_save_manager,
       std::unique_ptr<IbanSaveManager> iban_save_manager,
       PersonalDataManager* personal_data_manager,
diff --git a/components/embedder_support/android/metrics/android_metrics_service_client.cc b/components/embedder_support/android/metrics/android_metrics_service_client.cc
index 2650c57..b55345e 100644
--- a/components/embedder_support/android/metrics/android_metrics_service_client.cc
+++ b/components/embedder_support/android/metrics/android_metrics_service_client.cc
@@ -403,8 +403,6 @@
                  content::NotificationService::AllSources());
   registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
                  content::NotificationService::AllSources());
-  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
-                 content::NotificationService::AllSources());
   registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG,
                  content::NotificationService::AllSources());
 }
@@ -615,6 +613,23 @@
   return fast_startup_for_testing_;
 }
 
+void AndroidMetricsServiceClient::OnRenderProcessHostCreated(
+    content::RenderProcessHost* host) {
+  if (!host_observation_.IsObservingSource(host)) {
+    host_observation_.AddObservation(host);
+  }
+}
+
+void AndroidMetricsServiceClient::RenderProcessExited(
+    content::RenderProcessHost* host,
+    const content::ChildProcessTerminationInfo& info) {
+  host_observation_.RemoveObservation(host);
+
+  if (did_start_metrics_) {
+    metrics_service_->OnApplicationNotIdle();
+  }
+}
+
 void AndroidMetricsServiceClient::Observe(
     int type,
     const content::NotificationSource& source,
@@ -624,7 +639,6 @@
   switch (type) {
     case content::NOTIFICATION_LOAD_STOP:
     case content::NOTIFICATION_LOAD_START:
-    case content::NOTIFICATION_RENDERER_PROCESS_CLOSED:
     case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG:
       metrics_service_->OnApplicationNotIdle();
       break;
diff --git a/components/embedder_support/android/metrics/android_metrics_service_client.h b/components/embedder_support/android/metrics/android_metrics_service_client.h
index de7a61b..4796847 100644
--- a/components/embedder_support/android/metrics/android_metrics_service_client.h
+++ b/components/embedder_support/android/metrics/android_metrics_service_client.h
@@ -12,6 +12,7 @@
 #include "base/memory/raw_ptr.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/metrics/field_trial.h"
+#include "base/scoped_multi_source_observation.h"
 #include "base/scoped_observation.h"
 #include "base/sequence_checker.h"
 #include "base/time/time.h"
@@ -24,6 +25,8 @@
 #include "components/version_info/version_info.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/render_process_host_creation_observer.h"
+#include "content/public/browser/render_process_host_observer.h"
 
 class PrefRegistrySimple;
 class PrefService;
@@ -94,9 +97,12 @@
 //
 // To match chrome on other platforms (including android), the MetricsService is
 // always created.
-class AndroidMetricsServiceClient : public MetricsServiceClient,
-                                    public EnabledStateProvider,
-                                    public content::NotificationObserver {
+class AndroidMetricsServiceClient
+    : public MetricsServiceClient,
+      public EnabledStateProvider,
+      public content::RenderProcessHostCreationObserver,
+      public content::RenderProcessHostObserver,
+      public content::NotificationObserver {
  public:
   AndroidMetricsServiceClient();
   ~AndroidMetricsServiceClient() override;
@@ -164,6 +170,14 @@
   // returns the empty string.
   std::string GetAppPackageNameIfLoggable() override;
 
+  // content::RenderProcessHostCreationObserver
+  void OnRenderProcessHostCreated(content::RenderProcessHost* host) override;
+
+  // RenderProcessHostObserver:
+  void RenderProcessExited(
+      content::RenderProcessHost* host,
+      const content::ChildProcessTerminationInfo& info) override;
+
   // content::NotificationObserver
   void Observe(int type,
                const content::NotificationSource& source,
@@ -275,6 +289,9 @@
       synthetic_trial_observation_{&synthetic_trial_observer_};
   std::unique_ptr<MetricsService> metrics_service_;
   std::unique_ptr<ukm::UkmService> ukm_service_;
+  base::ScopedMultiSourceObservation<content::RenderProcessHost,
+                                     content::RenderProcessHostObserver>
+      host_observation_{this};
   content::NotificationRegistrar registrar_;
   raw_ptr<PrefService> pref_service_ = nullptr;
   bool init_finished_ = false;
diff --git a/components/feed/core/v2/BUILD.gn b/components/feed/core/v2/BUILD.gn
index da50649b3..70e9ed3 100644
--- a/components/feed/core/v2/BUILD.gn
+++ b/components/feed/core/v2/BUILD.gn
@@ -9,7 +9,7 @@
   import("//build/config/android/rules.gni")
 }
 
-if (!is_ios) {
+if (use_blink) {
   source_set("feed_core_v2") {
     public = [
       "public/feed_api.h",
@@ -243,7 +243,6 @@
     deps = [
       ":feed_core_stubs",
       ":feed_core_v2",
-      ":unit_tests_bundle_data",
       "public:common",
       "//base",
       "//base/test:test_support",
@@ -272,6 +271,12 @@
       "//third_party/zlib/google:compression_utils",
     ]
 
+    if (is_ios) {
+      deps += [ "//components/test:feed_test_bundle_data" ]
+    } else {
+      deps += [ ":unit_tests_bundle_data" ]
+    }
+
     if (enable_supervised_users) {
       sources += [ "api_test/feed_api_supervised_feed_unittest.cc" ]
       deps += [
diff --git a/components/ml/webnn/graph_validation_utils.cc b/components/ml/webnn/graph_validation_utils.cc
index 9cb0552..225904b0 100644
--- a/components/ml/webnn/graph_validation_utils.cc
+++ b/components/ml/webnn/graph_validation_utils.cc
@@ -74,28 +74,27 @@
                                       const Size2d<uint32_t>& strides,
                                       const Size2d<uint32_t>& dilations,
                                       const AutoPad auto_pad) {
+  if (strides.height == 0 || strides.width == 0) {
+    return base::unexpected("All strides should be greater than 0.");
+  }
+  if (dilations.height == 0 || dilations.width == 0) {
+    return base::unexpected("All dilations should be greater than 0.");
+  }
+  const uint32_t stride_height = strides.height;
+  const uint32_t stride_width = strides.width;
+  const uint32_t dilation_height = dilations.height;
+  const uint32_t dilation_width = dilations.width;
+
   uint32_t padding_beginning_height = padding.beginning.height;
   uint32_t padding_ending_height = padding.ending.height;
   uint32_t padding_beginning_width = padding.beginning.width;
   uint32_t padding_ending_width = padding.ending.width;
 
-  if (strides.height == 0 || strides.width == 0) {
-    return base::unexpected("All strides should be greater than 0.");
-  }
-  const uint32_t stride_height = strides.height;
-  const uint32_t stride_width = strides.width;
-
-  if (dilations.height == 0 || dilations.width == 0) {
-    return base::unexpected("All dilations should be greater than 0.");
-  }
-  const uint32_t dilation_height = dilations.height;
-  const uint32_t dilation_width = dilations.width;
-
   // When the autoPad is other than "explicit", the values in the
   // options.padding array are ignored and the explicit padding values need to
   // be calculated.
   if (auto_pad != AutoPad::kExplicit) {
-    auto padding_sizes_height = CalculateConv2dPadding(
+    const auto padding_sizes_height = CalculateConv2dPadding(
         auto_pad, input_height, filter_height, stride_height, dilation_height);
     if (!padding_sizes_height) {
       return base::unexpected(
@@ -104,7 +103,7 @@
     }
     padding_beginning_height = padding_sizes_height->begin;
     padding_ending_height = padding_sizes_height->end;
-    auto padding_sizes_width = CalculateConv2dPadding(
+    const auto padding_sizes_width = CalculateConv2dPadding(
         auto_pad, input_width, filter_width, stride_width, dilation_width);
     if (!padding_sizes_width) {
       return base::unexpected(
@@ -115,7 +114,7 @@
     padding_ending_width = padding_sizes_width->end;
   }
 
-  auto float_output_height = CalculateConv2dOutputSize(
+  const auto float_output_height = CalculateConv2dOutputSize(
       input_height, filter_height, padding_beginning_height,
       padding_ending_height, stride_height, dilation_height);
   if (!float_output_height.has_value()) {
@@ -123,7 +122,7 @@
                             float_output_height.error());
   }
 
-  auto float_output_width = CalculateConv2dOutputSize(
+  const auto float_output_width = CalculateConv2dOutputSize(
       input_width, filter_width, padding_beginning_width, padding_ending_width,
       stride_width, dilation_width);
   if (!float_output_width.has_value()) {
@@ -135,6 +134,172 @@
                         .width = float_output_width.value()};
 }
 
+// Validate and calculate the output spatial dimensions of convTranspose2d given
+// input sizes, filter sizes, padding, strides, dilations and output padding.
+base::expected<Size2d<uint32_t>, std::string>
+ValidateAndCalculateConvTranspose2dOutputSizes(
+    const uint32_t input_height,
+    const uint32_t input_width,
+    const uint32_t filter_height,
+    const uint32_t filter_width,
+    const Padding2d& padding,
+    const Size2d<uint32_t>& strides,
+    const Size2d<uint32_t>& dilations,
+    const Size2d<uint32_t>& output_padding,
+    const AutoPad auto_pad) {
+  if (strides.height == 0 || strides.width == 0) {
+    return base::unexpected("All strides should be greater than 0.");
+  }
+  if (dilations.height == 0 || dilations.width == 0) {
+    return base::unexpected("All dilations should be greater than 0.");
+  }
+  const uint32_t stride_height = strides.height;
+  const uint32_t stride_width = strides.width;
+  const uint32_t dilation_height = dilations.height;
+  const uint32_t dilation_width = dilations.width;
+
+  const uint32_t output_padding_height = output_padding.height;
+  const uint32_t output_padding_width = output_padding.width;
+  if (output_padding_height >= stride_height ||
+      output_padding_width >= stride_width) {
+    return base::unexpected(
+        "The output padding must be smaller than the stride along the same "
+        "dimension.");
+  }
+
+  uint32_t padding_beginning_height = padding.beginning.height;
+  uint32_t padding_ending_height = padding.ending.height;
+  uint32_t padding_beginning_width = padding.beginning.width;
+  uint32_t padding_ending_width = padding.ending.width;
+
+  // When the autoPad is other than "explicit", the values in the
+  // options.padding array are ignored and the padding values need to be
+  // calculated.
+  if (auto_pad != AutoPad::kExplicit) {
+    const auto padding_sizes_height = CalculateConvTranspose2dPadding(
+        auto_pad, input_height, filter_height, stride_height, dilation_height,
+        output_padding_height);
+    if (!padding_sizes_height) {
+      return base::unexpected(
+          "Overflow occurred when calculating the padding along the height "
+          "dimension.");
+    }
+    padding_beginning_height = padding_sizes_height->begin;
+    padding_ending_height = padding_sizes_height->end;
+    const auto padding_sizes_width = CalculateConvTranspose2dPadding(
+        auto_pad, input_width, filter_width, stride_width, dilation_width,
+        output_padding_width);
+    if (!padding_sizes_width) {
+      return base::unexpected(
+          "Overflow occurred when calculating the padding along the width "
+          "dimension.");
+    }
+    padding_beginning_width = padding_sizes_width->begin;
+    padding_ending_width = padding_sizes_width->end;
+  }
+
+  const auto output_height = CalculateConvTranspose2dOutputSize(
+      input_height, filter_height, padding_beginning_height,
+      padding_ending_height, stride_height, dilation_height,
+      output_padding_height);
+  if (!output_height.has_value()) {
+    return base::unexpected("Failed to calculate the output height: " +
+                            output_height.error());
+  }
+
+  const auto output_width = CalculateConvTranspose2dOutputSize(
+      input_width, filter_width, padding_beginning_width, padding_ending_width,
+      stride_width, dilation_width, output_padding_width);
+  if (!output_width.has_value()) {
+    return base::unexpected("Failed to calculate the output width: " +
+                            output_width.error());
+  }
+
+  return Size2d<uint32_t>{.height = output_height.value(),
+                          .width = output_width.value()};
+}
+
+struct Conv2dInputOutputInfo {
+  uint32_t batches;
+  uint32_t channels;
+  uint32_t height;
+  uint32_t width;
+};
+
+// Validate and get the input info of 2-D direct and transposed convolution
+// operation given input operand and attributes.
+base::expected<Conv2dInputOutputInfo, std::string>
+ValidateAndGetConv2dInputInfo(const Operand& input,
+                              const Conv2dAttributesBase& attributes) {
+  // Validate input operand.
+  const auto& input_shape = input.dimensions;
+  if (input_shape.size() != 4) {
+    return base::unexpected("The input should be a 4-D tensor.");
+  }
+  // The input layout option specifies the layout format of the input tensor.
+  uint32_t batches, channels, height, width;
+  switch (attributes.input_layout) {
+    case InputOperandLayout::kNchw:
+      // "nchw": [batches, input_channels, height, width]
+      batches = input_shape[0];
+      channels = input_shape[1];
+      height = input_shape[2];
+      width = input_shape[3];
+      break;
+    case InputOperandLayout::kNhwc:
+      // "nhwc": [batches, height, width, input_channels]
+      batches = input_shape[0];
+      height = input_shape[1];
+      width = input_shape[2];
+      channels = input_shape[3];
+      break;
+  }
+
+  return Conv2dInputOutputInfo{.batches = batches,
+                               .channels = channels,
+                               .height = height,
+                               .width = width};
+}
+
+// Validate the bias of 2-D direct and transposed convolution operation and
+// create output operand given input operand, attributes and output info.
+base::expected<Operand, std::string> ValidateConv2dBiasAndCreateOutputOperand(
+    const Operand& input,
+    const Conv2dAttributesBase& attributes,
+    const Conv2dInputOutputInfo& output_info) {
+  // Validate bias operand if it is present.
+  if (attributes.bias_operand) {
+    const auto& bias_shape = attributes.bias_operand->dimensions;
+    if (bias_shape.size() != 1) {
+      return base::unexpected("The bias should be a 1-D tensor.");
+    }
+    if (bias_shape[0] != output_info.channels) {
+      return base::unexpected(base::StringPrintf(
+          "The bias shape should be [%u].", output_info.channels));
+    }
+    if (attributes.bias_operand->data_type != input.data_type) {
+      return base::unexpected("The bias type doesn't match input type.");
+    }
+  }
+
+  // The input layout option specifies the layout format of the output tensor.
+  std::vector<uint32_t> output_shape;
+  switch (attributes.input_layout) {
+    case InputOperandLayout::kNchw:
+      // "nchw": [batches, output_channels, height, width]
+      output_shape = {output_info.batches, output_info.channels,
+                      output_info.height, output_info.width};
+      break;
+    case InputOperandLayout::kNhwc:
+      // "nhwc": [batches, height, width, output_channels]
+      output_shape = {output_info.batches, output_info.height,
+                      output_info.width, output_info.channels};
+      break;
+  }
+
+  return Operand(input.data_type, std::move(output_shape));
+}
+
 }  // namespace
 
 Operand::Operand(DataType data_type, std::vector<uint32_t> dimensions) {
@@ -269,6 +434,14 @@
   return outputs;
 }
 
+Conv2dAttributesBase::Conv2dAttributesBase() = default;
+Conv2dAttributesBase::~Conv2dAttributesBase() = default;
+
+Conv2dAttributesBase::Conv2dAttributesBase(Conv2dAttributesBase&& other) =
+    default;
+Conv2dAttributesBase& Conv2dAttributesBase::operator=(
+    Conv2dAttributesBase&& other) = default;
+
 Conv2dAttributes::Conv2dAttributes() = default;
 Conv2dAttributes::~Conv2dAttributes() = default;
 
@@ -280,31 +453,12 @@
     const Operand& input,
     const Operand& filter,
     const Conv2dAttributes& attributes) {
-  // Validate input operand and set its sizes.
-  const auto input_shape = input.dimensions;
-  if (input_shape.size() != 4) {
-    return base::unexpected("The input should be a 4-D tensor.");
+  // Validate input operand.
+  const auto input_info = ValidateAndGetConv2dInputInfo(input, attributes);
+  if (!input_info.has_value()) {
+    return base::unexpected(input_info.error());
   }
-  // The input layout option specifies the layout format of the input tensor.
-  uint32_t input_batches, input_channels, input_height, input_width;
-  switch (attributes.input_layout) {
-    case InputOperandLayout::kNchw:
-      // "nchw": [batches, input_channels, height, width]
-      input_batches = input_shape[0];
-      input_channels = input_shape[1];
-      input_height = input_shape[2];
-      input_width = input_shape[3];
-      break;
-    case InputOperandLayout::kNhwc:
-      // "nhwc": [batches, height, width, input_channels]
-      input_batches = input_shape[0];
-      input_height = input_shape[1];
-      input_width = input_shape[2];
-      input_channels = input_shape[3];
-      break;
-  }
-
-  // Validate filter operand and set its sizes.
+  // Validate filter operand.
   if (filter.data_type != input.data_type) {
     return base::unexpected("The filter type doesn't match the input type.");
   }
@@ -312,8 +466,9 @@
   if (filter_shape.size() != 4) {
     return base::unexpected("The filter should be a 4-D tensor.");
   }
-  // The filter layout specifies the filter layout format.
+
   uint32_t filter_height, filter_width, output_channels, filter_input_channels;
+  // The conv2d filter layout specifies the filter layout format.
   switch (attributes.filter_layout) {
     case Conv2dFilterOperandLayout::kHwio:
       // "hwio": [height, width, input_channels/groups, output_channels]
@@ -344,57 +499,165 @@
       filter_width = filter_shape[3];
       break;
   }
-  // Validate bias operand if it is present.
-  if (attributes.bias_operand) {
-    const auto bias_shape = attributes.bias_operand->dimensions;
-    if (bias_shape.size() != 1) {
-      return base::unexpected("The bias should be a 1-D tensor.");
-    }
-    if (bias_shape[0] != output_channels) {
-      return base::unexpected(base::StringPrintf(
-          "The bias shape should be [%u].", output_channels));
-    }
-    if (attributes.bias_operand->data_type != input.data_type) {
-      return base::unexpected("The bias type doesn't match input type.");
-    }
-  }
-  // Validate groups.
+
+  // Validate groups and input channels.
   if (attributes.groups == 0) {
     return base::unexpected("The groups should be greater than 0.");
   }
-  if (input_channels % attributes.groups != 0 ||
-      filter_input_channels != input_channels / attributes.groups) {
+  if (input_info->channels % attributes.groups != 0 ||
+      filter_input_channels != input_info->channels / attributes.groups) {
     return base::unexpected(
         "The groups must evenly divide the input channels to filter input "
         "channels.");
   }
 
+  // Validate and calculate output sizes.
   const auto output_sizes = ValidateAndCalculateConv2dOutputSizes(
-      input_height, input_width, filter_height, filter_width,
+      input_info->height, input_info->width, filter_height, filter_width,
       attributes.padding, attributes.strides, attributes.dilations,
       attributes.auto_pad);
   if (!output_sizes.has_value()) {
     return base::unexpected(output_sizes.error());
   }
-  const uint32_t output_height =
-      base::ClampFloor<uint32_t>(output_sizes->height);
-  const uint32_t output_width = base::ClampFloor<uint32_t>(output_sizes->width);
-  // The input layout option specifies the layout format of the output tensor.
-  std::vector<uint32_t> output_shape;
-  switch (attributes.input_layout) {
-    case InputOperandLayout::kNchw:
-      // "nchw": [batches, output_channels, height, width]
-      output_shape = {input_batches, output_channels, output_height,
-                      output_width};
-      break;
-    case InputOperandLayout::kNhwc:
-      // "nhwc": [batches, height, width, output_channels]
-      output_shape = {input_batches, output_height, output_width,
-                      output_channels};
-      break;
+  uint32_t output_height = base::ClampFloor<uint32_t>(output_sizes->height);
+  uint32_t output_width = base::ClampFloor<uint32_t>(output_sizes->width);
+
+  Conv2dInputOutputInfo output_info{.batches = input_info->batches,
+                                    .channels = output_channels,
+                                    .height = output_height,
+                                    .width = output_width};
+  return ValidateConv2dBiasAndCreateOutputOperand(input, attributes,
+                                                  output_info);
+}
+
+ConvTranspose2dAttributes::ConvTranspose2dAttributes() = default;
+ConvTranspose2dAttributes::~ConvTranspose2dAttributes() = default;
+
+ConvTranspose2dAttributes::ConvTranspose2dAttributes(
+    ConvTranspose2dAttributes&& other) = default;
+ConvTranspose2dAttributes& ConvTranspose2dAttributes::operator=(
+    ConvTranspose2dAttributes&& other) = default;
+
+base::expected<Operand, std::string> ValidateConvTranspose2dAndInferOutput(
+    const Operand& input,
+    const Operand& filter,
+    const ConvTranspose2dAttributes& attributes) {
+  // Validate input operand.
+  const auto input_info = ValidateAndGetConv2dInputInfo(input, attributes);
+  if (!input_info.has_value()) {
+    return base::unexpected(input_info.error());
+  }
+  // Validate filter operand.
+  if (filter.data_type != input.data_type) {
+    return base::unexpected("The filter type doesn't match the input type.");
+  }
+  const auto filter_shape = filter.dimensions;
+  if (filter_shape.size() != 4) {
+    return base::unexpected("The filter should be a 4-D tensor.");
   }
 
-  return Operand(input.data_type, std::move(output_shape));
+  uint32_t input_channels, filter_height, filter_width, filter_output_channels;
+  // The conv2d filter layout specifies the filter layout format.
+  switch (attributes.filter_layout) {
+    case ConvTranspose2dFilterOperandLayout::kIohw:
+      // "iohw": [input_channels, output_channels/groups, height, width]
+      input_channels = filter_shape[0];
+      filter_output_channels = filter_shape[1];
+      filter_height = filter_shape[2];
+      filter_width = filter_shape[3];
+      break;
+    case ConvTranspose2dFilterOperandLayout::kHwoi:
+      // "hwoi": [height, width, output_channels/groups, input_channels]
+      filter_height = filter_shape[0];
+      filter_width = filter_shape[1];
+      filter_output_channels = filter_shape[2];
+      input_channels = filter_shape[3];
+      break;
+    case ConvTranspose2dFilterOperandLayout::kOhwi:
+      // "ohwi": [output_channels/groups, height, width, input_channels]
+      filter_output_channels = filter_shape[0];
+      filter_height = filter_shape[1];
+      filter_width = filter_shape[2];
+      input_channels = filter_shape[3];
+      break;
+  }
+  // Validate groups, input channels and calculate output channels.
+  if (attributes.groups == 0) {
+    return base::unexpected("The groups should be greater than 0.");
+  }
+  if (input_info->channels != input_channels) {
+    return base::unexpected(
+        "The input channels should equal to filter input channels.");
+  }
+  const auto checked_output_channels =
+      base::MakeCheckedNum<uint32_t>(filter_output_channels) *
+      attributes.groups;
+  if (!checked_output_channels.IsValid()) {
+    return base::unexpected("The output channels is too large.");
+  }
+  const uint32_t output_channels = checked_output_channels.ValueOrDie();
+
+  // Validate and calculate output sizes.
+  uint32_t output_height, output_width;
+  if (attributes.output_sizes) {
+    const auto& output_sizes = attributes.output_sizes;
+    output_height = output_sizes->height;
+    output_width = output_sizes->width;
+    if (output_height <= 0 || output_width <= 0) {
+      return base::unexpected("All output sizes should be greater than 0.");
+    }
+    const auto strides = attributes.strides;
+    const auto calculated_output_sizes =
+        ValidateAndCalculateConvTranspose2dOutputSizes(
+            input_info->height, input_info->width, filter_height, filter_width,
+            attributes.padding, strides, attributes.dilations,
+            // According to WebNN spec:
+            // https://webmachinelearning.github.io/webnn/#dom-mlconvtranspose2doptions-outputsizes
+            // When the output sizes are explicitly specified, the output
+            // padding values in outputPadding are ignored.
+            {0, 0}, attributes.auto_pad);
+    if (!calculated_output_sizes.has_value()) {
+      return base::unexpected(calculated_output_sizes.error());
+    }
+    const auto calculated_output_height = calculated_output_sizes->height;
+    const auto max_output_height =
+        base::MakeCheckedNum<uint32_t>(calculated_output_height) +
+        strides.height;
+    if (!max_output_height.IsValid()) {
+      return base::unexpected("The checked maximum output height is too large");
+    }
+    if (output_height < calculated_output_height ||
+        output_height >= max_output_height.ValueOrDie()) {
+      return base::unexpected("The height of output sizes is invalid.");
+    }
+    const auto calculated_output_width = calculated_output_sizes->width;
+    const auto max_output_width =
+        base::MakeCheckedNum<uint32_t>(calculated_output_width) + strides.width;
+    if (!max_output_width.IsValid()) {
+      return base::unexpected("The checked maximum output width is too large");
+    }
+    if (output_width < calculated_output_width ||
+        output_width >= max_output_width.ValueOrDie()) {
+      return base::unexpected("The width of output sizes is invalid.");
+    }
+  } else {
+    const auto output_sizes = ValidateAndCalculateConvTranspose2dOutputSizes(
+        input_info->height, input_info->width, filter_height, filter_width,
+        attributes.padding, attributes.strides, attributes.dilations,
+        attributes.output_padding, attributes.auto_pad);
+    if (!output_sizes.has_value()) {
+      return base::unexpected(output_sizes.error());
+    }
+    output_height = output_sizes->height;
+    output_width = output_sizes->width;
+  }
+
+  Conv2dInputOutputInfo output_info{.batches = input_info->batches,
+                                    .channels = output_channels,
+                                    .height = output_height,
+                                    .width = output_width};
+  return ValidateConv2dBiasAndCreateOutputOperand(input, attributes,
+                                                  output_info);
 }
 
 base::expected<Operand, std::string> ValidatePadAndInferOutput(
@@ -1103,6 +1366,69 @@
   return PaddingSizes({.begin = padding_begin, .end = padding_end});
 }
 
+absl::optional<PaddingSizes> CalculateConvTranspose2dPadding(
+    AutoPad auto_pad,
+    const uint32_t input_size,
+    const uint32_t filter_size,
+    const uint32_t stride,
+    const uint32_t dilation,
+    const uint32_t output_padding) {
+  auto checked_output_size =
+      base::MakeCheckedNum<uint32_t>(input_size) * stride;
+  auto checked_effective_filter_size =
+      (base::MakeCheckedNum<uint32_t>(filter_size) - 1) * dilation + 1;
+  auto checked_total_padding =
+      stride * (base::MakeCheckedNum<uint32_t>(input_size) - 1) +
+      checked_effective_filter_size + output_padding - checked_output_size;
+  base::CheckedNumeric<uint32_t> checked_padding_begin, checked_padding_end;
+  switch (auto_pad) {
+    case AutoPad::kSameUpper:
+      checked_padding_begin = checked_total_padding / 2;
+      checked_padding_end = (checked_total_padding + 1) / 2;
+      break;
+    case AutoPad::kSameLower:
+      checked_padding_begin = (checked_total_padding + 1) / 2;
+      checked_padding_end = checked_total_padding / 2;
+      break;
+    case AutoPad::kExplicit:
+      // The case has been ruled out before the function be called.
+      NOTREACHED_NORETURN()
+          << "Invalid auto pad value when calculating convTranspose2d padding.";
+  }
+  uint32_t padding_begin, padding_end;
+  if (!checked_padding_begin.AssignIfValid(&padding_begin) ||
+      !checked_padding_end.AssignIfValid(&padding_end)) {
+    return absl::nullopt;
+  }
+  return webnn::PaddingSizes({.begin = padding_begin, .end = padding_end});
+}
+
+base::expected<uint32_t, std::string> CalculateConvTranspose2dOutputSize(
+    const uint32_t input_size,
+    const uint32_t filter_size,
+    const uint32_t beginning_padding,
+    const uint32_t ending_padding,
+    const uint32_t stride,
+    const uint32_t dilation,
+    const uint32_t output_padding) {
+  // Calculate the dilated filter sizes.
+  auto checked_effective_filter_size =
+      (base::MakeCheckedNum<uint32_t>(filter_size) - 1) * dilation + 1;
+  if (!checked_effective_filter_size.IsValid()) {
+    return base::unexpected("The effective filter size is too large.");
+  }
+  auto checked_output_size =
+      (base::MakeCheckedNum<uint32_t>(input_size) - 1) * stride +
+      checked_effective_filter_size - beginning_padding - ending_padding +
+      output_padding;
+  if (!checked_output_size.IsValid()) {
+    return base::unexpected(
+        "The stride is too large or the input size is too small for padding.");
+  }
+
+  return checked_output_size.ValueOrDie();
+}
+
 bool IsFloatingPointType(Operand::DataType data_type) {
   return DataTypeConstraint::kFloat.Has(data_type);
 }
diff --git a/components/ml/webnn/graph_validation_utils.h b/components/ml/webnn/graph_validation_utils.h
index c52e831..ae6dad7b 100644
--- a/components/ml/webnn/graph_validation_utils.h
+++ b/components/ml/webnn/graph_validation_utils.h
@@ -23,12 +23,14 @@
 struct Operand {
   // Represents the `MLOperandType` in the WebIDL definition.
   enum DataType {
-    kFloat32,
+    kMinValue = 0,
+    kFloat32 = 0,
     kFloat16,
     kInt32,
     kUint32,
     kInt8,
     kUint8,
+    kMaxValue = kUint8,
   };
 
   Operand(DataType data_type, std::vector<uint32_t> dimensions);
@@ -51,11 +53,9 @@
   std::vector<uint32_t> dimensions;
 };
 
-// TODO(crbug.com/1273291): Use the data type constraint in service side to
-// validate operators.
 using DataTypeConstraintSet = base::EnumSet<Operand::DataType,
-                                            Operand::DataType::kFloat32,
-                                            Operand::DataType::kUint8>;
+                                            Operand::DataType::kMinValue,
+                                            Operand::DataType::kMaxValue>;
 
 namespace DataTypeConstraint {
 
@@ -65,11 +65,6 @@
 static constexpr DataTypeConstraintSet kSignedInteger = {
     Operand::DataType::kInt32, Operand::DataType::kInt8};
 
-static constexpr DataTypeConstraintSet kAll = {
-    Operand::DataType::kFloat32, Operand::DataType::kFloat16,
-    Operand::DataType::kInt32,   Operand::DataType::kUint32,
-    Operand::DataType::kInt8,    Operand::DataType::kUint8};
-
 }  // namespace DataTypeConstraint
 
 std::string DataTypeConstraintToString(
@@ -78,20 +73,25 @@
 // Represents the `MLInputOperandLayout` that specifies the layout format of
 // the input tensor. N is the batch, C is input channels, H is height and W is
 // the width of the tensor.
-enum InputOperandLayout { kNchw, kNhwc };
+enum class InputOperandLayout { kNchw, kNhwc };
 
 // Represents the `MLConv2dFilterOperandLayout` that specifies the layout format
-// of the filter tensor. O is output channels, I is input channels, H is height
-// and W is the width of filter.
-enum Conv2dFilterOperandLayout { kOihw, kHwio, kOhwi, kIhwo };
+// of the filter tensor. O is output channels, I is input channels / groups, H
+// is height and W is the width of filter.
+enum class Conv2dFilterOperandLayout { kOihw, kHwio, kOhwi, kIhwo };
+
+// Represents the `MLConvTranspose2dFilterOperandLayout` that specifies the
+// layout format of the filter tensor. I is input channels, O is output channels
+// / groups, H is height and W is the width of filter.
+enum class ConvTranspose2dFilterOperandLayout { kIohw, kHwoi, kOhwi };
 
 // Represents the `MLAutoPad`. `Explicit` means that the values in the padding
 // array should be used for calculating input padding, the `SameUpper` and
 // `SameLower` options mean the padding values are automatically computed.
-enum AutoPad { kExplicit, kSameUpper, kSameLower };
+enum class AutoPad { kExplicit, kSameUpper, kSameLower };
 
 // Represents the `MLRoundingType` that is used to compute the output shape.
-enum RoundingType { kFloor, kCeil };
+enum class RoundingType { kFloor, kCeil };
 
 enum ReduceKind {
   kL1,
@@ -123,15 +123,15 @@
 };
 
 // Contains the attributes of conv2d operator.
-struct Conv2dAttributes {
-  Conv2dAttributes();
-  ~Conv2dAttributes();
+struct Conv2dAttributesBase {
+  Conv2dAttributesBase();
+  ~Conv2dAttributesBase();
 
-  Conv2dAttributes(Conv2dAttributes&& other);
-  Conv2dAttributes& operator=(Conv2dAttributes&& other);
+  Conv2dAttributesBase(Conv2dAttributesBase&& other);
+  Conv2dAttributesBase& operator=(Conv2dAttributesBase&& other);
 
-  Conv2dAttributes(const Conv2dAttributes&) = delete;
-  Conv2dAttributes& operator=(const Conv2dAttributes&) = delete;
+  Conv2dAttributesBase(const Conv2dAttributesBase&) = delete;
+  Conv2dAttributesBase& operator=(const Conv2dAttributesBase&) = delete;
 
   // The additional rows and columns added to the beginning and ending of each
   // spatial dimension of input.
@@ -147,13 +147,47 @@
   uint32_t groups = 1;
   // The layout format of the input.
   InputOperandLayout input_layout = InputOperandLayout::kNchw;
-  // The layout format of the filter.
-  Conv2dFilterOperandLayout filter_layout = Conv2dFilterOperandLayout::kOihw;
   // The additional 1-D tensor with the shape of [output_channels] whose values
   // are to be added to the convolution result.
   absl::optional<Operand> bias_operand;
 };
 
+// Contains the attributes of conv2d operator.
+struct Conv2dAttributes : Conv2dAttributesBase {
+  Conv2dAttributes();
+  ~Conv2dAttributes();
+
+  Conv2dAttributes(Conv2dAttributes&& other);
+  Conv2dAttributes& operator=(Conv2dAttributes&& other);
+
+  Conv2dAttributes(const Conv2dAttributes&) = delete;
+  Conv2dAttributes& operator=(const Conv2dAttributes&) = delete;
+
+  // The layout format of the conv2d filter.
+  Conv2dFilterOperandLayout filter_layout = Conv2dFilterOperandLayout::kOihw;
+};
+
+// Contains the attributes of convTranspose2d operator.
+struct ConvTranspose2dAttributes : Conv2dAttributesBase {
+  ConvTranspose2dAttributes();
+  ~ConvTranspose2dAttributes();
+
+  ConvTranspose2dAttributes(ConvTranspose2dAttributes&& other);
+  ConvTranspose2dAttributes& operator=(ConvTranspose2dAttributes&& other);
+
+  ConvTranspose2dAttributes(const ConvTranspose2dAttributes&) = delete;
+  ConvTranspose2dAttributes& operator=(const ConvTranspose2dAttributes&) =
+      delete;
+
+  // The padding values applied to each spatial dimension of the output tensor.
+  Size2d<uint32_t> output_padding;
+  // The sizes of the last two dimensions of the output tensor.
+  absl::optional<Size2d<uint32_t>> output_sizes;
+  // The layout format of the convTranspose2d filter.
+  ConvTranspose2dFilterOperandLayout filter_layout =
+      ConvTranspose2dFilterOperandLayout::kIohw;
+};
+
 // Contains the attributes of pool2d operator.
 struct Pool2dAttributes {
   // The dimensions of the sliding window.
@@ -248,6 +282,14 @@
     const Operand& filter,
     const Conv2dAttributes& attributes);
 
+// Validate and infer output information of 2-D transposed convolution operator
+// defined in WebIDL here
+// https://www.w3.org/TR/webnn/#api-mlgraphbuilder-convtranspose2d
+base::expected<Operand, std::string> ValidateConvTranspose2dAndInferOutput(
+    const Operand& input,
+    const Operand& filter,
+    const ConvTranspose2dAttributes& attributes);
+
 // Validate and infer output information of pad operator defined in
 // WebIDL here https://www.w3.org/TR/webnn/#api-mlgraphbuilder-pad
 base::expected<Operand, std::string> ValidatePadAndInferOutput(
@@ -353,6 +395,31 @@
                                                     const uint32_t stride,
                                                     const uint32_t dilation);
 
+// Calculate the effective padding for convTranspose2d based on WebNN auto
+// padding rules.
+//
+// TODO(crbug.com/1273291): Add the link to WebNN spec's algorithm once it is
+// defined, tracked by: https://github.com/webmachinelearning/webnn/issues/326
+absl::optional<PaddingSizes> CalculateConvTranspose2dPadding(
+    AutoPad auto_pad,
+    const uint32_t input_size,
+    const uint32_t filter_size,
+    const uint32_t stride,
+    const uint32_t dilation,
+    const uint32_t output_padding);
+
+// Calculate the output size for convTranspose2d based on WebNN spec:
+// https://www.w3.org/TR/webnn/#api-mlgraphbuilder-convtranspose2d
+// Return the calculated output size if no error.
+base::expected<uint32_t, std::string> CalculateConvTranspose2dOutputSize(
+    const uint32_t input_size,
+    const uint32_t filter_size,
+    const uint32_t beginning_padding,
+    const uint32_t ending_padding,
+    const uint32_t stride,
+    const uint32_t dilation,
+    const uint32_t output_padding);
+
 bool IsFloatingPointType(Operand::DataType data_type);
 
 }  // namespace webnn
diff --git a/components/password_manager/core/browser/password_manager_util_unittest.cc b/components/password_manager/core/browser/password_manager_util_unittest.cc
index b1943ac..2668846 100644
--- a/components/password_manager/core/browser/password_manager_util_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_util_unittest.cc
@@ -110,8 +110,8 @@
   MOCK_METHOD(syncer::SyncService*, GetSyncService, (), (override));
   MOCK_METHOD(signin::IdentityManager*, GetIdentityManager, (), (override));
   MOCK_METHOD(autofill::FormDataImporter*, GetFormDataImporter, (), (override));
-  MOCK_METHOD(autofill::payments::PaymentsClient*,
-              GetPaymentsClient,
+  MOCK_METHOD(autofill::payments::PaymentsNetworkInterface*,
+              GetPaymentsNetworkInterface,
               (),
               (override));
   MOCK_METHOD(autofill::StrikeDatabase*, GetStrikeDatabase, (), (override));
diff --git a/components/payments/core/test_payment_request_delegate.cc b/components/payments/core/test_payment_request_delegate.cc
index a3c32bf..b41183c 100644
--- a/components/payments/core/test_payment_request_delegate.cc
+++ b/components/payments/core/test_payment_request_delegate.cc
@@ -21,11 +21,11 @@
       test_shared_loader_factory_(
           base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
               &test_url_loader_factory_)),
-      payments_client_(test_shared_loader_factory_,
-                       /*identity_manager=*/nullptr,
-                       personal_data_manager),
+      payments_network_interface_(test_shared_loader_factory_,
+                                  /*identity_manager=*/nullptr,
+                                  personal_data_manager),
       full_card_request_(&autofill_client_,
-                         &payments_client_,
+                         &payments_network_interface_,
                          personal_data_manager) {}
 
 TestPaymentRequestDelegate::~TestPaymentRequestDelegate() {}
diff --git a/components/payments/core/test_payment_request_delegate.h b/components/payments/core/test_payment_request_delegate.h
index 6d716813..29b8bda 100644
--- a/components/payments/core/test_payment_request_delegate.h
+++ b/components/payments/core/test_payment_request_delegate.h
@@ -12,7 +12,7 @@
 #include "base/task/single_thread_task_executor.h"
 #include "base/task/single_thread_task_runner.h"
 #include "components/autofill/core/browser/payments/full_card_request.h"
-#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/browser/payments/payments_network_interface.h"
 #include "components/autofill/core/browser/test_address_normalizer.h"
 #include "components/autofill/core/browser/test_autofill_client.h"
 #include "components/payments/core/payment_request_delegate.h"
@@ -64,7 +64,7 @@
   network::TestURLLoaderFactory test_url_loader_factory_;
   scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
   autofill::TestAutofillClient autofill_client_;
-  autofill::payments::PaymentsClient payments_client_;
+  autofill::payments::PaymentsNetworkInterface payments_network_interface_;
   autofill::payments::FullCardRequest full_card_request_;
 
   bool instantaneous_full_card_request_result_ = true;
diff --git a/components/services/app_service/public/cpp/BUILD.gn b/components/services/app_service/public/cpp/BUILD.gn
index ec3465e..4fb86b0 100644
--- a/components/services/app_service/public/cpp/BUILD.gn
+++ b/components/services/app_service/public/cpp/BUILD.gn
@@ -326,6 +326,7 @@
     sources += [
       "app_storage/app_storage_file_handler_unittest.cc",
       "app_storage/app_storage_unittest.cc",
+      "icon_types_unittest.cc",
       "instance_registry_unittest.cc",
       "instance_unittest.cc",
       "instance_update_unittest.cc",
diff --git a/components/services/app_service/public/cpp/app_update.cc b/components/services/app_service/public/cpp/app_update.cc
index 24e6342..6dc995fb 100644
--- a/components/services/app_service/public/cpp/app_update.cc
+++ b/components/services/app_service/public/cpp/app_update.cc
@@ -99,33 +99,10 @@
     return icon_key;
   }
 
-  if (!delta || !delta->icon_key.has_value()) {
-    if (state && state->icon_key.has_value()) {
-      return std::move(*state->icon_key->Clone());
-    }
-    return absl::nullopt;
-  }
-
-  IconKey icon_key =
-      IconKey(delta->icon_key->resource_id, delta->icon_key->icon_effects);
-
-  if (delta->icon_key->resource_id != IconKey::kInvalidResourceId) {
-    icon_key.update_version = IconKey::kInvalidVersion;
-    return icon_key;
-  }
-
-  if (!state || !state->icon_key.has_value()) {
-    icon_key.update_version = IconKey::kInitVersion;
-    return icon_key;
-  }
-
-  icon_key.update_version = absl::get<int32_t>(state->icon_key->update_version);
-
-  // The icon is updated by the app, so increase `update_version`.
-  if (delta->icon_key->HasUpdatedVersion()) {
-    icon_key.update_version = absl::get<int32_t>(icon_key.update_version) + 1;
-  }
-  return icon_key;
+  return MergeIconKey(
+      state && state->icon_key.has_value() ? &state->icon_key.value() : nullptr,
+      delta && delta->icon_key.has_value() ? &delta->icon_key.value()
+                                           : nullptr);
 }
 
 bool MergeWithoutIconKey(App* state, const App* delta) {
diff --git a/components/services/app_service/public/cpp/icon_types.cc b/components/services/app_service/public/cpp/icon_types.cc
index 870153e..e0327bd 100644
--- a/components/services/app_service/public/cpp/icon_types.cc
+++ b/components/services/app_service/public/cpp/icon_types.cc
@@ -45,4 +45,40 @@
 IconValue::IconValue() = default;
 IconValue::~IconValue() = default;
 
+absl::optional<apps::IconKey> MergeIconKey(const apps::IconKey* state,
+                                           const apps::IconKey* delta) {
+  //`state` should have int32_t `update_version` only.
+  CHECK(!state || absl::holds_alternative<int32_t>(state->update_version));
+
+  // `delta` should hold a bool icon version only.
+  CHECK(!delta || absl::holds_alternative<bool>(delta->update_version));
+
+  if (!delta) {
+    if (state) {
+      return std::move(*state->Clone());
+    }
+    return absl::nullopt;
+  }
+
+  IconKey icon_key = IconKey(delta->resource_id, delta->icon_effects);
+
+  if (delta->resource_id != IconKey::kInvalidResourceId) {
+    icon_key.update_version = IconKey::kInvalidVersion;
+    return icon_key;
+  }
+
+  if (!state) {
+    icon_key.update_version = IconKey::kInitVersion;
+    return icon_key;
+  }
+
+  icon_key.update_version = absl::get<int32_t>(state->update_version);
+
+  // The icon is updated by the app, so increase `update_version`.
+  if (delta->HasUpdatedVersion()) {
+    ++absl::get<int32_t>(icon_key.update_version);
+  }
+  return icon_key;
+}
+
 }  // namespace apps
diff --git a/components/services/app_service/public/cpp/icon_types.h b/components/services/app_service/public/cpp/icon_types.h
index 10b6743d..12f5d31 100644
--- a/components/services/app_service/public/cpp/icon_types.h
+++ b/components/services/app_service/public/cpp/icon_types.h
@@ -9,6 +9,7 @@
 
 #include "base/component_export.h"
 #include "base/functional/callback.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/abseil-cpp/absl/types/variant.h"
 #include "ui/gfx/image/image_skia.h"
 
@@ -149,6 +150,12 @@
 using IconValuePtr = std::unique_ptr<IconValue>;
 using LoadIconCallback = base::OnceCallback<void(IconValuePtr)>;
 
+// Merges `delta` to `state`, and  returns's the merge result. If `delta`'s
+// `update_version` is true, increase `state`'s `update_version`.
+COMPONENT_EXPORT(APP_TYPES)
+absl::optional<apps::IconKey> MergeIconKey(const apps::IconKey* state,
+                                           const apps::IconKey* delta);
+
 }  // namespace apps
 
 #endif  // COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_ICON_TYPES_H_
diff --git a/components/services/app_service/public/cpp/icon_types_unittest.cc b/components/services/app_service/public/cpp/icon_types_unittest.cc
new file mode 100644
index 0000000..cedb7cd
--- /dev/null
+++ b/components/services/app_service/public/cpp/icon_types_unittest.cc
@@ -0,0 +1,112 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/services/app_service/public/cpp/icon_types.h"
+
+#include "components/services/app_service/public/cpp/icon_effects.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace apps {
+
+using IconTypesTest = testing::Test;
+
+TEST_F(IconTypesTest, VerifyMergeBothAreNull) {
+  auto icon_key = MergeIconKey(nullptr, nullptr);
+  EXPECT_FALSE(icon_key.has_value());
+}
+
+TEST_F(IconTypesTest, VerifyMergeDeltaIsNull) {
+  {
+    IconKey state(/*resource_id=*/65535, IconEffects::kCrOsStandardIcon);
+    state.update_version = IconKey::kInvalidResourceId;
+
+    auto icon_key = MergeIconKey(&state, nullptr);
+    ASSERT_TRUE(icon_key.has_value());
+    EXPECT_EQ(state, icon_key.value());
+  }
+  {
+    IconKey state(IconKey::kInvalidResourceId, IconEffects::kBlocked);
+    state.update_version = IconKey::kInitVersion;
+
+    auto icon_key = MergeIconKey(&state, nullptr);
+    ASSERT_TRUE(icon_key.has_value());
+    EXPECT_EQ(state, icon_key.value());
+  }
+}
+
+TEST_F(IconTypesTest, VerifyMergeStateIsNull) {
+  {
+    IconKey delta(/*resource_id=*/65535, IconEffects::kChromeBadge);
+    delta.update_version = false;
+
+    auto icon_key = MergeIconKey(nullptr, &delta);
+    IconKey state(delta.resource_id, delta.icon_effects);
+    state.update_version = IconKey::kInvalidVersion;
+    ASSERT_TRUE(icon_key.has_value());
+    EXPECT_EQ(state, icon_key.value());
+  }
+  {
+    IconKey delta(IconKey::kInvalidResourceId,
+                  IconEffects::kCrOsStandardIcon | IconEffects::kPaused);
+    delta.update_version = false;
+
+    auto icon_key = MergeIconKey(nullptr, &delta);
+    IconKey state(delta.resource_id, delta.icon_effects);
+    state.update_version = IconKey::kInitVersion;
+    ASSERT_TRUE(icon_key.has_value());
+    EXPECT_EQ(state, icon_key.value());
+  }
+  {
+    IconKey delta(IconKey::kInvalidResourceId,
+                  IconEffects::kCrOsStandardIcon | IconEffects::kBlocked);
+    delta.update_version = true;
+
+    auto icon_key = MergeIconKey(nullptr, &delta);
+    IconKey state(delta.resource_id, delta.icon_effects);
+    state.update_version = IconKey::kInitVersion;
+    ASSERT_TRUE(icon_key.has_value());
+    EXPECT_EQ(state, icon_key.value());
+  }
+}
+
+TEST_F(IconTypesTest, VerifyMergeBothAreNotNull) {
+  {
+    IconKey state(/*resource_id=*/65535, IconEffects::kNone);
+    state.update_version = IconKey::kInvalidVersion;
+    IconKey delta(/*resource_id=*/65535, IconEffects::kChromeBadge);
+    delta.update_version = false;
+
+    auto icon_key = MergeIconKey(&state, &delta);
+    state.icon_effects = delta.icon_effects;
+    ASSERT_TRUE(icon_key.has_value());
+    EXPECT_EQ(state, icon_key.value());
+  }
+  {
+    IconKey state(IconKey::kInvalidResourceId, IconEffects::kNone);
+    state.update_version = IconKey::kInitVersion;
+    IconKey delta(IconKey::kInvalidResourceId,
+                  IconEffects::kCrOsStandardIcon | IconEffects::kPaused);
+    delta.update_version = false;
+
+    auto icon_key = MergeIconKey(&state, &delta);
+    state.icon_effects = delta.icon_effects;
+    ASSERT_TRUE(icon_key.has_value());
+    EXPECT_EQ(state, icon_key.value());
+  }
+  {
+    IconKey state(IconKey::kInvalidResourceId, IconEffects::kChromeBadge);
+    state.update_version = 100;
+    IconKey delta(IconKey::kInvalidResourceId,
+                  IconEffects::kChromeBadge | IconEffects::kPaused);
+    delta.update_version = true;
+
+    auto icon_key = MergeIconKey(&state, &delta);
+    state.icon_effects = delta.icon_effects;
+    ++absl::get<int32_t>(state.update_version);
+    ASSERT_TRUE(icon_key.has_value());
+    EXPECT_EQ(state, icon_key.value());
+  }
+}
+
+}  // namespace apps
diff --git a/components/services/app_service/public/cpp/shortcut/BUILD.gn b/components/services/app_service/public/cpp/shortcut/BUILD.gn
index 3cdc5a9..eac46af2 100644
--- a/components/services/app_service/public/cpp/shortcut/BUILD.gn
+++ b/components/services/app_service/public/cpp/shortcut/BUILD.gn
@@ -39,6 +39,7 @@
   deps = [
     ":shortcut",
     "//base",
+    "//components/services/app_service/public/cpp:app_types",
     "//testing/gtest",
   ]
 }
diff --git a/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache.cc b/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache.cc
index 484a5ae3..7eacd05 100644
--- a/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache.cc
+++ b/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache.cc
@@ -46,7 +46,12 @@
   if (state) {
     ShortcutUpdate::Merge(state, delta.get());
   } else {
-    states_.emplace(shortcut_id, delta->Clone());
+    // Call ShortcutUpdate::Merge to set the init value for the icon key's
+    // `update_version`.
+    auto shortcut =
+        std::make_unique<Shortcut>(delta->host_app_id, delta->local_id);
+    ShortcutUpdate::Merge(shortcut.get(), delta.get());
+    states_.emplace(shortcut_id, std::move(shortcut));
   }
 
   for (auto& obs : observers_) {
diff --git a/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache_unittest.cc b/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache_unittest.cc
index 9a456ee..5052fafa 100644
--- a/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache_unittest.cc
+++ b/components/services/app_service/public/cpp/shortcut/shortcut_registry_cache_unittest.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/scoped_observation.h"
+#include "components/services/app_service/public/cpp/icon_effects.h"
 #include "components/services/app_service/public/cpp/shortcut/shortcut.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -81,7 +82,7 @@
   shortcut->name = "name";
   shortcut->shortcut_source = ShortcutSource::kUser;
   shortcut->icon_key = IconKey();
-  shortcut->icon_key->update_version = 100;
+  shortcut->icon_key->update_version = false;
 
   EXPECT_FALSE(cache().HasShortcut(shortcut_id));
   cache().UpdateShortcut(std::move(shortcut));
@@ -96,7 +97,7 @@
   EXPECT_EQ(stored_shortcut->host_app_id, host_app_id);
   EXPECT_EQ(stored_shortcut->local_id, local_id);
   IconKey icon_key;
-  icon_key.update_version = 100;
+  icon_key.update_version = IconKey::kInitVersion;
   EXPECT_EQ(stored_shortcut->icon_key, icon_key);
 
   EXPECT_EQ(cache().GetAllShortcuts().size(), 1u);
@@ -110,7 +111,7 @@
   shortcut->name = "name";
   shortcut->shortcut_source = ShortcutSource::kUser;
   shortcut->icon_key = IconKey();
-  shortcut->icon_key->update_version = 100;
+  shortcut->icon_key->update_version = false;
 
   EXPECT_FALSE(cache().HasShortcut(shortcut_id));
   cache().UpdateShortcut(std::move(shortcut));
@@ -121,8 +122,9 @@
   auto shortcut_delta = std::make_unique<Shortcut>(host_app_id, local_id);
   shortcut_delta->name = "new name";
   shortcut_delta->shortcut_source = ShortcutSource::kDeveloper;
-  shortcut_delta->icon_key = IconKey(1, 1);
-  shortcut_delta->icon_key->update_version = 101;
+  shortcut_delta->icon_key =
+      IconKey(IconKey::kInvalidResourceId, IconEffects::kCrOsStandardIcon);
+  shortcut_delta->icon_key->update_version = true;
 
   cache().UpdateShortcut(std::move(shortcut_delta));
 
@@ -136,8 +138,8 @@
   EXPECT_EQ(stored_shortcut->shortcut_source, ShortcutSource::kDeveloper);
   EXPECT_EQ(stored_shortcut->host_app_id, host_app_id);
   EXPECT_EQ(stored_shortcut->local_id, local_id);
-  IconKey icon_key(1, 1);
-  icon_key.update_version = 101;
+  IconKey icon_key(IconKey::kInvalidResourceId, IconEffects::kCrOsStandardIcon);
+  icon_key.update_version = IconKey::kInitVersion + 1;
   EXPECT_EQ(stored_shortcut->icon_key, icon_key);
 }
 
@@ -149,7 +151,7 @@
   shortcut->name = "name";
   shortcut->shortcut_source = ShortcutSource::kUser;
   shortcut->icon_key = IconKey();
-  shortcut->icon_key->update_version = 100;
+  shortcut->icon_key->update_version = false;
 
   cache().UpdateShortcut(std::move(shortcut));
   ASSERT_TRUE(cache().HasShortcut(shortcut_id));
@@ -169,7 +171,7 @@
   shortcut->name = "name";
   shortcut->shortcut_source = ShortcutSource::kUser;
   shortcut->icon_key = IconKey();
-  shortcut->icon_key->update_version = 100;
+  shortcut->icon_key->update_version = false;
   ExpectShortcutUpdate(
       std::make_unique<ShortcutUpdate>(nullptr, shortcut.get()));
   ASSERT_NO_FATAL_FAILURE(cache().UpdateShortcut(std::move(shortcut)));
@@ -178,8 +180,8 @@
   auto shortcut_delta = std::make_unique<Shortcut>(host_app_id, local_id);
   shortcut_delta->name = "new name";
   shortcut_delta->shortcut_source = ShortcutSource::kDeveloper;
-  shortcut_delta->icon_key = IconKey(1, 1);
-  shortcut_delta->icon_key->update_version = 101;
+  shortcut_delta->icon_key = IconKey(/*resource_id=*/1, /*icon_effects=*/1);
+  shortcut_delta->icon_key->update_version = false;
   std::unique_ptr<Shortcut> current_state =
       cache().GetShortcut(shortcut_id)->Clone();
   ExpectShortcutUpdate(std::make_unique<ShortcutUpdate>(current_state.get(),
diff --git a/components/services/app_service/public/cpp/shortcut/shortcut_update.cc b/components/services/app_service/public/cpp/shortcut/shortcut_update.cc
index cc599cc..24115a23 100644
--- a/components/services/app_service/public/cpp/shortcut/shortcut_update.cc
+++ b/components/services/app_service/public/cpp/shortcut/shortcut_update.cc
@@ -71,9 +71,10 @@
   SET_OPTIONAL_VALUE(name);
   SET_ENUM_VALUE(shortcut_source, ShortcutSource::kUnknown);
 
-  if (delta->icon_key.has_value()) {
-    state->icon_key = std::move(*delta->icon_key->Clone());
-  }
+  state->icon_key = MergeIconKey(
+      state && state->icon_key.has_value() ? &state->icon_key.value() : nullptr,
+      delta && delta->icon_key.has_value() ? &delta->icon_key.value()
+                                           : nullptr);
 
   // When adding new fields to the Shortcut struct, this function should also
   // be updated.
@@ -109,17 +110,22 @@
 }
 
 absl::optional<apps::IconKey> ShortcutUpdate::IconKey() const {
-  if (delta_ && delta_->icon_key.has_value()) {
-    return std::move(*delta_->icon_key->Clone());
-  }
-  if (state_ && state_->icon_key.has_value()) {
-    return std::move(*state_->icon_key->Clone());
-  }
-  return absl::nullopt;
+  return MergeIconKey(
+      state_ && state_->icon_key.has_value() ? &state_->icon_key.value()
+                                             : nullptr,
+      delta_ && delta_->icon_key.has_value() ? &delta_->icon_key.value()
+                                             : nullptr);
 }
 
 bool ShortcutUpdate::IconKeyChanged() const {
-  RETURN_OPTIONAL_VALUE_CHANGED(icon_key);
+  if (!delta_ || !delta_->icon_key.has_value()) {
+    return false;
+  }
+  if (!state_ || !state_->icon_key.has_value()) {
+    return true;
+  }
+  return MergeIconKey(&(state_->icon_key.value()),
+                      &(delta_->icon_key.value())) != state_->icon_key;
 }
 
 bool ShortcutUpdate::ShortcutInitialized() const {
diff --git a/components/services/app_service/public/cpp/shortcut/shortcut_update_unittest.cc b/components/services/app_service/public/cpp/shortcut/shortcut_update_unittest.cc
index 57a82b2..d0f4ea8 100644
--- a/components/services/app_service/public/cpp/shortcut/shortcut_update_unittest.cc
+++ b/components/services/app_service/public/cpp/shortcut/shortcut_update_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "components/services/app_service/public/cpp/icon_effects.h"
 #include "components/services/app_service/public/cpp/shortcut/shortcut.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -49,7 +50,7 @@
   shortcut.name = "Name";
   shortcut.shortcut_source = ShortcutSource::kDeveloper;
   shortcut.icon_key = IconKey();
-  shortcut.icon_key->update_version = 100;
+  shortcut.icon_key->update_version = false;
   ShortcutUpdate u(nullptr, &shortcut);
 
   EXPECT_EQ(u.HostAppId(), host_app_id_);
@@ -63,7 +64,7 @@
   EXPECT_TRUE(u.ShortcutSourceChanged());
 
   IconKey icon_key;
-  icon_key.update_version = 100;
+  icon_key.update_version = IconKey::kInitVersion;
   EXPECT_EQ(u.IconKey(), icon_key);
   EXPECT_TRUE(u.IconKeyChanged());
 
@@ -80,8 +81,8 @@
   Shortcut shortcut_delta = Shortcut(host_app_id_, local_id_);
   shortcut_delta.name = "New name";
   shortcut_delta.shortcut_source = ShortcutSource::kUser;
-  shortcut_delta.icon_key = IconKey(1, 1);
-  shortcut_delta.icon_key->update_version = 101;
+  shortcut_delta.icon_key = IconKey(/*resource_id=*/1, /*icon_effects=*/1);
+  shortcut_delta.icon_key->update_version = false;
 
   ShortcutUpdate u(&shortcut_state, &shortcut_delta);
 
@@ -95,8 +96,8 @@
   EXPECT_EQ(u.ShortcutSource(), ShortcutSource::kUser);
   EXPECT_TRUE(u.ShortcutSourceChanged());
 
-  IconKey icon_key(1, 1);
-  icon_key.update_version = 101;
+  IconKey icon_key(/*resource_id=*/1, /*icon_effects=*/1);
+  icon_key.update_version = IconKey::kInvalidVersion;
   EXPECT_EQ(u.IconKey(), icon_key);
   EXPECT_TRUE(u.IconKeyChanged());
 
@@ -113,8 +114,9 @@
   Shortcut shortcut_delta = Shortcut(host_app_id_, local_id_);
   shortcut_delta.name = "New name";
   shortcut_delta.shortcut_source = ShortcutSource::kUser;
-  shortcut_delta.icon_key = IconKey(1, 1);
-  shortcut_delta.icon_key->update_version = 101;
+  shortcut_delta.icon_key =
+      IconKey(IconKey::kInvalidResourceId, IconEffects::kCrOsStandardIcon);
+  shortcut_delta.icon_key->update_version = true;
 
   ShortcutUpdate::Merge(&shortcut_state, &shortcut_delta);
 
@@ -124,7 +126,7 @@
   EXPECT_EQ(shortcut_state.shortcut_source, ShortcutSource::kUser);
   EXPECT_EQ(shortcut_state.host_app_id, host_app_id_);
   EXPECT_EQ(shortcut_state.local_id, local_id_);
-  IconKey icon_key(1, 1);
+  IconKey icon_key(IconKey::kInvalidResourceId, IconEffects::kCrOsStandardIcon);
   icon_key.update_version = 101;
   EXPECT_EQ(shortcut_state.icon_key, icon_key);
 }
diff --git a/components/services/screen_ai/public/mojom/screen_ai_service.mojom b/components/services/screen_ai/public/mojom/screen_ai_service.mojom
index baa8efae..4d80f53f 100644
--- a/components/services/screen_ai/public/mojom/screen_ai_service.mojom
+++ b/components/services/screen_ai/public/mojom/screen_ai_service.mojom
@@ -137,9 +137,13 @@
   // Triggers the service to load and initialize the Screen AI library at
   // |library_path| for OCR. Model files are read from |library_path| folder.
   // This should be called from the browser process.
-  // TODO(crbug.com/1443341): Read all model files from file handles.
+  // |model_files| includes a map from file paths relative to the library base
+  // path, to opened file handles. The list of files is downloaded with the
+  // component. The file handles will be closed once the file is read.
+  // TODO(b/297824387): Replace `string` with `RelativePath`.
   InitializeOCR(
     mojo_base.mojom.FilePath library_path,
+    map<string, mojo_base.mojom.ReadOnlyFile> model_files,
     pending_receiver<OCRService> ocr_service_receiver) =>
       (bool initialized);
 
diff --git a/components/services/screen_ai/sandbox/screen_ai_sandbox_hook_linux.cc b/components/services/screen_ai/sandbox/screen_ai_sandbox_hook_linux.cc
index ec358bb..0e70560e 100644
--- a/components/services/screen_ai/sandbox/screen_ai_sandbox_hook_linux.cc
+++ b/components/services/screen_ai/sandbox/screen_ai_sandbox_hook_linux.cc
@@ -70,13 +70,6 @@
       BrokerFilePermission::ReadOnly("/sys/devices/system/cpu/present"));
 #endif
 
-  // The models are in the same folder as the library, and the library requires
-  // read access for them.
-  if (!library_path.empty()) {
-    permissions.push_back(BrokerFilePermission::ReadOnlyRecursive(
-        library_path.DirName().MaybeAsASCII() + base::FilePath::kSeparators));
-  }
-
   instance->StartBrokerProcess(
       MakeBrokerCommandSet({sandbox::syscall_broker::COMMAND_ACCESS,
                             sandbox::syscall_broker::COMMAND_OPEN}),
diff --git a/components/services/screen_ai/screen_ai_library_wrapper.cc b/components/services/screen_ai/screen_ai_library_wrapper.cc
index c010bbd..202a629b 100644
--- a/components/services/screen_ai/screen_ai_library_wrapper.cc
+++ b/components/services/screen_ai/screen_ai_library_wrapper.cc
@@ -100,7 +100,7 @@
   }
 
 #if !BUILDFLAG(IS_WIN)
-  if (!LoadFunction(init_ocr_, "InitOCR") ||
+  if (!LoadFunction(init_ocr_, "InitOCRUsingCallback") ||
       !LoadFunction(perform_ocr_, "PerformOCR")) {
     return false;
   }
@@ -154,9 +154,9 @@
 }
 
 NO_SANITIZE("cfi-icall")
-bool ScreenAILibraryWrapper::InitOCR(const base::FilePath& models_folder) {
+bool ScreenAILibraryWrapper::InitOCR() {
   CHECK(init_ocr_);
-  return init_ocr_(models_folder.MaybeAsASCII().c_str());
+  return init_ocr_();
 }
 
 NO_SANITIZE("cfi-icall")
diff --git a/components/services/screen_ai/screen_ai_library_wrapper.h b/components/services/screen_ai/screen_ai_library_wrapper.h
index e9f711d..1a409ec 100644
--- a/components/services/screen_ai/screen_ai_library_wrapper.h
+++ b/components/services/screen_ai/screen_ai_library_wrapper.h
@@ -55,7 +55,7 @@
   void EnableDebugMode();
   bool InitLayoutExtraction();
 
-  bool InitOCR(const base::FilePath& models_folder);
+  bool InitOCR();
   bool InitMainContentExtraction();
 
   absl::optional<chrome_screen_ai::VisualAnnotation> ExtractLayout(
@@ -96,10 +96,7 @@
   InitLayoutExtractionFn init_layout_extraction_ = nullptr;
 
   // Initializes the pipeline for OCR.
-  // |models_folder| is a null terminated string pointing to the
-  // folder that includes model files for OCR.
-  // TODO(b/297824387): Remove |models_folder|.
-  typedef bool (*InitOCRFn)(const char* /*models_folder*/);
+  typedef bool (*InitOCRFn)();
   InitOCRFn init_ocr_ = nullptr;
 
   // Initializes the pipeline for main content extraction.
diff --git a/components/services/screen_ai/screen_ai_service_impl.cc b/components/services/screen_ai/screen_ai_service_impl.cc
index 42e1add..9802c1c 100644
--- a/components/services/screen_ai/screen_ai_service_impl.cc
+++ b/components/services/screen_ai/screen_ai_service_impl.cc
@@ -184,6 +184,9 @@
         main_content_extractor_service_receiver,
     InitializeMainContentExtractionCallback callback,
     std::unique_ptr<PreloadedModelData> model_data) {
+  // `model_data` contains the content of the model files and its accessors are
+  // passed to the library. It should be kept in memory until after library
+  // initialization.
   bool init_successful = library_->InitMainContentExtraction();
   base::UmaHistogramBoolean(
       "Accessibility.ScreenAI.MainContentExtraction.Initialized",
@@ -204,6 +207,7 @@
 
 void ScreenAIService::InitializeOCR(
     const base::FilePath& library_path,
+    base::flat_map<std::string, base::File> model_files,
     mojo::PendingReceiver<mojom::OCRService> ocr_service_receiver,
     InitializeOCRCallback callback) {
   if (!library_) {
@@ -214,8 +218,23 @@
     std::move(callback).Run(false);
     base::Process::TerminateCurrentProcessImmediately(-1);
   }
+  base::ThreadPool::PostTaskAndReplyWithResult(
+      FROM_HERE,
+      {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
+      base::BindOnce(&PreloadedModelData::Create, std::move(model_files)),
+      base::BindOnce(&ScreenAIService::InitializeOCRInternal,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     std::move(ocr_service_receiver), std::move(callback)));
+}
 
-  bool init_successful = library_->InitOCR(library_path.DirName());
+void ScreenAIService::InitializeOCRInternal(
+    mojo::PendingReceiver<mojom::OCRService> ocr_service_receiver,
+    InitializeMainContentExtractionCallback callback,
+    std::unique_ptr<PreloadedModelData> model_data) {
+  // `model_data` contains the content of the model files and its accessors are
+  // passed to the library. It should be kept in memory until after library
+  // initialization.
+  bool init_successful = library_->InitOCR();
   base::UmaHistogramBoolean("Accessibility.ScreenAI.OCR.Initialized",
                             init_successful);
 
diff --git a/components/services/screen_ai/screen_ai_service_impl.h b/components/services/screen_ai/screen_ai_service_impl.h
index cef92fd..16d61b6 100644
--- a/components/services/screen_ai/screen_ai_service_impl.h
+++ b/components/services/screen_ai/screen_ai_service_impl.h
@@ -89,6 +89,7 @@
   // mojom::ScreenAIServiceFactory:
   void InitializeOCR(
       const base::FilePath& library_path,
+      base::flat_map<std::string, base::File> model_files,
       mojo::PendingReceiver<mojom::OCRService> ocr_service_receiver,
       InitializeOCRCallback callback) override;
 
@@ -111,6 +112,11 @@
       InitializeMainContentExtractionCallback callback,
       std::unique_ptr<PreloadedModelData> model_data);
 
+  void InitializeOCRInternal(
+      mojo::PendingReceiver<mojom::OCRService> ocr_service_receiver,
+      InitializeMainContentExtractionCallback callback,
+      std::unique_ptr<PreloadedModelData> model_data);
+
   // Wrapper to call `PerformOcr` library function and record metrics.
   absl::optional<chrome_screen_ai::VisualAnnotation> PerformOcrAndRecordMetrics(
       const SkBitmap& image);
diff --git a/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/AndroidStylusWritingHandler.java b/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/AndroidStylusWritingHandler.java
index a83ff28..8b6515a1 100644
--- a/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/AndroidStylusWritingHandler.java
+++ b/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/AndroidStylusWritingHandler.java
@@ -22,7 +22,6 @@
 
 import org.chromium.base.Log;
 import org.chromium.content_public.browser.StylusWritingHandler;
-import org.chromium.content_public.browser.StylusWritingImeCallback;
 import org.chromium.content_public.browser.WebContents;
 
 import java.util.List;
@@ -109,7 +108,7 @@
     }
 
     @Override
-    public boolean requestStartStylusWriting(StylusWritingImeCallback imeCallback) {
+    public boolean requestStartStylusWriting() {
         Log.d(TAG, "Requesting Stylus Writing");
         StylusApiOption.recordStylusHandwritingTriggered(Api.ANDROID);
         mInputMethodManager.startStylusHandwriting(mTargetView);
diff --git a/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/DirectWritingBundleUtil.java b/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/DirectWritingBundleUtil.java
index 51f00c0..590ef73df 100644
--- a/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/DirectWritingBundleUtil.java
+++ b/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/DirectWritingBundleUtil.java
@@ -5,6 +5,7 @@
 package org.chromium.components.stylus_handwriting;
 
 import static android.widget.directwriting.IDirectWritingService.KEY_BUNDLE_EDIT_RECT;
+import static android.widget.directwriting.IDirectWritingService.KEY_BUNDLE_EDIT_RECT_RELOCATED;
 import static android.widget.directwriting.IDirectWritingService.KEY_BUNDLE_EVENT;
 import static android.widget.directwriting.IDirectWritingService.KEY_BUNDLE_ROOT_VIEW_RECT;
 import static android.widget.directwriting.IDirectWritingService.KEY_BUNDLE_SERVICE_HOST_SOURCE;
@@ -48,10 +49,11 @@
         return new Rect(x, y, x + width, y + height);
     }
 
-    static Bundle buildBundle(Rect rect, View rootView) {
+    static Bundle buildBundle(Rect rect, View rootView, boolean isOnlyRectChanged) {
         Bundle bundle = new Bundle();
         bundle.putParcelable(KEY_BUNDLE_EDIT_RECT, rect);
         bundle.putParcelable(KEY_BUNDLE_ROOT_VIEW_RECT, getViewBoundsOnScreen(rootView));
+        bundle.putBoolean(KEY_BUNDLE_EDIT_RECT_RELOCATED, isOnlyRectChanged);
         bundle.putString(KEY_BUNDLE_SERVICE_HOST_SOURCE, VALUE_BUNDLE_SERVICE_HOST_SOURCE_WEBVIEW);
         return bundle;
     }
diff --git a/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/DirectWritingServiceBinder.java b/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/DirectWritingServiceBinder.java
index 41fcd8b..478de37 100644
--- a/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/DirectWritingServiceBinder.java
+++ b/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/DirectWritingServiceBinder.java
@@ -260,11 +260,12 @@
         }
     }
 
-    void updateEditableBounds(Rect editableBounds, View rootView) {
+    void updateEditableBounds(Rect editableBounds, View rootView, boolean isOnlyRectChanged) {
         if (!isServiceConnected()) return;
         try {
             mRemoteDwService.onBoundedEditTextChanged(
-                    DirectWritingBundleUtil.buildBundle(editableBounds, rootView));
+                    DirectWritingBundleUtil.buildBundle(
+                            editableBounds, rootView, isOnlyRectChanged));
         } catch (DeadObjectException e) {
             Log.e(TAG, "updateEditableBounds failed due to DeadObjectException.", e);
             resetDwServiceConnection();
diff --git a/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/DirectWritingTrigger.java b/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/DirectWritingTrigger.java
index 3a7023e..5bc5b221 100644
--- a/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/DirectWritingTrigger.java
+++ b/components/stylus_handwriting/android/java/src/org/chromium/components/stylus_handwriting/DirectWritingTrigger.java
@@ -73,6 +73,10 @@
     public void onWebContentsChanged(Context context, WebContents webContents) {
         updateDWSettings(context);
         webContents.setStylusWritingHandler(this);
+        // TODO(crbug.com/1457860): Drop StylusHandwritingImeCallback reference when webContents is
+        // destroyed.
+        mStylusWritingImeCallback = webContents.getStylusWritingImeCallback();
+        mCallback.setImeCallback(mStylusWritingImeCallback);
     }
 
     @Override
@@ -98,7 +102,7 @@
         if (isEditable) {
             if (!mStylusWritingDetected && mNeedsFocusedNodeChangedAfterTouchUp
                     && mStylusUpEvent != null) {
-                mBinder.updateEditableBounds(roundedBounds, currentView);
+                mBinder.updateEditableBounds(roundedBounds, currentView, true);
                 // Call onStopRecognition with editable bounds to show DW toolbar on Pen TAP in
                 // input field.
                 onStopRecognition(mStylusUpEvent, roundedBounds, currentView);
@@ -116,10 +120,8 @@
     }
 
     @Override
-    public boolean requestStartStylusWriting(StylusWritingImeCallback imeCallback) {
+    public boolean requestStartStylusWriting() {
         if (!mDwServiceEnabled || !mBinder.isServiceConnected()) return false;
-        mStylusWritingImeCallback = imeCallback;
-        mCallback.setImeCallback(imeCallback);
         StylusApiOption.recordStylusHandwritingTriggered(Api.DIRECT_WRITING);
         mStylusWritingDetected = true;
         // We know writing can be started but wait for onEditElementFocusedForStylusWriting to be
@@ -171,18 +173,21 @@
         // enabled. Platform Crash occurs if it is created when DW setting is not enabled.
         if (mCallback != null) return;
         mCallback = new DirectWritingServiceCallback();
-        mCallback.setTriggerCallback(new DirectWritingServiceCallback.TriggerCallback() {
-            @Override
-            public void updateEditableBoundsToService() {
-                mBinder.updateEditableBounds(
-                        mEditableNodeBounds, mStylusWritingImeCallback.getContainerView());
-            }
+        mCallback.setTriggerCallback(
+                new DirectWritingServiceCallback.TriggerCallback() {
+                    @Override
+                    public void updateEditableBoundsToService() {
+                        mBinder.updateEditableBounds(
+                                mEditableNodeBounds,
+                                mStylusWritingImeCallback.getContainerView(),
+                                true);
+                    }
 
-            @Override
-            public boolean isHandwritingIconShowing() {
-                return mIsHandwritingIconShowing;
-            }
-        });
+                    @Override
+                    public boolean isHandwritingIconShowing() {
+                        return mIsHandwritingIconShowing;
+                    }
+                });
     }
 
     @Override
@@ -442,7 +447,7 @@
         startRecognition(focusedEditBounds);
         mCallback.updateEditableBounds(focusedEditBounds, cursorPosition);
         mBinder.updateEditableBounds(
-                focusedEditBounds, mStylusWritingImeCallback.getContainerView());
+                focusedEditBounds, mStylusWritingImeCallback.getContainerView(), false);
         return editorBoundsInfo;
     }
 
diff --git a/components/stylus_handwriting/android/junit/src/org/chromium/components/stylus_handwriting/AndroidStylusWritingHandlerTest.java b/components/stylus_handwriting/android/junit/src/org/chromium/components/stylus_handwriting/AndroidStylusWritingHandlerTest.java
index 4c4ae136..3c955530 100644
--- a/components/stylus_handwriting/android/junit/src/org/chromium/components/stylus_handwriting/AndroidStylusWritingHandlerTest.java
+++ b/components/stylus_handwriting/android/junit/src/org/chromium/components/stylus_handwriting/AndroidStylusWritingHandlerTest.java
@@ -176,7 +176,7 @@
         HistogramWatcher histogramWatcher =
                 HistogramWatcher.newSingleRecordWatcher(
                         "InputMethod.StylusHandwriting.Triggered", StylusApiOption.Api.ANDROID);
-        mHandler.requestStartStylusWriting(null);
+        mHandler.requestStartStylusWriting();
         histogramWatcher.assertExpected();
     }
 
diff --git a/components/stylus_handwriting/android/junit/src/org/chromium/components/stylus_handwriting/DirectWritingTriggerTest.java b/components/stylus_handwriting/android/junit/src/org/chromium/components/stylus_handwriting/DirectWritingTriggerTest.java
index dd08eccc2..4c2d8e65 100644
--- a/components/stylus_handwriting/android/junit/src/org/chromium/components/stylus_handwriting/DirectWritingTriggerTest.java
+++ b/components/stylus_handwriting/android/junit/src/org/chromium/components/stylus_handwriting/DirectWritingTriggerTest.java
@@ -109,11 +109,13 @@
     @Feature({"Stylus Handwriting"})
     public void testOnWebContentsChanged() {
         // Test that settings are updated and callback is created if null, when WebContents is set.
-        assertNull(mDwTrigger.getServiceCallback());
+        mDwTrigger.setServiceCallbackForTest(mDwServiceCallback);
+        doReturn(mStylusWritingImeCallback).when(mWebContents).getStylusWritingImeCallback();
         mDwTrigger.onWebContentsChanged(mContext, mWebContents);
         verify(mDwTrigger).updateDWSettings(mContext);
-        assertNotNull(mDwTrigger.getServiceCallback());
         verify(mWebContents).setStylusWritingHandler(mDwTrigger);
+        verify(mWebContents).getStylusWritingImeCallback();
+        verify(mDwServiceCallback).setImeCallback(mStylusWritingImeCallback);
     }
 
     @Test
@@ -151,8 +153,9 @@
         verify(mDwServiceBinder, never()).onStopRecognition(any(), any(), any());
 
         doReturn(true).when(mDwServiceBinder).isServiceConnected();
-        // Set Ime callback via requestStartStylusWriting.
-        assertTrue(mDwTrigger.requestStartStylusWriting(mStylusWritingImeCallback));
+        // Set Ime callback via onWebContentsChanged.
+        doReturn(mStylusWritingImeCallback).when(mWebContents).getStylusWritingImeCallback();
+        mDwTrigger.onWebContentsChanged(mContext, mWebContents);
         mDwTrigger.onFocusChanged(false);
         verify(mDwServiceBinder).onStopRecognition(null, null, mContainerView);
     }
@@ -173,13 +176,11 @@
     public void testRequestStartStylusWriting() {
         mDwTrigger.updateDWSettings(mContext);
         // requestStartStylusWriting returns false until service is connected.
-        assertFalse(mDwTrigger.requestStartStylusWriting(mStylusWritingImeCallback));
+        assertFalse(mDwTrigger.requestStartStylusWriting());
         assertFalse(mDwTrigger.stylusWritingDetected());
 
         doReturn(true).when(mDwServiceBinder).isServiceConnected();
-        mDwTrigger.setServiceCallbackForTest(mDwServiceCallback);
-        assertTrue(mDwTrigger.requestStartStylusWriting(mStylusWritingImeCallback));
-        verify(mDwServiceCallback).setImeCallback(mStylusWritingImeCallback);
+        assertTrue(mDwTrigger.requestStartStylusWriting());
         assertTrue(mDwTrigger.stylusWritingDetected());
     }
 
@@ -312,7 +313,7 @@
                         editableBounds.right * 2,
                         editableBounds.bottom * 2 + 5);
         verify(mDwServiceCallback).updateEditableBounds(eq(scaledBounds), any());
-        verify(mDwServiceBinder).updateEditableBounds(scaledBounds, mContainerView);
+        verify(mDwServiceBinder).updateEditableBounds(scaledBounds, mContainerView, true);
         verify(mDwServiceBinder)
                 .onStopRecognition(eventReceived.capture(), eq(scaledBounds), eq(mContainerView));
         assertEquals(eventReceived.getValue().getAction(), MotionEvent.ACTION_UP);
@@ -336,7 +337,8 @@
         // Verify that hide DW toolbar is called and stop recognition is also called.
         verify(mDwServiceBinder).hideDWToolbar();
         verify(mDwServiceBinder).onStopRecognition(null, null, mContainerView);
-        verify(mDwServiceBinder, never()).updateEditableBounds(editableBounds, mContainerView);
+        verify(mDwServiceBinder, never())
+                .updateEditableBounds(editableBounds, mContainerView, true);
         verify(mDwServiceBinder, never())
                 .onStopRecognition(any(), eq(editableBounds), eq(mContainerView));
     }
diff --git a/components/test/BUILD.gn b/components/test/BUILD.gn
index 9a61511..97685f7 100644
--- a/components/test/BUILD.gn
+++ b/components/test/BUILD.gn
@@ -71,6 +71,10 @@
     testonly = true
     filelist_name = "data/dom_distiller/unit_tests_bundle_data.filelist"
   }
+  bundle_data_from_filelist("feed_test_bundle_data") {
+    testonly = true
+    filelist_name = "data/feed/unit_tests_bundle_data.filelist"
+  }
   bundle_data_from_filelist("fenced_frames_test_bundle_data") {
     testonly = true
     filelist_name = "data/fenced_frames/unit_tests_bundle_data.filelist"
diff --git a/components/test/PRESUBMIT.py b/components/test/PRESUBMIT.py
index 81c136f..62d9821 100644
--- a/components/test/PRESUBMIT.py
+++ b/components/test/PRESUBMIT.py
@@ -24,6 +24,9 @@
                 'data/dom_distiller/unit_tests_bundle_data')
         results += presubmit_support.CheckBundleData(
                 input_api, output_api,
+                'data/feed/unit_tests_bundle_data')
+        results += presubmit_support.CheckBundleData(
+                input_api, output_api,
                 'data/fenced_frames/unit_tests_bundle_data')
         results += presubmit_support.CheckBundleData(
                 input_api, output_api,
diff --git a/components/test/data/feed/OWNERS b/components/test/data/feed/OWNERS
new file mode 100644
index 0000000..4e6079c
--- /dev/null
+++ b/components/test/data/feed/OWNERS
@@ -0,0 +1,2 @@
+# Anyone can update the test bundle data filelist.
+per-file unit_tests_bundle_data.filelist=*
diff --git a/components/test/data/feed/unit_tests_bundle_data.filelist b/components/test/data/feed/unit_tests_bundle_data.filelist
new file mode 100644
index 0000000..768f1c5
--- /dev/null
+++ b/components/test/data/feed/unit_tests_bundle_data.filelist
@@ -0,0 +1,7 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# NOTE: this file is generated by build/ios/update_bundle_filelist.py
+#       If it requires updating, you should get a presubmit error with
+#       instructions on how to regenerate. Otherwise, do not edit.
+//components/test/data/feed/response.binarypb
diff --git a/components/test/data/feed/unit_tests_bundle_data.globlist b/components/test/data/feed/unit_tests_bundle_data.globlist
new file mode 100644
index 0000000..e1d27f4
--- /dev/null
+++ b/components/test/data/feed/unit_tests_bundle_data.globlist
@@ -0,0 +1,11 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# See build/ios/update_bundle_filelist.py for details on how .globlist
+# files are used to update their .filelist counterparts.
+
+//components/test/data/feed/**
+-//components/test/data/feed/*.filelist
+-//components/test/data/feed/*.globlist
+-//components/test/data/feed/OWNERS
diff --git a/content/browser/attribution_reporting/BUILD.gn b/content/browser/attribution_reporting/BUILD.gn
index 15e49a4..6920d6b 100644
--- a/content/browser/attribution_reporting/BUILD.gn
+++ b/content/browser/attribution_reporting/BUILD.gn
@@ -13,7 +13,6 @@
 mojom("mojo_bindings") {
   sources = [ "attribution_reporting.mojom" ]
   webui_module_path = "/"
-  use_typescript_sources = true
   generate_java = false
   disable_variants = true
   disallow_interfaces = true
@@ -26,7 +25,6 @@
     "store_source_result.mojom",
   ]
   webui_module_path = "/"
-  use_typescript_sources = true
   generate_java = false
   disable_variants = true
   disallow_interfaces = true
@@ -43,7 +41,6 @@
     "//url/mojom:url_mojom_origin",
   ]
   webui_module_path = "/"
-  use_typescript_sources = true
   generate_java = false
   disable_variants = true
 
diff --git a/content/browser/indexed_db/BUILD.gn b/content/browser/indexed_db/BUILD.gn
index 807ae51..652bfd58 100644
--- a/content/browser/indexed_db/BUILD.gn
+++ b/content/browser/indexed_db/BUILD.gn
@@ -7,7 +7,6 @@
 mojom("mojo_bindings") {
   sources = [ "indexed_db_internals.mojom" ]
   webui_module_path = "/"
-  use_typescript_sources = true
 
   public_deps = [
     "//components/services/storage/privileged/mojom:mojom_bucket",
diff --git a/content/browser/preloading/prefetch/no_vary_search_helper.h b/content/browser/preloading/prefetch/no_vary_search_helper.h
index 292aacab..da53301 100644
--- a/content/browser/preloading/prefetch/no_vary_search_helper.h
+++ b/content/browser/preloading/prefetch/no_vary_search_helper.h
@@ -49,18 +49,20 @@
   }
 };
 
-template <typename T>
-class PrefetchKeyTraits<std::pair<T, GURL>> {
+template <>
+class PrefetchKeyTraits<PrefetchContainer::Key> {
  public:
-  using PrefetchKey = std::pair<T, GURL>;
-  static const GURL& GetURL(const PrefetchKey& key) { return key.second; }
-  static PrefetchKey KeyWithNewURL(const PrefetchKey& old_key,
-                                   const GURL& new_url) {
-    return PrefetchKey(old_key.first, new_url);
+  static const GURL& GetURL(const PrefetchContainer::Key& key) {
+    return key.prefetch_url();
   }
-  static bool NonUrlPartIsSame(const PrefetchKey& key1,
-                               const PrefetchKey& key2) {
-    return key1.first == key2.first;
+  static PrefetchContainer::Key KeyWithNewURL(
+      const PrefetchContainer::Key& old_key,
+      const GURL& new_url) {
+    return PrefetchContainer::Key(old_key.referring_document_token(), new_url);
+  }
+  static bool NonUrlPartIsSame(const PrefetchContainer::Key& key1,
+                               const PrefetchContainer::Key& key2) {
+    return key1.referring_document_token() == key2.referring_document_token();
   }
 };
 
diff --git a/content/browser/preloading/prefetch/no_vary_search_helper_unittest.cc b/content/browser/preloading/prefetch/no_vary_search_helper_unittest.cc
index 844199f..d8367c8c 100644
--- a/content/browser/preloading/prefetch/no_vary_search_helper_unittest.cc
+++ b/content/browser/preloading/prefetch/no_vary_search_helper_unittest.cc
@@ -103,7 +103,7 @@
                          blink::mojom::SpeculationEagerness::kEager),
             blink::mojom::Referrer(),
             /*no_vary_search_expected=*/absl::nullopt,
-            blink::mojom::SpeculationInjectionWorld::kNone,
+            blink::mojom::SpeculationInjectionType::kNone,
             /*prefetch_document_manager=*/nullptr);
 
     MakeServableStreamingURLLoaderForTest(prefetch_container.get(),
diff --git a/content/browser/preloading/prefetch/prefetch_container.cc b/content/browser/preloading/prefetch/prefetch_container.cc
index 3865971da..996d9b9 100644
--- a/content/browser/preloading/prefetch/prefetch_container.cc
+++ b/content/browser/preloading/prefetch/prefetch_container.cc
@@ -370,7 +370,7 @@
     const PrefetchType& prefetch_type,
     const blink::mojom::Referrer& referrer,
     absl::optional<net::HttpNoVarySearchData> no_vary_search_hint,
-    blink::mojom::SpeculationInjectionWorld world,
+    blink::mojom::SpeculationInjectionType injection_type,
     base::WeakPtr<PrefetchDocumentManager> prefetch_document_manager,
     PreloadingURLMatchCallback matcher)
     : referring_render_frame_host_id_(referring_render_frame_host_id),
@@ -395,8 +395,8 @@
     }
     auto* attempt = static_cast<PreloadingAttemptImpl*>(
         preloading_data->AddPreloadingAttempt(
-            GetPredictorForSpeculationRules(world), PreloadingType::kPrefetch,
-            std::move(matcher),
+            GetPredictorForSpeculationRules(injection_type),
+            PreloadingType::kPrefetch, std::move(matcher),
             web_contents->GetPrimaryMainFrame()->GetPageUkmSourceId()));
     attempt->SetSpeculationEagerness(prefetch_type.GetEagerness());
     attempt_ = attempt->GetWeakPtr();
@@ -1238,8 +1238,8 @@
 
 std::ostream& operator<<(std::ostream& ostream,
                          const PrefetchContainer::Key& prefetch_key) {
-  return ostream << "(" << prefetch_key.first << ", " << prefetch_key.second
-                 << ")";
+  return ostream << "(" << prefetch_key.referring_document_token() << ", "
+                 << prefetch_key.prefetch_url() << ")";
 }
 
 CONTENT_EXPORT std::ostream& operator<<(
diff --git a/content/browser/preloading/prefetch/prefetch_container.h b/content/browser/preloading/prefetch/prefetch_container.h
index be15e1b..073e8bfc 100644
--- a/content/browser/preloading/prefetch/prefetch_container.h
+++ b/content/browser/preloading/prefetch/prefetch_container.h
@@ -100,7 +100,7 @@
       const PrefetchType& prefetch_type,
       const blink::mojom::Referrer& referrer,
       absl::optional<net::HttpNoVarySearchData> no_vary_search_expected,
-      blink::mojom::SpeculationInjectionWorld world,
+      blink::mojom::SpeculationInjectionType injection_type,
       base::WeakPtr<PrefetchDocumentManager> prefetch_document_manager,
       PreloadingURLMatchCallback matcher = {});
   ~PrefetchContainer();
@@ -109,9 +109,36 @@
   PrefetchContainer& operator=(const PrefetchContainer&) = delete;
 
   // Defines the key to uniquely identify a prefetch.
-  using Key = std::pair<blink::DocumentToken, GURL>;
+  class Key {
+   public:
+    Key() = delete;
+    Key(blink::DocumentToken referring_document_token, GURL prefetch_url)
+        : referring_document_token_(std::move(referring_document_token)),
+          prefetch_url_(std::move(prefetch_url)) {}
+
+    bool operator==(const Key& rhs) const = default;
+    bool operator<(const Key& rhs) const {
+      if (referring_document_token_ != rhs.referring_document_token()) {
+        return referring_document_token_ < rhs.referring_document_token_;
+      }
+      return prefetch_url_ < rhs.prefetch_url_;
+    }
+
+    const blink::DocumentToken& referring_document_token() const {
+      return referring_document_token_;
+    }
+    const GURL& prefetch_url() const { return prefetch_url_; }
+
+   private:
+    friend CONTENT_EXPORT std::ostream& operator<<(std::ostream& ostream,
+                                                   const Key& prefetch_key);
+
+    const blink::DocumentToken referring_document_token_;
+    const GURL prefetch_url_;
+  };
+
   Key GetPrefetchContainerKey() const {
-    return std::make_pair(referring_document_token_, prefetch_url_);
+    return Key(referring_document_token_, prefetch_url_);
   }
 
   // The ID of the RenderFrameHost that triggered the prefetch.
diff --git a/content/browser/preloading/prefetch/prefetch_container_unittest.cc b/content/browser/preloading/prefetch/prefetch_container_unittest.cc
index e32b93a..9bae7ab 100644
--- a/content/browser/preloading/prefetch/prefetch_container_unittest.cc
+++ b/content/browser/preloading/prefetch/prefetch_container_unittest.cc
@@ -149,7 +149,7 @@
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
       /*no_vary_search_expected=*/absl::nullopt,
-      blink::mojom::SpeculationInjectionWorld::kNone,
+      blink::mojom::SpeculationInjectionType::kNone,
       /*prefetch_document_manager=*/nullptr);
 
   EXPECT_EQ(prefetch_container.GetReferringRenderFrameHostId(),
@@ -162,7 +162,7 @@
       prefetch_container.IsIsolatedNetworkContextRequiredForCurrentPrefetch());
 
   EXPECT_EQ(prefetch_container.GetPrefetchContainerKey(),
-            std::make_pair(document_token, GURL("https://test.com")));
+            PrefetchContainer::Key(document_token, GURL("https://test.com")));
   EXPECT_FALSE(prefetch_container.GetHead());
 }
 
@@ -174,7 +174,7 @@
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
       /*no_vary_search_expected=*/absl::nullopt,
-      blink::mojom::SpeculationInjectionWorld::kNone,
+      blink::mojom::SpeculationInjectionType::kNone,
       /*prefetch_document_manager=*/nullptr);
 
   EXPECT_FALSE(prefetch_container.HasPrefetchStatus());
@@ -194,7 +194,7 @@
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
       /*no_vary_search_expected=*/absl::nullopt,
-      blink::mojom::SpeculationInjectionWorld::kNone,
+      blink::mojom::SpeculationInjectionType::kNone,
       /*prefetch_document_manager=*/nullptr);
 
   EXPECT_FALSE(prefetch_container.IsDecoy());
@@ -211,7 +211,7 @@
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
       /*no_vary_search_expected=*/absl::nullopt,
-      blink::mojom::SpeculationInjectionWorld::kNone,
+      blink::mojom::SpeculationInjectionType::kNone,
       /*prefetch_document_manager=*/nullptr);
 
   MakeServableStreamingURLLoaderForTest(
@@ -237,7 +237,7 @@
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
       /*no_vary_search_expected=*/absl::nullopt,
-      blink::mojom::SpeculationInjectionWorld::kNone,
+      blink::mojom::SpeculationInjectionType::kNone,
       /*prefetch_document_manager=*/nullptr);
   prefetch_container.MakeResourceRequest({});
   prefetch_container.RegisterCookieListener(cookie_manager());
@@ -313,7 +313,7 @@
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
       /*no_vary_search_expected=*/absl::nullopt,
-      blink::mojom::SpeculationInjectionWorld::kNone,
+      blink::mojom::SpeculationInjectionType::kNone,
       /*prefetch_document_manager=*/nullptr);
   prefetch_container.RegisterCookieListener(cookie_manager());
 
@@ -375,7 +375,7 @@
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
       /*no_vary_search_expected=*/absl::nullopt,
-      blink::mojom::SpeculationInjectionWorld::kNone,
+      blink::mojom::SpeculationInjectionType::kNone,
       /*prefetch_document_manager=*/nullptr);
   prefetch_container.MakeResourceRequest({});
   prefetch_container.RegisterCookieListener(cookie_manager());
@@ -506,7 +506,7 @@
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
           /*no_vary_search_expected=*/absl::nullopt,
-          blink::mojom::SpeculationInjectionWorld::kNone,
+          blink::mojom::SpeculationInjectionType::kNone,
           /*prefetch_document_manager=*/nullptr);
 
   network::URLLoaderCompletionStatus completion_status;
@@ -628,7 +628,7 @@
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
           /*no_vary_search_expected=*/absl::nullopt,
-          blink::mojom::SpeculationInjectionWorld::kNone,
+          blink::mojom::SpeculationInjectionType::kNone,
           /*prefetch_document_manager=*/nullptr);
   prefetch_container.reset();
 
@@ -701,7 +701,7 @@
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
       /*no_vary_search_expected=*/absl::nullopt,
-      blink::mojom::SpeculationInjectionWorld::kNone,
+      blink::mojom::SpeculationInjectionType::kNone,
       prefetch_document_manager->GetWeakPtr());
   prefetch_container.MakeResourceRequest({});
 
@@ -741,7 +741,7 @@
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
       /*no_vary_search_expected=*/absl::nullopt,
-      blink::mojom::SpeculationInjectionWorld::kNone,
+      blink::mojom::SpeculationInjectionType::kNone,
       prefetch_document_manager->GetWeakPtr());
   prefetch_container.MakeResourceRequest({});
 
@@ -791,7 +791,7 @@
         PrefetchType(/*use_prefetch_proxy=*/true, test_case.eagerness),
         blink::mojom::Referrer(),
         /*no_vary_search_expected=*/absl::nullopt,
-        blink::mojom::SpeculationInjectionWorld::kNone,
+        blink::mojom::SpeculationInjectionType::kNone,
         /*prefetch_document_manager=*/nullptr);
 
     prefetch_container.OnGetPrefetchToServe(test_case.block_until_head);
@@ -849,7 +849,7 @@
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
       /*no_vary_search_expected=*/absl::nullopt,
-      blink::mojom::SpeculationInjectionWorld::kNone,
+      blink::mojom::SpeculationInjectionType::kNone,
       /*prefetch_document_manager=*/nullptr);
   prefetch_container.MakeResourceRequest({});
 
@@ -872,7 +872,7 @@
       PrefetchType(/*use_prefetch_proxy=*/true,
                    blink::mojom::SpeculationEagerness::kEager),
       referrer, /*no_vary_search_expected=*/absl::nullopt,
-      blink::mojom::SpeculationInjectionWorld::kNone,
+      blink::mojom::SpeculationInjectionType::kNone,
       /*prefetch_document_manager=*/nullptr);
   prefetch_container.MakeResourceRequest({});
 
@@ -920,7 +920,7 @@
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
       /*no_vary_search_expected=*/absl::nullopt,
-      blink::mojom::SpeculationInjectionWorld::kNone,
+      blink::mojom::SpeculationInjectionType::kNone,
       /*prefetch_document_manager=*/nullptr);
   prefetch_container->MakeResourceRequest({});
 
@@ -1015,7 +1015,7 @@
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
       /*no_vary_search_expected=*/absl::nullopt,
-      blink::mojom::SpeculationInjectionWorld::kNone,
+      blink::mojom::SpeculationInjectionType::kNone,
       /*prefetch_document_manager=*/nullptr);
   prefetch_container.MakeResourceRequest({});
 
@@ -1146,7 +1146,7 @@
                    blink::mojom::SpeculationEagerness::kEager),
       blink::mojom::Referrer(),
       /*no_vary_search_expected=*/absl::nullopt,
-      blink::mojom::SpeculationInjectionWorld::kNone,
+      blink::mojom::SpeculationInjectionType::kNone,
       /*prefetch_document_manager=*/nullptr);
 
   auto pending_request =
diff --git a/content/browser/preloading/prefetch/prefetch_document_manager.cc b/content/browser/preloading/prefetch/prefetch_document_manager.cc
index 68167767..7865508 100644
--- a/content/browser/preloading/prefetch/prefetch_document_manager.cc
+++ b/content/browser/preloading/prefetch/prefetch_document_manager.cc
@@ -38,7 +38,7 @@
            PrefetchType,
            blink::mojom::Referrer,
            network::mojom::NoVarySearchPtr,
-           blink::mojom::SpeculationInjectionWorld>
+           blink::mojom::SpeculationInjectionType>
 SpeculationCandidateToPrefetchUrlParams(
     const blink::mojom::SpeculationCandidatePtr& candidate) {
   PrefetchType prefetch_type = PrefetchType(
@@ -56,7 +56,7 @@
 
   return std::make_tuple(prefetch_url, prefetch_type, *candidate->referrer,
                          candidate->no_vary_search_hint.Clone(),
-                         candidate->injection_world);
+                         candidate->injection_type);
 }
 
 }  // namespace
@@ -177,7 +177,7 @@
   // code can handle up a layer to |SpeculationHostImpl|.
   std::vector<std::tuple<GURL, PrefetchType, blink::mojom::Referrer,
                          network::mojom::NoVarySearchPtr,
-                         blink::mojom::SpeculationInjectionWorld>>
+                         blink::mojom::SpeculationInjectionType>>
       prefetches;
 
   // Evicts an existing prefetch if there is no longer a matching speculation
@@ -232,9 +232,9 @@
   base::EraseIf(candidates, should_process_entry);
 
   for (auto& [prefetch_url, prefetch_type, referrer, no_vary_search_expected,
-              world] : prefetches) {
+              injection_type] : prefetches) {
     PrefetchUrl(prefetch_url, prefetch_type, referrer, no_vary_search_expected,
-                world, devtools_observer);
+                injection_type, devtools_observer);
   }
 
   if (PrefetchService* prefetch_service = GetPrefetchService()) {
@@ -249,10 +249,10 @@
     return false;
   }
 
-  auto [prefetch_url, prefetch_type, referrer, no_vary_search_expected, world] =
-      SpeculationCandidateToPrefetchUrlParams(candidate);
+  auto [prefetch_url, prefetch_type, referrer, no_vary_search_expected,
+        injection_type] = SpeculationCandidateToPrefetchUrlParams(candidate);
   PrefetchUrl(prefetch_url, prefetch_type, referrer, no_vary_search_expected,
-              world, devtools_observer);
+              injection_type, devtools_observer);
   return true;
 }
 
@@ -261,7 +261,7 @@
     const PrefetchType& prefetch_type,
     const blink::mojom::Referrer& referrer,
     const network::mojom::NoVarySearchPtr& mojo_no_vary_search_expected,
-    blink::mojom::SpeculationInjectionWorld world,
+    blink::mojom::SpeculationInjectionType injection_type,
     base::WeakPtr<SpeculationHostDevToolsObserver> devtools_observer) {
   // Skip any prefetches that have already been requested.
   auto prefetch_container_iter = all_prefetches_.find(url);
@@ -289,7 +289,7 @@
   // Create a new |PrefetchContainer| and take ownership of it
   auto container = std::make_unique<PrefetchContainer>(
       render_frame_host().GetGlobalId(), document_token_, url, prefetch_type,
-      referrer, std::move(no_vary_search_expected), world,
+      referrer, std::move(no_vary_search_expected), injection_type,
       weak_method_factory_.GetWeakPtr(),
       PreloadingDataImpl::GetPrefetchServiceMatcher(
           prefetch_service, PrefetchContainer::Key(document_token_, url)));
diff --git a/content/browser/preloading/prefetch/prefetch_document_manager.h b/content/browser/preloading/prefetch/prefetch_document_manager.h
index 52748cec..022e2b2 100644
--- a/content/browser/preloading/prefetch/prefetch_document_manager.h
+++ b/content/browser/preloading/prefetch/prefetch_document_manager.h
@@ -72,7 +72,7 @@
       const PrefetchType& prefetch_type,
       const blink::mojom::Referrer& referrer,
       const network::mojom::NoVarySearchPtr& no_vary_search_expected,
-      blink::mojom::SpeculationInjectionWorld world,
+      blink::mojom::SpeculationInjectionType injection_type,
       base::WeakPtr<SpeculationHostDevToolsObserver> devtools_observer);
 
   // Checking the canary cache can be a slow and blocking operation (see
diff --git a/content/browser/preloading/prefetch/prefetch_service.cc b/content/browser/preloading/prefetch/prefetch_service.cc
index 433ccbe..2d3086a 100644
--- a/content/browser/preloading/prefetch/prefetch_service.cc
+++ b/content/browser/preloading/prefetch/prefetch_service.cc
@@ -408,8 +408,7 @@
     }
 
     const auto& prefetch_type = prefetch_container->GetPrefetchType();
-    if (prefetch_type.IsProxyRequiredWhenCrossOrigin() &&
-        !prefetch_type.IsProxyBypassedForTesting()) {
+    if (prefetch_type.IsProxyRequiredWhenCrossOrigin()) {
       bool allow_all_domains =
           PrefetchAllowAllDomains() ||
           (PrefetchAllowAllDomainsForExtendedPreloading() &&
@@ -1421,7 +1420,7 @@
                 if (const auto& nvs_expected =
                         prefetch_container->GetNoVarySearchHint()) {
                   if (nvs_expected->AreEquivalent(
-                          key.second, prefetch_container->GetURL())) {
+                          key.prefetch_url(), prefetch_container->GetURL())) {
                     hint_matches->push_back(prefetch_container.get());
                   }
                 }
@@ -1483,7 +1482,7 @@
     const PrefetchContainer::Key& key,
     PrefetchContainer& prefetch_container,
     PrefetchMatchResolver& prefetch_match_resolver) {
-  const GURL& url = key.second;
+  const GURL& url = key.prefetch_url();
   DVLOG(1) << "PrefetchService::HandlePrefetchContainerToServe("
            << prefetch_container << "): Start";
 
@@ -1541,9 +1540,8 @@
       return HandlePrefetchContainerResult::kWaitForHead;
     }
     case PrefetchContainer::ServableState::kNotServable: {
-      DVLOG(1) << "PrefetchService::HandlePrefetchContainerToServe("
-               << key.second << "): " << prefetch_container
-               << " is not servable";
+      DVLOG(1) << "PrefetchService::HandlePrefetchContainerToServe(" << key
+               << "): " << prefetch_container << " is not servable";
       prefetch_container.OnReturnPrefetchToServe(/*served=*/false);
       return HandlePrefetchContainerResult::kNotUsable;
     }
@@ -1558,7 +1556,7 @@
   DumpPrefetchesForDebug();
   auto potential_matching_prefetches = FindPrefetchContainerToServe(
       key, std::move(serving_page_metrics_container));
-  DVLOG(1) << "PrefetchService::GetPrefetchToServe(" << key.second
+  DVLOG(1) << "PrefetchService::GetPrefetchToServe(" << key
            << "): Potential matched with "
            << potential_matching_prefetches.size() << " prefetch containers.";
   bool waiting_on_prefetch_head = false;
@@ -1583,7 +1581,7 @@
   }
   // If not waiting on any prefetches it means there is no match. Let the
   // browser know to request url from the web server.
-  DVLOG(1) << "PrefetchService::GetPrefetchToServe(" << key.second
+  DVLOG(1) << "PrefetchService::GetPrefetchToServe(" << key
            << "): No PrefetchContainer is servable";
   ReturnPrefetchToServe({}, {}, prefetch_match_resolver);
 }
@@ -1610,8 +1608,7 @@
   // Make sure we are not waiting on this prefetch_url anymore.
   CHECK(!prefetch_match_resolver->IsWaitingForPrefetch(prefetch_url));
 
-  const GURL& nav_url = key.second;
-  DVLOG(1) << "PrefetchService::WaitOnPrefetchToServeHead(" << nav_url
+  DVLOG(1) << "PrefetchService::WaitOnPrefetchToServeHead(" << key
            << "): PrefetchContainer head received for " << prefetch_url << "!";
   // This method is registered with the prefetch_container as the
   // ReceivedHeadCallback. We only call this method immediately after
@@ -1623,7 +1620,7 @@
   switch (prefetch_container->GetServableState(PrefetchCacheableDuration())) {
     case PrefetchContainer::ServableState::kNotServable:
     case PrefetchContainer::ServableState::kShouldBlockUntilHeadReceived: {
-      DVLOG(1) << "PrefetchService::WaitOnPrefetchToServeHead(" << nav_url
+      DVLOG(1) << "PrefetchService::WaitOnPrefetchToServeHead(" << key
                << "): " << *prefetch_container << " not servable!";
       prefetch_container->OnReturnPrefetchToServe(/*served=*/false);
       ReturnPrefetchToServe(prefetch_url, {}, *prefetch_match_resolver);
@@ -1633,7 +1630,7 @@
       break;
   }
 
-  if (nav_url == prefetch_container->GetURL()) {
+  if (key.prefetch_url() == prefetch_container->GetURL()) {
     HandlePrefetchContainerToServe(key, *prefetch_container,
                                    *prefetch_match_resolver);
     return;
@@ -1656,16 +1653,15 @@
         no_vary_search::ParseHttpNoVarySearchDataFromMojom(
             head->parsed_headers->no_vary_search_with_parse_error
                 ->get_no_vary_search());
-    if (!no_vary_search_data.AreEquivalent(nav_url,
+    if (!no_vary_search_data.AreEquivalent(key.prefetch_url(),
                                            prefetch_container->GetURL())) {
       prefetch_container->OnReturnPrefetchToServe(/*served=*/false);
       prefetch_container->UpdateServingPageMetrics();
       ReturnPrefetchToServe(prefetch_url, {}, *prefetch_match_resolver);
       return;
     }
-    DVLOG(1) << "PrefetchService::WaitOnPrefetchToServeHead::"
-             << "url = " << nav_url << "::"
-             << "matches by NVS header the prefetch "
+    DVLOG(1) << "PrefetchService::WaitOnPrefetchToServeHead::" << key
+             << "::" << "matches by NVS header the prefetch "
              << prefetch_container->GetURL();
     if (auto attempt = prefetch_container->preloading_attempt()) {
       // Before No-Vary-Search hint, the decision to use a prefetched response
@@ -1677,7 +1673,7 @@
       // have already decided we are going to use the prefetch, so we can
       // safely call `SetIsAccurateTriggering`.
       static_cast<PreloadingAttemptImpl*>(attempt.get())
-          ->SetIsAccurateTriggering(nav_url);
+          ->SetIsAccurateTriggering(key.prefetch_url());
     }
     HandlePrefetchContainerToServe(key, *prefetch_container,
                                    *prefetch_match_resolver);
diff --git a/content/browser/preloading/prefetch/prefetch_service_unittest.cc b/content/browser/preloading/prefetch/prefetch_service_unittest.cc
index b7823bc..9958df92 100644
--- a/content/browser/preloading/prefetch/prefetch_service_unittest.cc
+++ b/content/browser/preloading/prefetch/prefetch_service_unittest.cc
@@ -370,7 +370,7 @@
 
     prefetch_document_manager->PrefetchUrl(
         prefetch_url, prefetch_type, referrer, no_vary_search_hint,
-        blink::mojom::SpeculationInjectionWorld::kNone, nullptr);
+        blink::mojom::SpeculationInjectionType::kNone, nullptr);
   }
 
   int RequestCount() { return test_url_loader_factory_.NumPending(); }
diff --git a/content/browser/preloading/prefetch/prefetch_type.cc b/content/browser/preloading/prefetch/prefetch_type.cc
index f681ce97..c50065a 100644
--- a/content/browser/preloading/prefetch/prefetch_type.cc
+++ b/content/browser/preloading/prefetch/prefetch_type.cc
@@ -17,8 +17,6 @@
 
 PrefetchType::~PrefetchType() = default;
 PrefetchType::PrefetchType(const PrefetchType& prefetch_type) = default;
-PrefetchType& PrefetchType::operator=(const PrefetchType& prefetch_type) =
-    default;
 
 void PrefetchType::SetProxyBypassedForTest() {
   DCHECK(use_prefetch_proxy_);
diff --git a/content/browser/preloading/prefetch/prefetch_type.h b/content/browser/preloading/prefetch/prefetch_type.h
index 7abf3b30..80e4814 100644
--- a/content/browser/preloading/prefetch/prefetch_type.h
+++ b/content/browser/preloading/prefetch/prefetch_type.h
@@ -19,7 +19,7 @@
   ~PrefetchType();
 
   PrefetchType(const PrefetchType& prefetch_type);
-  PrefetchType& operator=(const PrefetchType& prefetch_type);
+  PrefetchType& operator=(const PrefetchType& prefetch_type) = delete;
 
   // Whether this prefetch should bypass the proxy even though it would need to
   // be proxied for anonymity. For use in test automation only.
diff --git a/content/browser/preloading/prefetch/prefetch_url_loader_interceptor_unittest.cc b/content/browser/preloading/prefetch/prefetch_url_loader_interceptor_unittest.cc
index baace5b..5870262 100644
--- a/content/browser/preloading/prefetch/prefetch_url_loader_interceptor_unittest.cc
+++ b/content/browser/preloading/prefetch/prefetch_url_loader_interceptor_unittest.cc
@@ -478,7 +478,7 @@
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
           /*no_vary_search_expected=*/absl::nullopt,
-          blink::mojom::SpeculationInjectionWorld::kNone,
+          blink::mojom::SpeculationInjectionType::kNone,
           /*prefetch_document_manager=*/nullptr);
   prefetch_container->SimulateAttemptAtInterceptorForTest();
 
@@ -555,7 +555,7 @@
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
           /*no_vary_search_expected=*/absl::nullopt,
-          blink::mojom::SpeculationInjectionWorld::kNone,
+          blink::mojom::SpeculationInjectionType::kNone,
           /*prefetch_document_manager=*/nullptr);
   prefetch_container->SimulateAttemptAtInterceptorForTest();
 
@@ -641,7 +641,7 @@
                        blink::mojom::SpeculationEagerness::kEager),
           referrer,
           /*no_vary_search_expected=*/absl::nullopt,
-          blink::mojom::SpeculationInjectionWorld::kNone,
+          blink::mojom::SpeculationInjectionType::kNone,
           /*prefetch_document_manager=*/nullptr);
   prefetch_container->SimulateAttemptAtInterceptorForTest();
 
@@ -737,7 +737,7 @@
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
           /*no_vary_search_expected=*/absl::nullopt,
-          blink::mojom::SpeculationInjectionWorld::kNone,
+          blink::mojom::SpeculationInjectionType::kNone,
           /*prefetch_document_manager=*/nullptr);
   prefetch_container->SimulateAttemptAtInterceptorForTest();
 
@@ -789,7 +789,7 @@
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
           /*no_vary_search_expected=*/absl::nullopt,
-          blink::mojom::SpeculationInjectionWorld::kNone,
+          blink::mojom::SpeculationInjectionType::kNone,
           /*prefetch_document_manager=*/nullptr);
   prefetch_container->SimulateAttemptAtInterceptorForTest();
 
@@ -846,7 +846,7 @@
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
           /*no_vary_search_expected=*/absl::nullopt,
-          blink::mojom::SpeculationInjectionWorld::kNone,
+          blink::mojom::SpeculationInjectionType::kNone,
           /*prefetch_document_manager=*/nullptr);
   prefetch_container->RegisterCookieListener(cookie_manager());
   prefetch_container->SimulateAttemptAtInterceptorForTest();
@@ -920,7 +920,7 @@
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
           /*no_vary_search_expected=*/absl::nullopt,
-          blink::mojom::SpeculationInjectionWorld::kNone,
+          blink::mojom::SpeculationInjectionType::kNone,
           /*prefetch_document_manager=*/nullptr);
   prefetch_container->SimulateAttemptAtInterceptorForTest();
 
@@ -975,7 +975,7 @@
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
           /*no_vary_search_expected=*/absl::nullopt,
-          blink::mojom::SpeculationInjectionWorld::kNone,
+          blink::mojom::SpeculationInjectionType::kNone,
           /*prefetch_document_manager=*/nullptr);
   prefetch_container->SimulateAttemptAtInterceptorForTest();
 
@@ -1056,7 +1056,7 @@
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
           /*no_vary_search_expected=*/absl::nullopt,
-          blink::mojom::SpeculationInjectionWorld::kNone,
+          blink::mojom::SpeculationInjectionType::kNone,
           /*prefetch_document_manager=*/nullptr);
   prefetch_container->SimulateAttemptAtInterceptorForTest();
 
@@ -1239,7 +1239,7 @@
                        blink::mojom::SpeculationEagerness::kEager),
           blink::mojom::Referrer(),
           /*no_vary_search_expected=*/absl::nullopt,
-          blink::mojom::SpeculationInjectionWorld::kNone,
+          blink::mojom::SpeculationInjectionType::kNone,
           /*prefetch_document_manager=*/nullptr);
   prefetch_container->MakeResourceRequest({});
   prefetch_container->SimulateAttemptAtInterceptorForTest();
@@ -1356,7 +1356,7 @@
                        blink::mojom::SpeculationEagerness::kEager),
           referrer,
           /*no_vary_search_expected=*/absl::nullopt,
-          blink::mojom::SpeculationInjectionWorld::kNone,
+          blink::mojom::SpeculationInjectionType::kNone,
           /*prefetch_document_manager=*/nullptr);
   prefetch_container->MakeResourceRequest({});
   prefetch_container->SimulateAttemptAtInterceptorForTest();
diff --git a/content/browser/preloading/preloading.cc b/content/browser/preloading/preloading.cc
index 8cbdb2b..844812f 100644
--- a/content/browser/preloading/preloading.cc
+++ b/content/browser/preloading/preloading.cc
@@ -27,13 +27,13 @@
 }
 
 PreloadingPredictor GetPredictorForSpeculationRules(
-    blink::mojom::SpeculationInjectionWorld world) {
-  switch (world) {
-    case blink::mojom::SpeculationInjectionWorld::kNone:
+    blink::mojom::SpeculationInjectionType type) {
+  switch (type) {
+    case blink::mojom::SpeculationInjectionType::kNone:
       [[fallthrough]];
-    case blink::mojom::SpeculationInjectionWorld::kMain:
+    case blink::mojom::SpeculationInjectionType::kMainWorldScript:
       return content_preloading_predictor::kSpeculationRules;
-    case blink::mojom::SpeculationInjectionWorld::kIsolated:
+    case blink::mojom::SpeculationInjectionType::kIsolatedWorldScript:
       return content_preloading_predictor::kSpeculationRulesFromIsolatedWorld;
   }
   NOTREACHED_NORETURN();
diff --git a/content/browser/preloading/preloading.h b/content/browser/preloading/preloading.h
index f5bcf9e..f432970 100644
--- a/content/browser/preloading/preloading.h
+++ b/content/browser/preloading/preloading.h
@@ -50,7 +50,7 @@
 CONTENT_EXPORT base::StringPiece PreloadingTypeToString(PreloadingType type);
 
 PreloadingPredictor GetPredictorForSpeculationRules(
-    blink::mojom::SpeculationInjectionWorld world);
+    blink::mojom::SpeculationInjectionType);
 
 }  // namespace content
 
diff --git a/content/browser/preloading/preloading_config.cc b/content/browser/preloading/preloading_config.cc
index 36ee0e1..a544dcbf 100644
--- a/content/browser/preloading/preloading_config.cc
+++ b/content/browser/preloading/preloading_config.cc
@@ -29,69 +29,69 @@
 constexpr base::FeatureParam<std::string> kPreloadingConfigParam{
     &features::kPreloadingConfig, "preloading_config", R"(
 [{
-  "preloading_type": "Prerender",
-  "preloading_predictor": "SpeculationRulesFromIsolatedWorld",
-  "sampling_likelihood": 1.000000
-}, {
-  "preloading_type": "Prefetch",
-  "preloading_predictor": "OmniboxSearchPredictor",
-  "sampling_likelihood": 1.000000
-}, {
-  "preloading_type": "Prefetch",
-  "preloading_predictor": "OmniboxMousePredictor",
-  "sampling_likelihood": 1.000000
-}, {
-  "preloading_type": "Prerender",
-  "preloading_predictor": "SpeculationRules",
-  "sampling_likelihood": 1.000000
-}, {
-  "preloading_type": "NoStatePrefetch",
-  "preloading_predictor": "OmniboxDirectURLInput",
-  "sampling_likelihood": 1.000000
-}, {
-  "preloading_type": "Prerender",
-  "preloading_predictor": "PointerDownOnBookmarkBar",
-  "sampling_likelihood": 1.000000
-}, {
-  "preloading_type": "Prerender",
-  "preloading_predictor": "MouseHoverOnBookmarkBar",
-  "sampling_likelihood": 0.501609
-}, {
-  "preloading_type": "Prerender",
-  "preloading_predictor": "BackGestureNavigation",
-  "sampling_likelihood": 0.444169
-}, {
-  "preloading_type": "Prerender",
-  "preloading_predictor": "MouseBackButton",
-  "sampling_likelihood": 0.147112
-}, {
-  "preloading_type": "Prerender",
-  "preloading_predictor": "DefaultSearchEngine",
-  "sampling_likelihood": 0.134034
-}, {
-  "preloading_type": "Prefetch",
-  "preloading_predictor": "DefaultSearchEngine",
-  "sampling_likelihood": 0.030895
-}, {
-  "preloading_type": "Prerender",
-  "preloading_predictor": "OmniboxDirectURLInput",
-  "sampling_likelihood": 0.015387
-}, {
-  "preloading_type": "Prerender",
-  "preloading_predictor": "BackButtonHover",
-  "sampling_likelihood": 0.013294
-}, {
   "preloading_type": "NoStatePrefetch",
   "preloading_predictor": "LinkRel",
-  "sampling_likelihood": 0.010198
+  "sampling_likelihood": "0.007824"
 }, {
-  "preloading_type": "Prefetch",
-  "preloading_predictor": "SpeculationRules",
-  "sampling_likelihood": 0.005237
+  "preloading_type": "NoStatePrefetch",
+  "preloading_predictor": "OmniboxDirectURLInput",
+  "sampling_likelihood": "1.000000"
 }, {
   "preloading_type": "Preconnect",
   "preloading_predictor": "PointerDownOnAnchor",
-  "sampling_likelihood": 0.000240
+  "sampling_likelihood": "0.000190"
+}, {
+  "preloading_type": "Prefetch",
+  "preloading_predictor": "DefaultSearchEngine",
+  "sampling_likelihood": "0.023205"
+}, {
+  "preloading_type": "Prefetch",
+  "preloading_predictor": "OmniboxMousePredictor",
+  "sampling_likelihood": "1.000000"
+}, {
+  "preloading_type": "Prefetch",
+  "preloading_predictor": "OmniboxSearchPredictor",
+  "sampling_likelihood": "1.000000"
+}, {
+  "preloading_type": "Prefetch",
+  "preloading_predictor": "SpeculationRules",
+  "sampling_likelihood": "0.004185"
+}, {
+  "preloading_type": "Prerender",
+  "preloading_predictor": "BackButtonHover",
+  "sampling_likelihood": "0.010113"
+}, {
+  "preloading_type": "Prerender",
+  "preloading_predictor": "BackGestureNavigation",
+  "sampling_likelihood": "0.340065"
+}, {
+  "preloading_type": "Prerender",
+  "preloading_predictor": "DefaultSearchEngine",
+  "sampling_likelihood": "0.057099"
+}, {
+  "preloading_type": "Prerender",
+  "preloading_predictor": "MouseBackButton",
+  "sampling_likelihood": "0.111760"
+}, {
+  "preloading_type": "Prerender",
+  "preloading_predictor": "MouseHoverOnBookmarkBar",
+  "sampling_likelihood": "0.306493"
+}, {
+  "preloading_type": "Prerender",
+  "preloading_predictor": "OmniboxDirectURLInput",
+  "sampling_likelihood": "0.010774"
+}, {
+  "preloading_type": "Prerender",
+  "preloading_predictor": "PointerDownOnBookmarkBar",
+  "sampling_likelihood": "1.000000"
+}, {
+  "preloading_type": "Prerender",
+  "preloading_predictor": "SpeculationRules",
+  "sampling_likelihood": "1.000000"
+}, {
+  "preloading_type": "Prerender",
+  "preloading_predictor": "SpeculationRulesFromIsolatedWorld",
+  "sampling_likelihood": "1.000000"
 }]
 )"};
 
diff --git a/content/browser/preloading/preloading_data_impl.cc b/content/browser/preloading/preloading_data_impl.cc
index bc574338..1dca0d76 100644
--- a/content/browser/preloading/preloading_data_impl.cc
+++ b/content/browser/preloading/preloading_data_impl.cc
@@ -74,15 +74,15 @@
       [](base::WeakPtr<PrefetchService> prefetch_service,
          const PrefetchContainer::Key& predicted, const GURL& navigated_url) {
         if (!prefetch_service) {
-          return predicted.second == navigated_url;
+          return predicted.prefetch_url() == navigated_url;
         }
-        if (predicted.second == navigated_url) {
+        if (predicted.prefetch_url() == navigated_url) {
           return true;
         }
 
         base::WeakPtr<PrefetchContainer> prefetch_container =
-            prefetch_service->MatchUrl(
-                PrefetchContainer::Key(predicted.first, navigated_url));
+            prefetch_service->MatchUrl(PrefetchContainer::Key(
+                predicted.referring_document_token(), navigated_url));
         return prefetch_container &&
                prefetch_container->GetPrefetchContainerKey() == predicted;
       },
diff --git a/content/browser/preloading/preloading_decider.cc b/content/browser/preloading/preloading_decider.cc
index f67bb6d..990f814 100644
--- a/content/browser/preloading/preloading_decider.cc
+++ b/content/browser/preloading/preloading_decider.cc
@@ -342,7 +342,7 @@
     // TODO(crbug.com/1341019): Pass the action requested by speculation rules
     // to PreloadingPrediction.
     AddPreloadingPrediction(candidate->url, GetPredictorForSpeculationRules(
-                                                candidate->injection_world));
+                                                candidate->injection_type));
 
     return false;
   };
diff --git a/content/browser/preloading/prerender/prerender_browsertest.cc b/content/browser/preloading/prerender/prerender_browsertest.cc
index 5bc8ddfe..dec72d2 100644
--- a/content/browser/preloading/prerender/prerender_browsertest.cc
+++ b/content/browser/preloading/prerender/prerender_browsertest.cc
@@ -488,6 +488,12 @@
     return prerender_helper_->NavigatePrerenderedPage(host_id, url);
   }
 
+  bool HasHostForUrl(WebContents& web_contents, const GURL& url) {
+    int host_id =
+        content::test::PrerenderTestHelper::GetHostForUrl(web_contents, url);
+    return host_id != RenderFrameHost::kNoFrameTreeNodeId;
+  }
+
   bool HasHostForUrl(const GURL& url) {
     int host_id = GetHostForUrl(url);
     return host_id != RenderFrameHost::kNoFrameTreeNodeId;
@@ -1329,7 +1335,7 @@
   EXPECT_NE(prerender_web_contents->GetLastCommittedURL(), kPrerenderingUrl);
   EXPECT_FALSE(prerender_observer.was_activated());
   // The host should still be available.
-  EXPECT_TRUE(HasHostForUrl(kPrerenderingUrl));
+  EXPECT_TRUE(HasHostForUrl(*prerender_web_contents, kPrerenderingUrl));
 
   // The navigation occurred in a new WebContents, so the original WebContents
   // should still be showing the initial trigger page.
@@ -4444,8 +4450,8 @@
   auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
   registry->SetTaskRunnerForTesting(task_runner);
 
-  test::PrerenderHostObserver prerender_observer(*web_contents_impl(),
-                                                 kPrerenderUrl);
+  test::PrerenderHostObserver prerender_observer(*prerender_web_contents,
+                                                 host_id);
 
   // Changing the visibility state to HIDDEN/OCCLUDED will not stop prerendering
   // immediately, but start the timers.
@@ -6137,9 +6143,12 @@
   EXPECT_TRUE(prerender_observer.was_activated());
 
   // prerendering_urls[0] was consumed for activation, but others were not.
-  EXPECT_FALSE(HasHostForUrl(prerendering_urls[0]));
-  EXPECT_TRUE(HasHostForUrl(prerendering_urls[1]));
-  EXPECT_TRUE(HasHostForUrl(prerendering_urls[2]));
+  EXPECT_FALSE(
+      HasHostForUrl(*prerender_web_contents_list[0], prerendering_urls[0]));
+  EXPECT_TRUE(
+      HasHostForUrl(*prerender_web_contents_list[1], prerendering_urls[1]));
+  EXPECT_TRUE(
+      HasHostForUrl(*prerender_web_contents_list[2], prerendering_urls[2]));
 
   ExpectFinalStatusForSpeculationRule(PrerenderFinalStatus::kActivated);
 
@@ -8221,6 +8230,7 @@
                        ResetForNonEagerPrerener) {
   const GURL initial_url = GetUrl("/empty.html");
   std::vector<GURL> prerendering_urls;
+  std::vector<base::WeakPtr<WebContents>> prerender_web_contents_list;
 
   // Navigate to an initial page.
   ASSERT_TRUE(NavigateToURL(shell(), initial_url));
@@ -8229,8 +8239,8 @@
   // by hovering their links. All prerenders should be started at the time of
   // hovering, and the oldest started prerender should be canceled and removed
   // from the registry for the limit after the last prerender is started.
-  for (int i = 0; i < MaxNumOfRunningSpeculationRulesNonEagerPrerenders() + 1;
-       i++) {
+  int num_of_attempts = MaxNumOfRunningSpeculationRulesNonEagerPrerenders() + 1;
+  for (int i = 0; i < num_of_attempts; i++) {
     PreloadingDeciderObserverForPrerenderTesting preloading_decider_observer(
         current_frame_host());
     const GURL prerendering_url =
@@ -8242,23 +8252,19 @@
                        GetParam());
     preloading_decider_observer.WaitUpdateSpeculationCandidates();
 
-    if (GetParam() == "_blank") {
-      TestNavigationObserver nav_observer(prerendering_url);
-      nav_observer.StartWatchingNewWebContents();
-      PointerHoverToAnchor(prerendering_url);
-      nav_observer.WaitForNavigationFinished();
-      EXPECT_EQ(nav_observer.last_navigation_url(), prerendering_url);
-    } else if (GetParam() == "_self") {
-      PointerHoverToAnchor(prerendering_url);
-      WaitForPrerenderLoadCompletion(prerendering_url);
-    }
+    PrerenderHostCreationWaiter host_creation_waiter;
+    PointerHoverToAnchor(prerendering_url);
+    int host_id = host_creation_waiter.Wait();
+    auto* prerender_web_contents = WebContents::FromFrameTreeNodeId(host_id);
+    prerender_web_contents_list.push_back(prerender_web_contents->GetWeakPtr());
+    test::PrerenderTestHelper::WaitForPrerenderLoadCompletion(
+        *prerender_web_contents, prerendering_url);
   }
-  for (int i = 0; i < MaxNumOfRunningSpeculationRulesNonEagerPrerenders() + 1;
-       i++) {
+
+  for (int i = 0; i < num_of_attempts; i++) {
     bool host_existing_in_registry =
-        web_contents_impl()
-            ->GetPrerenderHostRegistry()
-            ->FindHostByUrlForTesting(prerendering_urls[i]);
+        prerender_web_contents_list[i] &&
+        HasHostForUrl(*prerender_web_contents_list[i], prerendering_urls[i]);
     if (i == 0) {
       // The first (= oldest) prerender is removed since the (limit + 1)-th
       // prerender was started.
@@ -8270,25 +8276,20 @@
 
   // Hover the first link again. This should be retriggered.
   const auto& prerendering_url_first = prerendering_urls[0];
-  if (GetParam() == "_blank") {
-    TestNavigationObserver nav_observer(prerendering_url_first);
-    nav_observer.StartWatchingNewWebContents();
-    PointerHoverToAnchor(prerendering_url_first);
-    nav_observer.WaitForNavigationFinished();
-    EXPECT_EQ(nav_observer.last_navigation_url(), prerendering_url_first);
-  } else if (GetParam() == "_self") {
-    PointerHoverToAnchor(prerendering_url_first);
-    WaitForPrerenderLoadCompletion(prerendering_url_first);
-  }
+  PrerenderHostCreationWaiter host_creation_waiter;
+  PointerHoverToAnchor(prerendering_url_first);
+  int host_id = host_creation_waiter.Wait();
+  auto* prerender_web_contents = WebContents::FromFrameTreeNodeId(host_id);
+  prerender_web_contents_list[0] = prerender_web_contents->GetWeakPtr();
+  test::PrerenderTestHelper::WaitForPrerenderLoadCompletion(
+      *prerender_web_contents, prerendering_url_first);
 
   // The oldest prerender in registry at this point should be removed due to the
   // limit.
-  for (int i = 0; i < MaxNumOfRunningSpeculationRulesNonEagerPrerenders() + 1;
-       i++) {
+  for (int i = 0; i < num_of_attempts; i++) {
     bool host_existing_in_registry =
-        web_contents_impl()
-            ->GetPrerenderHostRegistry()
-            ->FindHostByUrlForTesting(prerendering_urls[i]);
+        prerender_web_contents_list[i] &&
+        HasHostForUrl(*prerender_web_contents_list[i], prerendering_urls[i]);
     if (i == 1) {
       EXPECT_FALSE(host_existing_in_registry);
     } else {
diff --git a/content/browser/preloading/prerender/prerender_host_registry.cc b/content/browser/preloading/prerender/prerender_host_registry.cc
index 5258895b..da0d632 100644
--- a/content/browser/preloading/prerender/prerender_host_registry.cc
+++ b/content/browser/preloading/prerender/prerender_host_registry.cc
@@ -1183,12 +1183,6 @@
       return iter.second.get();
     }
   }
-  for (auto& iter : prerender_new_tab_handle_by_frame_tree_node_id_) {
-    PrerenderHost* host = iter.second->GetPrerenderHostForTesting();  // IN-TEST
-    if (host && host->IsUrlMatch(prerendering_url)) {
-      return host;
-    }
-  }
   return nullptr;
 }
 
diff --git a/content/browser/preloading/prerenderer_impl.cc b/content/browser/preloading/prerenderer_impl.cc
index 69941a7..20aaf13 100644
--- a/content/browser/preloading/prerenderer_impl.cc
+++ b/content/browser/preloading/prerenderer_impl.cc
@@ -14,6 +14,7 @@
 #include "content/browser/preloading/prerender/prerender_navigation_utils.h"
 #include "content/browser/preloading/prerender/prerender_new_tab_handle.h"
 #include "content/browser/renderer_host/render_frame_host_delegate.h"
+#include "content/public/browser/preloading_trigger_type.h"
 #include "content/public/browser/web_contents.h"
 
 namespace content {
@@ -21,13 +22,13 @@
 namespace {
 
 PreloadingTriggerType GetTriggerType(
-    blink::mojom::SpeculationInjectionWorld world) {
-  switch (world) {
-    case blink::mojom::SpeculationInjectionWorld::kNone:
+    blink::mojom::SpeculationInjectionType type) {
+  switch (type) {
+    case blink::mojom::SpeculationInjectionType::kNone:
       [[fallthrough]];
-    case blink::mojom::SpeculationInjectionWorld::kMain:
+    case blink::mojom::SpeculationInjectionType::kMainWorldScript:
       return PreloadingTriggerType::kSpeculationRule;
-    case blink::mojom::SpeculationInjectionWorld::kIsolated:
+    case blink::mojom::SpeculationInjectionType::kIsolatedWorldScript:
       return PreloadingTriggerType::kSpeculationRuleFromIsolatedWorld;
   }
 }
@@ -35,7 +36,7 @@
 }  // namespace
 
 struct PrerendererImpl::PrerenderInfo {
-  blink::mojom::SpeculationInjectionWorld injection_world;
+  blink::mojom::SpeculationInjectionType injection_type;
   blink::mojom::SpeculationEagerness eagerness;
   int prerender_host_id;
   GURL url;
@@ -221,7 +222,7 @@
   GetContentClient()->browser()->LogWebFeatureForCurrentPage(
       &rfhi, blink::mojom::WebFeature::kSpeculationRulesPrerender);
   IncrementReceivedPrerendersCountForMetrics(
-      GetTriggerType(candidate->injection_world), candidate->eagerness);
+      GetTriggerType(candidate->injection_type), candidate->eagerness);
 
   // TODO(crbug.com/1176054): Remove it after supporting cross-site
   // prerender.
@@ -239,7 +240,7 @@
 
   Referrer referrer(*(candidate->referrer));
   PrerenderAttributes attributes(
-      candidate->url, GetTriggerType(candidate->injection_world),
+      candidate->url, GetTriggerType(candidate->injection_type),
       /*embedder_histogram_suffix=*/"",
       candidate->target_browsing_context_name_hint, referrer,
       candidate->eagerness, rfhi.GetLastCommittedOrigin(),
@@ -263,7 +264,7 @@
           // a prerender WebContents to be created later.
           return registry_->CreateAndStartHostForNewTab(
               attributes,
-              GetPredictorForSpeculationRules(candidate->injection_world));
+              GetPredictorForSpeculationRules(candidate->injection_type));
         }
         // Handle the rule as kNoHint if the prerender-in-new-tab is not
         // enabled.
@@ -279,7 +280,7 @@
             PreloadingData::GetSameURLMatcher(candidate->url);
         auto* preloading_attempt = static_cast<PreloadingAttemptImpl*>(
             preloading_data->AddPreloadingAttempt(
-                GetPredictorForSpeculationRules(candidate->injection_world),
+                GetPredictorForSpeculationRules(candidate->injection_type),
                 PreloadingType::kPrerender, std::move(same_url_matcher),
                 web_contents->GetPrimaryMainFrame()->GetPageUkmSourceId()));
         preloading_attempt->SetSpeculationEagerness(candidate->eagerness);
@@ -299,12 +300,11 @@
                                     std::less<>(), &PrerenderInfo::url);
   }
 
-  started_prerenders_.insert(end,
-                             {.injection_world = candidate->injection_world,
-                              .eagerness = candidate->eagerness,
-                              .prerender_host_id = prerender_host_id,
-                              .url = candidate->url,
-                              .referrer = referrer});
+  started_prerenders_.insert(end, {.injection_type = candidate->injection_type,
+                                   .eagerness = candidate->eagerness,
+                                   .prerender_host_id = prerender_host_id,
+                                   .url = candidate->url,
+                                   .referrer = referrer});
 
   return true;
 }
diff --git a/content/browser/private_aggregation/BUILD.gn b/content/browser/private_aggregation/BUILD.gn
index 44eb76d..8ce7468 100644
--- a/content/browser/private_aggregation/BUILD.gn
+++ b/content/browser/private_aggregation/BUILD.gn
@@ -11,7 +11,6 @@
     "//url/mojom:url_mojom_origin",
   ]
   webui_module_path = "/"
-  use_typescript_sources = true
 
   cpp_typemaps = [
     {
diff --git a/content/browser/process_internals/BUILD.gn b/content/browser/process_internals/BUILD.gn
index ade7b83..dbf61530 100644
--- a/content/browser/process_internals/BUILD.gn
+++ b/content/browser/process_internals/BUILD.gn
@@ -9,5 +9,4 @@
 
   deps = [ "//url/mojom:url_mojom_gurl" ]
   webui_module_path = "/"
-  use_typescript_sources = true
 }
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 0ea34e7..0b25ae9c 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -4283,16 +4283,19 @@
 // static
 void RenderProcessHostImpl::RegisterCreationObserver(
     RenderProcessHostCreationObserver* observer) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
+         // Android unit tests trigger the thread uninitialized case.
+         !BrowserThread::IsThreadInitialized(BrowserThread::UI));
   GetAllCreationObservers().push_back(observer);
 }
 
 // static
 void RenderProcessHostImpl::UnregisterCreationObserver(
     RenderProcessHostCreationObserver* observer) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
-         // Chrome OS unit tests trigger the thread uninitialized case.
-         !BrowserThread::IsThreadInitialized(BrowserThread::UI));
+  DCHECK(
+      BrowserThread::CurrentlyOn(BrowserThread::UI) ||
+      // Chrome OS and Android unit tests trigger the thread uninitialized case.
+      !BrowserThread::IsThreadInitialized(BrowserThread::UI));
   auto iter = base::ranges::find(GetAllCreationObservers(), observer);
   DCHECK(iter != GetAllCreationObservers().end());
   GetAllCreationObservers().erase(iter);
diff --git a/content/browser/sandbox_parameters_mac.mm b/content/browser/sandbox_parameters_mac.mm
index 676ac06..8dcad1f 100644
--- a/content/browser/sandbox_parameters_mac.mm
+++ b/content/browser/sandbox_parameters_mac.mm
@@ -245,7 +245,6 @@
 #if BUILDFLAG(ENABLE_OOP_PRINTING)
     case sandbox::mojom::Sandbox::kPrintBackend:
 #endif
-    case sandbox::mojom::Sandbox::kOnDeviceModelExecution:
     case sandbox::mojom::Sandbox::kPrintCompositor:
     case sandbox::mojom::Sandbox::kRenderer:
     case sandbox::mojom::Sandbox::kService:
@@ -253,6 +252,7 @@
     case sandbox::mojom::Sandbox::kUtility:
       SetupCommonSandboxParameters(compiler, command_line);
       break;
+    case sandbox::mojom::Sandbox::kOnDeviceModelExecution:
     case sandbox::mojom::Sandbox::kGpu: {
       SetupGpuSandboxParameters(compiler, command_line);
       break;
diff --git a/content/browser/tracing/trace_report/BUILD.gn b/content/browser/tracing/trace_report/BUILD.gn
index b9d31dff..f08fbce 100644
--- a/content/browser/tracing/trace_report/BUILD.gn
+++ b/content/browser/tracing/trace_report/BUILD.gn
@@ -8,7 +8,6 @@
   sources = [ "trace_report.mojom" ]
   public_deps = [ "//mojo/public/mojom/base" ]
   webui_module_path = "/"
-  use_typescript_sources = true
 
   cpp_typemaps = [
     {
diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc
index ac993ad9..6c67113 100644
--- a/content/browser/utility_process_host.cc
+++ b/content/browser/utility_process_host.cc
@@ -318,6 +318,7 @@
       switches::kDisableDevShmUsage,
 #endif
 #if BUILDFLAG(IS_MAC)
+      sandbox::policy::switches::kDisableMetalShaderCache,
       sandbox::policy::switches::kEnableSandboxLogging,
       os_crypt::switches::kUseMockKeychain,
 #endif
diff --git a/content/browser/xr/webxr_internals/mojom/BUILD.gn b/content/browser/xr/webxr_internals/mojom/BUILD.gn
index 37f2cb2b..f196634 100644
--- a/content/browser/xr/webxr_internals/mojom/BUILD.gn
+++ b/content/browser/xr/webxr_internals/mojom/BUILD.gn
@@ -8,5 +8,4 @@
   sources = [ "webxr_internals.mojom" ]
   deps = [ "//device/vr/public/mojom:xr_common" ]
   webui_module_path = "/"
-  use_typescript_sources = true
 }
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
index 086995a..735e546 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
@@ -1092,8 +1092,7 @@
         if (!ViewUtils.hasFocus(containerView)) ViewUtils.requestFocus(containerView);
 
         updateInputStateForStylusWriting();
-        return mWebContents.getStylusWritingHandler().requestStartStylusWriting(
-                getStylusWritingImeCallback());
+        return mWebContents.getStylusWritingHandler().requestStartStylusWriting();
     }
 
     @CalledByNative
@@ -1152,7 +1151,7 @@
     }
 
     /** Lazily creates/returns a StylusWritingImeCallback object. */
-    private StylusWritingImeCallback getStylusWritingImeCallback() {
+    public StylusWritingImeCallback getStylusWritingImeCallback() {
         if (mStylusWritingImeCallback == null) {
             mStylusWritingImeCallback = new StylusWritingImeCallback() {
                 @Override
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
index 819a831..e237432 100644
--- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
@@ -43,6 +43,7 @@
 import org.chromium.content.browser.accessibility.ViewStructureBuilder;
 import org.chromium.content.browser.framehost.RenderFrameHostDelegate;
 import org.chromium.content.browser.framehost.RenderFrameHostImpl;
+import org.chromium.content.browser.input.ImeAdapterImpl;
 import org.chromium.content.browser.selection.SelectionPopupControllerImpl;
 import org.chromium.content_public.browser.ChildProcessImportance;
 import org.chromium.content_public.browser.GlobalRenderFrameHostId;
@@ -53,6 +54,7 @@
 import org.chromium.content_public.browser.NavigationController;
 import org.chromium.content_public.browser.RenderFrameHost;
 import org.chromium.content_public.browser.StylusWritingHandler;
+import org.chromium.content_public.browser.StylusWritingImeCallback;
 import org.chromium.content_public.browser.ViewEventSink.InternalAccessDelegate;
 import org.chromium.content_public.browser.Visibility;
 import org.chromium.content_public.browser.WebContents;
@@ -840,6 +842,13 @@
                 mNativeWebContentsAndroid, mStylusWritingHandler != null);
     }
 
+    @Override
+    public StylusWritingImeCallback getStylusWritingImeCallback() {
+        ImeAdapterImpl imeAdapter = ImeAdapterImpl.fromWebContents(this);
+        if (imeAdapter == null) return null;
+        return imeAdapter.getStylusWritingImeCallback();
+    }
+
     public StylusWritingHandler getStylusWritingHandler() {
         return mStylusWritingHandler;
     }
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/StylusWritingHandler.java b/content/public/android/java/src/org/chromium/content_public/browser/StylusWritingHandler.java
index 23207c40..3f251a4 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/StylusWritingHandler.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/StylusWritingHandler.java
@@ -29,10 +29,10 @@
     /**
      * Requests to start stylus writing for input field in web page.
      *
-     * @return true if writing can be started or if started successfully, false if writing cannot
-     * be started.
+     * @return true if writing can be started or if started successfully, false if writing cannot be
+     *     started.
      */
-    boolean requestStartStylusWriting(StylusWritingImeCallback imeCallback);
+    boolean requestStartStylusWriting();
 
     /**
      * Update current input state parameters to stylus writing system.
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
index a173fd1..3504160 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
@@ -453,6 +453,12 @@
     void setStylusWritingHandler(StylusWritingHandler stylusWritingHandler);
 
     /**
+     * @return {@link StylusWritingImeCallback} which is used to implement the IME functionality for
+     *     the Stylus handwriting feature.
+     */
+    StylusWritingImeCallback getStylusWritingImeCallback();
+
+    /**
      * Returns {@link EventForwarder} which is used to forward input/view events
      * to native content layer.
      */
diff --git a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockWebContents.java b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockWebContents.java
index 9275f645..78c52b7 100644
--- a/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockWebContents.java
+++ b/content/public/test/android/javatests/src/org/chromium/content_public/browser/test/mock/MockWebContents.java
@@ -21,6 +21,7 @@
 import org.chromium.content_public.browser.RenderFrameHost;
 import org.chromium.content_public.browser.RenderWidgetHostView;
 import org.chromium.content_public.browser.StylusWritingHandler;
+import org.chromium.content_public.browser.StylusWritingImeCallback;
 import org.chromium.content_public.browser.ViewEventSink;
 import org.chromium.content_public.browser.Visibility;
 import org.chromium.content_public.browser.WebContents;
@@ -271,6 +272,11 @@
     public void setStylusWritingHandler(StylusWritingHandler stylusWritingHandler) {}
 
     @Override
+    public StylusWritingImeCallback getStylusWritingImeCallback() {
+        return null;
+    }
+
+    @Override
     public EventForwarder getEventForwarder() {
         return null;
     }
diff --git a/content/public/test/prerender_test_util.cc b/content/public/test/prerender_test_util.cc
index debb88b..6b452bc 100644
--- a/content/public/test/prerender_test_util.cc
+++ b/content/public/test/prerender_test_util.cc
@@ -410,7 +410,7 @@
   }
 
   WaitForPrerenderLoadCompletion(*prerender_web_contents, prerendering_url);
-  int host_id = GetHostForUrl(prerendering_url);
+  int host_id = GetHostForUrl(*prerender_web_contents, prerendering_url);
   EXPECT_NE(host_id, RenderFrameHost::kNoFrameTreeNodeId);
   return host_id;
 }
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 5ead614e..3a38a1d 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1124,7 +1124,6 @@
   ]
   public_deps = [ "//url/mojom:url_mojom_gurl" ]
   webui_module_path = "/content/test/data"
-  use_typescript_sources = true
 }
 
 preprocess_if_expr("preprocess_mojo_webui_test") {
diff --git a/content/test/data/accessibility/html/landmark-expected-android.txt b/content/test/data/accessibility/html/landmark-expected-android.txt
index a100a6b..7f09dfc1 100644
--- a/content/test/data/accessibility/html/landmark-expected-android.txt
+++ b/content/test/data/accessibility/html/landmark-expected-android.txt
@@ -73,4 +73,12 @@
 ++android.view.View
 ++++android.widget.TextView name='This should NOT have complementary role.'
 ++android.view.View role_description='main'
+++++android.view.View role_description='complementary' name='This should have complementary role.'
+++android.view.View role_description='article'
+++++android.view.View role_description='complementary' name='This should have complementary role.'
+++android.view.View role_description='complementary'
+++++android.view.View role_description='complementary' name='This should have complementary role.'
+++android.view.View role_description='navigation'
+++++android.view.View role_description='complementary' name='This should have complementary role.'
+++android.view.View
 ++++android.view.View role_description='complementary' name='This should have complementary role.'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/landmark-expected-auralinux.txt b/content/test/data/accessibility/html/landmark-expected-auralinux.txt
index 96b3c223..f9395458 100644
--- a/content/test/data/accessibility/html/landmark-expected-auralinux.txt
+++ b/content/test/data/accessibility/html/landmark-expected-auralinux.txt
@@ -119,3 +119,15 @@
 ++[landmark] xml-roles:main
 ++++[landmark] xml-roles:complementary
 ++++++[static] name='This should have complementary role.'
+++[article]
+++++[landmark] xml-roles:complementary
+++++++[static] name='This should have complementary role.'
+++[landmark] xml-roles:complementary
+++++[landmark] xml-roles:complementary
+++++++[static] name='This should have complementary role.'
+++[landmark] xml-roles:navigation
+++++[landmark] xml-roles:complementary
+++++++[static] name='This should have complementary role.'
+++[section]
+++++[landmark] xml-roles:complementary
+++++++[static] name='This should have complementary role.'
diff --git a/content/test/data/accessibility/html/landmark-expected-blink.txt b/content/test/data/accessibility/html/landmark-expected-blink.txt
index 2f20091..68cd4df 100644
--- a/content/test/data/accessibility/html/landmark-expected-blink.txt
+++ b/content/test/data/accessibility/html/landmark-expected-blink.txt
@@ -181,3 +181,23 @@
 ++++++++++complementary
 ++++++++++++staticText name='This should have complementary role.'
 ++++++++++++++inlineTextBox name='This should have complementary role.'
+++++++article
+++++++++genericContainer ignored
+++++++++++complementary
+++++++++++++staticText name='This should have complementary role.'
+++++++++++++++inlineTextBox name='This should have complementary role.'
+++++++complementary
+++++++++genericContainer ignored
+++++++++++complementary
+++++++++++++staticText name='This should have complementary role.'
+++++++++++++++inlineTextBox name='This should have complementary role.'
+++++++navigation
+++++++++genericContainer ignored
+++++++++++complementary
+++++++++++++staticText name='This should have complementary role.'
+++++++++++++++inlineTextBox name='This should have complementary role.'
+++++++section
+++++++++genericContainer ignored
+++++++++++complementary
+++++++++++++staticText name='This should have complementary role.'
+++++++++++++++inlineTextBox name='This should have complementary role.'
diff --git a/content/test/data/accessibility/html/landmark-expected-fuchsia.txt b/content/test/data/accessibility/html/landmark-expected-fuchsia.txt
index d949d60..d25949eb 100644
--- a/content/test/data/accessibility/html/landmark-expected-fuchsia.txt
+++ b/content/test/data/accessibility/html/landmark-expected-fuchsia.txt
@@ -181,3 +181,23 @@
 ++++++++++UNKNOWN
 ++++++++++++STATIC_TEXT label='This should have complementary role.'
 ++++++++++++++UNKNOWN label='This should have complementary role.'
+++++++UNKNOWN
+++++++++UNKNOWN hidden
+++++++++++UNKNOWN
+++++++++++++STATIC_TEXT label='This should have complementary role.'
+++++++++++++++UNKNOWN label='This should have complementary role.'
+++++++UNKNOWN
+++++++++UNKNOWN hidden
+++++++++++UNKNOWN
+++++++++++++STATIC_TEXT label='This should have complementary role.'
+++++++++++++++UNKNOWN label='This should have complementary role.'
+++++++UNKNOWN
+++++++++UNKNOWN hidden
+++++++++++UNKNOWN
+++++++++++++STATIC_TEXT label='This should have complementary role.'
+++++++++++++++UNKNOWN label='This should have complementary role.'
+++++++UNKNOWN
+++++++++UNKNOWN hidden
+++++++++++UNKNOWN
+++++++++++++STATIC_TEXT label='This should have complementary role.'
+++++++++++++++UNKNOWN label='This should have complementary role.'
diff --git a/content/test/data/accessibility/html/landmark-expected-mac.txt b/content/test/data/accessibility/html/landmark-expected-mac.txt
index 52af4aa..95edb17 100644
--- a/content/test/data/accessibility/html/landmark-expected-mac.txt
+++ b/content/test/data/accessibility/html/landmark-expected-mac.txt
@@ -119,3 +119,15 @@
 ++AXGroup AXSubrole=AXLandmarkMain AXRoleDescription='main'
 ++++AXGroup AXSubrole=AXLandmarkComplementary AXRoleDescription='complementary'
 ++++++AXStaticText AXRoleDescription='text' AXValue='This should have complementary role.'
+++AXGroup AXSubrole=AXDocumentArticle AXRoleDescription='article'
+++++AXGroup AXSubrole=AXLandmarkComplementary AXRoleDescription='complementary'
+++++++AXStaticText AXRoleDescription='text' AXValue='This should have complementary role.'
+++AXGroup AXSubrole=AXLandmarkComplementary AXRoleDescription='complementary'
+++++AXGroup AXSubrole=AXLandmarkComplementary AXRoleDescription='complementary'
+++++++AXStaticText AXRoleDescription='text' AXValue='This should have complementary role.'
+++AXGroup AXSubrole=AXLandmarkNavigation AXRoleDescription='navigation'
+++++AXGroup AXSubrole=AXLandmarkComplementary AXRoleDescription='complementary'
+++++++AXStaticText AXRoleDescription='text' AXValue='This should have complementary role.'
+++AXGroup AXRoleDescription='group'
+++++AXGroup AXSubrole=AXLandmarkComplementary AXRoleDescription='complementary'
+++++++AXStaticText AXRoleDescription='text' AXValue='This should have complementary role.'
diff --git a/content/test/data/accessibility/html/landmark-expected-uia-win.txt b/content/test/data/accessibility/html/landmark-expected-uia-win.txt
index 1797900..80b77d1 100644
--- a/content/test/data/accessibility/html/landmark-expected-uia-win.txt
+++ b/content/test/data/accessibility/html/landmark-expected-uia-win.txt
@@ -119,3 +119,15 @@
 ++Group
 ++++Group
 ++++++Text Name='This should have complementary role.'
+++Group
+++++Group
+++++++Text Name='This should have complementary role.'
+++Group
+++++Group
+++++++Text Name='This should have complementary role.'
+++Group
+++++Group
+++++++Text Name='This should have complementary role.'
+++Group
+++++Group
+++++++Text Name='This should have complementary role.'
diff --git a/content/test/data/accessibility/html/landmark-expected-win.txt b/content/test/data/accessibility/html/landmark-expected-win.txt
index 93cab18a..f8f4322 100644
--- a/content/test/data/accessibility/html/landmark-expected-win.txt
+++ b/content/test/data/accessibility/html/landmark-expected-win.txt
@@ -119,3 +119,15 @@
 ++IA2_ROLE_LANDMARK xml-roles:main
 ++++IA2_ROLE_LANDMARK xml-roles:complementary
 ++++++ROLE_SYSTEM_STATICTEXT name='This should have complementary role.'
+++ROLE_SYSTEM_DOCUMENT READONLY
+++++IA2_ROLE_LANDMARK xml-roles:complementary
+++++++ROLE_SYSTEM_STATICTEXT name='This should have complementary role.'
+++IA2_ROLE_LANDMARK xml-roles:complementary
+++++IA2_ROLE_LANDMARK xml-roles:complementary
+++++++ROLE_SYSTEM_STATICTEXT name='This should have complementary role.'
+++IA2_ROLE_LANDMARK xml-roles:navigation
+++++IA2_ROLE_LANDMARK xml-roles:complementary
+++++++ROLE_SYSTEM_STATICTEXT name='This should have complementary role.'
+++IA2_ROLE_SECTION
+++++IA2_ROLE_LANDMARK xml-roles:complementary
+++++++ROLE_SYSTEM_STATICTEXT name='This should have complementary role.'
\ No newline at end of file
diff --git a/content/test/data/accessibility/html/landmark.html b/content/test/data/accessibility/html/landmark.html
index b74b7a7..6d216cc 100644
--- a/content/test/data/accessibility/html/landmark.html
+++ b/content/test/data/accessibility/html/landmark.html
@@ -58,5 +58,10 @@
   <nav><div><aside>This should NOT have complementary role.</aside></div></nav>
   <section><div><aside>This should NOT have complementary role.</aside></div></section>
   <main><div><aside>This should have complementary role.</aside></div></main>
+
+  <article><div><aside role="complementary">This should have complementary role.</aside></div></article>
+  <aside><div><aside role="complementary">This should have complementary role.</aside></div></aside>
+  <nav><div><aside role="complementary">This should have complementary role.</aside></div></nav>
+  <section><div><aside role="complementary">This should have complementary role.</aside></div></section>
 </body>
 </html>
diff --git a/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt
index 237f9716..e81f5674 100644
--- a/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/trace_test_expectations.txt
@@ -245,8 +245,6 @@
 crbug.com/1446057 [ win10 amd-0x7340 angle-d3d11 ] VideoPathTraceTest_DirectComposition_Video_SW_Decode [ Failure ]
 
 
-# Canvas capture trace tests on M1 Mac
-crbug.com/1493530 [ angle-metal apple-angle-metal-renderer:-apple-m2 mac ] WebGPUTraceTest_WebGPUCanvasOneCopyCapture_Hidden [ RetryOnFailure ]
 
 #######################################################################
 # Automated Entries After This Point - Do Not Manually Add Below Here #
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index f3bf978..419c9d2 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -857,6 +857,7 @@
 crbug.com/1492258 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance2/glsl3/uninitialized-local-global-variables.html [ Failure ]
 crbug.com/1492270 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance2/reading/read-pixels-pack-parameters.html [ Failure ]
 crbug.com/1499514 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance/textures/canvas_sub_rectangle/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ RetryOnFailure ]
+crbug.com/1499514 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance/textures/webgl_canvas/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ RetryOnFailure ]
 crbug.com/1499514 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance/textures/webgl_canvas/tex-2d-luminance-luminance-unsigned_byte.html [ RetryOnFailure ]
 crbug.com/1499514 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance2/textures/canvas_sub_rectangle/tex-2d-srgb8-rgb-unsigned_byte.html [ Failure ]
 crbug.com/1499516 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance2/transform_feedback/transform_feedback.html [ Failure ]
@@ -872,7 +873,7 @@
 crbug.com/1499536 [ chromeos cros-chrome chromeos-board-jacuzzi ] deqp/functional/gles3/uniformbuffers/random.html [ Failure ]
 crbug.com/1499536 [ chromeos cros-chrome chromeos-board-jacuzzi ] deqp/functional/gles3/uniformbuffers/single_basic_array.html [ Failure ]
 crbug.com/1499536 [ chromeos cros-chrome chromeos-board-jacuzzi ] deqp/functional/gles3/uniformbuffers/single_basic_type.html [ Failure ]
-crbug.com/1500045 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance2/rendering/blitframebuffer-r11f-g11f-b10f.html [ RetryOnFailure ]
+crbug.com/1500045 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance2/rendering/blitframebuffer-r11f-g11f-b10f.html [ Failure ]
 
 #####################
 # Lacros failures #
diff --git a/docs/linux/build_instructions.md b/docs/linux/build_instructions.md
index 4c75bca..0730a192 100644
--- a/docs/linux/build_instructions.md
+++ b/docs/linux/build_instructions.md
@@ -163,8 +163,14 @@
 [Remote Execution API](https://github.com/bazelbuild/remote-apis)
 client called [reclient](https://github.com/bazelbuild/reclient).
 
-If you would like to use `reclient`, specify your `rbe_instance` in .gclient
-like
+*** note
+**Warning:** Following instruction is not ready to be used yet.
+***
+
+If you would like to use `reclient`, install gcloud via
+https://cloud.google.com/sdk/docs/install, authorize with your account via
+https://cloud.google.com/sdk/docs/authorizing and specify your `rbe_instance`
+in .gclient like
 ```
 solutions = [
   {
diff --git a/docs/webui_explainer.md b/docs/webui_explainer.md
index d2efe542..226304d 100644
--- a/docs/webui_explainer.md
+++ b/docs/webui_explainer.md
@@ -508,7 +508,6 @@
 mojom("mojo_bindings") {
   sources = [ "donuts.mojom" ]
   webui_module_path = "/"
-  use_typescript_sources = true
 }
 ```
 
diff --git a/extensions/common/api/scripts_internal/script_serialization.cc b/extensions/common/api/scripts_internal/script_serialization.cc
index 9bba01b..4b821c3 100644
--- a/extensions/common/api/scripts_internal/script_serialization.cc
+++ b/extensions/common/api/scripts_internal/script_serialization.cc
@@ -13,15 +13,6 @@
 
 namespace extensions::script_serialization {
 
-namespace {
-
-// TODO(crbug.com/1168627): The can_execute_script_everywhere flag is currently
-// only used by the legacy version Chromevox extension. We can assume it will
-// always be false here, but it may be added back if needed.
-constexpr bool kScriptsCanExecuteEverywhere = false;
-
-}  // namespace
-
 std::vector<api::scripts_internal::ScriptSource> GetSourcesFromFileNames(
     std::vector<std::string> file_names) {
   std::vector<api::scripts_internal::ScriptSource> script_sources;
@@ -198,14 +189,12 @@
           parse_options.index_for_error, user_script.get(), error_out)) {
     return nullptr;
   }
-  const int valid_schemes = parse_options.custom_schemes.value_or(
-      UserScript::ValidUserScriptSchemes(kScriptsCanExecuteEverywhere));
   // `excludeMatches`/`matches`.
   if (!script_parsing::ParseMatchPatterns(
           serialized_script.matches,
           base::OptionalToPtr(serialized_script.exclude_matches),
           extension.creation_flags(),
-          parse_options.can_execute_script_everywhere, valid_schemes,
+          parse_options.can_execute_script_everywhere,
           parse_options.all_urls_includes_chrome_urls,
           parse_options.index_for_error, user_script.get(), error_out,
           wants_file_access_out)) {
diff --git a/extensions/common/api/scripts_internal/script_serialization.h b/extensions/common/api/scripts_internal/script_serialization.h
index fbed764..c7fced8 100644
--- a/extensions/common/api/scripts_internal/script_serialization.h
+++ b/extensions/common/api/scripts_internal/script_serialization.h
@@ -29,8 +29,6 @@
 struct SerializedUserScriptParseOptions {
   // If populated, used in the error message.
   absl::optional<int> index_for_error;
-  // If populated, used instead of the default schemes for URLPattern parsing.
-  absl::optional<int> custom_schemes;
   // If true, indicates the extension can execute scripts on every page without
   // additional permission (this should only be true for special extensions like
   // ChromeVox).
diff --git a/extensions/common/manifest_handlers/content_scripts_handler.cc b/extensions/common/manifest_handlers/content_scripts_handler.cc
index 3e749207..dff1fcd 100644
--- a/extensions/common/manifest_handlers/content_scripts_handler.cc
+++ b/extensions/common/manifest_handlers/content_scripts_handler.cc
@@ -43,7 +43,6 @@
     content_scripts_api::ContentScript content_script,
     int definition_index,
     bool can_execute_script_everywhere,
-    int valid_schemes,
     bool all_urls_includes_chrome_urls,
     Extension* extension,
     std::u16string* error) {
@@ -133,7 +132,6 @@
 
   script_serialization::SerializedUserScriptParseOptions parse_options;
   parse_options.index_for_error = definition_index;
-  parse_options.custom_schemes = valid_schemes;
   parse_options.can_execute_script_everywhere = can_execute_script_everywhere;
   parse_options.all_urls_includes_chrome_urls = all_urls_includes_chrome_urls;
 
@@ -230,14 +228,12 @@
   const bool can_execute_script_everywhere =
       PermissionsData::CanExecuteScriptEverywhere(extension->id(),
                                                   extension->location());
-  const int valid_schemes =
-      UserScript::ValidUserScriptSchemes(can_execute_script_everywhere);
   const bool all_urls_includes_chrome_urls =
       PermissionsData::AllUrlsIncludesChromeUrls(extension->id());
   for (size_t i = 0; i < manifest_keys.content_scripts.size(); ++i) {
     std::unique_ptr<UserScript> user_script =
         CreateUserScript(std::move(manifest_keys.content_scripts[i]), i,
-                         can_execute_script_everywhere, valid_schemes,
+                         can_execute_script_everywhere,
                          all_urls_includes_chrome_urls, extension, error);
     if (!user_script)
       return false;  // Failed to parse script context definition.
diff --git a/extensions/common/utils/content_script_utils.cc b/extensions/common/utils/content_script_utils.cc
index 41143d09..49eb4bf0 100644
--- a/extensions/common/utils/content_script_utils.cc
+++ b/extensions/common/utils/content_script_utils.cc
@@ -213,7 +213,6 @@
                         const std::vector<std::string>* exclude_matches,
                         int creation_flags,
                         bool can_execute_script_everywhere,
-                        int valid_schemes,
                         bool all_urls_includes_chrome_urls,
                         absl::optional<int> definition_index,
                         UserScript* result,
@@ -224,6 +223,9 @@
     return false;
   }
 
+  const int valid_schemes =
+      UserScript::ValidUserScriptSchemes(can_execute_script_everywhere);
+
   for (size_t i = 0; i < matches.size(); ++i) {
     URLPattern pattern(valid_schemes);
 
diff --git a/extensions/common/utils/content_script_utils.h b/extensions/common/utils/content_script_utils.h
index d76d53b..2bdde78 100644
--- a/extensions/common/utils/content_script_utils.h
+++ b/extensions/common/utils/content_script_utils.h
@@ -49,7 +49,6 @@
                         const std::vector<std::string>* exclude_matches,
                         int creation_flags,
                         bool can_execute_script_everywhere,
-                        int valid_schemes,
                         bool all_urls_includes_chrome_urls,
                         absl::optional<int> definition_index,
                         UserScript* result,
diff --git a/gpu/command_buffer/service/dawn_context_provider.cc b/gpu/command_buffer/service/dawn_context_provider.cc
index a2bee58..6de2d30d 100644
--- a/gpu/command_buffer/service/dawn_context_provider.cc
+++ b/gpu/command_buffer/service/dawn_context_provider.cc
@@ -246,6 +246,8 @@
   enabled_toggles.push_back("disable_robustness");
 #endif
 
+  enabled_toggles.push_back("disable_lazy_clear_for_mapped_at_creation_buffer");
+
 #if BUILDFLAG(IS_APPLE)
   // We need MultiPlanarFormatExtendedUsages to copy to/from multiplanar
   // texture. And this feature is currently experimental.
diff --git a/gpu/command_buffer/service/shared_image/dawn_gl_texture_representation.cc b/gpu/command_buffer/service/shared_image/dawn_gl_texture_representation.cc
index 1ea2b82..ef01d2a97 100644
--- a/gpu/command_buffer/service/shared_image/dawn_gl_texture_representation.cc
+++ b/gpu/command_buffer/service/shared_image/dawn_gl_texture_representation.cc
@@ -48,6 +48,13 @@
 
   // TODO(crbug.com/1472861): implement support for multiplanar formats.
   texture_descriptor.format = ToDawnFormat(format());
+
+  // Add internal TextureBinding usage for copyTextureForBrowser().
+  wgpu::DawnTextureInternalUsageDescriptor internalDesc;
+  internalDesc.internalUsage = wgpu::TextureUsage::TextureBinding;
+
+  texture_descriptor.nextInChain = &internalDesc;
+
   texture_descriptor.usage = usage;
   texture_descriptor.dimension = wgpu::TextureDimension::e2D;
   texture_descriptor.size = {static_cast<uint32_t>(size().width()),
diff --git a/gpu/vulkan/vulkan_function_pointers.cc b/gpu/vulkan/vulkan_function_pointers.cc
index 09d77d3..cd77267 100644
--- a/gpu/vulkan/vulkan_function_pointers.cc
+++ b/gpu/vulkan/vulkan_function_pointers.cc
@@ -62,8 +62,7 @@
   vkCreateInstance = reinterpret_cast<PFN_vkCreateInstance>(
       vkGetInstanceProcAddr(nullptr, "vkCreateInstance"));
   if (!vkCreateInstance) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkCreateInstance";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkCreateInstance";
     return false;
   }
 
@@ -98,8 +97,7 @@
   vkCreateDevice = reinterpret_cast<PFN_vkCreateDevice>(
       vkGetInstanceProcAddr(vk_instance, "vkCreateDevice"));
   if (!vkCreateDevice) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkCreateDevice";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkCreateDevice";
     return false;
   }
 
@@ -424,8 +422,7 @@
   vkAllocateMemory = reinterpret_cast<PFN_vkAllocateMemory>(
       vkGetDeviceProcAddr(vk_device, "vkAllocateMemory"));
   if (!vkAllocateMemory) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkAllocateMemory";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkAllocateMemory";
     return false;
   }
 
@@ -504,8 +501,7 @@
   vkCmdCopyBuffer = reinterpret_cast<PFN_vkCmdCopyBuffer>(
       vkGetDeviceProcAddr(vk_device, "vkCmdCopyBuffer"));
   if (!vkCmdCopyBuffer) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkCmdCopyBuffer";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkCmdCopyBuffer";
     return false;
   }
 
@@ -528,8 +524,7 @@
   vkCmdDraw = reinterpret_cast<PFN_vkCmdDraw>(
       vkGetDeviceProcAddr(vk_device, "vkCmdDraw"));
   if (!vkCmdDraw) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkCmdDraw";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkCmdDraw";
     return false;
   }
 
@@ -552,8 +547,7 @@
   vkCmdNextSubpass = reinterpret_cast<PFN_vkCmdNextSubpass>(
       vkGetDeviceProcAddr(vk_device, "vkCmdNextSubpass"));
   if (!vkCmdNextSubpass) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkCmdNextSubpass";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkCmdNextSubpass";
     return false;
   }
 
@@ -576,24 +570,21 @@
   vkCmdSetScissor = reinterpret_cast<PFN_vkCmdSetScissor>(
       vkGetDeviceProcAddr(vk_device, "vkCmdSetScissor"));
   if (!vkCmdSetScissor) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkCmdSetScissor";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkCmdSetScissor";
     return false;
   }
 
   vkCmdSetViewport = reinterpret_cast<PFN_vkCmdSetViewport>(
       vkGetDeviceProcAddr(vk_device, "vkCmdSetViewport"));
   if (!vkCmdSetViewport) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkCmdSetViewport";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkCmdSetViewport";
     return false;
   }
 
   vkCreateBuffer = reinterpret_cast<PFN_vkCreateBuffer>(
       vkGetDeviceProcAddr(vk_device, "vkCreateBuffer"));
   if (!vkCreateBuffer) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkCreateBuffer";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkCreateBuffer";
     return false;
   }
 
@@ -625,8 +616,7 @@
   vkCreateFence = reinterpret_cast<PFN_vkCreateFence>(
       vkGetDeviceProcAddr(vk_device, "vkCreateFence"));
   if (!vkCreateFence) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkCreateFence";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkCreateFence";
     return false;
   }
 
@@ -649,8 +639,7 @@
   vkCreateImage = reinterpret_cast<PFN_vkCreateImage>(
       vkGetDeviceProcAddr(vk_device, "vkCreateImage"));
   if (!vkCreateImage) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkCreateImage";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkCreateImage";
     return false;
   }
 
@@ -681,8 +670,7 @@
   vkCreateSampler = reinterpret_cast<PFN_vkCreateSampler>(
       vkGetDeviceProcAddr(vk_device, "vkCreateSampler"));
   if (!vkCreateSampler) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkCreateSampler";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkCreateSampler";
     return false;
   }
 
@@ -705,8 +693,7 @@
   vkDestroyBuffer = reinterpret_cast<PFN_vkDestroyBuffer>(
       vkGetDeviceProcAddr(vk_device, "vkDestroyBuffer"));
   if (!vkDestroyBuffer) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkDestroyBuffer";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkDestroyBuffer";
     return false;
   }
 
@@ -738,16 +725,14 @@
   vkDestroyDevice = reinterpret_cast<PFN_vkDestroyDevice>(
       vkGetDeviceProcAddr(vk_device, "vkDestroyDevice"));
   if (!vkDestroyDevice) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkDestroyDevice";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkDestroyDevice";
     return false;
   }
 
   vkDestroyFence = reinterpret_cast<PFN_vkDestroyFence>(
       vkGetDeviceProcAddr(vk_device, "vkDestroyFence"));
   if (!vkDestroyFence) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkDestroyFence";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkDestroyFence";
     return false;
   }
 
@@ -762,8 +747,7 @@
   vkDestroyImage = reinterpret_cast<PFN_vkDestroyImage>(
       vkGetDeviceProcAddr(vk_device, "vkDestroyImage"));
   if (!vkDestroyImage) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkDestroyImage";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkDestroyImage";
     return false;
   }
 
@@ -802,8 +786,7 @@
   vkDestroySampler = reinterpret_cast<PFN_vkDestroySampler>(
       vkGetDeviceProcAddr(vk_device, "vkDestroySampler"));
   if (!vkDestroySampler) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkDestroySampler";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkDestroySampler";
     return false;
   }
 
@@ -826,8 +809,7 @@
   vkDeviceWaitIdle = reinterpret_cast<PFN_vkDeviceWaitIdle>(
       vkGetDeviceProcAddr(vk_device, "vkDeviceWaitIdle"));
   if (!vkDeviceWaitIdle) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkDeviceWaitIdle";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkDeviceWaitIdle";
     return false;
   }
 
@@ -866,8 +848,7 @@
   vkFreeMemory = reinterpret_cast<PFN_vkFreeMemory>(
       vkGetDeviceProcAddr(vk_device, "vkFreeMemory"));
   if (!vkFreeMemory) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkFreeMemory";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkFreeMemory";
     return false;
   }
 
@@ -901,8 +882,7 @@
   vkGetDeviceQueue = reinterpret_cast<PFN_vkGetDeviceQueue>(
       vkGetDeviceProcAddr(vk_device, "vkGetDeviceQueue"));
   if (!vkGetDeviceQueue) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkGetDeviceQueue";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkGetDeviceQueue";
     return false;
   }
 
@@ -917,8 +897,7 @@
   vkGetFenceStatus = reinterpret_cast<PFN_vkGetFenceStatus>(
       vkGetDeviceProcAddr(vk_device, "vkGetFenceStatus"));
   if (!vkGetFenceStatus) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkGetFenceStatus";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkGetFenceStatus";
     return false;
   }
 
@@ -952,24 +931,21 @@
   vkMapMemory = reinterpret_cast<PFN_vkMapMemory>(
       vkGetDeviceProcAddr(vk_device, "vkMapMemory"));
   if (!vkMapMemory) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkMapMemory";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkMapMemory";
     return false;
   }
 
   vkQueueSubmit = reinterpret_cast<PFN_vkQueueSubmit>(
       vkGetDeviceProcAddr(vk_device, "vkQueueSubmit"));
   if (!vkQueueSubmit) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkQueueSubmit";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkQueueSubmit";
     return false;
   }
 
   vkQueueWaitIdle = reinterpret_cast<PFN_vkQueueWaitIdle>(
       vkGetDeviceProcAddr(vk_device, "vkQueueWaitIdle"));
   if (!vkQueueWaitIdle) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkQueueWaitIdle";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkQueueWaitIdle";
     return false;
   }
 
@@ -984,16 +960,14 @@
   vkResetFences = reinterpret_cast<PFN_vkResetFences>(
       vkGetDeviceProcAddr(vk_device, "vkResetFences"));
   if (!vkResetFences) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkResetFences";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkResetFences";
     return false;
   }
 
   vkUnmapMemory = reinterpret_cast<PFN_vkUnmapMemory>(
       vkGetDeviceProcAddr(vk_device, "vkUnmapMemory"));
   if (!vkUnmapMemory) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkUnmapMemory";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkUnmapMemory";
     return false;
   }
 
@@ -1008,8 +982,7 @@
   vkWaitForFences = reinterpret_cast<PFN_vkWaitForFences>(
       vkGetDeviceProcAddr(vk_device, "vkWaitForFences"));
   if (!vkWaitForFences) {
-    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
-                  << "vkWaitForFences";
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: " << "vkWaitForFences";
     return false;
   }
 
diff --git "a/infra/config/generated/builders/ci/Android arm64 Builder All Targets \050dbg\051/properties.json" "b/infra/config/generated/builders/ci/Android arm64 Builder All Targets \050dbg\051/properties.json"
index e8d9eafb..05e933b 100644
--- "a/infra/config/generated/builders/ci/Android arm64 Builder All Targets \050dbg\051/properties.json"
+++ "b/infra/config/generated/builders/ci/Android arm64 Builder All Targets \050dbg\051/properties.json"
@@ -53,6 +53,10 @@
         {
           "builder": "android_compile_dbg",
           "group": "tryserver.chromium.android"
+        },
+        {
+          "builder": "android_compile_siso_dbg",
+          "group": "tryserver.chromium.android"
         }
       ]
     }
diff --git "a/infra/config/generated/builders/ci/Linux Builder \050dbg\051/properties.json" "b/infra/config/generated/builders/ci/Linux Builder \050dbg\051/properties.json"
index 712de12..340fd3a7 100644
--- "a/infra/config/generated/builders/ci/Linux Builder \050dbg\051/properties.json"
+++ "b/infra/config/generated/builders/ci/Linux Builder \050dbg\051/properties.json"
@@ -79,6 +79,10 @@
           "group": "tryserver.chromium.linux"
         },
         {
+          "builder": "linux_chromium_compile_siso_dbg_ng",
+          "group": "tryserver.chromium.linux"
+        },
+        {
           "builder": "linux_chromium_dbg_ng",
           "group": "tryserver.chromium.linux"
         }
diff --git "a/infra/config/generated/builders/ci/Linux Tests \050dbg\051\0501\051/properties.json" "b/infra/config/generated/builders/ci/Linux Tests \050dbg\051\0501\051/properties.json"
index 6b38b79..d2f0ed27 100644
--- "a/infra/config/generated/builders/ci/Linux Tests \050dbg\051\0501\051/properties.json"
+++ "b/infra/config/generated/builders/ci/Linux Tests \050dbg\051\0501\051/properties.json"
@@ -69,6 +69,10 @@
           "group": "tryserver.chromium.linux"
         },
         {
+          "builder": "linux_chromium_compile_siso_dbg_ng",
+          "group": "tryserver.chromium.linux"
+        },
+        {
           "builder": "linux_chromium_dbg_ng",
           "group": "tryserver.chromium.linux"
         }
diff --git a/infra/config/generated/builders/ci/linux-chromeos-dbg/properties.json b/infra/config/generated/builders/ci/linux-chromeos-dbg/properties.json
index dadb5cc..be5e1b2 100644
--- a/infra/config/generated/builders/ci/linux-chromeos-dbg/properties.json
+++ b/infra/config/generated/builders/ci/linux-chromeos-dbg/properties.json
@@ -45,6 +45,10 @@
           "group": "tryserver.chromium.chromiumos"
         },
         {
+          "builder": "linux-chromeos-compile-siso-dbg",
+          "group": "tryserver.chromium.chromiumos"
+        },
+        {
           "builder": "linux-chromeos-dbg",
           "group": "tryserver.chromium.chromiumos"
         }
diff --git a/infra/config/generated/builders/gn_args_locations.json b/infra/config/generated/builders/gn_args_locations.json
index f158687..315fd778 100644
--- a/infra/config/generated/builders/gn_args_locations.json
+++ b/infra/config/generated/builders/gn_args_locations.json
@@ -169,6 +169,7 @@
     "android-asan-compile-dbg": "try/android-asan-compile-dbg/gn-args.json",
     "android-bfcache-rel": "try/android-bfcache-rel/gn-args.json",
     "android-binary-size": "try/android-binary-size/gn-args.json",
+    "android-binary-size-siso": "try/android-binary-size-siso/gn-args.json",
     "android-cronet-arm-dbg": "try/android-cronet-arm-dbg/gn-args.json",
     "android-cronet-arm64-dbg": "try/android-cronet-arm64-dbg/gn-args.json",
     "android-cronet-arm64-rel": "try/android-cronet-arm64-rel/gn-args.json",
@@ -207,6 +208,7 @@
     "android-x86-rel": "try/android-x86-rel/gn-args.json",
     "android_arm64_dbg_recipe": "try/android_arm64_dbg_recipe/gn-args.json",
     "android_compile_dbg": "try/android_compile_dbg/gn-args.json",
+    "android_compile_siso_dbg": "try/android_compile_siso_dbg/gn-args.json",
     "android_compile_x64_dbg": "try/android_compile_x64_dbg/gn-args.json",
     "android_compile_x86_dbg": "try/android_compile_x86_dbg/gn-args.json",
     "android_cronet": "try/android_cronet/gn-args.json"
@@ -224,6 +226,7 @@
     "linux-x64-castos-audio": "try/linux-x64-castos-audio/gn-args.json",
     "linux-x64-castos-dbg": "try/linux-x64-castos-dbg/gn-args.json",
     "linux_chromium_compile_dbg_ng": "try/linux_chromium_compile_dbg_ng/gn-args.json",
+    "linux_chromium_compile_siso_dbg_ng": "try/linux_chromium_compile_siso_dbg_ng/gn-args.json",
     "linux_chromium_dbg_ng": "try/linux_chromium_dbg_ng/gn-args.json",
     "network_service_linux": "try/network_service_linux/gn-args.json"
   },
diff --git a/infra/config/generated/builders/try/android-binary-size-siso/gn-args.json b/infra/config/generated/builders/try/android-binary-size-siso/gn-args.json
new file mode 100644
index 0000000..2d8abbd0
--- /dev/null
+++ b/infra/config/generated/builders/try/android-binary-size-siso/gn-args.json
@@ -0,0 +1,14 @@
+{
+  "gn_args": {
+    "android_channel": "stable",
+    "debuggable_apks": false,
+    "ffmpeg_branding": "Chrome",
+    "is_official_build": true,
+    "is_on_release_branch": true,
+    "proprietary_codecs": true,
+    "symbol_level": 1,
+    "target_os": "android",
+    "use_dummy_lastchange": true,
+    "use_remoteexec": true
+  }
+}
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/android_compile_siso_dbg/gn-args.json b/infra/config/generated/builders/try/android_compile_siso_dbg/gn-args.json
new file mode 100644
index 0000000..35a882c
--- /dev/null
+++ b/infra/config/generated/builders/try/android_compile_siso_dbg/gn-args.json
@@ -0,0 +1,14 @@
+{
+  "gn_args": {
+    "debuggable_apks": false,
+    "ffmpeg_branding": "Chrome",
+    "is_component_build": true,
+    "is_debug": true,
+    "proprietary_codecs": true,
+    "symbol_level": 0,
+    "target_cpu": "arm64",
+    "target_os": "android",
+    "use_dummy_lastchange": true,
+    "use_remoteexec": true
+  }
+}
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/android_compile_siso_dbg/properties.json b/infra/config/generated/builders/try/android_compile_siso_dbg/properties.json
new file mode 100644
index 0000000..ead6b94
--- /dev/null
+++ b/infra/config/generated/builders/try/android_compile_siso_dbg/properties.json
@@ -0,0 +1,80 @@
+{
+  "$build/chromium_tests_builder_config": {
+    "builder_config": {
+      "additional_exclusions": [
+        "infra/config/generated/builders/try/android_compile_siso_dbg/gn-args.json"
+      ],
+      "builder_db": {
+        "entries": [
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "Android arm64 Builder All Targets (dbg)",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "build_gs_bucket": "chromium-android-archive",
+              "builder_group": "chromium.android",
+              "execution_mode": "COMPILE_AND_TEST",
+              "legacy_android_config": {
+                "config": "main_builder_mb"
+              },
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "download_xr_test_apks"
+                ],
+                "build_config": "Debug",
+                "config": "android",
+                "target_bits": 64,
+                "target_platform": "android"
+              },
+              "legacy_gclient_config": {
+                "apply_configs": [
+                  "android"
+                ],
+                "config": "chromium"
+              }
+            }
+          }
+        ]
+      },
+      "builder_ids": [
+        {
+          "bucket": "ci",
+          "builder": "Android arm64 Builder All Targets (dbg)",
+          "project": "chromium"
+        }
+      ],
+      "is_compile_only": true
+    }
+  },
+  "$build/flakiness": {
+    "check_for_flakiness": true,
+    "check_for_flakiness_with_resultdb": true
+  },
+  "$build/reclient": {
+    "instance": "rbe-chromium-untrusted",
+    "jobs": 500,
+    "metrics_project": "chromium-reclient-metrics",
+    "scandeps_server": true
+  },
+  "$build/siso": {
+    "configs": [
+      "builder"
+    ],
+    "enable_cloud_profiler": true,
+    "enable_cloud_trace": true,
+    "experiments": [],
+    "project": "rbe-chromium-untrusted"
+  },
+  "$recipe_engine/resultdb/test_presentation": {
+    "column_keys": [],
+    "grouping_keys": [
+      "status",
+      "v.test_suite"
+    ]
+  },
+  "builder_group": "tryserver.chromium.android",
+  "cq": "required",
+  "recipe": "chromium_trybot"
+}
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/linux-chromeos-compile-siso-dbg/properties.json b/infra/config/generated/builders/try/linux-chromeos-compile-siso-dbg/properties.json
new file mode 100644
index 0000000..c2b1a0c
--- /dev/null
+++ b/infra/config/generated/builders/try/linux-chromeos-compile-siso-dbg/properties.json
@@ -0,0 +1,74 @@
+{
+  "$build/chromium_tests_builder_config": {
+    "builder_config": {
+      "builder_db": {
+        "entries": [
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "linux-chromeos-dbg",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "build_gs_bucket": "chromium-chromiumos-archive",
+              "builder_group": "chromium.chromiumos",
+              "execution_mode": "COMPILE_AND_TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "mb"
+                ],
+                "build_config": "Debug",
+                "config": "chromium",
+                "target_arch": "intel",
+                "target_bits": 64
+              },
+              "legacy_gclient_config": {
+                "apply_configs": [
+                  "chromeos"
+                ],
+                "config": "chromium"
+              }
+            }
+          }
+        ]
+      },
+      "builder_ids": [
+        {
+          "bucket": "ci",
+          "builder": "linux-chromeos-dbg",
+          "project": "chromium"
+        }
+      ],
+      "is_compile_only": true
+    }
+  },
+  "$build/flakiness": {
+    "check_for_flakiness": true,
+    "check_for_flakiness_with_resultdb": true
+  },
+  "$build/reclient": {
+    "instance": "rbe-chromium-untrusted",
+    "jobs": 500,
+    "metrics_project": "chromium-reclient-metrics",
+    "scandeps_server": true
+  },
+  "$build/siso": {
+    "configs": [
+      "builder"
+    ],
+    "enable_cloud_profiler": true,
+    "enable_cloud_trace": true,
+    "experiments": [],
+    "project": "rbe-chromium-untrusted"
+  },
+  "$recipe_engine/resultdb/test_presentation": {
+    "column_keys": [],
+    "grouping_keys": [
+      "status",
+      "v.test_suite"
+    ]
+  },
+  "builder_group": "tryserver.chromium.chromiumos",
+  "cq": "required",
+  "recipe": "chromium_trybot"
+}
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/linux_chromium_compile_siso_dbg_ng/gn-args.json b/infra/config/generated/builders/try/linux_chromium_compile_siso_dbg_ng/gn-args.json
new file mode 100644
index 0000000..df67d1e
--- /dev/null
+++ b/infra/config/generated/builders/try/linux_chromium_compile_siso_dbg_ng/gn-args.json
@@ -0,0 +1,9 @@
+{
+  "gn_args": {
+    "is_component_build": true,
+    "is_debug": true,
+    "symbol_level": 1,
+    "use_dummy_lastchange": true,
+    "use_remoteexec": true
+  }
+}
\ No newline at end of file
diff --git a/infra/config/generated/builders/try/linux_chromium_compile_siso_dbg_ng/properties.json b/infra/config/generated/builders/try/linux_chromium_compile_siso_dbg_ng/properties.json
new file mode 100644
index 0000000..a2d87e6
--- /dev/null
+++ b/infra/config/generated/builders/try/linux_chromium_compile_siso_dbg_ng/properties.json
@@ -0,0 +1,108 @@
+{
+  "$build/chromium_tests_builder_config": {
+    "builder_config": {
+      "additional_exclusions": [
+        "infra/config/generated/builders/try/linux_chromium_compile_siso_dbg_ng/gn-args.json"
+      ],
+      "builder_db": {
+        "entries": [
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "Linux Builder (dbg)",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "build_gs_bucket": "chromium-linux-archive",
+              "builder_group": "chromium.linux",
+              "execution_mode": "COMPILE_AND_TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "mb"
+                ],
+                "build_config": "Debug",
+                "config": "chromium",
+                "target_bits": 64
+              },
+              "legacy_gclient_config": {
+                "config": "chromium"
+              }
+            }
+          },
+          {
+            "builder_id": {
+              "bucket": "ci",
+              "builder": "Linux Tests (dbg)(1)",
+              "project": "chromium"
+            },
+            "builder_spec": {
+              "build_gs_bucket": "chromium-linux-archive",
+              "builder_group": "chromium.linux",
+              "execution_mode": "TEST",
+              "legacy_chromium_config": {
+                "apply_configs": [
+                  "mb"
+                ],
+                "build_config": "Debug",
+                "config": "chromium",
+                "target_bits": 64
+              },
+              "legacy_gclient_config": {
+                "config": "chromium"
+              },
+              "parent": {
+                "bucket": "ci",
+                "builder": "Linux Builder (dbg)",
+                "project": "chromium"
+              }
+            }
+          }
+        ]
+      },
+      "builder_ids": [
+        {
+          "bucket": "ci",
+          "builder": "Linux Builder (dbg)",
+          "project": "chromium"
+        }
+      ],
+      "builder_ids_in_scope_for_testing": [
+        {
+          "bucket": "ci",
+          "builder": "Linux Tests (dbg)(1)",
+          "project": "chromium"
+        }
+      ],
+      "is_compile_only": true
+    }
+  },
+  "$build/flakiness": {
+    "check_for_flakiness": true,
+    "check_for_flakiness_with_resultdb": true
+  },
+  "$build/reclient": {
+    "instance": "rbe-chromium-untrusted",
+    "jobs": 500,
+    "metrics_project": "chromium-reclient-metrics",
+    "scandeps_server": true
+  },
+  "$build/siso": {
+    "configs": [
+      "builder"
+    ],
+    "enable_cloud_profiler": true,
+    "enable_cloud_trace": true,
+    "experiments": [],
+    "project": "rbe-chromium-untrusted"
+  },
+  "$recipe_engine/resultdb/test_presentation": {
+    "column_keys": [],
+    "grouping_keys": [
+      "status",
+      "v.test_suite"
+    ]
+  },
+  "builder_group": "tryserver.chromium.linux",
+  "cq": "required",
+  "recipe": "chromium_trybot"
+}
\ No newline at end of file
diff --git a/infra/config/generated/cq-builders.md b/infra/config/generated/cq-builders.md
index 3ae2b7e..550c3681 100644
--- a/infra/config/generated/cq-builders.md
+++ b/infra/config/generated/cq-builders.md
@@ -605,9 +605,15 @@
 * [android-arm64-siso-rel](https://ci.chromium.org/p/chromium/builders/try/android-arm64-siso-rel) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""android-arm64-siso-rel""))
   * Experiment percentage: 10.0
 
+* [android-binary-size-siso](https://ci.chromium.org/p/chromium/builders/try/android-binary-size-siso) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""android-binary-size-siso""))
+  * Experiment percentage: 10.0
+
 * [android-x86-dual-coverage-exp-rel](https://ci.chromium.org/p/chromium/builders/try/android-x86-dual-coverage-exp-rel) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""android-x86-dual-coverage-exp-rel""))
   * Experiment percentage: 10.0
 
+* [android_compile_siso_dbg](https://ci.chromium.org/p/chromium/builders/try/android_compile_siso_dbg) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""android_compile_siso_dbg""))
+  * Experiment percentage: 10.0
+
 * [chromeos-amd64-generic-siso-rel](https://ci.chromium.org/p/chromium/builders/try/chromeos-amd64-generic-siso-rel) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""chromeos-amd64-generic-siso-rel""))
   * Experiment percentage: 10.0
 
@@ -633,15 +639,24 @@
   * [`//tools/clang/scripts/update.py`](https://cs.chromium.org/search?q=+file:tools/clang/scripts/update.py)
   * [`//ui/gl/features.gni`](https://cs.chromium.org/search?q=+file:ui/gl/features.gni)
 
+* [fuchsia-binary-size-siso](https://ci.chromium.org/p/chromium/builders/try/fuchsia-binary-size-siso) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""fuchsia-binary-size-siso""))
+  * Experiment percentage: 10.0
+
 * [ios-simulator-siso](https://ci.chromium.org/p/chromium/builders/try/ios-simulator-siso) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""ios-simulator-siso""))
   * Experiment percentage: 10.0
 
+* [linux-chromeos-compile-siso-dbg](https://ci.chromium.org/p/chromium/builders/try/linux-chromeos-compile-siso-dbg) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""linux-chromeos-compile-siso-dbg""))
+  * Experiment percentage: 10.0
+
 * [linux-siso-rel](https://ci.chromium.org/p/chromium/builders/try/linux-siso-rel) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""linux-siso-rel""))
   * Experiment percentage: 10.0
 
 * [linux_chromium_asan_siso_rel_ng](https://ci.chromium.org/p/chromium/builders/try/linux_chromium_asan_siso_rel_ng) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""linux_chromium_asan_siso_rel_ng""))
   * Experiment percentage: 10.0
 
+* [linux_chromium_compile_siso_dbg_ng](https://ci.chromium.org/p/chromium/builders/try/linux_chromium_compile_siso_dbg_ng) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""linux_chromium_compile_siso_dbg_ng""))
+  * Experiment percentage: 10.0
+
 * [linux_chromium_tsan_siso_rel_ng](https://ci.chromium.org/p/chromium/builders/try/linux_chromium_tsan_siso_rel_ng) ([definition](https://cs.chromium.org/search?q=+file:/try/.*\.star$+""linux_chromium_tsan_siso_rel_ng""))
   * Experiment percentage: 10.0
 
diff --git a/infra/config/generated/cq-usage/mega_cq_bots.txt b/infra/config/generated/cq-usage/mega_cq_bots.txt
index 6004f973..1c62d069 100644
--- a/infra/config/generated/cq-usage/mega_cq_bots.txt
+++ b/infra/config/generated/cq-usage/mega_cq_bots.txt
@@ -26,6 +26,7 @@
 chromium/try/android-x86-rel
 chromium/try/android_arm64_dbg_recipe
 chromium/try/android_compile_dbg
+chromium/try/android_compile_siso_dbg
 chromium/try/android_compile_x64_dbg
 chromium/try/android_compile_x86_dbg
 chromium/try/chromeos-amd64-generic-asan-rel
@@ -90,6 +91,7 @@
 chromium/try/linux-cfm-rel
 chromium/try/linux-chromeos-asan-rel
 chromium/try/linux-chromeos-compile-dbg
+chromium/try/linux-chromeos-compile-siso-dbg
 chromium/try/linux-chromeos-dbg
 chromium/try/linux-chromeos-rel
 chromium/try/linux-clobber-rel
@@ -126,6 +128,7 @@
 chromium/try/linux_chromium_chromeos_msan_rel_ng
 chromium/try/linux_chromium_compile_dbg_ng
 chromium/try/linux_chromium_compile_rel_ng
+chromium/try/linux_chromium_compile_siso_dbg_ng
 chromium/try/linux_chromium_dbg_ng
 chromium/try/linux_chromium_msan_rel_ng
 chromium/try/linux_chromium_tsan_rel_ng
diff --git a/infra/config/generated/luci/commit-queue.cfg b/infra/config/generated/luci/commit-queue.cfg
index b4ac9e5..1a057d1 100644
--- a/infra/config/generated/luci/commit-queue.cfg
+++ b/infra/config/generated/luci/commit-queue.cfg
@@ -590,6 +590,29 @@
         mode_allowlist: "FULL_RUN"
       }
       builders {
+        name: "chromium/try/android-binary-size-siso"
+        experiment_percentage: 10
+        location_filters {
+          gerrit_host_regexp: ".*"
+          gerrit_project_regexp: ".*"
+          path_regexp: "docs/.+"
+          exclude: true
+        }
+        location_filters {
+          gerrit_host_regexp: ".*"
+          gerrit_project_regexp: ".*"
+          path_regexp: "infra/config/.+"
+          exclude: true
+        }
+        location_filters {
+          gerrit_host_regexp: ".*"
+          gerrit_project_regexp: ".*"
+          path_regexp: "infra/config/generated/builders/try/android-binary-size-siso/.+"
+        }
+        mode_allowlist: "DRY_RUN"
+        mode_allowlist: "FULL_RUN"
+      }
+      builders {
         name: "chromium/try/android-chrome-pie-x86-wpt-android-specific"
         includable_only: true
       }
@@ -1165,6 +1188,29 @@
         mode_allowlist: "FULL_RUN"
       }
       builders {
+        name: "chromium/try/android_compile_siso_dbg"
+        experiment_percentage: 10
+        location_filters {
+          gerrit_host_regexp: ".*"
+          gerrit_project_regexp: ".*"
+          path_regexp: "docs/.+"
+          exclude: true
+        }
+        location_filters {
+          gerrit_host_regexp: ".*"
+          gerrit_project_regexp: ".*"
+          path_regexp: "infra/config/.+"
+          exclude: true
+        }
+        location_filters {
+          gerrit_host_regexp: ".*"
+          gerrit_project_regexp: ".*"
+          path_regexp: "infra/config/generated/builders/try/android_compile_siso_dbg/.+"
+        }
+        mode_allowlist: "DRY_RUN"
+        mode_allowlist: "FULL_RUN"
+      }
+      builders {
         name: "chromium/try/android_compile_x64_dbg"
         location_filters {
           gerrit_host_regexp: ".*"
@@ -2347,6 +2393,29 @@
         mode_allowlist: "FULL_RUN"
       }
       builders {
+        name: "chromium/try/fuchsia-binary-size-siso"
+        experiment_percentage: 10
+        location_filters {
+          gerrit_host_regexp: ".*"
+          gerrit_project_regexp: ".*"
+          path_regexp: "docs/.+"
+          exclude: true
+        }
+        location_filters {
+          gerrit_host_regexp: ".*"
+          gerrit_project_regexp: ".*"
+          path_regexp: "infra/config/.+"
+          exclude: true
+        }
+        location_filters {
+          gerrit_host_regexp: ".*"
+          gerrit_project_regexp: ".*"
+          path_regexp: "infra/config/generated/builders/try/fuchsia-binary-size-siso/.+"
+        }
+        mode_allowlist: "DRY_RUN"
+        mode_allowlist: "FULL_RUN"
+      }
+      builders {
         name: "chromium/try/fuchsia-clang-tidy-rel"
         includable_only: true
       }
@@ -3287,6 +3356,29 @@
         mode_allowlist: "FULL_RUN"
       }
       builders {
+        name: "chromium/try/linux-chromeos-compile-siso-dbg"
+        experiment_percentage: 10
+        location_filters {
+          gerrit_host_regexp: ".*"
+          gerrit_project_regexp: ".*"
+          path_regexp: "docs/.+"
+          exclude: true
+        }
+        location_filters {
+          gerrit_host_regexp: ".*"
+          gerrit_project_regexp: ".*"
+          path_regexp: "infra/config/.+"
+          exclude: true
+        }
+        location_filters {
+          gerrit_host_regexp: ".*"
+          gerrit_project_regexp: ".*"
+          path_regexp: "infra/config/generated/builders/try/linux-chromeos-compile-siso-dbg/.+"
+        }
+        mode_allowlist: "DRY_RUN"
+        mode_allowlist: "FULL_RUN"
+      }
+      builders {
         name: "chromium/try/linux-chromeos-dbg"
         includable_only: true
       }
@@ -4037,6 +4129,29 @@
         includable_only: true
       }
       builders {
+        name: "chromium/try/linux_chromium_compile_siso_dbg_ng"
+        experiment_percentage: 10
+        location_filters {
+          gerrit_host_regexp: ".*"
+          gerrit_project_regexp: ".*"
+          path_regexp: "docs/.+"
+          exclude: true
+        }
+        location_filters {
+          gerrit_host_regexp: ".*"
+          gerrit_project_regexp: ".*"
+          path_regexp: "infra/config/.+"
+          exclude: true
+        }
+        location_filters {
+          gerrit_host_regexp: ".*"
+          gerrit_project_regexp: ".*"
+          path_regexp: "infra/config/generated/builders/try/linux_chromium_compile_siso_dbg_ng/.+"
+        }
+        mode_allowlist: "DRY_RUN"
+        mode_allowlist: "FULL_RUN"
+      }
+      builders {
         name: "chromium/try/linux_chromium_dbg_ng"
         location_filters {
           gerrit_host_regexp: ".*"
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 73c2d9d..b8357f51 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -3922,7 +3922,7 @@
           use_invocation_timestamp: true
         }
       }
-      description_html: "This builder is mirrored by any of the following try builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/android-arm64-all-targets-dbg\">android-arm64-all-targets-dbg</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/android_compile_dbg\">android_compile_dbg</a></li></ul>"
+      description_html: "This builder is mirrored by any of the following try builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/android-arm64-all-targets-dbg\">android-arm64-all-targets-dbg</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/android_compile_dbg\">android_compile_dbg</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/android_compile_siso_dbg\">android_compile_siso_dbg</a></li></ul>"
       shadow_builder_adjustments {
         service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
         pool: "luci.chromium.try"
@@ -15743,7 +15743,7 @@
           use_invocation_timestamp: true
         }
       }
-      description_html: "This builder is mirrored by any of the following try builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/linux_chromium_compile_dbg_ng\">linux_chromium_compile_dbg_ng</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/linux_chromium_dbg_ng\">linux_chromium_dbg_ng</a></li></ul>"
+      description_html: "This builder is mirrored by any of the following try builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/linux_chromium_compile_dbg_ng\">linux_chromium_compile_dbg_ng</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/linux_chromium_compile_siso_dbg_ng\">linux_chromium_compile_siso_dbg_ng</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/linux_chromium_dbg_ng\">linux_chromium_dbg_ng</a></li></ul>"
       shadow_builder_adjustments {
         service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
         pool: "luci.chromium.try"
@@ -17844,7 +17844,7 @@
           use_invocation_timestamp: true
         }
       }
-      description_html: "This builder is mirrored by any of the following try builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/linux_chromium_compile_dbg_ng\">linux_chromium_compile_dbg_ng</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/linux_chromium_dbg_ng\">linux_chromium_dbg_ng</a></li></ul>"
+      description_html: "This builder is mirrored by any of the following try builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/linux_chromium_compile_dbg_ng\">linux_chromium_compile_dbg_ng</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/linux_chromium_compile_siso_dbg_ng\">linux_chromium_compile_siso_dbg_ng</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/linux_chromium_dbg_ng\">linux_chromium_dbg_ng</a></li></ul>"
       shadow_builder_adjustments {
         service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
         pool: "luci.chromium.try"
@@ -43553,7 +43553,7 @@
           use_invocation_timestamp: true
         }
       }
-      description_html: "This builder is mirrored by any of the following try builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/linux-chromeos-compile-dbg\">linux-chromeos-compile-dbg</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/linux-chromeos-dbg\">linux-chromeos-dbg</a></li></ul>"
+      description_html: "This builder is mirrored by any of the following try builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/linux-chromeos-compile-dbg\">linux-chromeos-compile-dbg</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/linux-chromeos-compile-siso-dbg\">linux-chromeos-compile-siso-dbg</a></li><li><a href=\"https://ci.chromium.org/p/chromium/builders/try/linux-chromeos-dbg\">linux-chromeos-dbg</a></li></ul>"
       shadow_builder_adjustments {
         service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
         pool: "luci.chromium.try"
@@ -64179,6 +64179,119 @@
       }
     }
     builders {
+      name: "android-binary-size-siso"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "builderless:1"
+      dimensions: "cores:16"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:Ubuntu-22.04"
+      dimensions: "pool:luci.chromium.try"
+      dimensions: "ssd:1"
+      exe {
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/main"
+        cmd: "luciexe"
+      }
+      properties:
+        '{'
+        '  "$build/binary_size": {'
+        '    "analyze_targets": ['
+        '      "//chrome/android:monochrome_public_minimal_apks",'
+        '      "//chrome/android:trichrome_32_minimal_apks",'
+        '      "//chrome/android:validate_expectations",'
+        '      "//tools/binary_size:binary_size_trybot_py"'
+        '    ],'
+        '    "compile_targets": ['
+        '      "monochrome_public_minimal_apks",'
+        '      "monochrome_static_initializers",'
+        '      "trichrome_32_minimal_apks",'
+        '      "validate_expectations"'
+        '    ]'
+        '  },'
+        '  "$build/flakiness": {'
+        '    "check_for_flakiness": true,'
+        '    "check_for_flakiness_with_resultdb": true'
+        '  },'
+        '  "$build/reclient": {'
+        '    "instance": "rbe-chromium-untrusted",'
+        '    "jobs": 500,'
+        '    "metrics_project": "chromium-reclient-metrics",'
+        '    "scandeps_server": true'
+        '  },'
+        '  "$build/siso": {'
+        '    "configs": ['
+        '      "builder"'
+        '    ],'
+        '    "enable_cloud_profiler": true,'
+        '    "enable_cloud_trace": true,'
+        '    "experiments": [],'
+        '    "project": "rbe-chromium-untrusted"'
+        '  },'
+        '  "$recipe_engine/resultdb/test_presentation": {'
+        '    "column_keys": [],'
+        '    "grouping_keys": ['
+        '      "status",'
+        '      "v.test_suite"'
+        '    ]'
+        '  },'
+        '  "builder_group": "tryserver.chromium.android",'
+        '  "cq": "required",'
+        '  "recipe": "binary_size_trybot"'
+        '}'
+      execution_timeout_secs: 14400
+      expiration_secs: 7200
+      grace_period {
+        seconds: 120
+      }
+      build_numbers: YES
+      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+      task_template_canary_percentage {
+        value: 5
+      }
+      experiments {
+        key: "chromium_swarming.expose_merge_script_failures"
+        value: 100
+      }
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "try_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "gpu_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+"
+            }
+          }
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "blink_web_tests_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*_wpt_tests/.+)"
+            }
+          }
+        }
+        history_options {
+          use_invocation_timestamp: true
+        }
+      }
+      description_html: "This builder shadows android-binary-size builder to compare between Siso builds and Ninja builds.<br/>\nThis builder should be removed after migrating android-binary-size from Ninja to Siso. b/277863839\n"
+      contact_team_email: "chrome-build-team@google.com"
+    }
+    builders {
       name: "android-chrome-pie-x86-wpt-android-specific"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
@@ -69472,6 +69585,99 @@
       description_html: "This builder mirrors the following CI builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/Android arm64 Builder All Targets (dbg)\">Android arm64 Builder All Targets (dbg)</a></li></ul>"
     }
     builders {
+      name: "android_compile_siso_dbg"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "builderless:1"
+      dimensions: "cores:32"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:Ubuntu-22.04"
+      dimensions: "pool:luci.chromium.try"
+      dimensions: "ssd:1"
+      exe {
+        cipd_package: "infra/chromium/bootstrapper/${platform}"
+        cipd_version: "latest"
+        cmd: "bootstrapper"
+      }
+      properties:
+        '{'
+        '  "$bootstrap/exe": {'
+        '    "exe": {'
+        '      "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",'
+        '      "cipd_version": "refs/heads/main",'
+        '      "cmd": ['
+        '        "luciexe"'
+        '      ]'
+        '    }'
+        '  },'
+        '  "$bootstrap/properties": {'
+        '    "properties_file": "infra/config/generated/builders/try/android_compile_siso_dbg/properties.json",'
+        '    "top_level_project": {'
+        '      "ref": "refs/heads/main",'
+        '      "repo": {'
+        '        "host": "chromium.googlesource.com",'
+        '        "project": "chromium/src"'
+        '      }'
+        '    }'
+        '  },'
+        '  "builder_group": "tryserver.chromium.android",'
+        '  "cq": "required",'
+        '  "led_builder_is_bootstrapped": true,'
+        '  "recipe": "chromium_trybot"'
+        '}'
+      execution_timeout_secs: 14400
+      expiration_secs: 7200
+      grace_period {
+        seconds: 120
+      }
+      build_numbers: YES
+      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+      task_template_canary_percentage {
+        value: 5
+      }
+      experiments {
+        key: "chromium_swarming.expose_merge_script_failures"
+        value: 100
+      }
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "try_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "gpu_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+"
+            }
+          }
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "blink_web_tests_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*_wpt_tests/.+)"
+            }
+          }
+        }
+        history_options {
+          use_invocation_timestamp: true
+        }
+      }
+      description_html: "This builder shadows android_compile_dbg builder to compare between Siso builds and Ninja builds.<br/>\nThis builder should be removed after migrating android_compile_dbg from Ninja to Siso. b/277863839\n<br/>This builder mirrors the following CI builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/Android arm64 Builder All Targets (dbg)\">Android arm64 Builder All Targets (dbg)</a></li></ul>"
+      contact_team_email: "chrome-build-team@google.com"
+    }
+    builders {
       name: "android_compile_x64_dbg"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
@@ -73710,6 +73916,113 @@
       }
     }
     builders {
+      name: "fuchsia-binary-size-siso"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "builderless:1"
+      dimensions: "cores:16"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:Ubuntu-22.04"
+      dimensions: "pool:luci.chromium.try"
+      dimensions: "ssd:0"
+      exe {
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/main"
+        cmd: "luciexe"
+      }
+      properties:
+        '{'
+        '  "$build/binary_size": {'
+        '    "analyze_targets": ['
+        '      "//tools/fuchsia/size_tests:fuchsia_sizes"'
+        '    ],'
+        '    "compile_targets": ['
+        '      "fuchsia_sizes"'
+        '    ]'
+        '  },'
+        '  "$build/flakiness": {'
+        '    "check_for_flakiness": true,'
+        '    "check_for_flakiness_with_resultdb": true'
+        '  },'
+        '  "$build/reclient": {'
+        '    "instance": "rbe-chromium-untrusted",'
+        '    "jobs": 500,'
+        '    "metrics_project": "chromium-reclient-metrics",'
+        '    "scandeps_server": true'
+        '  },'
+        '  "$build/siso": {'
+        '    "configs": ['
+        '      "builder"'
+        '    ],'
+        '    "enable_cloud_profiler": true,'
+        '    "enable_cloud_trace": true,'
+        '    "experiments": [],'
+        '    "project": "rbe-chromium-untrusted"'
+        '  },'
+        '  "$recipe_engine/resultdb/test_presentation": {'
+        '    "column_keys": [],'
+        '    "grouping_keys": ['
+        '      "status",'
+        '      "v.test_suite"'
+        '    ]'
+        '  },'
+        '  "builder_group": "tryserver.chromium.fuchsia",'
+        '  "cq": "required",'
+        '  "recipe": "binary_size_fuchsia_trybot"'
+        '}'
+      execution_timeout_secs: 14400
+      expiration_secs: 7200
+      grace_period {
+        seconds: 120
+      }
+      build_numbers: YES
+      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+      task_template_canary_percentage {
+        value: 5
+      }
+      experiments {
+        key: "chromium_swarming.expose_merge_script_failures"
+        value: 100
+      }
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "try_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "gpu_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+"
+            }
+          }
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "blink_web_tests_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*_wpt_tests/.+)"
+            }
+          }
+        }
+        history_options {
+          use_invocation_timestamp: true
+        }
+      }
+      description_html: "This builder shadows fuchsia-binary-size builder to compare between Siso builds and Ninja builds.<br/>\nThis builder should be removed after migrating size from Ninja to Siso. b/277863839\n"
+      contact_team_email: "chrome-build-team@google.com"
+    }
+    builders {
       name: "fuchsia-clang-tidy-rel"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
@@ -83880,6 +84193,99 @@
       description_html: "This builder mirrors the following CI builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/linux-chromeos-dbg\">linux-chromeos-dbg</a></li></ul>"
     }
     builders {
+      name: "linux-chromeos-compile-siso-dbg"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "builderless:1"
+      dimensions: "cores:8"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:Ubuntu-22.04"
+      dimensions: "pool:luci.chromium.try"
+      dimensions: "ssd:0"
+      exe {
+        cipd_package: "infra/chromium/bootstrapper/${platform}"
+        cipd_version: "latest"
+        cmd: "bootstrapper"
+      }
+      properties:
+        '{'
+        '  "$bootstrap/exe": {'
+        '    "exe": {'
+        '      "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",'
+        '      "cipd_version": "refs/heads/main",'
+        '      "cmd": ['
+        '        "luciexe"'
+        '      ]'
+        '    }'
+        '  },'
+        '  "$bootstrap/properties": {'
+        '    "properties_file": "infra/config/generated/builders/try/linux-chromeos-compile-siso-dbg/properties.json",'
+        '    "top_level_project": {'
+        '      "ref": "refs/heads/main",'
+        '      "repo": {'
+        '        "host": "chromium.googlesource.com",'
+        '        "project": "chromium/src"'
+        '      }'
+        '    }'
+        '  },'
+        '  "builder_group": "tryserver.chromium.chromiumos",'
+        '  "cq": "required",'
+        '  "led_builder_is_bootstrapped": true,'
+        '  "recipe": "chromium_trybot"'
+        '}'
+      execution_timeout_secs: 14400
+      expiration_secs: 7200
+      grace_period {
+        seconds: 120
+      }
+      build_numbers: YES
+      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+      task_template_canary_percentage {
+        value: 5
+      }
+      experiments {
+        key: "chromium_swarming.expose_merge_script_failures"
+        value: 100
+      }
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "try_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "gpu_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+"
+            }
+          }
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "blink_web_tests_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*_wpt_tests/.+)"
+            }
+          }
+        }
+        history_options {
+          use_invocation_timestamp: true
+        }
+      }
+      description_html: "This builder shadows linux-chromeos-compile-dbg builder to compare between Siso builds and Ninja builds.<br/>\nThis builder should be removed after migrating linux-chromeos-compile-dbg from Ninja to Siso. b/277863839\n<br/>This builder mirrors the following CI builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/linux-chromeos-dbg\">linux-chromeos-dbg</a></li></ul>"
+      contact_team_email: "chrome-build-team@google.com"
+    }
+    builders {
       name: "linux-chromeos-dbg"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
@@ -90832,6 +91238,103 @@
       description_html: "This builder mirrors the following CI builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/Linux Builder\">Linux Builder</a></li></ul>"
     }
     builders {
+      name: "linux_chromium_compile_siso_dbg_ng"
+      swarming_host: "chromium-swarm.appspot.com"
+      dimensions: "builderless:1"
+      dimensions: "cores:8"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:Ubuntu-22.04"
+      dimensions: "pool:luci.chromium.try"
+      dimensions: "ssd:0"
+      exe {
+        cipd_package: "infra/chromium/bootstrapper/${platform}"
+        cipd_version: "latest"
+        cmd: "bootstrapper"
+      }
+      properties:
+        '{'
+        '  "$bootstrap/exe": {'
+        '    "exe": {'
+        '      "cipd_package": "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build",'
+        '      "cipd_version": "refs/heads/main",'
+        '      "cmd": ['
+        '        "luciexe"'
+        '      ]'
+        '    }'
+        '  },'
+        '  "$bootstrap/properties": {'
+        '    "properties_file": "infra/config/generated/builders/try/linux_chromium_compile_siso_dbg_ng/properties.json",'
+        '    "top_level_project": {'
+        '      "ref": "refs/heads/main",'
+        '      "repo": {'
+        '        "host": "chromium.googlesource.com",'
+        '        "project": "chromium/src"'
+        '      }'
+        '    }'
+        '  },'
+        '  "builder_group": "tryserver.chromium.linux",'
+        '  "cq": "required",'
+        '  "led_builder_is_bootstrapped": true,'
+        '  "recipe": "chromium_trybot"'
+        '}'
+      execution_timeout_secs: 14400
+      expiration_secs: 7200
+      grace_period {
+        seconds: 120
+      }
+      caches {
+        name: "builder"
+        path: "linux_debug"
+      }
+      build_numbers: YES
+      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+      task_template_canary_percentage {
+        value: 5
+      }
+      experiments {
+        key: "chromium_swarming.expose_merge_script_failures"
+        value: 100
+      }
+      experiments {
+        key: "luci.recipes.use_python3"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "try_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "gpu_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+"
+            }
+          }
+        }
+        bq_exports {
+          project: "chrome-luci-data"
+          dataset: "chromium"
+          table: "blink_web_tests_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*_wpt_tests/.+)"
+            }
+          }
+        }
+        history_options {
+          use_invocation_timestamp: true
+        }
+      }
+      description_html: "This builder shadows linux_chromium_compile_dbg_ng builder to compare between Siso builds and Ninja builds.<br/>\nThis builder should be removed after migrating linux_chromium_compile_dbg_ng from Ninja to Siso. b/277863839\n<br/>This builder mirrors the following CI builders:<br/><ul><li><a href=\"https://ci.chromium.org/p/chromium/builders/ci/Linux Builder (dbg)\">Linux Builder (dbg)</a></li></ul>"
+      contact_team_email: "chrome-build-team@google.com"
+    }
+    builders {
       name: "linux_chromium_dbg_ng"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
@@ -91648,7 +92151,7 @@
       name: "mac-angle-chromium-try"
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builder:mac-angle-chromium-try"
-      dimensions: "cpu:x86-64"
+      dimensions: "cpu:arm64"
       dimensions: "os:Mac"
       dimensions: "pool:luci.chromium.try"
       exe {
@@ -93921,7 +94424,7 @@
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac"
+      dimensions: "os:Mac-13"
       dimensions: "pool:luci.chromium.try"
       dimensions: "ssd:1"
       exe {
@@ -94370,7 +94873,7 @@
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builder:mac11.0-blink-rel"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac"
+      dimensions: "os:Mac-13"
       dimensions: "pool:luci.chromium.try"
       dimensions: "ssd:1"
       exe {
@@ -94459,7 +94962,7 @@
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac"
+      dimensions: "os:Mac-13"
       dimensions: "pool:luci.chromium.try"
       dimensions: "ssd:1"
       exe {
@@ -94908,7 +95411,7 @@
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac"
+      dimensions: "os:Mac-13"
       dimensions: "pool:luci.chromium.try"
       dimensions: "ssd:1"
       exe {
@@ -94997,7 +95500,7 @@
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac"
+      dimensions: "os:Mac-13"
       dimensions: "pool:luci.chromium.try"
       dimensions: "ssd:1"
       exe {
@@ -95357,7 +95860,7 @@
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac"
+      dimensions: "os:Mac-13"
       dimensions: "pool:luci.chromium.try"
       dimensions: "ssd:1"
       exe {
@@ -95626,7 +96129,7 @@
       swarming_host: "chromium-swarm.appspot.com"
       dimensions: "builderless:1"
       dimensions: "cpu:x86-64"
-      dimensions: "os:Mac"
+      dimensions: "os:Mac-13"
       dimensions: "pool:luci.chromium.try"
       dimensions: "ssd:1"
       exe {
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg
index b2a5833..138ec65 100644
--- a/infra/config/generated/luci/luci-milo.cfg
+++ b/infra/config/generated/luci/luci-milo.cfg
@@ -3017,6 +3017,9 @@
     name: "buildbucket/luci.chromium.try/android-binary-size"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/android-binary-size-siso"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/android-cronet-arm-dbg"
   }
   builders {
@@ -3047,6 +3050,9 @@
     name: "buildbucket/luci.chromium.try/android_compile_dbg"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/android_compile_siso_dbg"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/android_compile_x64_dbg"
   }
   builders {
@@ -3194,6 +3200,9 @@
     name: "buildbucket/luci.chromium.try/linux-chromeos-compile-dbg"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/linux-chromeos-compile-siso-dbg"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/linux-chromeos-rel"
   }
   builders {
@@ -3260,6 +3269,9 @@
     name: "buildbucket/luci.chromium.try/linux_chromium_compile_dbg_ng"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/linux_chromium_compile_siso_dbg_ng"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/linux_chromium_dbg_ng"
   }
   builders {
@@ -17035,6 +17047,9 @@
     name: "buildbucket/luci.chromium.try/android-binary-size"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/android-binary-size-siso"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/android-chrome-pie-x86-wpt-android-specific"
   }
   builders {
@@ -17209,6 +17224,9 @@
     name: "buildbucket/luci.chromium.try/android_compile_dbg"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/android_compile_siso_dbg"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/android_compile_x64_dbg"
   }
   builders {
@@ -17347,6 +17365,9 @@
     name: "buildbucket/luci.chromium.try/fuchsia-binary-size"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/fuchsia-binary-size-siso"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/fuchsia-clang-tidy-rel"
   }
   builders {
@@ -17680,6 +17701,9 @@
     name: "buildbucket/luci.chromium.try/linux-chromeos-compile-dbg"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/linux-chromeos-compile-siso-dbg"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/linux-chromeos-dbg"
   }
   builders {
@@ -17908,6 +17932,9 @@
     name: "buildbucket/luci.chromium.try/linux_chromium_compile_rel_ng"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/linux_chromium_compile_siso_dbg_ng"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/linux_chromium_dbg_ng"
   }
   builders {
@@ -18441,6 +18468,9 @@
     name: "buildbucket/luci.chromium.try/android-binary-size"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/android-binary-size-siso"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/android-chrome-pie-x86-wpt-android-specific"
   }
   builders {
@@ -18594,6 +18624,9 @@
     name: "buildbucket/luci.chromium.try/android_compile_dbg"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/android_compile_siso_dbg"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/android_compile_x64_dbg"
   }
   builders {
@@ -18762,6 +18795,9 @@
     name: "buildbucket/luci.chromium.try/linux-chromeos-compile-dbg"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/linux-chromeos-compile-siso-dbg"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/linux-chromeos-dbg"
   }
   builders {
@@ -18894,6 +18930,9 @@
     name: "buildbucket/luci.chromium.try/fuchsia-binary-size"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/fuchsia-binary-size-siso"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/fuchsia-code-coverage"
   }
   builders {
@@ -19218,6 +19257,9 @@
     name: "buildbucket/luci.chromium.try/linux_chromium_compile_rel_ng"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/linux_chromium_compile_siso_dbg_ng"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/linux_chromium_dbg_ng"
   }
   builders {
diff --git a/infra/config/generated/testing/variants.pyl b/infra/config/generated/testing/variants.pyl
index a82bef5a..7021c96 100644
--- a/infra/config/generated/testing/variants.pyl
+++ b/infra/config/generated/testing/variants.pyl
@@ -70,16 +70,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'identifier': 'Lacros version skew testing ash canary',
-    'description': 'Run with ash-chrome version 121.0.6118.0',
+    'description': 'Run with ash-chrome version 121.0.6119.0',
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6118.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6119.0/test_ash_chrome',
     ],
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v121.0.6118.0',
-          'revision': 'version:121.0.6118.0',
+          'location': 'lacros_version_skew_tests_v121.0.6119.0',
+          'revision': 'version:121.0.6119.0',
         },
       ],
     },
@@ -620,7 +620,7 @@
     'identifier': 'EVE_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'eve',
-      'cros_img': 'eve-public/R121-15672.0.0',
+      'cros_img': 'eve-public/R121-15673.0.0',
       'bucket': 'chromiumos-image-archive',
       'dut_pool': 'chromium',
       'public_builder': 'cros_test_platform_public',
@@ -694,7 +694,7 @@
     'identifier': 'JACUZZI_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'jacuzzi',
-      'cros_img': 'jacuzzi-public/R121-15672.0.0',
+      'cros_img': 'jacuzzi-public/R121-15673.0.0',
       'bucket': 'chromiumos-image-archive',
     },
   },
@@ -702,7 +702,7 @@
     'identifier': 'JACUZZI_CQ_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'jacuzzi',
-      'cros_img': 'jacuzzi-public/R121-15672.0.0',
+      'cros_img': 'jacuzzi-public/R121-15673.0.0',
       'bucket': 'chromiumos-image-archive',
       'public_builder': 'cros_test_platform_public',
       'public_builder_bucket': 'testplatform-public',
@@ -712,7 +712,7 @@
     'identifier': 'TROGDOR_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'trogdor',
-      'cros_img': 'trogdor-public/R121-15672.0.0',
+      'cros_img': 'trogdor-public/R121-15673.0.0',
       'bucket': 'chromiumos-image-archive',
     },
   },
@@ -720,7 +720,7 @@
     'identifier': 'OCTOPUS_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'octopus',
-      'cros_img': 'octopus-public/R121-15672.0.0',
+      'cros_img': 'octopus-public/R121-15673.0.0',
       'bucket': 'chromiumos-image-archive',
     },
   },
@@ -799,7 +799,7 @@
     'skylab': {
       'cros_board': 'volteer',
       'cros_model': 'voxel',
-      'cros_img': 'volteer-public/R121-15672.0.0',
+      'cros_img': 'volteer-public/R121-15673.0.0',
       'bucket': 'chromiumos-image-archive',
       'dut_pool': 'chromium',
       'public_builder': 'cros_test_platform_public',
diff --git a/infra/config/subprojects/chromium/try/tryserver.blink.star b/infra/config/subprojects/chromium/try/tryserver.blink.star
index fbed0dcc..e3e9514 100644
--- a/infra/config/subprojects/chromium/try/tryserver.blink.star
+++ b/infra/config/subprojects/chromium/try/tryserver.blink.star
@@ -29,7 +29,7 @@
     kwargs.setdefault("branch_selector", branches.selector.MAC_BRANCHES)
     kwargs.setdefault("builderless", True)
     kwargs.setdefault("cores", None)
-    kwargs.setdefault("os", os.MAC_ANY)
+    kwargs.setdefault("os", os.MAC_DEFAULT)
     kwargs.setdefault("ssd", True)
     return try_.builder(
         name = name,
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.android.star b/infra/config/subprojects/chromium/try/tryserver.chromium.android.star
index 7f64230..50ff30f95 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.android.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.android.star
@@ -324,6 +324,51 @@
 )
 
 try_.builder(
+    name = "android-binary-size-siso",
+    description_html = """\
+This builder shadows android-binary-size builder to compare between Siso builds and Ninja builds.<br/>
+This builder should be removed after migrating android-binary-size from Ninja to Siso. b/277863839
+""",
+    executable = "recipe:binary_size_trybot",
+    cores = 16,
+    ssd = True,
+    contact_team_email = "chrome-build-team@google.com",
+    gn_args = gn_args.config(
+        configs = [
+            "android",
+            "chrome_with_codecs",
+            "reclient",
+            "minimal_symbols",
+            "official_optimize",
+            "stable_channel",
+            "v8_release_branch",
+            "use_dummy_lastchange",
+        ],
+    ),
+    main_list_view = "try",
+    properties = {
+        "$build/binary_size": {
+            "analyze_targets": [
+                "//chrome/android:monochrome_public_minimal_apks",
+                "//chrome/android:trichrome_32_minimal_apks",
+                "//chrome/android:validate_expectations",
+                "//tools/binary_size:binary_size_trybot_py",
+            ],
+            "compile_targets": [
+                "monochrome_public_minimal_apks",
+                "monochrome_static_initializers",
+                "trichrome_32_minimal_apks",
+                "validate_expectations",
+            ],
+        },
+    },
+    siso_enabled = True,
+    tryjob = try_.job(
+        experiment_percentage = 10,
+    ),
+)
+
+try_.builder(
     name = "android-clobber-rel",
     mirrors = [
         "ci/android-archive-rel",
@@ -1023,6 +1068,38 @@
 )
 
 try_.builder(
+    name = "android_compile_siso_dbg",
+    description_html = """\
+This builder shadows android_compile_dbg builder to compare between Siso builds and Ninja builds.<br/>
+This builder should be removed after migrating android_compile_dbg from Ninja to Siso. b/277863839
+""",
+    mirrors = builder_config.copy_from("try/android_compile_dbg"),
+    try_settings = builder_config.try_settings(
+        include_all_triggered_testers = True,
+        is_compile_only = True,
+    ),
+    cores = 32,
+    ssd = True,
+    contact_team_email = "chrome-build-team@google.com",
+    gn_args = gn_args.config(
+        configs = [
+            "android",
+            "debug_builder",
+            "reclient",
+            "compile_only",
+            "arm64",
+            "use_dummy_lastchange",
+        ],
+    ),
+    main_list_view = "try",
+    reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ,
+    siso_enabled = True,
+    tryjob = try_.job(
+        experiment_percentage = 10,
+    ),
+)
+
+try_.builder(
     name = "android_compile_x64_dbg",
     branch_selector = branches.selector.ANDROID_BRANCHES,
     # Since we expect this builder to compile all, let it mirror
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.angle.star b/infra/config/subprojects/chromium/try/tryserver.chromium.angle.star
index 01b9dc74..47ca374 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.angle.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.angle.star
@@ -3,7 +3,7 @@
 # found in the LICENSE file.
 """Definitions of builders in the tryserver.chromium.angle builder group."""
 
-load("//lib/builders.star", "os", "reclient")
+load("//lib/builders.star", "cpu", "os", "reclient")
 load("//lib/builder_config.star", "builder_config")
 load("//lib/consoles.star", "consoles")
 load("//lib/try.star", "try_")
@@ -75,6 +75,7 @@
     ),
     cores = None,
     os = os.MAC_ANY,
+    cpu = cpu.ARM64,
 )
 
 try_.builder(
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star b/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star
index afa2aa72..0c704c0 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.chromiumos.star
@@ -313,6 +313,26 @@
 )
 
 try_.builder(
+    name = "linux-chromeos-compile-siso-dbg",
+    description_html = """\
+This builder shadows linux-chromeos-compile-dbg builder to compare between Siso builds and Ninja builds.<br/>
+This builder should be removed after migrating linux-chromeos-compile-dbg from Ninja to Siso. b/277863839
+""",
+    mirrors = builder_config.copy_from("try/linux-chromeos-compile-dbg"),
+    try_settings = builder_config.try_settings(
+        include_all_triggered_testers = True,
+        is_compile_only = True,
+    ),
+    contact_team_email = "chrome-build-team@google.com",
+    main_list_view = "try",
+    reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ,
+    siso_enabled = True,
+    tryjob = try_.job(
+        experiment_percentage = 10,
+    ),
+)
+
+try_.builder(
     name = "chromeos-jacuzzi-rel",
     branch_selector = branches.selector.CROS_LTS_BRANCHES,
     mirrors = [
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star b/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star
index 3c134bd..48ada83 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.fuchsia.star
@@ -98,6 +98,31 @@
 )
 
 try_.builder(
+    name = "fuchsia-binary-size-siso",
+    description_html = """\
+This builder shadows fuchsia-binary-size builder to compare between Siso builds and Ninja builds.<br/>
+This builder should be removed after migrating size from Ninja to Siso. b/277863839
+""",
+    executable = "recipe:binary_size_fuchsia_trybot",
+    cores = 16,
+    contact_team_email = "chrome-build-team@google.com",
+    properties = {
+        "$build/binary_size": {
+            "analyze_targets": [
+                "//tools/fuchsia/size_tests:fuchsia_sizes",
+            ],
+            "compile_targets": [
+                "fuchsia_sizes",
+            ],
+        },
+    },
+    siso_enabled = True,
+    tryjob = try_.job(
+        experiment_percentage = 10,
+    ),
+)
+
+try_.builder(
     name = "fuchsia-compile-x64-dbg",
     mirrors = [
         "ci/fuchsia-x64-dbg",
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
index 7627eb0..ec0f1c4 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
@@ -625,6 +625,39 @@
 )
 
 try_.builder(
+    name = "linux_chromium_compile_siso_dbg_ng",
+    description_html = """\
+This builder shadows linux_chromium_compile_dbg_ng builder to compare between Siso builds and Ninja builds.<br/>
+This builder should be removed after migrating linux_chromium_compile_dbg_ng from Ninja to Siso. b/277863839
+""",
+    mirrors = builder_config.copy_from("try/linux_chromium_compile_dbg_ng"),
+    try_settings = builder_config.try_settings(
+        include_all_triggered_testers = True,
+        is_compile_only = True,
+    ),
+    caches = [
+        swarming.cache(
+            name = "builder",
+            path = "linux_debug",
+        ),
+    ],
+    contact_team_email = "chrome-build-team@google.com",
+    gn_args = gn_args.config(
+        configs = [
+            "debug_builder",
+            "reclient",
+            "use_dummy_lastchange",
+        ],
+    ),
+    main_list_view = "try",
+    reclient_jobs = reclient.jobs.HIGH_JOBS_FOR_CQ,
+    siso_enabled = True,
+    tryjob = try_.job(
+        experiment_percentage = 10,
+    ),
+)
+
+try_.builder(
     name = "linux_chromium_compile_rel_ng",
     mirrors = [
         "ci/Linux Builder",
diff --git a/infra/config/targets/cros-skylab-variants.json b/infra/config/targets/cros-skylab-variants.json
index 3e073bc..7510ca9 100644
--- a/infra/config/targets/cros-skylab-variants.json
+++ b/infra/config/targets/cros-skylab-variants.json
@@ -202,7 +202,7 @@
     "skylab": {
       "cros_board": "eve",
       "cros_chrome_version": "121.0.6110.0",
-      "cros_img": "eve-public/R121-15672.0.0",
+      "cros_img": "eve-public/R121-15673.0.0",
       "bucket": "chromiumos-image-archive",
       "dut_pool": "chromium",
       "public_builder": "cros_test_platform_public",
@@ -292,7 +292,7 @@
     "skylab": {
       "cros_board": "jacuzzi",
       "cros_chrome_version": "121.0.6110.0",
-      "cros_img": "jacuzzi-public/R121-15672.0.0",
+      "cros_img": "jacuzzi-public/R121-15673.0.0",
       "bucket": "chromiumos-image-archive"
     },
     "enabled": true,
@@ -302,7 +302,7 @@
     "skylab": {
       "cros_board": "jacuzzi",
       "cros_chrome_version": "121.0.6110.0",
-      "cros_img": "jacuzzi-public/R121-15672.0.0",
+      "cros_img": "jacuzzi-public/R121-15673.0.0",
       "bucket": "chromiumos-image-archive",
       "public_builder": "cros_test_platform_public",
       "public_builder_bucket": "testplatform-public"
@@ -314,7 +314,7 @@
     "skylab": {
       "cros_board": "trogdor",
       "cros_chrome_version": "121.0.6110.0",
-      "cros_img": "trogdor-public/R121-15672.0.0",
+      "cros_img": "trogdor-public/R121-15673.0.0",
       "bucket": "chromiumos-image-archive"
     },
     "enabled": true,
@@ -324,7 +324,7 @@
     "skylab": {
       "cros_board": "octopus",
       "cros_chrome_version": "121.0.6110.0",
-      "cros_img": "octopus-public/R121-15672.0.0",
+      "cros_img": "octopus-public/R121-15673.0.0",
       "bucket": "chromiumos-image-archive"
     },
     "enabled": true,
@@ -419,7 +419,7 @@
       "cros_board": "volteer",
       "cros_model": "voxel",
       "cros_chrome_version": "121.0.6110.0",
-      "cros_img": "volteer-public/R121-15672.0.0",
+      "cros_img": "volteer-public/R121-15673.0.0",
       "bucket": "chromiumos-image-archive",
       "dut_pool": "chromium",
       "public_builder": "cros_test_platform_public",
diff --git a/infra/config/targets/lacros-version-skew-variants.json b/infra/config/targets/lacros-version-skew-variants.json
index d4f9b66c..290a535 100644
--- a/infra/config/targets/lacros-version-skew-variants.json
+++ b/infra/config/targets/lacros-version-skew-variants.json
@@ -1,16 +1,16 @@
 {
   "LACROS_VERSION_SKEW_CANARY": {
     "args": [
-      "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6118.0/test_ash_chrome"
+      "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6119.0/test_ash_chrome"
     ],
-    "description": "Run with ash-chrome version 121.0.6118.0",
+    "description": "Run with ash-chrome version 121.0.6119.0",
     "identifier": "Lacros version skew testing ash canary",
     "swarming": {
       "cipd_packages": [
         {
           "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-          "location": "lacros_version_skew_tests_v121.0.6118.0",
-          "revision": "version:121.0.6118.0"
+          "location": "lacros_version_skew_tests_v121.0.6119.0",
+          "revision": "version:121.0.6119.0"
         }
       ]
     }
diff --git a/internal b/internal
index d478c0f..5a39204 160000
--- a/internal
+++ b/internal
@@ -1 +1 @@
-Subproject commit d478c0ffef4852b4e4d56a6fd914a9e0e94653d2
+Subproject commit 5a392040dbeaedc5f2cfabe8ac08793c446f8d6c
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index c0848e0..dca2df7 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -1262,10 +1262,6 @@
      FEATURE_WITH_PARAMS_VALUE_TYPE(kTabInactivityThreshold,
                                     kTabInactivityThresholdVariations,
                                     "TabInactivityThreshold")},
-    {"enable-feed-synthetic-capabilities",
-     flag_descriptions::kEnableFeedSyntheticCapabilitiesName,
-     flag_descriptions::kEnableFeedSyntheticCapabilitiesDescription,
-     flags_ui::kOsIos, FEATURE_VALUE_TYPE(kEnableFeedSyntheticCapabilities)},
     {"enable-friendlier-safe-browsing-settings-enhanced-protection",
      flag_descriptions::
          kEnableFriendlierSafeBrowsingSettingsEnhancedProtectionName,
@@ -1627,6 +1623,10 @@
     {"dynamic-background-color", flag_descriptions::kDynamicBackgroundColorName,
      flag_descriptions::kDynamicBackgroundColorDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kDynamicBackgroundColor)},
+    {"set-up-list-content-notification",
+     flag_descriptions::kSetUpListContentNotificationName,
+     flag_descriptions::kSetUpListContentNotificationDescription,
+     flags_ui::kOsIos, FEATURE_VALUE_TYPE(kSetUpListContentNotification)},
 
 };
 
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index 4df8266..699eb5e 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -386,11 +386,11 @@
 const char kEnableFeedContainmentDescription[] =
     "If enabled, the feed is contained in a module on the Home surface.";
 
-const char kEnableFeedSyntheticCapabilitiesName[] =
-    "Enable Feed synthetic capabilities.";
-const char kEnableFeedSyntheticCapabilitiesDescription[] =
-    "If enabled synthethic capablities will be used to inform the server of "
-    "the client capabilities.";
+const char kEnableFeedCardMenuSignInPromoName[] =
+    "Enable Feed card menu sign-in promotion";
+const char kEnableFeedCardMenuSignInPromoDescription[] =
+    "Display a sign-in promotion UI when signed out users click on "
+    "personalization options within the feed card menu.";
 
 const char kEnableFollowIPHExpParamsName[] =
     "Enable Follow IPH Experiment Parameters";
@@ -923,6 +923,12 @@
 const char kSendUmaOverAnyNetworkDescription[] =
     "When enabled, will send UMA data over either WiFi or cellular by default.";
 
+const char kSetUpListContentNotificationName[] =
+    "Set Up List Content Notification Opt-in";
+const char kSetUpListContentNotificationDescription[] =
+    "Displays an content notification opt-in entry point in list of set up "
+    "tasks on Home for a new user.";
+
 const char kSharedHighlightingIOSName[] = "Enable Shared Highlighting features";
 const char kSharedHighlightingIOSDescription[] =
     "Adds a Link to Text option in the Edit Menu which generates URLs with a "
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index 99d8c34..5610dfb 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -283,9 +283,10 @@
 extern const char kEnableFeedHeaderSettingsName[];
 extern const char kEnableFeedHeaderSettingsDescription[];
 
-// Title and description for the flag to enable Feed synthetic capabilities.
-extern const char kEnableFeedSyntheticCapabilitiesName[];
-extern const char kEnableFeedSyntheticCapabilitiesDescription[];
+// Title and description for the flag to enable the sign-in promotion triggered
+// by the discover feed card menu.
+extern const char kEnableFeedCardMenuSignInPromoName[];
+extern const char kEnableFeedCardMenuSignInPromoDescription[];
 
 // Title and description for the flag to enable follow IPH experiment
 // parameters.
@@ -809,6 +810,11 @@
 extern const char kSendUmaOverAnyNetwork[];
 extern const char kSendUmaOverAnyNetworkDescription[];
 
+// Title and description for the flag to display the Set Up List Content
+// Notification Opt-in.
+extern const char kSetUpListContentNotificationName[];
+extern const char kSetUpListContentNotificationDescription[];
+
 // Title and description for the flag to enable Shared Highlighting (Link to
 // Text Edit Menu option).
 extern const char kSharedHighlightingIOSName[];
diff --git a/ios/chrome/browser/ui/autofill/autofill_app_interface.mm b/ios/chrome/browser/ui/autofill/autofill_app_interface.mm
index 385fa52..75c578c 100644
--- a/ios/chrome/browser/ui/autofill/autofill_app_interface.mm
+++ b/ios/chrome/browser/ui/autofill/autofill_app_interface.mm
@@ -205,8 +205,8 @@
         ->credit_card_save_manager_.get();
   }
 
-  // Access the PaymentsClient.
-  static payments::PaymentsClient* GetPaymentsClient() {
+  // Access the PaymentsNetworkInterface.
+  static payments::PaymentsNetworkInterface* GetPaymentsNetworkInterface() {
     web::WebState* web_state = chrome_test_util::GetCurrentWebState();
     web::WebFramesManager* frames_manager =
         autofill::AutofillJavaScriptFeature::GetInstance()->GetWebFramesManager(
@@ -216,7 +216,7 @@
     return AutofillDriverIOS::FromWebStateAndWebFrame(web_state, main_frame)
         ->GetAutofillManager()
         .client()
-        .GetPaymentsClient();
+        .GetPaymentsNetworkInterface();
   }
 
   // Delete all failed attempds registered on every cards.
@@ -302,19 +302,20 @@
   void SetUp() {
     test_url_loader_factory_ =
         std::make_unique<network::TestURLLoaderFactory>();
-    // Set up the URL loader factory for the PaymentsClient so we can intercept
-    // those network requests.
+    // Set up the URL loader factory for the PaymentsNetworkInterface so we can
+    // intercept those network requests.
     shared_url_loader_factory_ =
         base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
             test_url_loader_factory_.get());
 
-    payments::PaymentsClient* payments_client =
-        SaveCardInfobarEGTestHelper::GetPaymentsClient();
-    payments_client->set_url_loader_factory_for_testing(
+    payments::PaymentsNetworkInterface* payments_network_interface =
+        SaveCardInfobarEGTestHelper::GetPaymentsNetworkInterface();
+    payments_network_interface->set_url_loader_factory_for_testing(
         shared_url_loader_factory_);
 
     // Set a fake access token to avoid fetch requests.
-    payments_client->set_access_token_for_testing("fake_access_token");
+    payments_network_interface->set_access_token_for_testing(
+        "fake_access_token");
 
     // Observe actions in CreditCardSaveManager.
     CreditCardSaveManager* credit_card_save_manager =
diff --git a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h
index 3c5adebf..c2947b06 100644
--- a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h
+++ b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h
@@ -75,7 +75,7 @@
   syncer::SyncService* GetSyncService() override;
   signin::IdentityManager* GetIdentityManager() override;
   FormDataImporter* GetFormDataImporter() override;
-  payments::PaymentsClient* GetPaymentsClient() override;
+  payments::PaymentsNetworkInterface* GetPaymentsNetworkInterface() override;
   StrikeDatabase* GetStrikeDatabase() override;
   ukm::UkmRecorder* GetUkmRecorder() override;
   ukm::SourceId GetUkmSourceId() override;
@@ -180,7 +180,8 @@
   web::WebState* web_state_;
   __weak id<AutofillClientIOSBridge> bridge_;
   signin::IdentityManager* identity_manager_;
-  std::unique_ptr<payments::PaymentsClient> payments_client_;
+  std::unique_ptr<payments::PaymentsNetworkInterface>
+      payments_network_interface_;
   std::unique_ptr<CreditCardCvcAuthenticator> cvc_authenticator_;
   std::unique_ptr<CreditCardOtpAuthenticator> otp_authenticator_;
   std::unique_ptr<FormDataImporter> form_data_importer_;
diff --git a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm
index e6a1a62..b3fc6ac 100644
--- a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm
+++ b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm
@@ -24,7 +24,7 @@
 #import "components/autofill/core/browser/payments/autofill_save_card_ui_info.h"
 #import "components/autofill/core/browser/payments/credit_card_cvc_authenticator.h"
 #import "components/autofill/core/browser/payments/credit_card_otp_authenticator.h"
-#import "components/autofill/core/browser/payments/payments_client.h"
+#import "components/autofill/core/browser/payments/payments_network_interface.h"
 #import "components/autofill/core/browser/ui/payments/card_unmask_prompt_view.h"
 #import "components/autofill/core/browser/ui/popup_item_ids.h"
 #import "components/autofill/core/common/autofill_features.h"
@@ -97,15 +97,16 @@
       bridge_(bridge),
       identity_manager_(IdentityManagerFactory::GetForBrowserState(
           browser_state->GetOriginalChromeBrowserState())),
-      payments_client_(std::make_unique<payments::PaymentsClient>(
-          base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
-              browser_state_->GetURLLoaderFactory()),
-          identity_manager_,
-          personal_data_manager_,
-          browser_state_->IsOffTheRecord())),
+      payments_network_interface_(
+          std::make_unique<payments::PaymentsNetworkInterface>(
+              base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+                  browser_state_->GetURLLoaderFactory()),
+              identity_manager_,
+              personal_data_manager_,
+              browser_state_->IsOffTheRecord())),
       form_data_importer_(std::make_unique<FormDataImporter>(
           this,
-          payments_client_.get(),
+          payments_network_interface_.get(),
           personal_data_manager_,
           GetApplicationContext()->GetApplicationLocale())),
       infobar_manager_(infobar_manager),
@@ -190,8 +191,9 @@
   return form_data_importer_.get();
 }
 
-payments::PaymentsClient* ChromeAutofillClientIOS::GetPaymentsClient() {
-  return payments_client_.get();
+payments::PaymentsNetworkInterface*
+ChromeAutofillClientIOS::GetPaymentsNetworkInterface() {
+  return payments_network_interface_.get();
 }
 
 StrikeDatabase* ChromeAutofillClientIOS::GetStrikeDatabase() {
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_feature.h b/ios/chrome/browser/ui/ntp/new_tab_page_feature.h
index 1f877ed..e80c045 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_feature.h
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_feature.h
@@ -38,9 +38,6 @@
 // its own does nothing; relies on feature parameters.
 BASE_DECLARE_FEATURE(kOverrideFeedSettings);
 
-// Feature flag to enable synthentic capabilities.
-BASE_DECLARE_FEATURE(kEnableFeedSyntheticCapabilities);
-
 // Feature flag to enable sending discover feedback to an updated target
 BASE_DECLARE_FEATURE(kWebFeedFeedbackReroute);
 
@@ -51,6 +48,9 @@
 // Feature flag to enable signed out user view demotion.
 BASE_DECLARE_FEATURE(kEnableSignedOutViewDemotion);
 
+// Feature flag to enable Set Up List Content Notification.
+BASE_DECLARE_FEATURE(kSetUpListContentNotification);
+
 #pragma mark - Feature parameters
 
 // A parameter to indicate whether Reconstructed Templates is enabled for static
@@ -118,10 +118,6 @@
 // Following feed.
 bool IsDotEnabledForNewFollowedContent();
 
-// YES if synthetic capabilities will be used to inform the server of client
-// capabilities.
-bool IsFeedSyntheticCapabilitiesEnabled();
-
 // Returns a custom height for the Following feed header if it is overridden
 // from the server, or returns the default value.
 int FollowingFeedHeaderHeight();
@@ -135,4 +131,7 @@
 // Yes if the signed out user view demotion is enabled.
 bool IsSignedOutViewDemotionEnabled();
 
+// Yes if the Set Up List Content Notification is enabled.
+bool IsSetUpListContentNotificationEnabled();
+
 #endif  // IOS_CHROME_BROWSER_UI_NTP_NEW_TAB_PAGE_FEATURE_H_
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_feature.mm b/ios/chrome/browser/ui/ntp/new_tab_page_feature.mm
index 28f4a02f..f22c50c 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_feature.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_feature.mm
@@ -47,10 +47,6 @@
              "OverrideFeedSettings",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kEnableFeedSyntheticCapabilities,
-             "EnableFeedSyntheticCapabilities",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 BASE_FEATURE(kWebFeedFeedbackReroute,
              "WebFeedFeedbackReroute",
              base::FEATURE_ENABLED_BY_DEFAULT);
@@ -63,6 +59,10 @@
              "EnableSignedOutViewDemotion",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+BASE_FEATURE(kSetUpListContentNotification,
+             "SetUpListContentNotification",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 #pragma mark - Feature parameters
 
 const char kDiscoverFeedSRSReconstructedTemplatesEnabled[] =
@@ -168,10 +168,6 @@
       kFeedHeaderSettings, kEnableDotForNewFollowedContent, false);
 }
 
-bool IsFeedSyntheticCapabilitiesEnabled() {
-  return base::FeatureList::IsEnabled(kEnableFeedSyntheticCapabilities);
-}
-
 int FollowingFeedHeaderHeight() {
   int defaultWebChannelsHeaderHeight = 30;
   return base::GetFieldTrialParamByFeatureAsInt(kFeedHeaderSettings,
@@ -190,3 +186,7 @@
 bool IsSignedOutViewDemotionEnabled() {
   return base::FeatureList::IsEnabled(kEnableSignedOutViewDemotion);
 }
+
+bool IsSetUpListContentNotificationEnabled() {
+  return base::FeatureList::IsEnabled(kSetUpListContentNotification);
+}
diff --git a/ios/web_view/internal/autofill/web_view_autofill_client_ios.h b/ios/web_view/internal/autofill/web_view_autofill_client_ios.h
index fa23ec9..2b615d8 100644
--- a/ios/web_view/internal/autofill/web_view_autofill_client_ios.h
+++ b/ios/web_view/internal/autofill/web_view_autofill_client_ios.h
@@ -62,7 +62,7 @@
   syncer::SyncService* GetSyncService() override;
   signin::IdentityManager* GetIdentityManager() override;
   FormDataImporter* GetFormDataImporter() override;
-  payments::PaymentsClient* GetPaymentsClient() override;
+  payments::PaymentsNetworkInterface* GetPaymentsNetworkInterface() override;
   StrikeDatabase* GetStrikeDatabase() override;
   ukm::UkmRecorder* GetUkmRecorder() override;
   ukm::SourceId GetUkmSourceId() override;
@@ -145,7 +145,8 @@
   web::WebState* web_state_;
   __weak id<CWVAutofillClientIOSBridge> bridge_;
   signin::IdentityManager* identity_manager_;
-  std::unique_ptr<payments::PaymentsClient> payments_client_;
+  std::unique_ptr<payments::PaymentsNetworkInterface>
+      payments_network_interface_;
   std::unique_ptr<CreditCardCvcAuthenticator> cvc_authenticator_;
   std::unique_ptr<FormDataImporter> form_data_importer_;
   StrikeDatabase* strike_database_;
diff --git a/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm b/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm
index 5735a9f..4b0ebc88 100644
--- a/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm
+++ b/ios/web_view/internal/autofill/web_view_autofill_client_ios.mm
@@ -15,7 +15,7 @@
 #import "components/autofill/core/browser/form_data_importer.h"
 #import "components/autofill/core/browser/logging/log_router.h"
 #import "components/autofill/core/browser/payments/credit_card_cvc_authenticator.h"
-#import "components/autofill/core/browser/payments/payments_client.h"
+#import "components/autofill/core/browser/payments/payments_network_interface.h"
 #import "components/autofill/core/browser/ui/popup_item_ids.h"
 #import "components/autofill/core/common/autofill_prefs.h"
 #import "components/autofill/ios/browser/autofill_util.h"
@@ -77,15 +77,16 @@
       autocomplete_history_manager_(autocomplete_history_manager),
       web_state_(web_state),
       identity_manager_(identity_manager),
-      payments_client_(std::make_unique<payments::PaymentsClient>(
-          base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
-              web_state_->GetBrowserState()->GetURLLoaderFactory()),
-          identity_manager_,
-          personal_data_manager_,
-          web_state_->GetBrowserState()->IsOffTheRecord())),
+      payments_network_interface_(
+          std::make_unique<payments::PaymentsNetworkInterface>(
+              base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+                  web_state_->GetBrowserState()->GetURLLoaderFactory()),
+              identity_manager_,
+              personal_data_manager_,
+              web_state_->GetBrowserState()->IsOffTheRecord())),
       form_data_importer_(
           std::make_unique<FormDataImporter>(this,
-                                             payments_client_.get(),
+                                             payments_network_interface_.get(),
                                              personal_data_manager_,
                                              locale)),
       strike_database_(strike_database),
@@ -151,8 +152,9 @@
   return form_data_importer_.get();
 }
 
-payments::PaymentsClient* WebViewAutofillClientIOS::GetPaymentsClient() {
-  return payments_client_.get();
+payments::PaymentsNetworkInterface*
+WebViewAutofillClientIOS::GetPaymentsNetworkInterface() {
+  return payments_network_interface_.get();
 }
 
 StrikeDatabase* WebViewAutofillClientIOS::GetStrikeDatabase() {
diff --git a/media/base/video_encoder.cc b/media/base/video_encoder.cc
index 4ae5780..c238897 100644
--- a/media/base/video_encoder.cc
+++ b/media/base/video_encoder.cc
@@ -37,7 +37,7 @@
 
   if (area >= 3840 * 2160) {
     desired_threads = 16;
-  } else if (area >= 2560 * 1080) {
+  } else if (area >= 1920 * 1080) {
     desired_threads = 8;
   } else if (area >= 1280 * 720) {
     desired_threads = 4;
diff --git a/media/gpu/android/ndk_media_codec_wrapper.h b/media/gpu/android/ndk_media_codec_wrapper.h
index b3032c6c..15eda6c4 100644
--- a/media/gpu/android/ndk_media_codec_wrapper.h
+++ b/media/gpu/android/ndk_media_codec_wrapper.h
@@ -25,7 +25,7 @@
   }
 };
 
-// Small wrapper class which manages async callbacks from an AMediaCodec, as
+// A wrapper class which manages async callbacks from an AMediaCodec, as
 // well as queues of available input/output buffers.
 class MEDIA_GPU_EXPORT NdkMediaCodecWrapper {
  public:
diff --git a/media/gpu/android/ndk_video_encode_accelerator.cc b/media/gpu/android/ndk_video_encode_accelerator.cc
index cb9b580b..b49727b6 100644
--- a/media/gpu/android/ndk_video_encode_accelerator.cc
+++ b/media/gpu/android/ndk_video_encode_accelerator.cc
@@ -5,7 +5,6 @@
 #include "media/gpu/android/ndk_video_encode_accelerator.h"
 
 #include "base/bits.h"
-#include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/memory/shared_memory_mapping.h"
 #include "base/memory/unsafe_shared_memory_region.h"
@@ -166,10 +165,6 @@
   return result;
 }
 
-BASE_FEATURE(kAndroidNdkVideoEncoder,
-             "AndroidNdkVideoEncoder",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 absl::optional<std::string> FindMediaCodecFor(
     const VideoEncodeAccelerator::Config& config) {
   absl::optional<std::string> encoder_name;
@@ -240,8 +235,7 @@
 }
 
 bool NdkVideoEncodeAccelerator::IsSupported() {
-  return base::FeatureList::IsEnabled(kAndroidNdkVideoEncoder) &&
-         NdkMediaCodecWrapper::IsSupported();
+  return NdkMediaCodecWrapper::IsSupported();
 }
 
 VideoEncodeAccelerator::SupportedProfiles
diff --git a/media/gpu/chromeos/BUILD.gn b/media/gpu/chromeos/BUILD.gn
index 33a536d..730f805a 100644
--- a/media/gpu/chromeos/BUILD.gn
+++ b/media/gpu/chromeos/BUILD.gn
@@ -189,6 +189,7 @@
     "fake_chromeos_intel_compressed_gpu_memory_buffer.h",
   ]
   deps = [
+    ":common",
     "//base",
     "//build/config/linux/libdrm",
     "//ui/gfx",
diff --git a/media/gpu/chromeos/chromeos_compressed_gpu_memory_buffer_video_frame_utils.cc b/media/gpu/chromeos/chromeos_compressed_gpu_memory_buffer_video_frame_utils.cc
index 061f18fe..6e541f6 100644
--- a/media/gpu/chromeos/chromeos_compressed_gpu_memory_buffer_video_frame_utils.cc
+++ b/media/gpu/chromeos/chromeos_compressed_gpu_memory_buffer_video_frame_utils.cc
@@ -93,7 +93,20 @@
 }
 
 bool IsIntelMediaCompressedModifier(uint64_t modifier) {
-  return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS;
+  return modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS ||
+         modifier == I915_FORMAT_MOD_4_TILED_MTL_MC_CCS;
+}
+
+std::string IntelMediaCompressedModifierToString(uint64_t modifier) {
+  switch (modifier) {
+    case I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS:
+      return "I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS";
+    case I915_FORMAT_MOD_4_TILED_MTL_MC_CCS:
+      return "I915_FORMAT_MOD_4_TILED_MTL_MC_CCS";
+  }
+  NOTREACHED() << "Invalid Intel Media Compressed modifier provided: "
+               << modifier;
+  return "";
 }
 
 }  // namespace media
diff --git a/media/gpu/chromeos/chromeos_compressed_gpu_memory_buffer_video_frame_utils.h b/media/gpu/chromeos/chromeos_compressed_gpu_memory_buffer_video_frame_utils.h
index 76dc488b..c16b393 100644
--- a/media/gpu/chromeos/chromeos_compressed_gpu_memory_buffer_video_frame_utils.h
+++ b/media/gpu/chromeos/chromeos_compressed_gpu_memory_buffer_video_frame_utils.h
@@ -9,6 +9,22 @@
 
 #include "base/memory/scoped_refptr.h"
 
+#ifndef I915_FORMAT_MOD_4_TILED_MTL_MC_CCS
+// TODO(b/271455200): Remove this definition once drm_fourcc.h contains it.
+/*
+ * Intel color control surfaces (CCS) for display ver 14 media compression
+ *
+ * The main surface is tile4 and at plane index 0, the CCS is linear and
+ * at index 1. A 64B CCS cache line corresponds to an area of 4x1 tiles in
+ * main surface. In other words, 4 bits in CCS map to a main surface cache
+ * line pair. The main surface pitch is required to be a multiple of four
+ * tile4 widths. For semi-planar formats like NV12, CCS planes follow the
+ * Y and UV planes i.e., planes 0 and 1 are used for Y and UV surfaces,
+ * planes 2 and 3 for the respective CCS.
+ */
+#define I915_FORMAT_MOD_4_TILED_MTL_MC_CCS fourcc_mod_code(INTEL, 14)
+#endif
+
 namespace base {
 class TimeDelta;
 }  // namespace base
@@ -42,6 +58,8 @@
 // compression feature.
 bool IsIntelMediaCompressedModifier(uint64_t modifier);
 
+// Returns the name of an Intel Media Compressed modifier as a string.
+std::string IntelMediaCompressedModifierToString(uint64_t modifier);
 }  // namespace media
 
 #endif  // MEDIA_GPU_CHROMEOS_CHROMEOS_COMPRESSED_GPU_MEMORY_BUFFER_VIDEO_FRAME_UTILS_H_
diff --git a/media/gpu/chromeos/chromeos_compressed_gpu_memory_buffer_video_frame_utils_unittest.cc b/media/gpu/chromeos/chromeos_compressed_gpu_memory_buffer_video_frame_utils_unittest.cc
index 0cff395..864ec0b 100644
--- a/media/gpu/chromeos/chromeos_compressed_gpu_memory_buffer_video_frame_utils_unittest.cc
+++ b/media/gpu/chromeos/chromeos_compressed_gpu_memory_buffer_video_frame_utils_unittest.cc
@@ -15,26 +15,45 @@
 namespace media {
 
 class ChromeOSCompressedGpuMemoryBufferTest
-    : public ::testing::TestWithParam<VideoPixelFormat> {};
+    : public testing::TestWithParam<std::tuple<VideoPixelFormat, uint64_t>> {
+ public:
+  ChromeOSCompressedGpuMemoryBufferTest() = default;
+  ~ChromeOSCompressedGpuMemoryBufferTest() override = default;
+
+  struct PrintToStringParamName {
+    template <class ParamType>
+    std::string operator()(
+        const testing::TestParamInfo<ParamType>& info) const {
+      return base::StringPrintf(
+          "%s_%s", VideoPixelFormatToString(std::get<0>(info.param)).c_str(),
+          IntelMediaCompressedModifierToString(std::get<1>(info.param))
+              .c_str());
+    }
+  };
+};
+
+constexpr VideoPixelFormat kPixelFormats[] = {PIXEL_FORMAT_NV12,
+                                              PIXEL_FORMAT_P016LE};
+constexpr uint64_t kCompressedBufferModifiers[] = {
+    I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS, I915_FORMAT_MOD_4_TILED_MTL_MC_CCS};
 
 INSTANTIATE_TEST_SUITE_P(
     All,
     ChromeOSCompressedGpuMemoryBufferTest,
-    testing::Values(PIXEL_FORMAT_NV12, PIXEL_FORMAT_P016LE),
-    [](const ::testing::TestParamInfo<VideoPixelFormat>& info) {
-      return VideoPixelFormatToString(info.param);
-    });
+    testing::Combine(testing::ValuesIn(kPixelFormats),
+                     testing::ValuesIn(kCompressedBufferModifiers)),
+    ChromeOSCompressedGpuMemoryBufferTest::PrintToStringParamName());
 
 TEST_P(ChromeOSCompressedGpuMemoryBufferTest,
        WrapChromeOSCompressedGpuMemoryBufferAsVideoFrame) {
-  const VideoPixelFormat pixel_format = GetParam();
+  const VideoPixelFormat pixel_format = std::get<0>(GetParam());
+  const uint64_t modifier = std::get<1>(GetParam());
   constexpr gfx::Size kCodedSize(256, 256);
   constexpr gfx::Size kNaturalSize(240, 240);
   constexpr gfx::Rect kVisibleRect(kCodedSize);
   constexpr auto kTimestamp = base::Milliseconds(1);
-  constexpr uint64_t kModifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS;
   auto gmb = std::make_unique<FakeChromeOSIntelCompressedGpuMemoryBuffer>(
-      kCodedSize, *VideoPixelFormatToGfxBufferFormat(pixel_format));
+      kCodedSize, *VideoPixelFormatToGfxBufferFormat(pixel_format), modifier);
   FakeChromeOSIntelCompressedGpuMemoryBuffer* gmb_raw_ptr = gmb.get();
 
   auto frame = WrapChromeOSCompressedGpuMemoryBufferAsVideoFrame(
@@ -51,7 +70,7 @@
     EXPECT_EQ(frame->layout().planes()[i].offset, gmb_raw_ptr->plane_offset(i));
     EXPECT_EQ(frame->layout().planes()[i].size, gmb_raw_ptr->plane_size(i));
   }
-  EXPECT_EQ(frame->layout().modifier(), kModifier);
+  EXPECT_EQ(frame->layout().modifier(), modifier);
   EXPECT_EQ(frame->storage_type(), VideoFrame::STORAGE_GPU_MEMORY_BUFFER);
   ASSERT_TRUE(frame->HasGpuMemoryBuffer());
   EXPECT_EQ(frame->GetGpuMemoryBuffer(), gmb_raw_ptr);
diff --git a/media/gpu/chromeos/fake_chromeos_intel_compressed_gpu_memory_buffer.cc b/media/gpu/chromeos/fake_chromeos_intel_compressed_gpu_memory_buffer.cc
index 24f652b8..8c699d8 100644
--- a/media/gpu/chromeos/fake_chromeos_intel_compressed_gpu_memory_buffer.cc
+++ b/media/gpu/chromeos/fake_chromeos_intel_compressed_gpu_memory_buffer.cc
@@ -8,6 +8,7 @@
 #include <fcntl.h>
 
 #include "base/atomic_sequence_num.h"
+#include "media/gpu/chromeos/chromeos_compressed_gpu_memory_buffer_video_frame_utils.h"
 
 namespace media {
 
@@ -22,9 +23,20 @@
 FakeChromeOSIntelCompressedGpuMemoryBuffer::
     FakeChromeOSIntelCompressedGpuMemoryBuffer(const gfx::Size& size,
                                                gfx::BufferFormat format)
+    : FakeChromeOSIntelCompressedGpuMemoryBuffer(
+          size,
+          format,
+          I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS) {}
+
+FakeChromeOSIntelCompressedGpuMemoryBuffer::
+    FakeChromeOSIntelCompressedGpuMemoryBuffer(const gfx::Size& size,
+                                               gfx::BufferFormat format,
+                                               uint64_t modifier)
     : size_(size), format_(format) {
   CHECK(format == gfx::BufferFormat::YUV_420_BIPLANAR ||
         format == gfx::BufferFormat::P010);
+  CHECK(modifier == I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS ||
+        modifier == I915_FORMAT_MOD_4_TILED_MTL_MC_CCS);
 
   handle_.type = gfx::NATIVE_PIXMAP;
 
@@ -40,7 +52,7 @@
         /*offset=*/i,
         /*size=*/i, GetDummyFD());
   }
-  handle_.native_pixmap_handle.modifier = I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS;
+  handle_.native_pixmap_handle.modifier = modifier;
 }
 
 FakeChromeOSIntelCompressedGpuMemoryBuffer::
diff --git a/media/gpu/chromeos/fake_chromeos_intel_compressed_gpu_memory_buffer.h b/media/gpu/chromeos/fake_chromeos_intel_compressed_gpu_memory_buffer.h
index 8acd349..7d93f9c8 100644
--- a/media/gpu/chromeos/fake_chromeos_intel_compressed_gpu_memory_buffer.h
+++ b/media/gpu/chromeos/fake_chromeos_intel_compressed_gpu_memory_buffer.h
@@ -11,12 +11,15 @@
 
 // A fake implementation of gpu::GpuMemoryBuffer for
 // testing purposes. It emulates a GpuMemoryBuffer that references a dma-buf
-// that uses Intel media compression (with a modifier of
-// I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS).
+// that uses Intel media compression (with a modifier of either
+// I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS or I915_FORMAT_MOD_4_TILED_MTL_MC_CCS).
 class FakeChromeOSIntelCompressedGpuMemoryBuffer : public gfx::GpuMemoryBuffer {
  public:
   FakeChromeOSIntelCompressedGpuMemoryBuffer(const gfx::Size& size,
                                              gfx::BufferFormat format);
+  FakeChromeOSIntelCompressedGpuMemoryBuffer(const gfx::Size& size,
+                                             gfx::BufferFormat format,
+                                             uint64_t modifier);
 
   FakeChromeOSIntelCompressedGpuMemoryBuffer(
       const FakeChromeOSIntelCompressedGpuMemoryBuffer&) = delete;
diff --git a/media/gpu/chromeos/platform_video_frame_pool.h b/media/gpu/chromeos/platform_video_frame_pool.h
index 14882039..dade648 100644
--- a/media/gpu/chromeos/platform_video_frame_pool.h
+++ b/media/gpu/chromeos/platform_video_frame_pool.h
@@ -75,7 +75,7 @@
   void SetCustomFrameAllocator(DmabufVideoFramePool::CreateFrameCB allocator);
 
  private:
-  friend class PlatformVideoFramePoolTest;
+  friend class PlatformVideoFramePoolTestBase;
 
   // Thunk to post OnFrameReleased() to |task_runner|.
   // Because this thunk may be called in any thread, We don't want to
diff --git a/media/gpu/chromeos/platform_video_frame_pool_unittest.cc b/media/gpu/chromeos/platform_video_frame_pool_unittest.cc
index aba236b7..fcb7316 100644
--- a/media/gpu/chromeos/platform_video_frame_pool_unittest.cc
+++ b/media/gpu/chromeos/platform_video_frame_pool_unittest.cc
@@ -66,10 +66,9 @@
 
 }  // namespace
 
-class PlatformVideoFramePoolTest
-    : public ::testing::TestWithParam<VideoPixelFormat> {
+class PlatformVideoFramePoolTestBase : public ::testing::Test {
  public:
-  PlatformVideoFramePoolTest()
+  PlatformVideoFramePoolTestBase()
       : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME),
         pool_(new PlatformVideoFramePool()) {
     SetCreateFrameCB(
@@ -132,10 +131,16 @@
   gfx::Size natural_size_;
 };
 
+class PlatformVideoFramePoolTest
+    : public PlatformVideoFramePoolTestBase,
+      public testing::WithParamInterface<VideoPixelFormat> {};
+
+constexpr VideoPixelFormat kPixelFormats[] = {
+    PIXEL_FORMAT_YV12, PIXEL_FORMAT_NV12, PIXEL_FORMAT_P016LE};
 INSTANTIATE_TEST_SUITE_P(
     All,
     PlatformVideoFramePoolTest,
-    testing::Values(PIXEL_FORMAT_YV12, PIXEL_FORMAT_NV12, PIXEL_FORMAT_P016LE),
+    testing::ValuesIn(kPixelFormats),
     [](const ::testing::TestParamInfo<VideoPixelFormat>& info) {
       return VideoPixelFormatToString(info.param);
     });
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index 92876e4..45fb29f 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -2864,15 +2864,20 @@
   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_SETTINGS);
   net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_SETTINGS_ACK);
 
-  base::UmaHistogramCounts1000("Net.SpdySession.OnSettings.CreatedStreamCount",
-                               created_streams_.size());
-  base::UmaHistogramCounts1000("Net.SpdySession.OnSettings.ActiveStreamCount",
-                               active_streams_.size());
-  base::UmaHistogramCounts1000(
-      "Net.SpdySession.OnSettings.CreatedAndActiveStreamCount",
-      created_streams_.size() + active_streams_.size());
-  base::UmaHistogramCounts1000("Net.SpdySession.OnSettings.PendingStreamCount",
-                               GetTotalSize(pending_create_stream_queues_));
+  if (!settings_frame_received_) {
+    base::UmaHistogramCounts1000(
+        "Net.SpdySession.OnSettings.CreatedStreamCount2",
+        created_streams_.size());
+    base::UmaHistogramCounts1000(
+        "Net.SpdySession.OnSettings.ActiveStreamCount2",
+        active_streams_.size());
+    base::UmaHistogramCounts1000(
+        "Net.SpdySession.OnSettings.CreatedAndActiveStreamCount2",
+        created_streams_.size() + active_streams_.size());
+    base::UmaHistogramCounts1000(
+        "Net.SpdySession.OnSettings.PendingStreamCount2",
+        GetTotalSize(pending_create_stream_queues_));
+  }
 
   // Send an acknowledgment of the setting.
   spdy::SpdySettingsIR settings_ir;
diff --git a/remoting/android/internal b/remoting/android/internal
index d4b268b..016a13f 160000
--- a/remoting/android/internal
+++ b/remoting/android/internal
@@ -1 +1 @@
-Subproject commit d4b268b20d45eeb46d9c7cb2b9d88f921254fdae
+Subproject commit 016a13fdc552a86d4ca8e730f156e6487c93056b
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn
index 4cd40bd..7d622ae 100644
--- a/remoting/host/BUILD.gn
+++ b/remoting/host/BUILD.gn
@@ -374,6 +374,8 @@
     "mouse_shape_pump.h",
     "pairing_registry_delegate.cc",
     "pairing_registry_delegate.h",
+    "passthrough_register_support_host_request.cc",
+    "passthrough_register_support_host_request.h",
     "pin_hash.cc",
     "pin_hash.h",
     "policy_watcher.cc",
diff --git a/remoting/host/chromeos/remote_support_host_ash.cc b/remoting/host/chromeos/remote_support_host_ash.cc
index 20b26ea..00787d55 100644
--- a/remoting/host/chromeos/remote_support_host_ash.cc
+++ b/remoting/host/chromeos/remote_support_host_ash.cc
@@ -207,6 +207,10 @@
 
   auto session_params =
       SessionParamsFromDict(*session->EnsureDict(kSessionParamsDict));
+  // DCHECK is added to detect cases where the access_token prefix is still
+  // being used when it shouldn't as this will mess up the store/retrieve cycle.
+  // TODO(b/309958013): Remove this DCHECK after M122.
+  DCHECK(!access_token.starts_with("oauth2:"));
   session_params.oauth_access_token = access_token;
 
   LOG(INFO) << "CRD: Reconnectable session found - starting connection";
diff --git a/remoting/host/chromeos/remote_support_host_ash_unittest.cc b/remoting/host/chromeos/remote_support_host_ash_unittest.cc
index 4286058..76f9e59 100644
--- a/remoting/host/chromeos/remote_support_host_ash_unittest.cc
+++ b/remoting/host/chromeos/remote_support_host_ash_unittest.cc
@@ -77,8 +77,7 @@
       reconnect_params.support_id = "1234567";
       reconnect_params.host_secret = "12345";
       reconnect_params.private_key = std::string(384, 'a');
-      reconnect_params.ftl_device_registration_id =
-          "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee";
+      reconnect_params.ftl_device_id = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee";
       return reconnect_params;
     }
     return absl::nullopt;
@@ -226,7 +225,7 @@
   mojom::SupportSessionParams GetSupportSessionParams() {
     mojom::SupportSessionParams params;
     params.user_name = "<the-user>";
-    params.oauth_access_token = "oauth2: VALID_ACCESS_TOKEN";
+    params.oauth_access_token = "VALID_ACCESS_TOKEN";
     params.authorized_helper = kRemoteAdminEmail;
     return params;
   }
@@ -347,13 +346,14 @@
   EXPECT_EQ(it2me_host().user_name(), params.user_name);
 }
 
-TEST_F(RemoteSupportHostAshTest, ShouldPassOAuthTokenToIt2MeHostWhenStarting) {
+// TODO(b/309958013): Remove this test when we remove the oauth prefix logic.
+TEST_F(RemoteSupportHostAshTest, ValidLegacyAccessTokenFormatSucceeds) {
   mojom::SupportSessionParams params = GetSupportSessionParams();
-  params.oauth_access_token = "<the-oauth-token>";
+  params.oauth_access_token = "oauth2:<the-oauth-token>";
 
   StartSession(params, ChromeOsEnterpriseParams{});
 
-  EXPECT_EQ(it2me_host().user_name(), params.user_name);
+  EXPECT_TRUE(it2me_host().WaitForConnectCall());
 }
 
 TEST_P(RemoteSupportHostAshTest,
diff --git a/remoting/host/it2me/it2me_constants.cc b/remoting/host/it2me/it2me_constants.cc
index 938a11a..b893045e0 100644
--- a/remoting/host/it2me/it2me_constants.cc
+++ b/remoting/host/it2me/it2me_constants.cc
@@ -13,6 +13,7 @@
 const char kConnectMessage[] = "connect";
 const char kUserName[] = "userName";
 const char kAuthServiceWithToken[] = "authServiceWithToken";
+const char kAccessToken[] = "accessToken";
 const char kLocalJid[] = "localJid";
 const char kDirectoryBotJidValue[] = "remoting@bot.talk.google.com";
 const char kSuppressUserDialogs[] = "suppressUserDialogs";
@@ -72,7 +73,6 @@
 const char kReconnectSupportId[] = "reconnectSupportId";
 const char kReconnectHostSecret[] = "reconnectHostSecret";
 const char kReconnectPrivateKey[] = "reconnectPrivateKey";
-const char kReconnectFtlDeviceRegistrationId[] =
-    "reconnectFtlDeviceRegistrationId";
+const char kReconnectFtlDeviceId[] = "reconnectFtlDeviceId";
 
 }  // namespace remoting
diff --git a/remoting/host/it2me/it2me_constants.h b/remoting/host/it2me/it2me_constants.h
index 59aad34..e3af536 100644
--- a/remoting/host/it2me/it2me_constants.h
+++ b/remoting/host/it2me/it2me_constants.h
@@ -38,6 +38,7 @@
 // Connect message parameters.
 extern const char kUserName[];
 extern const char kAuthServiceWithToken[];
+extern const char kAccessToken[];
 extern const char kLocalJid[];
 extern const char kDirectoryBotJidValue[];
 extern const char kIsEnterpriseAdminUser[];
@@ -117,7 +118,7 @@
 extern const char kReconnectSupportId[];
 extern const char kReconnectHostSecret[];
 extern const char kReconnectPrivateKey[];
-extern const char kReconnectFtlDeviceRegistrationId[];
+extern const char kReconnectFtlDeviceId[];
 
 }  // namespace remoting
 
diff --git a/remoting/host/it2me/it2me_host.cc b/remoting/host/it2me/it2me_host.cc
index 9065e2b..7c37e0a 100644
--- a/remoting/host/it2me/it2me_host.cc
+++ b/remoting/host/it2me/it2me_host.cc
@@ -33,6 +33,7 @@
 #include "remoting/host/it2me/it2me_confirmation_dialog.h"
 #include "remoting/host/it2me/it2me_helpers.h"
 #include "remoting/host/it2me_desktop_environment.h"
+#include "remoting/host/passthrough_register_support_host_request.h"
 #include "remoting/protocol/auth_util.h"
 #include "remoting/protocol/chromium_port_allocator_factory.h"
 #include "remoting/protocol/it2me_host_authenticator_factory.h"
@@ -136,7 +137,7 @@
   reconnect_params->support_id = support_id_;
   reconnect_params->host_secret = host_secret_;
   reconnect_params->private_key = host_key_pair_->ToString();
-  reconnect_params->ftl_device_registration_id = ftl_device_registration_id_;
+  reconnect_params->ftl_device_id = ftl_device_id_;
 #endif
 
   return reconnect_params;
@@ -217,6 +218,7 @@
     ftl_signaling_connector_ = std::make_unique<FtlSignalingConnector>(
         signal_strategy_.get(), base::DoNothing());
     ftl_signaling_connector_->Start();
+    ftl_device_id_ = connection_context->ftl_device_id;
   }
 
   // Check the host domain policy.
@@ -245,13 +247,8 @@
     // Generate a new host secret for this instance.
     host_secret_ = GenerateSupportHostSecret();
 
-    // Request registration of the host for support.
+    // Register this host instance in the backend service.
     register_request_ = std::move(connection_context->register_request);
-    register_request_->StartRequest(
-        signal_strategy_.get(), host_key_pair_, authorized_helper_,
-        std::move(chrome_os_enterprise_params_),
-        base::BindOnce(&It2MeHost::OnReceivedSupportID,
-                       base::Unretained(this)));
   } else {
     // Reconnections are only allowed for Chrome OS enterprise sessions.
     CHECK(SessionSupportsReconnections());
@@ -264,12 +261,14 @@
 
     // Skip the registration service call as the entry will be retrievable by
     // the `authorized_helper` for ~24 hours when 'allow_reconnections' is set.
-    host_context_->network_task_runner()->PostTask(
-        FROM_HERE, base::BindOnce(&It2MeHost::OnReceivedSupportID,
-                                  weak_factory_.GetWeakPtr(),
-                                  reconnect_params_->support_id,
-                                  base::Minutes(5), ErrorCode::OK));
+    register_request_ = std::make_unique<PassthroughRegisterSupportHostRequest>(
+        reconnect_params_->support_id);
   }
+  register_request_->StartRequest(
+      signal_strategy_.get(), host_key_pair_, authorized_helper_,
+      std::move(chrome_os_enterprise_params_),
+      base::BindOnce(&It2MeHost::OnReceivedSupportID,
+                     weak_factory_.GetWeakPtr()));
 
   HOST_LOG << "NAT traversal enabled: " << nat_traversal_enabled_;
   HOST_LOG << "Relay connections allowed: " << relay_connections_allowed_;
@@ -669,13 +668,6 @@
   std::string access_code_hash =
       protocol::GetSharedSecretHash(support_id_, access_code);
 
-  if (SessionSupportsReconnections()) {
-    // Retrieve the registration id now that signaling is connected. This id
-    // will be required if the admin needs to reconnect.
-    signal_strategy_->GetLocalAddress().GetFtlInfo(
-        /*username=*/nullptr, &ftl_device_registration_id_);
-  }
-
   std::string local_certificate = host_key_pair_->GenerateCertificate();
   if (local_certificate.empty()) {
     LOG(ERROR) << "Failed to generate host certificate.";
diff --git a/remoting/host/it2me/it2me_host.h b/remoting/host/it2me/it2me_host.h
index 87453ca..60115b57 100644
--- a/remoting/host/it2me/it2me_host.h
+++ b/remoting/host/it2me/it2me_host.h
@@ -66,6 +66,8 @@
     // TODO(joedow): Remove this field once delegated signaling has been
     // deprecated and removed.
     bool use_ftl_signaling = false;
+    // Only set when FTL signaling is being used.
+    std::string ftl_device_id;
   };
 
   using CreateDeferredConnectContext =
@@ -224,7 +226,7 @@
 
   std::string support_id_;
   std::string host_secret_;
-  std::string ftl_device_registration_id_;
+  std::string ftl_device_id_;
   scoped_refptr<RsaKeyPair> host_key_pair_;
   std::unique_ptr<RegisterSupportHostRequest> register_request_;
   std::unique_ptr<HostStatusLogger> host_status_logger_;
diff --git a/remoting/host/it2me/it2me_native_messaging_host.cc b/remoting/host/it2me/it2me_native_messaging_host.cc
index c543433..b55eef5 100644
--- a/remoting/host/it2me/it2me_native_messaging_host.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host.cc
@@ -17,6 +17,7 @@
 #include "base/task/single_thread_task_runner.h"
 #include "base/threading/thread.h"
 #include "base/time/time.h"
+#include "base/uuid.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
@@ -38,8 +39,8 @@
 #include "remoting/host/xmpp_register_support_host_request.h"
 #include "remoting/protocol/ice_config.h"
 #include "remoting/signaling/delegating_signal_strategy.h"
-#include "remoting/signaling/ftl_client_uuid_device_id_provider.h"
 #include "remoting/signaling/ftl_signal_strategy.h"
+#include "remoting/signaling/ftl_support_host_device_id_provider.h"
 #include "remoting/signaling/remoting_log_to_server.h"
 #include "remoting/signaling/server_log_entry.h"
 #include "remoting/signaling/xmpp_log_to_server.h"
@@ -135,19 +136,19 @@
 CreateNativeSignalingDeferredConnectContext(
     const std::string& username,
     const std::string& access_token,
-    const std::string& ftl_device_registration_id,
+    const std::string& ftl_device_id,
     ChromotingHostContext* host_context) {
-  auto device_id_provider =
-      ftl_device_registration_id.empty()
-          ? std::make_unique<FtlClientUuidDeviceIdProvider>()
-          : std::make_unique<FtlClientUuidDeviceIdProvider>(
-                ftl_device_registration_id);
+  std::string device_id =
+      ftl_device_id.empty() ? base::Uuid::GenerateRandomV4().AsLowercaseString()
+                            : ftl_device_id;
   auto connection_context =
       std::make_unique<It2MeHost::DeferredConnectContext>();
   connection_context->use_ftl_signaling = true;
   connection_context->signal_strategy = std::make_unique<FtlSignalStrategy>(
       std::make_unique<PassthroughOAuthTokenGetter>(username, access_token),
-      host_context->url_loader_factory(), std::move(device_id_provider));
+      host_context->url_loader_factory(),
+      std::make_unique<FtlSupportHostDeviceIdProvider>(device_id));
+  connection_context->ftl_device_id = std::move(device_id);
   connection_context->register_request =
       std::make_unique<RemotingRegisterSupportHostRequest>(
           std::make_unique<PassthroughOAuthTokenGetter>(username, access_token),
@@ -357,14 +358,13 @@
   } else {
     if (!username.empty()) {
       std::string access_token = ExtractAccessToken(message);
-      std::string ftl_device_registration_id;
+      std::string ftl_device_id;
       if (reconnect_params.has_value()) {
-        ftl_device_registration_id =
-            reconnect_params->ftl_device_registration_id;
+        ftl_device_id = reconnect_params->ftl_device_id;
       }
       create_connection_context =
           base::BindOnce(&CreateNativeSignalingDeferredConnectContext, username,
-                         access_token, ftl_device_registration_id);
+                         access_token, ftl_device_id);
     } else {
       LOG(ERROR) << kUserName << " not found in request.";
     }
@@ -669,25 +669,44 @@
 
 std::string It2MeNativeMessagingHost::ExtractAccessToken(
     const base::Value::Dict& message) {
+  // TODO(b/309958013): Remove this function, code, and unused constants after
+  // M124 and we no longer need to deal with the kAuthServiceWithToken field.
+  const std::string* access_token = message.FindString(kAccessToken);
+  if (access_token) {
+    if (access_token->empty()) {
+      LOG(ERROR) << "Empty token stored in " << kAccessToken << " field";
+      return {};
+    }
+    return *access_token;
+  }
+
   const std::string* auth_service_with_token =
       message.FindString(kAuthServiceWithToken);
-  if (!auth_service_with_token) {
+  if (!auth_service_with_token || auth_service_with_token->empty()) {
     LOG(ERROR) << "'authServiceWithToken' not found in request.";
     return {};
   }
 
-  // For backward compatibility the webapp still passes OAuth service as part
-  // of the authServiceWithToken field. But auth service part is always
-  // expected to be set to oauth2.
+  // We are migrating away from requiring the oauth2 prefix in the
+  // kAuthServiceWithToken field, however ash-chrome needs to support different
+  // versions of lacros-chrome which may not have been updated. Therefore, we
+  // need to support messages which are prefixed with oauth2: as well as those
+  // which pass a raw access token.
   const char kOAuth2ServicePrefix[] = "oauth2:";
-  if (!base::StartsWith(*auth_service_with_token, kOAuth2ServicePrefix,
-                        base::CompareCase::SENSITIVE)) {
-    LOG(ERROR) << "Invalid 'authServiceWithToken': "
-               << *auth_service_with_token;
-    return {};
+  if (base::StartsWith(*auth_service_with_token, kOAuth2ServicePrefix,
+                       base::CompareCase::SENSITIVE)) {
+    return auth_service_with_token->substr(strlen(kOAuth2ServicePrefix));
   }
 
-  return auth_service_with_token->substr(strlen(kOAuth2ServicePrefix));
+  // Log an error if an access token is provided which does not match the
+  // expected format. Though this prefix is effectively stable, there is are no
+  // guarantees so we shouldn't reject requests based on it.
+  if (!auth_service_with_token->starts_with("ya29.")) {
+    LOG(ERROR) << "Potentially invalid auth_service_with_token value: "
+               << *auth_service_with_token;
+  }
+
+  return *auth_service_with_token;
 }
 
 #if BUILDFLAG(IS_WIN)
diff --git a/remoting/host/it2me/it2me_native_messaging_host_ash.cc b/remoting/host/it2me/it2me_native_messaging_host_ash.cc
index ee1859e3..8cd9948e 100644
--- a/remoting/host/it2me/it2me_native_messaging_host_ash.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host_ash.cc
@@ -170,11 +170,24 @@
   host_state_disconnected_callback_ =
       std::move(host_state_disconnected_callback);
 
+  // The version of Lacros is guaranteed to be at least as new as the code
+  // running in ash so we can remove this shim in M124, however we need it until
+  // then as Lacros will continue sending the oauth2 prefix for back-compat
+  // until that milestone. Basically the shim code in Lacros and Ash can be
+  // removed in the same milestone but the Lacros code needs to stay in place
+  // until the back-compat behavior is no longer required.
+  std::string access_token = params.oauth_access_token;
+  const char kOAuth2ServicePrefix[] = "oauth2:";
+  // Strip the prefix off, if it exists.
+  if (access_token.starts_with(kOAuth2ServicePrefix)) {
+    access_token = access_token.substr(strlen(kOAuth2ServicePrefix));
+  }
+
   auto message =
       base::Value::Dict()
           .Set(kMessageType, kConnectMessage)
           .Set(kUserName, params.user_name)
-          .Set(kAuthServiceWithToken, params.oauth_access_token)
+          .Set(kAccessToken, access_token)
           .Set(kSuppressUserDialogs,
                ShouldSuppressUserDialog(params, enterprise_params))
           .Set(kSuppressNotifications,
diff --git a/remoting/host/it2me/it2me_native_messaging_host_lacros.cc b/remoting/host/it2me/it2me_native_messaging_host_lacros.cc
index f8df9023..e9a58ae2f 100644
--- a/remoting/host/it2me/it2me_native_messaging_host_lacros.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host_lacros.cc
@@ -382,12 +382,31 @@
   }
   session_params->user_name = *user_name;
 
-  const std::string* access_token = message.FindString(kAuthServiceWithToken);
-  if (!access_token) {
+  // The code to extract and forward the access_token needs to handle a couple
+  // of conditions due to Lacros/Ash version skew. The M121 CRD host
+  // implementation can handle `oauth_access_token` values which are raw or
+  // prefixed by 'oauth2:' however Lacros can run on older versions of Ash which
+  // only handle the prefixed variant. This compat code can be removed in M124
+  // based on the current version skew policy.
+  // This code also handles the case where an older webclient does not send the
+  // kAccessToken field however that will resolve in a few weeks and the code
+  // can safely be removed in M122.
+  std::string access_token;
+  const std::string* access_token_ptr = message.FindString(kAccessToken);
+  const std::string* auth_service_with_token_ptr =
+      message.FindString(kAuthServiceWithToken);
+  if (access_token_ptr) {
+    // TODO(b/309958013): Remove the prefix shim.
+    access_token = "oauth2:" + *access_token_ptr;
+  } else if (auth_service_with_token_ptr) {
+    // kAuthServiceWithToken always starts with 'oauth2:'.
+    access_token = *auth_service_with_token_ptr;
+  }
+  if (access_token.empty()) {
     SendErrorAndExit(protocol::ErrorCode::INCOMPATIBLE_PROTOCOL, message_id);
     return;
   }
-  session_params->oauth_access_token = *access_token;
+  session_params->oauth_access_token = std::move(access_token);
 
   const std::string* authorized_helper = message.FindString(kAuthorizedHelper);
   if (authorized_helper) {
diff --git a/remoting/host/it2me/reconnect_params.cc b/remoting/host/it2me/reconnect_params.cc
index 88b6043..2cd9ab1 100644
--- a/remoting/host/it2me/reconnect_params.cc
+++ b/remoting/host/it2me/reconnect_params.cc
@@ -22,8 +22,7 @@
       .Set(kReconnectSupportId, params.support_id)
       .Set(kReconnectHostSecret, params.host_secret)
       .Set(kReconnectPrivateKey, params.private_key)
-      .Set(kReconnectFtlDeviceRegistrationId,
-           params.ftl_device_registration_id);
+      .Set(kReconnectFtlDeviceId, params.ftl_device_id);
 }
 
 ReconnectParams ReconnectParams::FromDict(const base::Value::Dict& dict) {
@@ -40,10 +39,9 @@
   if (private_key) {
     params.private_key = *private_key;
   }
-  const std::string* ftl_device_registration_id =
-      dict.FindString(kReconnectFtlDeviceRegistrationId);
-  if (ftl_device_registration_id) {
-    params.ftl_device_registration_id = *ftl_device_registration_id;
+  const std::string* ftl_device_id = dict.FindString(kReconnectFtlDeviceId);
+  if (ftl_device_id) {
+    params.ftl_device_id = *ftl_device_id;
   }
 
   DCHECK(params.IsValid());
@@ -72,13 +70,11 @@
     return false;
   }
 
-  if (ftl_device_registration_id.empty()) {
-    LOG(ERROR) << "Missing field: ftl_device_registration_id";
+  if (ftl_device_id.empty()) {
+    LOG(ERROR) << "Missing field: ftl_device_id";
     return false;
-  } else if (!base::Uuid::ParseLowercase(ftl_device_registration_id)
-                  .is_valid()) {
-    LOG(ERROR) << "Invalid ftl_device_registration_id: "
-               << ftl_device_registration_id;
+  } else if (!base::Uuid::ParseLowercase(ftl_device_id).is_valid()) {
+    LOG(ERROR) << "Invalid ftl_device_id: " << ftl_device_id;
     return false;
   }
 
diff --git a/remoting/host/it2me/reconnect_params.h b/remoting/host/it2me/reconnect_params.h
index a77d6867..e3c5a54 100644
--- a/remoting/host/it2me/reconnect_params.h
+++ b/remoting/host/it2me/reconnect_params.h
@@ -33,8 +33,9 @@
   // A Base64 encoded string representing the host's private key.
   std::string private_key;
 
-  // A UUID representing an endpoint in the FTL signaling service.
-  std::string ftl_device_registration_id;
+  // A UUID representing an endpoint in the FTL signaling service. This ID is
+  // used to generate the registration ID which is used for endpoint targeting.
+  std::string ftl_device_id;
 };
 
 }  // namespace remoting
diff --git a/remoting/host/passthrough_register_support_host_request.cc b/remoting/host/passthrough_register_support_host_request.cc
new file mode 100644
index 0000000..039fd3c
--- /dev/null
+++ b/remoting/host/passthrough_register_support_host_request.cc
@@ -0,0 +1,70 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "remoting/host/passthrough_register_support_host_request.h"
+
+#include "remoting/base/rsa_key_pair.h"
+#include "remoting/host/chromeos/chromeos_enterprise_params.h"
+
+namespace remoting {
+
+PassthroughRegisterSupportHostRequest::PassthroughRegisterSupportHostRequest(
+    const std::string& support_id)
+    : support_id_(support_id) {}
+
+PassthroughRegisterSupportHostRequest::
+    ~PassthroughRegisterSupportHostRequest() {
+  if (signal_strategy_) {
+    signal_strategy_->RemoveListener(this);
+  }
+}
+
+void PassthroughRegisterSupportHostRequest::StartRequest(
+    SignalStrategy* signal_strategy,
+    scoped_refptr<RsaKeyPair> key_pair,
+    const std::string& authorized_helper,
+    absl::optional<ChromeOsEnterpriseParams> params,
+    RegisterCallback callback) {
+  signal_strategy_ = signal_strategy;
+  callback_ = std::move(callback);
+
+  signal_strategy_->AddListener(this);
+}
+
+void PassthroughRegisterSupportHostRequest::OnSignalStrategyStateChange(
+    SignalStrategy::State state) {
+  switch (state) {
+    case SignalStrategy::State::CONNECTED:
+      RunCallback(support_id_, {}, protocol::ErrorCode::OK);
+      break;
+    case SignalStrategy::State::DISCONNECTED:
+      RunCallback({}, {}, protocol::ErrorCode::SIGNALING_ERROR);
+      break;
+    default:
+      // No work is needed until signaling connects or errors out.
+      break;
+  }
+}
+
+bool PassthroughRegisterSupportHostRequest::OnSignalStrategyIncomingStanza(
+    const jingle_xmpp::XmlElement* stanza) {
+  return false;
+}
+
+void PassthroughRegisterSupportHostRequest::RunCallback(
+    const std::string& support_id,
+    base::TimeDelta lifetime,
+    protocol::ErrorCode error_code) {
+  if (!callback_) {
+    // Callback has already been run, so just return.
+    return;
+  }
+
+  signal_strategy_->RemoveListener(this);
+  signal_strategy_ = nullptr;
+
+  std::move(callback_).Run(support_id, lifetime, error_code);
+}
+
+}  // namespace remoting
diff --git a/remoting/host/passthrough_register_support_host_request.h b/remoting/host/passthrough_register_support_host_request.h
new file mode 100644
index 0000000..2ee2679
--- /dev/null
+++ b/remoting/host/passthrough_register_support_host_request.h
@@ -0,0 +1,63 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef REMOTING_HOST_PASSTHROUGH_REGISTER_SUPPORT_HOST_REQUEST_H_
+#define REMOTING_HOST_PASSTHROUGH_REGISTER_SUPPORT_HOST_REQUEST_H_
+
+#include "base/functional/callback.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/time/time.h"
+#include "remoting/host/register_support_host_request.h"
+#include "remoting/protocol/errors.h"
+#include "remoting/signaling/signal_strategy.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace remoting {
+
+struct ChromeOsEnterpriseParams;
+class RsaKeyPair;
+
+// A RegisterSupportHostRequest implementation that skips the server-side
+// registration call and returns a specific value. This class is used for cases
+// where a host instance has already been registered and we want to use the same
+// support id for a new instance.
+class PassthroughRegisterSupportHostRequest final
+    : public RegisterSupportHostRequest,
+      public SignalStrategy::Listener {
+ public:
+  explicit PassthroughRegisterSupportHostRequest(const std::string& support_id);
+
+  PassthroughRegisterSupportHostRequest(
+      const PassthroughRegisterSupportHostRequest&) = delete;
+  PassthroughRegisterSupportHostRequest& operator=(
+      const PassthroughRegisterSupportHostRequest&) = delete;
+
+  ~PassthroughRegisterSupportHostRequest() override;
+
+  // RegisterSupportHostRequest implementation.
+  void StartRequest(SignalStrategy* signal_strategy,
+                    scoped_refptr<RsaKeyPair> key_pair,
+                    const std::string& authorized_helper,
+                    absl::optional<ChromeOsEnterpriseParams> params,
+                    RegisterCallback callback) override;
+
+ private:
+  // SignalStrategy::Listener interface.
+  void OnSignalStrategyStateChange(SignalStrategy::State state) override;
+  bool OnSignalStrategyIncomingStanza(
+      const jingle_xmpp::XmlElement* stanza) override;
+
+  void RunCallback(const std::string& support_id,
+                   base::TimeDelta lifetime,
+                   protocol::ErrorCode error_code);
+
+  std::string support_id_;
+  RegisterCallback callback_;
+  raw_ptr<SignalStrategy> signal_strategy_ = nullptr;
+};
+
+}  // namespace remoting
+
+#endif  // REMOTING_HOST_PASSTHROUGH_REGISTER_SUPPORT_HOST_REQUEST_H_
diff --git a/remoting/signaling/BUILD.gn b/remoting/signaling/BUILD.gn
index 9aace108..ba3ee18 100644
--- a/remoting/signaling/BUILD.gn
+++ b/remoting/signaling/BUILD.gn
@@ -21,6 +21,8 @@
     "ftl_services_context.h",
     "ftl_signal_strategy.cc",
     "ftl_signal_strategy.h",
+    "ftl_support_host_device_id_provider.cc",
+    "ftl_support_host_device_id_provider.h",
     "iq_sender.cc",
     "iq_sender.h",
     "message_reception_channel.h",
diff --git a/remoting/signaling/ftl_client_uuid_device_id_provider.cc b/remoting/signaling/ftl_client_uuid_device_id_provider.cc
index 8415852..bde5341 100644
--- a/remoting/signaling/ftl_client_uuid_device_id_provider.cc
+++ b/remoting/signaling/ftl_client_uuid_device_id_provider.cc
@@ -9,12 +9,7 @@
 namespace remoting {
 
 FtlClientUuidDeviceIdProvider::FtlClientUuidDeviceIdProvider()
-    : FtlClientUuidDeviceIdProvider(
-          base::Uuid::GenerateRandomV4().AsLowercaseString()) {}
-
-FtlClientUuidDeviceIdProvider::FtlClientUuidDeviceIdProvider(
-    const std::string& device_id)
-    : client_uuid_(device_id) {}
+    : client_uuid_(base::Uuid::GenerateRandomV4().AsLowercaseString()) {}
 
 FtlClientUuidDeviceIdProvider::~FtlClientUuidDeviceIdProvider() = default;
 
diff --git a/remoting/signaling/ftl_client_uuid_device_id_provider.h b/remoting/signaling/ftl_client_uuid_device_id_provider.h
index b18b30e..d7af1666 100644
--- a/remoting/signaling/ftl_client_uuid_device_id_provider.h
+++ b/remoting/signaling/ftl_client_uuid_device_id_provider.h
@@ -16,7 +16,6 @@
 class FtlClientUuidDeviceIdProvider : public FtlDeviceIdProvider {
  public:
   FtlClientUuidDeviceIdProvider();
-  explicit FtlClientUuidDeviceIdProvider(const std::string&);
   ~FtlClientUuidDeviceIdProvider() override;
 
   ftl::DeviceId GetDeviceId() override;
diff --git a/remoting/signaling/ftl_device_id_provider.h b/remoting/signaling/ftl_device_id_provider.h
index 18d06c3..beefe70f 100644
--- a/remoting/signaling/ftl_device_id_provider.h
+++ b/remoting/signaling/ftl_device_id_provider.h
@@ -17,7 +17,7 @@
   // Gets a device ID to use for signing into FTL. It's the subclass'
   // responsibility to store and reuse stored device ID.
   //
-  // Subclass should consider adding prefix to the device ID, like
+  // Subclasses should consider adding a prefix to the device ID, like
   // "crd-win-host-".
   virtual ftl::DeviceId GetDeviceId() = 0;
 };
diff --git a/remoting/signaling/ftl_support_host_device_id_provider.cc b/remoting/signaling/ftl_support_host_device_id_provider.cc
new file mode 100644
index 0000000..1a7721764
--- /dev/null
+++ b/remoting/signaling/ftl_support_host_device_id_provider.cc
@@ -0,0 +1,26 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "remoting/signaling/ftl_support_host_device_id_provider.h"
+
+namespace remoting {
+
+namespace {
+constexpr char kDeviceIdPrefix[] = "crd-it2me-host-";
+}
+
+FtlSupportHostDeviceIdProvider::FtlSupportHostDeviceIdProvider(
+    const std::string& device_id)
+    : support_host_device_id_(kDeviceIdPrefix + device_id) {}
+
+FtlSupportHostDeviceIdProvider::~FtlSupportHostDeviceIdProvider() = default;
+
+ftl::DeviceId FtlSupportHostDeviceIdProvider::GetDeviceId() {
+  ftl::DeviceId device_id;
+  device_id.set_type(ftl::DeviceIdType_Type_CHROMOTING_HOST_ID);
+  device_id.set_id(support_host_device_id_);
+  return device_id;
+}
+
+}  // namespace remoting
diff --git a/remoting/signaling/ftl_support_host_device_id_provider.h b/remoting/signaling/ftl_support_host_device_id_provider.h
new file mode 100644
index 0000000..2fb3b84
--- /dev/null
+++ b/remoting/signaling/ftl_support_host_device_id_provider.h
@@ -0,0 +1,28 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef REMOTING_SIGNALING_FTL_SUPPORT_HOST_DEVICE_ID_PROVIDER_H_
+#define REMOTING_SIGNALING_FTL_SUPPORT_HOST_DEVICE_ID_PROVIDER_H_
+
+#include <string>
+
+#include "remoting/signaling/ftl_device_id_provider.h"
+
+namespace remoting {
+
+// A device ID provider for remote support hosts.
+class FtlSupportHostDeviceIdProvider : public FtlDeviceIdProvider {
+ public:
+  explicit FtlSupportHostDeviceIdProvider(const std::string&);
+  ~FtlSupportHostDeviceIdProvider() override;
+
+  ftl::DeviceId GetDeviceId() override;
+
+ private:
+  std::string support_host_device_id_;
+};
+
+}  // namespace remoting
+
+#endif  // REMOTING_SIGNALING_FTL_SUPPORT_HOST_DEVICE_ID_PROVIDER_H_
diff --git a/remoting/test/it2me_cli_host.cc b/remoting/test/it2me_cli_host.cc
index 8d80bad..fbfca23 100644
--- a/remoting/test/it2me_cli_host.cc
+++ b/remoting/test/it2me_cli_host.cc
@@ -178,6 +178,7 @@
   connect_params_ = base::Value::Dict()
                         .Set(kUserName, user_email)
                         .Set(kAuthServiceWithToken, "oauth2:" + access_token)
+                        .Set(kAccessToken, access_token)
                         .Set(kSuppressUserDialogs, true)
                         .Set(kSuppressNotifications, true);
 
diff --git a/sandbox/policy/mac/BUILD.gn b/sandbox/policy/mac/BUILD.gn
index df919203..05afad1 100644
--- a/sandbox/policy/mac/BUILD.gn
+++ b/sandbox/policy/mac/BUILD.gn
@@ -13,6 +13,7 @@
   "mirroring.sb",
   "nacl_loader.sb",
   "network.sb",
+  "on_device_model_execution.sb",
   "ppapi.sb",
   "print_compositor.sb",
   "renderer.sb",
diff --git a/sandbox/policy/mac/common.sb b/sandbox/policy/mac/common.sb
index 91773ada..22d749b 100644
--- a/sandbox/policy/mac/common.sb
+++ b/sandbox/policy/mac/common.sb
@@ -12,6 +12,7 @@
 ; Define constants for all of the parameter strings passed in.
 (define browser-pid "BROWSER_PID")
 (define bundle-id "BUNDLE_ID")
+(define helper-bundle-id "HELPER_BUNDLE_ID")
 (define bundle-path "BUNDLE_PATH")
 (define component-path "COMPONENT_PATH")
 (define disable-sandbox-denial-logging "DISABLE_SANDBOX_DENIAL_LOGGING")
@@ -29,6 +30,9 @@
 (define filter-syscalls "FILTER_SYSCALLS")
 (define filter-syscalls-debug "FILTER_SYSCALLS_DEBUG")
 
+; Sandboxed processes which use Metal may need to disable the shader cache.
+(define disable-metal-shader-cache "DISABLE_METAL_SHADER_CACHE")
+
 ; --enable-sandbox-logging causes the sandbox to log failures to the syslog.
 (if (param-true? disable-sandbox-denial-logging)
   (deny default (with no-log))
@@ -65,6 +69,42 @@
     ; (https://crbug.com/662686)
     (allow file-read* (extension "com.apple.app-sandbox.read"))))
 
+; A function that profiles can call to allow forcibly disabling the Metal shader
+; cache in lieu of poking necessary holes in the sandbox for it.
+; See https://crbug.com/1159113
+(define (maybe-disable-metal-shader-cache)
+  (if (param-true? disable-metal-shader-cache)
+    (let ((metal-cache-dir (subpath (string-append (param darwin-user-cache-dir)
+                                                   "/com.apple.metal"))))
+      (deny file-read* metal-cache-dir)
+      (deny file-write* metal-cache-dir)
+      #t)
+    #f))
+
+; A function profiles can call to enable the requisite file access needed for
+; Metal shader compilation to work with the shader cache.
+;
+; Metal shader compilation may be offloaded to a helper process that needs
+; access to the user cache directory in order to cache its work to disk.
+; If this sandbox is applied to an executable that is not within an app bundle,
+; such as in a unit test, the helper-bundle-id parameter will not be set and
+; issuing sandbox extensions to the Metal cache directories will not be allowed.
+; See https://crbug.com/1453813
+(define (maybe-allow-metal-shader-cache-access)
+  (begin
+    (if (param helper-bundle-id)
+      (let ((helper-bundle-cache-dir
+            (string-append (param darwin-user-cache-dir)
+                            "/" (param helper-bundle-id))))
+        (allow file-issue-extension
+          (require-all
+            (extension-class "com.apple.app-sandbox.read-write")
+            (require-any
+              (subpath (string-append helper-bundle-cache-dir
+                                      "/com.apple.metalfe"))
+              (subpath (string-append helper-bundle-cache-dir
+                                      "/com.apple.gpuarchiver")))))))))
+
 ; Reads of signed Mach-O blobs created by the CVMS server.
 ; https://crbug.com/850021
 (define (allow-cvms-blobs)
diff --git a/sandbox/policy/mac/gpu.sb b/sandbox/policy/mac/gpu.sb
index b1c6787..27d7574a 100644
--- a/sandbox/policy/mac/gpu.sb
+++ b/sandbox/policy/mac/gpu.sb
@@ -14,9 +14,6 @@
 
 (allow ipc-posix-shm)
 
-(define helper-bundle-id "HELPER_BUNDLE_ID")
-(define disable-metal-shader-cache "DISABLE_METAL_SHADER_CACHE")
-
 ; Allow communication between the GPU process and the UI server.
 (allow mach-lookup
   ; Needed for AudioToolbox AAC encoding (https://crbug.com/1321287) and
@@ -133,23 +130,6 @@
   (subpath (param darwin-user-temp-dir))
 )
 
-; Metal shader compilation may be offloaded to a helper process that needs
-; access to the user cache directory in order to cache its work to disk.
-; If this sandbox is applied to an executable that is not within an app bundle,
-; such as in a unit test, the helper-bundle-id parameter will not be set and
-; issuing sandbox extensions to the Metal cache directories will not be allowed.
-; crbug.com/1453813
-(if (param helper-bundle-id)
-  (let ((helper-bundle-cache-dir
-        (string-append (param darwin-user-cache-dir)
-                        "/" (param helper-bundle-id))))
-    (allow file-issue-extension
-      (require-all
-        (extension-class "com.apple.app-sandbox.read-write")
-        (require-any
-          (subpath (string-append helper-bundle-cache-dir "/com.apple.metalfe"))
-          (subpath (string-append helper-bundle-cache-dir "/com.apple.gpuarchiver")))))))
-
 (if (param-true? filter-syscalls-debug)
   (when (defined? 'syscall-unix)
     (deny syscall-unix (with send-signal SIGSYS))
@@ -163,10 +143,5 @@
       (syscall-number SYS_write_nocancel)
 )))
 
-; crbug.com/1159113
-(if (param-true? disable-metal-shader-cache)
-  (let ((metal-cache-dir (subpath (string-append (param darwin-user-cache-dir)
-                                                 "/com.apple.metal"))))
-    (deny file-read* metal-cache-dir)
-    (deny file-write* metal-cache-dir))
-)
+(if (not (maybe-disable-metal-shader-cache))
+  (maybe-allow-metal-shader-cache-access))
diff --git a/sandbox/policy/mac/on_device_model_execution.sb b/sandbox/policy/mac/on_device_model_execution.sb
new file mode 100644
index 0000000..e25a5b3
--- /dev/null
+++ b/sandbox/policy/mac/on_device_model_execution.sb
@@ -0,0 +1,66 @@
+; Copyright 2023 The Chromium Authors
+; Use of this source code is governed by a BSD-style license that can be
+; found in the LICENSE file.
+
+; --- The contents of common.sb implicitly included here. ---
+
+; Allow cf prefs to work.
+(allow user-preference-read)
+
+(allow-cvms-blobs)
+
+(allow ipc-posix-shm)
+
+; Needed for metal decoding - https://crbug.com/957217
+(if (>= os-version 1014)
+  (allow mach-lookup (xpc-service-name "com.apple.MTLCompilerService"))
+)
+
+(allow iokit-open
+  (iokit-connection "IOAccelerator")
+  (iokit-user-client-class "AGPMClient")
+  (iokit-user-client-class "AppleGraphicsControlClient")
+  (iokit-user-client-class "AppleGraphicsPolicyClient")
+  (iokit-user-client-class "AppleIntelMEUserClient")
+  (iokit-user-client-class "AppleMGPUPowerControlClient")
+  (iokit-user-client-class "AppleSNBFBUserClient")
+  (iokit-user-client-class "IOAccelerationUserClient")
+  (iokit-user-client-class "IOSurfaceRootUserClient")
+)
+
+(allow ipc-posix-shm-read-data
+  (ipc-posix-name "apple.shm.notification_center"))
+
+(allow sysctl-read
+  (sysctl-name "hw.busfrequency_max")
+  (sysctl-name "hw.cachelinesize")
+  (sysctl-name "hw.logicalcpu_max")
+  (sysctl-name "hw.memsize")
+  (sysctl-name "hw.model")
+  (sysctl-name "kern.osvariant_status")
+)
+
+(allow file-read-data
+  (path "/Library/MessageTracer/SubmitDiagInfo.default.domains.searchtree")
+  (path "/System/Library/MessageTracer/SubmitDiagInfo.default.domains.searchtree")
+  (regex (user-homedir-path #"/Library/Preferences/(.*/)?com\.apple\.driver\..*\.plist"))
+  (regex (user-homedir-path #"/Library/Preferences/ByHost/com.apple.AppleGVA.*"))
+)
+
+(allow file-read*
+  (path (user-homedir-path "/Library/Preferences")) ; List contents of preference directories https://crbug.com/1126350#c14.
+  (path (user-homedir-path "/Library/Preferences/ByHost"))
+  (subpath "/Library/GPUBundles")
+  (subpath "/System/Library/Extensions")  ; https://crbug.com/515280
+)
+
+; crbug.com/980134
+(allow file-read* file-write*
+  (subpath (param darwin-user-cache-dir))
+  (subpath (param darwin-user-dir))
+  (subpath (param darwin-user-temp-dir))
+)
+
+(if (not (maybe-disable-metal-shader-cache))
+  (maybe-allow-metal-shader-cache-access))
+
diff --git a/sandbox/policy/mac/sandbox_mac.mm b/sandbox/policy/mac/sandbox_mac.mm
index 2dd2b99..9f4e6a6 100644
--- a/sandbox/policy/mac/sandbox_mac.mm
+++ b/sandbox/policy/mac/sandbox_mac.mm
@@ -24,6 +24,7 @@
 #include "sandbox/policy/mac/mirroring.sb.h"
 #include "sandbox/policy/mac/nacl_loader.sb.h"
 #include "sandbox/policy/mac/network.sb.h"
+#include "sandbox/policy/mac/on_device_model_execution.sb.h"
 #include "sandbox/policy/mac/ppapi.sb.h"
 #if BUILDFLAG(ENABLE_OOP_PRINTING)
 #include "sandbox/policy/mac/print_backend.sb.h"
@@ -98,8 +99,10 @@
     case sandbox::mojom::Sandbox::kSpeechRecognition:
       profile += kSeatbeltPolicyString_speech_recognition;
       break;
-    // kService and kUtility are the same on OS_MAC, so fallthrough.
     case sandbox::mojom::Sandbox::kOnDeviceModelExecution:
+      profile += kSeatbeltPolicyString_on_device_model_execution;
+      break;
+    // kService and kUtility are the same on OS_MAC, so fallthrough.
     case sandbox::mojom::Sandbox::kService:
     case sandbox::mojom::Sandbox::kServiceWithJit:
     case sandbox::mojom::Sandbox::kUtility:
diff --git a/services/webnn/dml/graph_impl.cc b/services/webnn/dml/graph_impl.cc
index c96e7ce..875765e 100644
--- a/services/webnn/dml/graph_impl.cc
+++ b/services/webnn/dml/graph_impl.cc
@@ -405,6 +405,11 @@
     const mojom::Conv2dPtr& conv2d,
     GraphBuilder& graph_builder,
     IdToNodeOutputMap& id_to_node_output_map) {
+  if (conv2d->type == mojom::Conv2d_Type::kTransposed) {
+    return base::unexpected(
+        mojom::Error::New(mojom::Error::Code::kNotSupportedError,
+                          "Operator convTranspose2d is not supported."));
+  }
   const NodeOutput* input =
       GetNodeOutputForOperand(id_to_node_output_map, conv2d->input_operand_id);
   // The input tensor description may be transposed.
diff --git a/services/webnn/dml/graph_impl_test.cc b/services/webnn/dml/graph_impl_test.cc
index 439bcdf..c1205a4 100644
--- a/services/webnn/dml/graph_impl_test.cc
+++ b/services/webnn/dml/graph_impl_test.cc
@@ -265,6 +265,7 @@
 
 template <typename T>
 struct Conv2dTester {
+  mojom::Conv2d_Type type;
   OperandInfo<T> input;
   OperandInfo<T> filter;
   struct Conv2dAttributes {
@@ -301,8 +302,9 @@
           base::as_bytes(base::make_span(attributes.bias->values)));
     }
 
-    builder.BuildConv2d(input_operand_id, filter_operand_id, output_operand_id,
-                        std::move(attributes), bias_operand_id);
+    builder.BuildConv2d(type, input_operand_id, filter_operand_id,
+                        output_operand_id, std::move(attributes),
+                        bias_operand_id);
 
     base::flat_map<std::string, mojo_base::BigBuffer> named_inputs;
 
@@ -324,6 +326,7 @@
   // fusing with bias.
   {
     Conv2dTester<float>{
+        .type = mojom::Conv2d_Type::kDirect,
         .input = {.type = mojom::Operand::DataType::kFloat32,
                   .dimensions = {1, 1, 5, 5},
                   .values = {0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12,
@@ -348,6 +351,7 @@
   // fusing with bias.
   {
     Conv2dTester<float16>{
+        .type = mojom::Conv2d_Type::kDirect,
         .input = {.type = mojom::Operand::DataType::kFloat16,
                   .dimensions = {1, 1, 5, 5},
                   .values = Float16FromFloat32(
@@ -373,6 +377,7 @@
   // without bias.
   {
     Conv2dTester<float>{
+        .type = mojom::Conv2d_Type::kDirect,
         .input = {.type = mojom::Operand::DataType::kFloat32,
                   .dimensions = {1, 1, 5, 5},
                   .values = {0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12,
@@ -392,6 +397,7 @@
   // without bias.
   {
     Conv2dTester<float>{
+        .type = mojom::Conv2d_Type::kDirect,
         .input = {.type = mojom::Operand::DataType::kFloat32,
                   .dimensions = {1, 5, 5, 1},
                   .values = {0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12,
@@ -413,6 +419,7 @@
   // without bias.
   {
     Conv2dTester<float16>{
+        .type = mojom::Conv2d_Type::kDirect,
         .input = {.type = mojom::Operand::DataType::kFloat16,
                   .dimensions = {1, 5, 5, 1},
                   .values = Float16FromFloat32(
@@ -482,6 +489,7 @@
   // activation.
   {
     Conv2dTester<float>{
+        .type = mojom::Conv2d_Type::kDirect,
         .input = {.type = mojom::Operand::DataType::kFloat32,
                   .dimensions = {1, 5, 5, 1},
                   .values = {0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12,
@@ -507,6 +515,7 @@
   // activation.
   {
     Conv2dTester<float16>{
+        .type = mojom::Conv2d_Type::kDirect,
         .input = {.type = mojom::Operand::DataType::kFloat16,
                   .dimensions = {1, 5, 5, 1},
                   .values = Float16FromFloat32(
diff --git a/services/webnn/public/mojom/webnn_graph.mojom b/services/webnn/public/mojom/webnn_graph.mojom
index ec9ef8e..8c6d472a 100644
--- a/services/webnn/public/mojom/webnn_graph.mojom
+++ b/services/webnn/public/mojom/webnn_graph.mojom
@@ -83,10 +83,23 @@
 
 // Represents a 2-D convolution given the input and filter tensors.
 //
-// Only `oihw` (output_channels, input_channels/groups, height, width) filter
-// layout is supported, other variants are being discussed in the working group
+// * conv2d (Type == kDirect) only supports `oihw` (output_channels,
+//   input_channels/groups, height, width) filter layout
+// * convTranspose2d (Type == kTransposed) only supports `iohw` (input_channels,
+//   output_channels/groups, height, width) filter layout
+// Support for other layouts are being discussed in the working group
 // https://github.com/webmachinelearning/webnn/issues/324.
 struct Conv2d {
+  enum Type {
+    // Represents a 2-D convolution given 4-D input and filter tensors.
+    kDirect,
+    // Represents a 2-D transposed convolution given 4-D input and filter
+    // tensors.
+    kTransposed,
+  };
+
+  // The type of 2-D convolution.
+  Type type;
   // The id of input operand is used to get the `Operand` description from
   // `GraphInfo.id_to_operand_map`.
   uint64 input_operand_id;
diff --git a/services/webnn/webnn_graph_impl.cc b/services/webnn/webnn_graph_impl.cc
index 31d139cc6..e0d312e 100644
--- a/services/webnn/webnn_graph_impl.cc
+++ b/services/webnn/webnn_graph_impl.cc
@@ -151,41 +151,77 @@
   NOTREACHED_NORETURN();
 }
 
-webnn::Conv2dAttributes ConvertToConv2dAttributes(
+const mojom::Operand* GetMojoOperand(const IdToOperandMap& id_to_operand_map,
+                                     uint64_t operand_id) {
+  const auto operand_iterator = id_to_operand_map.find(operand_id);
+  if (operand_iterator == id_to_operand_map.end()) {
+    // There is no operand for the id.
+    return nullptr;
+  }
+  return operand_iterator->second.get();
+}
+
+template <typename Conv2dAttributesType>
+Conv2dAttributesType ConvertToConv2dAttributes(
     const IdToOperandMap& id_to_operand_map,
-    const webnn::mojom::Conv2dPtr& conv2d) {
-  webnn::Conv2dAttributes component_attributes;
+    const webnn::mojom::Conv2dPtr& conv2d,
+    absl::optional<Operand> bias_operand) {
+  Conv2dAttributesType attributes_base;
   // Convert padding, strides, dilations.
   auto& mojo_padding = conv2d->padding;
-  component_attributes.padding = webnn::Padding2d{
+  attributes_base.padding = webnn::Padding2d{
       .beginning =
           webnn::Size2d<uint32_t>{.height = mojo_padding->beginning->height,
                                   .width = mojo_padding->beginning->width},
       .ending = webnn::Size2d<uint32_t>{.height = mojo_padding->ending->height,
                                         .width = mojo_padding->ending->width}};
-  component_attributes.strides = webnn::Size2d<uint32_t>{
+  attributes_base.strides = webnn::Size2d<uint32_t>{
       .height = conv2d->strides->height, .width = conv2d->strides->width};
-  component_attributes.dilations = webnn::Size2d<uint32_t>{
+  attributes_base.dilations = webnn::Size2d<uint32_t>{
       .height = conv2d->dilations->height, .width = conv2d->dilations->width};
 
-  // Convert groups, input and filter layout.
-  component_attributes.groups = conv2d->groups;
-  component_attributes.input_layout =
+  // Convert groups, input layout and bias.
+  attributes_base.groups = conv2d->groups;
+  attributes_base.input_layout =
       MojoInputOperandLayoutToComponent(conv2d->input_layout);
-  // The filter only supports default `Oihw` layout in mojo definition, other
-  // variants are being discussed in WebNN working group:
-  // https://github.com/webmachinelearning/webnn/issues/324.
-  component_attributes.filter_layout = webnn::Conv2dFilterOperandLayout::kOihw;
+  attributes_base.bias_operand = std::move(bias_operand);
 
-  // Convert to componment operand type with bias id.
-  auto& bias_operand_id = conv2d->bias_operand_id;
-  if (bias_operand_id) {
-    const auto bias_operand_iterator =
-        id_to_operand_map.find(bias_operand_id.value());
-    CHECK(bias_operand_iterator != id_to_operand_map.end());
-    component_attributes.bias_operand =
-        ConvertToComponentOperand(bias_operand_iterator->second.get());
+  return std::move(attributes_base);
+}
+
+webnn::Conv2dAttributes ConvertToConv2dAttributes(
+    const IdToOperandMap& id_to_operand_map,
+    const webnn::mojom::Conv2dPtr& conv2d,
+    absl::optional<Operand> bias_operand) {
+  return ConvertToConv2dAttributes<webnn::Conv2dAttributes>(
+      id_to_operand_map, conv2d, std::move(bias_operand));
+}
+
+webnn::ConvTranspose2dAttributes ConvertToConvTranspose2dAttributes(
+    const IdToOperandMap& id_to_operand_map,
+    const webnn::mojom::Conv2dPtr& conv2d,
+    absl::optional<Operand> bias_operand) {
+  auto component_attributes =
+      ConvertToConv2dAttributes<webnn::ConvTranspose2dAttributes>(
+          id_to_operand_map, conv2d, std::move(bias_operand));
+
+  // Convert the output sizes that fetched from dimensions of output operand.
+  auto* output = GetMojoOperand(id_to_operand_map, conv2d->output_operand_id);
+  CHECK_EQ(output->dimensions.size(), 4u);
+  webnn::Size2d<uint32_t> output_sizes;
+  switch (conv2d->input_layout) {
+    case webnn::mojom::InputOperandLayout::kChannelsFirst:
+      // "channelsFirst": [batches, input_channels, height, width]
+      output_sizes.height = output->dimensions[2];
+      output_sizes.width = output->dimensions[3];
+      break;
+    case webnn::mojom::InputOperandLayout::kChannelsLast:
+      // "channelsLast": [batches, height, width, input_channels]
+      output_sizes.height = output->dimensions[1];
+      output_sizes.width = output->dimensions[2];
+      break;
   }
+  component_attributes.output_sizes = std::move(output_sizes);
 
   return component_attributes;
 }
@@ -253,23 +289,26 @@
   return component_attributes;
 }
 
-const mojom::Operand* GetMojoOperand(const IdToOperandMap& id_to_operand_map,
-                                     uint64_t operand_id) {
-  const auto operand_iterator = id_to_operand_map.find(operand_id);
-  if (operand_iterator == id_to_operand_map.end()) {
-    // There is no operand for the id.
-    return nullptr;
-  }
-  return operand_iterator->second.get();
-}
-
-bool ValidateUnaryOperation(const mojom::Operand* input,
-                            const mojom::Operand* output) {
+template <typename Operation>
+bool ValidateUnaryOperation(
+    const IdToOperandMap& id_to_operand_map,
+    const Operation& operation,
+    const webnn::DataTypeConstraintSet& input_constraint) {
+  const auto* input =
+      GetMojoOperand(id_to_operand_map, operation->input_operand_id);
+  const auto* output =
+      GetMojoOperand(id_to_operand_map, operation->output_operand_id);
   if (!input || !output || output == input) {
     // The unary operator is invalid.
     return false;
   }
-  if (output->data_type != input->data_type) {
+
+  const auto input_data_type = input->data_type;
+  if (!input_constraint.Has(MojoOperandTypeToComponent(input_data_type))) {
+    // The data type is not in the constraint.
+    return false;
+  }
+  if (output->data_type != input_data_type) {
     // The output data type doesn't match input data type.
     return false;
   }
@@ -280,36 +319,10 @@
   return true;
 }
 
-template <typename Operation>
-bool ValidateUnaryOperation(const IdToOperandMap& id_to_operand_map,
-                            const Operation& operation) {
-  auto* input = GetMojoOperand(id_to_operand_map, operation->input_operand_id);
-  auto* output =
-      GetMojoOperand(id_to_operand_map, operation->output_operand_id);
-  return ValidateUnaryOperation(input, output);
-}
-
-template <typename Operation>
-bool ValidateFloatingPointUnaryOperation(
-    const IdToOperandMap& id_to_operand_map,
-    const Operation& operation) {
-  auto* input = GetMojoOperand(id_to_operand_map, operation->input_operand_id);
-  auto* output =
-      GetMojoOperand(id_to_operand_map, operation->output_operand_id);
-  if (!ValidateUnaryOperation(input, output)) {
-    return false;
-  }
-
-  if (!IsFloatingPointType(MojoOperandTypeToComponent(input->data_type))) {
-    return false;
-  }
-
-  return true;
-}
-
 bool ValidateClamp(const IdToOperandMap& id_to_operand_map,
                    const mojom::ClampPtr& clamp) {
-  if (!ValidateUnaryOperation(id_to_operand_map, clamp)) {
+  if (!ValidateUnaryOperation(id_to_operand_map, clamp,
+                              DataTypeConstraintSet::All())) {
     return false;
   }
   if (!ValidateClampAttributes(clamp)) {
@@ -357,21 +370,49 @@
     // The conv2d operator is invalid.
     return false;
   }
-  auto& bias_operand_id = conv2d->bias_operand_id;
-  if (bias_operand_id && !id_to_operand_map.contains(bias_operand_id.value())) {
-    // Invalid bias operand.
+  if (output->dimensions.size() != 4) {
+    // The element of output dimensions should be 4.
     return false;
   }
 
+  absl::optional<webnn::Operand> bias_operand;
+  auto& bias_operand_id = conv2d->bias_operand_id;
+  if (bias_operand_id) {
+    const auto bias_operand_iterator =
+        id_to_operand_map.find(bias_operand_id.value());
+    if (bias_operand_iterator == id_to_operand_map.end()) {
+      // Invalid bias operand.
+      return false;
+    }
+    bias_operand =
+        ConvertToComponentOperand(bias_operand_iterator->second.get());
+  }
+
   // Validate the activation if the option is configured.
   auto& activation = conv2d->activation;
   if (activation && !ValidateActivation(activation)) {
     // The activation is invalid.
     return false;
   }
-  auto validated_output = ValidateConv2dAndInferOutput(
-      ConvertToComponentOperand(input), ConvertToComponentOperand(filter),
-      ConvertToConv2dAttributes(id_to_operand_map, conv2d));
+
+  absl::optional<base::expected<Operand, std::string>> validated_output;
+  switch (conv2d->type) {
+    case mojom::Conv2d_Type::kDirect: {
+      validated_output = ValidateConv2dAndInferOutput(
+          ConvertToComponentOperand(input), ConvertToComponentOperand(filter),
+          ConvertToConv2dAttributes(id_to_operand_map, conv2d,
+                                    std::move(bias_operand)));
+      break;
+    }
+
+    case mojom::Conv2d_Type::kTransposed: {
+      validated_output = ValidateConvTranspose2dAndInferOutput(
+          ConvertToComponentOperand(input), ConvertToComponentOperand(filter),
+          ConvertToConvTranspose2dAttributes(id_to_operand_map, conv2d,
+                                             std::move(bias_operand)));
+      break;
+    }
+  }
   if (!validated_output.has_value()) {
     return false;
   }
@@ -410,7 +451,8 @@
 
 bool ValidateElu(const IdToOperandMap& id_to_operand_map,
                  const mojom::EluPtr& elu) {
-  if (!ValidateFloatingPointUnaryOperation(id_to_operand_map, elu)) {
+  if (!ValidateUnaryOperation(id_to_operand_map, elu,
+                              DataTypeConstraint::kFloat)) {
     return false;
   }
   if (!ValidateEluAttributes(elu)) {
@@ -425,18 +467,13 @@
   switch (operation->kind) {
     case mojom::ElementWiseUnary::Kind::kLogicalNot: {
       // Only uint8 is supported
-      auto* input =
-          GetMojoOperand(id_to_operand_map, operation->input_operand_id);
-      auto* output =
-          GetMojoOperand(id_to_operand_map, operation->output_operand_id);
-      if (ValidateUnaryOperation(input, output)) {
-        return input->data_type == mojom::Operand::DataType::kUint8;
-      }
-      return false;
+      return ValidateUnaryOperation(id_to_operand_map, operation,
+                                    {Operand::DataType::kUint8});
     }
     case mojom::ElementWiseUnary::Kind::kIdentity: {
       // All data types are supported
-      return ValidateUnaryOperation(id_to_operand_map, operation);
+      return ValidateUnaryOperation(id_to_operand_map, operation,
+                                    DataTypeConstraintSet::All());
     }
     case mojom::ElementWiseUnary::Kind::kSqrt:
       [[fallthrough]];
@@ -444,7 +481,8 @@
       [[fallthrough]];
     case mojom::ElementWiseUnary::Kind::kReciprocal: {
       // Only float data type is supported
-      return ValidateFloatingPointUnaryOperation(id_to_operand_map, operation);
+      return ValidateUnaryOperation(id_to_operand_map, operation,
+                                    DataTypeConstraint::kFloat);
     }
   }
   return false;
@@ -479,7 +517,8 @@
 
 bool ValidateLeakyRelu(const IdToOperandMap& id_to_operand_map,
                        const mojom::LeakyReluPtr& leaky_relu) {
-  if (!ValidateFloatingPointUnaryOperation(id_to_operand_map, leaky_relu)) {
+  if (!ValidateUnaryOperation(id_to_operand_map, leaky_relu,
+                              DataTypeConstraint::kFloat)) {
     return false;
   }
   if (!ValidateLeakyReluAttributes(leaky_relu)) {
@@ -835,19 +874,20 @@
     case mojom::Operation::Tag::kReshape:
       return ValidateReshape(id_to_operand_map, operation->get_reshape());
     case mojom::Operation::Tag::kRelu:
-      return ValidateUnaryOperation(id_to_operand_map, operation->get_relu());
+      return ValidateUnaryOperation(id_to_operand_map, operation->get_relu(),
+                                    DataTypeConstraintSet::All());
     case mojom::Operation::Tag::kSlice:
       return ValidateSlice(id_to_operand_map, operation->get_slice());
     case mojom::Operation::Tag::kSigmoid:
-      return ValidateFloatingPointUnaryOperation(id_to_operand_map,
-                                                 operation->get_sigmoid());
+      return ValidateUnaryOperation(id_to_operand_map, operation->get_sigmoid(),
+                                    DataTypeConstraint::kFloat);
     case mojom::Operation::Tag::kSoftmax:
       return ValidateSoftmax(id_to_operand_map, operation->get_softmax());
     case mojom::Operation::Tag::kSplit:
       return ValidateSplit(id_to_operand_map, operation->get_split());
     case mojom::Operation::Tag::kTanh:
-      return ValidateFloatingPointUnaryOperation(id_to_operand_map,
-                                                 operation->get_tanh());
+      return ValidateUnaryOperation(id_to_operand_map, operation->get_tanh(),
+                                    DataTypeConstraint::kFloat);
     case mojom::Operation::Tag::kTranspose:
       return ValidateTranspose(id_to_operand_map, operation->get_transpose());
   }
diff --git a/services/webnn/webnn_graph_impl_unittest.cc b/services/webnn/webnn_graph_impl_unittest.cc
index aa54069..feafe1f 100644
--- a/services/webnn/webnn_graph_impl_unittest.cc
+++ b/services/webnn/webnn_graph_impl_unittest.cc
@@ -440,6 +440,7 @@
 }
 
 struct Conv2dTester {
+  mojom::Conv2d_Type type;
   OperandInfo input;
   OperandInfo filter;
   struct Conv2dAttributes {
@@ -475,8 +476,9 @@
 
     uint64_t output_operand_id =
         builder.BuildOutput("output", output.dimensions, output.type);
-    builder.BuildConv2d(input_operand_id, filter_operand_id, output_operand_id,
-                        std::move(attributes), bias_operand_id);
+    builder.BuildConv2d(type, input_operand_id, filter_operand_id,
+                        output_operand_id, std::move(attributes),
+                        bias_operand_id);
     EXPECT_EQ(WebNNGraphImpl::ValidateGraph(builder.GetGraphInfo()), expected);
   }
 };
@@ -484,7 +486,8 @@
 TEST_F(WebNNGraphImplTest, Conv2dTest) {
   {
     // Test conv2d with default attributes.
-    Conv2dTester{.input = {.type = mojom::Operand::DataType::kFloat32,
+    Conv2dTester{.type = mojom::Conv2d_Type::kDirect,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
                            .dimensions = {1, 1, 5, 5}},
                  .filter = {.type = mojom::Operand::DataType::kFloat32,
                             .dimensions = {1, 1, 3, 3}},
@@ -495,7 +498,8 @@
   }
   {
     // Test conv2d for same upper or lower padding.
-    Conv2dTester{.input = {.type = mojom::Operand::DataType::kInt8,
+    Conv2dTester{.type = mojom::Conv2d_Type::kDirect,
+                 .input = {.type = mojom::Operand::DataType::kInt8,
                            .dimensions = {1, 1, 5, 5}},
                  .filter = {.type = mojom::Operand::DataType::kInt8,
                             .dimensions = {1, 1, 3, 3}},
@@ -507,7 +511,8 @@
   }
   {
     // Test conv2d with strides=2 and padding=1.
-    Conv2dTester{.input = {.type = mojom::Operand::DataType::kInt8,
+    Conv2dTester{.type = mojom::Conv2d_Type::kDirect,
+                 .input = {.type = mojom::Operand::DataType::kInt8,
                            .dimensions = {1, 1, 5, 5}},
                  .filter = {.type = mojom::Operand::DataType::kInt8,
                             .dimensions = {1, 1, 3, 3}},
@@ -519,7 +524,8 @@
   }
   {
     // Test depthwise conv2d by setting groups to input channels.
-    Conv2dTester{.input = {.type = mojom::Operand::DataType::kInt8,
+    Conv2dTester{.type = mojom::Conv2d_Type::kDirect,
+                 .input = {.type = mojom::Operand::DataType::kInt8,
                            .dimensions = {1, 4, 2, 2}},
                  .filter = {.type = mojom::Operand::DataType::kInt8,
                             .dimensions = {4, 1, 2, 2}},
@@ -531,7 +537,8 @@
   }
   {
     // Test conv2d with inputLayout="nchw" and filterLayout="oihw".
-    Conv2dTester{.input = {.type = mojom::Operand::DataType::kInt8,
+    Conv2dTester{.type = mojom::Conv2d_Type::kDirect,
+                 .input = {.type = mojom::Operand::DataType::kInt8,
                            .dimensions = {1, 2, 5, 5}},
                  .filter = {.type = mojom::Operand::DataType::kInt8,
                             .dimensions = {1, 2, 3, 3}},
@@ -544,7 +551,8 @@
   }
   {
     // Test conv2d with clamp activation.
-    Conv2dTester{.input = {.type = mojom::Operand::DataType::kFloat32,
+    Conv2dTester{.type = mojom::Conv2d_Type::kDirect,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
                            .dimensions = {1, 1, 5, 5}},
                  .filter = {.type = mojom::Operand::DataType::kFloat32,
                             .dimensions = {1, 1, 3, 3}},
@@ -586,7 +594,8 @@
   }
   {
     // Test conv2d with relu activation.
-    Conv2dTester{.input = {.type = mojom::Operand::DataType::kFloat32,
+    Conv2dTester{.type = mojom::Conv2d_Type::kDirect,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
                            .dimensions = {1, 1, 5, 5}},
                  .filter = {.type = mojom::Operand::DataType::kFloat32,
                             .dimensions = {1, 1, 3, 3}},
@@ -598,7 +607,8 @@
   }
   {
     // Test conv2d with sigmoid activation.
-    Conv2dTester{.input = {.type = mojom::Operand::DataType::kFloat32,
+    Conv2dTester{.type = mojom::Conv2d_Type::kDirect,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
                            .dimensions = {1, 1, 5, 5}},
                  .filter = {.type = mojom::Operand::DataType::kFloat32,
                             .dimensions = {1, 1, 3, 3}},
@@ -610,7 +620,8 @@
   }
   {
     // Test conv2d with softmax activation.
-    Conv2dTester{.input = {.type = mojom::Operand::DataType::kFloat32,
+    Conv2dTester{.type = mojom::Conv2d_Type::kDirect,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
                            .dimensions = {1, 1, 5, 5}},
                  .filter = {.type = mojom::Operand::DataType::kFloat32,
                             .dimensions = {1, 1, 3, 3}},
@@ -622,7 +633,8 @@
   }
   {
     // Test conv2d with tanh activation.
-    Conv2dTester{.input = {.type = mojom::Operand::DataType::kFloat32,
+    Conv2dTester{.type = mojom::Conv2d_Type::kDirect,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
                            .dimensions = {1, 1, 5, 5}},
                  .filter = {.type = mojom::Operand::DataType::kFloat32,
                             .dimensions = {1, 1, 3, 3}},
@@ -647,7 +659,8 @@
   }
   {
     // Test the invalid graph when the input is not a 4-D tensor.
-    Conv2dTester{.input = {.type = mojom::Operand::DataType::kFloat32,
+    Conv2dTester{.type = mojom::Conv2d_Type::kDirect,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
                            .dimensions = {1, 5, 5}},
                  .filter = {.type = mojom::Operand::DataType::kFloat32,
                             .dimensions = {1, 1, 3, 3}},
@@ -658,7 +671,8 @@
   }
   {
     // Test the invalid graph when the filter is not a 4-D tensor.
-    Conv2dTester{.input = {.type = mojom::Operand::DataType::kFloat32,
+    Conv2dTester{.type = mojom::Conv2d_Type::kDirect,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
                            .dimensions = {1, 1, 5, 5}},
                  .filter = {.type = mojom::Operand::DataType::kFloat32,
                             .dimensions = {1, 3, 3}},
@@ -670,7 +684,8 @@
   {
     // Test the invalid graph when the filter type doesn't match the input
     // type.
-    Conv2dTester{.input = {.type = mojom::Operand::DataType::kFloat32,
+    Conv2dTester{.type = mojom::Conv2d_Type::kDirect,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
                            .dimensions = {1, 1, 5, 5}},
                  .filter = {.type = mojom::Operand::DataType::kInt32,
                             .dimensions = {1, 1, 3, 3}},
@@ -682,6 +697,7 @@
   {
     // Test the invalid graph when the bias type doesn't match input type.
     Conv2dTester{
+        .type = mojom::Conv2d_Type::kDirect,
         .input = {.type = mojom::Operand::DataType::kFloat32,
                   .dimensions = {1, 1, 5, 5}},
         .filter = {.type = mojom::Operand::DataType::kFloat32,
@@ -698,6 +714,7 @@
     // Test the invalid graph when the bias shape is not equal to
     // [output_channels].
     Conv2dTester{
+        .type = mojom::Conv2d_Type::kDirect,
         .input = {.type = mojom::Operand::DataType::kFloat32,
                   .dimensions = {1, 1, 5, 5}},
         .filter = {.type = mojom::Operand::DataType::kFloat32,
@@ -712,8 +729,23 @@
         .Test();
   }
   {
+    // Test the invalid graph when the number of filter input channels doesn't
+    // match the result of input channels divided by groups
+    Conv2dTester{.type = mojom::Conv2d_Type::kDirect,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
+                           .dimensions = {1, 1, 5, 5}},
+                 .filter = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 3, 3}},
+                 .attributes = {.groups = 3},
+                 .output = {.type = mojom::Operand::DataType::kInt32,
+                            .dimensions = {1, 1, 3, 3}},
+                 .expected = false}
+        .Test();
+  }
+  {
     // Test the invalid graph when the max value is less than the min value.
-    Conv2dTester{.input = {.type = mojom::Operand::DataType::kFloat32,
+    Conv2dTester{.type = mojom::Conv2d_Type::kDirect,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
                            .dimensions = {1, 1, 5, 5}},
                  .filter = {.type = mojom::Operand::DataType::kFloat32,
                             .dimensions = {1, 1, 3, 3}},
@@ -728,7 +760,8 @@
   }
   {
     // Test the invalid graph for the output shapes are not expected.
-    Conv2dTester{.input = {.type = mojom::Operand::DataType::kFloat32,
+    Conv2dTester{.type = mojom::Conv2d_Type::kDirect,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
                            .dimensions = {1, 1, 5, 5}},
                  .filter = {.type = mojom::Operand::DataType::kFloat32,
                             .dimensions = {1, 1, 3, 3}},
@@ -739,7 +772,8 @@
   }
   {
     // Test the invalid graph for output types don't match.
-    Conv2dTester{.input = {.type = mojom::Operand::DataType::kFloat32,
+    Conv2dTester{.type = mojom::Conv2d_Type::kDirect,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
                            .dimensions = {1, 1, 5, 5}},
                  .filter = {.type = mojom::Operand::DataType::kFloat32,
                             .dimensions = {1, 1, 3, 3}},
@@ -748,6 +782,338 @@
                  .expected = false}
         .Test();
   }
+  {
+    // Test the invalid graph for input operand == output operand.
+    GraphInfoBuilder builder;
+    uint64_t input_operand_id = builder.BuildInput(
+        "input", {1, 1, 5, 5}, mojom::Operand::DataType::kFloat32);
+    uint64_t filter_operand_id = builder.BuildInput(
+        "filter", {1, 1, 3, 3}, mojom::Operand::DataType::kFloat32);
+
+    builder.BuildConv2d(mojom::Conv2d_Type::kDirect, input_operand_id,
+                        filter_operand_id, input_operand_id,
+                        Conv2dTester::Conv2dAttributes{}, absl::nullopt);
+
+    EXPECT_FALSE(WebNNGraphImpl::ValidateGraph(builder.GetGraphInfo()));
+  }
+  {
+    // Test the invalid graph for filter operand == output operand.
+    GraphInfoBuilder builder;
+    uint64_t input_operand_id = builder.BuildInput(
+        "input", {1, 1, 5, 5}, mojom::Operand::DataType::kFloat32);
+    uint64_t filter_operand_id = builder.BuildInput(
+        "filter", {1, 1, 3, 3}, mojom::Operand::DataType::kFloat32);
+
+    builder.BuildConv2d(mojom::Conv2d_Type::kDirect, input_operand_id,
+                        filter_operand_id, filter_operand_id,
+                        Conv2dTester::Conv2dAttributes{}, absl::nullopt);
+
+    EXPECT_FALSE(WebNNGraphImpl::ValidateGraph(builder.GetGraphInfo()));
+  }
+}
+
+TEST_F(WebNNGraphImplTest, ConvTranspose2dTest) {
+  {
+    // Test convTranspose2d with default attributes.
+    Conv2dTester{.type = mojom::Conv2d_Type::kTransposed,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
+                           .dimensions = {1, 1, 3, 3}},
+                 .filter = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 3, 3}},
+                 .output = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 5, 5}},
+                 .expected = true}
+        .Test();
+  }
+  {
+    // Test convTranspose2d with input_layout = kChannelsLast.
+    Conv2dTester{.type = mojom::Conv2d_Type::kTransposed,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
+                           .dimensions = {1, 3, 3, 1}},
+                 .filter = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 3, 3}},
+                 .attributes = {.input_layout =
+                                    mojom::InputOperandLayout::kChannelsLast},
+                 .output = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 5, 5, 1}},
+                 .expected = true}
+        .Test();
+  }
+  {
+    // Test convTranspose2d with padding = [1, 1, 1, 1].
+    Conv2dTester{.type = mojom::Conv2d_Type::kTransposed,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
+                           .dimensions = {1, 1, 5, 5}},
+                 .filter = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 3, 3}},
+                 .attributes = {.padding = {1, 1, 1, 1}},
+                 .output = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 5, 5}},
+                 .expected = true}
+        .Test();
+  }
+  {
+    // Test convTranspose2d with strides = [2, 2].
+    Conv2dTester{.type = mojom::Conv2d_Type::kTransposed,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
+                           .dimensions = {1, 1, 3, 3}},
+                 .filter = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 2, 3, 3}},
+                 .attributes = {.strides = {2, 2}},
+                 .output = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 2, 7, 7}},
+                 .expected = true}
+        .Test();
+  }
+  {
+    // Test convTranspose2d with strides = [2, 2] and padding = [1, 1, 1, 1].
+    Conv2dTester{.type = mojom::Conv2d_Type::kTransposed,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
+                           .dimensions = {1, 1, 3, 3}},
+                 .filter = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 3, 3}},
+                 .attributes = {.padding = {1, 1, 1, 1}, .strides = {2, 2}},
+                 .output = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 5, 5}},
+                 .expected = true}
+        .Test();
+  }
+  {
+    // Test convTranspose2d with group = 3.
+    Conv2dTester{.type = mojom::Conv2d_Type::kTransposed,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
+                           .dimensions = {1, 1, 3, 3}},
+                 .filter = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 3, 3}},
+                 .attributes = {.groups = 3},
+                 .output = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 3, 5, 5}},
+                 .expected = true}
+        .Test();
+  }
+  {
+    // Test convTranspose2d with clamp activation.
+    Conv2dTester{.type = mojom::Conv2d_Type::kTransposed,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
+                           .dimensions = {1, 1, 3, 3}},
+                 .filter = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 3, 3}},
+                 .attributes = {.activation = mojom::Activation::Tag::kClamp,
+                                .clamp_attributes =
+                                    ClampTester::ClampAttributes{
+                                        .min_value = 1.0, .max_value = 6.0}},
+                 .output = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 5, 5}},
+                 .expected = true}
+        .Test();
+  }
+  {
+    // Test convTranspose2d with relu activation.
+    Conv2dTester{.type = mojom::Conv2d_Type::kTransposed,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
+                           .dimensions = {1, 1, 3, 3}},
+                 .filter = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 3, 3}},
+                 .attributes = {.activation = mojom::Activation::Tag::kRelu},
+                 .output = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 5, 5}},
+                 .expected = true}
+        .Test();
+  }
+  {
+    // Test convTranspose2d with sigmoid activation.
+    Conv2dTester{.type = mojom::Conv2d_Type::kTransposed,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
+                           .dimensions = {1, 1, 3, 3}},
+                 .filter = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 3, 3}},
+                 .attributes = {.activation = mojom::Activation::Tag::kSigmoid},
+                 .output = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 5, 5}},
+                 .expected = true}
+        .Test();
+  }
+  {
+    // Test convTranspose2d with softmax activation.
+    Conv2dTester{.type = mojom::Conv2d_Type::kTransposed,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
+                           .dimensions = {1, 1, 3, 3}},
+                 .filter = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 3, 3}},
+                 .attributes = {.activation = mojom::Activation::Tag::kSoftmax},
+                 .output = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 5, 5}},
+                 .expected = true}
+        .Test();
+  }
+  {
+    // Test convTranspose2d with tanh activation.
+    Conv2dTester{.type = mojom::Conv2d_Type::kTransposed,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
+                           .dimensions = {1, 1, 3, 3}},
+                 .filter = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 3, 3}},
+                 .attributes = {.activation = mojom::Activation::Tag::kTanh},
+                 .output = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 5, 5}},
+                 .expected = true}
+        .Test();
+  }
+  {
+    // Test the invalid graph for output types don't match.
+    Conv2dTester{.type = mojom::Conv2d_Type::kTransposed,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
+                           .dimensions = {1, 1, 5, 5}},
+                 .filter = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 3, 3}},
+                 .output = {.type = mojom::Operand::DataType::kInt32,
+                            .dimensions = {1, 1, 3, 3}},
+                 .expected = false}
+        .Test();
+  }
+  {
+    // Test the invalid graph for the input is not a 4-D tensor.
+    Conv2dTester{.type = mojom::Conv2d_Type::kTransposed,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
+                           .dimensions = {1, 3, 3}},
+                 .filter = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 3, 3}},
+                 .output = {.type = mojom::Operand::DataType::kInt32,
+                            .dimensions = {1, 1, 5, 5}},
+                 .expected = false}
+        .Test();
+  }
+  {
+    // Test the invalid graph for the filter is not a 4-D tensor.
+    Conv2dTester{.type = mojom::Conv2d_Type::kTransposed,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
+                           .dimensions = {1, 1, 3, 3}},
+                 .filter = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 3, 3}},
+                 .output = {.type = mojom::Operand::DataType::kInt32,
+                            .dimensions = {1, 1, 5, 5}},
+                 .expected = false}
+        .Test();
+  }
+  {
+    // Test the invalid graph when the number of input channels is not equal to
+    // the number of filter input channels.
+    Conv2dTester{.type = mojom::Conv2d_Type::kTransposed,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
+                           .dimensions = {1, 1, 3, 3}},
+                 .filter = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {3, 1, 3, 3}},
+                 .attributes = {.groups = 3},
+                 .output = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 3, 5, 5}},
+                 .expected = false}
+        .Test();
+  }
+  {
+    // Test the invalid graph when the number of output channels doesn't match
+    // the result of filter output channels multiplied by groups
+    Conv2dTester{.type = mojom::Conv2d_Type::kTransposed,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
+                           .dimensions = {1, 1, 3, 3}},
+                 .filter = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 3, 3}},
+                 .attributes = {.groups = 3},
+                 .output = {.type = mojom::Operand::DataType::kInt32,
+                            .dimensions = {1, 1, 5, 5}},
+                 .expected = false}
+        .Test();
+  }
+  {
+    // Test the invalid graph when the filter type doesn't match the input
+    // type.
+    Conv2dTester{.type = mojom::Conv2d_Type::kTransposed,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
+                           .dimensions = {1, 1, 3, 3}},
+                 .filter = {.type = mojom::Operand::DataType::kInt32,
+                            .dimensions = {1, 1, 3, 3}},
+                 .output = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 5, 5}},
+                 .expected = false}
+        .Test();
+  }
+  {
+    // Test the invalid graph when the bias type doesn't match input type.
+    Conv2dTester{
+        .type = mojom::Conv2d_Type::kTransposed,
+        .input = {.type = mojom::Operand::DataType::kFloat32,
+                  .dimensions = {1, 1, 3, 3}},
+        .filter = {.type = mojom::Operand::DataType::kFloat32,
+                   .dimensions = {1, 1, 3, 3}},
+        .attributes = {.bias =
+                           OperandInfo{.type = mojom::Operand::DataType::kInt32,
+                                       .dimensions = {1}}},
+        .output = {.type = mojom::Operand::DataType::kFloat32,
+                   .dimensions = {1, 1, 5, 5}},
+        .expected = false}
+        .Test();
+  }
+  {
+    // Test the invalid graph when the bias shape is not equal to
+    // [output_channels].
+    Conv2dTester{
+        .type = mojom::Conv2d_Type::kTransposed,
+        .input = {.type = mojom::Operand::DataType::kFloat32,
+                  .dimensions = {1, 1, 3, 3}},
+        .filter = {.type = mojom::Operand::DataType::kFloat32,
+                   .dimensions = {1, 1, 3, 3}},
+        .attributes = {.bias =
+                           OperandInfo{
+                               .type = mojom::Operand::DataType::kFloat32,
+                               .dimensions = {2}}},
+        .output = {.type = mojom::Operand::DataType::kFloat32,
+                   .dimensions = {1, 1, 5, 5}},
+        .expected = false}
+        .Test();
+  }
+  {
+    // Test the invalid graph when the max value is less than the min value.
+    Conv2dTester{.type = mojom::Conv2d_Type::kTransposed,
+                 .input = {.type = mojom::Operand::DataType::kFloat32,
+                           .dimensions = {1, 1, 3, 3}},
+                 .filter = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 3, 3}},
+                 .attributes = {.activation = mojom::Activation::Tag::kClamp,
+                                .clamp_attributes =
+                                    ClampTester::ClampAttributes{
+                                        .min_value = 6.0, .max_value = 1.0}},
+                 .output = {.type = mojom::Operand::DataType::kFloat32,
+                            .dimensions = {1, 1, 5, 5}},
+                 .expected = false}
+        .Test();
+  }
+  {
+    // Test the invalid graph for input operand == output operand.
+    GraphInfoBuilder builder;
+    uint64_t input_operand_id = builder.BuildInput(
+        "input", {1, 1, 3, 3}, mojom::Operand::DataType::kFloat32);
+    uint64_t filter_operand_id = builder.BuildInput(
+        "filter", {1, 1, 3, 3}, mojom::Operand::DataType::kFloat32);
+
+    builder.BuildConv2d(mojom::Conv2d_Type::kTransposed, input_operand_id,
+                        filter_operand_id, input_operand_id,
+                        Conv2dTester::Conv2dAttributes{}, absl::nullopt);
+
+    EXPECT_FALSE(WebNNGraphImpl::ValidateGraph(builder.GetGraphInfo()));
+  }
+  {
+    // Test the invalid graph for filter operand == output operand.
+    GraphInfoBuilder builder;
+    uint64_t input_operand_id = builder.BuildInput(
+        "input", {1, 1, 3, 3}, mojom::Operand::DataType::kFloat32);
+    uint64_t filter_operand_id = builder.BuildInput(
+        "filter", {1, 1, 3, 3}, mojom::Operand::DataType::kFloat32);
+
+    builder.BuildConv2d(mojom::Conv2d_Type::kTransposed, input_operand_id,
+                        filter_operand_id, filter_operand_id,
+                        Conv2dTester::Conv2dAttributes{}, absl::nullopt);
+
+    EXPECT_FALSE(WebNNGraphImpl::ValidateGraph(builder.GetGraphInfo()));
+  }
 }
 
 struct ElementWiseBinaryTester {
diff --git a/services/webnn/webnn_test_utils.h b/services/webnn/webnn_test_utils.h
index 8e75958..d5d1b79 100644
--- a/services/webnn/webnn_test_utils.h
+++ b/services/webnn/webnn_test_utils.h
@@ -62,7 +62,8 @@
   //   absl::optional<float> leaky_relu_alpha;
   // };
   template <typename Conv2dAttributes>
-  void BuildConv2d(uint64_t input_operand_id,
+  void BuildConv2d(mojom::Conv2d_Type type,
+                   uint64_t input_operand_id,
                    uint64_t filter_operand_id,
                    uint64_t output_operand_id,
                    const Conv2dAttributes& attributes,
@@ -73,6 +74,7 @@
     conv2d->output_operand_id = output_operand_id;
 
     // Configure the attributes of conv2d.
+    conv2d->type = type;
     CHECK_EQ(attributes.padding.size(), 4u);
     conv2d->padding = mojom::Padding2d::New(
         /*beginning padding*/ mojom::Size2d::New(attributes.padding[0],
@@ -216,10 +218,10 @@
         mojom::Size2d::New(window_dimensions[0], window_dimensions[1]);
     CHECK_EQ(attributes.padding.size(), 4u);
     pool2d->padding = mojom::Padding2d::New(
-        /* beginning padding*/ mojom::Size2d::New(attributes.padding[0],
-                                                  attributes.padding[2]),
-        /* ending padding*/ mojom::Size2d::New(attributes.padding[1],
-                                               attributes.padding[3]));
+        /*beginning padding*/ mojom::Size2d::New(attributes.padding[0],
+                                                 attributes.padding[2]),
+        /*ending padding*/ mojom::Size2d::New(attributes.padding[1],
+                                              attributes.padding[3]));
     CHECK_EQ(attributes.strides.size(), 2u);
     pool2d->strides =
         mojom::Size2d::New(attributes.strides[0], attributes.strides[1]);
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 07d7b416..7b84ddf 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -2171,7 +2171,7 @@
         "bucket": "chromiumos-image-archive",
         "ci_only": true,
         "cros_board": "volteer",
-        "cros_img": "volteer-public/R121-15672.0.0",
+        "cros_img": "volteer-public/R121-15673.0.0",
         "cros_model": "voxel",
         "dut_pool": "chromium",
         "name": "chromeos_integration_tests VOLTEER_PUBLIC_LKGM",
@@ -2185,7 +2185,7 @@
         "autotest_name": "tast.lacros-from-gcs",
         "bucket": "chromiumos-image-archive",
         "cros_board": "volteer",
-        "cros_img": "volteer-public/R121-15672.0.0",
+        "cros_img": "volteer-public/R121-15673.0.0",
         "cros_model": "voxel",
         "dut_pool": "chromium",
         "name": "lacros_all_tast_tests VOLTEER_PUBLIC_LKGM",
@@ -2530,7 +2530,7 @@
         "autotest_name": "chromium",
         "bucket": "chromiumos-image-archive",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-public/R121-15672.0.0",
+        "cros_img": "jacuzzi-public/R121-15673.0.0",
         "name": "chromeos_integration_tests JACUZZI_PUBLIC_LKGM",
         "test": "chromeos_integration_tests",
         "test_id_prefix": "ninja://chrome/test:chromeos_integration_tests/",
@@ -2540,7 +2540,7 @@
         "autotest_name": "tast.lacros-from-gcs",
         "bucket": "chromiumos-image-archive",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-public/R121-15672.0.0",
+        "cros_img": "jacuzzi-public/R121-15673.0.0",
         "name": "lacros_all_tast_tests JACUZZI_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -2570,7 +2570,7 @@
         "autotest_name": "tast.lacros-from-gcs",
         "bucket": "chromiumos-image-archive",
         "cros_board": "trogdor",
-        "cros_img": "trogdor-public/R121-15672.0.0",
+        "cros_img": "trogdor-public/R121-15673.0.0",
         "name": "lacros_all_tast_tests TROGDOR_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -6097,9 +6097,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6118.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6119.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 121.0.6118.0",
+        "description": "Run with ash-chrome version 121.0.6119.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -6109,8 +6109,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v121.0.6118.0",
-              "revision": "version:121.0.6118.0"
+              "location": "lacros_version_skew_tests_v121.0.6119.0",
+              "revision": "version:121.0.6119.0"
             }
           ],
           "dimensions": {
@@ -6247,9 +6247,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6118.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6119.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 121.0.6118.0",
+        "description": "Run with ash-chrome version 121.0.6119.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -6259,8 +6259,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v121.0.6118.0",
-              "revision": "version:121.0.6118.0"
+              "location": "lacros_version_skew_tests_v121.0.6119.0",
+              "revision": "version:121.0.6119.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json
index 05eaffd..dda97f42 100644
--- a/testing/buildbot/chromium.coverage.json
+++ b/testing/buildbot/chromium.coverage.json
@@ -20451,9 +20451,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6118.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6119.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 121.0.6118.0",
+        "description": "Run with ash-chrome version 121.0.6119.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -20463,8 +20463,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v121.0.6118.0",
-              "revision": "version:121.0.6118.0"
+              "location": "lacros_version_skew_tests_v121.0.6119.0",
+              "revision": "version:121.0.6119.0"
             }
           ],
           "dimensions": {
@@ -20601,9 +20601,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6118.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6119.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 121.0.6118.0",
+        "description": "Run with ash-chrome version 121.0.6119.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -20613,8 +20613,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v121.0.6118.0",
-              "revision": "version:121.0.6118.0"
+              "location": "lacros_version_skew_tests_v121.0.6119.0",
+              "revision": "version:121.0.6119.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 0713885c..8786120 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -41099,7 +41099,7 @@
         "autotest_name": "tast.lacros-from-gcs",
         "bucket": "chromiumos-image-archive",
         "cros_board": "eve",
-        "cros_img": "eve-public/R121-15672.0.0",
+        "cros_img": "eve-public/R121-15673.0.0",
         "dut_pool": "chromium",
         "name": "lacros_all_tast_tests EVE_PUBLIC_LKGM",
         "public_builder": "cros_test_platform_public",
@@ -41120,7 +41120,7 @@
         "autotest_name": "tast.lacros-from-gcs",
         "bucket": "chromiumos-image-archive",
         "cros_board": "octopus",
-        "cros_img": "octopus-public/R121-15672.0.0",
+        "cros_img": "octopus-public/R121-15673.0.0",
         "name": "lacros_all_tast_tests OCTOPUS_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -41145,7 +41145,7 @@
         "autotest_name": "tast.lacros-from-gcs",
         "bucket": "chromiumos-image-archive",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-public/R121-15672.0.0",
+        "cros_img": "jacuzzi-public/R121-15673.0.0",
         "name": "lacros_all_tast_tests JACUZZI_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -41163,7 +41163,7 @@
         "autotest_name": "tast.lacros-from-gcs",
         "bucket": "chromiumos-image-archive",
         "cros_board": "trogdor",
-        "cros_img": "trogdor-public/R121-15672.0.0",
+        "cros_img": "trogdor-public/R121-15673.0.0",
         "name": "lacros_all_tast_tests TROGDOR_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -41188,7 +41188,7 @@
         "autotest_name": "tast.lacros-from-gcs",
         "bucket": "chromiumos-image-archive",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-public/R121-15672.0.0",
+        "cros_img": "jacuzzi-public/R121-15673.0.0",
         "name": "lacros_all_tast_tests JACUZZI_CQ_PUBLIC_LKGM",
         "public_builder": "cros_test_platform_public",
         "public_builder_bucket": "testplatform-public",
@@ -41208,7 +41208,7 @@
         "autotest_name": "tast.lacros-from-gcs",
         "bucket": "chromiumos-image-archive",
         "cros_board": "jacuzzi",
-        "cros_img": "jacuzzi-public/R121-15672.0.0",
+        "cros_img": "jacuzzi-public/R121-15673.0.0",
         "name": "lacros_all_tast_tests JACUZZI_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -41226,7 +41226,7 @@
         "autotest_name": "tast.lacros-from-gcs",
         "bucket": "chromiumos-image-archive",
         "cros_board": "trogdor",
-        "cros_img": "trogdor-public/R121-15672.0.0",
+        "cros_img": "trogdor-public/R121-15673.0.0",
         "name": "lacros_all_tast_tests TROGDOR_PUBLIC_LKGM",
         "resultdb": {
           "enable": true,
@@ -43451,9 +43451,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6118.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6119.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 121.0.6118.0",
+        "description": "Run with ash-chrome version 121.0.6119.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -43462,8 +43462,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v121.0.6118.0",
-              "revision": "version:121.0.6118.0"
+              "location": "lacros_version_skew_tests_v121.0.6119.0",
+              "revision": "version:121.0.6119.0"
             }
           ],
           "dimensions": {
@@ -43601,9 +43601,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6118.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6119.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 121.0.6118.0",
+        "description": "Run with ash-chrome version 121.0.6119.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -43612,8 +43612,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v121.0.6118.0",
-              "revision": "version:121.0.6118.0"
+              "location": "lacros_version_skew_tests_v121.0.6119.0",
+              "revision": "version:121.0.6119.0"
             }
           ],
           "dimensions": {
@@ -44910,9 +44910,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6118.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6119.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 121.0.6118.0",
+        "description": "Run with ash-chrome version 121.0.6119.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -44921,8 +44921,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v121.0.6118.0",
-              "revision": "version:121.0.6118.0"
+              "location": "lacros_version_skew_tests_v121.0.6119.0",
+              "revision": "version:121.0.6119.0"
             }
           ],
           "dimensions": {
@@ -45060,9 +45060,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6118.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6119.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 121.0.6118.0",
+        "description": "Run with ash-chrome version 121.0.6119.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -45071,8 +45071,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v121.0.6118.0",
-              "revision": "version:121.0.6118.0"
+              "location": "lacros_version_skew_tests_v121.0.6119.0",
+              "revision": "version:121.0.6119.0"
             }
           ],
           "dimensions": {
@@ -45755,9 +45755,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6118.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6119.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 121.0.6118.0",
+        "description": "Run with ash-chrome version 121.0.6119.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -45766,8 +45766,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v121.0.6118.0",
-              "revision": "version:121.0.6118.0"
+              "location": "lacros_version_skew_tests_v121.0.6119.0",
+              "revision": "version:121.0.6119.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 5243290..f1e0015 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -16249,12 +16249,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6118.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6119.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 121.0.6118.0",
+        "description": "Run with ash-chrome version 121.0.6119.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -16264,8 +16264,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v121.0.6118.0",
-              "revision": "version:121.0.6118.0"
+              "location": "lacros_version_skew_tests_v121.0.6119.0",
+              "revision": "version:121.0.6119.0"
             }
           ],
           "dimensions": {
@@ -16419,12 +16419,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.filter;../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6118.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6119.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 121.0.6118.0",
+        "description": "Run with ash-chrome version 121.0.6119.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -16434,8 +16434,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v121.0.6118.0",
-              "revision": "version:121.0.6118.0"
+              "location": "lacros_version_skew_tests_v121.0.6119.0",
+              "revision": "version:121.0.6119.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/tryserver.chromium.chromiumos.json b/testing/buildbot/tryserver.chromium.chromiumos.json
index 8abdd9cd..1a40690 100644
--- a/testing/buildbot/tryserver.chromium.chromiumos.json
+++ b/testing/buildbot/tryserver.chromium.chromiumos.json
@@ -11,7 +11,7 @@
         "bucket": "chromiumos-image-archive",
         "ci_only": true,
         "cros_board": "volteer",
-        "cros_img": "volteer-public/R121-15672.0.0",
+        "cros_img": "volteer-public/R121-15673.0.0",
         "cros_model": "voxel",
         "dut_pool": "chromium",
         "name": "chromeos_integration_tests VOLTEER_PUBLIC_LKGM",
@@ -25,7 +25,7 @@
         "autotest_name": "tast.lacros-from-gcs",
         "bucket": "chromiumos-image-archive",
         "cros_board": "volteer",
-        "cros_img": "volteer-public/R121-15672.0.0",
+        "cros_img": "volteer-public/R121-15673.0.0",
         "cros_model": "voxel",
         "dut_pool": "chromium",
         "name": "lacros_all_tast_tests VOLTEER_PUBLIC_LKGM",
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index a82bef5a..7021c96 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -70,16 +70,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'identifier': 'Lacros version skew testing ash canary',
-    'description': 'Run with ash-chrome version 121.0.6118.0',
+    'description': 'Run with ash-chrome version 121.0.6119.0',
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6118.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v121.0.6119.0/test_ash_chrome',
     ],
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v121.0.6118.0',
-          'revision': 'version:121.0.6118.0',
+          'location': 'lacros_version_skew_tests_v121.0.6119.0',
+          'revision': 'version:121.0.6119.0',
         },
       ],
     },
@@ -620,7 +620,7 @@
     'identifier': 'EVE_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'eve',
-      'cros_img': 'eve-public/R121-15672.0.0',
+      'cros_img': 'eve-public/R121-15673.0.0',
       'bucket': 'chromiumos-image-archive',
       'dut_pool': 'chromium',
       'public_builder': 'cros_test_platform_public',
@@ -694,7 +694,7 @@
     'identifier': 'JACUZZI_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'jacuzzi',
-      'cros_img': 'jacuzzi-public/R121-15672.0.0',
+      'cros_img': 'jacuzzi-public/R121-15673.0.0',
       'bucket': 'chromiumos-image-archive',
     },
   },
@@ -702,7 +702,7 @@
     'identifier': 'JACUZZI_CQ_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'jacuzzi',
-      'cros_img': 'jacuzzi-public/R121-15672.0.0',
+      'cros_img': 'jacuzzi-public/R121-15673.0.0',
       'bucket': 'chromiumos-image-archive',
       'public_builder': 'cros_test_platform_public',
       'public_builder_bucket': 'testplatform-public',
@@ -712,7 +712,7 @@
     'identifier': 'TROGDOR_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'trogdor',
-      'cros_img': 'trogdor-public/R121-15672.0.0',
+      'cros_img': 'trogdor-public/R121-15673.0.0',
       'bucket': 'chromiumos-image-archive',
     },
   },
@@ -720,7 +720,7 @@
     'identifier': 'OCTOPUS_PUBLIC_LKGM',
     'skylab': {
       'cros_board': 'octopus',
-      'cros_img': 'octopus-public/R121-15672.0.0',
+      'cros_img': 'octopus-public/R121-15673.0.0',
       'bucket': 'chromiumos-image-archive',
     },
   },
@@ -799,7 +799,7 @@
     'skylab': {
       'cros_board': 'volteer',
       'cros_model': 'voxel',
-      'cros_img': 'volteer-public/R121-15672.0.0',
+      'cros_img': 'volteer-public/R121-15673.0.0',
       'bucket': 'chromiumos-image-archive',
       'dut_pool': 'chromium',
       'public_builder': 'cros_test_platform_public',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index f83faed..76aa8c6cc 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -799,21 +799,6 @@
             ]
         }
     ],
-    "ArcVmBlockSize": [
-        {
-            "platforms": [
-                "chromeos"
-            ],
-            "experiments": [
-                {
-                    "name": "EnabledGroupA_20211105",
-                    "enable_features": [
-                        "ArcVmUseDefaultBlockSize"
-                    ]
-                }
-            ]
-        }
-    ],
     "ArcVmBroadcastPreAnrHandling": [
         {
             "platforms": [
@@ -12612,6 +12597,24 @@
             ]
         }
     ],
+    "PeripheralCustomization": [
+        {
+            "platforms": [
+                "chromeos",
+                "chromeos_lacros"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "PeripheralCustomization",
+                        "SearchCustomizableShortcutsInLauncher",
+                        "ShortcutCustomization"
+                    ]
+                }
+            ]
+        }
+    ],
     "PhoneHubOnboardingNotifiersStudy": [
         {
             "platforms": [
@@ -14500,6 +14503,27 @@
             ]
         }
     ],
+    "RustyJSONParser": [
+        {
+            "platforms": [
+                "android",
+                "android_webview",
+                "chromeos",
+                "chromeos_lacros",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled_20230929",
+                    "enable_features": [
+                        "UseRustJsonParser"
+                    ]
+                }
+            ]
+        }
+    ],
     "RustyQrCodeGenerator": [
         {
             "platforms": [
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 2cc5cad..c1c8183de 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -1010,7 +1010,7 @@
 const base::FeatureParam<int> kInterestGroupStorageMaxStoragePerOwner{
     &kInterestGroupStorage, "max_storage_per_owner", 10 * 1024 * 1024};
 const base::FeatureParam<int> kInterestGroupStorageMaxGroupsPerOwner{
-    &kInterestGroupStorage, "max_groups_per_owner", 1000};
+    &kInterestGroupStorage, "max_groups_per_owner", 2000};
 const base::FeatureParam<int> kInterestGroupStorageMaxNegativeGroupsPerOwner{
     &kInterestGroupStorage, "max_negative_groups_per_owner", 20000};
 const base::FeatureParam<int> kInterestGroupStorageMaxOpsBeforeMaintenance{
diff --git a/third_party/blink/public/mojom/lcp_critical_path_predictor/lcp_critical_path_predictor.mojom b/third_party/blink/public/mojom/lcp_critical_path_predictor/lcp_critical_path_predictor.mojom
index 544a59e..de7d10f 100644
--- a/third_party/blink/public/mojom/lcp_critical_path_predictor/lcp_critical_path_predictor.mojom
+++ b/third_party/blink/public/mojom/lcp_critical_path_predictor/lcp_critical_path_predictor.mojom
@@ -11,10 +11,10 @@
 interface LCPCriticalPathPredictorHost {
   // `lcp_element_locator` is a LCP ElementLocator information
   // serialized in proto3 binary format.
-  // `lcp_timing_was_predicted` indicates if `lcp_element_locator` was predicted
-  // as actual LCP.
+  // `predicted_lcp_index` is predicted index of `lcp_element_locators` in
+  //  LCPCriticalPathPredictorNavigationTimeHint.
   SetLcpElementLocator(mojo_base.mojom.ByteString lcp_element_locator,
-    bool lcp_timing_was_predicted);
+    uint32? predicted_lcp_index);
 
   // `lcp_influencer_scripts` contain the list of script URLs that affected
   // the LCP element.
diff --git a/third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom b/third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom
index 3fd5a973..c0515b6 100644
--- a/third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom
+++ b/third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom
@@ -53,12 +53,11 @@
   kEager = 2,
 };
 
-// Specifies the v8 world where the JavaScript runs if the JavaScript injects
-// the speculation rule.
-enum SpeculationInjectionWorld {
-  kNone,  // No v8 context, i.e. statically inserted script tags.
-  kMain,
-  kIsolated,
+// Specifies the way in which speculation rules were injected.
+enum SpeculationInjectionType {
+  kNone,                  // Not injected, i.e., statically-inserted script tags.
+  kMainWorldScript,       // Injected by main V8 world's script.
+  kIsolatedWorldScript,   // Injected by an isolated V8 world's script.
 };
 
 // A single candidate: a URL, an action, a referrer, and any associated
@@ -92,7 +91,6 @@
   // Explainer: https://github.com/WICG/nav-speculation/blob/main/no-vary-search.md#a-referrer-hint
   network.mojom.NoVarySearch? no_vary_search_hint;
 
-  // The v8 world where the JavaScript runs if the speculation rule is injected
-  // by the JavaScript.
-  SpeculationInjectionWorld injection_world = kNone;
+  // The way in which the speculation rules were injected.
+  SpeculationInjectionType injection_type = kNone;
 };
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index 3c095a52..0a90c0c0 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1683,6 +1683,7 @@
 
   source_dir = "lcp_critical_path_predictor/test_proto"
   sources = rebase_path([ "lcp_image_id.asciipb" ], "", source_dir)
+  sources += rebase_path([ "lcp_image_id_b.asciipb" ], "", source_dir)
 
   deps = [
     ":element_locator_proto",
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index d9352850..e0e1436 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -2688,11 +2688,6 @@
     }
   }
 
-  if (!RuntimeEnabledFeatures::SimplifiedClearPropertyTreeChangeEnabled() &&
-      paint_artifact_compositor_) {
-    paint_artifact_compositor_->ClearPropertyTreeChangedState();
-  }
-
   if (GetPage())
     GetPage()->Animator().ReportFrameAnimations(GetCompositorAnimationHost());
 }
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index 6a52eedb..0971d0a 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -3262,21 +3262,7 @@
     return;
   }
 
-  Vector<ElementLocator> lcp_element_locators;
-  lcp_element_locators.reserve(
-      base::checked_cast<wtf_size_t>(hint->lcp_element_locators.size()));
-  for (const std::string& serialized_locator : hint->lcp_element_locators) {
-    lcp_element_locators.push_back(ElementLocator());
-    bool result =
-        lcp_element_locators.back().ParseFromString(serialized_locator);
-    if (!result) {
-      // This can happen when the host LCPP database is corrupted or we
-      // updated the ElementLocator schema in an incompatible way.
-      LOG(INFO) << "Ignoring an invalid lcp_element_locator hint.";
-      lcp_element_locators.pop_back();
-    }
-  }
-  lcpp->set_lcp_element_locators(std::move(lcp_element_locators));
+  lcpp->set_lcp_element_locators(hint->lcp_element_locators);
 
   HashSet<KURL> lcp_influencer_scripts;
   for (auto& url : hint->lcp_influencer_scripts) {
diff --git a/third_party/blink/renderer/core/layout/layout_image_resource.cc b/third_party/blink/renderer/core/layout/layout_image_resource.cc
index 6ea668f..017b9eb 100644
--- a/third_party/blink/renderer/core/layout/layout_image_resource.cc
+++ b/third_party/blink/renderer/core/layout/layout_image_resource.cc
@@ -172,10 +172,11 @@
   return size;
 }
 
-gfx::SizeF LayoutImageResource::ImageSizeWithDefaultSize(
+gfx::SizeF LayoutImageResource::ConcreteObjectSize(
     float multiplier,
-    const gfx::SizeF&) const {
-  return ImageSize(multiplier);
+    const gfx::SizeF& default_object_size) const {
+  IntrinsicSizingInfo sizing_info = GetNaturalDimensions(multiplier);
+  return blink::ConcreteObjectSize(sizing_info, default_object_size);
 }
 
 Image* LayoutImageResource::BrokenImage(double device_pixel_ratio) {
diff --git a/third_party/blink/renderer/core/layout/layout_image_resource.h b/third_party/blink/renderer/core/layout/layout_image_resource.h
index 4ea86ff..f531db18 100644
--- a/third_party/blink/renderer/core/layout/layout_image_resource.h
+++ b/third_party/blink/renderer/core/layout/layout_image_resource.h
@@ -70,9 +70,9 @@
   virtual bool HasIntrinsicSize() const;
 
   virtual gfx::SizeF ImageSize(float multiplier) const;
-  // Default size is effective when this is LayoutImageResourceStyleImage.
-  virtual gfx::SizeF ImageSizeWithDefaultSize(float multiplier,
-                                              const gfx::SizeF&) const;
+  virtual gfx::SizeF ConcreteObjectSize(
+      float multiplier,
+      const gfx::SizeF& default_object_size) const;
   virtual IntrinsicSizingInfo GetNaturalDimensions(float multiplier) const;
   virtual RespectImageOrientationEnum ImageOrientation() const;
   virtual WrappedImagePtr ImagePtr() const { return cached_image_.Get(); }
diff --git a/third_party/blink/renderer/core/layout/layout_image_resource_style_image.cc b/third_party/blink/renderer/core/layout/layout_image_resource_style_image.cc
index 845ea40..318d38217 100644
--- a/third_party/blink/renderer/core/layout/layout_image_resource_style_image.cc
+++ b/third_party/blink/renderer/core/layout/layout_image_resource_style_image.cc
@@ -77,14 +77,14 @@
                                 ? list_marker->DefaultSize()
                                 : gfx::SizeF(LayoutReplaced::kDefaultWidth,
                                              LayoutReplaced::kDefaultHeight);
-  return ImageSizeWithDefaultSize(multiplier, default_size);
+  return ConcreteObjectSize(multiplier, default_size);
 }
 
-gfx::SizeF LayoutImageResourceStyleImage::ImageSizeWithDefaultSize(
+gfx::SizeF LayoutImageResourceStyleImage::ConcreteObjectSize(
     float multiplier,
-    const gfx::SizeF& default_size) const {
+    const gfx::SizeF& default_object_size) const {
   return style_image_->ImageSize(
-      multiplier, default_size,
+      multiplier, default_object_size,
       LayoutObject::ShouldRespectImageOrientation(layout_object_));
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_image_resource_style_image.h b/third_party/blink/renderer/core/layout/layout_image_resource_style_image.h
index 8206e2bd..646b270 100644
--- a/third_party/blink/renderer/core/layout/layout_image_resource_style_image.h
+++ b/third_party/blink/renderer/core/layout/layout_image_resource_style_image.h
@@ -51,8 +51,9 @@
     return style_image_->HasIntrinsicSize();
   }
   gfx::SizeF ImageSize(float multiplier) const override;
-  gfx::SizeF ImageSizeWithDefaultSize(float multiplier,
-                                      const gfx::SizeF&) const override;
+  gfx::SizeF ConcreteObjectSize(
+      float multiplier,
+      const gfx::SizeF& default_object_size) const override;
   IntrinsicSizingInfo GetNaturalDimensions(float multiplier) const override;
   RespectImageOrientationEnum ImageOrientation() const override;
   WrappedImagePtr ImagePtr() const override { return style_image_->Data(); }
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index 53b88851..02cf1ec6 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -84,7 +84,10 @@
 #include "third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h"
 #include "third_party/blink/renderer/core/layout/layout_object_inl.h"
 #include "third_party/blink/renderer/core/layout/layout_object_inlines.h"
+#include "third_party/blink/renderer/core/layout/layout_ruby.h"
+#include "third_party/blink/renderer/core/layout/layout_ruby_as_block.h"
 #include "third_party/blink/renderer/core/layout/layout_ruby_column.h"
+#include "third_party/blink/renderer/core/layout/layout_ruby_text.h"
 #include "third_party/blink/renderer/core/layout/layout_text_combine.h"
 #include "third_party/blink/renderer/core/layout/layout_text_fragment.h"
 #include "third_party/blink/renderer/core/layout/layout_theme.h"
@@ -417,11 +420,14 @@
     case EDisplay::kBlockMath:
       return MakeGarbageCollected<LayoutMathMLBlock>(element);
     case EDisplay::kRuby:
+      DCHECK(RuntimeEnabledFeatures::CssDisplayRubyEnabled());
+      return MakeGarbageCollected<LayoutRubyAsInline>(element);
     case EDisplay::kBlockRuby:
+      DCHECK(RuntimeEnabledFeatures::CssDisplayRubyEnabled());
+      return MakeGarbageCollected<LayoutRubyAsBlock>(element);
     case EDisplay::kRubyText:
-      // TODO(crbug.com/880802): Returns a LayoutRuby* instance.
-      NOTREACHED();
-      return CreateBlockFlowOrListItem(element, style);
+      DCHECK(RuntimeEnabledFeatures::CssDisplayRubyEnabled());
+      return MakeGarbageCollected<LayoutRubyText>(element);
     case EDisplay::kLayoutCustom:
     case EDisplay::kInlineLayoutCustom:
       return MakeGarbageCollected<LayoutCustom>(element);
diff --git a/third_party/blink/renderer/core/layout/list/layout_list_marker_image.cc b/third_party/blink/renderer/core/layout/list/layout_list_marker_image.cc
index 65e739a..38e40fe3 100644
--- a/third_party/blink/renderer/core/layout/list/layout_list_marker_image.cc
+++ b/third_party/blink/renderer/core/layout/list/layout_list_marker_image.cc
@@ -42,14 +42,11 @@
 void LayoutListMarkerImage::ComputeIntrinsicSizingInfoByDefaultSize(
     IntrinsicSizingInfo& intrinsic_sizing_info) const {
   NOT_DESTROYED();
-  gfx::SizeF concrete_size = ImageResource()->ImageSizeWithDefaultSize(
+  gfx::SizeF concrete_size = ImageResource()->ConcreteObjectSize(
       Style()->EffectiveZoom(), DefaultSize());
   concrete_size.Scale(ImageDevicePixelRatio());
 
-  intrinsic_sizing_info.size.set_width(
-      LayoutUnit(concrete_size.width()).ToFloat());
-  intrinsic_sizing_info.size.set_height(
-      LayoutUnit(concrete_size.height()).ToFloat());
+  intrinsic_sizing_info.size = concrete_size;
   intrinsic_sizing_info.has_width = true;
   intrinsic_sizing_info.has_height = true;
 }
@@ -61,8 +58,9 @@
 
   // If this is an image without intrinsic width and height, compute the
   // concrete object size by using the specified default object size.
-  if (intrinsic_sizing_info.size.IsEmpty() && ImageResource())
+  if (intrinsic_sizing_info.size.IsEmpty()) {
     ComputeIntrinsicSizingInfoByDefaultSize(intrinsic_sizing_info);
+  }
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/lcp_critical_path_predictor/lcp_critical_path_predictor.cc b/third_party/blink/renderer/core/lcp_critical_path_predictor/lcp_critical_path_predictor.cc
index 18dbccf1..0acca8db 100644
--- a/third_party/blink/renderer/core/lcp_critical_path_predictor/lcp_critical_path_predictor.cc
+++ b/third_party/blink/renderer/core/lcp_critical_path_predictor/lcp_critical_path_predictor.cc
@@ -41,12 +41,25 @@
 }
 
 void LCPCriticalPathPredictor::set_lcp_element_locators(
-    Vector<ElementLocator> locators) {
-  lcp_element_locators_ = std::move(locators);
-  if (lcp_element_locators_.size()) {
-    first_lcp_element_locator_string_ =
-        lcp_element_locators_[0].SerializeAsString();
+    const std::vector<std::string>& lcp_element_locator_strings) {
+  const wtf_size_t reserved_size =
+      base::checked_cast<wtf_size_t>(lcp_element_locator_strings.size());
+  lcp_element_locators_.reserve(reserved_size);
+  lcp_element_locator_strings_.reserve(reserved_size);
+  for (const std::string& serialized_locator : lcp_element_locator_strings) {
+    lcp_element_locators_.push_back(ElementLocator());
+    bool result =
+        lcp_element_locators_.back().ParseFromString(serialized_locator);
+    if (!result) {
+      // This can happen when the host LCPP database is corrupted or we
+      // updated the ElementLocator schema in an incompatible way.
+      LOG(INFO) << "Ignoring an invalid lcp_element_locator hint.";
+      lcp_element_locators_.pop_back();
+    } else {
+      lcp_element_locator_strings_.push_back(std::move(serialized_locator));
+    }
   }
+  CHECK_EQ(lcp_element_locators_.size(), lcp_element_locator_strings_.size());
 }
 
 void LCPCriticalPathPredictor::set_lcp_influencer_scripts(
@@ -60,6 +73,7 @@
 
 void LCPCriticalPathPredictor::Reset() {
   lcp_element_locators_.clear();
+  lcp_element_locator_strings_.clear();
   lcp_influencer_scripts_.clear();
   fetched_fonts_.clear();
 }
@@ -70,16 +84,16 @@
     std::string lcp_element_locator_string =
         element_locator::OfElement(lcp_element).SerializeAsString();
 
-    bool lcp_timing_was_predicted = false;
-    // Predicted the most frequent LCP would be next LCP and record the
-    // actual result. see PredictLcpElementLocators() for the `hint` contents.
+    wtf_size_t predicted_lcp_index;
+    // Regard `lcp_element` is the candidate if its locator is found in
+    // set_lcp_element_locators(lcp_element_locator_strings).
+    // See PredictLcpElementLocators() for the contents detail.
     // TODO(crbug.com/1493255): We might need another predictor e.g. checking
     // other element_locators as well.
-    if (first_lcp_element_locator_string_ &&
-        *first_lcp_element_locator_string_ == lcp_element_locator_string) {
+    if ((predicted_lcp_index = lcp_element_locator_strings_.Find(
+             lcp_element_locator_string)) != kNotFound) {
       // TODO(crbug.com/1493255): Trigger callbacks for the entire frame tree.
       frame_->GetDocument()->RunLCPPredictedCallbacks(lcp_element);
-      lcp_timing_was_predicted = true;
     }
 
     features::LcppRecordedLcpElementTypes recordable_lcp_element_type =
@@ -100,8 +114,11 @@
           base::checked_cast<size_t>(
               features::kLCPCriticalPathPredictorMaxElementLocatorLength
                   .Get())) {
-        GetHost().SetLcpElementLocator(lcp_element_locator_string,
-                                       lcp_timing_was_predicted);
+        GetHost().SetLcpElementLocator(
+            lcp_element_locator_string,
+            predicted_lcp_index == kNotFound
+                ? absl::nullopt
+                : absl::optional<wtf_size_t>(predicted_lcp_index));
       }
     }
   }
diff --git a/third_party/blink/renderer/core/lcp_critical_path_predictor/lcp_critical_path_predictor.h b/third_party/blink/renderer/core/lcp_critical_path_predictor/lcp_critical_path_predictor.h
index 5e7efe50..e3dcd23 100644
--- a/third_party/blink/renderer/core/lcp_critical_path_predictor/lcp_critical_path_predictor.h
+++ b/third_party/blink/renderer/core/lcp_critical_path_predictor/lcp_critical_path_predictor.h
@@ -40,7 +40,8 @@
   // Meant to be used as preconditions on metrics.
   bool HasAnyHintData() const;
 
-  void set_lcp_element_locators(Vector<ElementLocator> locators);
+  void set_lcp_element_locators(
+      const std::vector<std::string>& lcp_element_locator_strings);
 
   const Vector<ElementLocator>& lcp_element_locators() {
     return lcp_element_locators_;
@@ -81,7 +82,7 @@
   // LCPP hints for consumption (read path):
 
   Vector<ElementLocator> lcp_element_locators_;
-  absl::optional<std::string> first_lcp_element_locator_string_;
+  Vector<std::string> lcp_element_locator_strings_;
   HashSet<KURL> lcp_influencer_scripts_;
   Vector<KURL> fetched_fonts_;
 };
diff --git a/third_party/blink/renderer/core/lcp_critical_path_predictor/test_proto/lcp_image_id_b.asciipb b/third_party/blink/renderer/core/lcp_critical_path_predictor/test_proto/lcp_image_id_b.asciipb
new file mode 100644
index 0000000..e026e9f
--- /dev/null
+++ b/third_party/blink/renderer/core/lcp_critical_path_predictor/test_proto/lcp_image_id_b.asciipb
@@ -0,0 +1,9 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+components {
+  id {
+    id_attr: "lcp_image_b"
+  }
+}
diff --git a/third_party/blink/renderer/core/paint/svg_image_painter.cc b/third_party/blink/renderer/core/paint/svg_image_painter.cc
index d705478..10cb51f 100644
--- a/third_party/blink/renderer/core/paint/svg_image_painter.cc
+++ b/third_party/blink/renderer/core/paint/svg_image_painter.cc
@@ -14,7 +14,6 @@
 #include "third_party/blink/renderer/core/paint/timing/image_element_timing.h"
 #include "third_party/blink/renderer/core/paint/timing/paint_timing.h"
 #include "third_party/blink/renderer/core/paint/timing/paint_timing_detector.h"
-#include "third_party/blink/renderer/core/svg/graphics/svg_image.h"
 #include "third_party/blink/renderer/core/svg/svg_animated_preserve_aspect_ratio.h"
 #include "third_party/blink/renderer/core/svg/svg_animated_rect.h"
 #include "third_party/blink/renderer/core/svg/svg_element.h"
@@ -71,13 +70,12 @@
 }
 
 void SVGImagePainter::PaintForeground(const PaintInfo& paint_info) {
-  const LayoutImageResource& image_resource =
-      *layout_svg_image_.ImageResource();
   gfx::SizeF image_viewport_size = ComputeImageViewportSize();
-  image_viewport_size.Scale(layout_svg_image_.StyleRef().EffectiveZoom());
   if (image_viewport_size.IsEmpty())
     return;
 
+  const LayoutImageResource& image_resource =
+      *layout_svg_image_.ImageResource();
   scoped_refptr<Image> image = image_resource.GetImage(image_viewport_size);
   gfx::RectF dest_rect = layout_svg_image_.ObjectBoundingBox();
   auto* image_element = To<SVGImageElement>(layout_svg_image_.GetElement());
@@ -132,14 +130,16 @@
 gfx::SizeF SVGImagePainter::ComputeImageViewportSize() const {
   DCHECK(layout_svg_image_.ImageResource()->HasImage());
 
+  const float zoom = layout_svg_image_.StyleRef().EffectiveZoom();
+  const gfx::SizeF default_object_size =
+      gfx::ScaleSize(layout_svg_image_.ObjectBoundingBox().size(), zoom);
+
   if (To<SVGImageElement>(layout_svg_image_.GetElement())
           ->preserveAspectRatio()
           ->CurrentValue()
-          ->Align() != SVGPreserveAspectRatio::kSvgPreserveaspectratioNone)
-    return layout_svg_image_.ObjectBoundingBox().size();
-
-  ImageResourceContent* cached_image =
-      layout_svg_image_.ImageResource()->CachedImage();
+          ->Align() != SVGPreserveAspectRatio::kSvgPreserveaspectratioNone) {
+    return default_object_size;
+  }
 
   // Images with preserveAspectRatio=none should force non-uniform scaling. This
   // can be achieved by setting the image's container size to its viewport size
@@ -147,16 +147,13 @@
   // https://www.w3.org/TR/SVG/single-page.html#coords-PreserveAspectRatioAttribute
   // and https://drafts.csswg.org/css-images-3/#default-sizing.
 
+  const LayoutImageResource& image_resource =
+      *layout_svg_image_.ImageResource();
   // Avoid returning the size of the broken image.
-  if (cached_image->ErrorOccurred())
+  if (image_resource.ErrorOccurred()) {
     return gfx::SizeF();
-  Image* image = cached_image->GetImage();
-  if (auto* svg_image = DynamicTo<SVGImage>(image)) {
-    return svg_image->ConcreteObjectSize(
-        layout_svg_image_.ObjectBoundingBox().size());
   }
-  // The orientation here does not matter. Just use kRespectImageOrientation.
-  return image->SizeAsFloat(kRespectImageOrientation);
+  return image_resource.ConcreteObjectSize(zoom, default_object_size);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/script/detect_javascript_frameworks.cc b/third_party/blink/renderer/core/script/detect_javascript_frameworks.cc
index 93293a2..ca572c8 100644
--- a/third_party/blink/renderer/core/script/detect_javascript_frameworks.cc
+++ b/third_party/blink/renderer/core/script/detect_javascript_frameworks.cc
@@ -288,11 +288,13 @@
 
   HTMLMetaElement* generator_meta = nullptr;
 
-  for (HTMLMetaElement& meta_element :
-       Traversal<HTMLMetaElement>::DescendantsOf(*document.head())) {
-    if (EqualIgnoringASCIICase(meta_element.GetName(), "generator")) {
-      generator_meta = &meta_element;
-      break;
+  if (document.head()) {
+    for (HTMLMetaElement& meta_element :
+         Traversal<HTMLMetaElement>::DescendantsOf(*document.head())) {
+      if (EqualIgnoringASCIICase(meta_element.GetName(), "generator")) {
+        generator_meta = &meta_element;
+        break;
+      }
     }
   }
 
diff --git a/third_party/blink/renderer/core/speculation_rules/document_speculation_rules.cc b/third_party/blink/renderer/core/speculation_rules/document_speculation_rules.cc
index 10aa953..9e8c532 100644
--- a/third_party/blink/renderer/core/speculation_rules/document_speculation_rules.cc
+++ b/third_party/blink/renderer/core/speculation_rules/document_speculation_rules.cc
@@ -565,7 +565,7 @@
             rule->target_browsing_context_name_hint().value_or(
                 mojom::blink::SpeculationTargetHint::kNoHint),
             rule->eagerness(), rule->no_vary_search_expected().Clone(),
-            rule->injection_world(), rule_set, /*anchor=*/nullptr));
+            rule->injection_type(), rule_set, /*anchor=*/nullptr));
       }
     }
   };
@@ -731,7 +731,7 @@
                     rule->requires_anonymous_client_ip_when_cross_origin(),
                     target_hint, rule->eagerness(),
                     rule->no_vary_search_expected().Clone(),
-                    rule->injection_world(), rule_set, link);
+                    rule->injection_type(), rule_set, link);
             link_candidates->push_back(std::move(candidate));
           }
         };
diff --git a/third_party/blink/renderer/core/speculation_rules/speculation_candidate.cc b/third_party/blink/renderer/core/speculation_rules/speculation_candidate.cc
index d5b6c66..e3ae361 100644
--- a/third_party/blink/renderer/core/speculation_rules/speculation_candidate.cc
+++ b/third_party/blink/renderer/core/speculation_rules/speculation_candidate.cc
@@ -18,7 +18,7 @@
     mojom::blink::SpeculationTargetHint target_hint,
     mojom::blink::SpeculationEagerness eagerness,
     network::mojom::blink::NoVarySearchPtr no_vary_search,
-    mojom::blink::SpeculationInjectionWorld injection_world,
+    mojom::blink::SpeculationInjectionType injection_type,
     SpeculationRuleSet* rule_set,
     HTMLAnchorElement* anchor)
     : url_(url),
@@ -29,7 +29,7 @@
       target_hint_(target_hint),
       eagerness_(eagerness),
       no_vary_search_(std::move(no_vary_search)),
-      injection_world_(injection_world),
+      injection_type_(injection_type),
       rule_set_(rule_set),
       anchor_(anchor) {
   DCHECK(rule_set);
@@ -47,7 +47,7 @@
       mojom::blink::Referrer::New(KURL(referrer_.referrer),
                                   referrer_.referrer_policy),
       requires_anonymous_client_ip_when_cross_origin_, target_hint_, eagerness_,
-      no_vary_search_.Clone(), injection_world_);
+      no_vary_search_.Clone(), injection_type_);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/speculation_rules/speculation_candidate.h b/third_party/blink/renderer/core/speculation_rules/speculation_candidate.h
index 1989430..98692f188 100644
--- a/third_party/blink/renderer/core/speculation_rules/speculation_candidate.h
+++ b/third_party/blink/renderer/core/speculation_rules/speculation_candidate.h
@@ -32,7 +32,7 @@
                        mojom::blink::SpeculationTargetHint target_hint,
                        mojom::blink::SpeculationEagerness eagerness,
                        network::mojom::blink::NoVarySearchPtr no_vary_search,
-                       mojom::blink::SpeculationInjectionWorld injection_world,
+                       mojom::blink::SpeculationInjectionType injection_type,
                        SpeculationRuleSet* rule_set,
                        HTMLAnchorElement* anchor);
   virtual ~SpeculationCandidate() = default;
@@ -60,7 +60,7 @@
   const mojom::blink::SpeculationTargetHint target_hint_;
   const mojom::blink::SpeculationEagerness eagerness_;
   const network::mojom::blink::NoVarySearchPtr no_vary_search_;
-  const mojom::blink::SpeculationInjectionWorld injection_world_;
+  const mojom::blink::SpeculationInjectionType injection_type_;
   const Member<SpeculationRuleSet> rule_set_;
   const Member<HTMLAnchorElement> anchor_;
 };
diff --git a/third_party/blink/renderer/core/speculation_rules/speculation_rule.cc b/third_party/blink/renderer/core/speculation_rules/speculation_rule.cc
index aed55fb..9cf5706 100644
--- a/third_party/blink/renderer/core/speculation_rules/speculation_rule.cc
+++ b/third_party/blink/renderer/core/speculation_rules/speculation_rule.cc
@@ -18,7 +18,7 @@
     absl::optional<network::mojom::ReferrerPolicy> referrer_policy,
     mojom::blink::SpeculationEagerness eagerness,
     network::mojom::blink::NoVarySearchPtr no_vary_search_expected,
-    mojom::blink::SpeculationInjectionWorld injection_world)
+    mojom::blink::SpeculationInjectionType injection_type)
     : urls_(std::move(urls)),
       predicate_(predicate),
       requires_anonymous_client_ip_(requires_anonymous_client_ip),
@@ -26,7 +26,7 @@
       referrer_policy_(referrer_policy),
       eagerness_(eagerness),
       no_vary_search_expected_(std::move(no_vary_search_expected)),
-      injection_world_(injection_world) {}
+      injection_type_(injection_type) {}
 
 SpeculationRule::~SpeculationRule() = default;
 
diff --git a/third_party/blink/renderer/core/speculation_rules/speculation_rule.h b/third_party/blink/renderer/core/speculation_rules/speculation_rule.h
index 30e44064..46b060f 100644
--- a/third_party/blink/renderer/core/speculation_rules/speculation_rule.h
+++ b/third_party/blink/renderer/core/speculation_rules/speculation_rule.h
@@ -37,7 +37,7 @@
       absl::optional<network::mojom::ReferrerPolicy>,
       mojom::blink::SpeculationEagerness,
       network::mojom::blink::NoVarySearchPtr,
-      mojom::blink::SpeculationInjectionWorld);
+      mojom::blink::SpeculationInjectionType);
   ~SpeculationRule();
 
   const Vector<KURL>& urls() const { return urls_; }
@@ -57,8 +57,8 @@
       const {
     return no_vary_search_expected_;
   }
-  mojom::blink::SpeculationInjectionWorld injection_world() const {
-    return injection_world_;
+  mojom::blink::SpeculationInjectionType injection_type() const {
+    return injection_type_;
   }
 
   void Trace(Visitor*) const;
@@ -72,8 +72,8 @@
   const absl::optional<network::mojom::ReferrerPolicy> referrer_policy_;
   mojom::blink::SpeculationEagerness eagerness_;
   network::mojom::blink::NoVarySearchPtr no_vary_search_expected_;
-  mojom::blink::SpeculationInjectionWorld injection_world_ =
-      mojom::blink::SpeculationInjectionWorld::kNone;
+  mojom::blink::SpeculationInjectionType injection_type_ =
+      mojom::blink::SpeculationInjectionType::kNone;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/speculation_rules/speculation_rule_set.cc b/third_party/blink/renderer/core/speculation_rules/speculation_rule_set.cc
index 4c83c850..b9474c29 100644
--- a/third_party/blink/renderer/core/speculation_rules/speculation_rule_set.cc
+++ b/third_party/blink/renderer/core/speculation_rules/speculation_rule_set.cc
@@ -413,17 +413,17 @@
     }
   }
 
-  const mojom::blink::SpeculationInjectionWorld world =
+  const mojom::blink::SpeculationInjectionType injection_type =
       context->GetCurrentWorld()
           ? context->GetCurrentWorld()->IsMainWorld()
-                ? mojom::blink::SpeculationInjectionWorld::kMain
-                : mojom::blink::SpeculationInjectionWorld::kIsolated
-          : mojom::blink::SpeculationInjectionWorld::kNone;
+                ? mojom::blink::SpeculationInjectionType::kMainWorldScript
+                : mojom::blink::SpeculationInjectionType::kIsolatedWorldScript
+          : mojom::blink::SpeculationInjectionType::kNone;
 
   return MakeGarbageCollected<SpeculationRule>(
       std::move(urls), document_rule_predicate, requires_anonymous_client_ip,
       target_hint, referrer_policy, eagerness, std::move(no_vary_search),
-      world);
+      injection_type);
 }
 
 }  // namespace
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index 9a8e2a8..aac5ad93 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -2461,7 +2461,7 @@
 
   static bool IsDisplayInlineType(EDisplay display) {
     return display == EDisplay::kInline ||
-           display == EDisplay::kInlineListItem ||
+           display == EDisplay::kInlineListItem || display == EDisplay::kRuby ||
            IsDisplayReplacedType(display);
   }
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index 160bee9..43b83fc 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -877,6 +877,10 @@
   if (!GetNode())
     return false;
 
+  if (AriaRoleAttribute() == ax::mojom::blink::Role::kComplementary) {
+    return false;
+  }
+
   auto role_names = GetLandmarkIsNotAllowedAncestorRoles(RoleValue());
 
   for (AXObject* parent = ParentObjectUnignored(); parent;
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
index f4ec5da..01dbf795 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.cc
@@ -120,6 +120,20 @@
   NOTREACHED_NORETURN();
 }
 
+webnn::ConvTranspose2dFilterOperandLayout
+BlinkConvTranspose2dFilterLayoutToComponent(
+    blink::V8MLConvTranspose2dFilterOperandLayout::Enum type) {
+  switch (type) {
+    case blink::V8MLConvTranspose2dFilterOperandLayout::Enum::kIohw:
+      return webnn::ConvTranspose2dFilterOperandLayout::kIohw;
+    case blink::V8MLConvTranspose2dFilterOperandLayout::Enum::kHwoi:
+      return webnn::ConvTranspose2dFilterOperandLayout::kHwoi;
+    case blink::V8MLConvTranspose2dFilterOperandLayout::Enum::kOhwi:
+      return webnn::ConvTranspose2dFilterOperandLayout::kOhwi;
+  }
+  NOTREACHED_NORETURN();
+}
+
 webnn::RoundingType BlinkRoundingTypeToComponent(
     blink::V8MLRoundingType::Enum type) {
   switch (type) {
@@ -159,10 +173,11 @@
   }
 }
 
-base::expected<webnn::Conv2dAttributes, String> ConvertToConv2dAttributes(
-    const blink::MLConv2dOptions* options) {
+template <typename MLConv2dOptionsType, typename Conv2dAttributesType>
+base::expected<Conv2dAttributesType, String> ConvertToConv2dAttributesBase(
+    const MLConv2dOptionsType* options) {
+  Conv2dAttributesType attributes;
   CHECK(options);
-  webnn::Conv2dAttributes attributes;
   // If padding is not present, the values are assumed to be [0,0,0,0].
   auto padding = options->getPaddingOr({0, 0, 0, 0});
   if (padding.size() != 4) {
@@ -195,11 +210,58 @@
   attributes.groups = options->groups();
   attributes.input_layout =
       BlinkInputOperandLayoutToComponent(options->inputLayout().AsEnum());
-  attributes.filter_layout =
-      BlinkConv2dFilterLayoutToComponent(options->filterLayout().AsEnum());
   if (options->hasBias()) {
     attributes.bias_operand = ConvertToComponentOperand(options->bias());
   }
+
+  return std::move(attributes);
+}
+
+base::expected<webnn::Conv2dAttributes, String> ConvertToConv2dAttributes(
+    const blink::MLConv2dOptions* options) {
+  auto attributes =
+      ConvertToConv2dAttributesBase<blink::MLConv2dOptions,
+                                    webnn::Conv2dAttributes>(options);
+  if (!attributes.has_value()) {
+    return base::unexpected(attributes.error());
+  }
+  attributes.value().filter_layout =
+      BlinkConv2dFilterLayoutToComponent(options->filterLayout().AsEnum());
+
+  return attributes;
+}
+
+base::expected<webnn::ConvTranspose2dAttributes, String>
+ConvertToConvTranspose2dAttributes(
+    const blink::MLConvTranspose2dOptions* options) {
+  auto attributes =
+      ConvertToConv2dAttributesBase<blink::MLConvTranspose2dOptions,
+                                    webnn::ConvTranspose2dAttributes>(options);
+  if (!attributes.has_value()) {
+    return base::unexpected(attributes.error());
+  }
+
+  // If output padding is not present, the values are assumed to be [0,0].
+  const auto output_padding = options->getOutputPaddingOr({0, 0});
+  if (output_padding.size() != 2) {
+    return base::unexpected("The length of output padding should be 2.");
+  }
+  attributes.value().output_padding = webnn::Size2d<uint32_t>{
+      .height = output_padding[0], .width = output_padding[1]};
+
+  if (options->hasOutputSizes()) {
+    auto output_sizes = options->getOutputSizesOr({});
+    if (output_sizes.size() != 2) {
+      return base::unexpected("The length of output sizes should be 2.");
+    }
+    attributes.value().output_sizes = webnn::Size2d<uint32_t>{
+        .height = output_sizes[0], .width = output_sizes[1]};
+  }
+
+  attributes.value().filter_layout =
+      BlinkConvTranspose2dFilterLayoutToComponent(
+          options->filterLayout().AsEnum());
+
   return attributes;
 }
 
@@ -453,177 +515,6 @@
   return ml_context_.Get();
 }
 
-// static
-absl::optional<webnn::PaddingSizes>
-MLGraphBuilder::CalculateConvTransposed2dPadding(
-    V8MLAutoPad::Enum auto_pad,
-    const uint32_t input_size,
-    const uint32_t filter_size,
-    const uint32_t stride,
-    const uint32_t dilation,
-    const uint32_t output_padding) {
-  auto checked_output_size =
-      base::MakeCheckedNum<uint32_t>(input_size) * stride;
-  auto checked_effective_filter_size =
-      (base::MakeCheckedNum<uint32_t>(filter_size) - 1) * dilation + 1;
-  auto checked_total_padding = stride * (input_size - 1) +
-                               checked_effective_filter_size + output_padding -
-                               checked_output_size;
-  base::CheckedNumeric<uint32_t> checked_padding_begin, checked_padding_end;
-  switch (auto_pad) {
-    case V8MLAutoPad::Enum::kSameUpper:
-      checked_padding_begin = checked_total_padding / 2;
-      checked_padding_end = (checked_total_padding + 1) / 2;
-      break;
-    case V8MLAutoPad::Enum::kSameLower:
-      checked_padding_begin = (checked_total_padding + 1) / 2;
-      checked_padding_end = checked_total_padding / 2;
-      break;
-    case V8MLAutoPad::Enum::kExplicit:
-      // The case has been ruled out before the function be called.
-      NOTREACHED_NORETURN()
-          << "Invalid auto pad value when calculating convTranspose2d padding.";
-  }
-  uint32_t padding_begin, padding_end;
-  if (!checked_padding_begin.AssignIfValid(&padding_begin) ||
-      !checked_padding_end.AssignIfValid(&padding_end)) {
-    return absl::nullopt;
-  }
-  return webnn::PaddingSizes({.begin = padding_begin, .end = padding_end});
-}
-
-// Calculate the output size for convTranspose2d based on WebNN spec:
-// https://www.w3.org/TR/webnn/#api-mlgraphbuilder-convtranspose2d
-// Return the calculated output size if no error.
-base::expected<uint32_t, String> CalculateConvTranspose2dOutputSize(
-    const uint32_t input_size,
-    const uint32_t filter_size,
-    const uint32_t beginning_padding,
-    const uint32_t ending_padding,
-    const uint32_t stride,
-    const uint32_t dilation,
-    const uint32_t output_padding) {
-  // Calculate the dilated filter sizes.
-  auto checked_effective_filter_size =
-      (base::MakeCheckedNum<uint32_t>(filter_size) - 1) * dilation + 1;
-  if (!checked_effective_filter_size.IsValid()) {
-    return base::unexpected("The effective filter size is too large.");
-  }
-  auto checked_output_size =
-      (base::MakeCheckedNum<uint32_t>(input_size) - 1) * stride +
-      checked_effective_filter_size - beginning_padding - ending_padding +
-      output_padding;
-  // Check if the checked_output_size is valid.
-  if (!checked_output_size.IsValid()) {
-    return base::unexpected(
-        "The stride is too large or the input size is to small for padding.");
-  }
-
-  return checked_output_size.ValueOrDie();
-}
-
-// static
-base::expected<MLGraphBuilder::Size2D, String>
-MLGraphBuilder::ValidateAndCalculateConvTranspose2dOutputSizes(
-    const uint32_t input_height,
-    const uint32_t input_width,
-    const uint32_t filter_height,
-    const uint32_t filter_width,
-    const Vector<uint32_t>& padding,
-    const Vector<uint32_t>& strides,
-    const Vector<uint32_t>& dilations,
-    const Vector<uint32_t>& output_padding,
-    const V8MLAutoPad auto_pad) {
-  // Validate padding and get its values.
-  if (padding.size() != 4) {
-    return base::unexpected("The length of padding should be 4.");
-  }
-  uint32_t padding_beginning_height = padding[0];
-  uint32_t padding_ending_height = padding[1];
-  uint32_t padding_beginning_width = padding[2];
-  uint32_t padding_ending_width = padding[3];
-
-  // Validate strides and get its values.
-  if (strides.size() != 2) {
-    return base::unexpected("The length of strides should be 2.");
-  }
-  if (base::ranges::any_of(strides, [](uint32_t x) { return x == 0; })) {
-    return base::unexpected("All strides should be greater than 0.");
-  }
-  const uint32_t stride_height = strides[0];
-  const uint32_t stride_width = strides[1];
-
-  // Validate dilations and get its values.
-  if (dilations.size() != 2) {
-    return base::unexpected("The length of dilations should be 2.");
-  }
-  if (base::ranges::any_of(dilations, [](uint32_t x) { return x == 0; })) {
-    return base::unexpected("All dilations should be greater than 0.");
-  }
-  const uint32_t dilation_height = dilations[0];
-  const uint32_t dilation_width = dilations[1];
-
-  // Validate output padding and get its values.
-  if (output_padding.size() != 2) {
-    return base::unexpected("The length of outputPadding should be 2.");
-  }
-  const uint32_t outputPadding_height = output_padding[0];
-  const uint32_t outputPadding_width = output_padding[1];
-  if (outputPadding_height >= stride_height ||
-      outputPadding_width >= stride_width) {
-    return base::unexpected(
-        "The output padding must be smaller than the stride along the same "
-        "dimension.");
-  }
-
-  // When the autoPad is other than "explicit", the values in the
-  // options.padding array are ignored and the explicit padding values need to
-  // be calculated.
-  if (auto_pad != V8MLAutoPad::Enum::kExplicit) {
-    auto padding_sizes_height =
-        MLGraphBuilder::CalculateConvTransposed2dPadding(
-            auto_pad.AsEnum(), input_height, filter_height, stride_height,
-            dilation_height, outputPadding_height);
-    if (!padding_sizes_height) {
-      return base::unexpected(
-          "Overflow occurred when calculating the padding along the height "
-          "dimension.");
-    }
-    padding_beginning_height = padding_sizes_height->begin;
-    padding_ending_height = padding_sizes_height->end;
-    auto padding_sizes_width = MLGraphBuilder::CalculateConvTransposed2dPadding(
-        auto_pad.AsEnum(), input_width, filter_width, stride_width,
-        dilation_width, outputPadding_width);
-    if (!padding_sizes_width) {
-      return base::unexpected(
-          "Overflow occurred when calculating the padding along the width "
-          "dimension.");
-    }
-    padding_beginning_width = padding_sizes_width->begin;
-    padding_ending_width = padding_sizes_width->end;
-  }
-
-  auto output_height = CalculateConvTranspose2dOutputSize(
-      input_height, filter_height, padding_beginning_height,
-      padding_ending_height, stride_height, dilation_height,
-      outputPadding_height);
-  if (!output_height.has_value()) {
-    return base::unexpected("Failed to calculate the output height: " +
-                            output_height.error());
-  }
-
-  auto output_width = CalculateConvTranspose2dOutputSize(
-      input_width, filter_width, padding_beginning_width, padding_ending_width,
-      stride_width, dilation_width, outputPadding_width);
-  if (!output_width.has_value()) {
-    return base::unexpected("Failed to calculate the output width: " +
-                            output_width.error());
-  }
-
-  return Size2D(
-      {.height = output_height.value(), .width = output_width.value()});
-}
-
 MLOperand* MLGraphBuilder::input(String name,
                                  const MLOperandDescriptor* desc,
                                  ExceptionState& exception_state) {
@@ -756,191 +647,22 @@
     const MLOperand* filter,
     const MLConvTranspose2dOptions* options,
     ExceptionState& exception_state) {
-  // Validate input operand and set its sizes.
-  const auto input_shape = input->Dimensions();
-  if (input_shape.size() != 4) {
+  auto convTranspose2d_attributes = ConvertToConvTranspose2dAttributes(options);
+  if (!convTranspose2d_attributes.has_value()) {
     exception_state.ThrowDOMException(DOMExceptionCode::kDataError,
-                                      "The input should be a 4-D tensor.");
+                                      convTranspose2d_attributes.error());
     return nullptr;
   }
-  // The input layout option specifies the layout format of the input tensor.
-  uint32_t input_batches, input_channels, input_height, input_width;
-  switch (options->inputLayout().AsEnum()) {
-    case V8MLInputOperandLayout::Enum::kNchw:
-      // "nchw": [batches, input_channels, height, width]
-      input_batches = input_shape[0];
-      input_channels = input_shape[1];
-      input_height = input_shape[2];
-      input_width = input_shape[3];
-      break;
-    case V8MLInputOperandLayout::Enum::kNhwc:
-      // "nhwc": [batches, height, width, input_channels]
-      input_batches = input_shape[0];
-      input_height = input_shape[1];
-      input_width = input_shape[2];
-      input_channels = input_shape[3];
-      break;
-  }
 
-  // Validate filter operand and set its sizes.
-  if (filter->Type() != input->Type()) {
+  auto validated_output = webnn::ValidateConvTranspose2dAndInferOutput(
+      ConvertToComponentOperand(input), ConvertToComponentOperand(filter),
+      std::move(convTranspose2d_attributes.value()));
+  if (!validated_output.has_value()) {
     exception_state.ThrowDOMException(
         DOMExceptionCode::kDataError,
-        "The filter type doesn't match the input type.");
+        WTF::String::FromUTF8(validated_output.error()));
     return nullptr;
   }
-  const auto filter_shape = filter->Dimensions();
-  if (filter_shape.size() != 4) {
-    exception_state.ThrowDOMException(DOMExceptionCode::kDataError,
-                                      "The filter should be a 4-D tensor.");
-    return nullptr;
-  }
-  // The filter layout specifies the filter layout format.
-  uint32_t filter_height, filter_width, output_channels, filter_input_channels;
-  switch (options->filterLayout().AsEnum()) {
-    case V8MLConvTranspose2dFilterOperandLayout::Enum::kHwoi:
-      // "hwoi": [height, width, output_channels, input_channels/groups]
-      filter_height = filter_shape[0];
-      filter_width = filter_shape[1];
-      output_channels = filter_shape[2];
-      filter_input_channels = filter_shape[3];
-      break;
-    case V8MLConvTranspose2dFilterOperandLayout::Enum::kOhwi:
-      // "ohwi": [output_channels, height, width, input_channels/groups]
-      output_channels = filter_shape[0];
-      filter_height = filter_shape[1];
-      filter_width = filter_shape[2];
-      filter_input_channels = filter_shape[3];
-      break;
-    case V8MLConvTranspose2dFilterOperandLayout::Enum::kIohw:
-      // "iohw": [input_channels/groups, output_channels, height, width]
-      filter_input_channels = filter_shape[0];
-      output_channels = filter_shape[1];
-      filter_height = filter_shape[2];
-      filter_width = filter_shape[3];
-      break;
-  }
-  // Validate bias operand if it is present.
-  if (options->hasBias()) {
-    const auto bias_shape = options->bias()->Dimensions();
-    if (bias_shape.size() != 1) {
-      exception_state.ThrowDOMException(DOMExceptionCode::kDataError,
-                                        "The bias should be a 1-D tensor.");
-      return nullptr;
-    }
-    if (bias_shape[0] != output_channels) {
-      exception_state.ThrowDOMException(
-          DOMExceptionCode::kDataError,
-          String::Format("The bias shape should be [%u].", output_channels));
-      return nullptr;
-    }
-    if (options->bias()->Type() != input->Type()) {
-      exception_state.ThrowDOMException(
-          DOMExceptionCode::kDataError,
-          "The bias type doesn't match input type.");
-      return nullptr;
-    }
-  }
-  // Validate groups.
-  if (options->groups() == 0) {
-    exception_state.ThrowDOMException(DOMExceptionCode::kDataError,
-                                      "The groups should be greater than 0.");
-    return nullptr;
-  }
-  if (input_channels % options->groups() != 0 ||
-      filter_input_channels != input_channels / options->groups()) {
-    exception_state.ThrowDOMException(DOMExceptionCode::kDataError,
-                                      "The groups must evenly divide the input "
-                                      "channels to filter input channels.");
-    return nullptr;
-  }
-
-  // Validate and calculate output sizes.
-  uint32_t output_height, output_width;
-  if (options->hasOutputSizes()) {
-    const auto output_sizes = options->getOutputSizesOr({});
-    if (output_sizes.size() != 2) {
-      exception_state.ThrowDOMException(
-          DOMExceptionCode::kDataError,
-          "The length of outputSizes should be 2.");
-      return nullptr;
-    }
-    output_height = output_sizes[0];
-    output_width = output_sizes[1];
-    if (output_height == 0 || output_width == 0) {
-      exception_state.ThrowDOMException(
-          DOMExceptionCode::kDataError,
-          "All output sizes should be greater than 0.");
-      return nullptr;
-    }
-    // If strides is not present, the values are assumed to be [1,1].
-    const auto strides = options->getStridesOr({1, 1});
-    const auto calculated_output_sizes =
-        ValidateAndCalculateConvTranspose2dOutputSizes(
-            input_height, input_width, filter_height, filter_width,
-            // If padding is not present, the values are assumed to be
-            // [0,0,0,0].
-            options->getPaddingOr({0, 0, 0, 0}), strides,
-            // If dilations is not present, the values are assumed to be [1, 1].
-            options->getDilationsOr({1, 1}),
-            // Calculate the output sizes without the output padding.
-            {0, 0}, options->autoPad());
-    if (!calculated_output_sizes.has_value()) {
-      exception_state.ThrowDOMException(DOMExceptionCode::kDataError,
-                                        calculated_output_sizes.error());
-      return nullptr;
-    }
-    auto calculated_output_height = calculated_output_sizes->height;
-    auto calculated_output_width = calculated_output_sizes->width;
-    if (output_height < calculated_output_height ||
-        output_height >= calculated_output_height + strides[0]) {
-      exception_state.ThrowDOMException(
-          DOMExceptionCode::kDataError,
-          "The height of output sizes is invalid.");
-      return nullptr;
-    }
-    if (output_width < calculated_output_width ||
-        output_width >= calculated_output_width + strides[1]) {
-      exception_state.ThrowDOMException(
-          DOMExceptionCode::kDataError,
-          "The width of output sizes is invalid.");
-      return nullptr;
-    }
-    ml_context_->LogConsoleWarning(
-        "When output sizes are specified, output padding argument is ignored");
-  } else {
-    const auto output_sizes = ValidateAndCalculateConvTranspose2dOutputSizes(
-        input_height, input_width, filter_height, filter_width,
-        // If padding is not present, the values are assumed to be [0,0,0,0].
-        options->getPaddingOr({0, 0, 0, 0}),
-        // If strides is not present, the values are assumed to be [1,1].
-        options->getStridesOr({1, 1}),
-        // If dilations is not present, the values are assumed to be [1, 1].
-        options->getDilationsOr({1, 1}),
-        // If outputPadding is not present, the values are assumed to be [0, 0].
-        options->getOutputPaddingOr({0, 0}), options->autoPad());
-    if (!output_sizes.has_value()) {
-      exception_state.ThrowDOMException(DOMExceptionCode::kDataError,
-                                        output_sizes.error());
-      return nullptr;
-    }
-    output_height = output_sizes->height;
-    output_width = output_sizes->width;
-  }
-  // The input layout option specifies the layout format of the output tensor.
-  Vector<uint32_t> output_shape;
-  switch (options->inputLayout().AsEnum()) {
-    case V8MLInputOperandLayout::Enum::kNchw:
-      // "nchw": [batches, output_channels, height, width]
-      output_shape = {input_batches, output_channels, output_height,
-                      output_width};
-      break;
-    case V8MLInputOperandLayout::Enum::kNhwc:
-      // "nhwc": [batches, height, width, output_channels]
-      output_shape = {input_batches, output_height, output_width,
-                      output_channels};
-      break;
-  }
   // Create convTranspose2d operator and its output operand. Connect the
   // convTranspose2d operator to its input and output operands.
   auto* convTranspose2d = MakeGarbageCollected<MLOperator>(
@@ -950,7 +672,8 @@
     inputs.push_back(options->bias());
   }
   auto output = MLOperand::ValidateAndCreateOutput(
-      this, input->Type(), std::move(output_shape), convTranspose2d);
+      this, ComponentOperandTypeToBlink(validated_output.value().data_type),
+      Vector<uint32_t>(validated_output.value().dimensions), convTranspose2d);
   if (!output.has_value()) {
     exception_state.ThrowDOMException(DOMExceptionCode::kDataError,
                                       output.error());
@@ -999,7 +722,9 @@
 BUILD_ELEMENTWISE_UNARY_OP(sin, kSin, webnn::DataTypeConstraint::kFloat)
 BUILD_ELEMENTWISE_UNARY_OP(tan, kTan, webnn::DataTypeConstraint::kFloat)
 BUILD_ELEMENTWISE_UNARY_OP(erf, kErf, webnn::DataTypeConstraint::kFloat)
-BUILD_ELEMENTWISE_UNARY_OP(identity, kIdentity, webnn::DataTypeConstraint::kAll)
+BUILD_ELEMENTWISE_UNARY_OP(identity,
+                           kIdentity,
+                           webnn::DataTypeConstraintSet::All())
 BUILD_ELEMENTWISE_UNARY_OP(logicalNot,
                            kLogicalNot,
                            {webnn::Operand::DataType::kUint8})
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h
index 3ffbc46..6a368b10 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder.h
@@ -60,40 +60,11 @@
 
   MLContext* GetContext() const;
 
-  // Calculate the effective padding for convTranspose2d based on WebNN auto
-  // padding rules.
-  //
-  // TODO(crbug.com/1273291): Add the link to WebNN spec's algorithm once it is
-  // defined, tracked by: https://github.com/webmachinelearning/webnn/issues/326
-  static absl::optional<webnn::PaddingSizes> CalculateConvTransposed2dPadding(
-      V8MLAutoPad::Enum auto_pad,
-      const uint32_t input_size,
-      const uint32_t filter_size,
-      const uint32_t stride,
-      const uint32_t dilation,
-      const uint32_t output_padding);
-
   struct Size2D {
     uint32_t height;
     uint32_t width;
   };
 
-  // Validate and calculate the output spatial dimensions of convTranspose2d
-  // given input sizes, filter sizes, padding, strides, dilations and output
-  // padding. Return the calculated output sizes in double precision floating
-  // point number if no errors.
-  static base::expected<Size2D, String>
-  ValidateAndCalculateConvTranspose2dOutputSizes(
-      const uint32_t input_height,
-      const uint32_t input_width,
-      const uint32_t filter_height,
-      const uint32_t filter_width,
-      const Vector<uint32_t>& padding,
-      const Vector<uint32_t>& strides,
-      const Vector<uint32_t>& dilations,
-      const Vector<uint32_t>& output_padding,
-      const V8MLAutoPad auto_pad);
-
   // ml_graph_builder.idl
   MLOperand* input(String name,
                    const MLOperandDescriptor* desc,
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.cc
index 22853c02..b8a22f94 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.h"
 
 #include <algorithm>
+#include <limits>
 #include <memory>
 
 #include "base/numerics/checked_math.h"
@@ -24,8 +25,8 @@
 
 namespace blink {
 
-const uint32_t kSquareRootOfSizeMax =
-    base::saturated_cast<uint32_t>(std::sqrt(SIZE_MAX));
+const uint32_t kSquareRootOfSizeMax = base::saturated_cast<uint32_t>(
+    std::sqrt(std::numeric_limits<size_t>::max()));
 
 class MLGraphBuilderTest : public testing::Test {
  public:
@@ -1263,6 +1264,20 @@
     EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 1, 5, 5}));
   }
   {
+    // Test convTranspose2d with padding=1, groups=3.
+    auto* input =
+        BuildInput(builder, "input", {1, 1, 5, 5},
+                   V8MLOperandType::Enum::kFloat32, scope.GetExceptionState());
+    auto* filter =
+        BuildConstant(builder, {1, 1, 3, 3}, V8MLOperandType::Enum::kFloat32,
+                      scope.GetExceptionState());
+    auto* options = MLConvTranspose2dOptions::Create();
+    options->setPadding({1, 1, 1, 1});
+    options->setGroups(3);
+    auto* output = BuildConvTranspose2d(scope, builder, input, filter, options);
+    EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 3, 5, 5}));
+  }
+  {
     // Test convTranspose2d with autopad="explicit", strides=2.
     auto* input =
         BuildInput(builder, "input", {1, 1, 3, 3},
@@ -1547,7 +1562,8 @@
               "All dilations should be greater than 0.");
   }
   {
-    // Test throwing exception when input_channels % groups() != 0.
+    // Test throwing exception when the input channels is not equal to the
+    // filter input channels.
     auto* input =
         BuildInput(builder, "input", {1, 4, 5, 5},
                    V8MLOperandType::Enum::kFloat32, scope.GetExceptionState());
@@ -1562,28 +1578,25 @@
     EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(),
               DOMExceptionCode::kDataError);
     EXPECT_EQ(scope.GetExceptionState().Message(),
-              "The groups must evenly divide the input "
-              "channels to filter input channels.");
+              "The input channels should equal to filter input channels.");
   }
   {
-    // Test throwing exception when filter_input_channels != input_channels /
-    // groups().
+    // Test throwing exception when output channels is too large.
     auto* input =
         BuildInput(builder, "input", {1, 4, 5, 5},
                    V8MLOperandType::Enum::kFloat32, scope.GetExceptionState());
     auto* filter =
-        BuildConstant(builder, {1, 1, 2, 2}, V8MLOperandType::Enum::kFloat32,
+        BuildConstant(builder, {4, 2, 2, 2}, V8MLOperandType::Enum::kFloat32,
                       scope.GetExceptionState());
     auto* options = MLConvTranspose2dOptions::Create();
-    options->setGroups(2);
+    options->setGroups(std::numeric_limits<uint32_t>::max());
     auto* output = builder->convTranspose2d(input, filter, options,
                                             scope.GetExceptionState());
     EXPECT_EQ(output, nullptr);
     EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(),
               DOMExceptionCode::kDataError);
     EXPECT_EQ(scope.GetExceptionState().Message(),
-              "The groups must evenly divide the input "
-              "channels to filter input channels.");
+              "The output channels is too large.");
   }
   {
     // Test throwing exception when the groups is smaller than 1.
@@ -1768,7 +1781,7 @@
     EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(),
               DOMExceptionCode::kDataError);
     EXPECT_EQ(scope.GetExceptionState().Message(),
-              "The length of outputPadding should be 2.");
+              "The length of output padding should be 2.");
   }
   {
     // Test throwing exception when the outputPadding is greater than stride
@@ -1810,7 +1823,7 @@
     EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(),
               DOMExceptionCode::kDataError);
     EXPECT_EQ(scope.GetExceptionState().Message(),
-              "The length of outputSizes should be 2.");
+              "The length of output sizes should be 2.");
   }
   {
     // Test throwing exception due to underflow when calculating the output
@@ -1832,7 +1845,7 @@
               DOMExceptionCode::kDataError);
     EXPECT_EQ(scope.GetExceptionState().Message(),
               "Failed to calculate the output height: The stride is too large "
-              "or the input size is to small for padding.");
+              "or the input size is too small for padding.");
   }
   {
     // Test throwing exception due to outputSizes values are smaller than the
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.cc
index f3aa228..9e11c5c 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_type_converter.cc
@@ -7,6 +7,7 @@
 #include "base/ranges/algorithm.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_clamp_options.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_conv_2d_options.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_conv_transpose_2d_options.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_elu_options.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_gemm_options.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_leaky_relu_options.h"
@@ -214,6 +215,7 @@
   return blink_mojom::Operation::NewConcat(std::move(concat_mojo));
 }
 
+template <typename MLConv2dOptionsType>
 base::expected<OperationPtr, String> CreateConv2dOperation(
     const OperandToIdMap& operand_to_id_map,
     const MLOperator* conv2d) {
@@ -225,16 +227,10 @@
   conv2d_mojo->output_operand_id =
       GetOperatorOutputId(conv2d, operand_to_id_map);
 
-  const auto* options = static_cast<const MLConv2dOptions*>(conv2d->Options());
+  const auto* options =
+      static_cast<const MLConv2dOptionsType*>(conv2d->Options());
   CHECK(options);
-  if (options->filterLayout().AsEnum() !=
-      blink::V8MLConv2dFilterOperandLayout::Enum::kOihw) {
-    // The filter layout is being discussed to simplify other variants in WebNN
-    // working group https://github.com/webmachinelearning/webnn/issues/324.
-    return base::unexpected(
-        String::Format("The filter layout %s is not supported.",
-                       options->filterLayout().AsCStr()));
-  }
+
   // If strides is not present, the values are assumed to be [1,1].
   auto strides = options->getStridesOr({1, 1});
   CHECK_EQ(strides.size(), 2u);
@@ -254,38 +250,105 @@
   // Get height and width of input for calculating padding.
   auto input_size = mojo::GetInputOperandSize2d(
       conv2d->Inputs()[0].Get(), options->inputLayout().AsEnum());
-  // Get height and width of filter operand for calculating padding.
+
+  // Get and validate filter.
+  CHECK_GT(conv2d->Inputs().size(), 1u);
   const auto* filter = conv2d->Inputs()[1].Get();
   CHECK(filter);
   const auto filter_shape = filter->Dimensions();
   CHECK_EQ(filter_shape.size(), 4u);
-  uint32_t filter_height, filter_width;
-  switch (options->filterLayout().AsEnum()) {
-    case V8MLConv2dFilterOperandLayout::Enum::kOihw:
-      // "oihw": [output_channels, input_channels/groups, height, width]
-      filter_height = filter_shape[2];
-      filter_width = filter_shape[3];
-      break;
-    case V8MLConv2dFilterOperandLayout::Enum::kHwio:
-      // "hwio": [height, width, input_channels/groups, output_channels]
-      filter_height = filter_shape[0];
-      filter_width = filter_shape[1];
-      break;
-    case V8MLConv2dFilterOperandLayout::Enum::kOhwi:
-    case V8MLConv2dFilterOperandLayout::Enum::kIhwo:
-      // "ohwi": [output_channels, height, width, input_channels/groups]
-      // "ihwo": [input_channels/groups, height, width, output_channels]
-      filter_height = filter_shape[1];
-      filter_width = filter_shape[2];
-      break;
+
+  webnn::Padding2d padding;
+  if constexpr (std::is_same<MLConv2dOptionsType, MLConv2dOptions>::value) {
+    conv2d_mojo->type = blink_mojom::Conv2d::Type::kDirect;
+
+    if (options->filterLayout().AsEnum() !=
+        blink::V8MLConv2dFilterOperandLayout::Enum::kOihw) {
+      // The filter layout is being discussed to simplify other variants in
+      // WebNN working group
+      // https://github.com/webmachinelearning/webnn/issues/324.
+      return base::unexpected(
+          String::Format("The filter layout %s is not supported.",
+                         options->filterLayout().AsCStr()));
+    }
+    // Get height and width of filter operand for calculating padding.
+    auto filter_height = filter_shape[2];
+    auto filter_width = filter_shape[3];
+
+    // Calculate the padding given input sizes, filter size, padding, strides
+    // and dilations.
+    padding = blink::CalculatePadding2D(
+        options, input_size.height, input_size.width, filter_height,
+        filter_width, conv2d_mojo->strides->height, conv2d_mojo->strides->width,
+        conv2d_mojo->dilations->height, conv2d_mojo->dilations->width);
+  } else if constexpr (std::is_same<MLConv2dOptionsType,
+                                    MLConvTranspose2dOptions>::value) {
+    conv2d_mojo->type = blink_mojom::Conv2d::Type::kTransposed;
+
+    if (options->filterLayout().AsEnum() !=
+        blink::V8MLConvTranspose2dFilterOperandLayout::Enum::kIohw) {
+      // The filter layout is being discussed to simplify other variants in
+      // WebNN working group
+      // https://github.com/webmachinelearning/webnn/issues/324.
+      return base::unexpected(
+          String::Format("The filter layout %s is not supported.",
+                         options->filterLayout().AsCStr()));
+    }
+    // Get height and width of filter operand for calculating padding.
+    auto filter_height = filter_shape[2];
+    auto filter_width = filter_shape[3];
+
+    // Calculate output padding of convTranspose2d for calculating padding.
+    const Vector<uint32_t> default_output_padding({0, 0});
+    uint32_t output_padding_height, output_padding_width;
+    if (options->hasOutputSizes()) {
+      const auto calculated_output_sizes = CalculateConvTransposeOutputSize2D(
+          options, input_size.height, input_size.width, filter_height,
+          filter_width, conv2d_mojo->strides->height,
+          conv2d_mojo->strides->width, conv2d_mojo->dilations->height,
+          conv2d_mojo->dilations->width,
+          // Calculate output size without output padding.
+          0u, 0u);
+
+      const auto* output = conv2d->Outputs()[0].Get();
+      CHECK(output);
+      const auto output_shape = output->Dimensions();
+      CHECK_EQ(output_shape.size(), 4u);
+      uint32_t output_height, output_width;
+      switch (conv2d_mojo->input_layout) {
+        case blink_mojom::InputOperandLayout::kChannelsFirst: {
+          output_height = output_shape[2];
+          output_width = output_shape[3];
+          break;
+        }
+        case blink_mojom::InputOperandLayout::kChannelsLast: {
+          output_height = output_shape[1];
+          output_width = output_shape[2];
+          break;
+        }
+      }
+      CHECK_GE(output_height, calculated_output_sizes.height);
+      output_padding_height = output_height - calculated_output_sizes.height;
+      CHECK_GE(output_width, calculated_output_sizes.width);
+      output_padding_width = output_width - calculated_output_sizes.width;
+    } else {
+      output_padding_height =
+          options->getOutputPaddingOr(default_output_padding)[0];
+      output_padding_width =
+          options->getOutputPaddingOr(default_output_padding)[1];
+    }
+
+    // Calculate the padding given input sizes, filter size, padding, strides,
+    // dilations.
+    padding = blink::CalculateConvTransposePadding2D(
+        options, input_size.height, input_size.width, filter_height,
+        filter_width, conv2d_mojo->strides->height, conv2d_mojo->strides->width,
+        conv2d_mojo->dilations->height, conv2d_mojo->dilations->width,
+        output_padding_height, output_padding_width);
+  } else {
+    NOTREACHED_NORETURN();
   }
 
-  // Calculate the padding given input sizes, filter size, padding, strides and
-  // dilations.
-  auto padding = blink::CalculatePadding2D(
-      options, input_size.height, input_size.width, filter_height, filter_width,
-      conv2d_mojo->strides->height, conv2d_mojo->strides->width,
-      conv2d_mojo->dilations->height, conv2d_mojo->dilations->width);
   // The order of sequence array is [beginning_height, ending_height,
   // beginning_width, ending_width].
   conv2d_mojo->padding = blink_mojom::Padding2d::New(
@@ -733,7 +796,10 @@
     case MLOperator::OperatorKind::kConcat:
       return CreateConcatOperation(operand_to_id_map, op);
     case MLOperator::OperatorKind::kConv2d:
-      return CreateConv2dOperation(operand_to_id_map, op);
+      return CreateConv2dOperation<MLConv2dOptions>(operand_to_id_map, op);
+    case MLOperator::OperatorKind::kConvTranspose2d:
+      return CreateConv2dOperation<MLConvTranspose2dOptions>(operand_to_id_map,
+                                                             op);
     case MLOperator::OperatorKind::kAdd:
       [[fallthrough]];
     case MLOperator::OperatorKind::kSub:
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.cc
index dedebfe..91a5b779 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.cc
@@ -218,4 +218,85 @@
   std::iota(default_axes.begin(), default_axes.end(), 0);
   return default_axes;
 }
+
+webnn::Padding2d CalculateConvTransposePadding2D(
+    const blink::MLConvTranspose2dOptions* options,
+    uint32_t input_height,
+    uint32_t input_width,
+    uint32_t filter_height,
+    uint32_t filter_width,
+    uint32_t stride_height,
+    uint32_t stride_width,
+    uint32_t dilation_height,
+    uint32_t dilation_width,
+    uint32_t output_padding_height,
+    uint32_t output_padding_width) {
+  webnn::Padding2d padding;
+  switch (options->autoPad().AsEnum()) {
+    case V8MLAutoPad::Enum::kExplicit: {
+      // Set the padding from WebNN explicit padding that is in
+      // [beginning_height, ending_height, beginning_width, ending_width],
+      // default to 0.
+      auto ml_padding = options->getPaddingOr({0, 0, 0, 0});
+      CHECK_EQ(ml_padding.size(), 4u);
+      padding.beginning.height = ml_padding[0];
+      padding.ending.height = ml_padding[1];
+      padding.beginning.width = ml_padding[2];
+      padding.ending.width = ml_padding[3];
+      break;
+    }
+    case V8MLAutoPad::Enum::kSameUpper:
+    case V8MLAutoPad::Enum::kSameLower: {
+      webnn::AutoPad auto_pad =
+          BlinkAutoPadToComponent(options->autoPad().AsEnum());
+      // Calculate padding based on WebNN auto padding mode and sizes.
+      auto padding_sizes_height = webnn::CalculateConvTranspose2dPadding(
+          auto_pad, input_height, filter_height, stride_height, dilation_height,
+          output_padding_height);
+      CHECK(padding_sizes_height);
+      padding.beginning.height = padding_sizes_height.value().begin;
+      padding.ending.height = padding_sizes_height.value().end;
+      auto padding_sizes_width = webnn::CalculateConvTranspose2dPadding(
+          auto_pad, input_width, filter_width, stride_width, dilation_width,
+          output_padding_width);
+      CHECK(padding_sizes_width);
+      padding.beginning.width = padding_sizes_width.value().begin;
+      padding.ending.width = padding_sizes_width.value().end;
+      break;
+    }
+  }
+  return padding;
+}
+
+webnn::Size2d<uint32_t> CalculateConvTransposeOutputSize2D(
+    const blink::MLConvTranspose2dOptions* options,
+    uint32_t input_height,
+    uint32_t input_width,
+    uint32_t filter_height,
+    uint32_t filter_width,
+    uint32_t stride_height,
+    uint32_t stride_width,
+    uint32_t dilation_height,
+    uint32_t dilation_width,
+    uint32_t output_padding_height,
+    uint32_t output_padding_width) {
+  const auto padding = CalculateConvTransposePadding2D(
+      options, input_height, input_width, filter_height, filter_width,
+      stride_height, stride_width, dilation_height, dilation_width,
+      output_padding_height, output_padding_width);
+  const auto output_height = webnn::CalculateConvTranspose2dOutputSize(
+      input_height, filter_height, padding.beginning.height,
+      padding.ending.height, stride_height, dilation_height,
+      output_padding_height);
+  CHECK(output_height.has_value());
+
+  const auto output_width = webnn::CalculateConvTranspose2dOutputSize(
+      input_width, filter_width, padding.beginning.width, padding.ending.width,
+      stride_width, dilation_width, output_padding_width);
+  CHECK(output_width.has_value());
+
+  return webnn::Size2d<uint32_t>{.height = output_height.value(),
+                                 .width = output_width.value()};
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.h b/third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.h
index 4dae17f..26ccb62 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.h
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_utils.h
@@ -10,6 +10,7 @@
 
 #include "components/ml/webnn/graph_validation_utils.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_auto_pad.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_conv_transpose_2d_options.h"
 #include "third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
 #include "third_party/blink/renderer/modules/ml/webnn/ml_graph.h"
@@ -130,6 +131,34 @@
   return padding;
 }
 
+// Helper to get padding sizes for convolution transpose 2d Node.
+webnn::Padding2d CalculateConvTransposePadding2D(
+    const blink::MLConvTranspose2dOptions* options,
+    uint32_t input_height,
+    uint32_t input_width,
+    uint32_t filter_height,
+    uint32_t filter_width,
+    uint32_t stride_height,
+    uint32_t stride_width,
+    uint32_t dilation_height,
+    uint32_t dilation_width,
+    uint32_t output_padding_height,
+    uint32_t output_padding_width);
+
+// Helper to get output sizes for convolution transpose 2d Node.
+webnn::Size2d<uint32_t> CalculateConvTransposeOutputSize2D(
+    const blink::MLConvTranspose2dOptions* options,
+    uint32_t input_height,
+    uint32_t input_width,
+    uint32_t filter_height,
+    uint32_t filter_width,
+    uint32_t stride_height,
+    uint32_t stride_width,
+    uint32_t dilation_height,
+    uint32_t dilation_width,
+    uint32_t output_padding_height,
+    uint32_t output_padding_width);
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_GRAPH_UTILS_H_
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.cc
index 8fdf77e..9986bc2 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_xnnpack.cc
@@ -16,6 +16,7 @@
 #include "base/thread_annotations.h"
 #include "base/trace_event/typed_macros.h"
 #include "build/buildflag.h"
+#include "components/ml/webnn/graph_validation_utils.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_clamp_options.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_compute_result.h"
@@ -617,41 +618,14 @@
     uint32_t dilation_width,
     uint32_t output_padding_height,
     uint32_t output_padding_width) {
-  XnnPadding2D xnn_padding;
-  switch (options->autoPad().AsEnum()) {
-    case V8MLAutoPad::Enum::kExplicit: {
-      // Set the XNNPACK convTranspose2d padding from WebNN explicit padding
-      // that is in [beginning_height, ending_height, beginning_width,
-      // ending_width], default to 0.
-      const Vector<uint32_t> default_pads({0, 0, 0, 0});
-      xnn_padding.top = options->getPaddingOr(default_pads)[0];
-      xnn_padding.bottom = options->getPaddingOr(default_pads)[1];
-      xnn_padding.left = options->getPaddingOr(default_pads)[2];
-      xnn_padding.right = options->getPaddingOr(default_pads)[3];
-      break;
-    }
-    case V8MLAutoPad::Enum::kSameUpper:
-    case V8MLAutoPad::Enum::kSameLower: {
-      // Calculate the XNNPACK convTranspose2d padding based on WebNN auto
-      // padding mode and sizes.
-      auto padding_sizes_height =
-          MLGraphBuilder::CalculateConvTransposed2dPadding(
-              options->autoPad().AsEnum(), input_height, filter_height,
-              stride_height, dilation_height, output_padding_height);
-      CHECK(padding_sizes_height);
-      xnn_padding.top = padding_sizes_height.value().begin;
-      xnn_padding.bottom = padding_sizes_height.value().end;
-      auto padding_sizes_width =
-          MLGraphBuilder::CalculateConvTransposed2dPadding(
-              options->autoPad().AsEnum(), input_width, filter_width,
-              stride_width, dilation_width, output_padding_width);
-      CHECK(padding_sizes_width);
-      xnn_padding.left = padding_sizes_width.value().begin;
-      xnn_padding.right = padding_sizes_width.value().end;
-      break;
-    }
-  }
-  return xnn_padding;
+  auto padding = blink::CalculateConvTransposePadding2D(
+      options, input_height, input_width, filter_height, filter_width,
+      stride_height, stride_width, dilation_height, dilation_width,
+      output_padding_height, output_padding_width);
+  return XnnPadding2D{.top = padding.beginning.height,
+                      .bottom = padding.ending.height,
+                      .left = padding.beginning.width,
+                      .right = padding.ending.width};
 }
 
 xnn_status DefineXnnNodeForConv2d(xnn_subgraph_t subgraph,
@@ -874,20 +848,15 @@
   if (options->hasOutputSizes()) {
     // Calculate output padding of XNNPACK convTranspose2d using validated
     // calculated output sizes.
-    const auto calculated_output_sizes =
-        MLGraphBuilder::ValidateAndCalculateConvTranspose2dOutputSizes(
-            input_height, input_width, filter_height, filter_width,
-            // If padding is not present, the values are assumed to be
-            // [0,0,0,0].
-            options->getPaddingOr({0, 0, 0, 0}), {stride_height, stride_width},
-            {dilation_height, dilation_width},
-            // Calculate the output sizes without output padding.
-            {0u, 0u}, options->autoPad());
-    CHECK(calculated_output_sizes.has_value());
-    CHECK_GE(output_height, calculated_output_sizes->height);
-    output_padding_height = output_height - calculated_output_sizes->height;
-    CHECK_GE(output_width, calculated_output_sizes->width);
-    output_padding_width = output_width - calculated_output_sizes->width;
+    const auto calculated_output_sizes = CalculateConvTransposeOutputSize2D(
+        options, input_height, input_width, filter_height, filter_width,
+        stride_height, stride_width, dilation_height, dilation_width,
+        // Calculate output size without output padding.
+        0u, 0u);
+    CHECK_GE(output_height, calculated_output_sizes.height);
+    output_padding_height = output_height - calculated_output_sizes.height;
+    CHECK_GE(output_width, calculated_output_sizes.width);
+    output_padding_width = output_width - calculated_output_sizes.width;
   } else {
     // Set output padding of XNNPACK convTranspose2d.
     output_padding_height =
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
index 08bdead..4778ef5 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -948,13 +948,11 @@
 
   g_s_property_tree_sequence_number++;
 
-  if (RuntimeEnabledFeatures::SimplifiedClearPropertyTreeChangeEnabled()) {
-    // For information about |sequence_number|, see:
-    // PaintPropertyNode::changed_sequence_number_|;
-    for (auto& chunk : artifact->PaintChunks()) {
-      chunk.properties.GetPropertyTreeState().ClearChangedToRoot(
-          g_s_property_tree_sequence_number);
-    }
+  // For information about |sequence_number|, see:
+  // PaintPropertyNode::changed_sequence_number_|;
+  for (auto& chunk : artifact->PaintChunks()) {
+    chunk.properties.GetPropertyTreeState().ClearChangedToRoot(
+        g_s_property_tree_sequence_number);
   }
 
   DVLOG(2) << "PaintArtifactCompositor::Update() done\n"
@@ -1264,34 +1262,6 @@
   return synthesized_clip_layers;
 }
 
-void PaintArtifactCompositor::ClearPropertyTreeChangedState() {
-  CHECK(!RuntimeEnabledFeatures::SimplifiedClearPropertyTreeChangeEnabled());
-  // For information about |sequence_number|, see:
-  // PaintPropertyNode::changed_sequence_number_|;
-  static int changed_sequence_number = 1;
-
-  for (auto& layer : pending_layers_) {
-    // The chunks ref-counted property tree state keeps the |layer|'s non-ref
-    // property tree pointers alive and all chunk property tree states should
-    // be descendants of the |layer|'s. Therefore, we can just CHECK that the
-    // first chunk's references are keeping the |layer|'s property tree state
-    // alive.
-    CHECK(!layer.Chunks().IsEmpty());
-    const auto& layer_state = layer.GetPropertyTreeState();
-    const auto& first_chunk_state =
-        layer.Chunks()[0].properties.GetPropertyTreeState();
-    CHECK(layer_state.Transform().IsAncestorOf(first_chunk_state.Transform()));
-    CHECK(layer_state.Clip().IsAncestorOf(first_chunk_state.Clip()));
-    CHECK(layer_state.Effect().IsAncestorOf(first_chunk_state.Effect()));
-
-    for (auto& chunk : layer.Chunks()) {
-      chunk.properties.GetPropertyTreeState().ClearChangedToRoot(
-          changed_sequence_number);
-    }
-  }
-  changed_sequence_number++;
-}
-
 size_t PaintArtifactCompositor::ApproximateUnsharedMemoryUsage() const {
   size_t result = sizeof(*this) + synthesized_clip_cache_.CapacityInBytes() +
                   pending_layers_.CapacityInBytes();
@@ -1309,10 +1279,11 @@
 
 bool PaintArtifactCompositor::SetScrollbarNeedsDisplay(
     CompositorElementId element_id) {
-  for (auto& pending_layer : pending_layers_) {
-    if (pending_layer.GetCompositingType() == PendingLayer::kScrollbarLayer &&
-        pending_layer.CcLayer().element_id() == element_id) {
-      pending_layer.CcLayer().SetNeedsDisplay();
+  DCHECK(root_layer_);
+  CHECK(ScrollbarDisplayItem::IsScrollbarElementId(element_id));
+  if (cc::LayerTreeHost* host = root_layer_->layer_tree_host()) {
+    if (cc::Layer* layer = host->LayerByElementId(element_id)) {
+      layer->SetNeedsDisplay();
       return true;
     }
   }
@@ -1323,15 +1294,16 @@
 bool PaintArtifactCompositor::SetScrollbarSolidColor(
     CompositorElementId element_id,
     SkColor4f color) {
-  for (auto& pending_layer : pending_layers_) {
-    if (pending_layer.GetCompositingType() == PendingLayer::kScrollbarLayer &&
-        pending_layer.CcLayer().element_id() == element_id &&
-        static_cast<cc::ScrollbarLayerBase&>(pending_layer.CcLayer())
-                .GetScrollbarLayerType() ==
-            cc::ScrollbarLayerBase::kSolidColor) {
-      static_cast<cc::SolidColorScrollbarLayer&>(pending_layer.CcLayer())
-          .SetColor(color);
-      return true;
+  DCHECK(root_layer_);
+  CHECK(ScrollbarDisplayItem::IsScrollbarElementId(element_id));
+  if (cc::LayerTreeHost* host = root_layer_->layer_tree_host()) {
+    if (cc::Layer* layer = host->LayerByElementId(element_id)) {
+      if (static_cast<cc::ScrollbarLayerBase*>(layer)
+              ->GetScrollbarLayerType() ==
+          cc::ScrollbarLayerBase::kSolidColor) {
+        static_cast<cc::SolidColorScrollbarLayer*>(layer)->SetColor(color);
+        return true;
+      }
     }
   }
   // The scrollbar isn't currently composited.
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
index e03fa7b..dbba625 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
@@ -232,8 +232,6 @@
 
   Vector<cc::Layer*> SynthesizedClipLayersForTesting() const;
 
-  void ClearPropertyTreeChangedState();
-
   size_t ApproximateUnsharedMemoryUsage() const;
 
   // Invalidates the scrollbar layer. Returns true if the scrollbar layer is
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
index 11a0e83..de25c8c 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
@@ -157,13 +157,6 @@
     layer_tree_->layer_tree_host()->LayoutAndUpdateLayers();
   }
 
-  void ClearPropertyTreeChangedState() {
-    if (!RuntimeEnabledFeatures::SimplifiedClearPropertyTreeChangeEnabled()) {
-      paint_artifact_compositor_->ClearPropertyTreeChangedState();
-    }
-    // Otherwise PaintArtifactCompositor::Update() clears the changed state.
-  }
-
   void WillBeRemovedFromFrame() {
     paint_artifact_compositor_->WillBeRemovedFromFrame();
   }
@@ -4763,7 +4756,6 @@
 
   // Change t1 but not t2.
   layer->ClearSubtreePropertyChangedForTesting();
-  ClearPropertyTreeChangedState();
   t1->Update(
       t0(), TransformPaintPropertyNode::State{{MakeTranslationMatrix(20, 30)}});
   EXPECT_EQ(PaintPropertyChangeType::kChangedOnlySimpleValues,
@@ -4790,7 +4782,6 @@
 
   // Change t2 but not t1.
   layer->ClearSubtreePropertyChangedForTesting();
-  ClearPropertyTreeChangedState();
   t2->Update(*t1, Transform3dState(MakeRotationMatrix(135)));
   EXPECT_EQ(PaintPropertyChangeType::kUnchanged, t1->NodeChanged());
   EXPECT_EQ(PaintPropertyChangeType::kChangedOnlySimpleValues,
@@ -4814,7 +4805,6 @@
 
   // Change t2 to be 2d translation which will be decomposited.
   layer->ClearSubtreePropertyChangedForTesting();
-  ClearPropertyTreeChangedState();
   t2->Update(*t1, Transform3dState(MakeTranslationMatrix(20, 30)));
   EXPECT_EQ(PaintPropertyChangeType::kUnchanged, t1->NodeChanged());
   EXPECT_EQ(PaintPropertyChangeType::kChangedOnlyValues, t2->NodeChanged());
@@ -4836,7 +4826,6 @@
 
   // Change no transform nodes, but invalidate client.
   layer->ClearSubtreePropertyChangedForTesting();
-  ClearPropertyTreeChangedState();
   client.Invalidate(PaintInvalidationReason::kBackground);
   Update(TestPaintArtifact()
              .Chunk(1)
@@ -4865,8 +4854,6 @@
 
   // Change e1 but not e2.
   layer->ClearSubtreePropertyChangedForTesting();
-  ClearPropertyTreeChangedState();
-
   EffectPaintPropertyNode::State e1_state{&t0()};
   e1_state.opacity = 0.8f;
   e1_state.compositor_element_id = e1->GetCompositorElementId();
@@ -4894,7 +4881,6 @@
 
   // Change e2 but not e1.
   layer->ClearSubtreePropertyChangedForTesting();
-  ClearPropertyTreeChangedState();
   EffectPaintPropertyNode::State e2_state{&t0()};
   e2_state.opacity = 0.9f;
   e2_state.direct_compositing_reasons = CompositingReason::kWillChangeOpacity;
@@ -5018,7 +5004,6 @@
   CreateScrollableChunk(test_artifact, scroll_state);
   auto artifact = test_artifact.Build();
   Update(artifact);
-  ClearPropertyTreeChangedState();
 
   GetPaintArtifactCompositor().UpdateRepaintedLayers(artifact);
   // This test passes if no CHECK occurs.
@@ -5042,7 +5027,6 @@
                       .RectDrawing(gfx::Rect(2, 2, 2, 2), Color::kBlack)
                       .Build();
   Update(artifact);
-  ClearPropertyTreeChangedState();
   EXPECT_EQ(PaintPropertyChangeType::kUnchanged, t1->NodeChanged());
   EXPECT_EQ(PaintPropertyChangeType::kUnchanged, t2->NodeChanged());
   EXPECT_EQ(PaintPropertyChangeType::kUnchanged, c1->NodeChanged());
diff --git a/third_party/blink/renderer/platform/graphics/paint/scrollbar_display_item.cc b/third_party/blink/renderer/platform/graphics/paint/scrollbar_display_item.cc
index 6fc2a96..ee53d1e 100644
--- a/third_party/blink/renderer/platform/graphics/paint/scrollbar_display_item.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/scrollbar_display_item.cc
@@ -144,6 +144,7 @@
   // Must check PaintController::UseCachedItemIfPossible before this function.
   DCHECK(RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() ||
          !paint_controller.UseCachedItemIfPossible(client, type));
+  CHECK(IsScrollbarElementId(element_id));
 
   paint_controller.CreateAndAppend<ScrollbarDisplayItem>(
       client, type, std::move(scrollbar), visual_rect,
diff --git a/third_party/blink/renderer/platform/graphics/paint/scrollbar_display_item.h b/third_party/blink/renderer/platform/graphics/paint/scrollbar_display_item.h
index 306803c..addeab9 100644
--- a/third_party/blink/renderer/platform/graphics/paint/scrollbar_display_item.h
+++ b/third_party/blink/renderer/platform/graphics/paint/scrollbar_display_item.h
@@ -73,6 +73,13 @@
 
   bool IsOpaque() const;
 
+  static bool IsScrollbarElementId(CompositorElementId element_id) {
+    return NamespaceFromCompositorElementId(element_id) ==
+               CompositorElementIdNamespace::kHorizontalScrollbar ||
+           NamespaceFromCompositorElementId(element_id) ==
+               CompositorElementIdNamespace::kVerticalScrollbar;
+  }
+
  private:
   friend class DisplayItem;
   bool EqualsForUnderInvalidationImpl(const ScrollbarDisplayItem&) const;
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index d3e4eb4..49da2b45 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -861,6 +861,7 @@
     {
       name: "CssDisplayRuby",
       depends_on: ["RubySimplePairing"],
+      status: "test",
     },
     {
       name: "CSSDynamicRangeLimit",
@@ -3390,10 +3391,6 @@
       base_feature: "none",
     },
     {
-      name: "SimplifiedClearPropertyTreeChange",
-      status: "stable",
-    },
-    {
       name: "SiteInitiatedMirroring",
       status: "experimental",
       base_feature: "none",
diff --git a/third_party/blink/renderer/platform/text/text_break_iterator.cc b/third_party/blink/renderer/platform/text/text_break_iterator.cc
index 59ad6cc3..801f4a12 100644
--- a/third_party/blink/renderer/platform/text/text_break_iterator.cc
+++ b/third_party/blink/renderer/platform/text/text_break_iterator.cc
@@ -361,7 +361,9 @@
             for (;;) {
               // Adjust the offset by |start_offset_| because |break_iterator|
               // has text after |start_offset_|.
-              DCHECK_GE(next_break + prior_context.length, start_offset_);
+              // TODO(crbug.com/1500931): `+1` below shouldn't be there, but it
+              // was so before and removing it hits. This is to be investigated.
+              DCHECK_GE(next_break + prior_context.length + 1, start_offset_);
               next_break = break_iterator->following(
                   next_break + prior_context.length - start_offset_);
               if (next_break >= 0) {
diff --git a/third_party/blink/web_tests/IOSTestExpectations b/third_party/blink/web_tests/IOSTestExpectations
index 30142e6..0a99ca67 100644
--- a/third_party/blink/web_tests/IOSTestExpectations
+++ b/third_party/blink/web_tests/IOSTestExpectations
@@ -257,3 +257,20 @@
 crbug.com/1432082 [ iOS16-simulator ] printing/webgl-repeated-printing-preservedrawingbuffer.html [ Failure ]
 crbug.com/1432082 [ iOS16-simulator ] printing/webgl-repeated-printing.html [ Failure ]
 crbug.com/1432082 [ iOS16-simulator ] printing/width-overflow.html [ Failure ]
+
+# Failures need investigation.
+## dark-mode
+crbug.com/1496147 [ iOS16-simulator ] dark-mode/colors/select-popup.html [ Failure ]
+## scrollbars
+crbug.com/1500119 [ iOS16-simulator ] scrollbars/custom-scrollbar-with-incomplete-style.html [ Failure ]
+crbug.com/1500119 [ iOS16-simulator ] scrollbars/on-sub-pixel-position.html [ Failure ]
+crbug.com/1500119 [ iOS16-simulator ] scrollbars/overflow-scrollbar-combinations.html [ Failure ]
+crbug.com/1500119 [ iOS16-simulator ] scrollbars/custom-scrollbar-display.html [ Failure ]
+crbug.com/1500119 [ iOS16-simulator ] scrollbars/custom-scrollbar-not-inherited-by-iframe.html [ Failure ]
+crbug.com/1500119 [ iOS16-simulator ] scrollbars/destroy-scrollbar-if-scrollsizes-lesser-than-contentsizes.html [ Failure ]
+crbug.com/1500119 [ iOS16-simulator ] scrollbars/listbox-scrollbar-combinations.html [ Failure ]
+crbug.com/1500119 [ iOS16-simulator ] scrollbars/resize-scales-with-dpi-150.html [ Failure ]
+crbug.com/1500119 [ iOS16-simulator ] scrollbars/scrollbar-click-does-not-blur-content.html [ Failure ]
+crbug.com/1500119 [ iOS16-simulator ] scrollbars/scrollbar-iframe-click-does-not-blur-content.html [ Failure ]
+crbug.com/1500119 [ iOS16-simulator ] scrollbars/scrollbar-pointer-events.html [ Failure ]
+crbug.com/1500119 [ iOS16-simulator ] scrollbars/scrollbar-visibility-hidden.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 91922758a..2821b28 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2441,8 +2441,6 @@
 crbug.com/27659 external/wpt/css/css-ruby/empty-ruby-text-container-float.html [ Failure ]
 crbug.com/27659 external/wpt/css/css-ruby/improperly-contained-annotation-001.html [ Failure ]
 crbug.com/27659 external/wpt/css/css-ruby/rb-display-001.html [ Failure ]
-crbug.com/27659 external/wpt/css/css-ruby/root-block-ruby.xhtml [ Failure ]
-crbug.com/27659 external/wpt/css/css-ruby/root-ruby.xhtml [ Failure ]
 crbug.com/27659 external/wpt/css/css-ruby/rt-display-001.html [ Failure ]
 crbug.com/27659 external/wpt/css/css-ruby/ruby-align-001.html [ Failure ]
 crbug.com/27659 external/wpt/css/css-ruby/ruby-align-001a.html [ Failure ]
@@ -2461,6 +2459,7 @@
 crbug.com/27659 external/wpt/css/css-ruby/ruby-box-generation-005.html [ Failure ]
 crbug.com/27659 external/wpt/css/css-ruby/ruby-box-model-001.html [ Failure ]
 crbug.com/27659 external/wpt/css/css-ruby/ruby-float-handling-001.html [ Failure ]
+crbug.com/27659 external/wpt/css/css-ruby/ruby-intra-level-whitespace-003.html [ Failure ]
 crbug.com/27659 external/wpt/css/css-ruby/ruby-intrinsic-isize-001.html [ Failure ]
 crbug.com/27659 external/wpt/css/css-ruby/ruby-intrinsic-isize-002.html [ Failure ]
 crbug.com/27659 external/wpt/css/css-ruby/ruby-intrinsic-isize-003.html [ Failure ]
@@ -2477,6 +2476,8 @@
 crbug.com/27659 external/wpt/css/css-ruby/ruby-whitespace-002.html [ Failure ]
 crbug.com/27659 external/wpt/css/css-ruby/rbc-rtc-basic-001.html [ Failure ]
 
+crbug.com/1497899 external/wpt/css/css-ruby/block-ruby-004.html [ Crash Failure ]
+
 crbug.com/1223955 external/wpt/css/css-ruby/nested-ruby-pairing-001.html [ Failure ]
 crbug.com/1223955 external/wpt/css/css-ruby/ruby-autohide-001.html [ Failure ]
 crbug.com/1223955 external/wpt/css/css-ruby/ruby-autohide-002.html [ Failure ]
@@ -7531,3 +7532,6 @@
 
 # Gardener 2023-10-31
 crbug.com/1497825 [ Linux ] virtual/private-aggregation-developer-mode/wpt_internal/private-aggregation/shared-storage-aggregation-coordinator.https.html [ Pass Timeout ]
+
+# Gardener 2023-11-10
+crbug.com/1486131 [ Debug Linux ] external/wpt/html/browsers/history/the-history-interface/001.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index e4f3865..e6c8206 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -2584,6 +2584,14 @@
     "expires": "Dec 21, 2023"
   },
   {
+    "prefix": "url-non-special",
+    "platforms": ["Linux"],
+    "bases": ["external/wpt/url"],
+    "args": ["--enable-features=StandardCompliantNonSpecialSchemeURLParsing"],
+    "owners": ["hayato@chromium.org"],
+    "expires": "Jul 1, 2024"
+  },
+  {
     "prefix": "cookie-deprecation-label",
     "platforms": ["Linux", "Mac", "Win"],
     "bases": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-display/parsing/display-computed-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-display/parsing/display-computed-expected.txt
index c13a29b7..7fbd76d1 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-display/parsing/display-computed-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-display/parsing/display-computed-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 110 tests; 78 PASS, 32 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 112 tests; 84 PASS, 28 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [PASS] Property display value 'grid'
 [PASS] Property display value 'inline-grid'
 [PASS] Property display value 'inline'
@@ -24,8 +24,10 @@
   assert_true: 'run-in' is a supported value for display. expected true got false
 [PASS] Property display value 'flow'
 [PASS] Property display value 'flow-root'
-[FAIL] Property display value 'ruby'
-  assert_true: 'ruby' is a supported value for display. expected true got false
+[PASS] Property display value 'ruby'
+[FAIL] Property display value 'ruby-base'
+  assert_true: 'ruby-base' is a supported value for display. expected true got false
+[PASS] Property display value 'ruby-text'
 [PASS] Property display value 'flow list-item'
 [PASS] Property display value 'list-item flow'
 [PASS] Property display value 'flow-root list-item'
@@ -40,10 +42,8 @@
 [PASS] Property display value 'block grid'
 [PASS] Property display value 'table block'
 [PASS] Property display value 'block table'
-[FAIL] Property display value 'block ruby'
-  assert_true: 'block ruby' is a supported value for display. expected true got false
-[FAIL] Property display value 'ruby block'
-  assert_true: 'ruby block' is a supported value for display. expected true got false
+[PASS] Property display value 'block ruby'
+[PASS] Property display value 'ruby block'
 [PASS] Property display value 'block list-item'
 [PASS] Property display value 'list-item block'
 [PASS] Property display value 'flow block list-item'
@@ -68,10 +68,8 @@
 [PASS] Property display value 'inline grid'
 [PASS] Property display value 'table inline'
 [PASS] Property display value 'inline table'
-[FAIL] Property display value 'inline ruby'
-  assert_true: 'inline ruby' is a supported value for display. expected true got false
-[FAIL] Property display value 'ruby inline'
-  assert_true: 'ruby inline' is a supported value for display. expected true got false
+[PASS] Property display value 'inline ruby'
+[PASS] Property display value 'ruby inline'
 [PASS] Property display value 'inline list-item'
 [PASS] Property display value 'list-item inline'
 [PASS] Property display value 'flow inline list-item'
diff --git a/third_party/blink/web_tests/external/wpt/css/css-display/parsing/display-computed.html b/third_party/blink/web_tests/external/wpt/css/css-display/parsing/display-computed.html
index b8c7b5e4..c32f470 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-display/parsing/display-computed.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-display/parsing/display-computed.html
@@ -49,6 +49,8 @@
 test_computed_value("display", "flow", "block");
 test_computed_value("display", "flow-root");
 test_computed_value("display", "ruby");
+test_computed_value("display", "ruby-base");
+test_computed_value("display", "ruby-text");
 
 test_computed_value("display", "flow list-item", "list-item");
 test_computed_value("display", "list-item flow", "list-item");
@@ -154,6 +156,8 @@
       'table-row',
       'table-cell',
       'table-caption',
+      'ruby-base',
+      'ruby-text',
       'inline-block'
     ];
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-display/parsing/display-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-display/parsing/display-valid-expected.txt
index 741e8e4d..b1c2a79 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-display/parsing/display-valid-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-display/parsing/display-valid-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 106 tests; 74 PASS, 32 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 108 tests; 80 PASS, 28 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [PASS] e.style['display'] = "grid" should set the property value
 [PASS] e.style['display'] = "inline-grid" should set the property value
 [PASS] e.style['display'] = "inline" should set the property value
@@ -24,8 +24,10 @@
   assert_not_equals: property should be set got disallowed value ""
 [PASS] e.style['display'] = "flow" should set the property value
 [PASS] e.style['display'] = "flow-root" should set the property value
-[FAIL] e.style['display'] = "ruby" should set the property value
+[PASS] e.style['display'] = "ruby" should set the property value
+[FAIL] e.style['display'] = "ruby-base" should set the property value
   assert_not_equals: property should be set got disallowed value ""
+[PASS] e.style['display'] = "ruby-text" should set the property value
 [PASS] e.style['display'] = "flow list-item" should set the property value
 [PASS] e.style['display'] = "list-item flow" should set the property value
 [PASS] e.style['display'] = "flow-root list-item" should set the property value
@@ -40,10 +42,8 @@
 [PASS] e.style['display'] = "block grid" should set the property value
 [PASS] e.style['display'] = "table block" should set the property value
 [PASS] e.style['display'] = "block table" should set the property value
-[FAIL] e.style['display'] = "block ruby" should set the property value
-  assert_not_equals: property should be set got disallowed value ""
-[FAIL] e.style['display'] = "ruby block" should set the property value
-  assert_not_equals: property should be set got disallowed value ""
+[PASS] e.style['display'] = "block ruby" should set the property value
+[PASS] e.style['display'] = "ruby block" should set the property value
 [PASS] e.style['display'] = "block list-item" should set the property value
 [PASS] e.style['display'] = "list-item block" should set the property value
 [PASS] e.style['display'] = "flow block list-item" should set the property value
@@ -68,10 +68,8 @@
 [PASS] e.style['display'] = "inline grid" should set the property value
 [PASS] e.style['display'] = "table inline" should set the property value
 [PASS] e.style['display'] = "inline table" should set the property value
-[FAIL] e.style['display'] = "inline ruby" should set the property value
-  assert_not_equals: property should be set got disallowed value ""
-[FAIL] e.style['display'] = "ruby inline" should set the property value
-  assert_not_equals: property should be set got disallowed value ""
+[PASS] e.style['display'] = "inline ruby" should set the property value
+[PASS] e.style['display'] = "ruby inline" should set the property value
 [PASS] e.style['display'] = "inline list-item" should set the property value
 [PASS] e.style['display'] = "list-item inline" should set the property value
 [PASS] e.style['display'] = "flow inline list-item" should set the property value
diff --git a/third_party/blink/web_tests/external/wpt/css/css-display/parsing/display-valid.html b/third_party/blink/web_tests/external/wpt/css/css-display/parsing/display-valid.html
index 9501a6e..c011c2a3 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-display/parsing/display-valid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-display/parsing/display-valid.html
@@ -47,6 +47,8 @@
 test_valid_value("display", "flow");
 test_valid_value("display", "flow-root");
 test_valid_value("display", "ruby");
+test_valid_value("display", "ruby-base");
+test_valid_value("display", "ruby-text");
 
 test_valid_value("display", "flow list-item", "list-item");
 test_valid_value("display", "list-item flow", "list-item");
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-display-expected.txt b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-display-expected.txt
index 90899f7..d472e37a 100644
--- a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-display-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-display-expected.txt
@@ -13,17 +13,15 @@
 [PASS] fieldset with display: flow-root
 [FAIL] fieldset with display: run-in
   assert_equals: display: run-in is not supported expected "run-in" but got "block"
-[FAIL] fieldset with display: block ruby
-  assert_equals: display: block ruby is not supported expected "block ruby" but got "block"
+[PASS] fieldset with display: block ruby
 [PASS] fieldset with display: inline
 [PASS] fieldset with display: inline-block
 [PASS] fieldset with display: inline-table
-[FAIL] fieldset with display: ruby
-  assert_equals: display: ruby is not supported expected "ruby" but got "block"
+[PASS] fieldset with display: ruby
 [FAIL] fieldset with display: ruby-base
   assert_equals: display: ruby-base is not supported expected "ruby-base" but got "block"
 [FAIL] fieldset with display: ruby-text
-  assert_equals: display: ruby-text is not supported expected "ruby-text" but got "block"
+  assert_equals: expected "8px" but got "752px"
 [FAIL] fieldset with display: ruby-base-container
   assert_equals: display: ruby-base-container is not supported expected "ruby-base-container" but got "block"
 [FAIL] fieldset with display: ruby-text-container
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-expected.txt b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-expected.txt
index 7c4b3b7..9d8997b6 100644
--- a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 108 tests; 28 PASS, 80 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 108 tests; 32 PASS, 76 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [PASS] rendered legend with display: block
 [PASS] rendered legend with display: table
 [FAIL] rendered legend with display: table-row-group
@@ -29,10 +29,9 @@
   assert_equals: display: inline-block is not supported expected "inline-block" but got "block"
 [FAIL] rendered legend with display: inline-table
   assert_equals: display: inline-table is not supported expected "inline-table" but got "table"
-[FAIL] rendered legend with display: block ruby
-  assert_equals: display: block ruby is not supported expected "block ruby" but got "block"
+[PASS] rendered legend with display: block ruby
 [FAIL] rendered legend with display: ruby
-  assert_equals: display: ruby is not supported expected "ruby" but got "block"
+  assert_equals: display: ruby is not supported expected "ruby" but got "block ruby"
 [FAIL] rendered legend with display: ruby-base
   assert_equals: display: ruby-base is not supported expected "ruby-base" but got "block"
 [FAIL] rendered legend with display: ruby-text
@@ -76,10 +75,9 @@
   assert_equals: display: inline-block is not supported expected "inline-block" but got "block"
 [FAIL] rendered legend with display: inline-table; overflow:hidden
   assert_equals: display: inline-table is not supported expected "inline-table" but got "table"
-[FAIL] rendered legend with display: block ruby; overflow:hidden
-  assert_equals: display: block ruby is not supported expected "block ruby" but got "block"
+[PASS] rendered legend with display: block ruby; overflow:hidden
 [FAIL] rendered legend with display: ruby; overflow:hidden
-  assert_equals: display: ruby is not supported expected "ruby" but got "block"
+  assert_equals: display: ruby is not supported expected "ruby" but got "block ruby"
 [FAIL] rendered legend with display: ruby-base; overflow:hidden
   assert_equals: display: ruby-base is not supported expected "ruby-base" but got "block"
 [FAIL] rendered legend with display: ruby-text; overflow:hidden
@@ -123,10 +121,9 @@
   assert_equals: display: inline-block is not supported expected "inline-block" but got "block"
 [FAIL] rendered legend with display: inline-table; columns:1
   assert_equals: display: inline-table is not supported expected "inline-table" but got "table"
-[FAIL] rendered legend with display: block ruby; columns:1
-  assert_equals: display: block ruby is not supported expected "block ruby" but got "block"
+[PASS] rendered legend with display: block ruby; columns:1
 [FAIL] rendered legend with display: ruby; columns:1
-  assert_equals: display: ruby is not supported expected "ruby" but got "block"
+  assert_equals: display: ruby is not supported expected "ruby" but got "block ruby"
 [FAIL] rendered legend with display: ruby-base; columns:1
   assert_equals: display: ruby-base is not supported expected "ruby-base" but got "block"
 [FAIL] rendered legend with display: ruby-text; columns:1
@@ -170,10 +167,9 @@
   assert_equals: display: inline-block is not supported expected "inline-block" but got "block"
 [FAIL] rendered legend with display: inline-table; overflow:hidden;columns:1
   assert_equals: display: inline-table is not supported expected "inline-table" but got "table"
-[FAIL] rendered legend with display: block ruby; overflow:hidden;columns:1
-  assert_equals: display: block ruby is not supported expected "block ruby" but got "block"
+[PASS] rendered legend with display: block ruby; overflow:hidden;columns:1
 [FAIL] rendered legend with display: ruby; overflow:hidden;columns:1
-  assert_equals: display: ruby is not supported expected "ruby" but got "block"
+  assert_equals: display: ruby is not supported expected "ruby" but got "block ruby"
 [FAIL] rendered legend with display: ruby-base; overflow:hidden;columns:1
   assert_equals: display: ruby-base is not supported expected "ruby-base" but got "block"
 [FAIL] rendered legend with display: ruby-text; overflow:hidden;columns:1
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/computed-style-expected.txt b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/computed-style-expected.txt
index 2caf829..3ba4303a 100644
--- a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/computed-style-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/computed-style-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 135 tests; 50 PASS, 85 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 135 tests; 60 PASS, 75 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] computed display of <input type=reset> with display: inline
   assert_equals: expected "inline" but got "inline-block"
 [FAIL] computed display of <input type=button> with display: inline
@@ -160,16 +160,11 @@
 [PASS] computed display of <input type=submit> with display: grid
 [PASS] computed display of <input type=color> with display: grid
 [PASS] computed display of <button type=submit> with display: grid
-[FAIL] computed display of <input type=reset> with display: ruby
-  assert_not_equals: display: ruby is not supported got disallowed value ""
-[FAIL] computed display of <input type=button> with display: ruby
-  assert_not_equals: display: ruby is not supported got disallowed value ""
-[FAIL] computed display of <input type=submit> with display: ruby
-  assert_not_equals: display: ruby is not supported got disallowed value ""
-[FAIL] computed display of <input type=color> with display: ruby
-  assert_not_equals: display: ruby is not supported got disallowed value ""
-[FAIL] computed display of <button type=submit> with display: ruby
-  assert_not_equals: display: ruby is not supported got disallowed value ""
+[PASS] computed display of <input type=reset> with display: ruby
+[PASS] computed display of <input type=button> with display: ruby
+[PASS] computed display of <input type=submit> with display: ruby
+[PASS] computed display of <input type=color> with display: ruby
+[PASS] computed display of <button type=submit> with display: ruby
 [FAIL] computed display of <input type=reset> with display: ruby-base
   assert_not_equals: display: ruby-base is not supported got disallowed value ""
 [FAIL] computed display of <input type=button> with display: ruby-base
@@ -180,16 +175,11 @@
   assert_not_equals: display: ruby-base is not supported got disallowed value ""
 [FAIL] computed display of <button type=submit> with display: ruby-base
   assert_not_equals: display: ruby-base is not supported got disallowed value ""
-[FAIL] computed display of <input type=reset> with display: ruby-text
-  assert_not_equals: display: ruby-text is not supported got disallowed value ""
-[FAIL] computed display of <input type=button> with display: ruby-text
-  assert_not_equals: display: ruby-text is not supported got disallowed value ""
-[FAIL] computed display of <input type=submit> with display: ruby-text
-  assert_not_equals: display: ruby-text is not supported got disallowed value ""
-[FAIL] computed display of <input type=color> with display: ruby-text
-  assert_not_equals: display: ruby-text is not supported got disallowed value ""
-[FAIL] computed display of <button type=submit> with display: ruby-text
-  assert_not_equals: display: ruby-text is not supported got disallowed value ""
+[PASS] computed display of <input type=reset> with display: ruby-text
+[PASS] computed display of <input type=button> with display: ruby-text
+[PASS] computed display of <input type=submit> with display: ruby-text
+[PASS] computed display of <input type=color> with display: ruby-text
+[PASS] computed display of <button type=submit> with display: ruby-text
 [FAIL] computed display of <input type=reset> with display: ruby-base-container
   assert_not_equals: display: ruby-base-container is not supported got disallowed value ""
 [FAIL] computed display of <input type=button> with display: ruby-base-container
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/display-other-expected.txt b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/display-other-expected.txt
index 98ccee7..98b678f43 100644
--- a/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/display-other-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/widgets/button-layout/display-other-expected.txt
@@ -24,8 +24,7 @@
   assert_equals: afterLeft expected 0 but got 256
 [FAIL] display: ruby-base
   assert_true: display: ruby-base is not supported expected true got false
-[FAIL] display: ruby-text
-  assert_true: display: ruby-text is not supported expected true got false
+[PASS] display: ruby-text
 [FAIL] display: ruby-base-container
   assert_true: display: ruby-base-container is not supported expected true got false
 [FAIL] display: ruby-text-container
diff --git a/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/display-2-expected.txt b/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/display-2-expected.txt
index e7ffbcd..9d6e603 100644
--- a/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/display-2-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/mathml/relations/css-styling/display-2-expected.txt
@@ -12,10 +12,8 @@
 [PASS] flexbox display (mrow)
 [PASS] grid display (math)
 [PASS] grid display (mrow)
-[FAIL] ruby display (math)
-  assert_approx_equals: block size expected 78 +/- 1 but got 29
-[FAIL] ruby display (mrow)
-  assert_approx_equals: block size expected 78 +/- 1 but got 45
+[PASS] ruby display (math)
+[PASS] ruby display (mrow)
 [FAIL] block display with column width (math)
   assert_approx_equals: block size expected 78 +/- 1 but got 45
 [FAIL] block display with column width (mrow)
diff --git a/third_party/blink/web_tests/http/tests/lcp_critical_path_predictor/timing_predictor_hit_secondary.php b/third_party/blink/web_tests/http/tests/lcp_critical_path_predictor/timing_predictor_hit_secondary.php
new file mode 100644
index 0000000..faa9ea7
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/lcp_critical_path_predictor/timing_predictor_hit_secondary.php
@@ -0,0 +1,55 @@
+<!doctype html>
+<script src="/priorities/resources/common.js"></script>
+<script type=module>
+import {mojo} from "/gen/mojo/public/js/bindings.js";
+import {NonAssociatedWebTestControlHostRemote} from "/gen/content/web_test/common/web_test.mojom.m.js";
+import {ByteString} from "/gen/mojo/public/mojom/base/byte_string.mojom.m.js";
+import {LCPCriticalPathPredictorNavigationTimeHint} from "/gen/third_party/blink/public/mojom/lcp_critical_path_predictor/lcp_critical_path_predictor.mojom.m.js";
+
+if (!window.testRunner) {
+  console.log("This test requires window.testRunner.")
+}
+
+testRunner.dumpAsText();
+testRunner.waitUntilDone();
+if (window.location.search != "?start") {
+  const hint = new LCPCriticalPathPredictorNavigationTimeHint();
+
+  var getLCPBytes = async function(proto_file) {
+    const resp = await fetch("/gen/third_party/blink/renderer/core/lcp_critical_path_predictor/test_proto/" + proto_file);
+    const bytes = new ByteString;
+    bytes.data = new Uint8Array(await resp.arrayBuffer());
+    return bytes;
+  };
+
+  hint.lcpElementLocators = [
+      await getLCPBytes("lcp_image_id.pb"),
+      await getLCPBytes("lcp_image_id_b.pb")
+  ];
+  // All fields are non-nullable.
+  hint.lcpInfluencerScripts = [];
+  hint.fetchedFonts = [];
+
+  const web_test_control_host_remote = new NonAssociatedWebTestControlHostRemote();
+  web_test_control_host_remote.$.bindNewPipeAndPassReceiver().bindInBrowser('process');
+  web_test_control_host_remote.setLCPPNavigationHint(hint);
+
+  window.location.search = '?start';
+}
+</script>
+<?php
+// Do not output the HTML below this PHP block until the test is reloaded with
+// "?start" to avoid it being picked up by the HTMLPreloadScanner.
+if ($_SERVER['QUERY_STRING'] != "start")
+  exit;
+?>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+  promise_test(async t => {
+    const lcp_elment = await internals.LCPPrediction(document);
+    assert_equals(lcp_elment, "/#lcp_image_b");
+  }, "Ensure document::RunLCPPredictedCallbacks is called with the 2nd LCP element locator.")
+</script>
+<img src="/resources/square.png" id="lcp_image_b">
+<img src="/resources/square100.png">
diff --git a/third_party/blink/web_tests/platform/ios/dark-mode/colors/border-expected.png b/third_party/blink/web_tests/platform/ios/dark-mode/colors/border-expected.png
index 3ed243f9..a44b9de 100644
--- a/third_party/blink/web_tests/platform/ios/dark-mode/colors/border-expected.png
+++ b/third_party/blink/web_tests/platform/ios/dark-mode/colors/border-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/dark-mode/colors/list-markers-expected.png b/third_party/blink/web_tests/platform/ios/dark-mode/colors/list-markers-expected.png
deleted file mode 100644
index a874a75..0000000
--- a/third_party/blink/web_tests/platform/ios/dark-mode/colors/list-markers-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/dark-mode/colors/page-background-dark-color-expected.png b/third_party/blink/web_tests/platform/ios/dark-mode/colors/page-background-dark-color-expected.png
deleted file mode 100644
index 55332b7..0000000
--- a/third_party/blink/web_tests/platform/ios/dark-mode/colors/page-background-dark-color-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/dark-mode/colors/page-background-light-color-expected.png b/third_party/blink/web_tests/platform/ios/dark-mode/colors/page-background-light-color-expected.png
deleted file mode 100644
index e343cac..0000000
--- a/third_party/blink/web_tests/platform/ios/dark-mode/colors/page-background-light-color-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/dark-mode/colors/selection-expected.png b/third_party/blink/web_tests/platform/ios/dark-mode/colors/selection-expected.png
index efdb9ec3..df4136f1 100644
--- a/third_party/blink/web_tests/platform/ios/dark-mode/colors/selection-expected.png
+++ b/third_party/blink/web_tests/platform/ios/dark-mode/colors/selection-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/dark-mode/colors/text-on-backgrounds-expected.png b/third_party/blink/web_tests/platform/ios/dark-mode/colors/text-on-backgrounds-expected.png
deleted file mode 100644
index d695eda..0000000
--- a/third_party/blink/web_tests/platform/ios/dark-mode/colors/text-on-backgrounds-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/dark-mode/colors/web-theme-expected.png b/third_party/blink/web_tests/platform/ios/dark-mode/colors/web-theme-expected.png
index 6d7c332..9da5b17 100644
--- a/third_party/blink/web_tests/platform/ios/dark-mode/colors/web-theme-expected.png
+++ b/third_party/blink/web_tests/platform/ios/dark-mode/colors/web-theme-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/dark-mode/images/crossfade-expected.png b/third_party/blink/web_tests/platform/ios/dark-mode/images/crossfade-expected.png
deleted file mode 100644
index 28f0f74..0000000
--- a/third_party/blink/web_tests/platform/ios/dark-mode/images/crossfade-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/dark-mode/images/desaturate-before-inversion-expected.png b/third_party/blink/web_tests/platform/ios/dark-mode/images/desaturate-before-inversion-expected.png
deleted file mode 100644
index df67013aa..0000000
--- a/third_party/blink/web_tests/platform/ios/dark-mode/images/desaturate-before-inversion-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/dark-mode/images/gradient-expected.png b/third_party/blink/web_tests/platform/ios/dark-mode/images/gradient-expected.png
deleted file mode 100644
index c6d5dc4b..0000000
--- a/third_party/blink/web_tests/platform/ios/dark-mode/images/gradient-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/dark-mode/images/image-expected.png b/third_party/blink/web_tests/platform/ios/dark-mode/images/image-expected.png
deleted file mode 100644
index 829167de..0000000
--- a/third_party/blink/web_tests/platform/ios/dark-mode/images/image-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/dark-mode/images/opt-out-svg-gradient-expected.png b/third_party/blink/web_tests/platform/ios/dark-mode/images/opt-out-svg-gradient-expected.png
deleted file mode 100644
index 01d688f4..0000000
--- a/third_party/blink/web_tests/platform/ios/dark-mode/images/opt-out-svg-gradient-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/dark-mode/images/pattern-expected.png b/third_party/blink/web_tests/platform/ios/dark-mode/images/pattern-expected.png
deleted file mode 100644
index 9f5f7e4..0000000
--- a/third_party/blink/web_tests/platform/ios/dark-mode/images/pattern-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/dark-mode/images/shadow-expected.png b/third_party/blink/web_tests/platform/ios/dark-mode/images/shadow-expected.png
deleted file mode 100644
index e73821c8..0000000
--- a/third_party/blink/web_tests/platform/ios/dark-mode/images/shadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/dark-mode/images/svg-expected.png b/third_party/blink/web_tests/platform/ios/dark-mode/images/svg-expected.png
deleted file mode 100644
index 57cd0f5..0000000
--- a/third_party/blink/web_tests/platform/ios/dark-mode/images/svg-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/dom/legacy_dom_conformance/xhtml/level2/html/HTMLImageElement05-expected.txt b/third_party/blink/web_tests/platform/ios/dom/legacy_dom_conformance/xhtml/level2/html/HTMLImageElement05-expected.txt
deleted file mode 100644
index 8b28d8f..0000000
--- a/third_party/blink/web_tests/platform/ios/dom/legacy_dom_conformance/xhtml/level2/html/HTMLImageElement05-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Test	http://www.w3.org/2001/DOM-Test-Suite/level2/html/HTMLImageElement05
-Status	failure
-Message	heightLink: assertEquals failed, actual 18, expected 47.
diff --git a/third_party/blink/web_tests/platform/ios/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls-expected.txt b/third_party/blink/web_tests/platform/ios/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls-expected.txt
deleted file mode 100644
index 09d7b5b..0000000
--- a/third_party/blink/web_tests/platform/ios/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls-expected.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-This test makes sure that touch hit rects are reported for fullscreen HTML5 video control elements even when there is a document handler.
-
-Should have single rect on document before fullscreen
-handler: layer(980x735) has hit test rect (0,0 980x735)
-handler: layer(980x735) has hit test rect (0,0 980x735)
-
-EVENT(webkitfullscreenchange)
-Should keep rect on document
-handler: layer(980x735) has hit test rect (0,0 980x735)
-handler: layer(980x735) has hit test rect (0,0 980x735)
-handler: layer(980x735) has hit test rect (0,0 980x735)
-handler: layer(980x735) has hit test rect (0,0 980x735)
-
-Found composited video layer, as expected
-END OF TEST
-
diff --git a/third_party/blink/web_tests/platform/ios/fullscreen/full-screen-is-in-top-layer-expected.png b/third_party/blink/web_tests/platform/ios/fullscreen/full-screen-is-in-top-layer-expected.png
new file mode 100644
index 0000000..87c90f88
--- /dev/null
+++ b/third_party/blink/web_tests/platform/ios/fullscreen/full-screen-is-in-top-layer-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/fullscreen/full-screen-min-max-width-height-iframe-expected.txt b/third_party/blink/web_tests/platform/ios/fullscreen/full-screen-min-max-width-height-iframe-expected.txt
deleted file mode 100644
index b4c22f41..0000000
--- a/third_party/blink/web_tests/platform/ios/fullscreen/full-screen-min-max-width-height-iframe-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-EVENT(webkitfullscreenchange)
-EXPECTED (computedStyle.minWidth == '0px') OK
-EXPECTED (computedStyle.maxWidth == 'none') OK
-EXPECTED (computedStyle.minHeight == '0px') OK
-EXPECTED (computedStyle.maxHeight == 'none') OK
-EXPECTED (computedStyle.width == '980px') OK
-EXPECTED (computedStyle.height == '735px') OK
-END OF TEST
-
diff --git a/third_party/blink/web_tests/platform/ios/fullscreen/full-screen-with-flex-item-expected.txt b/third_party/blink/web_tests/platform/ios/fullscreen/full-screen-with-flex-item-expected.txt
deleted file mode 100644
index 16b6956..0000000
--- a/third_party/blink/web_tests/platform/ios/fullscreen/full-screen-with-flex-item-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Enter Fullscreen
-EVENT(webkitfullscreenchange)
-EVENT(webkitfullscreenchange)
-EXPECTED (735 == '735') OK
-END OF TEST
-
diff --git a/third_party/blink/web_tests/platform/ios/overflow/overflow-transform-perspective-expected.png b/third_party/blink/web_tests/platform/ios/overflow/overflow-transform-perspective-expected.png
index 8469490..d2d4fdf8 100644
--- a/third_party/blink/web_tests/platform/ios/overflow/overflow-transform-perspective-expected.png
+++ b/third_party/blink/web_tests/platform/ios/overflow/overflow-transform-perspective-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/scrollbars/auto-scrollbar-fades-out-expected.png b/third_party/blink/web_tests/platform/ios/scrollbars/auto-scrollbar-fades-out-expected.png
index b28f6b2..193f10d 100644
--- a/third_party/blink/web_tests/platform/ios/scrollbars/auto-scrollbar-fades-out-expected.png
+++ b/third_party/blink/web_tests/platform/ios/scrollbars/auto-scrollbar-fades-out-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/scrollbars/basic-scrollbar-expected.png b/third_party/blink/web_tests/platform/ios/scrollbars/basic-scrollbar-expected.png
index 69739fb..29f1a91 100644
--- a/third_party/blink/web_tests/platform/ios/scrollbars/basic-scrollbar-expected.png
+++ b/third_party/blink/web_tests/platform/ios/scrollbars/basic-scrollbar-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/scrollbars/border-box-rect-clips-scrollbars-expected.png b/third_party/blink/web_tests/platform/ios/scrollbars/border-box-rect-clips-scrollbars-expected.png
index c61d1e50..cf28187 100644
--- a/third_party/blink/web_tests/platform/ios/scrollbars/border-box-rect-clips-scrollbars-expected.png
+++ b/third_party/blink/web_tests/platform/ios/scrollbars/border-box-rect-clips-scrollbars-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/scrollbars/custom-scrollbar-table-cell-expected.png b/third_party/blink/web_tests/platform/ios/scrollbars/custom-scrollbar-table-cell-expected.png
deleted file mode 100644
index dfdc1900..0000000
--- a/third_party/blink/web_tests/platform/ios/scrollbars/custom-scrollbar-table-cell-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/scrollbars/custom-scrollbar-with-incomplete-style-expected.png b/third_party/blink/web_tests/platform/ios/scrollbars/custom-scrollbar-with-incomplete-style-expected.png
deleted file mode 100644
index f9f6e0b..0000000
--- a/third_party/blink/web_tests/platform/ios/scrollbars/custom-scrollbar-with-incomplete-style-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/scrollbars/disabled-scrollbar-expected.png b/third_party/blink/web_tests/platform/ios/scrollbars/disabled-scrollbar-expected.png
index 2222e0e..da231c6 100644
--- a/third_party/blink/web_tests/platform/ios/scrollbars/disabled-scrollbar-expected.png
+++ b/third_party/blink/web_tests/platform/ios/scrollbars/disabled-scrollbar-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/scrollbars/on-sub-pixel-position-expected.png b/third_party/blink/web_tests/platform/ios/scrollbars/on-sub-pixel-position-expected.png
deleted file mode 100644
index 5452a84..0000000
--- a/third_party/blink/web_tests/platform/ios/scrollbars/on-sub-pixel-position-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/scrollbars/overflow-scrollbar-combinations-expected.png b/third_party/blink/web_tests/platform/ios/scrollbars/overflow-scrollbar-combinations-expected.png
deleted file mode 100644
index 76493e0..0000000
--- a/third_party/blink/web_tests/platform/ios/scrollbars/overflow-scrollbar-combinations-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/scrollbars/overlay-scrollbars-with-scrollbar-color-expected.png b/third_party/blink/web_tests/platform/ios/scrollbars/overlay-scrollbars-with-scrollbar-color-expected.png
new file mode 100644
index 0000000..79228be
--- /dev/null
+++ b/third_party/blink/web_tests/platform/ios/scrollbars/overlay-scrollbars-with-scrollbar-color-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/scrollbars/overlay-scrollbars-with-scrollbar-color-expected.txt b/third_party/blink/web_tests/platform/ios/scrollbars/overlay-scrollbars-with-scrollbar-color-expected.txt
new file mode 100644
index 0000000..6c312b4
--- /dev/null
+++ b/third_party/blink/web_tests/platform/ios/scrollbars/overlay-scrollbars-with-scrollbar-color-expected.txt
@@ -0,0 +1,95 @@
+{
+  "layers": [
+    {
+      "name": "Scrolling background of LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "backgroundColor": "#FFFFFF"
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='outer'",
+      "position": [1, 1],
+      "bounds": [400, 300],
+      "drawsContent": false
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='outer'",
+      "position": [1, 1],
+      "bounds": [400, 500],
+      "drawsContent": false,
+      "transform": 1
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='inner'",
+      "bounds": [102, 102],
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='inner'",
+      "position": [1, 1],
+      "bounds": [100, 100],
+      "drawsContent": false,
+      "transform": 2
+    },
+    {
+      "name": "LayoutNGBlockFlow DIV id='inner'",
+      "position": [1, 1],
+      "bounds": [100, 500],
+      "drawsContent": false,
+      "transform": 3
+    },
+    {
+      "name": "VerticalScrollbar",
+      "position": [94, 1],
+      "bounds": [7, 100],
+      "transform": 2
+    },
+    {
+      "name": "VerticalScrollbar",
+      "position": [394, 1],
+      "bounds": [7, 300]
+    },
+    {
+      "name": "Inner Viewport Horizontal Scrollbar",
+      "position": [0, 593],
+      "bounds": [796, 4]
+    },
+    {
+      "name": "Inner Viewport Vertical Scrollbar",
+      "position": [793, 0],
+      "bounds": [4, 596]
+    }
+  ],
+  "transforms": [
+    {
+      "id": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -302, 0, 1]
+      ]
+    },
+    {
+      "id": 2,
+      "parent": 1,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [1, 501, 0, 1]
+      ]
+    },
+    {
+      "id": 3,
+      "parent": 2,
+      "transform": [
+        [1, 0, 0, 0],
+        [0, 1, 0, 0],
+        [0, 0, 1, 0],
+        [0, -400, 0, 1]
+      ]
+    }
+  ]
+}
+
diff --git a/third_party/blink/web_tests/platform/ios/scrollbars/overlay-scrollbars-within-overflow-scroll-expected.png b/third_party/blink/web_tests/platform/ios/scrollbars/overlay-scrollbars-within-overflow-scroll-expected.png
index 8e92880..e322787 100644
--- a/third_party/blink/web_tests/platform/ios/scrollbars/overlay-scrollbars-within-overflow-scroll-expected.png
+++ b/third_party/blink/web_tests/platform/ios/scrollbars/overlay-scrollbars-within-overflow-scroll-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/scrollbars/overlay-scrollbars-within-overflow-scroll-expected.txt b/third_party/blink/web_tests/platform/ios/scrollbars/overlay-scrollbars-within-overflow-scroll-expected.txt
index f141123..60dadce47 100644
--- a/third_party/blink/web_tests/platform/ios/scrollbars/overlay-scrollbars-within-overflow-scroll-expected.txt
+++ b/third_party/blink/web_tests/platform/ios/scrollbars/overlay-scrollbars-within-overflow-scroll-expected.txt
@@ -2,7 +2,7 @@
   "layers": [
     {
       "name": "Scrolling background of LayoutView #document",
-      "bounds": [980, 735],
+      "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF"
     },
@@ -19,13 +19,13 @@
     },
     {
       "name": "Inner Viewport Horizontal Scrollbar",
-      "position": [0, 728],
-      "bounds": [973, 7]
+      "position": [0, 593],
+      "bounds": [796, 4]
     },
     {
       "name": "Inner Viewport Vertical Scrollbar",
-      "position": [973, 0],
-      "bounds": [7, 728]
+      "position": [793, 0],
+      "bounds": [4, 596]
     }
   ],
   "transforms": [
diff --git a/third_party/blink/web_tests/platform/ios/scrollbars/rtl-resizer-position-expected.png b/third_party/blink/web_tests/platform/ios/scrollbars/rtl-resizer-position-expected.png
index 573b3ed..2f160bd 100644
--- a/third_party/blink/web_tests/platform/ios/scrollbars/rtl-resizer-position-expected.png
+++ b/third_party/blink/web_tests/platform/ios/scrollbars/rtl-resizer-position-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/scrollbars/rtl/overflow-scroll-rtl-expected.png b/third_party/blink/web_tests/platform/ios/scrollbars/rtl/overflow-scroll-rtl-expected.png
index 86cb880..8533a69 100644
--- a/third_party/blink/web_tests/platform/ios/scrollbars/rtl/overflow-scroll-rtl-expected.png
+++ b/third_party/blink/web_tests/platform/ios/scrollbars/rtl/overflow-scroll-rtl-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/scrollbars/scrollbar-buttons-expected.png b/third_party/blink/web_tests/platform/ios/scrollbars/scrollbar-buttons-expected.png
index 8864268..bc6efc82 100644
--- a/third_party/blink/web_tests/platform/ios/scrollbars/scrollbar-buttons-expected.png
+++ b/third_party/blink/web_tests/platform/ios/scrollbars/scrollbar-buttons-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/scrollbars/scrollbar-corner-colors-expected.png b/third_party/blink/web_tests/platform/ios/scrollbars/scrollbar-corner-colors-expected.png
index 648b8344..1440a00 100644
--- a/third_party/blink/web_tests/platform/ios/scrollbars/scrollbar-corner-colors-expected.png
+++ b/third_party/blink/web_tests/platform/ios/scrollbars/scrollbar-corner-colors-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/scrollbars/scrollbar-orientation-expected.png b/third_party/blink/web_tests/platform/ios/scrollbars/scrollbar-orientation-expected.png
index 9694a2f..2272dc8 100644
--- a/third_party/blink/web_tests/platform/ios/scrollbars/scrollbar-orientation-expected.png
+++ b/third_party/blink/web_tests/platform/ios/scrollbars/scrollbar-orientation-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/scrollbars/scrollbars-on-positioned-content-expected.png b/third_party/blink/web_tests/platform/ios/scrollbars/scrollbars-on-positioned-content-expected.png
index 7f05b815..ebddccfd 100644
--- a/third_party/blink/web_tests/platform/ios/scrollbars/scrollbars-on-positioned-content-expected.png
+++ b/third_party/blink/web_tests/platform/ios/scrollbars/scrollbars-on-positioned-content-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/ios/scrollbars/short-scrollbar-expected.png b/third_party/blink/web_tests/platform/ios/scrollbars/short-scrollbar-expected.png
index bf58405..c9b07eb9 100644
--- a/third_party/blink/web_tests/platform/ios/scrollbars/short-scrollbar-expected.png
+++ b/third_party/blink/web_tests/platform/ios/scrollbars/short-scrollbar-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-display-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-display-expected.txt
new file mode 100644
index 0000000..d472e37a
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-display-expected.txt
@@ -0,0 +1,30 @@
+This is a testharness.js-based test.
+[PASS] fieldset with display: block
+[PASS] fieldset with display: table
+[PASS] fieldset with display: table-row-group
+[PASS] fieldset with display: table-header-group
+[PASS] fieldset with display: table-footer-group
+[PASS] fieldset with display: table-row
+[PASS] fieldset with display: table-cell
+[PASS] fieldset with display: table-column-group
+[PASS] fieldset with display: table-column
+[PASS] fieldset with display: table-caption
+[PASS] fieldset with display: list-item
+[PASS] fieldset with display: flow-root
+[FAIL] fieldset with display: run-in
+  assert_equals: display: run-in is not supported expected "run-in" but got "block"
+[PASS] fieldset with display: block ruby
+[PASS] fieldset with display: inline
+[PASS] fieldset with display: inline-block
+[PASS] fieldset with display: inline-table
+[PASS] fieldset with display: ruby
+[FAIL] fieldset with display: ruby-base
+  assert_equals: display: ruby-base is not supported expected "ruby-base" but got "block"
+[FAIL] fieldset with display: ruby-text
+  assert_equals: expected "8px" but got "752px"
+[FAIL] fieldset with display: ruby-base-container
+  assert_equals: display: ruby-base-container is not supported expected "ruby-base-container" but got "block"
+[FAIL] fieldset with display: ruby-text-container
+  assert_equals: display: ruby-text-container is not supported expected "ruby-text-container" but got "block"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-sans-fieldset-display-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-sans-fieldset-display-expected.txt
index 5ea3b013..fe87e39 100644
--- a/third_party/blink/web_tests/platform/linux/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-sans-fieldset-display-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-sans-fieldset-display-expected.txt
@@ -17,8 +17,7 @@
 [FAIL] .inline-block
   assert_equals: .inline-block display expected "inline-block" but got "block"
 [FAIL] .ruby
-  assert_equals: .ruby display expected "inline" but got "block"
-[FAIL] .rt
-  assert_equals: .rt width expected "29px" but got "800px"
+  assert_equals: .ruby display expected "inline" but got "block ruby"
+[PASS] .rt
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-sans-fieldset-display-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-sans-fieldset-display-expected.txt
index de8ca186..fb2c9d85 100644
--- a/third_party/blink/web_tests/platform/mac/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-sans-fieldset-display-expected.txt
+++ b/third_party/blink/web_tests/platform/mac/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-sans-fieldset-display-expected.txt
@@ -17,8 +17,7 @@
 [FAIL] .inline-block
   assert_equals: .inline-block display expected "inline-block" but got "block"
 [FAIL] .ruby
-  assert_equals: .ruby display expected "inline" but got "block"
-[FAIL] .rt
-  assert_equals: .rt width expected "29.3281px" but got "800px"
+  assert_equals: .ruby display expected "inline" but got "block ruby"
+[PASS] .rt
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-display-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-display-expected.txt
new file mode 100644
index 0000000..fdaa81e
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-display-expected.txt
@@ -0,0 +1,30 @@
+This is a testharness.js-based test.
+[PASS] fieldset with display: block
+[PASS] fieldset with display: table
+[PASS] fieldset with display: table-row-group
+[PASS] fieldset with display: table-header-group
+[PASS] fieldset with display: table-footer-group
+[PASS] fieldset with display: table-row
+[PASS] fieldset with display: table-cell
+[PASS] fieldset with display: table-column-group
+[PASS] fieldset with display: table-column
+[PASS] fieldset with display: table-caption
+[PASS] fieldset with display: list-item
+[PASS] fieldset with display: flow-root
+[FAIL] fieldset with display: run-in
+  assert_equals: display: run-in is not supported expected "run-in" but got "block"
+[PASS] fieldset with display: block ruby
+[PASS] fieldset with display: inline
+[PASS] fieldset with display: inline-block
+[PASS] fieldset with display: inline-table
+[PASS] fieldset with display: ruby
+[FAIL] fieldset with display: ruby-base
+  assert_equals: display: ruby-base is not supported expected "ruby-base" but got "block"
+[FAIL] fieldset with display: ruby-text
+  assert_equals: expected "7px" but got "752px"
+[FAIL] fieldset with display: ruby-base-container
+  assert_equals: display: ruby-base-container is not supported expected "ruby-base-container" but got "block"
+[FAIL] fieldset with display: ruby-text-container
+  assert_equals: display: ruby-text-container is not supported expected "ruby-text-container" but got "block"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-sans-fieldset-display-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-sans-fieldset-display-expected.txt
index fe34b2d..fe87e39 100644
--- a/third_party/blink/web_tests/platform/win/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-sans-fieldset-display-expected.txt
+++ b/third_party/blink/web_tests/platform/win/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-sans-fieldset-display-expected.txt
@@ -17,8 +17,7 @@
 [FAIL] .inline-block
   assert_equals: .inline-block display expected "inline-block" but got "block"
 [FAIL] .ruby
-  assert_equals: .ruby display expected "inline" but got "block"
-[FAIL] .rt
-  assert_equals: .rt width expected "27px" but got "800px"
+  assert_equals: .ruby display expected "inline" but got "block ruby"
+[PASS] .rt
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-enabled/external/wpt/webnn/gpu/conv_transpose2d.https.any-expected.txt b/third_party/blink/web_tests/platform/win/virtual/webnn-service-enabled/external/wpt/webnn/gpu/conv_transpose2d.https.any-expected.txt
index 647277c..cf24549 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-enabled/external/wpt/webnn/gpu/conv_transpose2d.https.any-expected.txt
+++ b/third_party/blink/web_tests/platform/win/virtual/webnn-service-enabled/external/wpt/webnn/gpu/conv_transpose2d.https.any-expected.txt
@@ -1,49 +1,49 @@
 This is a testharness.js-based test.
 [FAIL] convTranspose2d float32 4D input and filter(non-constant) tensors default options / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Operator convTranspose2d is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors default options / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Operator convTranspose2d is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.padding / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Operator convTranspose2d is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.strides / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Operator convTranspose2d is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.dilations / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Operator convTranspose2d is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.outputPadding / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Operator convTranspose2d is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.outputSizes / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Operator convTranspose2d is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.autoPad=explicit options.padding / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Operator convTranspose2d is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.autoPad=same-upper / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Operator convTranspose2d is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.autoPad=same-upper ignored options.padding / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Operator convTranspose2d is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.autoPad=same-lower / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Operator convTranspose2d is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.autoPad=same-lower ignored options.padding / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Operator convTranspose2d is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.inputLayout=nchw / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Operator convTranspose2d is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.inputLayout=nhwc / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Operator convTranspose2d is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.filterLayout=iohw / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Operator convTranspose2d is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.filterLayout=hwoi / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: The filter layout hwoi is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.filterLayout=ohwi / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: The filter layout ohwi is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.inputLayout=nhwc options.filterLayout=iohw / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Operator convTranspose2d is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.inputLayout=nhwc options.filterLayout=hwoi / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: The filter layout hwoi is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.inputLayout=nhwc options.filterLayout=ohwi / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: The filter layout ohwi is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.bias / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Operator convTranspose2d is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors, both negative input tensor and options.bias / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Operator convTranspose2d is not supported."
 [FAIL] convTranspose2d float32 4D input and filter tensors options.activation=relu / async
-  promise_test: Unhandled rejection with value: object "DataError: Failed to build graph: convTranspose2d is not implemented."
+  promise_test: Unhandled rejection with value: object "NotSupportedError: Operator convTranspose2d is not supported."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/platform/win/virtual/webnn-service-enabled/external/wpt/webnn/gpu/conv_transpose2d.https.any.worker-expected.txt b/third_party/blink/web_tests/platform/win/virtual/webnn-service-enabled/external/wpt/webnn/gpu/conv_transpose2d.https.any.worker-expected.txt
index 287c880..9241f732 100644
--- a/third_party/blink/web_tests/platform/win/virtual/webnn-service-enabled/external/wpt/webnn/gpu/conv_transpose2d.https.any.worker-expected.txt
+++ b/third_party/blink/web_tests/platform/win/virtual/webnn-service-enabled/external/wpt/webnn/gpu/conv_transpose2d.https.any.worker-expected.txt
@@ -1,50 +1,50 @@
 This is a testharness.js-based test.
 [FAIL] convTranspose2d float32 4D input and filter(non-constant) tensors default options / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Operator convTranspose2d is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors default options / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Operator convTranspose2d is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors options.padding / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Operator convTranspose2d is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors options.strides / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Operator convTranspose2d is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors options.dilations / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Operator convTranspose2d is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors options.outputPadding / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Operator convTranspose2d is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors options.outputSizes / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Operator convTranspose2d is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors options.autoPad=explicit options.padding / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Operator convTranspose2d is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors options.autoPad=same-upper / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Operator convTranspose2d is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors options.autoPad=same-upper ignored options.padding / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Operator convTranspose2d is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors options.autoPad=same-lower / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Operator convTranspose2d is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors options.autoPad=same-lower ignored options.padding / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Operator convTranspose2d is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors options.inputLayout=nchw / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Operator convTranspose2d is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors options.inputLayout=nhwc / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Operator convTranspose2d is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors options.filterLayout=iohw / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Operator convTranspose2d is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors options.filterLayout=hwoi / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: The filter layout hwoi is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors options.filterLayout=ohwi / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: The filter layout ohwi is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors options.inputLayout=nhwc options.filterLayout=iohw / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Operator convTranspose2d is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors options.inputLayout=nhwc options.filterLayout=hwoi / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: The filter layout hwoi is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors options.inputLayout=nhwc options.filterLayout=ohwi / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: The filter layout ohwi is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors options.bias / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Operator convTranspose2d is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors, both negative input tensor and options.bias / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Operator convTranspose2d is not supported.
 [FAIL] convTranspose2d float32 4D input and filter tensors options.activation=relu / sync
-  Failed to execute 'buildSync' on 'MLGraphBuilder': Failed to build graph: convTranspose2d is not implemented.
+  Failed to execute 'buildSync' on 'MLGraphBuilder': Operator convTranspose2d is not supported.
 [FAIL] convTranspose2d float32 4D input and filter(non-constant) tensors default options / async
   promise_test: Unhandled rejection with value: object "TypeError: builder.build is not a function"
 [FAIL] convTranspose2d float32 4D input and filter tensors default options / async
diff --git a/third_party/blink/web_tests/virtual/url-non-special/OWNERS b/third_party/blink/web_tests/virtual/url-non-special/OWNERS
new file mode 100644
index 0000000..0121bbf
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/url-non-special/OWNERS
@@ -0,0 +1 @@
+hayato@chromium.org
diff --git a/third_party/blink/web_tests/virtual/url-non-special/README.md b/third_party/blink/web_tests/virtual/url-non-special/README.md
new file mode 100644
index 0000000..6cee0d66
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/url-non-special/README.md
@@ -0,0 +1,6 @@
+# url-non-special
+
+This suite runs the tests in external/wpt/url with
+`--enable-features=kStandardCompliantNonSpecialSchemeURLParsing`.
+
+See crbug.com/1340837.
diff --git a/third_party/catapult b/third_party/catapult
index 2cb6e99..f25d23e 160000
--- a/third_party/catapult
+++ b/third_party/catapult
@@ -1 +1 @@
-Subproject commit 2cb6e99795633dee1ea15183629bbc98f335702c
+Subproject commit f25d23e77a963e88af9199c7c3a0638268e44538
diff --git a/third_party/cros-components/src b/third_party/cros-components/src
index c33fd88..ccadd23 160000
--- a/third_party/cros-components/src
+++ b/third_party/cros-components/src
@@ -1 +1 @@
-Subproject commit c33fd88eeac4c67cd038ad565ddd94e17093e165
+Subproject commit ccadd234bf9dfa004a69560ed58874a857541e19
diff --git a/third_party/dawn b/third_party/dawn
index 3e56a38..d3e897d 160000
--- a/third_party/dawn
+++ b/third_party/dawn
@@ -1 +1 @@
-Subproject commit 3e56a384d541a9340164373c5640585401933b14
+Subproject commit d3e897d992221ddddce7a9a7893fa66db8559c52
diff --git a/third_party/depot_tools b/third_party/depot_tools
index 88cc0b8..dbd2967 160000
--- a/third_party/depot_tools
+++ b/third_party/depot_tools
@@ -1 +1 @@
-Subproject commit 88cc0b8ca8ab9103b94db6552e9f1ed4789445a8
+Subproject commit dbd29671bd11c2d59fa898722bdbbcb7d48b8f8b
diff --git a/third_party/devtools-frontend-internal b/third_party/devtools-frontend-internal
index 145e213..34951c1 160000
--- a/third_party/devtools-frontend-internal
+++ b/third_party/devtools-frontend-internal
@@ -1 +1 @@
-Subproject commit 145e21383e933fc2247a6f54e04772ac246f3763
+Subproject commit 34951c1d294f6e511c2ce3ecb17973a3a37cc1af
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index 58176c0..cef1d4d 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit 58176c04eea85c8e8746c2142a7cc3cb4c9e9553
+Subproject commit cef1d4d47c8c59859778863f2ab83b7b9db68aa3
diff --git a/third_party/pdfium b/third_party/pdfium
index 6a34da3..7233e99 160000
--- a/third_party/pdfium
+++ b/third_party/pdfium
@@ -1 +1 @@
-Subproject commit 6a34da391b15f5373247fda48c10a12bc4143c94
+Subproject commit 7233e99fcaeb18adbf048be2df0b1cca355abc70
diff --git a/third_party/skia b/third_party/skia
index 6ff0fdf..65a5cd0 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit 6ff0fdf79bfa8baf79c778e2713f4aa01fba26a6
+Subproject commit 65a5cd082bea45d16a7b4a251934acc632e77032
diff --git a/third_party/webgpu-cts/src b/third_party/webgpu-cts/src
index 04c09a8..8eee61b 160000
--- a/third_party/webgpu-cts/src
+++ b/third_party/webgpu-cts/src
@@ -1 +1 @@
-Subproject commit 04c09a823d9601c256b97ee1ffeef796d7d8f5fa
+Subproject commit 8eee61b66c5987e48fed3fc362910a52f91eb1ca
diff --git a/third_party/webgpu-cts/ts_sources.txt b/third_party/webgpu-cts/ts_sources.txt
index 4132a0bc..5476a4a 100644
--- a/third_party/webgpu-cts/ts_sources.txt
+++ b/third_party/webgpu-cts/ts_sources.txt
@@ -334,6 +334,7 @@
 src/webgpu/compat/compatibility_test.ts
 src/webgpu/compat/api/validation/createBindGroup.spec.ts
 src/webgpu/compat/api/validation/encoding/cmds/copyTextureToBuffer.spec.ts
+src/webgpu/compat/api/validation/encoding/cmds/copyTextureToTexture.spec.ts
 src/webgpu/compat/api/validation/encoding/programmable/pipeline_bind_group_compat.spec.ts
 src/webgpu/compat/api/validation/render_pipeline/fragment_state.spec.ts
 src/webgpu/compat/api/validation/render_pipeline/shader_module.spec.ts
diff --git a/third_party/win_virtual_display/controller/display_driver_controller.cc b/third_party/win_virtual_display/controller/display_driver_controller.cc
index f7b92ea..0200b8d 100644
--- a/third_party/win_virtual_display/controller/display_driver_controller.cc
+++ b/third_party/win_virtual_display/controller/display_driver_controller.cc
@@ -49,8 +49,8 @@
                                SWDeviceCapabilitiesDriverRequired;
 
   // Set configuration properties to send to the driver.
-  display::test::DriverProperties p({display::test::MonitorMode::k1024x768,
-                                     display::test::MonitorMode::k1920x1080});
+  display::test::DriverProperties p({display::test::MonitorConfig::k1024x768,
+                                     display::test::MonitorConfig::k1920x1080});
 
   DEVPROPERTY properties[1];
   DEVPROPERTY& property = properties[0];
diff --git a/third_party/win_virtual_display/driver/ChromiumVirtualDisplayDriver.inf b/third_party/win_virtual_display/driver/ChromiumVirtualDisplayDriver.inf
index 23dc153bb..835b0e0 100644
--- a/third_party/win_virtual_display/driver/ChromiumVirtualDisplayDriver.inf
+++ b/third_party/win_virtual_display/driver/ChromiumVirtualDisplayDriver.inf
Binary files differ
diff --git a/third_party/win_virtual_display/driver/Driver.cpp b/third_party/win_virtual_display/driver/Driver.cpp
index 0639829..4251878e 100644
--- a/third_party/win_virtual_display/driver/Driver.cpp
+++ b/third_party/win_virtual_display/driver/Driver.cpp
@@ -166,16 +166,17 @@
                 "WdfDeviceQueryPropertyEx failed: %!STATUS!", Status);
     return Status;
   }
-  const std::vector<display::test::MonitorMode>& requested_modes =
-      driver_properties.requested_modes();
+  const std::vector<display::test::MonitorConfig>& requested_configs =
+      driver_properties.requested_configs();
   TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "num_displays: %llu",
-              requested_modes.size());
+              requested_configs.size());
 
-  for (const auto& mode : requested_modes) {
+  for (const auto& config : requested_configs) {
     display::test::IndirectMonitor indirect_monitor;
     display::test::Edid edid(indirect_monitor.pEdidBlock.data());
-    bool success = edid.GetTimingEntry(0)->SetMode(mode.width(), mode.height(),
-                                                   mode.v_sync());
+    bool success = edid.GetTimingEntry(0)->SetMode(
+        config.width(), config.height(), config.v_sync());
+    edid.SetProductCode(config.product_code());
     if (!success) {
       TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "SetMode() unsuccessful");
     }
@@ -184,8 +185,8 @@
     TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER,
                 "Width (Modified EDID,Chosen Mode) (Inside "
                 "EvtWdfDriverDeviceAdd): %ld, %hu",
-                edid.GetTimingEntry(0)->GetWidth(), mode.width());
-    indirect_monitor.pModeList.push_back(mode);
+                edid.GetTimingEntry(0)->GetWidth(), config.width());
+    indirect_monitor.pConfigList.push_back(config);
     pContext->pContext->monitors.push_back(indirect_monitor);
   }
 
@@ -349,8 +350,8 @@
         new IndirectMonitorContext(MonitorCreateOut.MonitorObject);
 
     if (ConnectorIndex < monitors.size()) {
-      pMonitorContextWrapper->pContext->default_mode_list =
-          monitors[ConnectorIndex].pModeList;
+      pMonitorContextWrapper->pContext->default_config_list =
+          monitors[ConnectorIndex].pConfigList;
     }
 
     // Tell the OS that the monitor has been plugged in
@@ -495,24 +496,23 @@
 
   if (pInArgs->DefaultMonitorModeBufferInputCount == 0) {
     pOutArgs->DefaultMonitorModeBufferOutputCount = static_cast<UINT>(
-        pMonitorContextWrapper->pContext->default_mode_list.size());
+        pMonitorContextWrapper->pContext->default_config_list.size());
   } else {
-    for (DWORD ModeIndex = 0;
-         ModeIndex < pMonitorContextWrapper->pContext->default_mode_list.size();
-         ModeIndex++) {
-      const display::test::MonitorMode mode =
-          pMonitorContextWrapper->pContext->default_mode_list[ModeIndex];
+    for (DWORD i = 0;
+         i < pMonitorContextWrapper->pContext->default_config_list.size();
+         i++) {
+      const display::test::MonitorConfig config =
+          pMonitorContextWrapper->pContext->default_config_list[i];
       TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER,
-                  "Making the default modes: %hu, %hu, %hu", mode.width(),
-                  mode.height(), mode.v_sync());
-      pInArgs->pDefaultMonitorModes[ModeIndex] =
-          display::test::CreateIddCxMonitorMode(
-              mode.width(), mode.height(), mode.v_sync(),
-              IDDCX_MONITOR_MODE_ORIGIN_DRIVER);
+                  "Making the default modes: %hu, %hu, %hu", config.width(),
+                  config.height(), config.v_sync());
+      pInArgs->pDefaultMonitorModes[i] = display::test::CreateIddCxMonitorMode(
+          config.width(), config.height(), config.v_sync(),
+          IDDCX_MONITOR_MODE_ORIGIN_DRIVER);
     }
 
     pOutArgs->DefaultMonitorModeBufferOutputCount = static_cast<UINT>(
-        pMonitorContextWrapper->pContext->default_mode_list.size());
+        pMonitorContextWrapper->pContext->default_config_list.size());
     pOutArgs->PreferredMonitorModeIdx = 0;
   }
 
diff --git a/third_party/win_virtual_display/driver/Driver.h b/third_party/win_virtual_display/driver/Driver.h
index 707f69d..8b1f38e 100644
--- a/third_party/win_virtual_display/driver/Driver.h
+++ b/third_party/win_virtual_display/driver/Driver.h
@@ -44,9 +44,9 @@
                        HANDLE NewFrameEvent);
   void UnassignSwapChain();
 
-  // Default modes reported for edid-less monitors. The first mode is set as
+  // Default modes reported for edid-less monitors. The first config is set as
   // preferred
-  std::vector<MonitorMode> default_mode_list;
+  std::vector<MonitorConfig> default_config_list;
 
  private:
   IDDCX_MONITOR m_Monitor;
diff --git a/third_party/win_virtual_display/driver/Edid.cpp b/third_party/win_virtual_display/driver/Edid.cpp
index 0455696..8e88f47 100644
--- a/third_party/win_virtual_display/driver/Edid.cpp
+++ b/third_party/win_virtual_display/driver/Edid.cpp
@@ -51,7 +51,6 @@
   return vertical_frequency + 60;
 }
 
-// Return timing entries (Standard timing information; EDID 1.4).
 EdidTimingEntry* Edid::GetTimingEntry(int entry) {
   assert(0 <= entry && entry < 8);
   // Timing entries start at byte 38.
@@ -59,6 +58,13 @@
                                             (entry * sizeof(EdidTimingEntry)));
 }
 
+void Edid::SetProductCode(unsigned short code) {
+  // Manufacturer product code is bytes 10-11.
+  unsigned short* mfg_code =
+      reinterpret_cast<unsigned short*>(edidBlock.data() + 10);
+  *mfg_code = code;
+}
+
 void Edid::UpdateChecksum() {
   assert(edidBlock.size() == kBlockSize);
   // Sum all bytes except the last.
diff --git a/third_party/win_virtual_display/driver/Edid.h b/third_party/win_virtual_display/driver/Edid.h
index b61af71..b0cd708 100644
--- a/third_party/win_virtual_display/driver/Edid.h
+++ b/third_party/win_virtual_display/driver/Edid.h
@@ -57,6 +57,9 @@
   // There are 8 entries. `entry` should be in in the range [0,8).
   EdidTimingEntry* GetTimingEntry(int entry);
 
+  // Set the manufacturer product code (EDID 1.4).
+  void SetProductCode(unsigned short code);
+
   // Updates the checksum byte to be valid.
   void UpdateChecksum();
 
diff --git a/third_party/win_virtual_display/driver/IndirectMonitor.h b/third_party/win_virtual_display/driver/IndirectMonitor.h
index 4eaf6ff..97863ed2 100644
--- a/third_party/win_virtual_display/driver/IndirectMonitor.h
+++ b/third_party/win_virtual_display/driver/IndirectMonitor.h
@@ -21,7 +21,7 @@
   static constexpr size_t kModeListLength = 1;
   // Modified EDID from Dell S2719DGF
   std::array<unsigned char, Edid::kBlockSize> pEdidBlock = {
-      0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x10, 0xAC, 0xE6, 0xD0,
+      0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xC4, 0x0E, 0xE6, 0xD0,
       0x55, 0x5A, 0x4A, 0x30, 0x24, 0x1D, 0x01, 0x04, 0xA5, 0x3C, 0x22, 0x78,
       0xFB, 0x6C, 0xE5, 0xA5, 0x55, 0x50, 0xA0, 0x23, 0x0B, 0x50, 0x54, 0x00,
       0x02, 0x00, 0xD1, 0xC0, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
@@ -32,7 +32,7 @@
       0x32, 0x37, 0x31, 0x39, 0x44, 0x47, 0x46, 0x0A, 0x20, 0x20, 0x20, 0x20,
       0x00, 0x00, 0x00, 0xFD, 0x00, 0x28, 0x9B, 0xFA, 0xFA, 0x40, 0x01, 0x0A,
       0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x2C};
-  std::vector<MonitorMode> pModeList;
+  std::vector<MonitorConfig> pConfigList;
 };
 }  // namespace display::test
 
diff --git a/third_party/win_virtual_display/driver/public/properties.cc b/third_party/win_virtual_display/driver/public/properties.cc
index a5504e51..fefb920 100644
--- a/third_party/win_virtual_display/driver/public/properties.cc
+++ b/third_party/win_virtual_display/driver/public/properties.cc
@@ -6,18 +6,19 @@
 #include <iterator>
 
 namespace display::test {
-const MonitorMode MonitorMode::k1024x768 = MonitorMode(1024, 768);
-const MonitorMode MonitorMode::k1920x1080 = MonitorMode(1920, 1080);
+const MonitorConfig MonitorConfig::k1024x768 = MonitorConfig(1024, 768);
+const MonitorConfig MonitorConfig::k1920x1080 = MonitorConfig(1920, 1080);
 
-DriverProperties::DriverProperties(const std::vector<MonitorMode>& modes) {
-  requested_modes_size_ = std::min(modes.size(), kMaxMonitors);
-  std::copy_n(modes.begin(), requested_modes_size_, requested_modes_.begin());
+DriverProperties::DriverProperties(const std::vector<MonitorConfig>& modes) {
+  requested_configs_size_ = std::min(modes.size(), kMaxMonitors);
+  std::copy_n(modes.begin(), requested_configs_size_,
+              requested_configs_.begin());
 }
 
 // Return a vector of the requested monitor configurations.
-std::vector<MonitorMode> DriverProperties::requested_modes() const {
-  std::vector<MonitorMode> vector;
-  std::copy_n(requested_modes_.begin(), requested_modes_size_,
+std::vector<MonitorConfig> DriverProperties::requested_configs() const {
+  std::vector<MonitorConfig> vector;
+  std::copy_n(requested_configs_.begin(), requested_configs_size_,
               std::back_inserter(vector));
   return vector;
 }
diff --git a/third_party/win_virtual_display/driver/public/properties.h b/third_party/win_virtual_display/driver/public/properties.h
index 1e01552..2d14da58 100644
--- a/third_party/win_virtual_display/driver/public/properties.h
+++ b/third_party/win_virtual_display/driver/public/properties.h
@@ -38,29 +38,37 @@
                   2);
 
 // Holds configuration for a virtual display.
-class MonitorMode {
+class MonitorConfig {
  public:
-  // List of supported monitor modes.
-  static const MonitorMode k1024x768;
-  static const MonitorMode k1920x1080;
+  // List of configs with supported monitor modes.
+  static const MonitorConfig k1024x768;
+  static const MonitorConfig k1920x1080;
 
-  MonitorMode() = default;
+  MonitorConfig() = default;
   // Get width (horizontal resolution).
   unsigned short width() const { return width_; }
   // Get height (vertical resolution).
   unsigned short height() const { return height_; }
   // Get vertical sync (refresh rate).
   unsigned short v_sync() const { return v_sync_; }
+  // Manufacturer product code to be assigned to the EDID.
+  unsigned short product_code() const { return product_code_; }
+  void set_product_code(unsigned short v) { product_code_ = v; }
 
  private:
   // Private constructor. Use the defined constants for supported modes.
-  constexpr MonitorMode(unsigned short width,
-                        unsigned short height,
-                        unsigned short v_sync = 60)
-      : width_(width), height_(height), v_sync_(v_sync) {}
+  constexpr MonitorConfig(unsigned short width,
+                          unsigned short height,
+                          unsigned short v_sync = 60,
+                          unsigned short product_code = 0)
+      : width_(width),
+        height_(height),
+        v_sync_(v_sync),
+        product_code_(product_code) {}
   unsigned short width_;   // Horizontal resolution.
   unsigned short height_;  // Vertical resolution.
   unsigned short v_sync_;  // Vertical sync (refresh rate).
+  unsigned short product_code_;  // Manufacturer product code.
 };
 
 // Define the corresponding structure associated with the
@@ -70,17 +78,16 @@
   // Maximum number of virtual displays that may be created.
   static constexpr size_t kMaxMonitors = 10;
   DriverProperties() = default;
-  // Create monitors with the specified modes. If the length of `modes` is
-  // greater than `kMaxMonitors`, the modes are truncated to `kMaxMonitors`.
-  explicit DriverProperties(const std::vector<MonitorMode>& modes);
+  // Create monitors with the specified `configs`, truncated to `kMaxMonitors`.
+  explicit DriverProperties(const std::vector<MonitorConfig>& configs);
   // Return a vector of the requested monitor configurations.
-  std::vector<MonitorMode> requested_modes() const;
+  std::vector<MonitorConfig> requested_configs() const;
 
  private:
   // std::vector doesn't work here due to serialization & Windows API
   // limitations so a fixed array is used instead.
-  std::array<MonitorMode, kMaxMonitors> requested_modes_ = {};
-  size_t requested_modes_size_ = 0;
+  std::array<MonitorConfig, kMaxMonitors> requested_configs_ = {};
+  size_t requested_configs_size_ = 0;
 };
 
 }  // namespace display::test
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index ef453cc5..3040c323 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -43281,6 +43281,7 @@
   <int value="-370229772" label="RefreshFeedOnRestart:enabled"/>
   <int value="-369565225" label="SkipServiceWorkerCheckInstallOnly:disabled"/>
   <int value="-369150124" label="SendTabToSelfV2:enabled"/>
+  <int value="-368811558" label="DynamicTopChrome:enabled"/>
   <int value="-368106169"
       label="CrOSLateBootCrasSplitAlsaUSBInternal:disabled"/>
   <int value="-367474066" label="DialogTouchBar:enabled"/>
@@ -45782,6 +45783,7 @@
   <int value="824961931" label="use-simple-cache-backend"/>
   <int value="824968180" label="SimLockPolicy:enabled"/>
   <int value="828092263" label="TemporaryUnexpireFlagsM78:enabled"/>
+  <int value="828678083" label="DynamicTopChrome:disabled"/>
   <int value="830282555" label="DecodeJpeg420ImagesToYUV:enabled"/>
   <int value="830354646" label="SecondaryGoogleAccountUsage:disabled"/>
   <int value="832142463" label="WebAssemblyStreaming:enabled"/>
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index 5a0c2940..22fca2bc 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -6677,36 +6677,47 @@
 </histogram>
 
 <histogram name="Ash.TouchView.TouchViewActive" units="ms"
-    expires_after="2024-03-17">
-  <owner>girard@chromium.org</owner>
+    expires_after="2024-04-03">
+  <owner>xdai@chromium.org</owner>
+  <owner>chromeos-wm-corexp@google.com</owner>
   <summary>
     The length of time that TouchView is active, for each activation.
   </summary>
 </histogram>
 
 <histogram name="Ash.TouchView.TouchViewActivePercentage" units="%"
-    expires_after="2024-04-28">
-  <owner>girard@chromium.org</owner>
+    expires_after="2024-04-03">
+  <owner>xdai@chromium.org</owner>
+  <owner>chromeos-wm-corexp@google.com</owner>
   <summary>The proportion of time spent in TouchView during a session.</summary>
 </histogram>
 
 <histogram name="Ash.TouchView.TouchViewActiveTotal" units="minutes"
-    expires_after="2024-04-28">
-  <owner>girard@chromium.org</owner>
+    expires_after="2024-04-03">
+  <owner>xdai@chromium.org</owner>
+  <owner>chromeos-wm-corexp@google.com</owner>
   <summary>The total time that TouchView is active during a session.</summary>
 </histogram>
 
 <histogram name="Ash.TouchView.TouchViewInactive" units="ms"
-    expires_after="2023-03-19">
-  <owner>girard@chromium.org</owner>
-  <summary>The length of time between TouchView activations.</summary>
+    expires_after="2024-04-03">
+  <owner>xdai@chromium.org</owner>
+  <owner>chromeos-wm-corexp@google.com</owner>
+  <summary>
+    The length of time between TouchView activations.
+    Warning: this histogram was expired from 2023-03-19 to 2023-11-06; data may
+    be missing.
+  </summary>
 </histogram>
 
 <histogram name="Ash.TouchView.TouchViewInactiveTotal" units="minutes"
-    expires_after="2023-03-19">
-  <owner>girard@chromium.org</owner>
+    expires_after="2024-04-03">
+  <owner>xdai@chromium.org</owner>
+  <owner>chromeos-wm-corexp@google.com</owner>
   <summary>
     The total time that TouchView is not active during a session.
+    Warning: this histogram was expired from 2023-03-19 to 2023-11-06; data may
+    be missing.
   </summary>
 </histogram>
 
diff --git a/tools/metrics/histograms/metadata/net/histograms.xml b/tools/metrics/histograms/metadata/net/histograms.xml
index 27aef30..0761ed21 100644
--- a/tools/metrics/histograms/metadata/net/histograms.xml
+++ b/tools/metrics/histograms/metadata/net/histograms.xml
@@ -5099,13 +5099,13 @@
   </summary>
 </histogram>
 
-<histogram name="Net.SpdySession.OnSettings.{StreamState}StreamCount"
+<histogram name="Net.SpdySession.OnSettings.{StreamState}StreamCount2"
     units="count" expires_after="2024-05-05">
   <owner>bashi@chromium.org</owner>
   <owner>chrome-network-stack@google.com</owner>
   <summary>
     Records the number of {StreamState} streams when a SpdySession receives an
-    HTTP/2 SETTINGS frame.
+    HTTP/2 SETTINGS frame for the first time.
   </summary>
   <token key="StreamState">
     <variant name="Active" summary="active"/>
diff --git a/tools/metrics/histograms/metadata/optimization/histograms.xml b/tools/metrics/histograms/metadata/optimization/histograms.xml
index 590c875..f35e90a 100644
--- a/tools/metrics/histograms/metadata/optimization/histograms.xml
+++ b/tools/metrics/histograms/metadata/optimization/histograms.xml
@@ -404,7 +404,7 @@
 
 <histogram
     name="OptimizationGuide.HintsManager.ConcurrentPageNavigationFetches"
-    units="counts" expires_after="2023-11-12">
+    units="counts" expires_after="M125">
   <owner>sophiechang@chromium.org</owner>
   <owner>mcrouse@chromium.org</owner>
   <summary>
@@ -826,7 +826,7 @@
 <histogram
     name="OptimizationGuide.PageContentAnnotationsService.ContentAnnotationsStorageStatus"
     enum="OptimizationGuidePageContentAnnotationsStorageStatus"
-    expires_after="2023-11-19">
+    expires_after="M125">
   <owner>sophiechang@chromium.org</owner>
   <owner>mcrouse@chromium.org</owner>
   <summary>
@@ -915,7 +915,7 @@
 
 <histogram
     name="OptimizationGuide.PageEntitiesModelHandler.CreatedSuccessfully"
-    enum="BooleanSuccess" expires_after="2023-11-12">
+    enum="BooleanSuccess" expires_after="M125">
   <owner>sophiechang@chromium.org</owner>
   <owner>chrome-intelligence-core@google.com</owner>
   <summary>
@@ -926,8 +926,7 @@
 </histogram>
 
 <histogram name="OptimizationGuide.PageEntitiesModelHandler.CreationStatus"
-    enum="OptimizationGuideEntityAnnotatorCreationStatus"
-    expires_after="2023-11-12">
+    enum="OptimizationGuideEntityAnnotatorCreationStatus" expires_after="M125">
   <owner>sophiechang@chromium.org</owner>
   <owner>chrome-intelligence-core@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/page/histograms.xml b/tools/metrics/histograms/metadata/page/histograms.xml
index 3cab23e9..7d84879 100644
--- a/tools/metrics/histograms/metadata/page/histograms.xml
+++ b/tools/metrics/histograms/metadata/page/histograms.xml
@@ -594,8 +594,7 @@
 
 <histogram
     name="PageLoad.Clients.AMP.PaintTiming.InputToLargestContentfulPaint.Subframe.FullNavigation"
-    units="ms" expires_after="2023-06-18">
-  <owner>bmcquade@chromium.org</owner>
+    units="ms" expires_after="2024-02-09">
   <owner>sullivan@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
@@ -607,7 +606,7 @@
     image paint. See http://bit.ly/fcp_plus_plus for details.
 
     This histogram has incomplete data. It expired after M78 and was re-added in
-    M90, and also after 2022-12-11 until M111.
+    M90, also after 2022-12-11 until M111, and also after 2023-06-18 until M121.
   </summary>
 </histogram>
 
@@ -819,14 +818,16 @@
 
 <histogram
     name="PageLoad.Clients.GoogleSearch.ParseTiming.NavigationToParseStart"
-    units="ms" expires_after="2023-10-01">
-  <owner>spelchat@chromium.org</owner>
-  <owner>chrome-brapp-loading@google.com</owner>
+    units="ms" expires_after="2024-02-09">
+  <owner>kouhei@chromium.org</owner>
+  <owner>chrome-loading@google.com</owner>
   <summary>
     Measures the time from navigation timing's navigation start to the time the
     parser started, for Google Search page loads. Only recorded for Search
     navigations that start in the foreground and stay in the foreground until
     parse start.
+
+    This metric has incomplete data. It was expired between 2023-10-01 and M121.
   </summary>
 </histogram>
 
@@ -1321,7 +1322,7 @@
 
 <histogram
     name="PageLoad.Clients.UseCounter.Experimental.MetricsReplayAtActivationDuration"
-    units="ms" expires_after="2023-09-03">
+    units="ms" expires_after="2024-02-09">
   <owner>kenoss@chromium.org</owner>
   <owner>toyoshim@chromium.org</owner>
   <summary>
@@ -1334,8 +1335,8 @@
     recorded. This metric records the duration of this flush, in case of this
     cause a performance degradation.
 
-    Warning: this histogram was expired from 2023-03-16 to 2023-03-29; data may
-    be missing.
+    Warning: this histogram was expired from 2023-03-16 to 2023-03-2 9and also
+    between 2023-09-03 and M121; data may be missing.
   </summary>
 </histogram>
 
@@ -1692,34 +1693,40 @@
 
 <histogram
     name="PageLoad.Experimental.NavigationTiming.NavigationStartToFinalRequestStart"
-    units="ms" expires_after="2023-03-12">
+    units="ms" expires_after="2024-02-09">
   <owner>nhiroki@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
     The time relative to navigation start that the final HTTP request is sent
     for the main resource of a main frame navigation.
+
+    This metric has incomplete data. It was expired between 2023-03-12 and M121.
   </summary>
 </histogram>
 
 <histogram
     name="PageLoad.Experimental.NavigationTiming.NavigationStartToFinalResponseStart"
-    units="ms" expires_after="2022-12-18">
+    units="ms" expires_after="2024-02-09">
   <owner>nhiroki@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
     The time relative to navigation start that the headers of the final HTTP
     response is received for the main resource of a main frame navigation.
+
+    This metric has incomplete data. It was expired between 2022-12-18 and M121.
   </summary>
 </histogram>
 
 <histogram
     name="PageLoad.Experimental.NavigationTiming.NavigationStartToFirstLoaderCallback"
-    units="ms" expires_after="2023-07-09">
+    units="ms" expires_after="2024-02-09">
   <owner>nhiroki@chromium.org</owner>
   <owner>chrome-loading@google.com</owner>
   <summary>
     The time relative to navigation start that a callback for the navigation
     loader is first invoked for the main resource of a main frame navigation.
+
+    This metric has incomplete data. It was expired between 2023-07-09 and M121.
   </summary>
 </histogram>
 
@@ -1758,32 +1765,36 @@
 
 <histogram
     name="PageLoad.Experimental.PageTiming.CachedResourceLoadTime.{RequestDestination}"
-    units="ms" expires_after="2023-08-07">
+    units="ms" expires_after="2024-02-09">
   <owner>cduvall@chromium.org</owner>
   <owner>jam@chromium.org</owner>
   <summary>
     Measures the time from load start to when headers have been received for
     resource requests which come from the cache. Logged for every
     {RequestDestination} resource request from the cache.
+
+    This metric has incomplete data. It was expired between 2023-08-07 and M121.
   </summary>
   <token key="RequestDestination" variants="RequestDestination"/>
 </histogram>
 
 <histogram
     name="PageLoad.Experimental.PageTiming.CommitSentToFirstSubresourceLoadStart"
-    units="ms" expires_after="2023-02-12">
+    units="ms" expires_after="2024-02-09">
   <owner>cduvall@chromium.org</owner>
   <owner>jam@chromium.org</owner>
   <summary>
     Measures the time from when the navigation commit was sent to the renderer
     to the first subresource load start. Logged for every page load which has
     subresources.
+
+    This metric has incomplete data. It was expired between 2023-02-12 and M121.
   </summary>
 </histogram>
 
 <histogram
     name="PageLoad.Experimental.PageTiming.NavigationToFirstSubresourceLoadStart"
-    units="ms" expires_after="2023-08-07">
+    units="ms" expires_after="2024-02-09">
   <owner>cduvall@chromium.org</owner>
   <owner>jam@chromium.org</owner>
   <summary>
@@ -1794,7 +1805,7 @@
 
 <histogram
     name="PageLoad.Experimental.PageTiming.ResourceLoadTime.{RequestDestination}"
-    units="ms" expires_after="2023-08-07">
+    units="ms" expires_after="2024-02-09">
   <owner>cduvall@chromium.org</owner>
   <owner>jam@chromium.org</owner>
   <summary>
@@ -1807,7 +1818,7 @@
 
 <histogram
     name="PageLoad.Experimental.PageTiming.TotalSubresourceLoadTimeAtFirstContentfulPaint"
-    units="ms" expires_after="2023-08-07">
+    units="ms" expires_after="2024-02-09">
   <owner>cduvall@chromium.org</owner>
   <owner>jam@chromium.org</owner>
   <summary>
@@ -1844,7 +1855,7 @@
 
 <histogram
     name="PageLoad.Experimental.PaintTiming.FirstEligibleToPaintToFirstPaint"
-    units="ms" expires_after="2023-04-16">
+    units="ms" expires_after="2024-02-09">
   <owner>cduvall@chromium.org</owner>
   <owner>jam@chromium.org</owner>
   <summary>
@@ -2383,7 +2394,7 @@
 
 <histogram
     name="PageLoad.Internal.Prerender2.ForegroundCheckResult.{PageLoadPrerenderForegroundCheckEvent}"
-    enum="PageLoadPrerenderForegroundCheckResult" expires_after="2023-10-03">
+    enum="PageLoadPrerenderForegroundCheckResult" expires_after="2024-02-09">
   <owner>nhiroki@chromium.org</owner>
   <owner>src/content/browser/preloading/prerender/OWNERS</owner>
   <summary>
@@ -2930,7 +2941,7 @@
 
 <histogram
     name="PageLoad.PaintTiming.NavigationToLargestContentfulPaint2AtFirstOnHidden"
-    units="ms" expires_after="2023-08-08">
+    units="ms" expires_after="2024-02-09">
   <owner>lanwei@chromium.org</owner>
   <owner>speed-metrics-dev@chromium.org</owner>
   <summary>
@@ -2988,7 +2999,7 @@
 
 <histogram
     name="PageLoad.ParseTiming.ParseBlockedOnScriptExecutionFromDocumentWrite"
-    units="ms" expires_after="2023-05-29">
+    units="ms" expires_after="2024-02-09">
   <owner>cduvall@chromium.org</owner>
   <owner>swarm-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/tab/histograms.xml b/tools/metrics/histograms/metadata/tab/histograms.xml
index dda09ad..09552498 100644
--- a/tools/metrics/histograms/metadata/tab/histograms.xml
+++ b/tools/metrics/histograms/metadata/tab/histograms.xml
@@ -725,28 +725,6 @@
   </summary>
 </histogram>
 
-<histogram
-    name="TabManager.Experimental.SessionRestore.TabSwitchLoadTime.UntilTabIsLoaded"
-    units="ms" expires_after="M79">
-  <owner>chrisha@chromium.org</owner>
-  <summary>
-    The tab load time of a tab that is switched to during a session restore. Tab
-    load time is defined as the time between when the user switches to a
-    backround tab, and the time when that tab finishes loading in the
-    foreground. If the user switches away before the tab finishes loading, a
-    metric will not be recorded unless the user switches back, in which case the
-    tab load time is measured from that point in time. The metric is only
-    recorded when a tab is switched to from another tab within the same
-    tabstrip. As a result, the initial forground tab is not included in this
-    metric since it was not switched to from another tab. The metric is only
-    recorded when session restore is actively loading tabs, which ends when
-    either all tabs have been loaded and their pages rendered, or tab loading
-    needs to be deferred in cases where the system is under memory pressure. The
-    metric is not recorded when the session overlaps with background tab opening
-    session.
-  </summary>
-</histogram>
-
 <histogram name="TabManager.SessionOverlap.BackgroundTabOpening"
     enum="BooleanOverlap" expires_after="M79">
   <owner>chrisha@chromium.org</owner>
diff --git a/tools/traffic_annotation/safe_list.txt b/tools/traffic_annotation/safe_list.txt
index 9f1dfbb5..1c57877 100644
--- a/tools/traffic_annotation/safe_list.txt
+++ b/tools/traffic_annotation/safe_list.txt
@@ -179,7 +179,7 @@
 missing_new_fields,chromeos/ash/components/timezone/timezone_request.cc
 missing_new_fields,chromeos/components/quick_answers/result_loader.cc
 missing_new_fields,components/assist_ranker/ranker_url_fetcher.cc
-missing_new_fields,components/autofill/core/browser/payments/payments_client.cc
+missing_new_fields,components/autofill/core/browser/payments/payments_network_interface.cc
 missing_new_fields,components/captive_portal/content/captive_portal_service.cc
 missing_new_fields,components/commerce/core/account_checker.cc
 missing_new_fields,components/commerce/core/subscriptions/subscriptions_server_proxy.cc
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index 404ac95..38f65fa 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -152,7 +152,7 @@
  <item id="password_protection_request" added_in_milestone="62" content_hash_code="01869413" os_list="linux,windows,chromeos,android" file_path="components/safe_browsing/core/browser/password_protection/password_protection_request.cc" />
  <item id="password_requirements_spec_fetch" added_in_milestone="69" content_hash_code="005550dc" os_list="linux,windows,chromeos,android" file_path="components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc" />
  <item id="payment_manifest_downloader" added_in_milestone="62" content_hash_code="01266484" os_list="linux,windows,chromeos,android" file_path="components/payments/core/payment_manifest_downloader.cc" />
- <item id="payments_sync_cards" added_in_milestone="62" content_hash_code="035e86b1" os_list="linux,windows,chromeos,android" file_path="components/autofill/core/browser/payments/payments_client.cc" />
+ <item id="payments_sync_cards" added_in_milestone="62" content_hash_code="035e86b1" os_list="linux,windows,chromeos,android" file_path="components/autofill/core/browser/payments/payments_network_interface.cc" />
  <item id="pdf_plugin_placeholder" added_in_milestone="63" content_hash_code="0101fbd5" os_list="linux,windows,chromeos" file_path="chrome/browser/plugins/plugin_observer.cc" />
  <item id="pepper_tcp_socket" added_in_milestone="65" content_hash_code="01a37664" os_list="linux,windows,chromeos" file_path="content/browser/renderer_host/pepper/pepper_socket_utils.cc" />
  <item id="pepper_udp_socket" added_in_milestone="70" content_hash_code="006ee842" os_list="linux,windows,chromeos" file_path="content/browser/renderer_host/pepper/pepper_socket_utils.cc" />
diff --git a/ui/accessibility/platform/ax_platform_node.h b/ui/accessibility/platform/ax_platform_node.h
index 8915e8b..4e94f3d 100644
--- a/ui/accessibility/platform/ax_platform_node.h
+++ b/ui/accessibility/platform/ax_platform_node.h
@@ -29,6 +29,8 @@
 // own the AXPlatformNode instance (or otherwise manage its lifecycle).
 class COMPONENT_EXPORT(AX_PLATFORM) AXPlatformNode {
  public:
+  enum class AnnouncementType { kAlert, kPolite };
+
   using NativeWindowHandlerCallback =
       base::RepeatingCallback<AXPlatformNode*(gfx::NativeWindow)>;
 
@@ -95,8 +97,14 @@
   virtual void NotifyAccessibilityEvent(ax::mojom::Event event_type) = 0;
 
 #if BUILDFLAG(IS_APPLE)
-  // Fire a platform-specific notification to announce |text|.
-  virtual void AnnounceText(const std::u16string& text) = 0;
+  // Fire a platform-specific notification to speak the |text| string.
+  // AnnouncementType kPolite will speak the given string.
+  // AnnouncementType kAlert may make a stronger attempt to be noticeable;
+  // the screen reader may say something like "Alert: hello" instead of
+  // just "hello", and may interrupt any existing text being spoken.
+  // However, the screen reader may also just treat the two calls the same.
+  virtual void AnnounceTextAs(const std::u16string& text,
+                              AnnouncementType announcement_type) = 0;
 #endif
 
   // Return this object's delegate.
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc
index fc6a1e8..907f185 100644
--- a/ui/accessibility/platform/ax_platform_node_base.cc
+++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -467,7 +467,8 @@
 }
 
 #if BUILDFLAG(IS_APPLE)
-void AXPlatformNodeBase::AnnounceText(const std::u16string& text) {}
+void AXPlatformNodeBase::AnnounceTextAs(const std::u16string& text,
+                                        AnnouncementType announcement_type) {}
 #endif
 
 AXPlatformNodeDelegate* AXPlatformNodeBase::GetDelegate() const {
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h
index 8696761..372f071 100644
--- a/ui/accessibility/platform/ax_platform_node_base.h
+++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -104,7 +104,8 @@
   void NotifyAccessibilityEvent(ax::mojom::Event event_type) override;
 
 #if BUILDFLAG(IS_APPLE)
-  void AnnounceText(const std::u16string& text) override;
+  void AnnounceTextAs(const std::u16string& text,
+                      AnnouncementType announcement_type) override;
 #endif
 
   AXPlatformNodeDelegate* GetDelegate() const override;
diff --git a/ui/accessibility/platform/ax_platform_node_delegate.h b/ui/accessibility/platform/ax_platform_node_delegate.h
index aacde58..69f7f3e 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate.h
+++ b/ui/accessibility/platform/ax_platform_node_delegate.h
@@ -31,6 +31,7 @@
 #include "ui/accessibility/ax_text_utils.h"
 #include "ui/accessibility/ax_tree.h"
 #include "ui/accessibility/ax_tree_id.h"
+#include "ui/accessibility/platform/ax_platform_node.h"
 #include "ui/accessibility/platform/ax_unique_id.h"
 #include "ui/gfx/geometry/vector2d.h"
 #include "ui/gfx/native_widget_types.h"
@@ -46,7 +47,6 @@
 struct AXActionData;
 struct AXNodeData;
 struct AXTreeData;
-class AXPlatformNode;
 class ChildIterator;
 
 using TextAttribute = std::pair<std::string, std::string>;
diff --git a/ui/accessibility/platform/ax_platform_node_mac.h b/ui/accessibility/platform/ax_platform_node_mac.h
index 563bcc94..87108f1 100644
--- a/ui/accessibility/platform/ax_platform_node_mac.h
+++ b/ui/accessibility/platform/ax_platform_node_mac.h
@@ -26,7 +26,8 @@
   // AXPlatformNode.
   gfx::NativeViewAccessible GetNativeViewAccessible() override;
   void NotifyAccessibilityEvent(ax::mojom::Event event_type) override;
-  void AnnounceText(const std::u16string& text) override;
+  void AnnounceTextAs(const std::u16string& text,
+                      AnnouncementType announcement_type) override;
 
   // AXPlatformNodeBase.
   void Destroy() override;
diff --git a/ui/accessibility/platform/ax_platform_node_mac.mm b/ui/accessibility/platform/ax_platform_node_mac.mm
index af4d5b4..4dabb3d 100644
--- a/ui/accessibility/platform/ax_platform_node_mac.mm
+++ b/ui/accessibility/platform/ax_platform_node_mac.mm
@@ -147,9 +147,11 @@
   NotifyMacEvent(objc_storage_->native_node, event_type);
 }
 
-void AXPlatformNodeMac::AnnounceText(const std::u16string& text) {
+void AXPlatformNodeMac::AnnounceTextAs(const std::u16string& text,
+                                       AnnouncementType announcement_type) {
   PostAnnouncementNotification(base::SysUTF16ToNSString(text),
-                               [objc_storage_->native_node AXWindow], false);
+                               [objc_storage_->native_node AXWindow],
+                               announcement_type == AnnouncementType::kPolite);
 }
 
 bool IsNameExposedInAXValueForRole(ax::mojom::Role role) {
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 165eccd..bef4fb4 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -660,7 +660,9 @@
     }
   }
 
-  if (event_type == ax::mojom::Event::kValueChanged) {
+  if (event_type == ax::mojom::Event::kValueChanged ||
+      event_type == ax::mojom::Event::kLiveRegionCreated ||
+      event_type == ax::mojom::Event::kLiveRegionChanged) {
     // For the IAccessibleText interface to work on non-web content nodes, we
     // need to update the nodes' hypertext
     // when the value changes. Otherwise, for web and PDF content, this is
diff --git a/ui/base/models/dialog_model.cc b/ui/base/models/dialog_model.cc
index d645adba..1c657ff3b 100644
--- a/ui/base/models/dialog_model.cc
+++ b/ui/base/models/dialog_model.cc
@@ -124,7 +124,7 @@
 
 DialogModel::DialogModel(base::PassKey<Builder>,
                          std::unique_ptr<DialogModelDelegate> delegate)
-    : delegate_(std::move(delegate)) {
+    : delegate_(std::move(delegate)), contents_(GetPassKey()) {
   if (delegate_)
     delegate_->set_dialog_model(this);
 }
@@ -182,8 +182,14 @@
 }
 
 bool DialogModel::HasField(ElementIdentifier id) const {
-  return base::ranges::any_of(fields_,
-                              [id](auto& field) { return field->id_ == id; }) ||
+  return base::ranges::any_of(contents_.fields(GetPassKey()),
+                              [id](auto& field) {
+                                // TODO(pbos): This does not
+                                // work recursively yet.
+                                CHECK_NE(field->type_,
+                                         DialogModelField::kSection);
+                                return field->id_ == id;
+                              }) ||
          (ok_button_ && ok_button_->id_ == id) ||
          (cancel_button_ && cancel_button_->id_ == id) ||
          (extra_button_ && extra_button_->id_ == id);
@@ -192,11 +198,17 @@
 DialogModelField* DialogModel::GetFieldByUniqueId(ElementIdentifier id) {
   // Assert that there are not duplicate fields corresponding to `id`. There
   // could be no matches in `fields_` if `id` corresponds to a button.
-  DCHECK_LE(static_cast<int>(base::ranges::count_if(
-                fields_, [id](auto& field) { return field->id_ == id; })),
-            1);
+  CHECK_LE(static_cast<int>(base::ranges::count_if(
+               contents_.fields(GetPassKey()),
+               [id](auto& field) {
+                 // TODO(pbos): This does not
+                 // work recursively yet.
+                 CHECK_NE(field->type_, DialogModelField::kSection);
+                 return field->id_ == id;
+               })),
+           1);
 
-  for (auto& field : fields_) {
+  for (auto& field : contents_.fields(GetPassKey())) {
     if (field->id_ == id)
       return field.get();
   }
@@ -286,9 +298,16 @@
 }
 
 void DialogModel::AddField(std::unique_ptr<DialogModelField> field) {
-  fields_.push_back(std::move(field));
+  // TODO(pbos): This doesn't work for recursive fields. Here be dragons once we
+  // start nesting items. Right now we only support the top-level kSection.
+  //
+  // Once we start nesting sections then the DialogModelSection::AddField call
+  // should probably also be able to communicate the update.
+  CHECK_NE(field->type_, DialogModelField::kSection);
+  DialogModelField* const field_ptr = field.get();
+  contents_.AddField(GetPassKey(), std::move(field));
   if (host_)
-    host_->OnFieldAdded(fields_.back().get());
+    host_->OnFieldAdded(field_ptr);
 }
 
 }  // namespace ui
diff --git a/ui/base/models/dialog_model.h b/ui/base/models/dialog_model.h
index 133c26a6..b6758bd 100644
--- a/ui/base/models/dialog_model.h
+++ b/ui/base/models/dialog_model.h
@@ -479,12 +479,10 @@
     return close_on_deactivate_;
   }
 
-  // Accessor for ordered fields in the model. This includes DialogButtons even
-  // though they should be handled separately (OK button has fixed position in
-  // dialog).
+  // TODO(pbos): Replace this with a section() or something.
   const std::vector<std::unique_ptr<DialogModelField>>& fields(
       base::PassKey<DialogModelHost>) {
-    return fields_;
+    return contents_.fields(GetPassKey());
   }
 
  private:
@@ -513,7 +511,7 @@
   ImageModel dark_mode_banner_;
 
   absl::optional<DialogButton> override_default_button_;
-  std::vector<std::unique_ptr<DialogModelField>> fields_;
+  DialogModelSection contents_;
   ElementIdentifier initially_focused_field_;
   bool is_alert_dialog_ = false;
 
diff --git a/ui/base/models/dialog_model_field.cc b/ui/base/models/dialog_model_field.cc
index ed27d69..42fd5c0 100644
--- a/ui/base/models/dialog_model_field.cc
+++ b/ui/base/models/dialog_model_field.cc
@@ -349,6 +349,21 @@
   callback_.Run(event_flags);
 }
 
+DialogModelSection::DialogModelSection(base::PassKey<DialogModelBase> pass_key)
+    : DialogModelField(pass_key,
+                       kSection,
+                       ElementIdentifier(),
+                       {},
+                       DialogModelField::Params()) {}
+
+DialogModelSection::~DialogModelSection() = default;
+
+void DialogModelSection::AddField(base::PassKey<DialogModelBase>,
+                                  std::unique_ptr<DialogModelField> field) {
+  CHECK(field);
+  fields_.push_back(std::move(field));
+}
+
 DialogModelSeparator::DialogModelSeparator(
     base::PassKey<DialogModelBase> pass_key)
     : DialogModelField(pass_key,
diff --git a/ui/base/models/dialog_model_field.h b/ui/base/models/dialog_model_field.h
index cbe1f15..e3efd58 100644
--- a/ui/base/models/dialog_model_field.h
+++ b/ui/base/models/dialog_model_field.h
@@ -29,6 +29,7 @@
 class DialogModelCustomField;
 class DialogModelHost;
 class DialogModelMenuItem;
+class DialogModelSection;
 class DialogModelTextfield;
 class Event;
 
@@ -169,7 +170,10 @@
     kCombobox,
     kCustom,
     kMenuItem,
-    kSeparator,
+    kSeparator,  // TODO(pbos): Remove kSeparator once it can be implied by
+                 // having multiple subsequent kSections (3 sections imply 2
+                 // separators).
+    kSection,
     kTextfield
   };
 
@@ -213,6 +217,7 @@
   DialogModelMenuItem* AsMenuItem(base::PassKey<DialogModelHost>);
   const DialogModelMenuItem* AsMenuItem(base::PassKey<DialogModelHost>) const;
   DialogModelTextfield* AsTextfield(base::PassKey<DialogModelHost>);
+  DialogModelSection* AsSection(base::PassKey<DialogModelHost>);
   DialogModelCustomField* AsCustomField(base::PassKey<DialogModelHost>);
 
  protected:
@@ -279,8 +284,6 @@
     base::flat_set<Accelerator> accelerators_;
   };
 
-  // Note that this is constructed through a DialogModel which adds it to model
-  // fields.
   DialogModelButton(base::PassKey<DialogModelBase> pass_key,
                     base::RepeatingCallback<void(const Event&)> callback,
                     const Params& params);
@@ -315,8 +318,6 @@
 // Field class representing a paragraph.
 class COMPONENT_EXPORT(UI_BASE) DialogModelParagraph : public DialogModelField {
  public:
-  // Note that this is constructed through a DialogModel which adds it to model
-  // fields.
   DialogModelParagraph(base::PassKey<DialogModelBase> pass_key,
                        const DialogModelLabel& label,
                        std::u16string header,
@@ -364,8 +365,6 @@
     bool is_checked_ = false;
   };
 
-  // Note that this is constructed through a DialogModel which adds it to model
-  // fields.
   DialogModelCheckbox(base::PassKey<DialogModelBase> pass_key,
                       ElementIdentifier id,
                       const DialogModelLabel& label,
@@ -428,8 +427,6 @@
     base::flat_set<Accelerator> accelerators_;
   };
 
-  // Note that this is constructed through a DialogModel which adds it to model
-  // fields.
   DialogModelCombobox(base::PassKey<DialogModelBase> pass_key,
                       ElementIdentifier id,
                       std::u16string label,
@@ -492,8 +489,6 @@
     ElementIdentifier id_;
   };
 
-  // Note that this is constructed through a DialogModel which adds it to model
-  // fields.
   DialogModelMenuItem(base::PassKey<DialogModelBase> pass_key,
                       ImageModel icon,
                       std::u16string label,
@@ -519,11 +514,35 @@
   base::RepeatingCallback<void(int)> callback_;
 };
 
+// Field class representing a section. A section is a list of fields which may
+// include subsections too (tree structure).
+class COMPONENT_EXPORT(UI_BASE) DialogModelSection final
+    : public DialogModelField {
+ public:
+  // TODO(pbos): Params may make sense here? An optional title should be here?
+
+  explicit DialogModelSection(base::PassKey<DialogModelBase> pass_key);
+  DialogModelSection(const DialogModelSection&) = delete;
+  DialogModelSection& operator=(const DialogModelSection&) = delete;
+  ~DialogModelSection() override;
+
+  const std::vector<std::unique_ptr<DialogModelField>>& fields(
+      base::PassKey<DialogModelBase> pass_key) const {
+    return fields_;
+  }
+
+  void AddField(base::PassKey<DialogModelBase>,
+                std::unique_ptr<DialogModelField> field);
+
+ private:
+  friend class DialogModel;
+
+  std::vector<std::unique_ptr<DialogModelField>> fields_;
+};
+
 // Field class representing a separator.
 class COMPONENT_EXPORT(UI_BASE) DialogModelSeparator : public DialogModelField {
  public:
-  // Note that this is constructed through a DialogModel which adds it to model
-  // fields.
   explicit DialogModelSeparator(base::PassKey<DialogModelBase> pass_key);
   DialogModelSeparator(const DialogModelSeparator&) = delete;
   DialogModelSeparator& operator=(const DialogModelSeparator&) = delete;
@@ -564,8 +583,6 @@
     base::flat_set<Accelerator> accelerators_;
   };
 
-  // Note that this is constructed through a DialogModel which adds it to model
-  // fields.
   DialogModelTextfield(base::PassKey<DialogModelBase> pass_key,
                        ElementIdentifier id,
                        std::u16string label,
@@ -607,8 +624,6 @@
     virtual ~Field();
   };
 
-  // Note that this is constructed through a DialogModel which adds it to model
-  // fields.
   DialogModelCustomField(base::PassKey<DialogModelBase> pass_key,
                          ElementIdentifier id,
                          std::unique_ptr<DialogModelCustomField::Field> field);
diff --git a/ui/views/accessibility/view_accessibility.cc b/ui/views/accessibility/view_accessibility.cc
index 418404e..3a4fe2a 100644
--- a/ui/views/accessibility/view_accessibility.cc
+++ b/ui/views/accessibility/view_accessibility.cc
@@ -568,15 +568,28 @@
     accessibility_events_callback_.Run(nullptr, event_type);
 }
 
+void ViewAccessibility::AnnounceAlert(const std::u16string& text) {
+  if (auto* const widget = view_->GetWidget()) {
+    if (auto* const root_view =
+            static_cast<internal::RootView*>(widget->GetRootView())) {
+      root_view->AnnounceTextAs(text,
+                                ui::AXPlatformNode::AnnouncementType::kAlert);
+    }
+  }
+}
+
+void ViewAccessibility::AnnouncePolitely(const std::u16string& text) {
+  if (auto* const widget = view_->GetWidget()) {
+    if (auto* const root_view =
+            static_cast<internal::RootView*>(widget->GetRootView())) {
+      root_view->AnnounceTextAs(text,
+                                ui::AXPlatformNode::AnnouncementType::kPolite);
+    }
+  }
+}
+
 void ViewAccessibility::AnnounceText(const std::u16string& text) {
-  Widget* const widget = view_->GetWidget();
-  if (!widget)
-    return;
-  auto* const root_view =
-      static_cast<internal::RootView*>(widget->GetRootView());
-  if (!root_view)
-    return;
-  root_view->AnnounceText(text);
+  AnnounceAlert(text);
 }
 
 const ui::AXUniqueId& ViewAccessibility::GetUniqueId() const {
diff --git a/ui/views/accessibility/view_accessibility.h b/ui/views/accessibility/view_accessibility.h
index 201edf8..84f8051 100644
--- a/ui/views/accessibility/view_accessibility.h
+++ b/ui/views/accessibility/view_accessibility.h
@@ -232,7 +232,16 @@
   virtual gfx::NativeViewAccessible GetNativeObject() const;
 
   // Causes the screen reader to announce |text|. If the current user is not
-  // using a screen reader, has no effect.
+  // using a screen reader, has no effect. AnnouncePolitely() will speak
+  // the given string. AnnounceAlert() may make a stronger attempt to be
+  // noticeable; the screen reader may say something like "Alert: hello"
+  // instead of just "hello", and may interrupt any existing text being spoken.
+  // However, the screen reader may also treat the two calls the same.
+  // AnnounceText() is a deprecated alias for AnnounceAlert().
+  // TODO(crbug.com/1499368) - Migrate all callers of AnnounceText() to
+  // one of the other two methods.
+  virtual void AnnounceAlert(const std::u16string& text);
+  virtual void AnnouncePolitely(const std::u16string& text);
   virtual void AnnounceText(const std::u16string& text);
 
   virtual const ui::AXUniqueId& GetUniqueId() const;
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate.cc b/ui/views/accessibility/view_ax_platform_node_delegate.cc
index 02325f4..19a06cd5e 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate.cc
+++ b/ui/views/accessibility/view_ax_platform_node_delegate.cc
@@ -30,6 +30,7 @@
 #include "ui/base/layout.h"
 #include "ui/events/event_utils.h"
 #include "ui/views/accessibility/atomic_view_ax_tree_manager.h"
+#include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/accessibility/view_accessibility_utils.h"
 #include "ui/views/controls/native/native_view_host.h"
 #include "ui/views/view.h"
@@ -274,8 +275,10 @@
 }
 
 #if BUILDFLAG(IS_MAC)
-void ViewAXPlatformNodeDelegate::AnnounceText(const std::u16string& text) {
-  ax_platform_node_->AnnounceText(text);
+void ViewAXPlatformNodeDelegate::AnnounceTextAs(
+    const std::u16string& text,
+    ui::AXPlatformNode::AnnouncementType announcement_type) {
+  ax_platform_node_->AnnounceTextAs(text, announcement_type);
 }
 #endif  // BUILDFLAG(IS_MAC)
 
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate.h b/ui/views/accessibility/view_ax_platform_node_delegate.h
index 48c3682..678785b 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate.h
+++ b/ui/views/accessibility/view_ax_platform_node_delegate.h
@@ -17,6 +17,7 @@
 #include "ui/accessibility/ax_enums.mojom-forward.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/accessibility/ax_node_position.h"
+#include "ui/accessibility/platform/ax_platform_node.h"
 #include "ui/accessibility/platform/ax_platform_node_delegate.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/native_widget_types.h"
@@ -61,7 +62,8 @@
   gfx::NativeViewAccessible GetNativeObject() const override;
   void NotifyAccessibilityEvent(ax::mojom::Event event_type) override;
 #if BUILDFLAG(IS_MAC)
-  void AnnounceText(const std::u16string& text) override;
+  void AnnounceTextAs(const std::u16string& text,
+                      ui::AXPlatformNode::AnnouncementType announcement_type);
 #endif
 
   // ui::AXPlatformNodeDelegate.
diff --git a/ui/views/bubble/bubble_dialog_model_host.cc b/ui/views/bubble/bubble_dialog_model_host.cc
index 43f6ed9c..2e376265 100644
--- a/ui/views/bubble/bubble_dialog_model_host.cc
+++ b/ui/views/bubble/bubble_dialog_model_host.cc
@@ -89,6 +89,9 @@
       return BubbleDialogModelHost::FieldType::kControl;
     case ui::DialogModelField::kMenuItem:
       return BubbleDialogModelHost::FieldType::kMenuItem;
+    case ui::DialogModelField::kSection:
+      // TODO(pbos): Handle nested/multiple sections.
+      NOTREACHED_NORETURN();
     case ui::DialogModelField::kSeparator:
       return BubbleDialogModelHost::FieldType::kMenuItem;
     case ui::DialogModelField::kCustom:
@@ -601,6 +604,9 @@
     case ui::DialogModelField::kMenuItem:
       AddOrUpdateMenuItem(field->AsMenuItem(GetPassKey()));
       break;
+    case ui::DialogModelField::kSection:
+      // TODO(pbos): Handle nested/multiple sections.
+      NOTREACHED_NORETURN();
     case ui::DialogModelField::kSeparator:
       AddOrUpdateSeparator(field);
       break;
diff --git a/ui/views/views_features.cc b/ui/views/views_features.cc
index f428df2..0d746e0 100644
--- a/ui/views/views_features.cc
+++ b/ui/views/views_features.cc
@@ -11,6 +11,12 @@
 
 // Please keep alphabetized.
 
+// Implements desktop widgets reparenting. Enabling this feature allows them
+// to function correctly as tab modals.
+BASE_FEATURE(kDesktopWidgetReparentAura,
+             "kDesktopWidgetReparentAura",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+
 // Use a high-contrast style for ink drops when in platform high-contrast mode,
 // including full opacity and a high-contrast color
 BASE_FEATURE(kEnablePlatformHighContrastInkDrop,
diff --git a/ui/views/views_features.h b/ui/views/views_features.h
index 33dd610..ca872877 100644
--- a/ui/views/views_features.h
+++ b/ui/views/views_features.h
@@ -12,6 +12,7 @@
 namespace views::features {
 
 // Please keep alphabetized.
+VIEWS_EXPORT BASE_DECLARE_FEATURE(kDesktopWidgetReparentAura);
 VIEWS_EXPORT BASE_DECLARE_FEATURE(kEnablePlatformHighContrastInkDrop);
 VIEWS_EXPORT BASE_DECLARE_FEATURE(kEnableViewPaintOptimization);
 VIEWS_EXPORT BASE_DECLARE_FEATURE(kForceUseLegacyPreferredSize);
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc
index a32f29d..e26b76a 100644
--- a/ui/views/widget/native_widget_aura.cc
+++ b/ui/views/widget/native_widget_aura.cc
@@ -8,6 +8,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/feature_list.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/location.h"
@@ -43,6 +44,7 @@
 #include "ui/views/buildflags.h"
 #include "ui/views/drag_utils.h"
 #include "ui/views/views_delegate.h"
+#include "ui/views/views_features.h"
 #include "ui/views/widget/drop_helper.h"
 #include "ui/views/widget/focus_manager_event_handler.h"
 #include "ui/views/widget/native_widget_delegate.h"
@@ -1413,7 +1415,10 @@
   for (auto* widget : widgets)
     widget->NotifyNativeViewHierarchyWillChange();
 
-  if (Widget* child_widget = Widget::GetWidgetForNativeView(native_view)) {
+  Widget* child_widget = Widget::GetWidgetForNativeView(native_view);
+
+  if (base::FeatureList::IsEnabled(features::kDesktopWidgetReparentAura) &&
+      child_widget) {
     child_widget->native_widget_private()->ReparentNativeViewImpl(new_parent);
   } else {
     ReparentAuraWindow(native_view, new_parent);
diff --git a/ui/views/widget/root_view.cc b/ui/views/widget/root_view.cc
index ace679c..9be10b31 100644
--- a/ui/views/widget/root_view.cc
+++ b/ui/views/widget/root_view.cc
@@ -106,11 +106,20 @@
   METADATA_HEADER(AnnounceTextView);
   ~AnnounceTextView() override = default;
 
-  void Announce(const std::u16string& text) {
-    // TODO(crbug.com/1024898): Use kLiveRegionChanged when supported across
-    // screen readers and platforms. See bug for details.
+  void AnnounceTextAs(const std::u16string& text,
+                      ui::AXPlatformNode::AnnouncementType announcement_type) {
     announce_text_ = text;
-    NotifyAccessibilityEvent(ax::mojom::Event::kAlert, true);
+    switch (announcement_type) {
+      case ui::AXPlatformNode::AnnouncementType::kAlert:
+        announce_event_type_ = ax::mojom::Event::kAlert;
+        announce_role_ = ax::mojom::Role::kAlert;
+        break;
+      case ui::AXPlatformNode::AnnouncementType::kPolite:
+        announce_event_type_ = ax::mojom::Event::kLiveRegionChanged;
+        announce_role_ = ax::mojom::Role::kStatus;
+        break;
+    }
+    NotifyAccessibilityEvent(announce_event_type_, /*send_native_event=*/true);
   }
 
   // View:
@@ -118,17 +127,25 @@
 #if BUILDFLAG(IS_CHROMEOS)
     // On ChromeOS, kAlert role can invoke an unnecessary event on reparenting.
     node_data->role = ax::mojom::Role::kStaticText;
-#else
+#elif BUILDFLAG(IS_LINUX)
     // TODO(crbug.com/1024898): Use live regions (do not use alerts).
     // May require setting kLiveStatus, kContainerLiveStatus to "polite".
     node_data->role = ax::mojom::Role::kAlert;
+#else
+    node_data->role = announce_role_;
 #endif
+    node_data->AddBoolAttribute(ax::mojom::BoolAttribute::kLiveAtomic, true);
+    node_data->AddStringAttribute(ax::mojom::StringAttribute::kLiveStatus,
+                                  "polite");
+
     node_data->SetNameChecked(announce_text_);
     node_data->AddState(ax::mojom::State::kInvisible);
   }
 
  private:
   std::u16string announce_text_;
+  ax::mojom::Event announce_event_type_ = ax::mojom::Event::kNone;
+  ax::mojom::Role announce_role_ = ax::mojom::Role::kNone;
 };
 
 BEGIN_METADATA(AnnounceTextView, View)
@@ -319,16 +336,18 @@
   return announce_view_.get();
 }
 
-void RootView::AnnounceText(const std::u16string& text) {
+void RootView::AnnounceTextAs(
+    const std::u16string& text,
+    ui::AXPlatformNode::AnnouncementType announcement_type) {
 #if BUILDFLAG(IS_MAC)
   gfx::NativeViewAccessible native = GetViewAccessibility().GetNativeObject();
-  auto* ax_node = ui::AXPlatformNode::FromNativeViewAccessible(native);
-  if (ax_node)
-    ax_node->AnnounceText(text);
+  if (auto* ax_node = ui::AXPlatformNode::FromNativeViewAccessible(native)) {
+    ax_node->AnnounceTextAs(text, announcement_type);
+  }
 #else
-  DCHECK(GetWidget());
-  DCHECK(GetContentsView());
-  GetOrCreateAnnounceView()->Announce(text);
+  CHECK(GetWidget());
+  CHECK(GetContentsView());
+  GetOrCreateAnnounceView()->AnnounceTextAs(text, announcement_type);
 #endif
 }
 
diff --git a/ui/views/widget/root_view.h b/ui/views/widget/root_view.h
index 80fc491..81ba615 100644
--- a/ui/views/widget/root_view.h
+++ b/ui/views/widget/root_view.h
@@ -9,7 +9,9 @@
 #include <string>
 
 #include "base/memory/raw_ptr.h"
+#include "ui/accessibility/platform/ax_platform_node.h"
 #include "ui/events/event_processor.h"
+#include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/focus/focus_manager.h"
 #include "ui/views/focus/focus_search.h"
 #include "ui/views/view.h"
@@ -97,8 +99,9 @@
 
   // Accessibility -------------------------------------------------------------
 
-  // Make an announcement through the screen reader, if present.
-  void AnnounceText(const std::u16string& text);
+  // See AXPlatformNode::AnnounceTextAs for documentation of this.
+  void AnnounceTextAs(const std::u16string& text,
+                      ui::AXPlatformNode::AnnouncementType announcement_type);
   View* GetAnnounceViewForTesting();
 
   // FocusTraversable:
diff --git a/ui/views/widget/root_view_unittest.cc b/ui/views/widget/root_view_unittest.cc
index c740f36..54b71bf 100644
--- a/ui/views/widget/root_view_unittest.cc
+++ b/ui/views/widget/root_view_unittest.cc
@@ -889,23 +889,32 @@
 
 #if !BUILDFLAG(IS_MAC)
 
-// Tests that AnnounceText sets up the correct text value on the hidden view,
-// and that the resulting hidden view actually stays hidden.
-TEST_F(RootViewTest, AnnounceTextTest) {
+// Tests that AnnounceAlert sets up the correct text value on the hidden
+// view, and that the resulting hidden view actually stays hidden.
+TEST_F(RootViewTest, AnnounceTextAsTest) {
   RootViewTestState state(this, {.bounds = {100, 100, 100, 100}});
   internal::RootView* root_view = state.GetRootView();
 
   EXPECT_EQ(1U, root_view->children().size());
-  const std::u16string kText = u"Text";
-  root_view->AnnounceText(kText);
+  const std::u16string kAlertText = u"Alert";
+  root_view->AnnounceTextAs(kAlertText,
+                            ui::AXPlatformNode::AnnouncementType::kAlert);
   EXPECT_EQ(2U, root_view->children().size());
   views::test::RunScheduledLayout(root_view);
   EXPECT_FALSE(root_view->children()[0]->size().IsEmpty());
   EXPECT_TRUE(root_view->children()[1]->size().IsEmpty());
-  View* const hidden_view = root_view->children()[1];
+  View* const hidden_alert_view = root_view->children()[1];
   ui::AXNodeData node_data;
-  hidden_view->GetAccessibleNodeData(&node_data);
-  EXPECT_EQ(kText,
+  hidden_alert_view->GetAccessibleNodeData(&node_data);
+  EXPECT_EQ(kAlertText,
+            node_data.GetString16Attribute(ax::mojom::StringAttribute::kName));
+
+  const std::u16string kPoliteText = u"Something polite";
+  root_view->AnnounceTextAs(kPoliteText,
+                            ui::AXPlatformNode::AnnouncementType::kPolite);
+  View* const hidden_polite_view = root_view->children()[1];
+  hidden_polite_view->GetAccessibleNodeData(&node_data);
+  EXPECT_EQ(kPoliteText,
             node_data.GetString16Attribute(ax::mojom::StringAttribute::kName));
 }
 
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index 9fa201a..8044dca 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -584,7 +584,7 @@
   DCHECK(!(parent && owner));
 
   if (parent) {
-    // This is an child window.
+    // This is a child window.
     // TODO(crbug.com/1490267): allows setting NULL parent since WinAPI permits
     // it. It will require updating window styles. See
     // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setparent#remarks.
diff --git a/ui/webui/examples/BUILD.gn b/ui/webui/examples/BUILD.gn
index 4a0c593..06d898f4 100644
--- a/ui/webui/examples/BUILD.gn
+++ b/ui/webui/examples/BUILD.gn
@@ -154,7 +154,6 @@
     "//url/mojom:url_mojom_gurl",
   ]
   webui_module_path = "/"
-  use_typescript_sources = true
 }
 
 executable("webui_examples") {
diff --git a/ui/webui/resources/cr_components/app_management/app_management.mojom b/ui/webui/resources/cr_components/app_management/app_management.mojom
index cf99aa5..c173299 100644
--- a/ui/webui/resources/cr_components/app_management/app_management.mojom
+++ b/ui/webui/resources/cr_components/app_management/app_management.mojom
@@ -127,6 +127,19 @@
   bool is_managed;
 };
 
+// Locale info including tag and readable name translated based on ICU-20273.
+struct Locale {
+  // In general, this should be IETF BCP 47 tag, unless apps decide to specify
+  // their own tag.
+  string locale_tag;
+  // Readable name of the locale, translated based on the system language.
+  // Empty if `locale_tag` cannot be translated.
+  string display_name;
+  // Readable name of the locale, translated based on the `locale_tag`.
+  // Empty if `locale_tag` cannot be translated.
+  string native_display_name;
+};
+
 struct App {
   string id;
 
@@ -164,6 +177,8 @@
   // manifest that are no longer valid URLs, such as "foo.com", "app.foo.com",
   // "*.foo2.com".
   array<string> scope_extensions;
+  array<Locale> supported_locales;
+  Locale? selected_locale;
 };
 
 // Extension-based apps primarily use install-time permissions that cannot be
diff --git a/url/url_features.cc b/url/url_features.cc
index 5d6bc16..175e7dc7 100644
--- a/url/url_features.cc
+++ b/url/url_features.cc
@@ -26,6 +26,11 @@
              "StandardCompliantHostCharacters",
              base::FEATURE_ENABLED_BY_DEFAULT);
 
+// Kill switch for crbug.com/1416006.
+BASE_FEATURE(kStandardCompliantNonSpecialSchemeURLParsing,
+             "StandardCompliantNonSpecialSchemeURLParsing",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 bool IsUsingIDNA2008NonTransitional() {
   // If the FeatureList isn't available yet, fall back to the feature's default
   // state. This may happen during early startup, see crbug.com/1441956.
@@ -48,6 +53,17 @@
   return base::FeatureList::IsEnabled(kStandardCompliantHostCharacters);
 }
 
+bool IsUsingStandardCompliantNonSpecialSchemeURLParsing() {
+  // If the FeatureList isn't available yet, fall back to the feature's default
+  // state. This may happen during early startup, see crbug.com/1441956.
+  if (!base::FeatureList::GetInstance()) {
+    return kStandardCompliantNonSpecialSchemeURLParsing.default_state ==
+           base::FEATURE_ENABLED_BY_DEFAULT;
+  }
+  return base::FeatureList::IsEnabled(
+      kStandardCompliantNonSpecialSchemeURLParsing);
+}
+
 bool IsRecordingIDNA2008Metrics() {
   return base::FeatureList::IsEnabled(kRecordIDNA2008Metrics);
 }
diff --git a/url/url_features.h b/url/url_features.h
index 68bcc5a..9e694d8 100644
--- a/url/url_features.h
+++ b/url/url_features.h
@@ -22,6 +22,10 @@
 // See url::kStandardCompliantHostCharacters for details.
 COMPONENT_EXPORT(URL) bool IsUsingStandardCompliantHostCharacters();
 
+// Returns true if kStandardCompliantNonSpecialSchemeURLParsing feature is
+// enabled. See url::kStandardCompliantNonSpecialSchemeURLParsing for details.
+COMPONENT_EXPORT(URL) bool IsUsingStandardCompliantNonSpecialSchemeURLParsing();
+
 // When enabled, allows resolving of a bare fragment containing a colon against
 // a non-hierarchical URL. (For example '#foo:bar' against 'about:blank'.)
 COMPONENT_EXPORT(URL)
@@ -33,6 +37,11 @@
 COMPONENT_EXPORT(URL)
 BASE_DECLARE_FEATURE(kStandardCompliantHostCharacters);
 
+// When enabled, Chrome uses standard-compliant URL parsing for non-special
+// scheme URLs. See https://crbug.com/1416006 for details.
+COMPONENT_EXPORT(URL)
+BASE_DECLARE_FEATURE(kStandardCompliantNonSpecialSchemeURLParsing);
+
 }  // namespace url
 
 #endif  // URL_URL_FEATURES_H_
diff --git a/v8 b/v8
index 67b89a4..eb5ccbd 160000
--- a/v8
+++ b/v8
@@ -1 +1 @@
-Subproject commit 67b89a482182b443a888dac94e96767526ec08f9
+Subproject commit eb5ccbd8cda19af0d91ad55fb750637a3ec0f0b8