diff --git a/DEPS b/DEPS
index 4e9aca0..40edd432 100644
--- a/DEPS
+++ b/DEPS
@@ -312,11 +312,11 @@
   # 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': '28579a88aa9c12ef23c1d3ab798aba40f85ea0d8',
+  'skia_revision': '2a2fe430350798bf10c28ad55daf61c08c6a4121',
   # 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': 'de7ce8021831d4f3c4e49336623f25b2fc406fbc',
+  'v8_revision': '555084e67f98736a41e52d13e485ab0febc3cbae',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
@@ -399,7 +399,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling fuzztest
   # and whatever else without interference from each other.
-  'fuzztest_revision': 'd7c63cd216941e297569428e40f9b8bc155e0423',
+  'fuzztest_revision': '65354bf09a2479945b4683c42948695d4f2f7c07',
   # 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.
@@ -431,7 +431,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.
-  'quiche_revision': 'acbdda4e4aa43e72a19aa72115b71e8eba57babb',
+  'quiche_revision': '718c9019fe67253ca9aa76498dff0f35ef97b15e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ios_webkit
   # and whatever else without interference from each other.
@@ -459,7 +459,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling nearby
   # and whatever else without interference from each other.
-  'nearby_revision': '78505e91f7e054444030aec55110893b4fc62500',
+  'nearby_revision': '03f0b3dae98d218e8420add5a13893822d290855',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling securemessage
   # and whatever else without interference from each other.
@@ -827,7 +827,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '682118afe56ac594ac2a4343274a9bed1dac8710',
+    '2d1d020843dabd7ef41ae7a261f81b381281dbf4',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1517,7 +1517,7 @@
     Var('chromium_git') + '/external/github.com/google/libprotobuf-mutator.git' + '@' +  Var('libprotobuf-mutator'),
 
   'src/third_party/libsrtp':
-    Var('chromium_git') + '/chromium/deps/libsrtp.git' + '@' + '5b7c744eb8310250ccc534f3f86a2015b3887a0a',
+    Var('chromium_git') + '/chromium/deps/libsrtp.git' + '@' + '7a7e64c8b5a632f55929cb3bb7d3e6fb48c3205a',
 
   # Android Explicit Synchronization.
   'src/third_party/libsync/src': {
@@ -1848,10 +1848,10 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'f4bf599a8b575df685c31d9c4729a70a04e377ed',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'acb475026d7ac90725c629ef3664267c7aed72a1',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'e5fb8824ade85fae690f2bb45cc347a1398cca2f',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '0bb59b4edd23d4e69de14b316312571146b6448d',
+    Var('webrtc_git') + '/src.git' + '@' + 'f942a2901aa45546ec525c0adf977071f312f6f3',
 
   # Wuffs' canonical repository is at github.com/google/wuffs, but we use
   # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file.
@@ -4125,7 +4125,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        'c448ce76c3e84201da5db9ac4a2a579c2fabfdf3',
+        'debd0ef81bb8df6520b9cc80141ec587cd8e1c56',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/ash/capture_mode/capture_mode_controller.cc b/ash/capture_mode/capture_mode_controller.cc
index 070de21..39f5a80 100644
--- a/ash/capture_mode/capture_mode_controller.cc
+++ b/ash/capture_mode/capture_mode_controller.cc
@@ -1959,6 +1959,10 @@
       capture_params.window, capture_params.bounds,
       base::BindOnce(&CaptureModeController::InterruptVideoRecording,
                      weak_ptr_factory_.GetWeakPtr()));
+
+  if (on_video_recording_started_callback_for_test_) {
+    std::move(on_video_recording_started_callback_for_test_).Run();
+  }
 }
 
 void CaptureModeController::InterruptVideoRecording() {
diff --git a/ash/capture_mode/capture_mode_controller.h b/ash/capture_mode/capture_mode_controller.h
index aced8f78..3be1898 100644
--- a/ash/capture_mode/capture_mode_controller.h
+++ b/ash/capture_mode/capture_mode_controller.h
@@ -702,6 +702,8 @@
 
   base::OnceClosure on_countdown_finished_callback_for_test_;
 
+  base::OnceClosure on_video_recording_started_callback_for_test_;
+
   // Timers used to schedule recording of the number of screenshots taken.
   base::RepeatingTimer num_screenshots_taken_in_last_day_scheduler_;
   base::RepeatingTimer num_screenshots_taken_in_last_week_scheduler_;
diff --git a/ash/capture_mode/capture_mode_test_api.cc b/ash/capture_mode/capture_mode_test_api.cc
index 4425416..1f6e666 100644
--- a/ash/capture_mode/capture_mode_test_api.cc
+++ b/ash/capture_mode/capture_mode_test_api.cc
@@ -116,6 +116,12 @@
              ->IsInCountDownAnimation();
 }
 
+void CaptureModeTestApi::SetOnVideoRecordingStartedCallback(
+    base::OnceClosure callback) {
+  controller_->on_video_recording_started_callback_for_test_ =
+      std::move(callback);
+}
+
 void CaptureModeTestApi::StopVideoRecording() {
   DCHECK(controller_->is_recording_in_progress());
   controller_->EndVideoRecording(EndRecordingReason::kStopRecordingButton);
diff --git a/ash/capture_mode/capture_mode_test_util.cc b/ash/capture_mode/capture_mode_test_util.cc
index 9945af5..505d6c9a 100644
--- a/ash/capture_mode/capture_mode_test_util.cc
+++ b/ash/capture_mode/capture_mode_test_util.cc
@@ -98,11 +98,9 @@
   auto* controller = CaptureModeController::Get();
   if (controller->is_recording_in_progress())
     return;
-  auto* test_delegate =
-      static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing());
-  ASSERT_TRUE(test_delegate);
   base::RunLoop run_loop;
-  test_delegate->set_on_recording_started_callback(run_loop.QuitClosure());
+  ash::CaptureModeTestApi().SetOnVideoRecordingStartedCallback(
+      run_loop.QuitClosure());
   run_loop.Run();
   ASSERT_TRUE(controller->is_recording_in_progress());
 }
diff --git a/ash/capture_mode/test_capture_mode_delegate.cc b/ash/capture_mode/test_capture_mode_delegate.cc
index 607f59e..64e30ad 100644
--- a/ash/capture_mode/test_capture_mode_delegate.cc
+++ b/ash/capture_mode/test_capture_mode_delegate.cc
@@ -124,12 +124,7 @@
 void TestCaptureModeDelegate::StartObservingRestrictedContent(
     const aura::Window* window,
     const gfx::Rect& bounds,
-    base::OnceClosure stop_callback) {
-  // This is called at the last stage of recording initialization to signal that
-  // recording has actually started.
-  if (on_recording_started_callback_)
-    std::move(on_recording_started_callback_).Run();
-}
+    base::OnceClosure stop_callback) {}
 
 void TestCaptureModeDelegate::StopObservingRestrictedContent(
     OnCaptureModeDlpRestrictionChecked callback) {
diff --git a/ash/capture_mode/test_capture_mode_delegate.h b/ash/capture_mode/test_capture_mode_delegate.h
index 0ecee6b..f8f18038 100644
--- a/ash/capture_mode/test_capture_mode_delegate.h
+++ b/ash/capture_mode/test_capture_mode_delegate.h
@@ -43,9 +43,6 @@
   void set_on_session_state_changed_callback(base::OnceClosure callback) {
     on_session_state_changed_callback_ = std::move(callback);
   }
-  void set_on_recording_started_callback(base::OnceClosure callback) {
-    on_recording_started_callback_ = std::move(callback);
-  }
   void set_is_allowed_by_dlp(bool value) { is_allowed_by_dlp_ = value; }
   void set_is_allowed_by_policy(bool value) { is_allowed_by_policy_ = value; }
   void set_should_save_after_dlp_check(bool value) {
@@ -146,7 +143,6 @@
   std::unique_ptr<FakeVideoSourceProvider> video_source_provider_;
   base::ScopedTempDir fake_downloads_dir_;
   base::OnceClosure on_session_state_changed_callback_;
-  base::OnceClosure on_recording_started_callback_;
   bool is_session_active_ = false;
   bool is_allowed_by_dlp_ = true;
   bool is_allowed_by_policy_ = true;
diff --git a/ash/picker/search/picker_search_request.cc b/ash/picker/search/picker_search_request.cc
index 6bc3506..986144f 100644
--- a/ash/picker/search/picker_search_request.cc
+++ b/ash/picker/search/picker_search_request.cc
@@ -70,6 +70,12 @@
         query, category,
         base::BindRepeating(&PickerSearchRequest::HandleCrosSearchResults,
                             weak_ptr_factory_.GetWeakPtr()));
+
+    if (!category.has_value() || category == PickerCategory::kDriveFiles) {
+      drive_search_timeout_timer_.Start(
+          FROM_HERE, kDriveSearchTimeout, this,
+          &PickerSearchRequest::OnDriveSearchTimeout);
+    }
   }
 
   if (!category.has_value() || category == PickerCategory::kClipboard) {
@@ -166,6 +172,10 @@
           /*has_more_results=*/!is_category_specific_search_);
       break;
     case AppListSearchResultType::kDriveSearch: {
+      if (!drive_search_timeout_timer_.IsRunning()) {
+        return;
+      }
+
       if (cros_search_start_.has_value()) {
         base::TimeDelta elapsed = base::TimeTicks::Now() - *cros_search_start_;
         base::UmaHistogramTimes("Ash.Picker.Search.DriveProvider.QueryTime",
@@ -178,6 +188,7 @@
 
       HandleSearchSourceResults(PickerSearchSource::kDrive, std::move(results),
                                 /*has_more_results=*/files_to_remove > 0);
+      drive_search_timeout_timer_.Stop();
       break;
     }
     case AppListSearchResultType::kFileSearch: {
@@ -295,4 +306,9 @@
                             /*has_more_results=*/false);
 }
 
+void PickerSearchRequest::OnDriveSearchTimeout() {
+  HandleSearchSourceResults(PickerSearchSource::kDrive, {},
+                            /*has_more_results=*/false);
+}
+
 }  // namespace ash
diff --git a/ash/picker/search/picker_search_request.h b/ash/picker/search/picker_search_request.h
index 89e1a0d..5dd0d73 100644
--- a/ash/picker/search/picker_search_request.h
+++ b/ash/picker/search/picker_search_request.h
@@ -53,6 +53,7 @@
 
   static constexpr base::TimeDelta kGifDebouncingDelay =
       base::Milliseconds(200);
+  static constexpr base::TimeDelta kDriveSearchTimeout = base::Seconds(1);
 
  private:
   void StartGifSearch(const std::string& query);
@@ -71,6 +72,8 @@
   void HandleMathSearchResults(std::optional<PickerSearchResult> result);
   void HandleClipboardSearchResults(std::vector<PickerSearchResult> results);
 
+  void OnDriveSearchTimeout();
+
   bool is_category_specific_search_;
   const raw_ref<PickerClient> client_;
 
@@ -90,6 +93,8 @@
 
   PickerSearchDebouncer gif_search_debouncer_;
 
+  base::OneShotTimer drive_search_timeout_timer_;
+
   base::WeakPtrFactory<PickerSearchRequest> weak_ptr_factory_{this};
 };
 
diff --git a/ash/picker/search/picker_search_request_unittest.cc b/ash/picker/search/picker_search_request_unittest.cc
index 61e71c0..65bfd4b 100644
--- a/ash/picker/search/picker_search_request_unittest.cc
+++ b/ash/picker/search/picker_search_request_unittest.cc
@@ -639,6 +639,71 @@
        ash::PickerSearchResult::Text(u"4.jpg")});
 }
 
+TEST_F(PickerSearchRequestTest, SendsEmptyDriveResultsOnTimeout) {
+  MockSearchResultsCallback search_results_callback;
+  EXPECT_CALL(search_results_callback, Call).Times(AnyNumber());
+  EXPECT_CALL(search_results_callback,
+              Call(PickerSearchSource::kDrive, IsEmpty(),
+                   /*has_more_results=*/false))
+      .Times(1);
+
+  PickerSearchRequest request(
+      u"cat", std::nullopt,
+      base::BindRepeating(&MockSearchResultsCallback::Call,
+                          base::Unretained(&search_results_callback)),
+      &client(), &emoji_search(), kAllCategories);
+  task_environment().FastForwardBy(PickerSearchRequest::kDriveSearchTimeout);
+}
+
+TEST_F(PickerSearchRequestTest, IgnoresDriveResultsAfterTimeout) {
+  MockSearchResultsCallback search_results_callback;
+  EXPECT_CALL(search_results_callback, Call).Times(AnyNumber());
+  EXPECT_CALL(search_results_callback,
+              Call(PickerSearchSource::kDrive, IsEmpty(),
+                   /*has_more_results=*/false))
+      .Times(1);
+  EXPECT_CALL(search_results_callback,
+              Call(PickerSearchSource::kDrive, Not(IsEmpty()), _))
+      .Times(0);
+
+  PickerSearchRequest request(
+      u"cat", std::nullopt,
+      base::BindRepeating(&MockSearchResultsCallback::Call,
+                          base::Unretained(&search_results_callback)),
+      &client(), &emoji_search(), kAllCategories);
+  task_environment().FastForwardBy(PickerSearchRequest::kDriveSearchTimeout);
+  client().cros_search_callback().Run(
+      ash::AppListSearchResultType::kDriveSearch,
+      {ash::PickerSearchResult::Text(u"1.jpg")});
+}
+
+TEST_F(PickerSearchRequestTest, CancelsTimeoutTimerOnReceivingDriveResults) {
+  MockSearchResultsCallback search_results_callback;
+  EXPECT_CALL(search_results_callback, Call).Times(AnyNumber());
+  EXPECT_CALL(search_results_callback,
+              Call(PickerSearchSource::kDrive,
+                   ElementsAre(Property(
+                       "data", &PickerSearchResult::data,
+                       VariantWith<PickerSearchResult::TextData>(Field(
+                           "text", &PickerSearchResult::TextData::primary_text,
+                           u"1.jpg")))),
+                   /*has_more_results=*/false))
+      .Times(1);
+  EXPECT_CALL(search_results_callback,
+              Call(PickerSearchSource::kDrive, IsEmpty(), _))
+      .Times(0);
+
+  PickerSearchRequest request(
+      u"cat", std::nullopt,
+      base::BindRepeating(&MockSearchResultsCallback::Call,
+                          base::Unretained(&search_results_callback)),
+      &client(), &emoji_search(), kAllCategories);
+  client().cros_search_callback().Run(
+      ash::AppListSearchResultType::kDriveSearch,
+      {ash::PickerSearchResult::Text(u"1.jpg")});
+  task_environment().FastForwardBy(PickerSearchRequest::kDriveSearchTimeout);
+}
+
 TEST_F(PickerSearchRequestTest, RecordsDriveMetrics) {
   base::HistogramTester histogram;
   NiceMock<MockSearchResultsCallback> search_results_callback;
diff --git a/ash/public/cpp/capture_mode/capture_mode_test_api.h b/ash/public/cpp/capture_mode/capture_mode_test_api.h
index 827d604..c010ed27 100644
--- a/ash/public/cpp/capture_mode/capture_mode_test_api.h
+++ b/ash/public/cpp/capture_mode/capture_mode_test_api.h
@@ -84,6 +84,9 @@
   // Returns true if the 3-second countdown animation is in progress.
   bool IsInCountDownAnimation() const;
 
+  // Sets a callback that will be triggered once the video recording is started.
+  void SetOnVideoRecordingStartedCallback(base::OnceClosure callback);
+
   // Stops the video recording. Can only be called if a video recording was
   // in progress.
   void StopVideoRecording();
diff --git a/ash/system/camera/camera_effects_controller_unittest.cc b/ash/system/camera/camera_effects_controller_unittest.cc
index b504c0b..22e30f7 100644
--- a/ash/system/camera/camera_effects_controller_unittest.cc
+++ b/ash/system/camera/camera_effects_controller_unittest.cc
@@ -249,7 +249,7 @@
         cros::mojom::CameraEffect::kBackgroundBlur));
     EXPECT_FALSE(camera_effects_controller()->IsEffectControlAvailable(
         cros::mojom::CameraEffect::kPortraitRelight));
-    EXPECT_TRUE(camera_effects_controller()->IsEffectControlAvailable(
+    EXPECT_FALSE(camera_effects_controller()->IsEffectControlAvailable(
         cros::mojom::CameraEffect::kBackgroundReplace));
   }
 
@@ -261,7 +261,7 @@
         cros::mojom::CameraEffect::kBackgroundBlur));
     EXPECT_TRUE(camera_effects_controller()->IsEffectControlAvailable(
         cros::mojom::CameraEffect::kPortraitRelight));
-    EXPECT_FALSE(camera_effects_controller()->IsEffectControlAvailable(
+    EXPECT_TRUE(camera_effects_controller()->IsEffectControlAvailable(
         cros::mojom::CameraEffect::kBackgroundReplace));
   }
 
@@ -274,21 +274,20 @@
         cros::mojom::CameraEffect::kBackgroundBlur));
     EXPECT_FALSE(camera_effects_controller()->IsEffectControlAvailable(
         cros::mojom::CameraEffect::kPortraitRelight));
-    EXPECT_FALSE(camera_effects_controller()->IsEffectControlAvailable(
+    EXPECT_TRUE(camera_effects_controller()->IsEffectControlAvailable(
         cros::mojom::CameraEffect::kBackgroundReplace));
   }
 
   {
     base::test::ScopedFeatureList scoped_feature_list;
     scoped_feature_list.InitWithFeatures(
-        {features::kFeatureManagementVideoConference,
-         features::kVcBackgroundReplace},
-        {});
+        {features::kFeatureManagementVideoConference},
+        {features::kVcBackgroundReplace});
     EXPECT_TRUE(camera_effects_controller()->IsEffectControlAvailable(
         cros::mojom::CameraEffect::kBackgroundBlur));
     EXPECT_TRUE(camera_effects_controller()->IsEffectControlAvailable(
         cros::mojom::CameraEffect::kPortraitRelight));
-    EXPECT_TRUE(camera_effects_controller()->IsEffectControlAvailable(
+    EXPECT_FALSE(camera_effects_controller()->IsEffectControlAvailable(
         cros::mojom::CameraEffect::kBackgroundReplace));
   }
 }
diff --git a/build/config/siso/clang_linux.star b/build/config/siso/clang_linux.star
index 4c0229c..f0ad598 100644
--- a/build/config/siso/clang_linux.star
+++ b/build/config/siso/clang_linux.star
@@ -161,36 +161,6 @@
             "timeout": "2m",
         },
         {
-            "name": "clang/alink",
-            "action": "(.*_)?alink",
-            "inputs": [
-                "third_party/llvm-build/Release+Asserts/bin/llvm-ar",
-            ],
-            "remote": config.get(ctx, "cog"),
-            "canonicalize_dir": True,
-            "accumulate": True,
-            "timeout": "4m",
-        },
-        {
-            "name": "clang/link",
-            "action": "(.*_)?link",
-            "command_prefix": "\"python3\" \"../../build/toolchain/gcc_link_wrapper.py\"",
-            "inputs": [
-                "third_party/llvm-build/Release+Asserts/bin/clang",
-                "third_party/llvm-build/Release+Asserts/bin/clang++",
-                "third_party/llvm-build/Release+Asserts/bin/ld.lld",
-                "third_party/llvm-build/Release+Asserts/bin/lld",
-                "build/toolchain/whole_archive.py",
-                "build/toolchain/wrapper_utils.py",
-                "build/toolchain/gcc_link_wrapper.py",
-                "build/linux/debian_bullseye_amd64-sysroot:link",
-            ],
-            "remote": config.get(ctx, "cog"),
-            "platform_ref": "large",
-            "canonicalize_dir": True,
-            "timeout": "10m",
-        },
-        {
             "name": "clang-coverage/cxx",
             "action": "(.*_)?cxx",
             "command_prefix": "\"python3\" ../../build/toolchain/clang_code_coverage_wrapper.py",
@@ -237,6 +207,7 @@
                     "*.stamp",
                 ],
                 "remote": config.get(ctx, "remote-library-link"),
+                "canonicalize_dir": True,
                 "platform_ref": "large",
                 "accumulate": True,
             },
@@ -260,6 +231,7 @@
                     "*.stamp",
                 ],
                 "remote": config.get(ctx, "remote-library-link"),
+                "canonicalize_dir": True,
                 "platform_ref": "large",
             },
             {
@@ -282,7 +254,9 @@
                     "*.stamp",
                 ],
                 "remote": config.get(ctx, "remote-exec-link"),
+                "canonicalize_dir": True,
                 "platform_ref": "large",
+                "timeout": "10m",
             },
         ])
     return step_config
diff --git a/build/config/siso/main.star b/build/config/siso/main.star
index 4a5a619..23a02ea8 100644
--- a/build/config/siso/main.star
+++ b/build/config/siso/main.star
@@ -35,10 +35,13 @@
         # target_os = "chromeos"
         # use_cups = true
         # use_remoteexec = true
+        "./lacros_clang_x64/obj/chrome/browser/browser/chrome_browser_interface_binders.o",
         "./lacros_clang_x64/obj/chrome/browser/browser/chrome_content_browser_client.o",
         "./lacros_clang_x64/obj/content/browser/browser/browser_interface_binders.o",
+        "./lacros_clang_x64/obj/third_party/blink/public/mojom/mojom_platform/speech_recognition_grammar.mojom.o",
         "./obj/chrome/browser/ash/ash/autotest_private_api.o",
         "./obj/chrome/browser/ash/ash/chrome_browser_main_parts_ash.o",
+        "./obj/chrome/browser/ash/ash/user_session_manager.o",
         "./obj/chrome/browser/ash/ash/webui_login_view.o",
         "./obj/chrome/browser/ash/system_web_apps/apps/browser_tests/media_app_integration_browsertest.o",
         "./obj/chrome/browser/ash/system_web_apps/browser_tests/system_web_app_manager_browsertest.o",
@@ -46,6 +49,7 @@
         "./obj/chrome/browser/browser/browser_prefs.o",
         "./obj/chrome/browser/browser/chrome_browser_interface_binders.o",
         "./obj/chrome/browser/browser/chrome_content_browser_client.o",
+        "./obj/chrome/browser/browser/render_view_context_menu.o",
         "./obj/chrome/browser/ui/ash/holding_space/browser_tests/holding_space_ui_browsertest.o",
         "./obj/chrome/test/browser_tests/app_list_client_impl_browsertest.o",
         "./obj/chrome/test/browser_tests/browser_non_client_frame_view_chromeos_browsertest.o",
diff --git a/chrome/android/java/res/xml/unified_account_settings_preferences.xml b/chrome/android/java/res/xml/unified_account_settings_preferences.xml
index f38c8872..d2765b3 100644
--- a/chrome/android/java/res/xml/unified_account_settings_preferences.xml
+++ b/chrome/android/java/res/xml/unified_account_settings_preferences.xml
@@ -61,4 +61,9 @@
         android:key="encryption"
         android:title="@string/sync_encryption"/>
 
+    <org.chromium.components.browser_ui.settings.ChromeBasePreference
+        android:key="sync_review_data"
+        android:title="@string/signin_review_data_title"
+        android:summary="@string/signin_review_data_summary"/>
+
 </PreferenceScreen>
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java
index 9aad3a7..8daf5925 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java
@@ -737,6 +737,8 @@
     public void isAccountManaged(
             @NonNull CoreAccountInfo account, final Callback<Boolean> callback) {
         assert account != null;
+        if (account == null) throw new RuntimeException("Null account");
+        if (callback == null) throw new RuntimeException("Null callback");
         SigninManagerImplJni.get().isAccountManaged(mNativeSigninManagerAndroid, account, callback);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java
index ab8c6cbd..aa3b12c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/ManageSyncSettings.java
@@ -247,11 +247,6 @@
                 findPreference(PREF_ADVANCED_CATEGORY).setVisible(true);
             }
 
-            Preference reviewSyncData = findPreference(PREF_SYNC_REVIEW_DATA);
-            reviewSyncData.setOnPreferenceClickListener(
-                    SyncSettingsUtils.toOnClickListener(
-                            this, () -> SyncSettingsUtils.openSyncDashboard(getActivity())));
-
             mSyncTypeCheckBoxPreferencesMap = new HashMap<>();
             mSyncTypeCheckBoxPreferencesMap.put(
                     UserSelectableType.AUTOFILL, findPreference(PREF_SYNC_AUTOFILL));
@@ -315,6 +310,11 @@
         mSyncEncryption = findPreference(PREF_ENCRYPTION);
         mSyncEncryption.setOnPreferenceClickListener(
                 SyncSettingsUtils.toOnClickListener(this, this::onSyncEncryptionClicked));
+
+        Preference reviewSyncData = findPreference(PREF_SYNC_REVIEW_DATA);
+        reviewSyncData.setOnPreferenceClickListener(
+                SyncSettingsUtils.toOnClickListener(
+                        this, () -> SyncSettingsUtils.openSyncDashboard(getActivity())));
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewHelperTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewHelperTest.java
index 377d7a6..ab791fe9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewHelperTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/paint_preview/StartupPaintPreviewHelperTest.java
@@ -15,6 +15,7 @@
 
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.base.ColdStartTracker;
@@ -91,6 +92,7 @@
     @Test
     @MediumTest
     @Restriction(StartupPaintPreviewHelperTestRunner.RESTRICTION_TYPE_KEEP_ACTIVITIES)
+    @DisabledTest(message = "Very flaky. See crbug.com/333779543.")
     public void testDisplayOnStartup() throws ExecutionException {
         mActivityTestRule.startMainActivityWithURL(
                 mActivityTestRule.getTestServer().getURL(TEST_URL));
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index c397708..3af9130 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -7485,6 +7485,9 @@
   <message name="IDS_APP_INSTALL_DIALOG_FAILED_INSTALL_TITLE" desc="Title shown in the app install dialog if the app failed to install.">
     Can't install app. Something went wrong.
   </message>
+  <message name="IDS_APP_INSTALL_DIALOG_APP_ICON_ALT" desc="Alt text for the app icon displayed in the app install dialog. This is the text that will be read by screen reader when the app icon is focused.">
+    <ph name="APP">$1<ex>Google Docs</ex></ph> logo
+  </message>
 
   <!-- Extended Updates Dialog -->
   <message name="IDS_EXTENDED_UPDATES_DIALOG_DIALOG_HEADING" desc="Dialog heading of the Extended Updates Dialog" translateable="false">
diff --git a/chrome/app/chromeos_strings_grdp/IDS_APP_INSTALL_DIALOG_APP_ICON_ALT.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_APP_INSTALL_DIALOG_APP_ICON_ALT.png.sha1
new file mode 100644
index 0000000..876fa529
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_APP_INSTALL_DIALOG_APP_ICON_ALT.png.sha1
@@ -0,0 +1 @@
+29a4ea4af20d9c662f3fb44da7d19076b532f9e2
\ No newline at end of file
diff --git a/chrome/browser/accessibility/accessibility_labels_service_browsertest.cc b/chrome/browser/accessibility/accessibility_labels_service_browsertest.cc
index e8f2b8a7..61e84b2 100644
--- a/chrome/browser/accessibility/accessibility_labels_service_browsertest.cc
+++ b/chrome/browser/accessibility/accessibility_labels_service_browsertest.cc
@@ -2,13 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/command_line.h"
-#include "base/files/file_util.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
-#include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -17,12 +13,12 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_accessibility_state.h"
+#include "content/public/test/accessibility_notification_waiter.h"
 #include "content/public/test/browser_test.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ash/accessibility/accessibility_manager.h"
 #include "chrome/browser/ash/accessibility/speech_monitor.h"
-#include "chrome/browser/ash/profiles/profile_helper.h"
 #include "extensions/browser/browsertest_util.h"
 #include "extensions/common/constants.h"
 #else
@@ -107,6 +103,12 @@
 
   chrome::NewTab(browser());
   web_contents = browser()->tab_strip_model()->GetActiveWebContents();
+  // Wait for ChromeVox to attach to the new tab if needed.
+  if (!web_contents->GetAccessibilityMode().has_mode(
+          ui::AXMode::kScreenReader)) {
+    content::AccessibilityNotificationWaiter waiter(web_contents);
+    ASSERT_TRUE(waiter.WaitForNotification());
+  }
   ax_mode = web_contents->GetAccessibilityMode();
   EXPECT_TRUE(ax_mode.has_mode(ui::AXMode::kLabelImages));
 
@@ -179,51 +181,48 @@
       prefs::kAccessibilityImageLabelsEnabled, false);
 }
 
-IN_PROC_BROWSER_TEST_F(AccessibilityLabelsBrowserTest, EnabledOnStartup) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  ash::ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(true);
-#endif
-
-  // Make a testing profile so we can mimic prefs set before startup.
-  ProfileManager* profile_manager = g_browser_process->profile_manager();
-  std::unique_ptr<Profile> other_profile;
-  {
-    base::FilePath path =
-        profile_manager->user_data_dir().AppendASCII("test_profile");
-    base::ScopedAllowBlockingForTesting allow_blocking;
-    if (!base::PathExists(path)) {
-      ASSERT_TRUE(base::CreateDirectory(path));
-    }
-    other_profile =
-        Profile::CreateProfile(path, nullptr, Profile::CREATE_MODE_SYNCHRONOUS);
-  }
-  Profile* other_profile_ptr = other_profile.get();
-  profile_manager->RegisterTestingProfile(std::move(other_profile), true);
-
+// Turning on the preference while a screenreader is present should enable the
+// feature for existing tabs.
+IN_PROC_BROWSER_TEST_F(AccessibilityLabelsBrowserTest,
+                       PRE_EnabledByPreference) {
   EnableScreenReader(true);
 
-  // Verify clean state.
-  Browser* other_profile_browser = CreateBrowser(other_profile_ptr);
-  content::WebContents* web_contents =
-      other_profile_browser->tab_strip_model()->GetActiveWebContents();
-  ui::AXMode ax_mode = web_contents->GetAccessibilityMode();
-  EXPECT_FALSE(ax_mode.has_mode(ui::AXMode::kLabelImages));
+  // The preference is not yet set, so the feature is off.
+  auto* const web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_FALSE(
+      web_contents->GetAccessibilityMode().has_mode(ui::AXMode::kLabelImages));
 
-  // Simulate the pref being set prior to startup.
-  other_profile_ptr->GetPrefs()->SetBoolean(
+  browser()->profile()->GetPrefs()->SetBoolean(
       prefs::kAccessibilityImageLabelsEnabled, true);
 
-  // Now, simulate the initialization path which ordinarily gets called by
-  // ProfileManager on startup/profile creation.
-  AccessibilityLabelsService* a11y_labels_service =
-      AccessibilityLabelsServiceFactory::GetForProfile(other_profile_ptr);
-  a11y_labels_service->Init();
+  // Now the feature is on.
+  EXPECT_TRUE(
+      web_contents->GetAccessibilityMode().has_mode(ui::AXMode::kLabelImages));
+}
 
-  // Verify that tabs now get the mode. Open a new tab to avoid races for
-  // setting modes.
-  AddBlankTabAndShow(other_profile_browser);
-  web_contents =
-      other_profile_browser->tab_strip_model()->GetActiveWebContents();
-  ax_mode = web_contents->GetAccessibilityMode();
-  EXPECT_TRUE(ax_mode.has_mode(ui::AXMode::kLabelImages));
+// When the preference is present at startup, the feature should become enabled
+// when a screenreader is discovered.
+IN_PROC_BROWSER_TEST_F(AccessibilityLabelsBrowserTest, EnabledByPreference) {
+  // The preference was set for the profile by PRE_EnabledByPreference.
+  ASSERT_TRUE(browser()->profile()->GetPrefs()->GetBoolean(
+      prefs::kAccessibilityImageLabelsEnabled));
+
+  auto* const web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  // If the test is run without --force-renderer-accessibility, then no screen
+  // reader should have been detected yet, and the feature should be off.
+  if (!content::BrowserAccessibilityState::GetInstance()
+           ->GetAccessibilityMode()
+           .has_mode(ui::AXMode::kScreenReader)) {
+    EXPECT_FALSE(web_contents->GetAccessibilityMode().has_mode(
+        ui::AXMode::kLabelImages));
+
+    EnableScreenReader(true);
+  }
+
+  // Now the feature is on.
+  EXPECT_TRUE(
+      web_contents->GetAccessibilityMode().has_mode(ui::AXMode::kLabelImages));
 }
diff --git a/chrome/browser/ash/crosapi/test_mojo_connection_manager_unittest.cc b/chrome/browser/ash/crosapi/test_mojo_connection_manager_unittest.cc
index e768890..187e6d6 100644
--- a/chrome/browser/ash/crosapi/test_mojo_connection_manager_unittest.cc
+++ b/chrome/browser/ash/crosapi/test_mojo_connection_manager_unittest.cc
@@ -62,7 +62,7 @@
     return receiver_.BindNewPipeAndPassRemote();
   }
 
-  void REMOVED_0(REMOVED_0Callback callback) override { NOTIMPLEMENTED(); }
+  void REMOVED_0() override { NOTIMPLEMENTED(); }
   void REMOVED_2(crosapi::mojom::BrowserInitParamsPtr) override {
     NOTIMPLEMENTED();
   }
diff --git a/chrome/browser/ash/file_system_provider/content_cache/context_database.cc b/chrome/browser/ash/file_system_provider/content_cache/context_database.cc
index 3753337..13c8f6a 100644
--- a/chrome/browser/ash/file_system_provider/content_cache/context_database.cc
+++ b/chrome/browser/ash/file_system_provider/content_cache/context_database.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/ash/file_system_provider/content_cache/context_database.h"
 
 #include "base/sequence_checker.h"
-#include "sql/init_status.h"
+#include "sql/statement.h"
 #include "sql/transaction.h"
 
 namespace ash::file_system_provider {
@@ -23,6 +23,18 @@
         "PRIMARY KEY(id AUTOINCREMENT))";
 // clang-format on
 
+static constexpr char kInsertItemSql[] =
+    // clang-format off
+    "INSERT INTO items "
+    "(fsp_path, version_tag, accessed_time) VALUES (?, ?, ?) "
+    "RETURNING id";
+// clang-format on
+
+static constexpr char kSelectItemByIdSql[] =
+    // clang-format off
+    "SELECT fsp_path, version_tag, accessed_time FROM items WHERE id=? LIMIT 1";
+// clang-format on
+
 }  // namespace
 
 ContextDatabase::ContextDatabase(const base::FilePath& db_path)
@@ -81,6 +93,69 @@
   return committer.Commit();
 }
 
+bool ContextDatabase::AddItem(const base::FilePath& fsp_path,
+                              const std::string& version_tag,
+                              base::Time accessed_time,
+                              int64_t* inserted_id) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (fsp_path.empty() || version_tag.empty() || accessed_time.is_null()) {
+    return false;
+  }
+
+  std::unique_ptr<sql::Statement> statement = std::make_unique<sql::Statement>(
+      db_.GetCachedStatement(SQL_FROM_HERE, kInsertItemSql));
+  if (!statement) {
+    LOG(ERROR) << "Couldn't create SQL statement";
+    return false;
+  }
+
+  statement->BindString(0, fsp_path.value());
+  statement->BindString(1, version_tag);
+  statement->BindInt64(2, accessed_time.InMillisecondsSinceUnixEpoch());
+  if (!statement->Step()) {
+    LOG(ERROR) << "Couldn't execute statement";
+    return false;
+  }
+
+  *inserted_id = statement->ColumnInt64(0);
+  return true;
+}
+
+bool ContextDatabase::GetItemById(int64_t item_id, Item& item) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (item_id < 0) {
+    return false;
+  }
+
+  std::unique_ptr<sql::Statement> statement = std::make_unique<sql::Statement>(
+      db_.GetCachedStatement(SQL_FROM_HERE, kSelectItemByIdSql));
+  if (!statement) {
+    LOG(ERROR) << "Couldn't create SQL statement";
+    return false;
+  }
+
+  statement->BindInt64(0, item_id);
+  if (!statement->Step()) {
+    // In the event the `Step()` failed, this could simply mean there is no item
+    // for the `item_id`. `Succeeded` will return true in this case.
+    if (statement->Succeeded()) {
+      item.item_exists = false;
+      return true;
+    }
+    LOG(ERROR) << "Couldn't execute statement";
+    return false;
+  }
+
+  item.fsp_path = base::FilePath(statement->ColumnString(0));
+  item.version_tag = statement->ColumnString(1);
+  item.accessed_time =
+      base::Time::FromMillisecondsSinceUnixEpoch(statement->ColumnInt64(2));
+
+  return true;
+}
+
 bool ContextDatabase::Raze() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
diff --git a/chrome/browser/ash/file_system_provider/content_cache/context_database.h b/chrome/browser/ash/file_system_provider/content_cache/context_database.h
index 9678ea75..96fc894 100644
--- a/chrome/browser/ash/file_system_provider/content_cache/context_database.h
+++ b/chrome/browser/ash/file_system_provider/content_cache/context_database.h
@@ -28,6 +28,30 @@
   // empty) or at the path specified by the `db_path` in the constructor.
   bool Initialize();
 
+  // Insert an item into the database and returns the unique ID that references
+  // this item. In the event the `fsp_path` and `version_tag` have previously
+  // been used, this will remove the conflicted record and insert a new one.
+  bool AddItem(const base::FilePath& fsp_path,
+               const std::string& version_tag,
+               base::Time accessed_time,
+               int64_t* inserted_id);
+
+  // Represents a row returned from the SQLite database with the additional
+  // field of `item_exists` that will be set to `false` if the item requested is
+  // not available.
+  struct Item {
+    base::FilePath fsp_path;
+    base::Time accessed_time;
+    std::string version_tag;
+    bool item_exists = true;
+  };
+
+  // Retrieve an item by `item_id`. If this returns false, indicates a more
+  // fatal error. If this returns true the supplied `Item` will contain the data
+  // or alternatively the field `item_exists` will be false indicating the
+  // requested record is not available.
+  bool GetItemById(int64_t item_id, Item& item);
+
  private:
   SEQUENCE_CHECKER(sequence_checker_);
 
diff --git a/chrome/browser/ash/file_system_provider/content_cache/context_database_unittest.cc b/chrome/browser/ash/file_system_provider/content_cache/context_database_unittest.cc
index efd377a..2d5cf602 100644
--- a/chrome/browser/ash/file_system_provider/content_cache/context_database_unittest.cc
+++ b/chrome/browser/ash/file_system_provider/content_cache/context_database_unittest.cc
@@ -25,10 +25,74 @@
 
 TEST_F(FileSystemProviderContextDatabaseTest, DbCreatedOnInitialize) {
   base::FilePath db_path = temp_dir_.GetPath().Append("context.db");
-  ContextDatabase context_db(db_path);
-  EXPECT_TRUE(context_db.Initialize());
+  ContextDatabase db(db_path);
+  EXPECT_TRUE(db.Initialize());
   EXPECT_TRUE(base::PathExists(db_path));
 }
 
+TEST_F(FileSystemProviderContextDatabaseTest, AddItem) {
+  std::unique_ptr<ContextDatabase> db =
+      std::make_unique<ContextDatabase>(base::FilePath());
+  EXPECT_TRUE(db->Initialize());
+
+  // Doesn't accept empty parameters;
+  int64_t inserted_id = -1;
+  EXPECT_FALSE(db->AddItem(base::FilePath(), "versionA", base::Time::Now(),
+                           &inserted_id));
+  EXPECT_FALSE(db->AddItem(base::FilePath("/fsp_path.txt"), "",
+                           base::Time::Now(), &inserted_id));
+  EXPECT_FALSE(db->AddItem(base::FilePath("/fsp_path.txt"), "versionA",
+                           base::Time(), &inserted_id));
+  EXPECT_EQ(inserted_id, -1);
+
+  // Item added returns an auto incremented ID.
+  EXPECT_TRUE(db->AddItem(base::FilePath("/fsp_path.txt"), "versionA",
+                          base::Time::Now(), &inserted_id));
+  EXPECT_EQ(inserted_id, 1);
+  EXPECT_TRUE(db->AddItem(base::FilePath("/fsp_path_1.txt"), "versionA",
+                          base::Time::Now(), &inserted_id));
+  EXPECT_EQ(inserted_id, 2);
+
+  // If an item is added that matches the UNIQUE(fsp_path, version_tag)
+  // constraint the new ID is returned and the old ID gets removed.
+  EXPECT_TRUE(db->AddItem(base::FilePath("/fsp_path.txt"), "versionA",
+                          base::Time::Now(), &inserted_id));
+  EXPECT_EQ(inserted_id, 3);
+
+  // Expect that the item with id 1 is no longer available.
+  ContextDatabase::Item item;
+  db->GetItemById(1, item);
+  EXPECT_FALSE(item.item_exists);
+}
+
+TEST_F(FileSystemProviderContextDatabaseTest, GetItemById) {
+  std::unique_ptr<ContextDatabase> db =
+      std::make_unique<ContextDatabase>(base::FilePath());
+  EXPECT_TRUE(db->Initialize());
+
+  // Negative IDs should fail.
+  ContextDatabase::Item item;
+  EXPECT_FALSE(db->GetItemById(-1, item));
+
+  // Insert an item into the database.
+  int64_t inserted_id = -1;
+  base::FilePath fsp_path("/fsp_path.txt");
+  std::string version_tag("versionA");
+  base::Time accessed_time = base::Time::Now();
+  EXPECT_TRUE(db->AddItem(fsp_path, version_tag, accessed_time, &inserted_id));
+
+  // Retrieve the item back from the database.
+  EXPECT_TRUE(db->GetItemById(inserted_id, item));
+  EXPECT_TRUE(item.item_exists);
+
+  // We store the time in ms since unix epoch which doesn't have the same
+  // granularity as the `EXPECT_EQ` comparison, convert back to ensure the
+  // values are the same.
+  EXPECT_EQ(item.accessed_time.InMillisecondsSinceUnixEpoch(),
+            accessed_time.InMillisecondsSinceUnixEpoch());
+  EXPECT_EQ(item.fsp_path, fsp_path);
+  EXPECT_EQ(item.version_tag, version_tag);
+}
+
 }  // namespace
 }  // namespace ash::file_system_provider
diff --git a/chrome/browser/ash/file_system_provider/extension_provider.cc b/chrome/browser/ash/file_system_provider/extension_provider.cc
index cb2b773..2113e0d6 100644
--- a/chrome/browser/ash/file_system_provider/extension_provider.cc
+++ b/chrome/browser/ash/file_system_provider/extension_provider.cc
@@ -33,7 +33,7 @@
 
 // Timeout before an onMountRequested request is considered as stale and hence
 // aborted.
-constexpr base::TimeDelta kDefaultMountTimeout = base::Minutes(5);
+constexpr base::TimeDelta kDefaultMountTimeout = base::Minutes(10);
 
 extensions::file_system_provider::ServiceWorkerLifetimeManager*
 GetServiceWorkerLifetimeManager(Profile* profile) {
diff --git a/chrome/browser/ash/policy/enrollment/enrollment_config.h b/chrome/browser/ash/policy/enrollment/enrollment_config.h
index 00a5c2b8..881bd413 100644
--- a/chrome/browser/ash/policy/enrollment/enrollment_config.h
+++ b/chrome/browser/ash/policy/enrollment/enrollment_config.h
@@ -226,9 +226,6 @@
   // match.
   std::string management_domain;
 
-  // The realm the device is joined to (if managed by AD).
-  std::string management_realm;
-
   // Is a license packaged with device or not.
   bool is_license_packaged_with_device = false;
 
@@ -245,10 +242,6 @@
   // TODO(drcrash): Change to best available once ZTE is everywhere.
   AuthMechanism auth_mechanism = AUTH_MECHANISM_INTERACTIVE;
 
-  // The path for the device policy blob data for the offline demo mode. This
-  // should be empty and never used for other modes.
-  base::FilePath offline_policy_path;
-
   // User's email which can be passed from the Gaia screen in the enrollment
   // nudge flow.
   std::string enrollment_nudge_email;
diff --git a/chrome/browser/ash/telemetry_extension/routines/routine_converters.cc b/chrome/browser/ash/telemetry_extension/routines/routine_converters.cc
index 85935cf6..b0df925 100644
--- a/chrome/browser/ash/telemetry_extension/routines/routine_converters.cc
+++ b/chrome/browser/ash/telemetry_extension/routines/routine_converters.cc
@@ -45,9 +45,38 @@
   return crosapi::TelemetryDiagnosticRoutineStateInitialized::New();
 }
 
+crosapi::TelemetryDiagnosticNetworkBandwidthRoutineDetailPtr
+UncheckedConvertPtr(healthd::NetworkBandwidthRoutineDetailPtr input) {
+  auto detail =
+      crosapi::TelemetryDiagnosticNetworkBandwidthRoutineDetail::New();
+  detail->download_speed_kbps = input->download_speed_kbps;
+  detail->upload_speed_kbps = input->upload_speed_kbps;
+  return detail;
+}
+
+crosapi::TelemetryDiagnosticNetworkBandwidthRoutineRunningInfoPtr
+UncheckedConvertPtr(healthd::NetworkBandwidthRoutineRunningInfoPtr input) {
+  return crosapi::TelemetryDiagnosticNetworkBandwidthRoutineRunningInfo::New(
+      Convert(input->type), input->speed_kbps);
+}
+
+crosapi::TelemetryDiagnosticRoutineRunningInfoPtr UncheckedConvertPtr(
+    healthd::RoutineRunningInfoPtr input) {
+  switch (input->which()) {
+    case healthd::RoutineRunningInfo::Tag::kUnrecognizedArgument:
+      return crosapi::TelemetryDiagnosticRoutineRunningInfo::
+          NewUnrecognizedArgument(input->get_unrecognizedArgument());
+    case healthd::RoutineRunningInfo::Tag::kNetworkBandwidth:
+      return crosapi::TelemetryDiagnosticRoutineRunningInfo::
+          NewNetworkBandwidth(
+              ConvertRoutinePtr(std::move(input->get_network_bandwidth())));
+  }
+}
+
 crosapi::TelemetryDiagnosticRoutineStateRunningPtr UncheckedConvertPtr(
     healthd::RoutineStateRunningPtr input) {
-  return crosapi::TelemetryDiagnosticRoutineStateRunning::New();
+  return crosapi::TelemetryDiagnosticRoutineStateRunning::New(
+      ConvertRoutinePtr(std::move(input->info)));
 }
 
 crosapi::TelemetryDiagnosticCheckLedLitUpStateInquiryPtr UncheckedConvertPtr(
@@ -100,6 +129,9 @@
     case healthd::RoutineDetail::Tag::kFan:
       return crosapi::TelemetryDiagnosticRoutineDetail::NewFan(
           ConvertRoutinePtr(std::move(input->get_fan())));
+    case healthd::RoutineDetail::Tag::kNetworkBandwidth:
+      return crosapi::TelemetryDiagnosticRoutineDetail::NewNetworkBandwidth(
+          ConvertRoutinePtr(std::move(input->get_network_bandwidth())));
     // The following routines have not been added to crosapi yet.
     case healthd::RoutineDetail::Tag::kAudioDriver:
     case healthd::RoutineDetail::Tag::kUfsLifetime:
@@ -108,7 +140,6 @@
     case healthd::RoutineDetail::Tag::kBluetoothScanning:
     case healthd::RoutineDetail::Tag::kBluetoothPairing:
     case healthd::RoutineDetail::Tag::kCameraAvailability:
-    case healthd::RoutineDetail::Tag::kNetworkBandwidth:
       // The actual value of unrecognizedArgument should not be used. Assign an
       // arbitrary value to it.
       return crosapi::TelemetryDiagnosticRoutineDetail::NewUnrecognizedArgument(
@@ -170,6 +201,9 @@
     case crosapi::TelemetryDiagnosticRoutineArgument::Tag::kLedLitUp:
       return healthd::RoutineArgument::NewLedLitUp(
           ConvertRoutinePtr(std::move(input->get_led_lit_up())));
+    case crosapi::TelemetryDiagnosticRoutineArgument::Tag::kNetworkBandwidth:
+      return healthd::RoutineArgument::NewNetworkBandwidth(
+          ConvertRoutinePtr(std::move(input->get_network_bandwidth())));
   }
 }
 
@@ -221,6 +255,11 @@
   return arg;
 }
 
+healthd::NetworkBandwidthRoutineArgumentPtr UncheckedConvertPtr(
+    crosapi::TelemetryDiagnosticNetworkBandwidthRoutineArgumentPtr input) {
+  return healthd::NetworkBandwidthRoutineArgument::New();
+}
+
 healthd::RoutineInquiryReplyPtr UncheckedConvertPtr(
     crosapi::TelemetryDiagnosticRoutineInquiryReplyPtr input) {
   switch (input->which()) {
@@ -374,4 +413,20 @@
   NOTREACHED_NORETURN();
 }
 
+crosapi::TelemetryDiagnosticNetworkBandwidthRoutineRunningInfo::Type Convert(
+    healthd::NetworkBandwidthRoutineRunningInfo::Type input) {
+  switch (input) {
+    case healthd::NetworkBandwidthRoutineRunningInfo::Type::kUnmappedEnumField:
+      return crosapi::TelemetryDiagnosticNetworkBandwidthRoutineRunningInfo::
+          Type::kUnmappedEnumField;
+    case healthd::NetworkBandwidthRoutineRunningInfo::Type::kDownload:
+      return crosapi::TelemetryDiagnosticNetworkBandwidthRoutineRunningInfo::
+          Type::kDownload;
+    case healthd::NetworkBandwidthRoutineRunningInfo::Type::kUpload:
+      return crosapi::TelemetryDiagnosticNetworkBandwidthRoutineRunningInfo::
+          Type::kUpload;
+  }
+  NOTREACHED_NORETURN();
+}
+
 }  // namespace ash::converters
diff --git a/chrome/browser/ash/telemetry_extension/routines/routine_converters.h b/chrome/browser/ash/telemetry_extension/routines/routine_converters.h
index a52d13c..06872a1 100644
--- a/chrome/browser/ash/telemetry_extension/routines/routine_converters.h
+++ b/chrome/browser/ash/telemetry_extension/routines/routine_converters.h
@@ -30,9 +30,20 @@
 crosapi::mojom::TelemetryDiagnosticFanRoutineDetailPtr UncheckedConvertPtr(
     cros_healthd::mojom::FanRoutineDetailPtr input);
 
+crosapi::mojom::TelemetryDiagnosticNetworkBandwidthRoutineDetailPtr
+UncheckedConvertPtr(
+    cros_healthd::mojom::NetworkBandwidthRoutineDetailPtr input);
+
 crosapi::mojom::TelemetryDiagnosticRoutineStateInitializedPtr
 UncheckedConvertPtr(cros_healthd::mojom::RoutineStateInitializedPtr input);
 
+crosapi::mojom::TelemetryDiagnosticNetworkBandwidthRoutineRunningInfoPtr
+UncheckedConvertPtr(
+    cros_healthd::mojom::NetworkBandwidthRoutineRunningInfoPtr input);
+
+crosapi::mojom::TelemetryDiagnosticRoutineRunningInfoPtr UncheckedConvertPtr(
+    cros_healthd::mojom::RoutineRunningInfoPtr input);
+
 crosapi::mojom::TelemetryDiagnosticRoutineStateRunningPtr UncheckedConvertPtr(
     cros_healthd::mojom::RoutineStateRunningPtr input);
 
@@ -81,6 +92,10 @@
 cros_healthd::mojom::RoutineInquiryReplyPtr UncheckedConvertPtr(
     crosapi::mojom::TelemetryDiagnosticRoutineInquiryReplyPtr input);
 
+cros_healthd::mojom::NetworkBandwidthRoutineArgumentPtr UncheckedConvertPtr(
+    crosapi::mojom::TelemetryDiagnosticNetworkBandwidthRoutineArgumentPtr
+        input);
+
 }  // namespace unchecked
 
 cros_healthd::mojom::LedName Convert(
@@ -101,6 +116,9 @@
 crosapi::mojom::TelemetryDiagnosticRoutineStateWaiting::Reason Convert(
     cros_healthd::mojom::RoutineStateWaiting::Reason input);
 
+crosapi::mojom::TelemetryDiagnosticNetworkBandwidthRoutineRunningInfo::Type
+Convert(cros_healthd::mojom::NetworkBandwidthRoutineRunningInfo::Type input);
+
 template <class InputT,
           class OutputT = decltype(Convert(std::declval<InputT>())),
           class = std::enable_if_t<std::is_enum_v<InputT>, bool>>
diff --git a/chrome/browser/ash/telemetry_extension/routines/routine_converters_unittest.cc b/chrome/browser/ash/telemetry_extension/routines/routine_converters_unittest.cc
index f14ebf1b..3133e009 100644
--- a/chrome/browser/ash/telemetry_extension/routines/routine_converters_unittest.cc
+++ b/chrome/browser/ash/telemetry_extension/routines/routine_converters_unittest.cc
@@ -95,6 +95,16 @@
 }
 
 TEST(TelemetryDiagnosticRoutineConvertersTest,
+     ConvertNetworkBandwidthRoutineArgumentPtr) {
+  auto input =
+      crosapi::TelemetryDiagnosticNetworkBandwidthRoutineArgument::New();
+
+  auto result = ConvertRoutinePtr(std::move(input));
+
+  ASSERT_TRUE(result);
+}
+
+TEST(TelemetryDiagnosticRoutineConvertersTest,
      ConvertUnrecognizedRoutineInquiryReplyPtr) {
   auto input =
       crosapi::TelemetryDiagnosticRoutineInquiryReply::NewUnrecognizedReply(
@@ -349,6 +359,19 @@
 }
 
 TEST(TelemetryDiagnosticRoutineConvertersTest,
+     ConvertTelemetryDiagnosticNetworkBandwidthRoutineDetailPtr) {
+  auto input = healthd::NetworkBandwidthRoutineDetail::New();
+  input->download_speed_kbps = 123.0;
+  input->upload_speed_kbps = 456.0;
+
+  auto result = ConvertRoutinePtr(std::move(input));
+
+  ASSERT_TRUE(result);
+  EXPECT_EQ(result->download_speed_kbps, 123.0);
+  EXPECT_EQ(result->upload_speed_kbps, 456.0);
+}
+
+TEST(TelemetryDiagnosticRoutineConvertersTest,
      ConvertTelemetryDiagnosticRoutineDetailPtr) {
   EXPECT_EQ(
       ConvertRoutinePtr(healthd::RoutineDetail::NewUnrecognizedArgument(true)),
@@ -363,6 +386,12 @@
                 healthd::FanRoutineDetail::New())),
             crosapi::TelemetryDiagnosticRoutineDetail::NewFan(
                 crosapi::TelemetryDiagnosticFanRoutineDetail::New()));
+
+  EXPECT_EQ(
+      ConvertRoutinePtr(healthd::RoutineDetail::NewNetworkBandwidth(
+          healthd::NetworkBandwidthRoutineDetail::New())),
+      crosapi::TelemetryDiagnosticRoutineDetail::NewNetworkBandwidth(
+          crosapi::TelemetryDiagnosticNetworkBandwidthRoutineDetail::New()));
 }
 
 TEST(TelemetryDiagnosticRoutineConvertersTest,
@@ -432,4 +461,34 @@
                 crosapi::TelemetryDiagnosticRoutineStateRunning::New()));
 }
 
+TEST(TelemetryDiagnosticRoutineConvertersTest,
+     ConvertTelemetryDiagnosticRoutineRunningInfoPtr) {
+  EXPECT_EQ(
+      ConvertRoutinePtr(
+          healthd::RoutineRunningInfo::NewUnrecognizedArgument(true)),
+      crosapi::TelemetryDiagnosticRoutineRunningInfo::NewUnrecognizedArgument(
+          true));
+
+  EXPECT_EQ(ConvertRoutinePtr(healthd::RoutineRunningInfo::NewNetworkBandwidth(
+                healthd::NetworkBandwidthRoutineRunningInfo::New())),
+            crosapi::TelemetryDiagnosticRoutineRunningInfo::NewNetworkBandwidth(
+                crosapi::TelemetryDiagnosticNetworkBandwidthRoutineRunningInfo::
+                    New()));
+}
+
+TEST(TelemetryDiagnosticRoutineConvertersTest,
+     ConvertTelemetryDiagnosticNetworkBandwidthRoutineRunningInfoPtr) {
+  auto input = healthd::NetworkBandwidthRoutineRunningInfo::New();
+  input->type = healthd::NetworkBandwidthRoutineRunningInfo::Type::kDownload;
+  input->speed_kbps = 100.0;
+
+  auto result = ConvertRoutinePtr(std::move(input));
+
+  ASSERT_TRUE(result);
+  EXPECT_EQ(result->type,
+            crosapi::TelemetryDiagnosticNetworkBandwidthRoutineRunningInfo::
+                Type::kDownload);
+  EXPECT_EQ(result->speed_kbps, 100.0);
+}
+
 }  // namespace ash::converters
diff --git a/chrome/browser/attribution_reporting/chrome_attribution_browsertest.cc b/chrome/browser/attribution_reporting/chrome_attribution_browsertest.cc
index 54cc580..0fdfeea 100644
--- a/chrome/browser/attribution_reporting/chrome_attribution_browsertest.cc
+++ b/chrome/browser/attribution_reporting/chrome_attribution_browsertest.cc
@@ -247,8 +247,9 @@
           proto, base::Version("1.2.3")));
 }
 
+// TODO(crbug.com/327794975) Test is flaky on various platforms.
 IN_PROC_BROWSER_TEST_F(ChromeAttributionAttestationsBrowserTest,
-                       AttribtionUponAttestationsLoading) {
+                       DISABLED_AttribtionUponAttestationsLoading) {
   PrivacySandboxSettingsFactory::GetForProfile(browser()->profile())
       ->SetAllPrivacySandboxAllowedForTesting();
 
diff --git a/chrome/browser/autofill/android/save_update_address_profile_prompt_controller.cc b/chrome/browser/autofill/android/save_update_address_profile_prompt_controller.cc
index 30d20a2..988aefe 100644
--- a/chrome/browser/autofill/android/save_update_address_profile_prompt_controller.cc
+++ b/chrome/browser/autofill/android/save_update_address_profile_prompt_controller.cc
@@ -103,7 +103,7 @@
     // TODO(crbug.com/40066949): Simplify once ConsentLevel::kSync is not used
     // anymore, and thus IsSyncFeatureEnabledForAutofill() will always be false.
     return l10n_util::GetStringFUTF16(
-        personal_data_->IsSyncFeatureEnabledForAutofill()
+        personal_data_->address_data_manager().IsSyncFeatureEnabledForAutofill()
             ? IDS_AUTOFILL_SYNCABLE_PROFILE_MIGRATION_PROMPT_NOTICE
             : IDS_AUTOFILL_LOCAL_PROFILE_MIGRATION_PROMPT_NOTICE,
         base::UTF8ToUTF16(account->email));
diff --git a/chrome/browser/browser_features.h b/chrome/browser/browser_features.h
index 3a47bd3..57ae21c 100644
--- a/chrome/browser/browser_features.h
+++ b/chrome/browser/browser_features.h
@@ -97,6 +97,12 @@
     kNewTabPagePreconnectStartDelayOnMouseHoverByMiliSeconds{
         &features::kNewTabPageTriggerForPrerender2,
         "preconnect_start_delay_on_mouse_hover_ms", 100};
+const base::FeatureParam<bool> kPrerenderNewTabPageOnMousePressedTrigger{
+    &features::kNewTabPageTriggerForPrerender2,
+    "prerender_new_tab_page_on_mouse_pressed_trigger", false};
+const base::FeatureParam<bool> kPrerenderNewTabPageOnMouseHoverTrigger{
+    &features::kNewTabPageTriggerForPrerender2,
+    "prerender_new_tab_page_on_mouse_hover_trigger", false};
 
 #if BUILDFLAG(IS_WIN)
 BASE_DECLARE_FEATURE(kNoPreReadMainDll);
diff --git a/chrome/browser/chrome_navigation_browsertest.cc b/chrome/browser/chrome_navigation_browsertest.cc
index d7af1d5c..53cc74d 100644
--- a/chrome/browser/chrome_navigation_browsertest.cc
+++ b/chrome/browser/chrome_navigation_browsertest.cc
@@ -1996,8 +1996,9 @@
 
 // Tests that a main frame hosting pdf does not get skipped because of history
 // manipulation intervention if there was a user gesture.
+// TODO(crbug.com/333829580): Final navigation is flaky on all platforms.
 IN_PROC_BROWSER_TEST_F(HistoryManipulationInterventionBrowserTest,
-                       PDFDoNotSkipOnBackForwardDueToUserGesture) {
+                       DISABLED_PDFDoNotSkipOnBackForwardDueToUserGesture) {
   GURL pdf_url(embedded_test_server()->GetURL("/pdf/test.pdf"));
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), pdf_url));
 
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/diagnostics/diagnostics_api.cc b/chrome/browser/chromeos/extensions/telemetry/api/diagnostics/diagnostics_api.cc
index 61f3c88..35b06846 100644
--- a/chrome/browser/chromeos/extensions/telemetry/api/diagnostics/diagnostics_api.cc
+++ b/chrome/browser/chromeos/extensions/telemetry/api/diagnostics/diagnostics_api.cc
@@ -8,6 +8,7 @@
 #include <string>
 #include <utility>
 
+#include "base/feature_list.h"
 #include "base/functional/bind.h"
 #include "base/notreached.h"
 #include "base/time/time.h"
@@ -23,6 +24,7 @@
 #include "chromeos/crosapi/mojom/nullable_primitives.mojom.h"
 #include "chromeos/crosapi/mojom/telemetry_diagnostic_routine_service.mojom.h"
 #include "chromeos/crosapi/mojom/telemetry_extension_exception.mojom.h"
+#include "extensions/common/extension_features.h"
 #include "extensions/common/permissions/permissions_data.h"
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
@@ -61,6 +63,11 @@
   NOTREACHED_NORETURN();
 }
 
+bool IsPendingApprovalRoutine(
+    const crosapi::mojom::TelemetryDiagnosticRoutineArgumentPtr& arg) {
+  return arg->is_network_bandwidth();
+}
+
 }  // namespace
 
 // DiagnosticsApiFunctionV1AndV2Base -------------------------------------------
@@ -518,6 +525,14 @@
     return;
   }
 
+  // Block unreleased features behind the feature flag.
+  if (IsPendingApprovalRoutine(mojo_arg.value()) &&
+      !base::FeatureList::IsEnabled(
+          extensions_features::kTelemetryExtensionPendingApprovalApi)) {
+    mojo_arg = crosapi::mojom::TelemetryDiagnosticRoutineArgument::
+        NewUnrecognizedArgument(false);
+  }
+
   auto* routines_manager = DiagnosticRoutineManager::Get(browser_context());
   auto result = routines_manager->CreateRoutine(extension_id(),
                                                 std::move(mojo_arg.value()));
@@ -724,6 +739,14 @@
     return;
   }
 
+  // Block unreleased features behind the feature flag.
+  if (IsPendingApprovalRoutine(mojo_arg.value()) &&
+      !base::FeatureList::IsEnabled(
+          extensions_features::kTelemetryExtensionPendingApprovalApi)) {
+    mojo_arg = crosapi::mojom::TelemetryDiagnosticRoutineArgument::
+        NewUnrecognizedArgument(false);
+  }
+
   auto* routines_manager = DiagnosticRoutineManager::Get(browser_context());
   routines_manager->IsRoutineArgumentSupported(
       std::move(mojo_arg.value()),
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/diagnostics/diagnostics_api_converters.cc b/chrome/browser/chromeos/extensions/telemetry/api/diagnostics/diagnostics_api_converters.cc
index ecbf97b..be164b0 100644
--- a/chrome/browser/chromeos/extensions/telemetry/api/diagnostics/diagnostics_api_converters.cc
+++ b/chrome/browser/chromeos/extensions/telemetry/api/diagnostics/diagnostics_api_converters.cc
@@ -66,6 +66,14 @@
   return true;
 }
 
+bool PopulateNetworkBandwidthRoutineArguments(
+    const cx_diag::CreateNetworkBandwidthRoutineArguments& cx_args,
+    crosapi::TelemetryDiagnosticRoutineArgumentPtr& out) {
+  out = crosapi::TelemetryDiagnosticRoutineArgument::NewNetworkBandwidth(
+      crosapi::TelemetryDiagnosticNetworkBandwidthRoutineArgument::New());
+  return true;
+}
+
 }  // namespace
 
 bool ConvertMojoRoutine(crosapi::DiagnosticsRoutineEnum in,
@@ -311,6 +319,12 @@
       return std::nullopt;
     }
   }
+  if (extension_union.network_bandwidth) {
+    if (result || !PopulateNetworkBandwidthRoutineArguments(
+                      extension_union.network_bandwidth.value(), result)) {
+      return std::nullopt;
+    }
+  }
   if (result) {
     return result;
   }
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/diagnostics/diagnostics_api_v2_browsertest.cc b/chrome/browser/chromeos/extensions/telemetry/api/diagnostics/diagnostics_api_v2_browsertest.cc
index 54d5931..42d9dd7 100644
--- a/chrome/browser/chromeos/extensions/telemetry/api/diagnostics/diagnostics_api_v2_browsertest.cc
+++ b/chrome/browser/chromeos/extensions/telemetry/api/diagnostics/diagnostics_api_v2_browsertest.cc
@@ -15,6 +15,7 @@
 #include "chromeos/crosapi/mojom/telemetry_diagnostic_routine_service.mojom.h"
 #include "chromeos/crosapi/mojom/telemetry_extension_exception.mojom.h"
 #include "content/public/test/browser_test.h"
+#include "extensions/common/extension_features.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
@@ -1110,4 +1111,117 @@
   )");
 }
 
+IN_PROC_BROWSER_TEST_F(
+    TelemetryExtensionDiagnosticsApiV2BrowserTest,
+    CreateNetworkBandwidthRoutineWithoutFeatureFlagUnrecognized) {
+  fake_service().SetOnCreateRoutineCalled(base::BindLambdaForTesting([this]() {
+    auto* control = fake_service().GetCreatedRoutineControlForRoutineType(
+        crosapi::TelemetryDiagnosticRoutineArgument::Tag::
+            kUnrecognizedArgument);
+    ASSERT_TRUE(control);
+  }));
+
+  OpenAppUiAndMakeItSecure();
+
+  CreateExtensionAndRunServiceWorker(R"(
+    chrome.test.runTests([
+      async function createNetworkBandwidthRoutineUnrecognized() {
+        const result = await chrome.os.diagnostics.createRoutine({
+          networkBandwidth: {},
+        });
+
+        chrome.test.assertTrue(result !== undefined);
+        chrome.test.succeed();
+      }
+    ]);
+
+  )");
+}
+
+class PendingApprovalTelemetryExtensionDiagnosticsApiV2BrowserTest
+    : public TelemetryExtensionDiagnosticsApiV2BrowserTest {
+ public:
+  PendingApprovalTelemetryExtensionDiagnosticsApiV2BrowserTest() {
+    feature_list_.InitAndEnableFeature(
+        extensions_features::kTelemetryExtensionPendingApprovalApi);
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(
+    PendingApprovalTelemetryExtensionDiagnosticsApiV2BrowserTest,
+    CreateNetworkBandwidthRoutineWithFeatureFlagSuccess) {
+  fake_service().SetOnCreateRoutineCalled(base::BindLambdaForTesting([this]() {
+    auto* control = fake_service().GetCreatedRoutineControlForRoutineType(
+        crosapi::TelemetryDiagnosticRoutineArgument::Tag::kNetworkBandwidth);
+    ASSERT_TRUE(control);
+
+    auto network_bandwidth_detail =
+        crosapi::TelemetryDiagnosticNetworkBandwidthRoutineDetail::New();
+    network_bandwidth_detail->download_speed_kbps = 123.0;
+    network_bandwidth_detail->upload_speed_kbps = 456.0;
+
+    auto finished_state =
+        crosapi::TelemetryDiagnosticRoutineStateFinished::New();
+    finished_state->detail =
+        crosapi::TelemetryDiagnosticRoutineDetail::NewNetworkBandwidth(
+            std::move(network_bandwidth_detail));
+    finished_state->has_passed = true;
+
+    auto state = crosapi::TelemetryDiagnosticRoutineState::New();
+    state->state_union =
+        crosapi::TelemetryDiagnosticRoutineStateUnion::NewFinished(
+            std::move(finished_state));
+
+    control->SetState(std::move(state));
+  }));
+
+  OpenAppUiAndMakeItSecure();
+
+  CreateExtensionAndRunServiceWorker(R"(
+    chrome.test.runTests([
+      async function createNetworkBandwidthRoutine() {
+        let resolver;
+        // Set later once the routine was created.
+        var uuid = new Promise((resolve) => {
+          resolver = resolve;
+        });
+
+
+        let onInitCalled = false;
+        chrome.os.diagnostics.onRoutineInitialized.addListener(
+          async (status) => {
+          chrome.test.assertEq(status.uuid, await uuid);
+          onInitCalled = true;
+        });
+
+        // Only resolve the test once we got the final event.
+        chrome.os.diagnostics.onRoutineFinished.addListener(
+          async (status) => {
+          chrome.test.assertEq(status, {
+            "detail": {
+              "networkBandwidth": {
+                "downloadSpeedKbps": 123.0,
+                "uploadSpeedKbps": 456.0
+              }
+            },
+            "hasPassed": true,
+            "uuid": await uuid
+          });
+          chrome.test.assertTrue(onInitCalled);
+          chrome.test.succeed();
+        });
+
+        const response = await chrome.os.diagnostics.createRoutine({
+          networkBandwidth: {},
+        });
+        chrome.test.assertTrue(response !== undefined);
+        resolver(response.uuid);
+      }
+    ]);
+  )");
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_converters.cc b/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_converters.cc
index 58c9103e..23b91c2 100644
--- a/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_converters.cc
+++ b/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_converters.cc
@@ -39,6 +39,29 @@
     case crosapi::TelemetryDiagnosticRoutineDetail::Tag::kFan:
       detail.fan = ConvertPtr(std::move(input->get_fan()));
       return detail;
+    case crosapi::TelemetryDiagnosticRoutineDetail::Tag::kNetworkBandwidth:
+      detail.network_bandwidth =
+          ConvertPtr(std::move(input->get_network_bandwidth()));
+      return detail;
+  }
+}
+
+std::optional<cx_diag::RoutineRunningInfoUnion>
+ConvertRoutineRunningInfoUnionPtr(
+    crosapi::TelemetryDiagnosticRoutineRunningInfoPtr input) {
+  if (input.is_null()) {
+    return std::nullopt;
+  }
+  cx_diag::RoutineRunningInfoUnion info;
+  switch (input->which()) {
+    case crosapi::TelemetryDiagnosticRoutineRunningInfo::Tag::
+        kUnrecognizedArgument:
+      LOG(WARNING) << "Got unknown routine running info";
+      return std::nullopt;
+    case crosapi::TelemetryDiagnosticRoutineRunningInfo::Tag::kNetworkBandwidth:
+      info.network_bandwidth =
+          ConvertPtr(std::move(input->get_network_bandwidth()));
+      return info;
   }
 }
 
@@ -61,9 +84,18 @@
   cx_diag::RoutineRunningInfo result;
   result.uuid = uuid.AsLowercaseString();
   result.percentage = percentage;
+  result.info = ConvertRoutineRunningInfoUnionPtr(std::move(input->info));
   return result;
 }
 
+cx_diag::NetworkBandwidthRoutineRunningInfo UncheckedConvertPtr(
+    crosapi::TelemetryDiagnosticNetworkBandwidthRoutineRunningInfoPtr input) {
+  cx_diag::NetworkBandwidthRoutineRunningInfo info;
+  info.type = Convert(input->type);
+  info.speed_kbps = input->speed_kbps;
+  return info;
+}
+
 cx_diag::RoutineWaitingInfo UncheckedConvertPtr(
     crosapi::TelemetryDiagnosticRoutineStateWaitingPtr input,
     base::Uuid uuid,
@@ -162,6 +194,14 @@
   return result;
 }
 
+cx_diag::NetworkBandwidthRoutineFinishedDetail UncheckedConvertPtr(
+    crosapi::TelemetryDiagnosticNetworkBandwidthRoutineDetailPtr input) {
+  cx_diag::NetworkBandwidthRoutineFinishedDetail result;
+  result.download_speed_kbps = input->download_speed_kbps;
+  result.upload_speed_kbps = input->upload_speed_kbps;
+  return result;
+}
+
 cx_diag::RoutineFinishedInfo UncheckedConvertPtr(
     crosapi::TelemetryDiagnosticRoutineStateFinishedPtr input,
     base::Uuid uuid,
@@ -270,4 +310,21 @@
   NOTREACHED_NORETURN();
 }
 
+cx_diag::NetworkBandwidthRoutineRunningType Convert(
+    crosapi::TelemetryDiagnosticNetworkBandwidthRoutineRunningInfo::Type
+        input) {
+  switch (input) {
+    case crosapi::TelemetryDiagnosticNetworkBandwidthRoutineRunningInfo::Type::
+        kUnmappedEnumField:
+      return cx_diag::NetworkBandwidthRoutineRunningType::kNone;
+    case crosapi::TelemetryDiagnosticNetworkBandwidthRoutineRunningInfo::Type::
+        kDownload:
+      return cx_diag::NetworkBandwidthRoutineRunningType::kDownload;
+    case crosapi::TelemetryDiagnosticNetworkBandwidthRoutineRunningInfo::Type::
+        kUpload:
+      return cx_diag::NetworkBandwidthRoutineRunningType::kUpload;
+  }
+  NOTREACHED_NORETURN();
+}
+
 }  // namespace chromeos::converters::routines
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_converters.h b/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_converters.h
index b06aa91..49b58634 100644
--- a/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_converters.h
+++ b/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_converters.h
@@ -32,6 +32,10 @@
     base::Uuid uuid,
     uint32_t percentage);
 
+api::os_diagnostics::NetworkBandwidthRoutineRunningInfo UncheckedConvertPtr(
+    crosapi::mojom::TelemetryDiagnosticNetworkBandwidthRoutineRunningInfoPtr
+        input);
+
 api::os_diagnostics::RoutineWaitingInfo UncheckedConvertPtr(
     crosapi::mojom::TelemetryDiagnosticRoutineStateWaitingPtr input,
     base::Uuid uuid,
@@ -67,6 +71,9 @@
 api::os_diagnostics::FanRoutineFinishedDetail UncheckedConvertPtr(
     crosapi::mojom::TelemetryDiagnosticFanRoutineDetailPtr input);
 
+api::os_diagnostics::NetworkBandwidthRoutineFinishedDetail UncheckedConvertPtr(
+    crosapi::mojom::TelemetryDiagnosticNetworkBandwidthRoutineDetailPtr input);
+
 api::os_diagnostics::RoutineFinishedInfo UncheckedConvertPtr(
     crosapi::mojom::TelemetryDiagnosticRoutineStateFinishedPtr input,
     base::Uuid uuid,
@@ -86,6 +93,10 @@
 api::os_diagnostics::HardwarePresenceStatus Convert(
     crosapi::mojom::TelemetryDiagnosticHardwarePresenceStatus input);
 
+api::os_diagnostics::NetworkBandwidthRoutineRunningType Convert(
+    crosapi::mojom::TelemetryDiagnosticNetworkBandwidthRoutineRunningInfo::Type
+        input);
+
 template <class InputT,
           class OutputT = decltype(Convert(std::declval<InputT>())),
           class = std::enable_if_t<std::is_enum_v<InputT> ||
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_converters_unittest.cc b/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_converters_unittest.cc
index ad89b18..685e123 100644
--- a/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_converters_unittest.cc
+++ b/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_converters_unittest.cc
@@ -44,6 +44,40 @@
 
   ASSERT_TRUE(result.percentage.has_value());
   EXPECT_EQ(static_cast<uint32_t>(*result.percentage), kPercentage);
+
+  EXPECT_FALSE(result.info.has_value());
+}
+
+TEST(TelemetryExtensionDiagnosticRoutineConvertersTest,
+     NetworkBandwidthRoutineRunningInfo) {
+  const base::Uuid kUuid = base::Uuid::GenerateRandomV4();
+  constexpr uint32_t kPercentage = 50;
+
+  auto running_info =
+      crosapi::TelemetryDiagnosticNetworkBandwidthRoutineRunningInfo::New();
+  running_info->type = crosapi::
+      TelemetryDiagnosticNetworkBandwidthRoutineRunningInfo::Type::kDownload;
+  running_info->speed_kbps = 100.0;
+
+  auto input = crosapi::TelemetryDiagnosticRoutineStateRunning::New();
+  input->info =
+      crosapi::TelemetryDiagnosticRoutineRunningInfo::NewNetworkBandwidth(
+          std::move(running_info));
+
+  auto result = ConvertPtr(std::move(input), kUuid, kPercentage);
+
+  ASSERT_TRUE(result.uuid.has_value());
+  EXPECT_EQ(*result.uuid, kUuid.AsLowercaseString());
+
+  ASSERT_TRUE(result.percentage.has_value());
+  EXPECT_EQ(static_cast<uint32_t>(*result.percentage), kPercentage);
+
+  ASSERT_TRUE(result.info.has_value());
+  ASSERT_TRUE(result.info->network_bandwidth.has_value());
+
+  EXPECT_EQ(result.info->network_bandwidth->type,
+            cx_diag::NetworkBandwidthRoutineRunningType::kDownload);
+  EXPECT_EQ(result.info->network_bandwidth->speed_kbps, 100.0);
 }
 
 TEST(TelemetryExtensionDiagnosticRoutineConvertersTest, RoutineWaitingInfo) {
@@ -308,6 +342,36 @@
               cx_diag::HardwarePresenceStatus::kMatched);
 }
 
+TEST(TelemetryExtensionDiagnosticRoutineConvertersTest,
+     RoutineFinishedInfoWithNetworkBandwidthDetail) {
+  constexpr bool kHasPassed = true;
+  const base::Uuid kUuid = base::Uuid::GenerateRandomV4();
+
+  auto detail =
+      crosapi::TelemetryDiagnosticNetworkBandwidthRoutineDetail::New();
+  detail->download_speed_kbps = 123.0;
+  detail->upload_speed_kbps = 456.0;
+
+  auto input = crosapi::TelemetryDiagnosticRoutineStateFinished::New();
+  input->detail =
+      crosapi::TelemetryDiagnosticRoutineDetail::NewNetworkBandwidth(
+          std::move(detail));
+
+  auto result = ConvertPtr(std::move(input), kUuid, kHasPassed);
+
+  ASSERT_TRUE(result.uuid.has_value());
+  EXPECT_EQ(*result.uuid, kUuid.AsLowercaseString());
+
+  ASSERT_TRUE(result.has_passed.has_value());
+  EXPECT_EQ(*result.has_passed, kHasPassed);
+
+  ASSERT_TRUE(result.detail.has_value());
+  ASSERT_TRUE(result.detail->network_bandwidth.has_value());
+
+  EXPECT_EQ(result.detail->network_bandwidth->download_speed_kbps, 123.0);
+  EXPECT_EQ(result.detail->network_bandwidth->upload_speed_kbps, 456.0);
+}
+
 TEST(TelemetryExtensionDiagnosticRoutineConvertersTest, ExceptionReason) {
   EXPECT_EQ(
       Convert(crosapi::TelemetryExtensionException::Reason::kUnmappedEnumField),
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_observation.cc b/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_observation.cc
index 6edac1cd..cc5f5941 100644
--- a/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_observation.cc
+++ b/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_observation.cc
@@ -80,6 +80,9 @@
           cx_diag::OnFanRoutineFinished::kEventName,
           base::Value::List().Append(finished_info.ToValue()), browser_context);
     }
+    case crosapi::TelemetryDiagnosticRoutineDetail::Tag::kNetworkBandwidth:
+      // No need to support legacy finished events for newer routines.
+      return nullptr;
   }
   NOTREACHED_NORETURN();
 }
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_observation_browsertest.cc b/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_observation_browsertest.cc
index 96574b0f..a92a5ec 100644
--- a/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_observation_browsertest.cc
+++ b/chrome/browser/chromeos/extensions/telemetry/api/routines/diagnostic_routine_observation_browsertest.cc
@@ -185,6 +185,58 @@
 }
 
 IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticRoutineObserverBrowserTest,
+                       CanObserveOnRoutineRunningWithNetworkBandwidthInfo) {
+  SetRoutineObservation();
+  RegisterEventObserver(
+      api::os_diagnostics::OnRoutineRunning::kEventName,
+      base::BindLambdaForTesting([this] {
+        auto network_bandwidth_info = crosapi::
+            TelemetryDiagnosticNetworkBandwidthRoutineRunningInfo::New();
+        network_bandwidth_info->type =
+            crosapi::TelemetryDiagnosticNetworkBandwidthRoutineRunningInfo::
+                Type::kDownload;
+        network_bandwidth_info->speed_kbps = 100.0;
+
+        auto running_state =
+            crosapi::TelemetryDiagnosticRoutineStateRunning::New();
+        running_state->info =
+            crosapi::TelemetryDiagnosticRoutineRunningInfo::NewNetworkBandwidth(
+                std::move(network_bandwidth_info));
+
+        auto state = crosapi::TelemetryDiagnosticRoutineState::New();
+        state->state_union =
+            crosapi::TelemetryDiagnosticRoutineStateUnion::NewRunning(
+                std::move(running_state));
+        state->percentage = 50;
+
+        remote_->OnRoutineStateChange(std::move(state));
+      }));
+
+  CreateExtensionAndRunServiceWorker(
+      base::StringPrintf(R"(
+    chrome.test.runTests([
+      async function canObserveOnRoutineRunningWithNetworkBandwidthInfo() {
+        chrome.os.diagnostics.onRoutineRunning.addListener((event) => {
+          chrome.test.assertEq(event, {
+            info: {
+              "networkBandwidth": {
+                "speedKbps": 100.0,
+                "type": "download",
+              }
+            },
+            percentage: 50,
+            uuid:"%s",
+          });
+
+          chrome.test.succeed();
+        });
+      }
+    ]);
+  )",
+                         uuid_.AsLowercaseString().c_str()));
+}
+
+IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticRoutineObserverBrowserTest,
                        CanObserveOnRoutineWaiting) {
   SetRoutineObservation();
   RegisterEventObserver(
@@ -609,4 +661,59 @@
   EXPECT_EQ(info.uuid, uuid_);
 }
 
+IN_PROC_BROWSER_TEST_F(TelemetryExtensionDiagnosticRoutineObserverBrowserTest,
+                       CanObserveOnRoutineFinishedWithNetworkBandwidthDetail) {
+  SetRoutineObservation();
+  RegisterEventObserver(
+      api::os_diagnostics::OnRoutineFinished::kEventName,
+      base::BindLambdaForTesting([this] {
+        auto network_bandwidth_detail =
+            crosapi::TelemetryDiagnosticNetworkBandwidthRoutineDetail::New();
+        network_bandwidth_detail->download_speed_kbps = 123.0;
+        network_bandwidth_detail->upload_speed_kbps = 456.0;
+
+        auto finished_state =
+            crosapi::TelemetryDiagnosticRoutineStateFinished::New();
+        finished_state->detail =
+            crosapi::TelemetryDiagnosticRoutineDetail::NewNetworkBandwidth(
+                std::move(network_bandwidth_detail));
+        finished_state->has_passed = true;
+
+        auto state = crosapi::TelemetryDiagnosticRoutineState::New();
+        state->state_union =
+            crosapi::TelemetryDiagnosticRoutineStateUnion::NewFinished(
+                std::move(finished_state));
+        state->percentage = 100;
+
+        remote_->OnRoutineStateChange(std::move(state));
+      }));
+
+  CreateExtensionAndRunServiceWorker(
+      base::StringPrintf(R"(
+    chrome.test.runTests([
+      async function canObserveOnRoutineFinishedWithNetworkBandwidthDetail() {
+        chrome.os.diagnostics.onRoutineFinished.addListener((event) => {
+          chrome.test.assertEq(event, {
+            "detail": {
+              "networkBandwidth": {
+                "downloadSpeedKbps": 123.0,
+                "uploadSpeedKbps": 456.0
+              }
+            },
+            "hasPassed": true,
+            "uuid":"%s"
+          });
+
+          chrome.test.succeed();
+        });
+      }
+    ]);
+  )",
+                         uuid_.AsLowercaseString().c_str()));
+
+  auto info = WaitForFinishedReport();
+  EXPECT_EQ(info.extension_id, extension_id());
+  EXPECT_EQ(info.uuid, uuid_);
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/mahi/mahi_web_contents_manager.cc b/chrome/browser/chromeos/mahi/mahi_web_contents_manager.cc
index 3cb43e7..2a56e7f 100644
--- a/chrome/browser/chromeos/mahi/mahi_web_contents_manager.cc
+++ b/chrome/browser/chromeos/mahi/mahi_web_contents_manager.cc
@@ -14,6 +14,7 @@
 #include "base/functional/bind.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/no_destructor.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/unguessable_token.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/chromeos/mahi/mahi_browser_client_impl.h"
@@ -66,23 +67,31 @@
 
 void MahiWebContentsManager::OnFocusedPageLoadComplete(
     content::WebContents* web_contents) {
-  // Creates a new focused web content state, and fires `OnFocusedPageChanged()`
-  // event immediately so that `MahiManager` knows the focused page has changed.
-  focused_web_content_state_ = WebContentState(
-      web_contents->GetLastCommittedURL(), web_contents->GetTitle());
-  focused_web_content_state_.favicon = GetFavicon(web_contents);
+  // Page info may not be properly updated yet if the user forwards/backwards
+  // the tab through cache. Thus, if focused page's URL does not change, we
+  // don't create a new `focused_web_content_state_` here, and instead rely on
+  // the callback of `RequestAXTreeSnapshot` to update if needed.
+  if (web_contents->GetLastCommittedURL() != focused_web_content_state_.url) {
+    // Creates a new focused web content state, and fires
+    // `OnFocusedPageChanged()`
+    // event immediately so that `MahiManager` knows the focused page has
+    // changed.
+    focused_web_content_state_ = WebContentState(
+        web_contents->GetLastCommittedURL(), web_contents->GetTitle());
+    focused_web_content_state_.favicon = GetFavicon(web_contents);
 
-  // If the page is in the skip list, sets its distillability to false and
-  // notifies `MahiManager` immediately without requesting the snapshot.
-  if (ShouldSkip(web_contents)) {
-    focused_web_content_state_.is_distillable.emplace(false);
+    // If the page is in the skip list, sets its distillability to false and
+    // notifies `MahiManager` immediately without requesting the snapshot.
+    if (ShouldSkip(web_contents)) {
+      focused_web_content_state_.is_distillable.emplace(false);
+      client_->OnFocusedPageChanged(focused_web_content_state_);
+      return;
+    }
+
+    // Notifies `MahiManger` the focused page has changed.
     client_->OnFocusedPageChanged(focused_web_content_state_);
-    return;
   }
 
-  // Notifies `MahiManger` the focused page has changed.
-  client_->OnFocusedPageChanged(focused_web_content_state_);
-
   // Requests the a11y tree snapshot.
   content::RenderFrameHost* render_frame_host =
       web_contents->GetPrimaryMainFrame();
@@ -93,7 +102,7 @@
   web_contents->RequestAXTreeSnapshot(
       base::BindOnce(&MahiWebContentsManager::OnGetSnapshot,
                      weak_pointer_factory_.GetWeakPtr(),
-                     focused_web_content_state_.page_id),
+                     focused_web_content_state_.page_id, web_contents),
       ui::kAXModeWebContentsOnly,
       /* max_nodes= */ 5000, /* timeout= */ {});
 }
@@ -154,9 +163,24 @@
 
 void MahiWebContentsManager::OnGetSnapshot(
     const base::UnguessableToken& page_id,
+    content::WebContents* web_contents,
     const ui::AXTreeUpdate& snapshot) {
   // Updates states and checks the distillability of the snapshot.
   if (page_id == focused_web_content_state_.page_id) {
+    // If the acquired url does not match the one within the snapshot, updates
+    // `focused_web_content_state_` to ensure they match.
+    if (focused_web_content_state_.url != GURL(snapshot.tree_data.url)) {
+      focused_web_content_state_ =
+          WebContentState(GURL(snapshot.tree_data.url),
+                          base::UTF8ToUTF16(snapshot.tree_data.title));
+      // Attempts to update the favicon if the url of the focused web contents
+      // have updated.
+      if (web_contents && web_contents->GetLastCommittedURL() ==
+                              focused_web_content_state_.url) {
+        focused_web_content_state_.favicon = GetFavicon(web_contents);
+      }
+    }
+
     focused_web_content_state_.snapshot = snapshot;
     content_extraction_delegate_->CheckDistillablity(
         focused_web_content_state_);
diff --git a/chrome/browser/chromeos/mahi/mahi_web_contents_manager.h b/chrome/browser/chromeos/mahi/mahi_web_contents_manager.h
index 6a82ce12..aaf7e0a 100644
--- a/chrome/browser/chromeos/mahi/mahi_web_contents_manager.h
+++ b/chrome/browser/chromeos/mahi/mahi_web_contents_manager.h
@@ -85,6 +85,7 @@
   virtual ~MahiWebContentsManager();
 
   void OnGetSnapshot(const base::UnguessableToken& page_id,
+                     content::WebContents* web_contents,
                      const ui::AXTreeUpdate& snapshot);
 
   void OnFinishDistillableCheck(const base::UnguessableToken& page_id,
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_util.cc b/chrome/browser/extensions/api/autofill_private/autofill_util.cc
index 23af950..00a3673 100644
--- a/chrome/browser/extensions/api/autofill_private/autofill_util.cc
+++ b/chrome/browser/extensions/api/autofill_private/autofill_util.cc
@@ -260,12 +260,12 @@
   api::autofill_private::AccountInfo api_account;
   api_account.email = account->email;
   api_account.is_sync_enabled_for_autofill_profiles =
-      personal_data.IsSyncFeatureEnabledForAutofill();
+      personal_data.address_data_manager().IsSyncFeatureEnabledForAutofill();
   api_account.is_eligible_for_address_account_storage =
       personal_data.address_data_manager().IsEligibleForAddressAccountStorage();
   api_account.is_autofill_sync_toggle_enabled =
-      personal_data.IsUserSelectableTypeEnabled(
-          syncer::UserSelectableType::kAutofill);
+      personal_data.address_data_manager()
+          .IsAutofillUserSelectableTypeEnabled();
   api_account.is_autofill_sync_toggle_available =
       personal_data.IsAutofillSyncToggleAvailable();
   return std::move(api_account);
diff --git a/chrome/browser/lacros/browser_service_lacros.cc b/chrome/browser/lacros/browser_service_lacros.cc
index f5291be..778bc28 100644
--- a/chrome/browser/lacros/browser_service_lacros.cc
+++ b/chrome/browser/lacros/browser_service_lacros.cc
@@ -195,7 +195,7 @@
   BrowserList::RemoveObserver(this);
 }
 
-void BrowserServiceLacros::REMOVED_0(REMOVED_0Callback callback) {
+void BrowserServiceLacros::REMOVED_0() {
   NOTIMPLEMENTED();
 }
 
diff --git a/chrome/browser/lacros/browser_service_lacros.h b/chrome/browser/lacros/browser_service_lacros.h
index bb3e7b8..6d3afb3 100644
--- a/chrome/browser/lacros/browser_service_lacros.h
+++ b/chrome/browser/lacros/browser_service_lacros.h
@@ -31,7 +31,7 @@
   ~BrowserServiceLacros() override;
 
   // crosapi::mojom::BrowserService:
-  void REMOVED_0(REMOVED_0Callback callback) override;
+  void REMOVED_0() override;
   void REMOVED_2(crosapi::mojom::BrowserInitParamsPtr) override;
   void REMOVED_7(bool should_trigger_session_restore,
                  base::OnceClosure callback) override;
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.cc b/chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.cc
index 9116b96..60ec289 100644
--- a/chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.cc
+++ b/chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.h"
 
+#include <string_view>
 #include <utility>
 
 #include "base/base64url.h"
@@ -12,7 +13,6 @@
 #include "base/json/values_util.h"
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
 #include "chrome/browser/nearby_sharing/certificates/common.h"
 #include "chrome/browser/nearby_sharing/certificates/constants.h"
 #include "chrome/browser/nearby_sharing/common/nearby_share_switches.h"
@@ -122,7 +122,7 @@
   std::set<std::vector<uint8_t>> salts;
   for (size_t i = 0; i < str.size(); i += chars_per_salt) {
     std::vector<uint8_t> salt;
-    base::HexStringToBytes(base::StringPiece(&str[i], chars_per_salt), &salt);
+    base::HexStringToBytes(std::string_view(&str[i], chars_per_salt), &salt);
     salts.insert(std::move(salt));
   }
   return salts;
diff --git a/chrome/browser/nearby_sharing/instantmessaging/receive_messages_express.cc b/chrome/browser/nearby_sharing/instantmessaging/receive_messages_express.cc
index eb85cc53..d4d51d0 100644
--- a/chrome/browser/nearby_sharing/instantmessaging/receive_messages_express.cc
+++ b/chrome/browser/nearby_sharing/instantmessaging/receive_messages_express.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/nearby_sharing/instantmessaging/receive_messages_express.h"
 
 #include <sstream>
+#include <string_view>
 
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
@@ -260,7 +261,7 @@
   }
 }
 
-void ReceiveMessagesExpress::OnDataReceived(base::StringPiece data,
+void ReceiveMessagesExpress::OnDataReceived(std::string_view data,
                                             base::OnceClosure resume) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
diff --git a/chrome/browser/nearby_sharing/instantmessaging/receive_messages_express.h b/chrome/browser/nearby_sharing/instantmessaging/receive_messages_express.h
index 46aa76a..548ba79c 100644
--- a/chrome/browser/nearby_sharing/instantmessaging/receive_messages_express.h
+++ b/chrome/browser/nearby_sharing/instantmessaging/receive_messages_express.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_NEARBY_SHARING_INSTANTMESSAGING_RECEIVE_MESSAGES_EXPRESS_H_
 
 #include <cstdint>
+#include <string_view>
 
 #include "base/functional/callback_forward.h"
 #include "base/memory/scoped_refptr.h"
@@ -79,7 +80,7 @@
   void OnFastPathReadyTimeout();
 
   // network::SimpleURLLoaderStreamConsumer:
-  void OnDataReceived(base::StringPiece string_piece,
+  void OnDataReceived(std::string_view string_piece,
                       base::OnceClosure resume) override;
   void OnComplete(bool success) override;
   void OnRetry(base::OnceClosure start_retry) override;
diff --git a/chrome/browser/nearby_sharing/instantmessaging/stream_parser.cc b/chrome/browser/nearby_sharing/instantmessaging/stream_parser.cc
index e1ec7d70..b42af2ef 100644
--- a/chrome/browser/nearby_sharing/instantmessaging/stream_parser.cc
+++ b/chrome/browser/nearby_sharing/instantmessaging/stream_parser.cc
@@ -4,8 +4,9 @@
 
 #include "chrome/browser/nearby_sharing/instantmessaging/stream_parser.h"
 
+#include <string_view>
+
 #include "base/logging.h"
-#include "base/strings/string_piece.h"
 #include "net/base/io_buffer.h"
 #include "third_party/protobuf/src/google/protobuf/io/coded_stream.h"
 #include "third_party/protobuf/src/google/protobuf/wire_format_lite.h"
@@ -34,7 +35,7 @@
 
 std::vector<
     chrome_browser_nearby_sharing_instantmessaging::ReceiveMessagesResponse>
-StreamParser::Append(base::StringPiece data) {
+StreamParser::Append(std::string_view data) {
   if (!unparsed_data_buffer_) {
     unparsed_data_buffer_ = base::MakeRefCounted<net::GrowableIOBuffer>();
     unparsed_data_buffer_->SetCapacity(data.size() + kReadBufferSpareCapacity);
diff --git a/chrome/browser/nearby_sharing/instantmessaging/stream_parser.h b/chrome/browser/nearby_sharing/instantmessaging/stream_parser.h
index 65baff67..b0327339 100644
--- a/chrome/browser/nearby_sharing/instantmessaging/stream_parser.h
+++ b/chrome/browser/nearby_sharing/instantmessaging/stream_parser.h
@@ -6,9 +6,9 @@
 #define CHROME_BROWSER_NEARBY_SHARING_INSTANTMESSAGING_STREAM_PARSER_H_
 
 #include <string>
+#include <string_view>
 
 #include "base/functional/callback.h"
-#include "base/strings/string_piece.h"
 #include "chrome/browser/nearby_sharing/instantmessaging/proto/instantmessaging.pb.h"
 
 namespace google {
@@ -39,7 +39,7 @@
   // empty vector is returned.
   std::vector<
       chrome_browser_nearby_sharing_instantmessaging::ReceiveMessagesResponse>
-  Append(base::StringPiece data);
+  Append(std::string_view data);
 
  private:
   enum class StreamParsingResult {
diff --git a/chrome/browser/nearby_sharing/instantmessaging/stream_parser_unittest.cc b/chrome/browser/nearby_sharing/instantmessaging/stream_parser_unittest.cc
index 8a6f1d4..851eeee4 100644
--- a/chrome/browser/nearby_sharing/instantmessaging/stream_parser_unittest.cc
+++ b/chrome/browser/nearby_sharing/instantmessaging/stream_parser_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include "base/functional/bind.h"
@@ -164,7 +165,7 @@
   EXPECT_EQ(0u, responses.size());
 
   char bytes[2] = {0x0f, 0x00};
-  auto bytes_string = base::StringPiece(bytes);
+  auto bytes_string = std::string_view(bytes);
   EXPECT_EQ(1u, bytes_string.length());
   responses = GetStreamParser().Append(bytes);
   EXPECT_EQ(0u, responses.size());
diff --git a/chrome/browser/password_manager/android/save_update_password_message_delegate.cc b/chrome/browser/password_manager/android/save_update_password_message_delegate.cc
index 1f40ac6..459991c0f 100644
--- a/chrome/browser/password_manager/android/save_update_password_message_delegate.cc
+++ b/chrome/browser/password_manager/android/save_update_password_message_delegate.cc
@@ -46,6 +46,9 @@
 // Duration of message before timeout; 20 seconds.
 const int kMessageDismissDurationMs = 20000;
 
+constexpr base::TimeDelta kUpdateGMSCoreMessageDisplayDelay =
+    base::Milliseconds(500);
+
 // Log the outcome of the save/update password workflow.
 // It differentiates whether the the flow was accepted/cancelled immediately
 // or after calling the password edit dialog.
@@ -106,17 +109,6 @@
   }
 }
 
-void MaybeNudgeToUpdateGmsCore(ManagePasswordsState& passwords_state) {
-  if (passwords_state.client()
-          ->GetPasswordFeatureManager()
-          ->ShouldUpdateGmsCore()) {
-    passwords_state.client()->ShowPasswordManagerErrorMessage(
-        password_manager::ErrorMessageFlowType::kSaveFlow,
-        password_manager::PasswordStoreBackendErrorType::
-            kGMSCoreOutdatedSavingPossible);
-  }
-}
-
 }  // namespace
 
 SaveUpdatePasswordMessageDelegate::SaveUpdatePasswordMessageDelegate()
@@ -378,7 +370,12 @@
 void SaveUpdatePasswordMessageDelegate::SavePassword() {
   if (!device_lock_bridge_->ShouldShowDeviceLockUi()) {
     passwords_state_.form_manager()->Save();
-    MaybeNudgeToUpdateGmsCore(passwords_state_);
+    base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
+        FROM_HERE,
+        base::BindOnce(
+            &SaveUpdatePasswordMessageDelegate::MaybeNudgeToUpdateGmsCore,
+            weak_ptr_factory_.GetWeakPtr()),
+        kUpdateGMSCoreMessageDisplayDelay);
     return;
   }
   device_lock_bridge_->LaunchDeviceLockUiIfNeededBeforeRunningCallback(
@@ -393,7 +390,12 @@
   CHECK(device_lock_bridge_->RequiresDeviceLock());
   if (is_device_lock_requirement_met) {
     passwords_state_.form_manager()->Save();
-    MaybeNudgeToUpdateGmsCore(passwords_state_);
+    base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
+        FROM_HERE,
+        base::BindOnce(
+            &SaveUpdatePasswordMessageDelegate::MaybeNudgeToUpdateGmsCore,
+            weak_ptr_factory_.GetWeakPtr()),
+        kUpdateGMSCoreMessageDisplayDelay);
     TryToShowPasswordMigrationWarning(create_migration_warning_callback_,
                                       web_contents_);
   }
@@ -646,3 +648,14 @@
   }
   return ui_dismissal_reason;
 }
+
+void SaveUpdatePasswordMessageDelegate::MaybeNudgeToUpdateGmsCore() {
+  if (passwords_state_.client()
+          ->GetPasswordFeatureManager()
+          ->ShouldUpdateGmsCore()) {
+    passwords_state_.client()->ShowPasswordManagerErrorMessage(
+        password_manager::ErrorMessageFlowType::kSaveFlow,
+        password_manager::PasswordStoreBackendErrorType::
+            kGMSCoreOutdatedSavingPossible);
+  }
+}
diff --git a/chrome/browser/password_manager/android/save_update_password_message_delegate.h b/chrome/browser/password_manager/android/save_update_password_message_delegate.h
index 7eb9534..bbf2ca8 100644
--- a/chrome/browser/password_manager/android/save_update_password_message_delegate.h
+++ b/chrome/browser/password_manager/android/save_update_password_message_delegate.h
@@ -173,6 +173,8 @@
   MessageDismissReasonToPasswordManagerUIDismissalReason(
       messages::DismissReason dismiss_reason);
 
+  void MaybeNudgeToUpdateGmsCore();
+
   PasswordEditDialogFactory password_edit_dialog_factory_;
 
   raw_ptr<content::WebContents> web_contents_ = nullptr;
diff --git a/chrome/browser/password_manager/android/save_update_password_message_delegate_unittest.cc b/chrome/browser/password_manager/android/save_update_password_message_delegate_unittest.cc
index 9732aee..936316dc 100644
--- a/chrome/browser/password_manager/android/save_update_password_message_delegate_unittest.cc
+++ b/chrome/browser/password_manager/android/save_update_password_message_delegate_unittest.cc
@@ -233,6 +233,8 @@
     return delegate_.get();
   }
 
+  void FastForward() { task_environment()->FastForwardBy(base::Seconds(1)); }
+
  private:
   PasswordForm pending_credentials_;
   GURL password_form_url_;
@@ -251,8 +253,9 @@
   MockPasswordManagerClient password_manager_client_;
 };
 
-SaveUpdatePasswordMessageDelegateTest::SaveUpdatePasswordMessageDelegateTest() =
-    default;
+SaveUpdatePasswordMessageDelegateTest::SaveUpdatePasswordMessageDelegateTest()
+    : ChromeRenderViewHostTestHarness(
+          base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
 
 void SaveUpdatePasswordMessageDelegateTest::SetUp() {
   ChromeRenderViewHostTestHarness::SetUp();
@@ -643,6 +646,9 @@
   EXPECT_CALL(*(GetClient()->GetPasswordFeatureManager()), ShouldUpdateGmsCore)
       .WillOnce(Return(true));
   TriggerActionClick();
+
+  // Fast forward, since Update message is shown with a delay.
+  FastForward();
   EXPECT_EQ(nullptr, GetMessageWrapper());
 }
 
@@ -668,6 +674,9 @@
   EXPECT_CALL(*(GetClient()->GetPasswordFeatureManager()), ShouldUpdateGmsCore)
       .WillOnce(Return(false));
   TriggerActionClick();
+
+  // Fast forward, since Update message is shown with a delay.
+  FastForward();
   EXPECT_EQ(nullptr, GetMessageWrapper());
 }
 
@@ -765,6 +774,9 @@
   EXPECT_CALL(*(GetClient()->GetPasswordFeatureManager()), ShouldUpdateGmsCore)
       .WillOnce(Return(true));
   TriggerActionClick();
+
+  // Fast forward, since Update message is shown with a delay.
+  FastForward();
   EXPECT_EQ(nullptr, GetMessageWrapper());
 }
 
@@ -795,6 +807,9 @@
   EXPECT_CALL(*(GetClient()->GetPasswordFeatureManager()), ShouldUpdateGmsCore)
       .WillOnce(Return(false));
   TriggerActionClick();
+
+  // Fast forward, since Update message is shown with a delay.
+  FastForward();
   EXPECT_EQ(nullptr, GetMessageWrapper());
 }
 
@@ -879,6 +894,8 @@
                                 /*password=*/kPassword);
   EXPECT_CALL(GetMigrationWarningCallback(), Run);
   TriggerDialogDismissedCallback(/*dialog_accepted=*/true);
+  // Fast forward, since Update message is shown with a delay.
+  FastForward();
 }
 
 // Tests that the message to update GMSCore will not show when the user accepts
@@ -914,6 +931,8 @@
                                 /*password=*/kPassword);
   EXPECT_CALL(GetMigrationWarningCallback(), Run);
   TriggerDialogDismissedCallback(/*dialog_accepted=*/true);
+  // Fast forward, since Update message is shown with a delay.
+  FastForward();
 }
 
 // Tests that the local password migration warning will show when the user
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index cbe9540..d196944 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -41,6 +41,7 @@
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/sync/sync_service_factory.h"
 #include "chrome/browser/translate/chrome_translate_client.h"
+#include "chrome/browser/ui/passwords/password_cross_domain_confirmation_popup_controller_impl.h"
 #include "chrome/browser/ui/passwords/password_generation_popup_controller_impl.h"
 #include "chrome/browser/ui/passwords/passwords_client_ui_delegate.h"
 #include "chrome/browser/ui/passwords/passwords_model_delegate.h"
@@ -1084,6 +1085,32 @@
 #endif
 }
 
+#if !BUILDFLAG(IS_ANDROID)
+std::unique_ptr<
+    password_manager::PasswordCrossDomainConfirmationPopupController>
+ChromePasswordManagerClient::ShowCrossDomainConfirmationPopup(
+    const gfx::RectF& element_bounds,
+    base::i18n::TextDirection text_direction,
+    const GURL& domain,
+    const std::u16string& password_origin,
+    base::OnceClosure confirmation_callback) {
+  gfx::Rect client_area = web_contents()->GetContainerBounds();
+  gfx::RectF element_bounds_in_screen_space =
+      element_bounds + client_area.OffsetFromOrigin();
+  auto controller =
+      cross_domain_confirmation_popup_factory_for_testing_
+          ? cross_domain_confirmation_popup_factory_for_testing_.Run()
+          : std::make_unique<
+                PasswordCrossDomainConfirmationPopupControllerImpl>(
+                web_contents());
+
+  controller->Show(element_bounds_in_screen_space, text_direction, domain,
+                   password_origin, std::move(confirmation_callback));
+
+  return controller;
+}
+#endif  // !BUILDFLAG(IS_ANDROID)
+
 void ChromePasswordManagerClient::AutomaticGenerationAvailable(
     const autofill::password_generation::PasswordGenerationUIData& ui_data) {
   content::RenderFrameHost* rfh =
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h
index d3cba9fa..26181013 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.h
+++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -11,6 +11,7 @@
 #include <string>
 #include <vector>
 
+#include "base/functional/callback_forward.h"
 #include "base/memory/raw_ptr.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
@@ -23,6 +24,7 @@
 #include "components/password_manager/core/browser/http_auth_manager.h"
 #include "components/password_manager/core/browser/http_auth_manager_impl.h"
 #include "components/password_manager/core/browser/manage_passwords_referrer.h"
+#include "components/password_manager/core/browser/password_cross_domain_confirmation_popup_controller.h"
 #include "components/password_manager/core/browser/password_feature_manager_impl.h"
 #include "components/password_manager/core/browser/password_form_manager_for_ui.h"
 #include "components/password_manager/core/browser/password_manager.h"
@@ -284,6 +286,16 @@
 #endif  // BUILDFLAG(IS_ANDROID)
   version_info::Channel GetChannel() const override;
   void RefreshPasswordManagerSettingsIfNeeded() const override;
+#if !BUILDFLAG(IS_ANDROID)
+  std::unique_ptr<
+      password_manager::PasswordCrossDomainConfirmationPopupController>
+  ShowCrossDomainConfirmationPopup(
+      const gfx::RectF& element_bounds,
+      base::i18n::TextDirection text_direction,
+      const GURL& domain,
+      const std::u16string& password_origin,
+      base::OnceClosure confirmation_callback) override;
+#endif  // !BUILDFLAG(IS_ANDROID)
 
   // autofill::mojom::PasswordGenerationDriver overrides.
   void AutomaticGenerationAvailable(
@@ -327,6 +339,15 @@
   }
 #endif
 
+#if !BUILDFLAG(IS_ANDROID)
+  void set_cross_domain_confirmation_popup_factory_for_testing(
+      base::RepeatingCallback<std::unique_ptr<
+          password_manager::PasswordCrossDomainConfirmationPopupController>()>
+          factory) {
+    cross_domain_confirmation_popup_factory_for_testing_ = std::move(factory);
+  }
+#endif  // !BUILDFLAG(IS_ANDROID)
+
 #if BUILDFLAG(IS_ANDROID)
   PasswordAccessoryController* GetOrCreatePasswordAccessory();
 
@@ -496,6 +517,14 @@
   autofill::ScopedAutofillManagersObservation autofill_managers_observation_{
       this};
 
+#if !BUILDFLAG(IS_ANDROID)
+  // The cross domain confirmation popup view factory, used for testing to mock
+  // some views specific initializations.
+  base::RepeatingCallback<std::unique_ptr<
+      password_manager::PasswordCrossDomainConfirmationPopupController>()>
+      cross_domain_confirmation_popup_factory_for_testing_;
+#endif  // !BUILDFLAG(IS_ANDROID)
+
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 };
 
diff --git a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
index 48f08782..02306ca 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
@@ -14,11 +14,13 @@
 #include "base/command_line.h"
 #include "base/containers/span.h"
 #include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
 #include "base/ranges/algorithm.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/mock_callback.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/task_environment.h"
 #include "build/build_config.h"
@@ -31,6 +33,7 @@
 #include "chrome/browser/safe_browsing/user_interaction_observer.h"
 #include "chrome/browser/sync/sync_service_factory.h"
 #include "chrome/browser/ui/autofill/chrome_autofill_client.h"
+#include "chrome/browser/ui/passwords/password_cross_domain_confirmation_popup_controller_impl.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/scoped_testing_local_state.h"
 #include "chrome/test/base/testing_browser_process.h"
@@ -1624,3 +1627,52 @@
 }
 
 #endif  //  BUILDFLAG(IS_ANDROID)
+
+#if !BUILDFLAG(IS_ANDROID)
+
+class MockPasswordCrossDomainConfirmationPopupController
+    : public password_manager::PasswordCrossDomainConfirmationPopupController {
+ public:
+  MOCK_METHOD(void, Hide, (autofill::PopupHidingReason), (override));
+  MOCK_METHOD(void,
+              Show,
+              (const gfx::RectF&,
+               base::i18n::TextDirection,
+               const GURL&,
+               const std::u16string&,
+               base::OnceClosure),
+              (override));
+};
+
+TEST_F(ChromePasswordManagerClientTest, ShowCrossDomainConfirmationPopup) {
+// This simple method of the web contents repositioning doesn't work on Mac.
+// The screen coordinates calculation testing is skipped on this platform, but
+// the logic is completely platform independent and is being tested on others.
+#if !BUILDFLAG(IS_MAC)
+  web_contents()->GetNativeView()->SetBounds(gfx::Rect(100, 100, 1000, 1000));
+#endif  // !BUILDFLAG(IS_MAC)
+
+  base::MockRepeatingCallback<std::unique_ptr<
+      password_manager::PasswordCrossDomainConfirmationPopupController>()>
+      popup_factory;
+  EXPECT_CALL(popup_factory, Run).WillOnce([&]() {
+    auto mock_controller =
+        std::make_unique<MockPasswordCrossDomainConfirmationPopupController>();
+    EXPECT_CALL(
+        *mock_controller,
+        Show(gfx::RectF(
+                 gfx::PointF(web_contents()->GetContainerBounds().origin()),
+                 gfx::SizeF(100, 100)),
+             base::i18n::TextDirection::LEFT_TO_RIGHT,
+             GURL("https://google.com"), std::u16string(u"google.de"), _));
+    return mock_controller;
+  });
+  GetClient()->set_cross_domain_confirmation_popup_factory_for_testing(
+      popup_factory.Get());
+
+  GetClient()->ShowCrossDomainConfirmationPopup(
+      gfx::RectF(100, 100), base::i18n::TextDirection::LEFT_TO_RIGHT,
+      GURL("https://google.com"), u"google.de", base::DoNothing());
+}
+
+#endif  //  !BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service.cc b/chrome/browser/policy/cloud/user_policy_signin_service.cc
index 324e2db..e43f8f6 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service.cc
@@ -167,6 +167,7 @@
   if (identity_manager())
     identity_manager()->RemoveObserver(this);
   UserPolicySigninServiceBase::Shutdown();
+  profile_ = nullptr;
 }
 
 void UserPolicySigninService::ShutdownCloudPolicyManager() {
diff --git a/chrome/browser/predictors/lcp_critical_path_predictor/prewarm_http_disk_cache_manager.cc b/chrome/browser/predictors/lcp_critical_path_predictor/prewarm_http_disk_cache_manager.cc
index 1580aed..3930eea 100644
--- a/chrome/browser/predictors/lcp_critical_path_predictor/prewarm_http_disk_cache_manager.cc
+++ b/chrome/browser/predictors/lcp_critical_path_predictor/prewarm_http_disk_cache_manager.cc
@@ -9,6 +9,7 @@
 #include "base/task/sequenced_task_runner.h"
 #include "base/trace_event/base_tracing.h"
 #include "base/trace_event/common/trace_event_common.h"
+#include "chrome/browser/after_startup_task_utils.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/base/load_flags.h"
 #include "services/network/public/cpp/resource_request.h"
@@ -84,6 +85,11 @@
       TRACE_ID_LOCAL(this),
       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
 
+  // Avoid making network service to be more busy during the browser startup.
+  if (!AfterStartupTaskUtils::IsBrowserStartupComplete()) {
+    return;
+  }
+
   url::Origin top_frame_origin =
       url::Origin::Create(top_frame_main_resource_url);
   MaybeAddPrewarmJob(top_frame_origin, top_frame_main_resource_url);
diff --git a/chrome/browser/resources/ash/settings/os_languages_page/input_page.html b/chrome/browser/resources/ash/settings/os_languages_page/input_page.html
index dd5ff02d..a44f7b6f 100644
--- a/chrome/browser/resources/ash/settings/os_languages_page/input_page.html
+++ b/chrome/browser/resources/ash/settings/os_languages_page/input_page.html
@@ -129,15 +129,13 @@
   }
 </style>
 
-<template is="dom-if" if="[[shouldShowLanguagePacksNotice_]]">
-  <div class="settings-box first">
-    <localized-link id="languagePacksNotice"
-        class="cr-secondary-text"
-        localized-string="$i18n{languagePacksNotice}"
-        on-link-clicked="onLanguagePackNoticeLinkClick_">
-    </localized-link>
-  </div>
-</template>
+<div class="settings-box first">
+  <localized-link id="languagePacksNotice"
+      class="cr-secondary-text"
+      localized-string="$i18n{languagePacksNotice}"
+      on-link-clicked="onLanguagePackNoticeLinkClick_">
+  </localized-link>
+</div>
 <settings-toggle-button
     class="first" id="showImeMenu"
     pref="{{prefs.settings.language.ime_menu_activated}}"
diff --git a/chrome/browser/resources/ash/settings/os_languages_page/input_page.ts b/chrome/browser/resources/ash/settings/os_languages_page/input_page.ts
index 1846489..e4cf567 100644
--- a/chrome/browser/resources/ash/settings/os_languages_page/input_page.ts
+++ b/chrome/browser/resources/ash/settings/os_languages_page/input_page.ts
@@ -97,13 +97,6 @@
         },
       },
 
-      shouldShowLanguagePacksNotice_: {
-        type: Boolean,
-        value() {
-          return loadTimeData.getBoolean('languagePacksHandwritingEnabled');
-        },
-      },
-
       /**
        * Whether the shortcut reminder for the last used IME is currently
        * showing.
@@ -180,7 +173,6 @@
   // loadTimeData flags.
   private onDeviceGrammarCheckEnabled_: boolean;
   private languageSettingsJapaneseEnabled_: boolean;
-  private shouldShowLanguagePacksNotice_: boolean;
   private languagePacksInSettingsEnabled_ =
       loadTimeData.getBoolean('languagePacksInSettingsEnabled');
   private readonly allowEmojiSuggestion_: boolean =
diff --git a/chrome/browser/resources/chromeos/app_install/app_install_dialog.html b/chrome/browser/resources/chromeos/app_install/app_install_dialog.html
index 521286c..7954467a 100644
--- a/chrome/browser/resources/chromeos/app_install/app_install_dialog.html
+++ b/chrome/browser/resources/chromeos/app_install/app_install_dialog.html
@@ -113,7 +113,7 @@
   <h1 id="title">$i18n{installAppToDevice}</h1>
   <div id="content-card" style="display: none">
     <div id="essential-details">
-      <img id="app-icon" is="cr-auto-img" width="32" height="32" alt="">
+      <img id="app-icon" is="cr-auto-img" width="32" height="32">
       <div id="name-and-url">
         <p id="name"></p>
         <p id="url">$i18n{appDetails}
diff --git a/chrome/browser/resources/chromeos/app_install/app_install_dialog.ts b/chrome/browser/resources/chromeos/app_install/app_install_dialog.ts
index c0bd4321..e13e17f 100644
--- a/chrome/browser/resources/chromeos/app_install/app_install_dialog.ts
+++ b/chrome/browser/resources/chromeos/app_install/app_install_dialog.ts
@@ -197,6 +197,10 @@
       const iconElement = this.$<HTMLImageElement>('#app-icon');
       assert(iconElement);
       iconElement.setAttribute('auto-src', dialogArgs.args.iconUrl.url);
+      iconElement.setAttribute(
+          'alt',
+          loadTimeData.substituteString(
+              loadTimeData.getString('iconAlt'), dialogArgs.args.name));
 
       if (dialogArgs.args.description) {
         this.$<HTMLDivElement>('#description').textContent =
diff --git a/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl.cc b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl.cc
index 3a616db..b0061560 100644
--- a/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl.cc
+++ b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl.cc
@@ -150,7 +150,7 @@
       switches::kEnableBoundSessionCredentialsExclusiveRegistrationPath.Get();
   if (!exclusive_registration_path.empty() &&
       !base::EqualsCaseInsensitiveASCII(
-          registration_params.RegistrationEndpoint().path_piece(),
+          registration_params.registration_endpoint().path_piece(),
           exclusive_registration_path)) {
     return;
   }
diff --git a/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl_unittest.cc b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl_unittest.cc
index 0213b7c..3e00150 100644
--- a/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl_unittest.cc
+++ b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_refresh_service_impl_unittest.cc
@@ -821,7 +821,7 @@
       CreateTestRegistrationFetcherParams(kSecondPath));
   ASSERT_TRUE(registration_fetcher());
   EXPECT_EQ(
-      registration_fetcher()->params().RegistrationEndpoint().path_piece(),
+      registration_fetcher()->params().registration_endpoint().path_piece(),
       kFirstPath);
 
   // Verify that a request can complete normally.
diff --git a/chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_impl.cc b/chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_impl.cc
index 432b594..6bffccb 100644
--- a/chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_impl.cc
+++ b/chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_impl.cc
@@ -66,7 +66,7 @@
     RegistrationCompleteCallback callback) {
   TRACE_EVENT("browser", "BoundSessionRegistrationFetcherImpl::Start",
               perfetto::Flow::FromPointer(this), "endpoint",
-              registration_params_.RegistrationEndpoint());
+              registration_params_.registration_endpoint());
   CHECK(!registration_duration_.has_value());
   CHECK(!callback_);
   CHECK(!registration_token_helper_);
@@ -75,8 +75,8 @@
   // base::Unretained() is safe since `this` owns
   // `registration_token_helper_`.
   registration_token_helper_ = RegistrationTokenHelper::CreateForSessionBinding(
-      key_service_.get(), registration_params_.Challenge(),
-      registration_params_.RegistrationEndpoint(),
+      key_service_.get(), registration_params_.challenge(),
+      registration_params_.registration_endpoint(),
       base::BindOnce(
           &BoundSessionRegistrationFetcherImpl::OnRegistrationTokenCreated,
           base::Unretained(this), base::ElapsedTimer()));
@@ -130,7 +130,7 @@
   bound_session_credentials::BoundSessionParams params =
       std::move(params_or_error).value();
   params.set_site(
-      net::SchemefulSite(registration_params_.RegistrationEndpoint())
+      net::SchemefulSite(registration_params_.registration_endpoint())
           .Serialize());
   params.set_wrapped_key(wrapped_key_str_);
   *params.mutable_creation_time() =
@@ -210,14 +210,14 @@
         })");
 
   auto request = std::make_unique<network::ResourceRequest>();
-  request->url = registration_params_.RegistrationEndpoint();
+  request->url = registration_params_.registration_endpoint();
   request->method = "POST";
-  request->site_for_cookies =
-      net::SiteForCookies::FromUrl(registration_params_.RegistrationEndpoint());
+  request->site_for_cookies = net::SiteForCookies::FromUrl(
+      registration_params_.registration_endpoint());
   request->trusted_params = network::ResourceRequest::TrustedParams();
   request->trusted_params->isolation_info =
       net::IsolationInfo::CreateForInternalRequest(
-          url::Origin::Create(registration_params_.RegistrationEndpoint()));
+          url::Origin::Create(registration_params_.registration_endpoint()));
 
   std::string content_type = "application/jwt";
 
diff --git a/chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_param.cc b/chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_param.cc
index dad2a11..e5d5040e 100644
--- a/chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_param.cc
+++ b/chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_param.cc
@@ -31,7 +31,7 @@
 }  // namespace
 
 BoundSessionRegistrationFetcherParam::BoundSessionRegistrationFetcherParam(
-    BoundSessionRegistrationFetcherParam&& other) = default;
+    BoundSessionRegistrationFetcherParam&& other) noexcept = default;
 
 BoundSessionRegistrationFetcherParam&
 BoundSessionRegistrationFetcherParam::operator=(
@@ -48,6 +48,7 @@
       supported_algos_(std::move(supported_algos)),
       challenge_(std::move(challenge)) {}
 
+// static
 std::optional<BoundSessionRegistrationFetcherParam>
 BoundSessionRegistrationFetcherParam::MaybeCreateInstance(
     const GURL& request_url,
@@ -113,6 +114,7 @@
   }
 }
 
+// static
 BoundSessionRegistrationFetcherParam
 BoundSessionRegistrationFetcherParam::CreateInstanceForTesting(
     GURL registration_endpoint,
@@ -122,16 +124,3 @@
                                               std::move(supported_algos),
                                               std::move(challenge));
 }
-
-const GURL& BoundSessionRegistrationFetcherParam::RegistrationEndpoint() const {
-  return registration_endpoint_;
-}
-
-base::span<const crypto::SignatureVerifier::SignatureAlgorithm>
-BoundSessionRegistrationFetcherParam::SupportedAlgos() const {
-  return supported_algos_;
-}
-
-const std::string& BoundSessionRegistrationFetcherParam::Challenge() const {
-  return challenge_;
-}
diff --git a/chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_param.h b/chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_param.h
index 44744af..5ea6e24 100644
--- a/chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_param.h
+++ b/chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_param.h
@@ -16,14 +16,14 @@
 class BoundSessionRegistrationFetcherParam {
  public:
   BoundSessionRegistrationFetcherParam(
-      BoundSessionRegistrationFetcherParam&& other);
+      BoundSessionRegistrationFetcherParam&& other) noexcept;
   BoundSessionRegistrationFetcherParam& operator=(
       BoundSessionRegistrationFetcherParam&& other) noexcept;
 
   BoundSessionRegistrationFetcherParam(
       const BoundSessionRegistrationFetcherParam& other) = delete;
   BoundSessionRegistrationFetcherParam& operator=(
-      const BoundSessionRegistrationFetcherParam&) = delete;
+      const BoundSessionRegistrationFetcherParam& other) = delete;
   ~BoundSessionRegistrationFetcherParam();
 
   // Will return a valid instance or return std::nullopt;
@@ -38,10 +38,14 @@
           supported_algos,
       std::string challenge);
 
-  const GURL& RegistrationEndpoint() const;
+  const GURL& registration_endpoint() const { return registration_endpoint_; }
+
   base::span<const crypto::SignatureVerifier::SignatureAlgorithm>
-  SupportedAlgos() const;
-  const std::string& Challenge() const;
+  supported_algos() const {
+    return supported_algos_;
+  }
+
+  const std::string& challenge() const { return challenge_; }
 
  private:
   BoundSessionRegistrationFetcherParam(
diff --git a/chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_param_unittest.cc b/chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_param_unittest.cc
index 3599f224..5f2a178 100644
--- a/chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_param_unittest.cc
+++ b/chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_param_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/signin/bound_session_credentials/bound_session_registration_fetcher_param.h"
+
 #include "base/strings/strcat.h"
 #include "base/test/bind.h"
 #include "base/test/task_environment.h"
@@ -16,24 +17,14 @@
 constexpr char kChallenge[] = "test_challenge";
 }  // namespace
 
-class BoundSessionRegistrationFetcherParamTest : public testing::Test {
- public:
-  BoundSessionRegistrationFetcherParamTest() = default;
-  BoundSessionRegistrationFetcherParamTest(
-      const BoundSessionRegistrationFetcherParamTest&) = delete;
-  BoundSessionRegistrationFetcherParamTest& operator=(
-      const BoundSessionRegistrationFetcherParamTest&) = delete;
-  ~BoundSessionRegistrationFetcherParamTest() override = default;
-};
-
-TEST_F(BoundSessionRegistrationFetcherParamTest, AllInvalid) {
+TEST(BoundSessionRegistrationFetcherParamTest, AllInvalid) {
   std::vector<crypto::SignatureVerifier::SignatureAlgorithm> supported_algos;
   BoundSessionRegistrationFetcherParam params =
       BoundSessionRegistrationFetcherParam::CreateInstanceForTesting(
           GURL(), supported_algos, "");
 }
 
-TEST_F(BoundSessionRegistrationFetcherParamTest, AllValid) {
+TEST(BoundSessionRegistrationFetcherParamTest, AllValid) {
   GURL registration_request = GURL("https://www.google.com/registration");
   auto response_headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
   response_headers->SetHeader(
@@ -46,16 +37,16 @@
           registration_request, response_headers.get());
   ASSERT_TRUE(maybe_params.has_value());
   BoundSessionRegistrationFetcherParam params = std::move(maybe_params.value());
-  ASSERT_EQ(params.RegistrationEndpoint(),
+  EXPECT_EQ(params.registration_endpoint(),
             GURL("https://www.google.com/startsession"));
-  ASSERT_EQ(params.SupportedAlgos()[0],
+  EXPECT_EQ(params.supported_algos()[0],
             crypto::SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256);
-  ASSERT_EQ(params.SupportedAlgos()[1],
+  EXPECT_EQ(params.supported_algos()[1],
             crypto::SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256);
-  ASSERT_EQ(params.Challenge(), kChallenge);
+  EXPECT_EQ(params.challenge(), kChallenge);
 }
 
-TEST_F(BoundSessionRegistrationFetcherParamTest, AllValidFullUrl) {
+TEST(BoundSessionRegistrationFetcherParamTest, AllValidFullUrl) {
   GURL registration_request = GURL("https://www.google.com/registration");
   auto response_headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
   response_headers->SetHeader(
@@ -68,16 +59,16 @@
           registration_request, response_headers.get());
   ASSERT_TRUE(maybe_params.has_value());
   BoundSessionRegistrationFetcherParam params = std::move(maybe_params.value());
-  ASSERT_EQ(params.RegistrationEndpoint(),
+  EXPECT_EQ(params.registration_endpoint(),
             GURL("https://accounts.google.com/startsession"));
-  ASSERT_EQ(params.SupportedAlgos()[0],
+  EXPECT_EQ(params.supported_algos()[0],
             crypto::SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256);
-  ASSERT_EQ(params.SupportedAlgos()[1],
+  EXPECT_EQ(params.supported_algos()[1],
             crypto::SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256);
-  ASSERT_EQ(params.Challenge(), kChallenge);
+  EXPECT_EQ(params.challenge(), kChallenge);
 }
 
-TEST_F(BoundSessionRegistrationFetcherParamTest, AllValidFullDifferentUrl) {
+TEST(BoundSessionRegistrationFetcherParamTest, AllValidFullDifferentUrl) {
   GURL registration_request = GURL("https://www.google.com/registration");
   auto response_headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
   response_headers->SetHeader(
@@ -88,10 +79,10 @@
   std::optional<BoundSessionRegistrationFetcherParam> maybe_params =
       BoundSessionRegistrationFetcherParam::MaybeCreateInstance(
           registration_request, response_headers.get());
-  ASSERT_FALSE(maybe_params.has_value());
+  EXPECT_FALSE(maybe_params.has_value());
 }
 
-TEST_F(BoundSessionRegistrationFetcherParamTest, AllValidSwapAlgo) {
+TEST(BoundSessionRegistrationFetcherParamTest, AllValidSwapAlgo) {
   GURL registration_request = GURL("https://www.google.com/registration");
   auto response_headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
   response_headers->SetHeader(
@@ -104,16 +95,16 @@
           registration_request, response_headers.get());
   ASSERT_TRUE(maybe_params.has_value());
   BoundSessionRegistrationFetcherParam params = std::move(maybe_params.value());
-  ASSERT_EQ(params.RegistrationEndpoint(),
+  EXPECT_EQ(params.registration_endpoint(),
             GURL("https://www.google.com/startsession"));
-  ASSERT_EQ(params.SupportedAlgos()[0],
+  EXPECT_EQ(params.supported_algos()[0],
             crypto::SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256);
-  ASSERT_EQ(params.SupportedAlgos()[1],
+  EXPECT_EQ(params.supported_algos()[1],
             crypto::SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256);
-  ASSERT_EQ(params.Challenge(), kChallenge);
+  EXPECT_EQ(params.challenge(), kChallenge);
 }
 
-TEST_F(BoundSessionRegistrationFetcherParamTest, AllValidOneAlgo) {
+TEST(BoundSessionRegistrationFetcherParamTest, AllValidOneAlgo) {
   GURL registration_request = GURL("https://www.google.com/registration");
   auto response_headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
   response_headers->SetHeader(
@@ -126,24 +117,24 @@
           registration_request, response_headers.get());
   ASSERT_TRUE(maybe_params.has_value());
   BoundSessionRegistrationFetcherParam params = std::move(maybe_params.value());
-  ASSERT_EQ(params.RegistrationEndpoint(),
+  EXPECT_EQ(params.registration_endpoint(),
             GURL("https://www.google.com/startsession"));
-  ASSERT_EQ(params.SupportedAlgos()[0],
+  EXPECT_EQ(params.supported_algos()[0],
             crypto::SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256);
-  ASSERT_EQ(params.Challenge(), kChallenge);
+  EXPECT_EQ(params.challenge(), kChallenge);
 }
 
-TEST_F(BoundSessionRegistrationFetcherParamTest, MissingHeader) {
+TEST(BoundSessionRegistrationFetcherParamTest, MissingHeader) {
   GURL registration_request = GURL("https://www.google.com/registration");
   auto response_headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
   // Note: not adding the right header, causing std::nullopt to be returned.
   std::optional<BoundSessionRegistrationFetcherParam> maybe_params =
       BoundSessionRegistrationFetcherParam::MaybeCreateInstance(
           registration_request, response_headers.get());
-  ASSERT_FALSE(maybe_params.has_value());
+  EXPECT_FALSE(maybe_params.has_value());
 }
 
-TEST_F(BoundSessionRegistrationFetcherParamTest, MissingUrl) {
+TEST(BoundSessionRegistrationFetcherParamTest, MissingUrl) {
   GURL registration_request = GURL();
   auto response_headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
   response_headers->SetHeader(
@@ -154,10 +145,10 @@
   std::optional<BoundSessionRegistrationFetcherParam> maybe_params =
       BoundSessionRegistrationFetcherParam::MaybeCreateInstance(
           registration_request, response_headers.get());
-  ASSERT_FALSE(maybe_params.has_value());
+  EXPECT_FALSE(maybe_params.has_value());
 }
 
-TEST_F(BoundSessionRegistrationFetcherParamTest, MissingAlgo) {
+TEST(BoundSessionRegistrationFetcherParamTest, MissingAlgo) {
   GURL registration_request = GURL("https://www.google.com/registration");
   auto response_headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
   response_headers->SetHeader(
@@ -167,10 +158,10 @@
   std::optional<BoundSessionRegistrationFetcherParam> maybe_params =
       BoundSessionRegistrationFetcherParam::MaybeCreateInstance(
           registration_request, response_headers.get());
-  ASSERT_FALSE(maybe_params.has_value());
+  EXPECT_FALSE(maybe_params.has_value());
 }
 
-TEST_F(BoundSessionRegistrationFetcherParamTest, MissingRegistration) {
+TEST(BoundSessionRegistrationFetcherParamTest, MissingRegistration) {
   GURL registration_request = GURL("https://www.google.com/registration");
   auto response_headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
   response_headers->SetHeader(
@@ -179,10 +170,10 @@
   std::optional<BoundSessionRegistrationFetcherParam> maybe_params =
       BoundSessionRegistrationFetcherParam::MaybeCreateInstance(
           registration_request, response_headers.get());
-  ASSERT_FALSE(maybe_params.has_value());
+  EXPECT_FALSE(maybe_params.has_value());
 }
 
-TEST_F(BoundSessionRegistrationFetcherParamTest, MissingChallenge) {
+TEST(BoundSessionRegistrationFetcherParamTest, MissingChallenge) {
   GURL registration_request = GURL("https://www.google.com/registration");
   auto response_headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
   response_headers->SetHeader(
@@ -191,10 +182,10 @@
   std::optional<BoundSessionRegistrationFetcherParam> maybe_params =
       BoundSessionRegistrationFetcherParam::MaybeCreateInstance(
           registration_request, response_headers.get());
-  ASSERT_FALSE(maybe_params.has_value());
+  EXPECT_FALSE(maybe_params.has_value());
 }
 
-TEST_F(BoundSessionRegistrationFetcherParamTest, EmptyChallenge) {
+TEST(BoundSessionRegistrationFetcherParamTest, EmptyChallenge) {
   GURL registration_request = GURL("https://www.google.com/registration");
   auto response_headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
   response_headers->SetHeader(
@@ -203,10 +194,10 @@
   std::optional<BoundSessionRegistrationFetcherParam> maybe_params =
       BoundSessionRegistrationFetcherParam::MaybeCreateInstance(
           registration_request, response_headers.get());
-  ASSERT_FALSE(maybe_params.has_value());
+  EXPECT_FALSE(maybe_params.has_value());
 }
 
-TEST_F(BoundSessionRegistrationFetcherParamTest, ChallengeInvalidUtf8) {
+TEST(BoundSessionRegistrationFetcherParamTest, ChallengeInvalidUtf8) {
   GURL registration_request = GURL("https://www.google.com/registration");
   auto response_headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
   response_headers->SetHeader(
@@ -216,5 +207,5 @@
   std::optional<BoundSessionRegistrationFetcherParam> maybe_params =
       BoundSessionRegistrationFetcherParam::MaybeCreateInstance(
           registration_request, response_headers.get());
-  ASSERT_FALSE(maybe_params.has_value());
+  EXPECT_FALSE(maybe_params.has_value());
 }
diff --git a/chrome/browser/signin/signin_promo_unittest.cc b/chrome/browser/signin/signin_promo_unittest.cc
index e11221c3..17e86c66 100644
--- a/chrome/browser/signin/signin_promo_unittest.cc
+++ b/chrome/browser/signin/signin_promo_unittest.cc
@@ -6,7 +6,15 @@
 
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
+#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
+#include "chrome/browser/signin/signin_promo_util.h"
 #include "chrome/common/webui_url_constants.h"
+#include "chrome/test/base/browser_with_test_window_test.h"
+#include "components/signin/public/base/consent_level.h"
+#include "components/signin/public/base/signin_switches.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
+#include "components/signin/public/identity_manager/identity_test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
@@ -47,7 +55,7 @@
       "https://accounts.google.com/signin/chrome/sync?ssp=1&"
       "color_scheme=dark&flow=promo",
       GetChromeSyncURLForDice(
-          {.request_dark_scheme = true, .flow = signin::Flow::PROMO}));
+          {.request_dark_scheme = true, .flow = Flow::PROMO}));
   EXPECT_EQ(
       "https://accounts.google.com/signin/chrome/sync?ssp=1&"
       "email_hint=email%40gmail.com&continue=https%3A%2F%2Fcontinue_url%2F",
@@ -56,7 +64,7 @@
   EXPECT_EQ(
       "https://accounts.google.com/signin/chrome/"
       "sync?ssp=1&flow=embedded_promo",
-      GetChromeSyncURLForDice({.flow = signin::Flow::EMBEDDED_PROMO}));
+      GetChromeSyncURLForDice({.flow = Flow::EMBEDDED_PROMO}));
   EXPECT_EQ(
       "https://accounts.google.com/AddSession?"
       "Email=email%40gmail.com&continue=https%3A%2F%2Fcontinue_url%2F",
@@ -64,4 +72,112 @@
                               GURL("https://continue_url/")));
 }
 
+class ShowPromoTest : public testing::Test {
+ public:
+  ShowPromoTest() {
+    profile_ = IdentityTestEnvironmentProfileAdaptor::
+        CreateProfileForIdentityTestEnvironment();
+    identity_test_env_adaptor_ =
+        std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile_.get());
+  }
+
+  IdentityManager* identity_manager() {
+    return identity_test_env_adaptor_->identity_test_env()->identity_manager();
+  }
+
+  Profile* profile() { return profile_.get(); }
+
+ private:
+  content::BrowserTaskEnvironment task_environment_;
+  std::unique_ptr<TestingProfile> profile_;
+  std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
+      identity_test_env_adaptor_;
+};
+
+// Tests for ShouldShowPromo.
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+TEST_F(ShowPromoTest, ShowPromoWithNoAccount) {
+  EXPECT_TRUE(ShouldShowPromo(*profile(), ConsentLevel::kSync));
+}
+
+TEST_F(ShowPromoTest, ShowPromoWithSignedInAccount) {
+  MakePrimaryAccountAvailable(identity_manager(), "test@email.com",
+                              ConsentLevel::kSignin);
+  EXPECT_TRUE(ShouldShowPromo(*profile(), ConsentLevel::kSync));
+}
+
+TEST_F(ShowPromoTest, DoNotShowPromoWithSyncingAccount) {
+  MakePrimaryAccountAvailable(identity_manager(), "test@email.com",
+                              ConsentLevel::kSync);
+  EXPECT_FALSE(ShouldShowPromo(*profile(), ConsentLevel::kSync));
+}
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
+
+// Tests for ShouldShowSignInPromo.
+TEST_F(ShowPromoTest, DoNotShowSignInPromoWithoutExplicitBrowserSignin) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(
+      switches::kExplicitBrowserSigninUIOnDesktop);
+
+  EXPECT_FALSE(ShouldShowSignInPromo(*profile(),
+                                     SignInAutofillBubblePromoType::Passwords));
+}
+
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+class ShowSigninPromoTestExplicitBrowserSignin : public ShowPromoTest {
+  base::test::ScopedFeatureList feature_list{
+      switches::kExplicitBrowserSigninUIOnDesktop};
+};
+
+TEST_F(ShowSigninPromoTestExplicitBrowserSignin, ShowPromoWithNoAccount) {
+  EXPECT_TRUE(ShouldShowSignInPromo(*profile(),
+                                    SignInAutofillBubblePromoType::Payments));
+}
+
+TEST_F(ShowSigninPromoTestExplicitBrowserSignin,
+       ShowPromoWithWebSignedInAccount) {
+  MakeAccountAvailable(identity_manager(), "test@email.com");
+  EXPECT_TRUE(ShouldShowSignInPromo(*profile(),
+                                    SignInAutofillBubblePromoType::Addresses));
+}
+
+TEST_F(ShowSigninPromoTestExplicitBrowserSignin,
+       ShowPromoWithSignInPausedAccount) {
+  AccountInfo info = MakePrimaryAccountAvailable(
+      identity_manager(), "test@email.com", ConsentLevel::kSignin);
+  UpdatePersistentErrorOfRefreshTokenForAccount(
+      identity_manager(), info.account_id,
+      GoogleServiceAuthError(
+          GoogleServiceAuthError::State::USER_NOT_SIGNED_UP));
+  EXPECT_TRUE(ShouldShowSignInPromo(*profile(),
+                                    SignInAutofillBubblePromoType::Passwords));
+}
+
+TEST_F(ShowSigninPromoTestExplicitBrowserSignin,
+       DoNotShowPromoWithAlreadySignedInAccount) {
+  MakePrimaryAccountAvailable(identity_manager(), "test@email.com",
+                              ConsentLevel::kSignin);
+  EXPECT_FALSE(ShouldShowSignInPromo(*profile(),
+                                     SignInAutofillBubblePromoType::Payments));
+}
+
+TEST_F(ShowSigninPromoTestExplicitBrowserSignin,
+       DoNotShowPromoWithAlreadySyncingAccount) {
+  MakePrimaryAccountAvailable(identity_manager(), "test@email.com",
+                              ConsentLevel::kSync);
+  EXPECT_FALSE(ShouldShowSignInPromo(*profile(),
+                                     SignInAutofillBubblePromoType::Addresses));
+}
+
+TEST_F(ShowSigninPromoTestExplicitBrowserSignin,
+       DoNotShowPromoAfterFiveTimesShown) {
+  // TODO (crbug.com/319411728): Implement a counter and test it.
+}
+
+TEST_F(ShowSigninPromoTestExplicitBrowserSignin,
+       DoNotShowPromoAfterTwoTimesDismissed) {
+  // TODO (crbug.com/319411728): Implement a counter and test it.
+}
+#endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
+
 }  // namespace signin
diff --git a/chrome/browser/signin/signin_promo_util.cc b/chrome/browser/signin/signin_promo_util.cc
index 98aac88..b84e0ee 100644
--- a/chrome/browser/signin/signin_promo_util.cc
+++ b/chrome/browser/signin/signin_promo_util.cc
@@ -8,14 +8,16 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "components/prefs/pref_service.h"
+#include "components/signin/public/base/consent_level.h"
 #include "components/signin/public/base/signin_pref_names.h"
+#include "components/signin/public/base/signin_switches.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/signin/public/identity_manager/primary_account_mutator.h"
 #include "net/base/network_change_notifier.h"
 
 namespace signin {
 
-bool ShouldShowPromo(Profile* profile) {
+bool ShouldShowPromo(Profile& profile, ConsentLevel promo_type) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // There's no need to show the sign in promo on cros since cros users are
   // already logged in.
@@ -29,21 +31,41 @@
   // Consider original profile even if an off-the-record profile was
   // passed to this method as sign-in state is only defined for the
   // primary profile.
-  Profile* original_profile = profile->GetOriginalProfile();
+  Profile* original_profile = profile.GetOriginalProfile();
 
   // Don't show for supervised child profiles.
   if (original_profile->IsChild())
     return false;
 
-  // Don't show if sign-in is not allowed.
+  // Don't show if sign in is not allowed.
   if (!original_profile->GetPrefs()->GetBoolean(prefs::kSigninAllowed))
     return false;
 
-  // Display the signin promo if the user is not signed in.
-  signin::IdentityManager* identity_manager =
+  IdentityManager* identity_manager =
       IdentityManagerFactory::GetForProfile(original_profile);
-  return !identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSync);
+
+  // No promo if the user is already syncing.
+  if (identity_manager->HasPrimaryAccount(ConsentLevel::kSync)) {
+    return false;
+  }
+
+  // Sync Promos are always shown when the user is not syncing.
+  if (promo_type == ConsentLevel::kSync) {
+    return true;
+  }
+
+  // Signin promo is shown if the user is not signed in or needs to reauth.
+  return !identity_manager->HasPrimaryAccount(ConsentLevel::kSignin) ||
+         identity_manager->HasAccountWithRefreshTokenInPersistentErrorState(
+             identity_manager->GetPrimaryAccountId(ConsentLevel::kSignin));
 #endif
 }
 
+bool ShouldShowSignInPromo(Profile& profile,
+                           SignInAutofillBubblePromoType signin_promo_type) {
+  return ShouldShowPromo(profile, ConsentLevel::kSignin) &&
+         switches::IsExplicitBrowserSigninUIOnDesktopEnabled(
+             switches::ExplicitBrowserSigninPhase::kFull);
+}
+
 }  // namespace signin
diff --git a/chrome/browser/signin/signin_promo_util.h b/chrome/browser/signin/signin_promo_util.h
index c115c8b2..aef8dba4 100644
--- a/chrome/browser/signin/signin_promo_util.h
+++ b/chrome/browser/signin/signin_promo_util.h
@@ -5,13 +5,24 @@
 #ifndef CHROME_BROWSER_SIGNIN_SIGNIN_PROMO_UTIL_H_
 #define CHROME_BROWSER_SIGNIN_SIGNIN_PROMO_UTIL_H_
 
+#include "components/signin/public/base/consent_level.h"
+
 class Profile;
 
 namespace signin {
 
-// Returns true if the sign in promo should be visible.
+// Enumeration of sign in promo types for the autofill bubble.
+enum class SignInAutofillBubblePromoType { Passwords, Addresses, Payments };
+
+// Returns true if the sync/sign in promo should be visible.
 // |profile| is the profile of the tab the promo would be shown on.
-bool ShouldShowPromo(Profile* profile);
+// |promo_type| specifies whether the promo would be for sync or sign in.
+bool ShouldShowPromo(Profile& profile, ConsentLevel promo_type);
+
+// Whether we should show the sign in promo after data of the type
+// |signin_promo_type| was saved.
+bool ShouldShowSignInPromo(Profile& profile,
+                           SignInAutofillBubblePromoType signin_promo_type);
 
 }  // namespace signin
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 0ad697d9..5a161e5 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -745,6 +745,13 @@
     deps += [ "//chrome/browser/vr:vr_base" ]
   }
 
+  if (is_win || is_linux || is_mac || is_chromeos) {
+    sources += [
+      "passwords/password_cross_domain_confirmation_popup_controller_impl.cc",
+      "passwords/password_cross_domain_confirmation_popup_controller_impl.h",
+    ]
+  }
+
   if (is_win || is_android || is_linux || is_chromeos) {
     sources += [
       "webui/sandbox/sandbox_internals_ui.cc",
@@ -754,8 +761,6 @@
 
   if (is_win || is_linux || is_mac || is_chromeos_ash) {
     sources += [
-      "passwords/password_cross_domain_confirmation_popup_controller.cc",
-      "passwords/password_cross_domain_confirmation_popup_controller.h",
       "passwords/password_cross_domain_confirmation_popup_view.h",
       "webui/connectors_internals/connectors_internals_page_handler.cc",
       "webui/connectors_internals/connectors_internals_page_handler.h",
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 300f9d23..507c958 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -2243,6 +2243,14 @@
       <message name="IDS_SYNC_REVIEW_DATA" desc="Title for link to https://chrome.google.com/sync Dashboard to manage sync data.">
         Review your synced data
       </message>
+      <!-- TODO(b/326574743): Revisit string and mark it as translatable.-->
+      <message name="IDS_SIGNIN_REVIEW_DATA_TITLE" desc="Title for link to https://chrome.google.com/sync Dashboard to manage sync data." translateable="false">
+        Data in your account
+      </message>
+      <!-- TODO(b/326574743): Revisit string and mark it as translatable.-->
+      <message name="IDS_SIGNIN_REVIEW_DATA_SUMMARY" desc="Summary for link to https://chrome.google.com/sync Dashboard to manage sync data." translateable="false">
+        Review your account data
+      </message>
       <message name="IDS_SYNC_PASSPHRASE_TYPE_TITLE" desc="Title of sync passphrase type dialog. [CHAR_LIMIT=24]">
         Encryption
       </message>
diff --git a/chrome/browser/ui/ash/capture_mode/capture_mode_browsertest.cc b/chrome/browser/ui/ash/capture_mode/capture_mode_browsertest.cc
index 97e0c0d..2d1ca032 100644
--- a/chrome/browser/ui/ash/capture_mode/capture_mode_browsertest.cc
+++ b/chrome/browser/ui/ash/capture_mode/capture_mode_browsertest.cc
@@ -23,6 +23,7 @@
 #include "base/task/sequenced_task_runner.h"
 #include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/test/test_future.h"
 #include "chrome/browser/ash/crosapi/crosapi_ash.h"
 #include "chrome/browser/ash/crosapi/crosapi_manager.h"
 #include "chrome/browser/ash/file_manager/file_manager_test_util.h"
@@ -34,16 +35,20 @@
 #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager_factory.h"
 #include "chrome/browser/chromeos/policy/dlp/test/dlp_content_manager_test_helper.h"
 #include "chrome/browser/chromeos/policy/dlp/test/mock_dlp_rules_manager.h"
+#include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/enterprise/data_controls/dlp_reporting_manager.h"
 #include "chrome/browser/enterprise/data_controls/dlp_reporting_manager_test_helper.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
+#include "chrome/browser/policy/policy_test_utils.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/enterprise/data_controls/dlp_policy_event.pb.h"
+#include "components/policy/policy_constants.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/test/browser_test.h"
 #include "media/base/media_switches.h"
@@ -180,12 +185,39 @@
 
 }  // namespace
 
+class CaptureModeBrowserTest : public InProcessBrowserTest {};
+
+IN_PROC_BROWSER_TEST_F(CaptureModeBrowserTest, ContextMenuStaysOpen) {
+  // Right click the desktop to open a context menu.
+  aura::Window* browser_window = browser()->window()->GetNativeWindow();
+  const gfx::Point point_on_desktop(1, 1);
+  ASSERT_FALSE(browser_window->bounds().Contains(point_on_desktop));
+
+  ui::test::EventGenerator event_generator(browser_window->GetRootWindow(),
+                                           point_on_desktop);
+  event_generator.ClickRightButton();
+
+  ash::ShellTestApi shell_test_api;
+  ASSERT_TRUE(shell_test_api.IsContextMenuShown());
+
+  ash::CaptureModeTestApi().StartForWindow(/*for_video=*/false);
+  EXPECT_TRUE(shell_test_api.IsContextMenuShown());
+}
+
+// A regression test for https://crbug.com/1350711 in which a session is started
+// quickly after clicking the sign out button.
+IN_PROC_BROWSER_TEST_F(CaptureModeBrowserTest,
+                       SimulateStartingSessionAfterSignOut) {
+  ash::Shell::Get()->session_controller()->RequestSignOut();
+  ash::CaptureModeTestApi().StartForFullscreen(false);
+}
+
 // Testing class to test CrOS capture mode, which is a feature to take
 // screenshots and record video.
-class CaptureModeBrowserTest : public InProcessBrowserTest {
+class CaptureModeDlpBrowserTest : public CaptureModeBrowserTest {
  public:
-  CaptureModeBrowserTest() = default;
-  ~CaptureModeBrowserTest() override = default;
+  CaptureModeDlpBrowserTest() = default;
+  ~CaptureModeDlpBrowserTest() override = default;
 
   void SetUpOnMainThread() override {
     // Instantiate |DlpContentManagerTestHelper| after main thread has been
@@ -231,25 +263,8 @@
   std::vector<DlpPolicyEvent> events_;
 };
 
-IN_PROC_BROWSER_TEST_F(CaptureModeBrowserTest, ContextMenuStaysOpen) {
-  // Right click the desktop to open a context menu.
-  aura::Window* browser_window = browser()->window()->GetNativeWindow();
-  const gfx::Point point_on_desktop(1, 1);
-  ASSERT_FALSE(browser_window->bounds().Contains(point_on_desktop));
-
-  ui::test::EventGenerator event_generator(browser_window->GetRootWindow(),
-                                           point_on_desktop);
-  event_generator.ClickRightButton();
-
-  ash::ShellTestApi shell_test_api;
-  ASSERT_TRUE(shell_test_api.IsContextMenuShown());
-
-  ash::CaptureModeTestApi().StartForWindow(/*for_video=*/false);
-  EXPECT_TRUE(shell_test_api.IsContextMenuShown());
-}
-
 // Checks that video capture emits exactly one DLP reporting event.
-IN_PROC_BROWSER_TEST_F(CaptureModeBrowserTest, DlpReportingVideoCapture) {
+IN_PROC_BROWSER_TEST_F(CaptureModeDlpBrowserTest, DlpReportingVideoCapture) {
   // Set DLP restriction.
   auto* dlp_content_observer = policy::DlpContentObserver::Get();
   ASSERT_TRUE(dlp_content_observer);
@@ -300,7 +315,7 @@
 }
 
 // Tests DLP reporting without opening the capture bar.
-IN_PROC_BROWSER_TEST_F(CaptureModeBrowserTest,
+IN_PROC_BROWSER_TEST_F(CaptureModeDlpBrowserTest,
                        DlpReportingDialogOnFullscreenScreenCaptureShortcut) {
   ASSERT_TRUE(browser());
   // Set DLP restriction.
@@ -329,7 +344,7 @@
           kRuleName, kRuleId, policy::DlpRulesManager::Level::kReport)));
 }
 
-IN_PROC_BROWSER_TEST_F(CaptureModeBrowserTest,
+IN_PROC_BROWSER_TEST_F(CaptureModeDlpBrowserTest,
                        DlpWarningDialogOnVideoEndDismissed) {
   ASSERT_TRUE(browser());
   StartVideoRecording();
@@ -365,7 +380,7 @@
           policy::DlpRulesManager::Level::kWarn)));
 }
 
-IN_PROC_BROWSER_TEST_F(CaptureModeBrowserTest,
+IN_PROC_BROWSER_TEST_F(CaptureModeDlpBrowserTest,
                        DlpWarningDialogOnVideoEndAccepted) {
   ASSERT_TRUE(browser());
   StartVideoRecording();
@@ -401,32 +416,25 @@
               kRuleName, kRuleId)));
 }
 
-// A regression test for https://crbug.com/1350711 in which a session is started
-// quickly after clicking the sign out button.
-IN_PROC_BROWSER_TEST_F(CaptureModeBrowserTest,
-                       SimulateStartingSessionAfterSignOut) {
-  ash::Shell::Get()->session_controller()->RequestSignOut();
-  ash::CaptureModeTestApi().StartForFullscreen(false);
-}
-
 // Parametrize capture mode browser tests to check both making screenshots and
 // video capture. This is particularly important for DLP which handles reporting
 // of user activity differently for screenshots and video capture.
-class CaptureModeParamBrowserTest : public CaptureModeBrowserTest,
-                                    public ::testing::WithParamInterface<bool> {
+class CaptureModeParamDlpBrowserTest
+    : public CaptureModeDlpBrowserTest,
+      public ::testing::WithParamInterface<bool> {
  public:
-  CaptureModeParamBrowserTest() : for_video_(GetParam()) {}
-  ~CaptureModeParamBrowserTest() override = default;
+  CaptureModeParamDlpBrowserTest() : for_video_(GetParam()) {}
+  ~CaptureModeParamDlpBrowserTest() override = default;
 
  protected:
   const bool for_video_;
 };
 
-INSTANTIATE_TEST_SUITE_P(CaptureModeParamBrowserTest,
-                         CaptureModeParamBrowserTest,
+INSTANTIATE_TEST_SUITE_P(CaptureModeParamDlpBrowserTest,
+                         CaptureModeParamDlpBrowserTest,
                          ::testing::Bool());
 
-IN_PROC_BROWSER_TEST_P(CaptureModeParamBrowserTest,
+IN_PROC_BROWSER_TEST_P(CaptureModeParamDlpBrowserTest,
                        DlpWarningDialogOnSessionInitDismissed) {
   ASSERT_TRUE(browser());
   MarkActiveTabAsDlpWarnedForScreenCapture(browser());
@@ -453,7 +461,7 @@
           kRuleName, kRuleId, policy::DlpRulesManager::Level::kWarn)));
 }
 
-IN_PROC_BROWSER_TEST_P(CaptureModeParamBrowserTest,
+IN_PROC_BROWSER_TEST_P(CaptureModeParamDlpBrowserTest,
                        DlpWarningDialogOnSessionInitAccepted) {
   ASSERT_TRUE(browser());
   MarkActiveTabAsDlpWarnedForScreenCapture(browser());
@@ -482,7 +490,7 @@
           kRuleName, kRuleId, policy::DlpRulesManager::Level::kWarn)));
 }
 
-IN_PROC_BROWSER_TEST_P(CaptureModeParamBrowserTest,
+IN_PROC_BROWSER_TEST_P(CaptureModeParamDlpBrowserTest,
                        DlpWarningDialogOnPerformingCaptureDismissed) {
   ASSERT_TRUE(browser());
   // Start the session before a window becomes restricted.
@@ -516,7 +524,7 @@
           kRuleName, kRuleId, policy::DlpRulesManager::Level::kWarn)));
 }
 
-IN_PROC_BROWSER_TEST_F(CaptureModeBrowserTest,
+IN_PROC_BROWSER_TEST_F(CaptureModeDlpBrowserTest,
                        DlpWarningDialogOnPerformingScreenCaptureAccepted) {
   ASSERT_TRUE(browser());
   // Start the session before a window becomes restricted.
@@ -559,7 +567,7 @@
               kRuleName, kRuleId)));
 }
 
-IN_PROC_BROWSER_TEST_F(CaptureModeBrowserTest,
+IN_PROC_BROWSER_TEST_F(CaptureModeDlpBrowserTest,
                        DlpWarningDialogOnPerformingVideoCaptureAccepted) {
   ASSERT_TRUE(browser());
   SetupDlpReporting();
@@ -624,7 +632,7 @@
               kRuleName, kRuleId)));
 }
 
-IN_PROC_BROWSER_TEST_F(CaptureModeBrowserTest,
+IN_PROC_BROWSER_TEST_F(CaptureModeDlpBrowserTest,
                        DlpWarningDialogOnCountdownEndDismissed) {
   ASSERT_TRUE(browser());
   ash::CaptureModeTestApi test_api;
@@ -660,7 +668,7 @@
           kRuleName, kRuleId, policy::DlpRulesManager::Level::kWarn)));
 }
 
-IN_PROC_BROWSER_TEST_F(CaptureModeBrowserTest,
+IN_PROC_BROWSER_TEST_F(CaptureModeDlpBrowserTest,
                        DlpWarningDialogOnCountdownEndAccepted) {
   ASSERT_TRUE(browser());
   ash::CaptureModeTestApi test_api;
@@ -709,7 +717,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(
-    CaptureModeBrowserTest,
+    CaptureModeDlpBrowserTest,
     DlpWarningDialogOnCaptureScreenshotsOfAllDisplaysDismissed) {
   ASSERT_TRUE(browser());
   MarkActiveTabAsDlpWarnedForScreenCapture(browser());
@@ -736,7 +744,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(
-    CaptureModeBrowserTest,
+    CaptureModeDlpBrowserTest,
     DlpWarningDialogOnFullscreenScreenCaptureShortcutAccepted) {
   ASSERT_TRUE(browser());
   MarkActiveTabAsDlpWarnedForScreenCapture(browser());
@@ -1034,3 +1042,83 @@
   EXPECT_TRUE(!is_share_screen_icon_enabled_ ||
               !vc_tray_screen_share_icon()->GetVisible());
 }
+
+// Tests that the capture is saved to policy defined location if feature is
+// enabled. Received a param on whether to test video or image capture and
+// another param on whether the feature is enabled or not.
+class CaptureModePolicyBrowserTest
+    : public testing::WithParamInterface<std::pair<bool, bool>>,
+      public policy::PolicyTest {
+ public:
+  CaptureModePolicyBrowserTest()
+      : for_video_(GetParam().first), skyvault_enabled_(GetParam().second) {
+    if (skyvault_enabled_) {
+      scoped_feature_list_.InitAndEnableFeature(features::kSkyVault);
+    } else {
+      scoped_feature_list_.InitAndDisableFeature(features::kSkyVault);
+    }
+  }
+
+ protected:
+  bool for_video_, skyvault_enabled_;
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_P(CaptureModePolicyBrowserTest,
+                       ScreenCaptureLocationPolicy) {
+  ASSERT_TRUE(browser());
+  // Start the session before a window becomes restricted.
+  ash::CaptureModeTestApi test_api;
+
+  test_api.StartForFullscreen(for_video_);
+  ASSERT_TRUE(test_api.IsSessionActive());
+  {
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    base::ScopedTempDir temp_dir;
+    ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+    policy::PolicyMap policies;
+    SetPolicy(&policies, policy::key::kScreenCaptureLocation,
+              base::Value(temp_dir.GetPath().value()));
+    UpdateProviderPolicy(policies);
+
+    // Set up a waiter to wait for the file to be saved.
+    base::test::TestFuture<const base::FilePath&> path_future;
+    test_api.SetOnCaptureFileSavedCallback(path_future.GetCallback());
+
+    test_api.PerformCapture();
+
+    if (for_video_) {
+      // Explicitly waiting for video capture to start as it might
+      // asynchronously check custom destination folder.
+      if (!test_api.IsVideoRecordingInProgress()) {
+        base::RunLoop run_loop;
+        test_api.SetOnVideoRecordingStartedCallback(run_loop.QuitClosure());
+        run_loop.Run();
+      }
+      // Wait while the file location is checked.
+      test_api.FlushRecordingServiceForTesting();
+      test_api.StopVideoRecording();
+    }
+
+    // If SkyVault enabled - the file is saved
+    // to the policy dir, otherwise to the default downloads folder.
+    const base::FilePath expected_location =
+        skyvault_enabled_
+            ? temp_dir.GetPath()
+            : DownloadPrefs::FromBrowserContext(browser()->profile())
+                  ->GetDefaultDownloadDirectoryForProfile();
+    // Wait for the file to be saved.
+    EXPECT_TRUE(expected_location.IsParent(path_future.Get()));
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(,  // Empty to simplify gtest output
+                         CaptureModePolicyBrowserTest,
+                         testing::ValuesIn({
+                             std::make_pair(true, true),
+                             std::make_pair(true, false),
+                             std::make_pair(false, true),
+                             std::make_pair(false, false),
+                         }));
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller.h b/chrome/browser/ui/autofill/autofill_popup_controller.h
index 008cdad..ab0f4ec 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller.h
+++ b/chrome/browser/ui/autofill/autofill_popup_controller.h
@@ -18,11 +18,29 @@
 #include "components/autofill/core/browser/ui/suggestion.h"
 #include "components/autofill/core/common/aliases.h"
 
+namespace content {
+class WebContents;
+}  // namespace content
+
 namespace autofill {
 
+struct PopupControllerCommon;
+
 // This interface provides data to an AutofillPopupView.
 class AutofillPopupController : public AutofillPopupViewDelegate {
  public:
+  // Acts as a factory method to create a new `AutofillPopupController`, or
+  // reuse `previous` if the construction arguments are the same. `previous` may
+  // be invalidated by this call. The controller will listen for keyboard input
+  // routed to `web_contents` while the popup is showing, unless `web_contents`
+  // is null.
+  static base::WeakPtr<AutofillPopupController> GetOrCreate(
+      base::WeakPtr<AutofillPopupController> previous,
+      base::WeakPtr<AutofillPopupDelegate> delegate,
+      content::WebContents* web_contents,
+      PopupControllerCommon controller_common,
+      int32_t form_control_ax_id);
+
   // Recalculates the height and width of the popup and triggers a redraw when
   // suggestions change.
   virtual void OnSuggestionsChanged() = 0;
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
index f5aa886..9683bbe 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
@@ -110,7 +110,7 @@
 
 #if !BUILDFLAG(IS_MAC)
 // static
-WeakPtr<AutofillPopupControllerImpl> AutofillPopupControllerImpl::GetOrCreate(
+WeakPtr<AutofillPopupController> AutofillPopupController::GetOrCreate(
     WeakPtr<AutofillPopupController> previous,
     WeakPtr<AutofillPopupDelegate> delegate,
     content::WebContents* web_contents,
@@ -133,12 +133,12 @@
     previous->Hide(PopupHidingReason::kViewDestroyed);
   }
 #if BUILDFLAG(IS_ANDROID)
-  AutofillPopupControllerImpl* controller = new AutofillPopupControllerImpl(
+  auto* controller = new AutofillPopupControllerImpl(
       delegate, web_contents, std::move(controller_common), form_control_ax_id,
       base::BindRepeating(&local_password_migration::ShowWarning),
       /*parent=*/std::nullopt);
 #else
-  AutofillPopupControllerImpl* controller = new AutofillPopupControllerImpl(
+  auto* controller = new AutofillPopupControllerImpl(
       delegate, web_contents, std::move(controller_common), form_control_ax_id,
       base::DoNothing(), /*parent=*/std::nullopt);
 #endif
@@ -364,8 +364,12 @@
   }
   // For tests, keep open when hiding is due to external stimuli.
   if (keep_popup_open_for_testing_ &&
-      reason == PopupHidingReason::kWidgetChanged) {
-    return;  // Don't close the popup because the browser window is resized.
+      (reason == PopupHidingReason::kWidgetChanged ||
+       reason == PopupHidingReason::kEndEditing)) {
+    return;  // Don't close the popup because the browser window is resized or
+             // because too many fields get focus one after each other (this can
+             // happen on Desktop, if multiple password forms are present, and
+             // they are all autofilled by default).
   }
 
   if (delegate_ && IsRootPopup()) {
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.h b/chrome/browser/ui/autofill/autofill_popup_controller_impl.h
index da60cca..01c77795 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.h
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.h
@@ -74,17 +74,6 @@
   AutofillPopupControllerImpl& operator=(const AutofillPopupControllerImpl&) =
       delete;
 
-  // Creates a new `AutofillPopupControllerImpl`, or reuses `previous` if the
-  // construction arguments are the same. `previous` may be invalidated by this
-  // call. The controller will listen for keyboard input routed to
-  // `web_contents` while the popup is showing, unless `web_contents` is NULL.
-  static base::WeakPtr<AutofillPopupControllerImpl> GetOrCreate(
-      base::WeakPtr<AutofillPopupController> previous,
-      base::WeakPtr<AutofillPopupDelegate> delegate,
-      content::WebContents* web_contents,
-      PopupControllerCommon controller_common,
-      int32_t form_control_ax_id);
-
   // Handles a key press event and returns whether the event should be swallowed
   // (meaning that no other handler, in not particular the default handler, can
   // process it).
@@ -133,8 +122,6 @@
     time_view_shown_ = NextIdleTimeTicks::CaptureNextIdleTimeTicks();
   }
 
-  int GetLineCountForTesting() const { return GetLineCount(); }
-
  protected:
   AutofillPopupControllerImpl(
       base::WeakPtr<AutofillPopupDelegate> delegate,
@@ -176,6 +163,8 @@
   virtual void HideViewAndDie();
 
  private:
+  friend class AutofillPopupController;
+
   // Clear the internal state of the controller. This is needed to ensure that
   // when the popup is reused it doesn't leak values between uses.
   void ClearState();
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl_mac.mm b/chrome/browser/ui/autofill/autofill_popup_controller_impl_mac.mm
index 716c9fd8..0e70b2a 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl_mac.mm
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl_mac.mm
@@ -17,7 +17,7 @@
 namespace autofill {
 
 // static
-WeakPtr<AutofillPopupControllerImpl> AutofillPopupControllerImpl::GetOrCreate(
+WeakPtr<AutofillPopupController> AutofillPopupController::GetOrCreate(
     WeakPtr<AutofillPopupController> previous,
     WeakPtr<AutofillPopupDelegate> delegate,
     content::WebContents* web_contents,
@@ -36,7 +36,7 @@
   if (previous.get())
     previous->Hide(PopupHidingReason::kViewDestroyed);
 
-  AutofillPopupControllerImpl* controller = new AutofillPopupControllerImplMac(
+  auto* controller = new AutofillPopupControllerImplMac(
       delegate, web_contents, std::move(controller_common), form_control_ax_id);
   return controller->GetWeakPtr();
 }
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cc
index 0a327fc..44899f04 100644
--- a/chrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl_unittest.cc
@@ -4,56 +4,11 @@
 
 #include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h"
 
-#include <stddef.h>
-
-#include <memory>
 #include <optional>
-#include <string>
-#include <utility>
 
-#include "base/memory/weak_ptr.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/test/gmock_callback_support.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/mock_callback.h"
-#include "base/test/task_environment.h"
-#include "base/time/time.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
-#include "chrome/browser/accessibility/accessibility_state_utils.h"
-#include "chrome/browser/autofill/personal_data_manager_factory.h"
-#include "chrome/browser/ui/autofill/autofill_popup_view.h"
-#include "chrome/browser/ui/autofill/popup_controller_common.h"
-#include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "chrome/test/base/testing_profile.h"
-#include "components/autofill/content/browser/content_autofill_driver.h"
-#include "components/autofill/content/browser/content_autofill_driver_factory.h"
-#include "components/autofill/content/browser/content_autofill_driver_factory_test_api.h"
-#include "components/autofill/content/browser/test_autofill_client_injector.h"
-#include "components/autofill/content/browser/test_autofill_driver_injector.h"
-#include "components/autofill/content/browser/test_autofill_manager_injector.h"
-#include "components/autofill/content/browser/test_content_autofill_client.h"
-#include "components/autofill/core/browser/autofill_driver_router.h"
-#include "components/autofill/core/browser/autofill_external_delegate.h"
-#include "components/autofill/core/browser/autofill_manager.h"
-#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/test_personal_data_manager.h"
-#include "components/autofill/core/browser/ui/autofill_popup_delegate.h"
-#include "components/autofill/core/browser/ui/popup_hiding_reasons.h"
-#include "components/autofill/core/browser/ui/popup_item_ids.h"
-#include "components/autofill/core/browser/ui/suggestion.h"
-#include "components/autofill/core/common/aliases.h"
-#include "components/autofill/core/common/unique_ids.h"
-#include "components/password_manager/core/common/password_manager_features.h"
-#include "components/prefs/pref_service.h"
-#include "components/strings/grit/components_strings.h"
-#include "content/public/browser/render_widget_host_view.h"
-#include "content/public/browser/video_picture_in_picture_window_controller.h"
-#include "content/public/browser/weak_document_ptr.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/input/native_web_keyboard_event.h"
-#include "content/public/test/navigation_simulator.h"
+#include "chrome/browser/ui/autofill/autofill_popup_controller_test_base.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/accessibility/ax_active_popup.h"
@@ -63,41 +18,21 @@
 #include "ui/accessibility/ax_tree_manager_map.h"
 #include "ui/accessibility/platform/ax_platform_node_base.h"
 #include "ui/accessibility/platform/ax_platform_node_delegate.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/events/event.h"
-#include "ui/events/keycodes/dom/dom_code.h"
-#include "ui/events/keycodes/dom/keycode_converter.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/text_utils.h"
 
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "content/public/test/scoped_accessibility_mode_override.h"
 #endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if BUILDFLAG(IS_ANDROID)
-#include "chrome/browser/autofill/mock_manual_filling_view.h"
-#include "chrome/browser/keyboard_accessory/android/manual_filling_controller_impl.h"
-#include "chrome/browser/keyboard_accessory/test_utils/android/mock_address_accessory_controller.h"
-#include "chrome/browser/keyboard_accessory/test_utils/android/mock_credit_card_accessory_controller.h"
-#include "chrome/browser/keyboard_accessory/test_utils/android/mock_password_accessory_controller.h"
-#endif  // BUILDFLAG(IS_ANDROID)
-
 namespace autofill {
+
 namespace {
 
-using base::ASCIIToUTF16;
-using base::WeakPtr;
 using ::testing::_;
-using ::testing::AtLeast;
-using ::testing::Eq;
+using ::testing::AllOf;
 using ::testing::Field;
-using ::testing::Invoke;
 using ::testing::Matcher;
-using ::testing::Mock;
 using ::testing::NiceMock;
-using ::testing::Optional;
 using ::testing::Return;
-using ::testing::StrictMock;
 
 #if !BUILDFLAG(IS_ANDROID)
 Matcher<const AutofillPopupDelegate::SuggestionPosition&>
@@ -109,1139 +44,9 @@
 }
 #endif  // !BUILDFLAG(IS_ANDROID)
 
-class MockAutofillDriver : public ContentAutofillDriver {
- public:
-  MockAutofillDriver(content::RenderFrameHost* rfh,
-                     ContentAutofillDriverFactory* factory)
-      : ContentAutofillDriver(rfh, factory) {}
-
-  MockAutofillDriver(MockAutofillDriver&) = delete;
-  MockAutofillDriver& operator=(MockAutofillDriver&) = delete;
-
-  ~MockAutofillDriver() override = default;
-  MOCK_METHOD(ui::AXTreeID, GetAxTreeId, (), (const override));
-};
-
-class MockAutofillExternalDelegate : public AutofillExternalDelegate {
- public:
-  explicit MockAutofillExternalDelegate(
-      BrowserAutofillManager* autofill_manager)
-      : AutofillExternalDelegate(autofill_manager) {}
-  ~MockAutofillExternalDelegate() override = default;
-
-  void DidSelectSuggestion(const Suggestion& suggestion) override {}
-
-  MOCK_METHOD(void, ClearPreviewedForm, (), (override));
-  MOCK_METHOD(void, OnPopupShown, (), (override));
-  MOCK_METHOD(void, OnPopupHidden, (), (override));
-  MOCK_METHOD(void,
-              DidAcceptSuggestion,
-              (const Suggestion&,
-               const AutofillPopupDelegate::SuggestionPosition&),
-              (override));
-  MOCK_METHOD(void,
-              DidPerformButtonActionForSuggestion,
-              (const Suggestion&),
-              (override));
-  MOCK_METHOD(bool, RemoveSuggestion, (const Suggestion&), (override));
-};
-
-class MockAutofillPopupView : public AutofillPopupView {
- public:
-  MockAutofillPopupView() = default;
-  MockAutofillPopupView(MockAutofillPopupView&) = delete;
-  MockAutofillPopupView& operator=(MockAutofillPopupView&) = delete;
-  ~MockAutofillPopupView() override = default;
-
-  MOCK_METHOD(bool, Show, (AutoselectFirstSuggestion), (override));
-  MOCK_METHOD(void, Hide, (), (override));
-  MOCK_METHOD(bool,
-              HandleKeyPressEvent,
-              (const content::NativeWebKeyboardEvent&),
-              (override));
-  MOCK_METHOD(void, OnSuggestionsChanged, (), (override));
-  MOCK_METHOD(bool, OverlapsWithPictureInPictureWindow, (), (const override));
-  MOCK_METHOD(std::optional<int32_t>, GetAxUniqueId, (), (override));
-  MOCK_METHOD(void, AxAnnounce, (const std::u16string&), (override));
-  MOCK_METHOD(base::WeakPtr<AutofillPopupView>,
-              CreateSubPopupView,
-              (base::WeakPtr<AutofillPopupController>),
-              (override));
-  MOCK_METHOD(std::optional<AutofillClient::PopupScreenLocation>,
-              GetPopupScreenLocation,
-              (),
-              (const override));
-
-  base::WeakPtr<AutofillPopupView> GetWeakPtr() override {
-    return weak_ptr_factory_.GetWeakPtr();
-  }
-
- private:
-  base::WeakPtrFactory<AutofillPopupView> weak_ptr_factory_{this};
-};
-
-class TestAutofillPopupController : public AutofillPopupControllerImpl {
- public:
-  TestAutofillPopupController(
-      base::WeakPtr<AutofillExternalDelegate> external_delegate,
-      content::WebContents* web_contents,
-      const gfx::RectF& element_bounds,
-      base::RepeatingCallback<void(
-          gfx::NativeWindow,
-          Profile*,
-          password_manager::metrics_util::PasswordMigrationWarningTriggers)>
-          show_pwd_migration_warning_callback,
-      std::optional<base::WeakPtr<ExpandablePopupParentControllerImpl>> parent =
-          std::nullopt)
-      : AutofillPopupControllerImpl(
-            external_delegate,
-            web_contents,
-            PopupControllerCommon(element_bounds,
-                                  base::i18n::UNKNOWN_DIRECTION,
-                                  nullptr),
-            /*form_control_ax_id=*/0,
-            std::move(show_pwd_migration_warning_callback),
-            parent) {}
-  ~TestAutofillPopupController() override = default;
-
-  // Making protected functions public for testing
-  using AutofillPopupControllerImpl::AcceptSuggestion;
-  using AutofillPopupControllerImpl::element_bounds;
-  using AutofillPopupControllerImpl::FireControlsChangedEvent;
-  using AutofillPopupControllerImpl::GetLineCount;
-  using AutofillPopupControllerImpl::GetRootAXPlatformNodeForWebContents;
-  using AutofillPopupControllerImpl::GetSuggestionAt;
-  using AutofillPopupControllerImpl::GetSuggestionLabelsAt;
-  using AutofillPopupControllerImpl::GetSuggestionMainTextAt;
-  using AutofillPopupControllerImpl::GetWeakPtr;
-  using AutofillPopupControllerImpl::PerformButtonActionForSuggestion;
-  using AutofillPopupControllerImpl::RemoveSuggestion;
-  using AutofillPopupControllerImpl::SelectSuggestion;
-  MOCK_METHOD(void, Hide, (PopupHidingReason reason), (override));
-  MOCK_METHOD(ui::AXPlatformNode*,
-              GetRootAXPlatformNodeForWebContents,
-              (),
-              (override));
-
-  void DoHide() { DoHide(PopupHidingReason::kTabGone); }
-
-  void DoHide(PopupHidingReason reason) {
-    AutofillPopupControllerImpl::Hide(reason);
-  }
-};
-
-class BrowserAutofillManagerWithMockDelegate : public BrowserAutofillManager {
- public:
-  explicit BrowserAutofillManagerWithMockDelegate(AutofillDriver* driver)
-      : BrowserAutofillManager(driver, "en-US") {
-    test_api(*this).SetExternalDelegate(
-        std::make_unique<NiceMock<MockAutofillExternalDelegate>>(this));
-  }
-
-  BrowserAutofillManagerWithMockDelegate(
-      BrowserAutofillManagerWithMockDelegate&) = delete;
-  BrowserAutofillManagerWithMockDelegate& operator=(
-      BrowserAutofillManagerWithMockDelegate&) = delete;
-
-  ~BrowserAutofillManagerWithMockDelegate() override = default;
-
-  MockAutofillExternalDelegate& external_delegate() {
-    return static_cast<MockAutofillExternalDelegate&>(
-        *test_api(*this).external_delegate());
-  }
-};
-
-class TestContentAutofillClientWithMockController
-    : public TestContentAutofillClient {
- public:
-  explicit TestContentAutofillClientWithMockController(
-      content::WebContents* web_contents)
-      : TestContentAutofillClient(web_contents) {
-    ON_CALL(popup_view(), CreateSubPopupView)
-        .WillByDefault(Return(sub_popup_view().GetWeakPtr()));
-  }
-
-  ~TestContentAutofillClientWithMockController() override { DoHide(); }
-
-  // Returns the current controller. Controllers are specific to the `manager`'s
-  // AutofillExternalDelegate. Therefore, when there are two consecutive
-  // `popup_controller(x)` and `popup_controller(y)`, the second call hides the
-  // old and creates new controller iff `x` and `y` are distinct.
-  TestAutofillPopupController& popup_controller(
-      BrowserAutofillManagerWithMockDelegate& manager) {
-    if (manager_of_last_controller_.get() != &manager) {
-      DoHide();
-      CHECK(!popup_controller_);
-    }
-    if (!popup_controller_) {
-      popup_controller_ = (new NiceMock<TestAutofillPopupController>(
-                               manager.external_delegate().GetWeakPtrForTest(),
-                               &GetWebContents(), gfx::RectF(),
-                               show_pwd_migration_warning_callback_.Get()))
-                              ->GetWeakPtr();
-      popup_controller_->SetViewForTesting(popup_view_->GetWeakPtr());
-      manager_of_last_controller_ = manager.GetWeakPtr();
-      ON_CALL(cast_popup_controller(), Hide)
-          .WillByDefault([this](PopupHidingReason reason) { DoHide(reason); });
-    }
-    return cast_popup_controller();
-  }
-
-  MockAutofillPopupView& popup_view() { return *popup_view_; }
-
-  MockAutofillPopupView& sub_popup_view() { return *sub_popup_view_; }
-
-#if BUILDFLAG(IS_ANDROID)
-  base::MockCallback<base::RepeatingCallback<
-      void(gfx::NativeWindow,
-           Profile*,
-           password_manager::metrics_util::PasswordMigrationWarningTriggers)>>&
-  show_pwd_migration_warning_callback() {
-    return show_pwd_migration_warning_callback_;
-  }
-#endif  // BUILDFLAG(IS_ANDROID)
-
- private:
-  void DoHide(PopupHidingReason reason) {
-    if (popup_controller_) {
-      cast_popup_controller().DoHide(reason);
-    }
-  }
-
-  void DoHide() {
-    if (popup_controller_) {
-      cast_popup_controller().DoHide();
-    }
-  }
-
-  TestAutofillPopupController& cast_popup_controller() {
-    return static_cast<TestAutofillPopupController&>(*popup_controller_);
-  }
-
-  base::WeakPtr<AutofillPopupControllerImpl> popup_controller_;
-  base::WeakPtr<AutofillManager> manager_of_last_controller_;
-
-  std::unique_ptr<MockAutofillPopupView> popup_view_ =
-      std::make_unique<NiceMock<MockAutofillPopupView>>();
-  std::unique_ptr<MockAutofillPopupView> sub_popup_view_ =
-      std::make_unique<NiceMock<MockAutofillPopupView>>();
-  base::MockCallback<base::RepeatingCallback<void(
-      gfx::NativeWindow,
-      Profile*,
-      password_manager::metrics_util::PasswordMigrationWarningTriggers)>>
-      show_pwd_migration_warning_callback_;
-};
-
-content::RenderFrameHost* CreateAndNavigateChildFrame(
-    content::RenderFrameHost* parent,
-    const GURL& url,
-    std::string_view name) {
-  content::RenderFrameHost* rfh =
-      content::RenderFrameHostTester::For(parent)->AppendChild(
-          std::string(name));
-  // ContentAutofillDriverFactory::DidFinishNavigation() creates a driver for
-  // subframes only if
-  // `NavigationHandle::HasSubframeNavigationEntryCommitted()` is true. This
-  // is not the case for the first navigation. (In non-unit-tests, the first
-  // navigation creates a driver in
-  // ContentAutofillDriverFactory::BindAutofillDriver().) Therefore,
-  // we simulate *two* navigations here, and explicitly set the transition
-  // type for the second navigation.
-  std::unique_ptr<content::NavigationSimulator> simulator;
-  // First navigation: `HasSubframeNavigationEntryCommitted() == false`.
-  // Must be a different URL from the second navigation.
-  GURL about_blank("about:blank");
-  CHECK_NE(about_blank, url);
-  simulator =
-      content::NavigationSimulator::CreateRendererInitiated(about_blank, rfh);
-  simulator->Commit();
-  rfh = simulator->GetFinalRenderFrameHost();
-  // Second navigation: `HasSubframeNavigationEntryCommitted() == true`.
-  // Must set the transition type to ui::PAGE_TRANSITION_MANUAL_SUBFRAME.
-  simulator = content::NavigationSimulator::CreateRendererInitiated(url, rfh);
-  simulator->SetTransition(ui::PAGE_TRANSITION_MANUAL_SUBFRAME);
-  simulator->Commit();
-  return simulator->GetFinalRenderFrameHost();
-}
-
-content::RenderFrameHost* NavigateAndCommitFrame(content::RenderFrameHost* rfh,
-                                                 const GURL& url) {
-  std::unique_ptr<content::NavigationSimulator> simulator =
-      content::NavigationSimulator::CreateRendererInitiated(url, rfh);
-  simulator->Commit();
-  return simulator->GetFinalRenderFrameHost();
-}
-
 }  // namespace
 
-class AutofillPopupControllerImplTest : public ChromeRenderViewHostTestHarness {
- public:
-  AutofillPopupControllerImplTest()
-      : ChromeRenderViewHostTestHarness(
-            base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
-  ~AutofillPopupControllerImplTest() override = default;
-
-  void SetUp() override {
-    ChromeRenderViewHostTestHarness::SetUp();
-    PersonalDataManagerFactory::GetInstance()->SetTestingFactory(
-        profile(), base::BindRepeating([](content::BrowserContext* context)
-                                           -> std::unique_ptr<KeyedService> {
-          return std::make_unique<TestPersonalDataManager>();
-        }));
-    NavigateAndCommit(GURL("https://foo.com/"));
-    FocusWebContentsOnMainFrame();
-    ASSERT_TRUE(web_contents()->GetFocusedFrame());
-
-#if BUILDFLAG(IS_ANDROID)
-    ManualFillingControllerImpl::CreateForWebContentsForTesting(
-        web_contents(), mock_pwd_controller_.AsWeakPtr(),
-        mock_address_controller_.AsWeakPtr(), mock_cc_controller_.AsWeakPtr(),
-        std::make_unique<NiceMock<MockManualFillingView>>());
-#endif  // BUILDFLAG(IS_ANDROID)
-  }
-
-  void TearDown() override {
-    // Wait for the pending deletion of the controllers. Otherwise, the
-    // controllers are destroyed after the WebContents, and each of them
-    // receives a final Hide() call for which we'd need to add explicit
-    // expectations.
-    task_environment()->RunUntilIdle();
-    ChromeRenderViewHostTestHarness::TearDown();
-  }
-
-  content::RenderFrameHost* main_frame() {
-    return web_contents()->GetPrimaryMainFrame();
-  }
-
-  TestContentAutofillClientWithMockController& client() {
-    return *autofill_client_injector_[web_contents()];
-  }
-
-  MockAutofillDriver& driver(content::RenderFrameHost* rfh = nullptr) {
-    return *autofill_driver_injector_[rfh ? rfh : main_frame()];
-  }
-
-  BrowserAutofillManagerWithMockDelegate& manager(
-      content::RenderFrameHost* rfh = nullptr) {
-    return *autofill_manager_injector_[rfh ? rfh : main_frame()];
-  }
-
-  TestPersonalDataManager& personal_data() {
-    return static_cast<TestPersonalDataManager&>(
-        *PersonalDataManagerFactory::GetForProfile(profile()));
-  }
-
-  // Shows empty suggestions with the popup_item_id ids passed as
-  // `popup_item_ids`.
-  void ShowSuggestions(
-      BrowserAutofillManagerWithMockDelegate& manager,
-      const std::vector<PopupItemId>& popup_item_ids,
-      AutofillSuggestionTriggerSource trigger_source =
-          AutofillSuggestionTriggerSource::kFormControlElementClicked) {
-    std::vector<Suggestion> suggestions;
-    suggestions.reserve(popup_item_ids.size());
-    for (PopupItemId popup_item_id : popup_item_ids) {
-      suggestions.emplace_back(u"", popup_item_id);
-    }
-    ShowSuggestions(manager, std::move(suggestions), trigger_source);
-  }
-
-  void ShowSuggestions(
-      BrowserAutofillManagerWithMockDelegate& manager,
-      std::vector<Suggestion> suggestions,
-      AutofillSuggestionTriggerSource trigger_source =
-          AutofillSuggestionTriggerSource::kFormControlElementClicked) {
-    FocusWebContentsOnFrame(
-        static_cast<ContentAutofillDriver&>(manager.driver())
-            .render_frame_host());
-    client().popup_controller(manager).Show(std::move(suggestions),
-                                            trigger_source,
-                                            AutoselectFirstSuggestion(false));
-  }
-
-  content::NativeWebKeyboardEvent CreateKeyPressEvent(int windows_key_code) {
-    content::NativeWebKeyboardEvent event(
-        blink::WebInputEvent::Type::kRawKeyDown,
-        blink::WebInputEvent::kNoModifiers,
-        blink::WebInputEvent::GetStaticTimeStampForTests());
-    event.windows_key_code = windows_key_code;
-    return event;
-  }
-
- private:
-  test::AutofillUnitTestEnvironment autofill_test_environment_;
-
-  TestAutofillClientInjector<TestContentAutofillClientWithMockController>
-      autofill_client_injector_;
-  TestAutofillDriverInjector<NiceMock<MockAutofillDriver>>
-      autofill_driver_injector_;
-  TestAutofillManagerInjector<BrowserAutofillManagerWithMockDelegate>
-      autofill_manager_injector_;
-
-#if BUILDFLAG(IS_ANDROID)
-  NiceMock<MockPasswordAccessoryController> mock_pwd_controller_;
-  NiceMock<MockAddressAccessoryController> mock_address_controller_;
-  NiceMock<MockCreditCardAccessoryController> mock_cc_controller_;
-#endif  // BUILDFLAG(IS_ANDROID)
-};
-
-TEST_F(AutofillPopupControllerImplTest, RemoveSuggestion) {
-  ShowSuggestions(manager(),
-                  {PopupItemId::kAddressEntry, PopupItemId::kAddressEntry,
-                   PopupItemId::kAutofillOptions});
-
-  // Generate a popup, so it can be hidden later. It doesn't matter what the
-  // external_delegate thinks is being shown in the process, since we are just
-  // testing the popup here.
-  test::GenerateTestAutofillPopup(&manager().external_delegate());
-  EXPECT_CALL(manager().external_delegate(),
-              RemoveSuggestion(Field(&Suggestion::popup_item_id,
-                                     PopupItemId::kAddressEntry)))
-      .WillRepeatedly(Return(true));
-
-  // Remove the first entry. The popup should be redrawn since its size has
-  // changed.
-  EXPECT_CALL(client().popup_view(), OnSuggestionsChanged());
-  EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion(
-      0,
-      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed));
-  Mock::VerifyAndClearExpectations(&client().popup_view());
-
-  // Remove the next entry. The popup should then be hidden since there are
-  // no Autofill entries left.
-  EXPECT_CALL(client().popup_controller(manager()),
-              Hide(PopupHidingReason::kNoSuggestions));
-  EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion(
-      0,
-      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed));
-}
-
-// Regression test for (crbug.com/1513574): Showing an Autofill Compose
-// suggestion twice does not crash.
-TEST_F(AutofillPopupControllerImplTest, ShowTwice) {
-  ShowSuggestions(manager(),
-                  {Suggestion(u"Help me write", PopupItemId::kCompose)});
-  ShowSuggestions(manager(),
-                  {Suggestion(u"Help me write", PopupItemId::kCompose)});
-}
-
-TEST_F(AutofillPopupControllerImplTest,
-       RemoveAutocompleteSuggestion_AnnounceText) {
-  ShowSuggestions(manager(),
-                  {Suggestion(u"main text", PopupItemId::kAutocompleteEntry)});
-  test::GenerateTestAutofillPopup(&manager().external_delegate());
-
-  EXPECT_CALL(manager().external_delegate(),
-              RemoveSuggestion(Field(&Suggestion::popup_item_id,
-                                     PopupItemId::kAutocompleteEntry)))
-      .WillOnce(Return(true));
-  EXPECT_CALL(client().popup_view(),
-              AxAnnounce(Eq(u"Entry main text has been deleted")));
-  EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion(
-      0,
-      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed));
-}
-
-TEST_F(AutofillPopupControllerImplTest,
-       RemoveAutocompleteSuggestion_IgnoresClickOutsideCheck) {
-  ShowSuggestions(manager(), {PopupItemId::kAutocompleteEntry,
-                              PopupItemId::kAutocompleteEntry});
-
-  // Generate a popup, so it can be hidden later. It doesn't matter what the
-  // external_delegate thinks is being shown in the process, since we are just
-  // testing the popup here.
-  test::GenerateTestAutofillPopup(&manager().external_delegate());
-
-  EXPECT_CALL(manager().external_delegate(),
-              RemoveSuggestion(Field(&Suggestion::popup_item_id,
-                                     PopupItemId::kAutocompleteEntry)))
-      .WillOnce(Return(true));
-  // Remove the first entry. The popup should be redrawn since its size has
-  // changed.
-  EXPECT_CALL(client().popup_view(), OnSuggestionsChanged());
-  EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion(
-      0,
-      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed));
-  Mock::VerifyAndClearExpectations(&client().popup_view());
-
-  EXPECT_TRUE(client()
-                  .popup_controller(manager())
-                  .ShouldIgnoreMouseObservedOutsideItemBoundsCheck());
-}
-
-TEST_F(AutofillPopupControllerImplTest,
-       RemoveAutocompleteSuggestion_NoMetricsEmittedOnFail) {
-  base::HistogramTester histogram_tester;
-  ShowSuggestions(manager(), {PopupItemId::kAutocompleteEntry});
-  test::GenerateTestAutofillPopup(&manager().external_delegate());
-  EXPECT_CALL(manager().external_delegate(),
-              RemoveSuggestion(Field(&Suggestion::popup_item_id,
-                                     PopupItemId::kAutocompleteEntry)))
-      .WillOnce(Return(false));
-
-  EXPECT_FALSE(client().popup_controller(manager()).RemoveSuggestion(
-      0,
-      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed));
-  histogram_tester.ExpectUniqueSample(
-      "Autofill.Autocomplete.SingleEntryRemovalMethod",
-      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed,
-      0);
-  histogram_tester.ExpectUniqueSample(
-      "Autocomplete.Events2",
-      AutofillMetrics::AutocompleteEvent::AUTOCOMPLETE_SUGGESTION_DELETED, 0);
-}
-
-TEST_F(AutofillPopupControllerImplTest,
-       RemoveAutocompleteSuggestion_MetricsEmittedOnSuccess) {
-  base::HistogramTester histogram_tester;
-  ShowSuggestions(manager(), {PopupItemId::kAutocompleteEntry});
-  test::GenerateTestAutofillPopup(&manager().external_delegate());
-  EXPECT_CALL(manager().external_delegate(),
-              RemoveSuggestion(Field(&Suggestion::popup_item_id,
-                                     PopupItemId::kAutocompleteEntry)))
-      .WillOnce(Return(true));
-
-  EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion(
-      0,
-      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed));
-  histogram_tester.ExpectUniqueSample(
-      "Autofill.Autocomplete.SingleEntryRemovalMethod",
-      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed,
-      1);
-  histogram_tester.ExpectUniqueSample(
-      "Autocomplete.Events2",
-      AutofillMetrics::AutocompleteEvent::AUTOCOMPLETE_SUGGESTION_DELETED, 1);
-  // Also no autofill metrics are emitted.
-  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Popup", 1, 0);
-  histogram_tester.ExpectUniqueSample(
-      "Autofill.ProfileDeleted.KeyboardAccessory", 1, 0);
-  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Any", 1, 0);
-}
-
-TEST_F(AutofillPopupControllerImplTest,
-       RemoveAddressSuggestion_ShiftDelete_NoMetricsEmittedOnFail) {
-  base::HistogramTester histogram_tester;
-  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
-  test::GenerateTestAutofillPopup(&manager().external_delegate());
-  EXPECT_CALL(manager().external_delegate(),
-              RemoveSuggestion(Field(&Suggestion::popup_item_id,
-                                     PopupItemId::kAddressEntry)))
-      .WillOnce(Return(false));
-
-  EXPECT_FALSE(client().popup_controller(manager()).RemoveSuggestion(
-      0,
-      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed));
-  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Popup", 1, 0);
-  histogram_tester.ExpectUniqueSample(
-      "Autofill.ProfileDeleted.KeyboardAccessory", 1, 0);
-  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Any", 1, 0);
-}
-
-TEST_F(AutofillPopupControllerImplTest,
-       RemoveAddressSuggestion_ShiftDelete_MetricsEmittedOnSuccess) {
-  base::HistogramTester histogram_tester;
-  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
-  test::GenerateTestAutofillPopup(&manager().external_delegate());
-  EXPECT_CALL(manager().external_delegate(),
-              RemoveSuggestion(Field(&Suggestion::popup_item_id,
-                                     PopupItemId::kAddressEntry)))
-      .WillOnce(Return(true));
-
-  EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion(
-      0,
-      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed));
-  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Popup", 1, 1);
-  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Any", 1, 1);
-  // Also no autocomplete or keyboard accessory metrics are emitted.
-  histogram_tester.ExpectUniqueSample(
-      "Autofill.ProfileDeleted.KeyboardAccessory", 1, 0);
-  histogram_tester.ExpectUniqueSample(
-      "Autofill.Autocomplete.SingleEntryRemovalMethod",
-      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed,
-      0);
-  histogram_tester.ExpectUniqueSample(
-      "Autocomplete.Events2",
-      AutofillMetrics::AutocompleteEvent::AUTOCOMPLETE_SUGGESTION_DELETED, 0);
-}
-
-TEST_F(AutofillPopupControllerImplTest,
-       RemoveAddressSuggestion_KeyboardAccessory_NoMetricsEmittedOnFail) {
-  base::HistogramTester histogram_tester;
-  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
-  test::GenerateTestAutofillPopup(&manager().external_delegate());
-  EXPECT_CALL(manager().external_delegate(),
-              RemoveSuggestion(Field(&Suggestion::popup_item_id,
-                                     PopupItemId::kAddressEntry)))
-      .WillOnce(Return(false));
-
-  EXPECT_FALSE(client().popup_controller(manager()).RemoveSuggestion(
-      0, AutofillMetrics::SingleEntryRemovalMethod::kKeyboardAccessory));
-  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Popup", 1, 0);
-  histogram_tester.ExpectUniqueSample(
-      "Autofill.ProfileDeleted.KeyboardAccessory", 1, 0);
-  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Any", 1, 0);
-}
-
-TEST_F(AutofillPopupControllerImplTest,
-       RemoveAddressSuggestion_KeyboardAccessory_MetricsEmittedOnSuccess) {
-  base::HistogramTester histogram_tester;
-  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
-  test::GenerateTestAutofillPopup(&manager().external_delegate());
-  EXPECT_CALL(manager().external_delegate(),
-              RemoveSuggestion(Field(&Suggestion::popup_item_id,
-                                     PopupItemId::kAddressEntry)))
-      .WillOnce(Return(true));
-
-  EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion(
-      0, AutofillMetrics::SingleEntryRemovalMethod::kKeyboardAccessory));
-  histogram_tester.ExpectUniqueSample(
-      "Autofill.ProfileDeleted.KeyboardAccessory", 1, 1);
-  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Any", 1, 1);
-  // Also no autocomplete or shift+delete metrics are emitted.
-  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Popup", 1, 0);
-  histogram_tester.ExpectUniqueSample(
-      "Autofill.Autocomplete.SingleEntryRemovalMethod",
-      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed,
-      0);
-  histogram_tester.ExpectUniqueSample(
-      "Autocomplete.Events2",
-      AutofillMetrics::AutocompleteEvent::AUTOCOMPLETE_SUGGESTION_DELETED, 0);
-}
-
-TEST_F(AutofillPopupControllerImplTest,
-       RemoveCreditCardSuggestion_NoMetricsEmitted) {
-  base::HistogramTester histogram_tester;
-  ShowSuggestions(manager(), {PopupItemId::kCreditCardEntry});
-  test::GenerateTestAutofillPopup(&manager().external_delegate());
-  EXPECT_CALL(manager().external_delegate(),
-              RemoveSuggestion(Field(&Suggestion::popup_item_id,
-                                     PopupItemId::kCreditCardEntry)))
-      .WillOnce(Return(true));
-
-  EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion(
-      0,
-      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed));
-  histogram_tester.ExpectUniqueSample(
-      "Autofill.Autocomplete.SingleEntryRemovalMethod",
-      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed,
-      0);
-  histogram_tester.ExpectUniqueSample(
-      "Autocomplete.Events2",
-      AutofillMetrics::AutocompleteEvent::AUTOCOMPLETE_SUGGESTION_DELETED, 0);
-  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Popup", 1, 0);
-  histogram_tester.ExpectUniqueSample(
-      "Autofill.ProfileDeleted.KeyboardAccessory", 1, 0);
-  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Any", 1, 0);
-}
-
-TEST_F(AutofillPopupControllerImplTest,
-       ManualFallBackTriggerSource_IgnoresClickOutsideCheck) {
-  ShowSuggestions(manager(), {PopupItemId::kAddressEntry},
-                  AutofillSuggestionTriggerSource::kManualFallbackAddress);
-
-  // Generate a popup, so it can be hidden later. It doesn't matter what the
-  // external_delegate thinks is being shown in the process, since we are just
-  // testing the popup here.
-  test::GenerateTestAutofillPopup(&manager().external_delegate());
-
-  EXPECT_TRUE(client()
-                  .popup_controller(manager())
-                  .ShouldIgnoreMouseObservedOutsideItemBoundsCheck());
-}
-
-TEST_F(AutofillPopupControllerImplTest, UpdateDataListValues) {
-  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
-  std::vector<SelectOption> options = {
-      {.value = u"data list value 1", .content = u"data list label 1"}};
-  client().popup_controller(manager()).UpdateDataListValues(options);
-
-  ASSERT_EQ(3, client().popup_controller(manager()).GetLineCount());
-
-  Suggestion result0 = client().popup_controller(manager()).GetSuggestionAt(0);
-  EXPECT_EQ(options[0].value, result0.main_text.value);
-  EXPECT_EQ(options[0].value,
-            client().popup_controller(manager()).GetSuggestionMainTextAt(0));
-  ASSERT_EQ(1u, result0.labels.size());
-  ASSERT_EQ(1u, result0.labels[0].size());
-  EXPECT_EQ(options[0].content, result0.labels[0][0].value);
-  EXPECT_EQ(std::u16string(), result0.additional_label);
-  EXPECT_EQ(options[0].content, client()
-                                    .popup_controller(manager())
-                                    .GetSuggestionLabelsAt(0)[0][0]
-                                    .value);
-  EXPECT_EQ(PopupItemId::kDatalistEntry, result0.popup_item_id);
-
-  Suggestion result1 = client().popup_controller(manager()).GetSuggestionAt(1);
-  EXPECT_EQ(std::u16string(), result1.main_text.value);
-  EXPECT_TRUE(result1.labels.empty());
-  EXPECT_EQ(std::u16string(), result1.additional_label);
-  EXPECT_EQ(PopupItemId::kSeparator, result1.popup_item_id);
-
-  Suggestion result2 = client().popup_controller(manager()).GetSuggestionAt(2);
-  EXPECT_EQ(std::u16string(), result2.main_text.value);
-  EXPECT_TRUE(result2.labels.empty());
-  EXPECT_EQ(std::u16string(), result2.additional_label);
-  EXPECT_EQ(PopupItemId::kAddressEntry, result2.popup_item_id);
-
-  // Add two data list entries (which should replace the current one).
-  options.push_back(
-      {.value = u"data list value 1", .content = u"data list label 1"});
-  client().popup_controller(manager()).UpdateDataListValues(options);
-  ASSERT_EQ(4, client().popup_controller(manager()).GetLineCount());
-
-  // Original one first, followed by new one, then separator.
-  EXPECT_EQ(
-      options[0].value,
-      client().popup_controller(manager()).GetSuggestionAt(0).main_text.value);
-  EXPECT_EQ(options[0].value,
-            client().popup_controller(manager()).GetSuggestionMainTextAt(0));
-  ASSERT_EQ(
-      1u,
-      client().popup_controller(manager()).GetSuggestionAt(0).labels.size());
-  ASSERT_EQ(
-      1u,
-      client().popup_controller(manager()).GetSuggestionAt(0).labels[0].size());
-  EXPECT_EQ(options[0].content, client()
-                                    .popup_controller(manager())
-                                    .GetSuggestionAt(0)
-                                    .labels[0][0]
-                                    .value);
-  EXPECT_EQ(
-      std::u16string(),
-      client().popup_controller(manager()).GetSuggestionAt(0).additional_label);
-  EXPECT_EQ(
-      options[1].value,
-      client().popup_controller(manager()).GetSuggestionAt(1).main_text.value);
-  EXPECT_EQ(options[1].value,
-            client().popup_controller(manager()).GetSuggestionMainTextAt(1));
-  ASSERT_EQ(
-      1u,
-      client().popup_controller(manager()).GetSuggestionAt(1).labels.size());
-  ASSERT_EQ(
-      1u,
-      client().popup_controller(manager()).GetSuggestionAt(1).labels[0].size());
-  EXPECT_EQ(options[1].content, client()
-                                    .popup_controller(manager())
-                                    .GetSuggestionAt(1)
-                                    .labels[0][0]
-                                    .value);
-  EXPECT_EQ(
-      std::u16string(),
-      client().popup_controller(manager()).GetSuggestionAt(1).additional_label);
-  EXPECT_EQ(
-      PopupItemId::kSeparator,
-      client().popup_controller(manager()).GetSuggestionAt(2).popup_item_id);
-
-  // Clear all data list values.
-  options.clear();
-  client().popup_controller(manager()).UpdateDataListValues(options);
-
-  ASSERT_EQ(1, client().popup_controller(manager()).GetLineCount());
-  EXPECT_EQ(
-      PopupItemId::kAddressEntry,
-      client().popup_controller(manager()).GetSuggestionAt(0).popup_item_id);
-}
-
-TEST_F(AutofillPopupControllerImplTest, PopupsWithOnlyDataLists) {
-  // Create the popup with a single datalist element.
-  ShowSuggestions(manager(), {PopupItemId::kDatalistEntry});
-
-  // Replace the datalist element with a new one.
-  std::vector<SelectOption> options = {
-      {.value = u"data list value 1", .content = u"data list label 1"}};
-  client().popup_controller(manager()).UpdateDataListValues(options);
-
-  ASSERT_EQ(1, client().popup_controller(manager()).GetLineCount());
-  EXPECT_EQ(
-      options[0].value,
-      client().popup_controller(manager()).GetSuggestionAt(0).main_text.value);
-  ASSERT_EQ(
-      1u,
-      client().popup_controller(manager()).GetSuggestionAt(0).labels.size());
-  ASSERT_EQ(
-      1u,
-      client().popup_controller(manager()).GetSuggestionAt(0).labels[0].size());
-  EXPECT_EQ(options[0].content, client()
-                                    .popup_controller(manager())
-                                    .GetSuggestionAt(0)
-                                    .labels[0][0]
-                                    .value);
-  EXPECT_EQ(
-      std::u16string(),
-      client().popup_controller(manager()).GetSuggestionAt(0).additional_label);
-  EXPECT_EQ(
-      PopupItemId::kDatalistEntry,
-      client().popup_controller(manager()).GetSuggestionAt(0).popup_item_id);
-
-  // Clear datalist values and check that the popup becomes hidden.
-  EXPECT_CALL(client().popup_controller(manager()),
-              Hide(PopupHidingReason::kNoSuggestions));
-  options.clear();
-  client().popup_controller(manager()).UpdateDataListValues(options);
-}
-
-TEST_F(AutofillPopupControllerImplTest, GetOrCreate) {
-  auto create_controller = [&](gfx::RectF bounds) {
-    return AutofillPopupControllerImpl::GetOrCreate(
-        client().popup_controller(manager()).GetWeakPtr(),
-        manager().external_delegate().GetWeakPtrForTest(), nullptr,
-        PopupControllerCommon(std::move(bounds), base::i18n::UNKNOWN_DIRECTION,
-                              nullptr),
-        /*form_control_ax_id=*/0);
-  };
-  WeakPtr<AutofillPopupControllerImpl> controller =
-      create_controller(gfx::RectF());
-  EXPECT_TRUE(controller);
-
-  controller->Hide(PopupHidingReason::kViewDestroyed);
-  EXPECT_FALSE(controller);
-
-  controller = create_controller(gfx::RectF());
-  EXPECT_TRUE(controller);
-
-  WeakPtr<AutofillPopupControllerImpl> controller2 =
-      create_controller(gfx::RectF());
-  EXPECT_EQ(controller.get(), controller2.get());
-
-  controller->Hide(PopupHidingReason::kViewDestroyed);
-  EXPECT_FALSE(controller);
-  EXPECT_FALSE(controller2);
-
-  EXPECT_CALL(client().popup_controller(manager()),
-              Hide(PopupHidingReason::kViewDestroyed));
-  gfx::RectF bounds(0.f, 0.f, 1.f, 2.f);
-  base::WeakPtr<AutofillPopupControllerImpl> controller3 =
-      create_controller(bounds);
-  EXPECT_EQ(&client().popup_controller(manager()), controller3.get());
-  EXPECT_EQ(bounds, static_cast<AutofillPopupController*>(controller3.get())
-                        ->element_bounds());
-  controller3->Hide(PopupHidingReason::kViewDestroyed);
-
-  client().popup_controller(manager()).DoHide();
-
-  const base::WeakPtr<AutofillPopupControllerImpl> controller4 =
-      create_controller(bounds);
-  EXPECT_EQ(&client().popup_controller(manager()), controller4.get());
-  EXPECT_EQ(bounds,
-            static_cast<const AutofillPopupController*>(controller4.get())
-                ->element_bounds());
-
-  client().popup_controller(manager()).DoHide();
-}
-
-TEST_F(AutofillPopupControllerImplTest, ProperlyResetController) {
-  ShowSuggestions(manager(), {PopupItemId::kAutocompleteEntry,
-                              PopupItemId::kAutocompleteEntry});
-
-  // Now show a new popup with the same controller, but with fewer items.
-  WeakPtr<AutofillPopupControllerImpl> controller =
-      AutofillPopupControllerImpl::GetOrCreate(
-          client().popup_controller(manager()).GetWeakPtr(),
-          manager().external_delegate().GetWeakPtrForTest(), nullptr,
-          PopupControllerCommon(gfx::RectF(), base::i18n::UNKNOWN_DIRECTION,
-                                nullptr),
-          /*form_control_ax_id=*/0);
-  EXPECT_EQ(0, controller->GetLineCountForTesting());
-}
-
-TEST_F(AutofillPopupControllerImplTest, UnselectingClearsPreview) {
-  EXPECT_CALL(manager().external_delegate(), ClearPreviewedForm());
-  client().popup_controller(manager()).UnselectSuggestion();
-}
-
-TEST_F(AutofillPopupControllerImplTest, HidingClearsPreview) {
-  EXPECT_CALL(manager().external_delegate(), ClearPreviewedForm());
-  EXPECT_CALL(manager().external_delegate(), OnPopupHidden());
-  client().popup_controller(manager()).DoHide();
-}
-
-TEST_F(AutofillPopupControllerImplTest, DontHideWhenWaitingForData) {
-  EXPECT_CALL(client().popup_view(), Hide).Times(0);
-  client().popup_controller(manager()).PinView();
-
-  // Hide() will not work for stale data or when focusing native UI.
-  client().popup_controller(manager()).DoHide(PopupHidingReason::kStaleData);
-  client().popup_controller(manager()).DoHide(PopupHidingReason::kEndEditing);
-
-  // Check the expectations now since TearDown will perform a successful hide.
-  Mock::VerifyAndClearExpectations(&manager().external_delegate());
-  Mock::VerifyAndClearExpectations(&client().popup_view());
-}
-
-TEST_F(AutofillPopupControllerImplTest, ShouldReportHidingPopupReason) {
-  base::HistogramTester histogram_tester;
-  client().popup_controller(manager()).DoHide(PopupHidingReason::kTabGone);
-  histogram_tester.ExpectTotalCount("Autofill.PopupHidingReason", 1);
-  histogram_tester.ExpectBucketCount("Autofill.PopupHidingReason",
-                                     /*kTabGone=*/8, 1);
-}
-
-// This is a regression test for crbug.com/521133 to ensure that we don't crash
-// when suggestions updates race with user selections.
-TEST_F(AutofillPopupControllerImplTest, SelectInvalidSuggestion) {
-  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
-
-  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion).Times(0);
-
-  // The following should not crash:
-  client().popup_controller(manager()).AcceptSuggestion(
-      /*index=*/1);  // Out of bounds!
-}
-
-TEST_F(AutofillPopupControllerImplTest, AcceptSuggestionRespectsTimeout) {
-  base::HistogramTester histogram_tester;
-  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
-
-  // Calls before the threshold are ignored.
-  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion).Times(0);
-  client().popup_controller(manager()).AcceptSuggestion(0);
-  task_environment()->FastForwardBy(base::Milliseconds(100));
-  client().popup_controller(manager()).AcceptSuggestion(/*index=*/0);
-
-  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion);
-  task_environment()->FastForwardBy(base::Milliseconds(400));
-  client().popup_controller(manager()).AcceptSuggestion(/*index=*/0);
-
-  histogram_tester.ExpectTotalCount(
-      "Autofill.Popup.AcceptanceDelayThresholdNotMet", 2);
-}
-
-TEST_F(AutofillPopupControllerImplTest,
-       AcceptSuggestionTimeoutIsUpdatedOnPopupMove) {
-  base::HistogramTester histogram_tester;
-  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
-
-  // Calls before the threshold are ignored.
-  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion).Times(0);
-  client().popup_controller(manager()).AcceptSuggestion(/*index=*/0);
-  task_environment()->FastForwardBy(base::Milliseconds(100));
-  client().popup_controller(manager()).AcceptSuggestion(/*index=*/0);
-
-  histogram_tester.ExpectTotalCount(
-      "Autofill.Popup.AcceptanceDelayThresholdNotMet", 2);
-  task_environment()->FastForwardBy(base::Milliseconds(400));
-  // Show the suggestions again (simulating, e.g., a click somewhere slightly
-  // different).
-  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
-
-  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion).Times(0);
-  client().popup_controller(manager()).AcceptSuggestion(/*index=*/0);
-  histogram_tester.ExpectTotalCount(
-      "Autofill.Popup.AcceptanceDelayThresholdNotMet", 3);
-
-  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion);
-  // After waiting, suggestions are accepted again.
-  task_environment()->FastForwardBy(base::Milliseconds(500));
-  client().popup_controller(manager()).AcceptSuggestion(/*index=*/0);
-  histogram_tester.ExpectTotalCount(
-      "Autofill.Popup.AcceptanceDelayThresholdNotMet", 3);
-}
-
-// Tests that when a picture-in-picture window is initialized, there is a call
-// to the popup view to check if the autofill popup bounds overlap with the
-// picture-in-picture window.
-TEST_F(AutofillPopupControllerImplTest,
-       CheckBoundsOverlapWithPictureInPicture) {
-  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
-  PictureInPictureWindowManager* picture_in_picture_window_manager =
-      PictureInPictureWindowManager::GetInstance();
-  EXPECT_CALL(client().popup_view(), OverlapsWithPictureInPictureWindow);
-  picture_in_picture_window_manager->NotifyObserversOnEnterPictureInPicture();
-}
-
-TEST_F(AutofillPopupControllerImplTest,
-       GetRemovalConfirmationText_UnrelatedPopupItemId) {
-  std::u16string title;
-  std::u16string body;
-  ShowSuggestions(
-      manager(),
-      {Suggestion(u"Entry", PopupItemId::kAddressFieldByFieldFilling)});
-
-  EXPECT_FALSE(client().popup_controller(manager()).GetRemovalConfirmationText(
-      0, &title, &body));
-}
-
-TEST_F(AutofillPopupControllerImplTest,
-       GetRemovalConfirmationText_InvalidUniqueId) {
-  std::u16string title;
-  std::u16string body;
-  ShowSuggestions(manager(), {test::CreateAutofillSuggestion(
-                                 PopupItemId::kAddressFieldByFieldFilling,
-                                 u"Entry", Suggestion::Guid("1111"))});
-
-  EXPECT_FALSE(client().popup_controller(manager()).GetRemovalConfirmationText(
-      0, &title, &body));
-}
-
-TEST_F(AutofillPopupControllerImplTest,
-       GetRemovalConfirmationText_Autocomplete) {
-  std::u16string title;
-  std::u16string body;
-  ShowSuggestions(manager(), {Suggestion(u"Autocomplete entry",
-                                         PopupItemId::kAutocompleteEntry)});
-
-  EXPECT_TRUE(client().popup_controller(manager()).GetRemovalConfirmationText(
-      0, &title, &body));
-  EXPECT_EQ(title, u"Autocomplete entry");
-  EXPECT_EQ(body,
-            l10n_util::GetStringUTF16(
-                IDS_AUTOFILL_DELETE_AUTOCOMPLETE_SUGGESTION_CONFIRMATION_BODY));
-}
-
-TEST_F(AutofillPopupControllerImplTest,
-       GetRemovalConfirmationText_LocalCreditCard) {
-  CreditCard local_card = test::GetCreditCard();
-  personal_data().AddCreditCard(local_card);
-
-  std::u16string title;
-  std::u16string body;
-  ShowSuggestions(manager(),
-                  {test::CreateAutofillSuggestion(
-                      PopupItemId::kCreditCardEntry, u"Local credit card",
-                      Suggestion::Guid(local_card.guid()))});
-
-  EXPECT_TRUE(client().popup_controller(manager()).GetRemovalConfirmationText(
-      0, &title, &body));
-  EXPECT_EQ(title, local_card.CardNameAndLastFourDigits());
-  EXPECT_EQ(body,
-            l10n_util::GetStringUTF16(
-                IDS_AUTOFILL_DELETE_CREDIT_CARD_SUGGESTION_CONFIRMATION_BODY));
-}
-
-TEST_F(AutofillPopupControllerImplTest,
-       GetRemovalConfirmationText_ServerCreditCard) {
-  CreditCard server_card = test::GetMaskedServerCard();
-  personal_data().AddServerCreditCard(server_card);
-
-  std::u16string title;
-  std::u16string body;
-  ShowSuggestions(manager(),
-                  {test::CreateAutofillSuggestion(
-                      PopupItemId::kCreditCardEntry, u"Server credit card",
-                      Suggestion::Guid(server_card.guid()))});
-
-  EXPECT_FALSE(client().popup_controller(manager()).GetRemovalConfirmationText(
-      0, &title, &body));
-}
-
-TEST_F(AutofillPopupControllerImplTest,
-       GetRemovalConfirmationText_CompleteAutofillProfile) {
-  AutofillProfile complete_profile = test::GetFullProfile();
-  personal_data().AddProfile(complete_profile);
-
-  std::u16string title;
-  std::u16string body;
-  ShowSuggestions(manager(),
-                  {test::CreateAutofillSuggestion(
-                      PopupItemId::kAddressEntry, u"Complete autofill profile",
-                      Suggestion::Guid(complete_profile.guid()))});
-
-  EXPECT_TRUE(client().popup_controller(manager()).GetRemovalConfirmationText(
-      0, &title, &body));
-  EXPECT_EQ(title, complete_profile.GetRawInfo(ADDRESS_HOME_CITY));
-  EXPECT_EQ(body,
-            l10n_util::GetStringUTF16(
-                IDS_AUTOFILL_DELETE_PROFILE_SUGGESTION_CONFIRMATION_BODY));
-}
-
-TEST_F(AutofillPopupControllerImplTest,
-       GetRemovalConfirmationText_AutofillProfile_EmptyCity) {
-  AutofillProfile profile = test::GetFullProfile();
-  profile.ClearFields({ADDRESS_HOME_CITY});
-  personal_data().AddProfile(profile);
-
-  std::u16string title;
-  std::u16string body;
-  ShowSuggestions(manager(), {test::CreateAutofillSuggestion(
-                                 PopupItemId::kAddressEntry,
-                                 u"Autofill profile without city",
-                                 Suggestion::Guid(profile.guid()))});
-
-  EXPECT_TRUE(client().popup_controller(manager()).GetRemovalConfirmationText(
-      0, &title, &body));
-  EXPECT_EQ(title, u"Autofill profile without city");
-  EXPECT_EQ(body,
-            l10n_util::GetStringUTF16(
-                IDS_AUTOFILL_DELETE_PROFILE_SUGGESTION_CONFIRMATION_BODY));
-}
-
-#if BUILDFLAG(IS_ANDROID)
-TEST_F(AutofillPopupControllerImplTest,
-       AcceptPwdSuggestionInvokesWarningAndroid) {
-  base::test::ScopedFeatureList scoped_feature_list(
-      password_manager::features::
-          kUnifiedPasswordManagerLocalPasswordsMigrationWarning);
-  ShowSuggestions(manager(), {PopupItemId::kPasswordEntry});
-
-  // Calls are accepted immediately.
-  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion).Times(1);
-  EXPECT_CALL(client().show_pwd_migration_warning_callback(),
-              Run(_, _,
-                  password_manager::metrics_util::
-                      PasswordMigrationWarningTriggers::kKeyboardAcessoryBar));
-  task_environment()->FastForwardBy(base::Milliseconds(500));
-  client().popup_controller(manager()).AcceptSuggestion(0);
-}
-
-TEST_F(AutofillPopupControllerImplTest,
-       AcceptUsernameSuggestionInvokesWarningAndroid) {
-  base::test::ScopedFeatureList scoped_feature_list(
-      password_manager::features::
-          kUnifiedPasswordManagerLocalPasswordsMigrationWarning);
-  ShowSuggestions(manager(), {PopupItemId::kPasswordEntry});
-
-  // Calls are accepted immediately.
-  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion).Times(1);
-  EXPECT_CALL(client().show_pwd_migration_warning_callback(), Run);
-  task_environment()->FastForwardBy(base::Milliseconds(500));
-  client().popup_controller(manager()).AcceptSuggestion(0);
-}
-
-TEST_F(AutofillPopupControllerImplTest,
-       AcceptPwdSuggestionNoWarningIfDisabledAndroid) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndDisableFeature(
-      password_manager::features::
-          kUnifiedPasswordManagerLocalPasswordsMigrationWarning);
-  ShowSuggestions(manager(), {PopupItemId::kPasswordEntry});
-
-  // Calls are accepted immediately.
-  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion).Times(1);
-  EXPECT_CALL(client().show_pwd_migration_warning_callback(), Run).Times(0);
-  task_environment()->FastForwardBy(base::Milliseconds(500));
-  client().popup_controller(manager()).AcceptSuggestion(0);
-}
-
-TEST_F(AutofillPopupControllerImplTest, AcceptAddressNoPwdWarningAndroid) {
-  base::test::ScopedFeatureList scoped_feature_list(
-      password_manager::features::
-          kUnifiedPasswordManagerLocalPasswordsMigrationWarning);
-  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
-
-  // Calls are accepted immediately.
-  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion).Times(1);
-  EXPECT_CALL(client().show_pwd_migration_warning_callback(), Run).Times(0);
-  task_environment()->FastForwardBy(base::Milliseconds(500));
-  client().popup_controller(manager()).AcceptSuggestion(0);
-}
-
-// When a suggestion is accepted, the popup is hidden inside
-// `delegate->DidAcceptSuggestion()`. On Android, some code is still being
-// executed after hiding. This test makes sure no use-after-free, null pointer
-// dereferencing or other memory violations occur.
-TEST_F(AutofillPopupControllerImplTest, AcceptSuggestionIsMemorySafe) {
-  ShowSuggestions(manager(), {PopupItemId::kPasswordEntry});
-  task_environment()->FastForwardBy(base::Milliseconds(500));
-
-  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion)
-      .WillOnce([this]() {
-        client().popup_controller(manager()).Hide(
-            PopupHidingReason::kAcceptSuggestion);
-      });
-  client().popup_controller(manager()).AcceptSuggestion(/*index=*/0);
-}
-
-#endif  // BUILDFLAG(IS_ANDROID)
+using AutofillPopupControllerImplTest = AutofillPopupControllerTestBase<>;
 
 #if !BUILDFLAG(IS_ANDROID)
 TEST_F(AutofillPopupControllerImplTest, SubPopupIsCreatedWithViewFromParent) {
@@ -1312,41 +117,47 @@
 }
 #endif  // !BUILDFLAG(IS_ANDROID)
 
-// Tests that the popup controller queries the view for its screen location.
-TEST_F(AutofillPopupControllerImplTest, GetPopupScreenLocationCallsView) {
-  ShowSuggestions(manager(), {PopupItemId::kCompose});
-
-  using PopupScreenLocation = AutofillClient::PopupScreenLocation;
-  constexpr gfx::Rect kSampleRect = gfx::Rect(123, 234);
-  EXPECT_CALL(client().popup_view(), GetPopupScreenLocation)
-      .WillOnce(Return(PopupScreenLocation{.bounds = kSampleRect}));
-  EXPECT_THAT(client().popup_controller(manager()).GetPopupScreenLocation(),
-              Optional(Field(&PopupScreenLocation::bounds, kSampleRect)));
-}
-
-// Tests that a change to a text field hides a popup with a Compose suggestion.
-TEST_F(AutofillPopupControllerImplTest, HidesOnFieldChangeForComposeEntries) {
-  ShowSuggestions(manager(), {PopupItemId::kCompose});
-  EXPECT_CALL(client().popup_controller(manager()),
-              Hide(PopupHidingReason::kFieldValueChanged));
-  manager().NotifyObservers(
-      &AutofillManager::Observer::OnBeforeTextFieldDidChange, FormGlobalId(),
-      FieldGlobalId());
-}
-
-// Tests that a change to a text field does not hide a popup with an
-// Autocomplete suggestion.
 TEST_F(AutofillPopupControllerImplTest,
-       DoeNotHideOnFieldChangeForNonComposeEntries) {
-  ShowSuggestions(manager(), {PopupItemId::kAutocompleteEntry});
-  EXPECT_CALL(client().popup_controller(manager()), Hide).Times(0);
-  manager().NotifyObservers(
-      &AutofillManager::Observer::OnBeforeTextFieldDidChange, FormGlobalId(),
-      FieldGlobalId());
-  Mock::VerifyAndClearExpectations(&client().popup_controller(manager()));
+       ManualFallBackTriggerSource_IgnoresClickOutsideCheck) {
+  ShowSuggestions(manager(), {PopupItemId::kAddressEntry},
+                  AutofillSuggestionTriggerSource::kManualFallbackAddress);
+
+  // Generate a popup, so it can be hidden later. It doesn't matter what the
+  // external_delegate thinks is being shown in the process, since we are just
+  // testing the popup here.
+  test::GenerateTestAutofillPopup(&manager().external_delegate());
+
+  EXPECT_TRUE(client()
+                  .popup_controller(manager())
+                  .ShouldIgnoreMouseObservedOutsideItemBoundsCheck());
 }
 
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
+namespace {
+
+class MockAutofillDriver : public ContentAutofillDriver {
+ public:
+  using ContentAutofillDriver::ContentAutofillDriver;
+
+  MockAutofillDriver(MockAutofillDriver&) = delete;
+  MockAutofillDriver& operator=(MockAutofillDriver&) = delete;
+
+  ~MockAutofillDriver() override = default;
+  MOCK_METHOD(ui::AXTreeID, GetAxTreeId, (), (const override));
+};
+
+class AutofillPopupControllerForPopupAxTest
+    : public AutofillPopupControllerForPopupTest {
+ public:
+  using AutofillPopupControllerForPopupTest::
+      AutofillPopupControllerForPopupTest;
+
+  MOCK_METHOD(ui::AXPlatformNode*,
+              GetRootAXPlatformNodeForWebContents,
+              (),
+              (override));
+};
+
 class MockAxTreeManager : public ui::AXTreeManager {
  public:
   MockAxTreeManager() = default;
@@ -1396,8 +207,14 @@
   MOCK_METHOD(ui::AXPlatformNodeDelegate*, GetDelegate, (), (const override));
 };
 
+}  // namespace
+
+using AutofillPopupControllerImplTestAccessibilityBase =
+    AutofillPopupControllerTestBase<
+        NiceMock<AutofillPopupControllerForPopupAxTest>,
+        NiceMock<MockAutofillDriver>>;
 class AutofillPopupControllerImplTestAccessibility
-    : public AutofillPopupControllerImplTest {
+    : public AutofillPopupControllerImplTestAccessibilityBase {
  public:
   static constexpr int kAxUniqueId = 123;
 
@@ -1410,7 +227,7 @@
   ~AutofillPopupControllerImplTestAccessibility() override = default;
 
   void SetUp() override {
-    AutofillPopupControllerImplTest::SetUp();
+    AutofillPopupControllerImplTestAccessibilityBase::SetUp();
 
     ON_CALL(driver(), GetAxTreeId()).WillByDefault(Return(test_tree_id_));
     ON_CALL(client().popup_controller(manager()),
@@ -1429,7 +246,7 @@
     // `kScreenReader` causes mocked functions to get called  with
     // `mock_ax_platform_node_delegate` after it has been destroyed.
     accessibility_mode_override_.ResetMode();
-    AutofillPopupControllerImplTest::TearDown();
+    AutofillPopupControllerImplTestAccessibilityBase::TearDown();
   }
 
  protected:
@@ -1473,7 +290,7 @@
 TEST_F(AutofillPopupControllerImplTestAccessibility,
        FireControlsChangedEventNoPopupAxUniqueId) {
   EXPECT_CALL(client().popup_view(), GetAxUniqueId)
-      .WillOnce(testing::Return(std::nullopt));
+      .WillOnce(Return(std::nullopt));
 
   ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
   // Manually fire the event for popup show since setting the test view results
@@ -1483,179 +300,4 @@
 }
 #endif
 
-class AutofillPopupControllerImplTestHidingLogic
-    : public AutofillPopupControllerImplTest {
- public:
-  void SetUp() override {
-    AutofillPopupControllerImplTest::SetUp();
-#if !BUILDFLAG(IS_ANDROID)
-#endif  // BUILDFLAG(IS_ANDROID)
-    sub_frame_ = CreateAndNavigateChildFrame(
-                     main_frame(), GURL("https://bar.com"), "sub_frame")
-                     ->GetWeakDocumentPtr();
-  }
-
-  void TearDown() override {
-    AutofillPopupControllerImplTest::TearDown();
-  }
-
-  BrowserAutofillManagerWithMockDelegate& sub_manager() {
-    return manager(sub_frame());
-  }
-
-  content::RenderFrameHost* sub_frame() {
-    return sub_frame_.AsRenderFrameHostIfValid();
-  }
-
- private:
-  content::WeakDocumentPtr sub_frame_;
-};
-
-// Tests that if the popup is shown in the *main frame*, destruction of the
-// *sub frame* does not hide the popup.
-TEST_F(AutofillPopupControllerImplTestHidingLogic,
-       KeepOpenInMainFrameOnSubFrameDestruction) {
-  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
-  test::GenerateTestAutofillPopup(&manager().external_delegate());
-  EXPECT_CALL(client().popup_controller(manager()), Hide).Times(0);
-  content::RenderFrameHostTester::For(sub_frame())->Detach();
-  // Verify and clear before TearDown() closes the popup.
-  Mock::VerifyAndClearExpectations(&client().popup_controller(manager()));
-}
-
-// Tests that if the popup is shown in the *main frame*, a navigation in the
-// *sub frame* does not hide the popup.
-TEST_F(AutofillPopupControllerImplTestHidingLogic,
-       KeepOpenInMainFrameOnSubFrameNavigation) {
-  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
-  test::GenerateTestAutofillPopup(&manager().external_delegate());
-  EXPECT_CALL(client().popup_controller(manager()), Hide).Times(0);
-  NavigateAndCommitFrame(sub_frame(), GURL("https://bar.com/"));
-  // Verify and clear before TearDown() closes the popup.
-  Mock::VerifyAndClearExpectations(&client().popup_controller(manager()));
-}
-
-// Tests that if the popup is shown, destruction of the WebContents hides the
-// popup.
-TEST_F(AutofillPopupControllerImplTestHidingLogic, HideOnWebContentsDestroyed) {
-  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
-  test::GenerateTestAutofillPopup(&manager().external_delegate());
-  EXPECT_CALL(client().popup_controller(manager()),
-              Hide(PopupHidingReason::kRendererEvent));
-  DeleteContents();
-}
-
-// Tests that if the popup is shown in the *main frame*, destruction of the
-// *main frame* hides the popup.
-TEST_F(AutofillPopupControllerImplTestHidingLogic,
-       HideInMainFrameOnDestruction) {
-  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
-  test::GenerateTestAutofillPopup(&manager().external_delegate());
-  EXPECT_CALL(client().popup_controller(manager()),
-              Hide(PopupHidingReason::kRendererEvent));
-}
-
-// Tests that if the popup is shown in the *sub frame*, destruction of the
-// *sub frame* hides the popup.
-TEST_F(AutofillPopupControllerImplTestHidingLogic,
-       HideInSubFrameOnDestruction) {
-  ShowSuggestions(sub_manager(), {PopupItemId::kAddressEntry});
-  test::GenerateTestAutofillPopup(&sub_manager().external_delegate());
-  EXPECT_CALL(client().popup_controller(sub_manager()),
-              Hide(PopupHidingReason::kRendererEvent));
-  content::RenderFrameHostTester::For(sub_frame())->Detach();
-  // Verify and clear before TearDown() closes the popup.
-  Mock::VerifyAndClearExpectations(&client().popup_controller(sub_manager()));
-}
-
-// Tests that if the popup is shown in the *main frame*, a navigation in the
-// *main frame* hides the popup.
-TEST_F(AutofillPopupControllerImplTestHidingLogic,
-       HideInMainFrameOnMainFrameNavigation) {
-  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
-  test::GenerateTestAutofillPopup(&manager().external_delegate());
-  EXPECT_CALL(client().popup_controller(manager()),
-              Hide(PopupHidingReason::kNavigation));
-  NavigateAndCommitFrame(main_frame(), GURL("https://bar.com/"));
-  // Verify and clear before TearDown() closes the popup.
-  Mock::VerifyAndClearExpectations(&client().popup_controller(manager()));
-}
-
-// Tests that if the popup is shown in the *sub frame*, a navigation in the
-// *sub frame* hides the popup.
-TEST_F(AutofillPopupControllerImplTestHidingLogic,
-       HideInSubFrameOnSubFrameNavigation) {
-  ShowSuggestions(sub_manager(), {PopupItemId::kAddressEntry});
-  test::GenerateTestAutofillPopup(&sub_manager().external_delegate());
-  if (sub_frame()->ShouldChangeRenderFrameHostOnSameSiteNavigation()) {
-    // If the RenderFrameHost changes, a RenderFrameDeleted will fire first.
-    EXPECT_CALL(client().popup_controller(sub_manager()),
-                Hide(PopupHidingReason::kRendererEvent));
-  } else {
-    EXPECT_CALL(client().popup_controller(sub_manager()),
-                Hide(PopupHidingReason::kNavigation));
-  }
-  NavigateAndCommitFrame(sub_frame(), GURL("https://bar.com/"));
-  // Verify and clear before TearDown() closes the popup.
-  Mock::VerifyAndClearExpectations(&client().popup_controller(sub_manager()));
-}
-
-// Tests that if the popup is shown in the *sub frame*, a navigation in the
-// *main frame* hides the popup.
-//
-// TODO(crbug.com/1519872): This test only makes little sense: with BFcache, the
-// navigation doesn't destroy the `sub_frame()` and thus we wouldn't hide the
-// popup. What hides the popup in reality is
-// AutofillExternalDelegate::DidEndTextFieldEditing().
-TEST_F(AutofillPopupControllerImplTestHidingLogic,
-       HideInSubFrameOnMainFrameNavigation) {
-  ShowSuggestions(sub_manager(), {PopupItemId::kAddressEntry});
-  test::GenerateTestAutofillPopup(&sub_manager().external_delegate());
-  EXPECT_CALL(client().popup_controller(sub_manager()),
-              Hide(PopupHidingReason::kRendererEvent));
-  NavigateAndCommitFrame(main_frame(), GURL("https://bar.com/"));
-}
-
-// Tests that Compose saved state notification popup gets hidden after 2
-// seconds, but not after 1 second.
-TEST_F(AutofillPopupControllerImplTestHidingLogic,
-       TimedHideComposeSavedStateNotification) {
-  ShowSuggestions(manager(), {PopupItemId::kComposeSavedStateNotification});
-  test::GenerateTestAutofillPopup(&manager().external_delegate());
-  ::testing::MockFunction<void()> check;
-  {
-    ::testing::InSequence s;
-    EXPECT_CALL(check, Call);
-    EXPECT_CALL(client().popup_controller(manager()),
-                Hide(PopupHidingReason::kFadeTimerExpired));
-  }
-  task_environment()->FastForwardBy(base::Seconds(1));
-  check.Call();
-  task_environment()->FastForwardBy(base::Seconds(1));
-  Mock::VerifyAndClearExpectations(&client().popup_controller(manager()));
-}
-
-#if !BUILDFLAG(IS_ANDROID)
-// Tests that if the popup is shown in the *main frame*, changing the zoom hides
-// the popup.
-TEST_F(AutofillPopupControllerImplTestHidingLogic,
-       HideInMainFrameOnZoomChange) {
-  zoom::ZoomController::CreateForWebContents(web_contents());
-  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
-  test::GenerateTestAutofillPopup(&manager().external_delegate());
-  // Triggered by OnZoomChanged().
-  EXPECT_CALL(client().popup_controller(manager()),
-              Hide(PopupHidingReason::kContentAreaMoved));
-  // Override the default ON_CALL behavior to do nothing to avoid destroying the
-  // hide helper. We want to test ZoomObserver events explicitly.
-  EXPECT_CALL(client().popup_controller(manager()),
-              Hide(PopupHidingReason::kWidgetChanged))
-      .WillOnce(Return());
-  auto* zoom_controller = zoom::ZoomController::FromWebContents(web_contents());
-  zoom_controller->SetZoomLevel(zoom_controller->GetZoomLevel() + 1.0);
-  // Verify and clear before TearDown() closes the popup.
-  Mock::VerifyAndClearExpectations(&client().popup_controller(manager()));
-}
-#endif  // BUILDFLAG(IS_ANDROID)
-
 }  // namespace autofill
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_test_base.cc b/chrome/browser/ui/autofill/autofill_popup_controller_test_base.cc
new file mode 100644
index 0000000..8ce9d3b
--- /dev/null
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_test_base.cc
@@ -0,0 +1,43 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/autofill/autofill_popup_controller_test_base.h"
+
+#include <memory>
+#include <optional>
+#include <utility>
+
+namespace autofill {
+
+AutofillExternalDelegateForPopupTest::AutofillExternalDelegateForPopupTest(
+    BrowserAutofillManager* autofill_manager)
+    : AutofillExternalDelegate(autofill_manager) {}
+
+AutofillExternalDelegateForPopupTest::~AutofillExternalDelegateForPopupTest() =
+    default;
+
+AutofillPopupControllerForPopupTest::AutofillPopupControllerForPopupTest(
+    base::WeakPtr<AutofillExternalDelegate> external_delegate,
+    content::WebContents* web_contents,
+    const gfx::RectF& element_bounds,
+    base::RepeatingCallback<
+        void(gfx::NativeWindow,
+             Profile*,
+             password_manager::metrics_util::PasswordMigrationWarningTriggers)>
+        show_pwd_migration_warning_callback,
+    std::optional<base::WeakPtr<ExpandablePopupParentControllerImpl>> parent)
+    : AutofillPopupControllerImpl(
+          external_delegate,
+          web_contents,
+          PopupControllerCommon(element_bounds,
+                                base::i18n::UNKNOWN_DIRECTION,
+                                nullptr),
+          /*form_control_ax_id=*/0,
+          std::move(show_pwd_migration_warning_callback),
+          parent) {}
+
+AutofillPopupControllerForPopupTest::~AutofillPopupControllerForPopupTest() =
+    default;
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_test_base.h b/chrome/browser/ui/autofill/autofill_popup_controller_test_base.h
new file mode 100644
index 0000000..90969935
--- /dev/null
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_test_base.h
@@ -0,0 +1,371 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_CONTROLLER_TEST_BASE_H_
+#define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_CONTROLLER_TEST_BASE_H_
+
+#include <concepts>
+#include <memory>
+#include <optional>
+#include <utility>
+
+#include "base/functional/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/test/mock_callback.h"
+#include "chrome/browser/autofill/personal_data_manager_factory.h"
+#include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h"
+#include "chrome/browser/ui/autofill/autofill_popup_view.h"
+#include "chrome/browser/ui/autofill/mock_autofill_popup_view.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "components/autofill/content/browser/content_autofill_driver.h"
+#include "components/autofill/content/browser/test_autofill_client_injector.h"
+#include "components/autofill/content/browser/test_autofill_driver_injector.h"
+#include "components/autofill/content/browser/test_autofill_manager_injector.h"
+#include "components/autofill/content/browser/test_content_autofill_client.h"
+#include "components/autofill/core/browser/autofill_external_delegate.h"
+#include "components/autofill/core/browser/browser_autofill_manager.h"
+#include "components/autofill/core/browser/browser_autofill_manager_test_api.h"
+#include "components/autofill/core/browser/ui/autofill_popup_delegate.h"
+#include "components/autofill/core/common/autofill_test_utils.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if BUILDFLAG(IS_ANDROID)
+#include "chrome/browser/autofill/mock_manual_filling_view.h"
+#include "chrome/browser/keyboard_accessory/android/manual_filling_controller_impl.h"
+#include "chrome/browser/keyboard_accessory/test_utils/android/mock_address_accessory_controller.h"
+#include "chrome/browser/keyboard_accessory/test_utils/android/mock_credit_card_accessory_controller.h"
+#include "chrome/browser/keyboard_accessory/test_utils/android/mock_password_accessory_controller.h"
+#endif  // BUILDFLAG(IS_ANDROID)
+
+namespace autofill {
+
+class AutofillPopupControllerForPopupTest;
+
+namespace internal {
+
+// Satisfied if `D` is derived from either `B` or a mock wrapper around `B`.
+template <typename D, typename B>
+concept DerivedFromClassOrMock =
+    std::derived_from<D, B> || std::derived_from<D, ::testing::NaggyMock<B>> ||
+    std::derived_from<D, ::testing::NiceMock<B>> ||
+    std::derived_from<D, ::testing::StrictMock<B>>;
+
+template <typename Controller, typename Driver>
+concept ControllerAndDriver =
+    DerivedFromClassOrMock<Controller, AutofillPopupControllerForPopupTest> &&
+    DerivedFromClassOrMock<Driver, ContentAutofillDriver>;
+
+}  // namespace internal
+
+// This text fixture is intended for unit tests of the Autofill popup
+// controller, which controls the Autofill popup on Desktop and the Keyboard
+// Accessory on Clank. It has two template parameters that allow customizing the
+// test fixture's behavior:
+// - The class of the `AutofillPopupController` to test. The use of this
+//   parameter is to be able to test different implementations of the
+//   `AutofillPopupController` interface.
+// - The class of the `AutofillDriver` to inject, used, e.g., in a11y-specific
+//   tests.
+//
+// The main reason for the complexity of the test fixture is that there is
+// little value in testing an `AutofillPopupController` just by itself: Most of
+// its behavior depends on interactions with the `WebContents`, the
+// `AutofillClient`, or the `AutofillPopupView`. This test fixture sets these up
+// in a way that allows for controller testing.
+//
+// Once setup, the test fixture should allow writing popup controller unit tests
+// that closely mirror the production setup. Example:
+//
+// using SampleTest = AutofillPopupControllerTestBase<>;
+//
+// TEST_F(SampleTest, AcceptSuggestionWorksAfter500Ms) {
+//   ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
+//   EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion);
+//   task_environment()->FastForwardBy(base::Milliseconds(500));
+//   client().popup_controller(manager()).AcceptSuggestion(/*index=*/0);
+// }
+template <typename Controller =
+              ::testing::NiceMock<AutofillPopupControllerForPopupTest>,
+          typename Driver = ContentAutofillDriver>
+  requires(internal::ControllerAndDriver<Controller, Driver>)
+class AutofillPopupControllerTestBase : public ChromeRenderViewHostTestHarness {
+ public:
+  AutofillPopupControllerTestBase()
+      : ChromeRenderViewHostTestHarness(
+            base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
+  ~AutofillPopupControllerTestBase() override = default;
+
+  void SetUp() override {
+    ChromeRenderViewHostTestHarness::SetUp();
+    PersonalDataManagerFactory::GetInstance()->SetTestingFactory(
+        profile(), base::BindRepeating([](content::BrowserContext* context)
+                                           -> std::unique_ptr<KeyedService> {
+          return std::make_unique<TestPersonalDataManager>();
+        }));
+    NavigateAndCommit(GURL("https://foo.com/"));
+    FocusWebContentsOnMainFrame();
+    ASSERT_TRUE(web_contents()->GetFocusedFrame());
+
+#if BUILDFLAG(IS_ANDROID)
+    ManualFillingControllerImpl::CreateForWebContentsForTesting(
+        web_contents(), mock_pwd_controller_.AsWeakPtr(),
+        mock_address_controller_.AsWeakPtr(), mock_cc_controller_.AsWeakPtr(),
+        std::make_unique<::testing::NiceMock<MockManualFillingView>>());
+#endif  // BUILDFLAG(IS_ANDROID)
+  }
+
+  void TearDown() override {
+    // Wait for the pending deletion of the controllers. Otherwise, the
+    // controllers are destroyed after the WebContents, and each of them
+    // receives a final Hide() call for which we'd need to add explicit
+    // expectations.
+    task_environment()->RunUntilIdle();
+    ChromeRenderViewHostTestHarness::TearDown();
+  }
+
+  class TestManager;
+  class TestClient;
+
+  content::RenderFrameHost* main_frame() {
+    return web_contents()->GetPrimaryMainFrame();
+  }
+
+  TestClient& client() { return *autofill_client_injector_[web_contents()]; }
+
+  Driver& driver(content::RenderFrameHost* rfh = nullptr) {
+    return *autofill_driver_injector_[rfh ? rfh : main_frame()];
+  }
+
+  TestManager& manager(content::RenderFrameHost* rfh = nullptr) {
+    return *autofill_manager_injector_[rfh ? rfh : main_frame()];
+  }
+
+  TestPersonalDataManager& personal_data() {
+    return static_cast<TestPersonalDataManager&>(
+        *PersonalDataManagerFactory::GetForProfile(profile()));
+  }
+
+  // Shows empty suggestions with the popup_item_id ids passed as
+  // `popup_item_ids`.
+  void ShowSuggestions(
+      TestManager& manager,
+      const std::vector<PopupItemId>& popup_item_ids,
+      AutofillSuggestionTriggerSource trigger_source =
+          AutofillSuggestionTriggerSource::kFormControlElementClicked) {
+    std::vector<Suggestion> suggestions;
+    suggestions.reserve(popup_item_ids.size());
+    for (PopupItemId popup_item_id : popup_item_ids) {
+      suggestions.emplace_back(u"", popup_item_id);
+    }
+    ShowSuggestions(manager, std::move(suggestions), trigger_source);
+  }
+
+  void ShowSuggestions(
+      TestManager& manager,
+      std::vector<Suggestion> suggestions,
+      AutofillSuggestionTriggerSource trigger_source =
+          AutofillSuggestionTriggerSource::kFormControlElementClicked) {
+    FocusWebContentsOnFrame(
+        static_cast<ContentAutofillDriver&>(manager.driver())
+            .render_frame_host());
+    client().popup_controller(manager).Show(std::move(suggestions),
+                                            trigger_source,
+                                            AutoselectFirstSuggestion(false));
+  }
+
+  content::NativeWebKeyboardEvent CreateKeyPressEvent(int windows_key_code) {
+    content::NativeWebKeyboardEvent event(
+        blink::WebInputEvent::Type::kRawKeyDown,
+        blink::WebInputEvent::kNoModifiers,
+        blink::WebInputEvent::GetStaticTimeStampForTests());
+    event.windows_key_code = windows_key_code;
+    return event;
+  }
+
+ private:
+  ::autofill::test::AutofillUnitTestEnvironment autofill_test_environment_;
+
+  TestAutofillClientInjector<TestClient> autofill_client_injector_;
+  TestAutofillDriverInjector<Driver> autofill_driver_injector_;
+  TestAutofillManagerInjector<TestManager> autofill_manager_injector_;
+
+#if BUILDFLAG(IS_ANDROID)
+  ::testing::NiceMock<MockPasswordAccessoryController> mock_pwd_controller_;
+  ::testing::NiceMock<MockAddressAccessoryController> mock_address_controller_;
+  ::testing::NiceMock<MockCreditCardAccessoryController> mock_cc_controller_;
+#endif  // BUILDFLAG(IS_ANDROID)
+};
+
+// Below are test versions of `AutofillClient`, `BrowserAutofillManager`,
+// `AutofillExternalDelegate` and `AutofillPopupController` that are used in the
+// fixture above.
+
+class AutofillExternalDelegateForPopupTest : public AutofillExternalDelegate {
+ public:
+  explicit AutofillExternalDelegateForPopupTest(
+      BrowserAutofillManager* autofill_manager);
+  ~AutofillExternalDelegateForPopupTest() override;
+
+  void DidSelectSuggestion(const Suggestion& suggestion) override {}
+
+  MOCK_METHOD(void, ClearPreviewedForm, (), (override));
+  MOCK_METHOD(void, OnPopupShown, (), (override));
+  MOCK_METHOD(void, OnPopupHidden, (), (override));
+  MOCK_METHOD(void,
+              DidAcceptSuggestion,
+              (const Suggestion&,
+               const AutofillPopupDelegate::SuggestionPosition&),
+              (override));
+  MOCK_METHOD(void,
+              DidPerformButtonActionForSuggestion,
+              (const Suggestion&),
+              (override));
+  MOCK_METHOD(bool, RemoveSuggestion, (const Suggestion&), (override));
+};
+
+// A `BrowserAutofillManager` with a modified `AutofillExternalDelegate` that
+// allows verifying interactions with the popup.
+template <typename Controller, typename Driver>
+  requires(internal::ControllerAndDriver<Controller, Driver>)
+class AutofillPopupControllerTestBase<Controller, Driver>::TestManager
+    : public BrowserAutofillManager {
+ public:
+  explicit TestManager(AutofillDriver* driver)
+      : BrowserAutofillManager(driver, "en-US") {
+    test_api(*this).SetExternalDelegate(
+        std::make_unique<
+            ::testing::NiceMock<AutofillExternalDelegateForPopupTest>>(this));
+  }
+  TestManager(TestManager&) = delete;
+  TestManager& operator=(TestManager&) = delete;
+  ~TestManager() override = default;
+
+  AutofillExternalDelegateForPopupTest& external_delegate() {
+    return static_cast<AutofillExternalDelegateForPopupTest&>(
+        *test_api(*this).external_delegate());
+  }
+};
+
+// A modified `TestContentAutofillClient` that simulates the production behavior
+// of the controller lifetime.
+template <typename Controller, typename Driver>
+  requires(internal::ControllerAndDriver<Controller, Driver>)
+class AutofillPopupControllerTestBase<Controller, Driver>::TestClient
+    : public TestContentAutofillClient {
+ public:
+  explicit TestClient(content::WebContents* web_contents)
+      : TestContentAutofillClient(web_contents) {
+    ON_CALL(popup_view(), CreateSubPopupView)
+        .WillByDefault(::testing::Return(sub_popup_view().GetWeakPtr()));
+  }
+
+  ~TestClient() override { DoHide(); }
+
+  // Returns the current controller. Controllers are specific to the `manager`'s
+  // AutofillExternalDelegate. Therefore, when there are two consecutive
+  // `popup_controller(x)` and `popup_controller(y)`, the second call hides the
+  // old and creates new controller iff `x` and `y` are distinct.
+  Controller& popup_controller(TestManager& manager) {
+    if (manager_of_last_controller_.get() != &manager) {
+      DoHide();
+      CHECK(!popup_controller_);
+    }
+    if (!popup_controller_) {
+      popup_controller_ =
+          (new Controller(manager.external_delegate().GetWeakPtrForTest(),
+                          &GetWebContents(), gfx::RectF(),
+                          show_pwd_migration_warning_callback_.Get()))
+              ->GetWeakPtr();
+      cast_popup_controller().SetViewForTesting(popup_view_->GetWeakPtr());
+      manager_of_last_controller_ = manager.GetWeakPtr();
+      ON_CALL(cast_popup_controller(), Hide)
+          .WillByDefault([this](PopupHidingReason reason) { DoHide(reason); });
+    }
+    return cast_popup_controller();
+  }
+
+  MockAutofillPopupView& popup_view() { return *popup_view_; }
+
+  MockAutofillPopupView& sub_popup_view() { return *sub_popup_view_; }
+
+#if BUILDFLAG(IS_ANDROID)
+  base::MockCallback<base::RepeatingCallback<
+      void(gfx::NativeWindow,
+           Profile*,
+           password_manager::metrics_util::PasswordMigrationWarningTriggers)>>&
+  show_pwd_migration_warning_callback() {
+    return show_pwd_migration_warning_callback_;
+  }
+#endif  // BUILDFLAG(IS_ANDROID)
+
+ private:
+  void DoHide(PopupHidingReason reason) {
+    if (popup_controller_) {
+      cast_popup_controller().DoHide(reason);
+    }
+  }
+
+  void DoHide() {
+    if (popup_controller_) {
+      cast_popup_controller().DoHide();
+    }
+  }
+
+  Controller& cast_popup_controller() {
+    return static_cast<Controller&>(*popup_controller_);
+  }
+
+  base::WeakPtr<AutofillPopupController> popup_controller_;
+  base::WeakPtr<AutofillManager> manager_of_last_controller_;
+
+  std::unique_ptr<MockAutofillPopupView> popup_view_ =
+      std::make_unique<::testing::NiceMock<MockAutofillPopupView>>();
+  std::unique_ptr<MockAutofillPopupView> sub_popup_view_ =
+      std::make_unique<::testing::NiceMock<MockAutofillPopupView>>();
+  base::MockCallback<base::RepeatingCallback<void(
+      gfx::NativeWindow,
+      Profile*,
+      password_manager::metrics_util::PasswordMigrationWarningTriggers)>>
+      show_pwd_migration_warning_callback_;
+};
+
+class AutofillPopupControllerForPopupTest : public AutofillPopupControllerImpl {
+ public:
+  AutofillPopupControllerForPopupTest(
+      base::WeakPtr<AutofillExternalDelegate> external_delegate,
+      content::WebContents* web_contents,
+      const gfx::RectF& element_bounds,
+      base::RepeatingCallback<void(
+          gfx::NativeWindow,
+          Profile*,
+          password_manager::metrics_util::PasswordMigrationWarningTriggers)>
+          show_pwd_migration_warning_callback,
+      std::optional<base::WeakPtr<ExpandablePopupParentControllerImpl>> parent =
+          std::nullopt);
+  ~AutofillPopupControllerForPopupTest() override;
+
+  // Making protected functions public for testing
+  using AutofillPopupControllerImpl::AcceptSuggestion;
+  using AutofillPopupControllerImpl::element_bounds;
+  using AutofillPopupControllerImpl::FireControlsChangedEvent;
+  using AutofillPopupControllerImpl::GetLineCount;
+  using AutofillPopupControllerImpl::GetSuggestionAt;
+  using AutofillPopupControllerImpl::GetSuggestionLabelsAt;
+  using AutofillPopupControllerImpl::GetSuggestionMainTextAt;
+  using AutofillPopupControllerImpl::GetWeakPtr;
+  using AutofillPopupControllerImpl::PerformButtonActionForSuggestion;
+  using AutofillPopupControllerImpl::RemoveSuggestion;
+  using AutofillPopupControllerImpl::SelectSuggestion;
+  MOCK_METHOD(void, Hide, (PopupHidingReason reason), (override));
+
+  void DoHide(PopupHidingReason reason = PopupHidingReason::kTabGone) {
+    AutofillPopupControllerImpl::Hide(reason);
+  }
+};
+
+}  // namespace autofill
+
+#endif  // CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_CONTROLLER_TEST_BASE_H_
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
new file mode 100644
index 0000000..6dcca3a8
--- /dev/null
+++ b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
@@ -0,0 +1,1059 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+
+#include <memory>
+#include <optional>
+#include <string>
+#include <utility>
+
+#include "base/memory/weak_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/test/mock_callback.h"
+#include "base/test/task_environment.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "chrome/browser/accessibility/accessibility_state_utils.h"
+#include "chrome/browser/autofill/personal_data_manager_factory.h"
+#include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h"
+#include "chrome/browser/ui/autofill/autofill_popup_controller_test_base.h"
+#include "chrome/browser/ui/autofill/autofill_popup_view.h"
+#include "chrome/browser/ui/autofill/popup_controller_common.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/autofill/content/browser/content_autofill_driver.h"
+#include "components/autofill/content/browser/content_autofill_driver_factory.h"
+#include "components/autofill/content/browser/content_autofill_driver_factory_test_api.h"
+#include "components/autofill/content/browser/test_autofill_client_injector.h"
+#include "components/autofill/content/browser/test_autofill_driver_injector.h"
+#include "components/autofill/content/browser/test_autofill_manager_injector.h"
+#include "components/autofill/content/browser/test_content_autofill_client.h"
+#include "components/autofill/core/browser/autofill_driver_router.h"
+#include "components/autofill/core/browser/autofill_external_delegate.h"
+#include "components/autofill/core/browser/autofill_manager.h"
+#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/test_personal_data_manager.h"
+#include "components/autofill/core/browser/ui/autofill_popup_delegate.h"
+#include "components/autofill/core/browser/ui/popup_hiding_reasons.h"
+#include "components/autofill/core/browser/ui/popup_item_ids.h"
+#include "components/autofill/core/browser/ui/suggestion.h"
+#include "components/autofill/core/common/aliases.h"
+#include "components/autofill/core/common/unique_ids.h"
+#include "components/password_manager/core/common/password_manager_features.h"
+#include "components/prefs/pref_service.h"
+#include "components/strings/grit/components_strings.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/video_picture_in_picture_window_controller.h"
+#include "content/public/browser/weak_document_ptr.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/input/native_web_keyboard_event.h"
+#include "content/public/test/navigation_simulator.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/events/event.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/text_utils.h"
+
+namespace autofill {
+namespace {
+
+using base::ASCIIToUTF16;
+using base::WeakPtr;
+using ::testing::_;
+using ::testing::AtLeast;
+using ::testing::Eq;
+using ::testing::Field;
+using ::testing::Invoke;
+using ::testing::Mock;
+using ::testing::Optional;
+using ::testing::Return;
+
+content::RenderFrameHost* CreateAndNavigateChildFrame(
+    content::RenderFrameHost* parent,
+    const GURL& url,
+    std::string_view name) {
+  content::RenderFrameHost* rfh =
+      content::RenderFrameHostTester::For(parent)->AppendChild(
+          std::string(name));
+  // ContentAutofillDriverFactory::DidFinishNavigation() creates a driver for
+  // subframes only if
+  // `NavigationHandle::HasSubframeNavigationEntryCommitted()` is true. This
+  // is not the case for the first navigation. (In non-unit-tests, the first
+  // navigation creates a driver in
+  // ContentAutofillDriverFactory::BindAutofillDriver().) Therefore,
+  // we simulate *two* navigations here, and explicitly set the transition
+  // type for the second navigation.
+  std::unique_ptr<content::NavigationSimulator> simulator;
+  // First navigation: `HasSubframeNavigationEntryCommitted() == false`.
+  // Must be a different URL from the second navigation.
+  GURL about_blank("about:blank");
+  CHECK_NE(about_blank, url);
+  simulator =
+      content::NavigationSimulator::CreateRendererInitiated(about_blank, rfh);
+  simulator->Commit();
+  rfh = simulator->GetFinalRenderFrameHost();
+  // Second navigation: `HasSubframeNavigationEntryCommitted() == true`.
+  // Must set the transition type to ui::PAGE_TRANSITION_MANUAL_SUBFRAME.
+  simulator = content::NavigationSimulator::CreateRendererInitiated(url, rfh);
+  simulator->SetTransition(ui::PAGE_TRANSITION_MANUAL_SUBFRAME);
+  simulator->Commit();
+  return simulator->GetFinalRenderFrameHost();
+}
+
+content::RenderFrameHost* NavigateAndCommitFrame(content::RenderFrameHost* rfh,
+                                                 const GURL& url) {
+  std::unique_ptr<content::NavigationSimulator> simulator =
+      content::NavigationSimulator::CreateRendererInitiated(url, rfh);
+  simulator->Commit();
+  return simulator->GetFinalRenderFrameHost();
+}
+
+}  // namespace
+
+using AutofillPopupControllerTest = AutofillPopupControllerTestBase<>;
+
+TEST_F(AutofillPopupControllerTest, RemoveSuggestion) {
+  ShowSuggestions(manager(),
+                  {PopupItemId::kAddressEntry, PopupItemId::kAddressEntry,
+                   PopupItemId::kAutofillOptions});
+
+  // Generate a popup, so it can be hidden later. It doesn't matter what the
+  // external_delegate thinks is being shown in the process, since we are just
+  // testing the popup here.
+  test::GenerateTestAutofillPopup(&manager().external_delegate());
+  EXPECT_CALL(manager().external_delegate(),
+              RemoveSuggestion(Field(&Suggestion::popup_item_id,
+                                     PopupItemId::kAddressEntry)))
+      .WillRepeatedly(Return(true));
+
+  // Remove the first entry. The popup should be redrawn since its size has
+  // changed.
+  EXPECT_CALL(client().popup_view(), OnSuggestionsChanged());
+  EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion(
+      0,
+      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed));
+  Mock::VerifyAndClearExpectations(&client().popup_view());
+
+  // Remove the next entry. The popup should then be hidden since there are
+  // no Autofill entries left.
+  EXPECT_CALL(client().popup_controller(manager()),
+              Hide(PopupHidingReason::kNoSuggestions));
+  EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion(
+      0,
+      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed));
+}
+
+// Regression test for (crbug.com/1513574): Showing an Autofill Compose
+// suggestion twice does not crash.
+TEST_F(AutofillPopupControllerTest, ShowTwice) {
+  ShowSuggestions(manager(),
+                  {Suggestion(u"Help me write", PopupItemId::kCompose)});
+  ShowSuggestions(manager(),
+                  {Suggestion(u"Help me write", PopupItemId::kCompose)});
+}
+
+TEST_F(AutofillPopupControllerTest, RemoveAutocompleteSuggestion_AnnounceText) {
+  ShowSuggestions(manager(),
+                  {Suggestion(u"main text", PopupItemId::kAutocompleteEntry)});
+  test::GenerateTestAutofillPopup(&manager().external_delegate());
+
+  EXPECT_CALL(manager().external_delegate(),
+              RemoveSuggestion(Field(&Suggestion::popup_item_id,
+                                     PopupItemId::kAutocompleteEntry)))
+      .WillOnce(Return(true));
+  EXPECT_CALL(client().popup_view(),
+              AxAnnounce(Eq(u"Entry main text has been deleted")));
+  EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion(
+      0,
+      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed));
+}
+
+TEST_F(AutofillPopupControllerTest,
+       RemoveAutocompleteSuggestion_IgnoresClickOutsideCheck) {
+  ShowSuggestions(manager(), {PopupItemId::kAutocompleteEntry,
+                              PopupItemId::kAutocompleteEntry});
+
+  // Generate a popup, so it can be hidden later. It doesn't matter what the
+  // external_delegate thinks is being shown in the process, since we are just
+  // testing the popup here.
+  test::GenerateTestAutofillPopup(&manager().external_delegate());
+
+  EXPECT_CALL(manager().external_delegate(),
+              RemoveSuggestion(Field(&Suggestion::popup_item_id,
+                                     PopupItemId::kAutocompleteEntry)))
+      .WillOnce(Return(true));
+  // Remove the first entry. The popup should be redrawn since its size has
+  // changed.
+  EXPECT_CALL(client().popup_view(), OnSuggestionsChanged());
+  EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion(
+      0,
+      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed));
+  Mock::VerifyAndClearExpectations(&client().popup_view());
+
+  EXPECT_TRUE(client()
+                  .popup_controller(manager())
+                  .ShouldIgnoreMouseObservedOutsideItemBoundsCheck());
+}
+
+TEST_F(AutofillPopupControllerTest,
+       RemoveAutocompleteSuggestion_NoMetricsEmittedOnFail) {
+  base::HistogramTester histogram_tester;
+  ShowSuggestions(manager(), {PopupItemId::kAutocompleteEntry});
+  test::GenerateTestAutofillPopup(&manager().external_delegate());
+  EXPECT_CALL(manager().external_delegate(),
+              RemoveSuggestion(Field(&Suggestion::popup_item_id,
+                                     PopupItemId::kAutocompleteEntry)))
+      .WillOnce(Return(false));
+
+  EXPECT_FALSE(client().popup_controller(manager()).RemoveSuggestion(
+      0,
+      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed));
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.Autocomplete.SingleEntryRemovalMethod",
+      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed,
+      0);
+  histogram_tester.ExpectUniqueSample(
+      "Autocomplete.Events2",
+      AutofillMetrics::AutocompleteEvent::AUTOCOMPLETE_SUGGESTION_DELETED, 0);
+}
+
+TEST_F(AutofillPopupControllerTest,
+       RemoveAutocompleteSuggestion_MetricsEmittedOnSuccess) {
+  base::HistogramTester histogram_tester;
+  ShowSuggestions(manager(), {PopupItemId::kAutocompleteEntry});
+  test::GenerateTestAutofillPopup(&manager().external_delegate());
+  EXPECT_CALL(manager().external_delegate(),
+              RemoveSuggestion(Field(&Suggestion::popup_item_id,
+                                     PopupItemId::kAutocompleteEntry)))
+      .WillOnce(Return(true));
+
+  EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion(
+      0,
+      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed));
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.Autocomplete.SingleEntryRemovalMethod",
+      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed,
+      1);
+  histogram_tester.ExpectUniqueSample(
+      "Autocomplete.Events2",
+      AutofillMetrics::AutocompleteEvent::AUTOCOMPLETE_SUGGESTION_DELETED, 1);
+  // Also no autofill metrics are emitted.
+  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Popup", 1, 0);
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.ProfileDeleted.KeyboardAccessory", 1, 0);
+  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Any", 1, 0);
+}
+
+TEST_F(AutofillPopupControllerTest,
+       RemoveAddressSuggestion_ShiftDelete_NoMetricsEmittedOnFail) {
+  base::HistogramTester histogram_tester;
+  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
+  test::GenerateTestAutofillPopup(&manager().external_delegate());
+  EXPECT_CALL(manager().external_delegate(),
+              RemoveSuggestion(Field(&Suggestion::popup_item_id,
+                                     PopupItemId::kAddressEntry)))
+      .WillOnce(Return(false));
+
+  EXPECT_FALSE(client().popup_controller(manager()).RemoveSuggestion(
+      0,
+      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed));
+  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Popup", 1, 0);
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.ProfileDeleted.KeyboardAccessory", 1, 0);
+  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Any", 1, 0);
+}
+
+TEST_F(AutofillPopupControllerTest,
+       RemoveAddressSuggestion_ShiftDelete_MetricsEmittedOnSuccess) {
+  base::HistogramTester histogram_tester;
+  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
+  test::GenerateTestAutofillPopup(&manager().external_delegate());
+  EXPECT_CALL(manager().external_delegate(),
+              RemoveSuggestion(Field(&Suggestion::popup_item_id,
+                                     PopupItemId::kAddressEntry)))
+      .WillOnce(Return(true));
+
+  EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion(
+      0,
+      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed));
+  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Popup", 1, 1);
+  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Any", 1, 1);
+  // Also no autocomplete or keyboard accessory metrics are emitted.
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.ProfileDeleted.KeyboardAccessory", 1, 0);
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.Autocomplete.SingleEntryRemovalMethod",
+      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed,
+      0);
+  histogram_tester.ExpectUniqueSample(
+      "Autocomplete.Events2",
+      AutofillMetrics::AutocompleteEvent::AUTOCOMPLETE_SUGGESTION_DELETED, 0);
+}
+
+TEST_F(AutofillPopupControllerTest,
+       RemoveAddressSuggestion_KeyboardAccessory_NoMetricsEmittedOnFail) {
+  base::HistogramTester histogram_tester;
+  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
+  test::GenerateTestAutofillPopup(&manager().external_delegate());
+  EXPECT_CALL(manager().external_delegate(),
+              RemoveSuggestion(Field(&Suggestion::popup_item_id,
+                                     PopupItemId::kAddressEntry)))
+      .WillOnce(Return(false));
+
+  EXPECT_FALSE(client().popup_controller(manager()).RemoveSuggestion(
+      0, AutofillMetrics::SingleEntryRemovalMethod::kKeyboardAccessory));
+  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Popup", 1, 0);
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.ProfileDeleted.KeyboardAccessory", 1, 0);
+  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Any", 1, 0);
+}
+
+TEST_F(AutofillPopupControllerTest,
+       RemoveAddressSuggestion_KeyboardAccessory_MetricsEmittedOnSuccess) {
+  base::HistogramTester histogram_tester;
+  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
+  test::GenerateTestAutofillPopup(&manager().external_delegate());
+  EXPECT_CALL(manager().external_delegate(),
+              RemoveSuggestion(Field(&Suggestion::popup_item_id,
+                                     PopupItemId::kAddressEntry)))
+      .WillOnce(Return(true));
+
+  EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion(
+      0, AutofillMetrics::SingleEntryRemovalMethod::kKeyboardAccessory));
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.ProfileDeleted.KeyboardAccessory", 1, 1);
+  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Any", 1, 1);
+  // Also no autocomplete or shift+delete metrics are emitted.
+  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Popup", 1, 0);
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.Autocomplete.SingleEntryRemovalMethod",
+      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed,
+      0);
+  histogram_tester.ExpectUniqueSample(
+      "Autocomplete.Events2",
+      AutofillMetrics::AutocompleteEvent::AUTOCOMPLETE_SUGGESTION_DELETED, 0);
+}
+
+TEST_F(AutofillPopupControllerTest,
+       RemoveCreditCardSuggestion_NoMetricsEmitted) {
+  base::HistogramTester histogram_tester;
+  ShowSuggestions(manager(), {PopupItemId::kCreditCardEntry});
+  test::GenerateTestAutofillPopup(&manager().external_delegate());
+  EXPECT_CALL(manager().external_delegate(),
+              RemoveSuggestion(Field(&Suggestion::popup_item_id,
+                                     PopupItemId::kCreditCardEntry)))
+      .WillOnce(Return(true));
+
+  EXPECT_TRUE(client().popup_controller(manager()).RemoveSuggestion(
+      0,
+      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed));
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.Autocomplete.SingleEntryRemovalMethod",
+      AutofillMetrics::SingleEntryRemovalMethod::kKeyboardShiftDeletePressed,
+      0);
+  histogram_tester.ExpectUniqueSample(
+      "Autocomplete.Events2",
+      AutofillMetrics::AutocompleteEvent::AUTOCOMPLETE_SUGGESTION_DELETED, 0);
+  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Popup", 1, 0);
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.ProfileDeleted.KeyboardAccessory", 1, 0);
+  histogram_tester.ExpectUniqueSample("Autofill.ProfileDeleted.Any", 1, 0);
+}
+
+TEST_F(AutofillPopupControllerTest, UpdateDataListValues) {
+  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
+  std::vector<SelectOption> options = {
+      {.value = u"data list value 1", .content = u"data list label 1"}};
+  client().popup_controller(manager()).UpdateDataListValues(options);
+
+  ASSERT_EQ(3, client().popup_controller(manager()).GetLineCount());
+
+  Suggestion result0 = client().popup_controller(manager()).GetSuggestionAt(0);
+  EXPECT_EQ(options[0].value, result0.main_text.value);
+  EXPECT_EQ(options[0].value,
+            client().popup_controller(manager()).GetSuggestionMainTextAt(0));
+  ASSERT_EQ(1u, result0.labels.size());
+  ASSERT_EQ(1u, result0.labels[0].size());
+  EXPECT_EQ(options[0].content, result0.labels[0][0].value);
+  EXPECT_EQ(std::u16string(), result0.additional_label);
+  EXPECT_EQ(options[0].content, client()
+                                    .popup_controller(manager())
+                                    .GetSuggestionLabelsAt(0)[0][0]
+                                    .value);
+  EXPECT_EQ(PopupItemId::kDatalistEntry, result0.popup_item_id);
+
+  Suggestion result1 = client().popup_controller(manager()).GetSuggestionAt(1);
+  EXPECT_EQ(std::u16string(), result1.main_text.value);
+  EXPECT_TRUE(result1.labels.empty());
+  EXPECT_EQ(std::u16string(), result1.additional_label);
+  EXPECT_EQ(PopupItemId::kSeparator, result1.popup_item_id);
+
+  Suggestion result2 = client().popup_controller(manager()).GetSuggestionAt(2);
+  EXPECT_EQ(std::u16string(), result2.main_text.value);
+  EXPECT_TRUE(result2.labels.empty());
+  EXPECT_EQ(std::u16string(), result2.additional_label);
+  EXPECT_EQ(PopupItemId::kAddressEntry, result2.popup_item_id);
+
+  // Add two data list entries (which should replace the current one).
+  options.push_back(
+      {.value = u"data list value 1", .content = u"data list label 1"});
+  client().popup_controller(manager()).UpdateDataListValues(options);
+  ASSERT_EQ(4, client().popup_controller(manager()).GetLineCount());
+
+  // Original one first, followed by new one, then separator.
+  EXPECT_EQ(
+      options[0].value,
+      client().popup_controller(manager()).GetSuggestionAt(0).main_text.value);
+  EXPECT_EQ(options[0].value,
+            client().popup_controller(manager()).GetSuggestionMainTextAt(0));
+  ASSERT_EQ(
+      1u,
+      client().popup_controller(manager()).GetSuggestionAt(0).labels.size());
+  ASSERT_EQ(
+      1u,
+      client().popup_controller(manager()).GetSuggestionAt(0).labels[0].size());
+  EXPECT_EQ(options[0].content, client()
+                                    .popup_controller(manager())
+                                    .GetSuggestionAt(0)
+                                    .labels[0][0]
+                                    .value);
+  EXPECT_EQ(
+      std::u16string(),
+      client().popup_controller(manager()).GetSuggestionAt(0).additional_label);
+  EXPECT_EQ(
+      options[1].value,
+      client().popup_controller(manager()).GetSuggestionAt(1).main_text.value);
+  EXPECT_EQ(options[1].value,
+            client().popup_controller(manager()).GetSuggestionMainTextAt(1));
+  ASSERT_EQ(
+      1u,
+      client().popup_controller(manager()).GetSuggestionAt(1).labels.size());
+  ASSERT_EQ(
+      1u,
+      client().popup_controller(manager()).GetSuggestionAt(1).labels[0].size());
+  EXPECT_EQ(options[1].content, client()
+                                    .popup_controller(manager())
+                                    .GetSuggestionAt(1)
+                                    .labels[0][0]
+                                    .value);
+  EXPECT_EQ(
+      std::u16string(),
+      client().popup_controller(manager()).GetSuggestionAt(1).additional_label);
+  EXPECT_EQ(
+      PopupItemId::kSeparator,
+      client().popup_controller(manager()).GetSuggestionAt(2).popup_item_id);
+
+  // Clear all data list values.
+  options.clear();
+  client().popup_controller(manager()).UpdateDataListValues(options);
+
+  ASSERT_EQ(1, client().popup_controller(manager()).GetLineCount());
+  EXPECT_EQ(
+      PopupItemId::kAddressEntry,
+      client().popup_controller(manager()).GetSuggestionAt(0).popup_item_id);
+}
+
+TEST_F(AutofillPopupControllerTest, PopupsWithOnlyDataLists) {
+  // Create the popup with a single datalist element.
+  ShowSuggestions(manager(), {PopupItemId::kDatalistEntry});
+
+  // Replace the datalist element with a new one.
+  std::vector<SelectOption> options = {
+      {.value = u"data list value 1", .content = u"data list label 1"}};
+  client().popup_controller(manager()).UpdateDataListValues(options);
+
+  ASSERT_EQ(1, client().popup_controller(manager()).GetLineCount());
+  EXPECT_EQ(
+      options[0].value,
+      client().popup_controller(manager()).GetSuggestionAt(0).main_text.value);
+  ASSERT_EQ(
+      1u,
+      client().popup_controller(manager()).GetSuggestionAt(0).labels.size());
+  ASSERT_EQ(
+      1u,
+      client().popup_controller(manager()).GetSuggestionAt(0).labels[0].size());
+  EXPECT_EQ(options[0].content, client()
+                                    .popup_controller(manager())
+                                    .GetSuggestionAt(0)
+                                    .labels[0][0]
+                                    .value);
+  EXPECT_EQ(
+      std::u16string(),
+      client().popup_controller(manager()).GetSuggestionAt(0).additional_label);
+  EXPECT_EQ(
+      PopupItemId::kDatalistEntry,
+      client().popup_controller(manager()).GetSuggestionAt(0).popup_item_id);
+
+  // Clear datalist values and check that the popup becomes hidden.
+  EXPECT_CALL(client().popup_controller(manager()),
+              Hide(PopupHidingReason::kNoSuggestions));
+  options.clear();
+  client().popup_controller(manager()).UpdateDataListValues(options);
+}
+
+TEST_F(AutofillPopupControllerTest, GetOrCreate) {
+  auto create_controller = [&](gfx::RectF bounds) {
+    return AutofillPopupController::GetOrCreate(
+        client().popup_controller(manager()).GetWeakPtr(),
+        manager().external_delegate().GetWeakPtrForTest(), nullptr,
+        PopupControllerCommon(std::move(bounds), base::i18n::UNKNOWN_DIRECTION,
+                              nullptr),
+        /*form_control_ax_id=*/0);
+  };
+  WeakPtr<AutofillPopupController> controller = create_controller(gfx::RectF());
+  EXPECT_TRUE(controller);
+
+  controller->Hide(PopupHidingReason::kViewDestroyed);
+  EXPECT_FALSE(controller);
+
+  controller = create_controller(gfx::RectF());
+  EXPECT_TRUE(controller);
+
+  WeakPtr<AutofillPopupController> controller2 =
+      create_controller(gfx::RectF());
+  EXPECT_EQ(controller.get(), controller2.get());
+
+  controller->Hide(PopupHidingReason::kViewDestroyed);
+  EXPECT_FALSE(controller);
+  EXPECT_FALSE(controller2);
+
+  EXPECT_CALL(client().popup_controller(manager()),
+              Hide(PopupHidingReason::kViewDestroyed));
+  gfx::RectF bounds(0.f, 0.f, 1.f, 2.f);
+  base::WeakPtr<AutofillPopupController> controller3 =
+      create_controller(bounds);
+  EXPECT_EQ(&client().popup_controller(manager()), controller3.get());
+  EXPECT_EQ(bounds, static_cast<AutofillPopupController*>(controller3.get())
+                        ->element_bounds());
+  controller3->Hide(PopupHidingReason::kViewDestroyed);
+
+  client().popup_controller(manager()).DoHide();
+
+  const base::WeakPtr<AutofillPopupController> controller4 =
+      create_controller(bounds);
+  EXPECT_EQ(&client().popup_controller(manager()), controller4.get());
+  EXPECT_EQ(bounds,
+            static_cast<const AutofillPopupController*>(controller4.get())
+                ->element_bounds());
+
+  client().popup_controller(manager()).DoHide();
+}
+
+TEST_F(AutofillPopupControllerTest, ProperlyResetController) {
+  ShowSuggestions(manager(), {PopupItemId::kAutocompleteEntry,
+                              PopupItemId::kAutocompleteEntry});
+
+  // Now show a new popup with the same controller, but with fewer items.
+  WeakPtr<AutofillPopupController> controller =
+      AutofillPopupController::GetOrCreate(
+          client().popup_controller(manager()).GetWeakPtr(),
+          manager().external_delegate().GetWeakPtrForTest(), nullptr,
+          PopupControllerCommon(gfx::RectF(), base::i18n::UNKNOWN_DIRECTION,
+                                nullptr),
+          /*form_control_ax_id=*/0);
+  EXPECT_EQ(0, controller->GetLineCount());
+}
+
+TEST_F(AutofillPopupControllerTest, UnselectingClearsPreview) {
+  EXPECT_CALL(manager().external_delegate(), ClearPreviewedForm());
+  client().popup_controller(manager()).UnselectSuggestion();
+}
+
+TEST_F(AutofillPopupControllerTest, HidingClearsPreview) {
+  EXPECT_CALL(manager().external_delegate(), ClearPreviewedForm());
+  EXPECT_CALL(manager().external_delegate(), OnPopupHidden());
+  client().popup_controller(manager()).DoHide();
+}
+
+TEST_F(AutofillPopupControllerTest, DontHideWhenWaitingForData) {
+  EXPECT_CALL(client().popup_view(), Hide).Times(0);
+  client().popup_controller(manager()).PinView();
+
+  // Hide() will not work for stale data or when focusing native UI.
+  client().popup_controller(manager()).DoHide(PopupHidingReason::kStaleData);
+  client().popup_controller(manager()).DoHide(PopupHidingReason::kEndEditing);
+
+  // Check the expectations now since TearDown will perform a successful hide.
+  Mock::VerifyAndClearExpectations(&manager().external_delegate());
+  Mock::VerifyAndClearExpectations(&client().popup_view());
+}
+
+TEST_F(AutofillPopupControllerTest, ShouldReportHidingPopupReason) {
+  base::HistogramTester histogram_tester;
+  client().popup_controller(manager()).DoHide(PopupHidingReason::kTabGone);
+  histogram_tester.ExpectTotalCount("Autofill.PopupHidingReason", 1);
+  histogram_tester.ExpectBucketCount("Autofill.PopupHidingReason",
+                                     PopupHidingReason::kTabGone, 1);
+}
+
+// This is a regression test for crbug.com/521133 to ensure that we don't crash
+// when suggestions updates race with user selections.
+TEST_F(AutofillPopupControllerTest, SelectInvalidSuggestion) {
+  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
+
+  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion).Times(0);
+
+  // The following should not crash:
+  client().popup_controller(manager()).AcceptSuggestion(
+      /*index=*/1);  // Out of bounds!
+}
+
+TEST_F(AutofillPopupControllerTest, AcceptSuggestionRespectsTimeout) {
+  base::HistogramTester histogram_tester;
+  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
+
+  // Calls before the threshold are ignored.
+  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion).Times(0);
+  client().popup_controller(manager()).AcceptSuggestion(0);
+  task_environment()->FastForwardBy(base::Milliseconds(100));
+  client().popup_controller(manager()).AcceptSuggestion(/*index=*/0);
+
+  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion);
+  task_environment()->FastForwardBy(base::Milliseconds(400));
+  client().popup_controller(manager()).AcceptSuggestion(/*index=*/0);
+
+  histogram_tester.ExpectTotalCount(
+      "Autofill.Popup.AcceptanceDelayThresholdNotMet", 2);
+}
+
+TEST_F(AutofillPopupControllerTest,
+       AcceptSuggestionTimeoutIsUpdatedOnPopupMove) {
+  base::HistogramTester histogram_tester;
+  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
+
+  // Calls before the threshold are ignored.
+  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion).Times(0);
+  client().popup_controller(manager()).AcceptSuggestion(/*index=*/0);
+  task_environment()->FastForwardBy(base::Milliseconds(100));
+  client().popup_controller(manager()).AcceptSuggestion(/*index=*/0);
+
+  histogram_tester.ExpectTotalCount(
+      "Autofill.Popup.AcceptanceDelayThresholdNotMet", 2);
+  task_environment()->FastForwardBy(base::Milliseconds(400));
+  // Show the suggestions again (simulating, e.g., a click somewhere slightly
+  // different).
+  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
+
+  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion).Times(0);
+  client().popup_controller(manager()).AcceptSuggestion(/*index=*/0);
+  histogram_tester.ExpectTotalCount(
+      "Autofill.Popup.AcceptanceDelayThresholdNotMet", 3);
+
+  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion);
+  // After waiting, suggestions are accepted again.
+  task_environment()->FastForwardBy(base::Milliseconds(500));
+  client().popup_controller(manager()).AcceptSuggestion(/*index=*/0);
+  histogram_tester.ExpectTotalCount(
+      "Autofill.Popup.AcceptanceDelayThresholdNotMet", 3);
+}
+
+// Tests that when a picture-in-picture window is initialized, there is a call
+// to the popup view to check if the autofill popup bounds overlap with the
+// picture-in-picture window.
+TEST_F(AutofillPopupControllerTest, CheckBoundsOverlapWithPictureInPicture) {
+  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
+  PictureInPictureWindowManager* picture_in_picture_window_manager =
+      PictureInPictureWindowManager::GetInstance();
+  EXPECT_CALL(client().popup_view(), OverlapsWithPictureInPictureWindow);
+  picture_in_picture_window_manager->NotifyObserversOnEnterPictureInPicture();
+}
+
+TEST_F(AutofillPopupControllerTest,
+       GetRemovalConfirmationText_UnrelatedPopupItemId) {
+  std::u16string title;
+  std::u16string body;
+  ShowSuggestions(
+      manager(),
+      {Suggestion(u"Entry", PopupItemId::kAddressFieldByFieldFilling)});
+
+  EXPECT_FALSE(client().popup_controller(manager()).GetRemovalConfirmationText(
+      0, &title, &body));
+}
+
+TEST_F(AutofillPopupControllerTest,
+       GetRemovalConfirmationText_InvalidUniqueId) {
+  std::u16string title;
+  std::u16string body;
+  ShowSuggestions(manager(), {test::CreateAutofillSuggestion(
+                                 PopupItemId::kAddressFieldByFieldFilling,
+                                 u"Entry", Suggestion::Guid("1111"))});
+
+  EXPECT_FALSE(client().popup_controller(manager()).GetRemovalConfirmationText(
+      0, &title, &body));
+}
+
+TEST_F(AutofillPopupControllerTest, GetRemovalConfirmationText_Autocomplete) {
+  std::u16string title;
+  std::u16string body;
+  ShowSuggestions(manager(), {Suggestion(u"Autocomplete entry",
+                                         PopupItemId::kAutocompleteEntry)});
+
+  EXPECT_TRUE(client().popup_controller(manager()).GetRemovalConfirmationText(
+      0, &title, &body));
+  EXPECT_EQ(title, u"Autocomplete entry");
+  EXPECT_EQ(body,
+            l10n_util::GetStringUTF16(
+                IDS_AUTOFILL_DELETE_AUTOCOMPLETE_SUGGESTION_CONFIRMATION_BODY));
+}
+
+TEST_F(AutofillPopupControllerTest,
+       GetRemovalConfirmationText_LocalCreditCard) {
+  CreditCard local_card = test::GetCreditCard();
+  personal_data().AddCreditCard(local_card);
+
+  std::u16string title;
+  std::u16string body;
+  ShowSuggestions(manager(),
+                  {test::CreateAutofillSuggestion(
+                      PopupItemId::kCreditCardEntry, u"Local credit card",
+                      Suggestion::Guid(local_card.guid()))});
+
+  EXPECT_TRUE(client().popup_controller(manager()).GetRemovalConfirmationText(
+      0, &title, &body));
+  EXPECT_EQ(title, local_card.CardNameAndLastFourDigits());
+  EXPECT_EQ(body,
+            l10n_util::GetStringUTF16(
+                IDS_AUTOFILL_DELETE_CREDIT_CARD_SUGGESTION_CONFIRMATION_BODY));
+}
+
+TEST_F(AutofillPopupControllerTest,
+       GetRemovalConfirmationText_ServerCreditCard) {
+  CreditCard server_card = test::GetMaskedServerCard();
+  personal_data().AddServerCreditCard(server_card);
+
+  std::u16string title;
+  std::u16string body;
+  ShowSuggestions(manager(),
+                  {test::CreateAutofillSuggestion(
+                      PopupItemId::kCreditCardEntry, u"Server credit card",
+                      Suggestion::Guid(server_card.guid()))});
+
+  EXPECT_FALSE(client().popup_controller(manager()).GetRemovalConfirmationText(
+      0, &title, &body));
+}
+
+TEST_F(AutofillPopupControllerTest,
+       GetRemovalConfirmationText_CompleteAutofillProfile) {
+  AutofillProfile complete_profile = test::GetFullProfile();
+  personal_data().AddProfile(complete_profile);
+
+  std::u16string title;
+  std::u16string body;
+  ShowSuggestions(manager(),
+                  {test::CreateAutofillSuggestion(
+                      PopupItemId::kAddressEntry, u"Complete autofill profile",
+                      Suggestion::Guid(complete_profile.guid()))});
+
+  EXPECT_TRUE(client().popup_controller(manager()).GetRemovalConfirmationText(
+      0, &title, &body));
+  EXPECT_EQ(title, complete_profile.GetRawInfo(ADDRESS_HOME_CITY));
+  EXPECT_EQ(body,
+            l10n_util::GetStringUTF16(
+                IDS_AUTOFILL_DELETE_PROFILE_SUGGESTION_CONFIRMATION_BODY));
+}
+
+TEST_F(AutofillPopupControllerTest,
+       GetRemovalConfirmationText_AutofillProfile_EmptyCity) {
+  AutofillProfile profile = test::GetFullProfile();
+  profile.ClearFields({ADDRESS_HOME_CITY});
+  personal_data().AddProfile(profile);
+
+  std::u16string title;
+  std::u16string body;
+  ShowSuggestions(manager(), {test::CreateAutofillSuggestion(
+                                 PopupItemId::kAddressEntry,
+                                 u"Autofill profile without city",
+                                 Suggestion::Guid(profile.guid()))});
+
+  EXPECT_TRUE(client().popup_controller(manager()).GetRemovalConfirmationText(
+      0, &title, &body));
+  EXPECT_EQ(title, u"Autofill profile without city");
+  EXPECT_EQ(body,
+            l10n_util::GetStringUTF16(
+                IDS_AUTOFILL_DELETE_PROFILE_SUGGESTION_CONFIRMATION_BODY));
+}
+
+#if BUILDFLAG(IS_ANDROID)
+TEST_F(AutofillPopupControllerTest, AcceptPwdSuggestionInvokesWarningAndroid) {
+  base::test::ScopedFeatureList scoped_feature_list(
+      password_manager::features::
+          kUnifiedPasswordManagerLocalPasswordsMigrationWarning);
+  ShowSuggestions(manager(), {PopupItemId::kPasswordEntry});
+
+  // Calls are accepted immediately.
+  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion).Times(1);
+  EXPECT_CALL(client().show_pwd_migration_warning_callback(),
+              Run(_, _,
+                  password_manager::metrics_util::
+                      PasswordMigrationWarningTriggers::kKeyboardAcessoryBar));
+  task_environment()->FastForwardBy(base::Milliseconds(500));
+  client().popup_controller(manager()).AcceptSuggestion(0);
+}
+
+TEST_F(AutofillPopupControllerTest,
+       AcceptUsernameSuggestionInvokesWarningAndroid) {
+  base::test::ScopedFeatureList scoped_feature_list(
+      password_manager::features::
+          kUnifiedPasswordManagerLocalPasswordsMigrationWarning);
+  ShowSuggestions(manager(), {PopupItemId::kPasswordEntry});
+
+  // Calls are accepted immediately.
+  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion).Times(1);
+  EXPECT_CALL(client().show_pwd_migration_warning_callback(), Run);
+  task_environment()->FastForwardBy(base::Milliseconds(500));
+  client().popup_controller(manager()).AcceptSuggestion(0);
+}
+
+TEST_F(AutofillPopupControllerTest,
+       AcceptPwdSuggestionNoWarningIfDisabledAndroid) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndDisableFeature(
+      password_manager::features::
+          kUnifiedPasswordManagerLocalPasswordsMigrationWarning);
+  ShowSuggestions(manager(), {PopupItemId::kPasswordEntry});
+
+  // Calls are accepted immediately.
+  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion).Times(1);
+  EXPECT_CALL(client().show_pwd_migration_warning_callback(), Run).Times(0);
+  task_environment()->FastForwardBy(base::Milliseconds(500));
+  client().popup_controller(manager()).AcceptSuggestion(0);
+}
+
+TEST_F(AutofillPopupControllerTest, AcceptAddressNoPwdWarningAndroid) {
+  base::test::ScopedFeatureList scoped_feature_list(
+      password_manager::features::
+          kUnifiedPasswordManagerLocalPasswordsMigrationWarning);
+  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
+
+  // Calls are accepted immediately.
+  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion).Times(1);
+  EXPECT_CALL(client().show_pwd_migration_warning_callback(), Run).Times(0);
+  task_environment()->FastForwardBy(base::Milliseconds(500));
+  client().popup_controller(manager()).AcceptSuggestion(0);
+}
+
+// When a suggestion is accepted, the popup is hidden inside
+// `delegate->DidAcceptSuggestion()`. On Android, some code is still being
+// executed after hiding. This test makes sure no use-after-free, null pointer
+// dereferencing or other memory violations occur.
+TEST_F(AutofillPopupControllerTest, AcceptSuggestionIsMemorySafe) {
+  ShowSuggestions(manager(), {PopupItemId::kPasswordEntry});
+  task_environment()->FastForwardBy(base::Milliseconds(500));
+
+  EXPECT_CALL(manager().external_delegate(), DidAcceptSuggestion)
+      .WillOnce([this]() {
+        client().popup_controller(manager()).Hide(
+            PopupHidingReason::kAcceptSuggestion);
+      });
+  client().popup_controller(manager()).AcceptSuggestion(/*index=*/0);
+}
+
+#endif  // BUILDFLAG(IS_ANDROID)
+
+// Tests that the popup controller queries the view for its screen location.
+TEST_F(AutofillPopupControllerTest, GetPopupScreenLocationCallsView) {
+  ShowSuggestions(manager(), {PopupItemId::kCompose});
+
+  using PopupScreenLocation = AutofillClient::PopupScreenLocation;
+  constexpr gfx::Rect kSampleRect = gfx::Rect(123, 234);
+  EXPECT_CALL(client().popup_view(), GetPopupScreenLocation)
+      .WillOnce(Return(PopupScreenLocation{.bounds = kSampleRect}));
+  EXPECT_THAT(client().popup_controller(manager()).GetPopupScreenLocation(),
+              Optional(Field(&PopupScreenLocation::bounds, kSampleRect)));
+}
+
+// Tests that a change to a text field hides a popup with a Compose suggestion.
+TEST_F(AutofillPopupControllerTest, HidesOnFieldChangeForComposeEntries) {
+  ShowSuggestions(manager(), {PopupItemId::kCompose});
+  EXPECT_CALL(client().popup_controller(manager()),
+              Hide(PopupHidingReason::kFieldValueChanged));
+  manager().NotifyObservers(
+      &AutofillManager::Observer::OnBeforeTextFieldDidChange, FormGlobalId(),
+      FieldGlobalId());
+}
+
+// Tests that a change to a text field does not hide a popup with an
+// Autocomplete suggestion.
+TEST_F(AutofillPopupControllerTest,
+       DoeNotHideOnFieldChangeForNonComposeEntries) {
+  ShowSuggestions(manager(), {PopupItemId::kAutocompleteEntry});
+  EXPECT_CALL(client().popup_controller(manager()), Hide).Times(0);
+  manager().NotifyObservers(
+      &AutofillManager::Observer::OnBeforeTextFieldDidChange, FormGlobalId(),
+      FieldGlobalId());
+  Mock::VerifyAndClearExpectations(&client().popup_controller(manager()));
+}
+
+class AutofillPopupControllerTestHidingLogic
+    : public AutofillPopupControllerTest {
+ public:
+  void SetUp() override {
+    AutofillPopupControllerTest::SetUp();
+    sub_frame_ = CreateAndNavigateChildFrame(
+                     main_frame(), GURL("https://bar.com"), "sub_frame")
+                     ->GetWeakDocumentPtr();
+  }
+
+  TestManager& sub_manager() { return manager(sub_frame()); }
+
+  content::RenderFrameHost* sub_frame() {
+    return sub_frame_.AsRenderFrameHostIfValid();
+  }
+
+ private:
+  content::WeakDocumentPtr sub_frame_;
+};
+
+// Tests that if the popup is shown in the *main frame*, destruction of the
+// *sub frame* does not hide the popup.
+TEST_F(AutofillPopupControllerTestHidingLogic,
+       KeepOpenInMainFrameOnSubFrameDestruction) {
+  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
+  test::GenerateTestAutofillPopup(&manager().external_delegate());
+  EXPECT_CALL(client().popup_controller(manager()), Hide).Times(0);
+  content::RenderFrameHostTester::For(sub_frame())->Detach();
+  // Verify and clear before TearDown() closes the popup.
+  Mock::VerifyAndClearExpectations(&client().popup_controller(manager()));
+}
+
+// Tests that if the popup is shown in the *main frame*, a navigation in the
+// *sub frame* does not hide the popup.
+TEST_F(AutofillPopupControllerTestHidingLogic,
+       KeepOpenInMainFrameOnSubFrameNavigation) {
+  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
+  test::GenerateTestAutofillPopup(&manager().external_delegate());
+  EXPECT_CALL(client().popup_controller(manager()), Hide).Times(0);
+  NavigateAndCommitFrame(sub_frame(), GURL("https://bar.com/"));
+  // Verify and clear before TearDown() closes the popup.
+  Mock::VerifyAndClearExpectations(&client().popup_controller(manager()));
+}
+
+// Tests that if the popup is shown, destruction of the WebContents hides the
+// popup.
+TEST_F(AutofillPopupControllerTestHidingLogic, HideOnWebContentsDestroyed) {
+  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
+  test::GenerateTestAutofillPopup(&manager().external_delegate());
+  EXPECT_CALL(client().popup_controller(manager()),
+              Hide(PopupHidingReason::kRendererEvent));
+  DeleteContents();
+}
+
+// Tests that if the popup is shown in the *main frame*, destruction of the
+// *main frame* hides the popup.
+TEST_F(AutofillPopupControllerTestHidingLogic, HideInMainFrameOnDestruction) {
+  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
+  test::GenerateTestAutofillPopup(&manager().external_delegate());
+  EXPECT_CALL(client().popup_controller(manager()),
+              Hide(PopupHidingReason::kRendererEvent));
+}
+
+// Tests that if the popup is shown in the *sub frame*, destruction of the
+// *sub frame* hides the popup.
+TEST_F(AutofillPopupControllerTestHidingLogic, HideInSubFrameOnDestruction) {
+  ShowSuggestions(sub_manager(), {PopupItemId::kAddressEntry});
+  test::GenerateTestAutofillPopup(&sub_manager().external_delegate());
+  EXPECT_CALL(client().popup_controller(sub_manager()),
+              Hide(PopupHidingReason::kRendererEvent));
+  content::RenderFrameHostTester::For(sub_frame())->Detach();
+  // Verify and clear before TearDown() closes the popup.
+  Mock::VerifyAndClearExpectations(&client().popup_controller(sub_manager()));
+}
+
+// Tests that if the popup is shown in the *main frame*, a navigation in the
+// *main frame* hides the popup.
+TEST_F(AutofillPopupControllerTestHidingLogic,
+       HideInMainFrameOnMainFrameNavigation) {
+  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
+  test::GenerateTestAutofillPopup(&manager().external_delegate());
+  EXPECT_CALL(client().popup_controller(manager()),
+              Hide(PopupHidingReason::kNavigation));
+  NavigateAndCommitFrame(main_frame(), GURL("https://bar.com/"));
+  // Verify and clear before TearDown() closes the popup.
+  Mock::VerifyAndClearExpectations(&client().popup_controller(manager()));
+}
+
+// Tests that if the popup is shown in the *sub frame*, a navigation in the
+// *sub frame* hides the popup.
+TEST_F(AutofillPopupControllerTestHidingLogic,
+       HideInSubFrameOnSubFrameNavigation) {
+  ShowSuggestions(sub_manager(), {PopupItemId::kAddressEntry});
+  test::GenerateTestAutofillPopup(&sub_manager().external_delegate());
+  if (sub_frame()->ShouldChangeRenderFrameHostOnSameSiteNavigation()) {
+    // If the RenderFrameHost changes, a RenderFrameDeleted will fire first.
+    EXPECT_CALL(client().popup_controller(sub_manager()),
+                Hide(PopupHidingReason::kRendererEvent));
+  } else {
+    EXPECT_CALL(client().popup_controller(sub_manager()),
+                Hide(PopupHidingReason::kNavigation));
+  }
+  NavigateAndCommitFrame(sub_frame(), GURL("https://bar.com/"));
+  // Verify and clear before TearDown() closes the popup.
+  Mock::VerifyAndClearExpectations(&client().popup_controller(sub_manager()));
+}
+
+// Tests that if the popup is shown in the *sub frame*, a navigation in the
+// *main frame* hides the popup.
+//
+// TODO(crbug.com/1519872): This test only makes little sense: with BFcache, the
+// navigation doesn't destroy the `sub_frame()` and thus we wouldn't hide the
+// popup. What hides the popup in reality is
+// AutofillExternalDelegate::DidEndTextFieldEditing().
+TEST_F(AutofillPopupControllerTestHidingLogic,
+       HideInSubFrameOnMainFrameNavigation) {
+  ShowSuggestions(sub_manager(), {PopupItemId::kAddressEntry});
+  test::GenerateTestAutofillPopup(&sub_manager().external_delegate());
+  EXPECT_CALL(client().popup_controller(sub_manager()),
+              Hide(PopupHidingReason::kRendererEvent));
+  NavigateAndCommitFrame(main_frame(), GURL("https://bar.com/"));
+}
+
+// Tests that Compose saved state notification popup gets hidden after 2
+// seconds, but not after 1 second.
+TEST_F(AutofillPopupControllerTestHidingLogic,
+       TimedHideComposeSavedStateNotification) {
+  ShowSuggestions(manager(), {PopupItemId::kComposeSavedStateNotification});
+  test::GenerateTestAutofillPopup(&manager().external_delegate());
+  ::testing::MockFunction<void()> check;
+  {
+    ::testing::InSequence s;
+    EXPECT_CALL(check, Call);
+    EXPECT_CALL(client().popup_controller(manager()),
+                Hide(PopupHidingReason::kFadeTimerExpired));
+  }
+  task_environment()->FastForwardBy(base::Seconds(1));
+  check.Call();
+  task_environment()->FastForwardBy(base::Seconds(1));
+  Mock::VerifyAndClearExpectations(&client().popup_controller(manager()));
+}
+
+#if !BUILDFLAG(IS_ANDROID)
+// Tests that if the popup is shown in the *main frame*, changing the zoom hides
+// the popup.
+TEST_F(AutofillPopupControllerTestHidingLogic, HideInMainFrameOnZoomChange) {
+  zoom::ZoomController::CreateForWebContents(web_contents());
+  ShowSuggestions(manager(), {PopupItemId::kAddressEntry});
+  test::GenerateTestAutofillPopup(&manager().external_delegate());
+  // Triggered by OnZoomChanged().
+  EXPECT_CALL(client().popup_controller(manager()),
+              Hide(PopupHidingReason::kContentAreaMoved));
+  // Override the default ON_CALL behavior to do nothing to avoid destroying the
+  // hide helper. We want to test ZoomObserver events explicitly.
+  EXPECT_CALL(client().popup_controller(manager()),
+              Hide(PopupHidingReason::kWidgetChanged))
+      .WillOnce(Return());
+  auto* zoom_controller = zoom::ZoomController::FromWebContents(web_contents());
+  zoom_controller->SetZoomLevel(zoom_controller->GetZoomLevel() + 1.0);
+  // Verify and clear before TearDown() closes the popup.
+  Mock::VerifyAndClearExpectations(&client().popup_controller(manager()));
+}
+#endif  // BUILDFLAG(IS_ANDROID)
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/autofill/autofill_signin_promo_tab_helper.cc b/chrome/browser/ui/autofill/autofill_signin_promo_tab_helper.cc
index 90437f0..6a2dbb7 100644
--- a/chrome/browser/ui/autofill/autofill_signin_promo_tab_helper.cc
+++ b/chrome/browser/ui/autofill/autofill_signin_promo_tab_helper.cc
@@ -68,6 +68,11 @@
   state_->access_point_ = access_point;
   state_->time_limit_ = time_limit;
   state_->initialization_time_ = base::Time::Now();
+  state_->is_initialized_ = true;
+}
+
+bool AutofillSigninPromoTabHelper::IsInitializedForTesting() const {
+  return state_->is_initialized_;
 }
 
 void AutofillSigninPromoTabHelper::OnPrimaryAccountChanged(
diff --git a/chrome/browser/ui/autofill/autofill_signin_promo_tab_helper.h b/chrome/browser/ui/autofill/autofill_signin_promo_tab_helper.h
index 860134c..3938d16 100644
--- a/chrome/browser/ui/autofill/autofill_signin_promo_tab_helper.h
+++ b/chrome/browser/ui/autofill/autofill_signin_promo_tab_helper.h
@@ -41,6 +41,9 @@
       signin_metrics::AccessPoint access_point,
       base::TimeDelta time_limit = base::Minutes(50));
 
+  // Returns true if the helper has been initialized for testing.
+  bool IsInitializedForTesting() const;
+
   // Overrides signin::IdentityManager::Observer functions.
   void OnPrimaryAccountChanged(
       const signin::PrimaryAccountChangeEvent& event_details) override;
@@ -67,6 +70,7 @@
         signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN;
     base::Time initialization_time_;
     base::TimeDelta time_limit_;
+    bool is_initialized_ = false;
   };
 
   std::unique_ptr<ResetableState> state_;
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index 0d9b7b85..9db2de3 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -927,7 +927,7 @@
       open_args.element_bounds + client_area.OffsetFromOrigin();
 
   // Deletes or reuses the old `popup_controller_`.
-  popup_controller_ = AutofillPopupControllerImpl::GetOrCreate(
+  popup_controller_ = AutofillPopupController::GetOrCreate(
       popup_controller_, delegate, web_contents(),
       PopupControllerCommon(element_bounds_in_screen_space,
                             open_args.text_direction,
@@ -946,8 +946,10 @@
     autofill_field_promo_controller_manual_fallback_->Hide();
   }
 
-  // When testing, try to keep popup open when the reason to hide is from an
-  // external browser frame resize that is extraneous to our testing goals.
+  // When testing, try to keep popup open when the reason to hide is one of:
+  // - An external browser frame resize that is extraneous to our testing goals.
+  // - Too many fields get focus one after another (for example, multiple
+  // password fields being autofilled by default on Desktop).
   if (keep_popup_open_for_testing_ && popup_controller_.get()) {
     popup_controller_->KeepPopupOpenForTesting();
   }
diff --git a/chrome/browser/ui/autofill/delete_address_profile_dialog_controller_impl.cc b/chrome/browser/ui/autofill/delete_address_profile_dialog_controller_impl.cc
index cd7d48e..6ba54a3 100644
--- a/chrome/browser/ui/autofill/delete_address_profile_dialog_controller_impl.cc
+++ b/chrome/browser/ui/autofill/delete_address_profile_dialog_controller_impl.cc
@@ -80,7 +80,7 @@
   PersonalDataManager* pdm = PersonalDataManagerFactory::GetForBrowserContext(
       web_contents_->GetBrowserContext());
   return l10n_util::GetStringUTF16(
-      pdm->IsSyncFeatureEnabledForAutofill()
+      pdm->address_data_manager().IsSyncFeatureEnabledForAutofill()
           ? IDS_AUTOFILL_DELETE_SYNC_ADDRESS_SOURCE_NOTICE
           : IDS_AUTOFILL_DELETE_LOCAL_ADDRESS_SOURCE_NOTICE);
 }
diff --git a/chrome/browser/ui/autofill/mock_autofill_popup_view.cc b/chrome/browser/ui/autofill/mock_autofill_popup_view.cc
new file mode 100644
index 0000000..8a9a153
--- /dev/null
+++ b/chrome/browser/ui/autofill/mock_autofill_popup_view.cc
@@ -0,0 +1,13 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/autofill/mock_autofill_popup_view.h"
+
+namespace autofill {
+
+MockAutofillPopupView::MockAutofillPopupView() = default;
+
+MockAutofillPopupView::~MockAutofillPopupView() = default;
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/autofill/mock_autofill_popup_view.h b/chrome/browser/ui/autofill/mock_autofill_popup_view.h
new file mode 100644
index 0000000..8cdaedb
--- /dev/null
+++ b/chrome/browser/ui/autofill/mock_autofill_popup_view.h
@@ -0,0 +1,55 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_AUTOFILL_MOCK_AUTOFILL_POPUP_VIEW_H_
+#define CHROME_BROWSER_UI_AUTOFILL_MOCK_AUTOFILL_POPUP_VIEW_H_
+
+#include <optional>
+#include <string>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/ui/autofill/autofill_popup_view.h"
+#include "components/autofill/core/browser/autofill_client.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace autofill {
+
+class MockAutofillPopupView : public AutofillPopupView {
+ public:
+  MockAutofillPopupView();
+  MockAutofillPopupView(MockAutofillPopupView&) = delete;
+  MockAutofillPopupView& operator=(MockAutofillPopupView&) = delete;
+  ~MockAutofillPopupView() override;
+
+  MOCK_METHOD(bool, Show, (AutoselectFirstSuggestion), (override));
+  MOCK_METHOD(void, Hide, (), (override));
+  MOCK_METHOD(bool,
+              HandleKeyPressEvent,
+              (const content::NativeWebKeyboardEvent&),
+              (override));
+  MOCK_METHOD(void, OnSuggestionsChanged, (), (override));
+  MOCK_METHOD(bool, OverlapsWithPictureInPictureWindow, (), (const override));
+  MOCK_METHOD(std::optional<int32_t>, GetAxUniqueId, (), (override));
+  MOCK_METHOD(void, AxAnnounce, (const std::u16string&), (override));
+  MOCK_METHOD(base::WeakPtr<AutofillPopupView>,
+              CreateSubPopupView,
+              (base::WeakPtr<AutofillPopupController>),
+              (override));
+  MOCK_METHOD(std::optional<AutofillClient::PopupScreenLocation>,
+              GetPopupScreenLocation,
+              (),
+              (const override));
+
+  base::WeakPtr<AutofillPopupView> GetWeakPtr() override {
+    return weak_ptr_factory_.GetWeakPtr();
+  }
+
+ private:
+  base::WeakPtrFactory<AutofillPopupView> weak_ptr_factory_{this};
+};
+
+}  // namespace autofill
+
+#endif  // CHROME_BROWSER_UI_AUTOFILL_MOCK_AUTOFILL_POPUP_VIEW_H_
diff --git a/chrome/browser/ui/autofill/save_address_bubble_controller.cc b/chrome/browser/ui/autofill/save_address_bubble_controller.cc
index 54e12b3..6bbf3b2 100644
--- a/chrome/browser/ui/autofill/save_address_bubble_controller.cc
+++ b/chrome/browser/ui/autofill/save_address_bubble_controller.cc
@@ -154,9 +154,10 @@
         GetPrimaryAccountInfoFromBrowserContext(
             web_contents()->GetBrowserContext());
 
-    int string_id = pdm->IsSyncFeatureEnabledForAutofill()
-                        ? IDS_AUTOFILL_SYNCABLE_PROFILE_MIGRATION_PROMPT_NOTICE
-                        : IDS_AUTOFILL_LOCAL_PROFILE_MIGRATION_PROMPT_NOTICE;
+    int string_id =
+        pdm->address_data_manager().IsSyncFeatureEnabledForAutofill()
+            ? IDS_AUTOFILL_SYNCABLE_PROFILE_MIGRATION_PROMPT_NOTICE
+            : IDS_AUTOFILL_LOCAL_PROFILE_MIGRATION_PROMPT_NOTICE;
 
     return l10n_util::GetStringFUTF16(string_id,
                                       base::UTF8ToUTF16(account->email));
diff --git a/chrome/browser/ui/passwords/manage_passwords_test.cc b/chrome/browser/ui/passwords/manage_passwords_test.cc
index 6641defb..2ea6aaa8 100644
--- a/chrome/browser/ui/passwords/manage_passwords_test.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_test.cc
@@ -23,6 +23,8 @@
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "components/password_manager/core/browser/form_saver.h"
+#include "components/password_manager/core/browser/form_saver_impl.h"
 #include "components/password_manager/core/browser/mock_password_form_manager_for_ui.h"
 #include "components/password_manager/core/browser/password_form.h"
 #include "components/password_manager/core/browser/password_form_manager.h"
@@ -246,6 +248,14 @@
   }
 }
 
+void ManagePasswordsTest::SetupSaveToAccountStore() {
+  ON_CALL(*client_.GetPasswordFeatureManager(), IsOptedInForAccountStorage())
+      .WillByDefault(testing::Return(true));
+  ON_CALL(*client_.GetPasswordFeatureManager(), GetDefaultPasswordStore())
+      .WillByDefault(testing::Return(
+          password_manager::PasswordForm::Store::kAccountStore));
+}
+
 std::unique_ptr<base::HistogramSamples> ManagePasswordsTest::GetSamples(
     const char* histogram) {
   // Ensure that everything has been properly recorded before pulling samples.
@@ -258,7 +268,9 @@
       browser()->tab_strip_model()->GetActiveWebContents());
 }
 
-std::unique_ptr<PasswordFormManager> ManagePasswordsTest::CreateFormManager() {
+std::unique_ptr<PasswordFormManager> ManagePasswordsTest::CreateFormManager(
+    password_manager::PasswordStoreInterface* profile_store,
+    password_manager::PasswordStoreInterface* account_store) {
   autofill::FormData observed_form;
   observed_form.url = password_form_.url;
   autofill::FormFieldData field;
@@ -267,12 +279,21 @@
   field.form_control_type = autofill::FormControlType::kInputPassword;
   observed_form.fields.push_back(field);
 
+  std::unique_ptr<password_manager::FormSaver> form_saver;
+  if (profile_store) {
+    form_saver =
+        std::make_unique<password_manager::FormSaverImpl>(profile_store);
+  } else {
+    form_saver = std::make_unique<password_manager::StubFormSaver>();
+  }
+
   auto form_manager = std::make_unique<PasswordFormManager>(
       &client_, driver_.AsWeakPtr(), observed_form, &fetcher_,
       std::make_unique<password_manager::PasswordSaveManagerImpl>(
-          /*profile_form_saver=*/std::make_unique<
-              password_manager::StubFormSaver>(),
-          /*account_form_saver=*/nullptr),
+          /*profile_form_saver=*/std::move(form_saver),
+          /*account_form_saver=*/account_store
+              ? std::make_unique<password_manager::FormSaverImpl>(account_store)
+              : nullptr),
       /*metrics_recorder=*/nullptr);
 
   insecure_credential_ = password_form_;
diff --git a/chrome/browser/ui/passwords/manage_passwords_test.h b/chrome/browser/ui/passwords/manage_passwords_test.h
index cc1b1c60..3afe28a 100644
--- a/chrome/browser/ui/passwords/manage_passwords_test.h
+++ b/chrome/browser/ui/passwords/manage_passwords_test.h
@@ -75,6 +75,9 @@
   // Put the controller, icon, and bubble into a moving-password state.
   void SetupMovingPasswords();
 
+  // Put the client into a state which induces password save to account store.
+  void SetupSaveToAccountStore();
+
   // Always configures a signed-in user, and when |is_enabled| is true, it also
   // configures the Sync service to sync passwords. |is_account_storage_enabled|
   // enables account storage for the user.
@@ -88,9 +91,16 @@
   // Get the UI controller for the current WebContents.
   ManagePasswordsUIController* GetController();
 
- private:
-  std::unique_ptr<password_manager::PasswordFormManager> CreateFormManager();
+ protected:
+  // Creates a form manager using the given password password stores.
+  // If |profile_store| is nullptr, password_manager::StubFormSaver is used for
+  // the profile store. If |account_store| is nullptr, a nullptr
+  // password_manager::FormSaver is used for the account store.
+  std::unique_ptr<password_manager::PasswordFormManager> CreateFormManager(
+      password_manager::PasswordStoreInterface* profile_store = nullptr,
+      password_manager::PasswordStoreInterface* account_store = nullptr);
 
+ private:
   password_manager::PasswordForm password_form_;
   password_manager::PasswordForm insecure_credential_;
   base::HistogramTester histogram_tester_;
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
index 9ed7998..8d0310be 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
@@ -25,6 +25,7 @@
 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
 #include "chrome/browser/password_manager/profile_password_store_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
+#include "chrome/browser/signin/signin_promo_util.h"
 #include "chrome/browser/signin/signin_ui_util.h"
 #include "chrome/browser/ui/autofill/autofill_signin_promo_tab_helper.h"
 #include "chrome/browser/ui/browser_command_controller.h"
@@ -764,6 +765,8 @@
         ->NotifyEvent("passwords_account_storage_used");
   }
 
+  // TODO(crbug/333709971): Decide whether the post save compromised bubble or
+  // the sign in promo bubble should be shown.
   post_save_compromised_helper_ =
       std::make_unique<password_manager::PostSaveCompromisedHelper>(
           passwords_data_.form_manager()->GetInsecureCredentials(), username);
@@ -780,7 +783,11 @@
   // The icon is to be updated after the bubble (either "Save password" or "Sign
   // in to Chrome") is closed.
   bubble_status_ = BubbleStatus::SHOWN_PENDING_ICON_UPDATE;
-  if (Browser* browser = chrome::FindBrowserWithTab(web_contents())) {
+  Browser* browser = chrome::FindBrowserWithTab(web_contents());
+  // Do not trigger the IPH if the sign in promo will be shown.
+  if (browser && !signin::ShouldShowSignInPromo(
+                     *browser->profile(),
+                     signin::SignInAutofillBubblePromoType::Passwords)) {
     if (browser->window()->MaybeShowFeaturePromo(
             feature_engagement::
                 kIPHPasswordsManagementBubbleAfterSaveFeature)) {
diff --git a/chrome/browser/ui/passwords/password_cross_domain_confirmation_popup_controller.cc b/chrome/browser/ui/passwords/password_cross_domain_confirmation_popup_controller.cc
deleted file mode 100644
index 7a3f6bfe..0000000
--- a/chrome/browser/ui/passwords/password_cross_domain_confirmation_popup_controller.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/passwords/password_cross_domain_confirmation_popup_controller.h"
-
-#include "base/functional/bind.h"
-#include "chrome/browser/ui/passwords/password_cross_domain_confirmation_popup_view.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
-
-PasswordCrossDomainConfirmationPopupController::
-    PasswordCrossDomainConfirmationPopupController(
-        content::WebContents* web_contents)
-    : content::WebContentsObserver(web_contents) {}
-
-PasswordCrossDomainConfirmationPopupController::
-    ~PasswordCrossDomainConfirmationPopupController() {
-  HideImpl();
-}
-
-void PasswordCrossDomainConfirmationPopupController::Show(
-    const gfx::RectF& element_bounds,
-    base::i18n::TextDirection text_direction,
-    const GURL& domain,
-    const std::u16string& password_origin,
-    base::OnceClosure confirmation_callback) {
-  if (!web_contents()) {
-    return;
-  }
-
-  HideImpl();
-
-  element_bounds_ = element_bounds;
-  text_direction_ = text_direction;
-  confirmation_callback_ = std::move(confirmation_callback);
-
-  view_ = PasswordCrossDomainConfirmationPopupView::Show(
-      weak_ptr_factory_.GetWeakPtr(), domain, password_origin,
-      base::BindOnce(&PasswordCrossDomainConfirmationPopupController::OnConfirm,
-                     weak_ptr_factory_.GetWeakPtr()),
-      base::BindOnce(&PasswordCrossDomainConfirmationPopupController::OnCancel,
-                     weak_ptr_factory_.GetWeakPtr()));
-
-  content::RenderFrameHost* rfh = web_contents()->GetFocusedFrame();
-  popup_hide_helper_.emplace(
-      web_contents(), rfh->GetGlobalId(),
-      autofill::AutofillPopupHideHelper::HidingParams{},
-      /*hiding_callback=*/
-      base::BindRepeating(&PasswordCrossDomainConfirmationPopupController::Hide,
-                          base::Unretained(this)),
-      /*pip_detection_callback=*/
-      base::BindRepeating(&PasswordCrossDomainConfirmationPopupController::
-                              OverlapsWithPictureInPictureWindow,
-                          base::Unretained(this)));
-}
-
-void PasswordCrossDomainConfirmationPopupController::Hide(
-    autofill::PopupHidingReason) {
-  HideImpl();
-}
-
-void PasswordCrossDomainConfirmationPopupController::ViewDestroyed() {
-  HideImpl();
-}
-
-gfx::NativeView PasswordCrossDomainConfirmationPopupController::container_view()
-    const {
-  return web_contents() ? web_contents()->GetContentNativeView()
-                        : gfx::NativeView();
-}
-
-content::WebContents*
-PasswordCrossDomainConfirmationPopupController::GetWebContents() const {
-  return web_contents();
-}
-
-const gfx::RectF&
-PasswordCrossDomainConfirmationPopupController::element_bounds() const {
-  return element_bounds_;
-}
-
-base::i18n::TextDirection
-PasswordCrossDomainConfirmationPopupController::GetElementTextDirection()
-    const {
-  return text_direction_;
-}
-
-void PasswordCrossDomainConfirmationPopupController::HideImpl() {
-  if (view_) {
-    view_->Hide();
-  }
-  popup_hide_helper_.reset();
-}
-
-bool PasswordCrossDomainConfirmationPopupController::
-    OverlapsWithPictureInPictureWindow() const {
-  return view_ && view_->OverlapsWithPictureInPictureWindow();
-}
-
-void PasswordCrossDomainConfirmationPopupController::OnConfirm() {
-  HideImpl();
-
-  std::move(confirmation_callback_).Run();
-}
-
-void PasswordCrossDomainConfirmationPopupController::OnCancel() {
-  HideImpl();
-}
diff --git a/chrome/browser/ui/passwords/password_cross_domain_confirmation_popup_controller.h b/chrome/browser/ui/passwords/password_cross_domain_confirmation_popup_controller.h
deleted file mode 100644
index ebe5ada..0000000
--- a/chrome/browser/ui/passwords/password_cross_domain_confirmation_popup_controller.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2024 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_PASSWORDS_PASSWORD_CROSS_DOMAIN_CONFIRMATION_POPUP_CONTROLLER_H_
-#define CHROME_BROWSER_UI_PASSWORDS_PASSWORD_CROSS_DOMAIN_CONFIRMATION_POPUP_CONTROLLER_H_
-
-#include "base/functional/callback_forward.h"
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/ui/autofill/autofill_popup_hide_helper.h"
-#include "chrome/browser/ui/autofill/autofill_popup_view_delegate.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "ui/gfx/geometry/rect_f.h"
-#include "url/gurl.h"
-
-class PasswordCrossDomainConfirmationPopupView;
-
-// The controller of the cross domain usage confirmation popup. It provides API
-// to Show/Hide the popup and get the user's decision (via a callback).
-class PasswordCrossDomainConfirmationPopupController
-    : public autofill::AutofillPopupViewDelegate,
-      public content::WebContentsObserver {
- public:
-  explicit PasswordCrossDomainConfirmationPopupController(
-      content::WebContents* web_contents);
-  PasswordCrossDomainConfirmationPopupController(
-      const PasswordCrossDomainConfirmationPopupController&) = delete;
-  PasswordCrossDomainConfirmationPopupController& operator=(
-      const PasswordCrossDomainConfirmationPopupController&) = delete;
-  ~PasswordCrossDomainConfirmationPopupController() override;
-
-  // autofill::AutofillPopupViewDelegate:
-  void Hide(autofill::PopupHidingReason reason) override;
-  void ViewDestroyed() override;
-  gfx::NativeView container_view() const override;
-  content::WebContents* GetWebContents() const override;
-  const gfx::RectF& element_bounds() const override;
-  base::i18n::TextDirection GetElementTextDirection() const override;
-
-  // Creates and shows a popup pointing to `element_bounds` and presenting
-  // a message regarding cross domain password usage. `domain` is the domain
-  // of the current web site the popup is triggered on. `password_origin` is
-  // the name of the place where the password was originally created, it can
-  // be the domain of the web site or the name of the Android application.
-  // `confirmation_callback` is called if the user confirms the action, if
-  // the user cancels it, the popup is silently hidden.
-  // If the popup is already shown, it gets hidden and a new one shows up.
-  void Show(const gfx::RectF& element_bounds,
-            base::i18n::TextDirection text_direction,
-            const GURL& domain,
-            const std::u16string& password_origin,
-            base::OnceClosure confirmation_callback);
-
- private:
-  void HideImpl();
-  bool OverlapsWithPictureInPictureWindow() const;
-
-  // Handles the confirmation response from the view.
-  void OnConfirm();
-
-  // Handles the cancel response from the view.
-  void OnCancel();
-
-  gfx::RectF element_bounds_;
-  base::i18n::TextDirection text_direction_;
-  base::OnceClosure confirmation_callback_;
-
-  base::WeakPtr<PasswordCrossDomainConfirmationPopupView> view_;
-
-  std::optional<autofill::AutofillPopupHideHelper> popup_hide_helper_;
-
-  base::WeakPtrFactory<PasswordCrossDomainConfirmationPopupController>
-      weak_ptr_factory_{this};
-};
-
-#endif  // CHROME_BROWSER_UI_PASSWORDS_PASSWORD_CROSS_DOMAIN_CONFIRMATION_POPUP_CONTROLLER_H_
diff --git a/chrome/browser/ui/passwords/password_cross_domain_confirmation_popup_controller_impl.cc b/chrome/browser/ui/passwords/password_cross_domain_confirmation_popup_controller_impl.cc
new file mode 100644
index 0000000..3b7f390
--- /dev/null
+++ b/chrome/browser/ui/passwords/password_cross_domain_confirmation_popup_controller_impl.cc
@@ -0,0 +1,112 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/passwords/password_cross_domain_confirmation_popup_controller_impl.h"
+
+#include "base/functional/bind.h"
+#include "chrome/browser/ui/passwords/password_cross_domain_confirmation_popup_view.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+
+PasswordCrossDomainConfirmationPopupControllerImpl::
+    PasswordCrossDomainConfirmationPopupControllerImpl(
+        content::WebContents* web_contents)
+    : content::WebContentsObserver(web_contents) {}
+
+PasswordCrossDomainConfirmationPopupControllerImpl::
+    ~PasswordCrossDomainConfirmationPopupControllerImpl() {
+  HideImpl();
+}
+
+void PasswordCrossDomainConfirmationPopupControllerImpl::Show(
+    const gfx::RectF& element_bounds,
+    base::i18n::TextDirection text_direction,
+    const GURL& domain,
+    const std::u16string& password_origin,
+    base::OnceClosure confirmation_callback) {
+  if (!web_contents()) {
+    return;
+  }
+
+  HideImpl();
+
+  element_bounds_ = element_bounds;
+  text_direction_ = text_direction;
+  confirmation_callback_ = std::move(confirmation_callback);
+
+  view_ = PasswordCrossDomainConfirmationPopupView::Show(
+      weak_ptr_factory_.GetWeakPtr(), domain, password_origin,
+      base::BindOnce(
+          &PasswordCrossDomainConfirmationPopupControllerImpl::OnConfirm,
+          weak_ptr_factory_.GetWeakPtr()),
+      base::BindOnce(
+          &PasswordCrossDomainConfirmationPopupControllerImpl::OnCancel,
+          weak_ptr_factory_.GetWeakPtr()));
+
+  content::RenderFrameHost* rfh = web_contents()->GetFocusedFrame();
+  popup_hide_helper_.emplace(
+      web_contents(), rfh->GetGlobalId(),
+      autofill::AutofillPopupHideHelper::HidingParams{},
+      /*hiding_callback=*/
+      base::BindRepeating(
+          &PasswordCrossDomainConfirmationPopupControllerImpl::Hide,
+          base::Unretained(this)),
+      /*pip_detection_callback=*/
+      base::BindRepeating(&PasswordCrossDomainConfirmationPopupControllerImpl::
+                              OverlapsWithPictureInPictureWindow,
+                          base::Unretained(this)));
+}
+
+void PasswordCrossDomainConfirmationPopupControllerImpl::Hide(
+    autofill::PopupHidingReason) {
+  HideImpl();
+}
+
+void PasswordCrossDomainConfirmationPopupControllerImpl::ViewDestroyed() {
+  HideImpl();
+}
+
+gfx::NativeView
+PasswordCrossDomainConfirmationPopupControllerImpl::container_view() const {
+  return web_contents() ? web_contents()->GetContentNativeView()
+                        : gfx::NativeView();
+}
+
+content::WebContents*
+PasswordCrossDomainConfirmationPopupControllerImpl::GetWebContents() const {
+  return web_contents();
+}
+
+const gfx::RectF&
+PasswordCrossDomainConfirmationPopupControllerImpl::element_bounds() const {
+  return element_bounds_;
+}
+
+base::i18n::TextDirection
+PasswordCrossDomainConfirmationPopupControllerImpl::GetElementTextDirection()
+    const {
+  return text_direction_;
+}
+
+void PasswordCrossDomainConfirmationPopupControllerImpl::HideImpl() {
+  if (view_) {
+    view_->Hide();
+  }
+  popup_hide_helper_.reset();
+}
+
+bool PasswordCrossDomainConfirmationPopupControllerImpl::
+    OverlapsWithPictureInPictureWindow() const {
+  return view_ && view_->OverlapsWithPictureInPictureWindow();
+}
+
+void PasswordCrossDomainConfirmationPopupControllerImpl::OnConfirm() {
+  HideImpl();
+
+  std::move(confirmation_callback_).Run();
+}
+
+void PasswordCrossDomainConfirmationPopupControllerImpl::OnCancel() {
+  HideImpl();
+}
diff --git a/chrome/browser/ui/passwords/password_cross_domain_confirmation_popup_controller_impl.h b/chrome/browser/ui/passwords/password_cross_domain_confirmation_popup_controller_impl.h
new file mode 100644
index 0000000..d7c8dcd
--- /dev/null
+++ b/chrome/browser/ui/passwords/password_cross_domain_confirmation_popup_controller_impl.h
@@ -0,0 +1,70 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_PASSWORDS_PASSWORD_CROSS_DOMAIN_CONFIRMATION_POPUP_CONTROLLER_IMPL_H_
+#define CHROME_BROWSER_UI_PASSWORDS_PASSWORD_CROSS_DOMAIN_CONFIRMATION_POPUP_CONTROLLER_IMPL_H_
+
+#include "base/functional/callback_forward.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/ui/autofill/autofill_popup_hide_helper.h"
+#include "chrome/browser/ui/autofill/autofill_popup_view_delegate.h"
+#include "components/password_manager/core/browser/password_cross_domain_confirmation_popup_controller.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "url/gurl.h"
+
+class PasswordCrossDomainConfirmationPopupView;
+
+// Implementation of the cross domain usage confirmation popup controller.
+class PasswordCrossDomainConfirmationPopupControllerImpl
+    : public password_manager::PasswordCrossDomainConfirmationPopupController,
+      public autofill::AutofillPopupViewDelegate,
+      public content::WebContentsObserver {
+ public:
+  explicit PasswordCrossDomainConfirmationPopupControllerImpl(
+      content::WebContents* web_contents);
+  PasswordCrossDomainConfirmationPopupControllerImpl(
+      const PasswordCrossDomainConfirmationPopupControllerImpl&) = delete;
+  PasswordCrossDomainConfirmationPopupControllerImpl& operator=(
+      const PasswordCrossDomainConfirmationPopupControllerImpl&) = delete;
+  ~PasswordCrossDomainConfirmationPopupControllerImpl() override;
+
+  // autofill::AutofillPopupViewDelegate:
+  void Hide(autofill::PopupHidingReason reason) override;
+  void ViewDestroyed() override;
+  gfx::NativeView container_view() const override;
+  content::WebContents* GetWebContents() const override;
+  const gfx::RectF& element_bounds() const override;
+  base::i18n::TextDirection GetElementTextDirection() const override;
+
+  // PasswordCrossDomainConfirmationPopupController:
+  void Show(const gfx::RectF& element_bounds,
+            base::i18n::TextDirection text_direction,
+            const GURL& domain,
+            const std::u16string& password_origin,
+            base::OnceClosure confirmation_callback) override;
+
+ private:
+  void HideImpl();
+  bool OverlapsWithPictureInPictureWindow() const;
+
+  // Handles the confirmation response from the view.
+  void OnConfirm();
+
+  // Handles the cancel response from the view.
+  void OnCancel();
+
+  gfx::RectF element_bounds_;
+  base::i18n::TextDirection text_direction_;
+  base::OnceClosure confirmation_callback_;
+
+  base::WeakPtr<PasswordCrossDomainConfirmationPopupView> view_;
+
+  std::optional<autofill::AutofillPopupHideHelper> popup_hide_helper_;
+
+  base::WeakPtrFactory<PasswordCrossDomainConfirmationPopupControllerImpl>
+      weak_ptr_factory_{this};
+};
+
+#endif  // CHROME_BROWSER_UI_PASSWORDS_PASSWORD_CROSS_DOMAIN_CONFIRMATION_POPUP_CONTROLLER_IMPL_H_
diff --git a/chrome/browser/ui/sync/sync_promo_ui.cc b/chrome/browser/ui/sync/sync_promo_ui.cc
index e481b42e..df5da2ce 100644
--- a/chrome/browser/ui/sync/sync_promo_ui.cc
+++ b/chrome/browser/ui/sync/sync_promo_ui.cc
@@ -7,11 +7,12 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/signin_promo_util.h"
 #include "chrome/browser/sync/sync_service_factory.h"
+#include "components/signin/public/base/consent_level.h"
 #include "components/sync/service/sync_prefs.h"
 
 bool SyncPromoUI::ShouldShowSyncPromo(Profile* profile) {
   // Don't show sync promo if the sign in promo should not be shown.
-  if (!signin::ShouldShowPromo(profile)) {
+  if (!signin::ShouldShowPromo(*profile, signin::ConsentLevel::kSync)) {
     return false;
   }
 
diff --git a/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.cc b/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.cc
index 54373aa..f1a13a6 100644
--- a/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.cc
+++ b/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.cc
@@ -36,7 +36,7 @@
 namespace {
 using TabRole = ::TabSharingInfoBarDelegate::TabRole;
 
-constexpr int kCscPermissionButtonIconHeight = 16;
+constexpr int kCapturedSurfaceControlIndicatorButtonIconHeight = 16;
 }  // namespace
 
 class TabSharingInfoBarDelegate::TabSharingInfoBarDelegateButton {
@@ -165,12 +165,12 @@
   const bool focus_target_is_capturer_;
 };
 
-class TabSharingInfoBarDelegate::CscPermissionButton
+class TabSharingInfoBarDelegate::CscIndicatorButton
     : public TabSharingInfoBarDelegate::TabSharingInfoBarDelegateButton {
  public:
-  explicit CscPermissionButton(content::WebContents* web_contents)
+  explicit CscIndicatorButton(content::WebContents* web_contents)
       : web_contents_(web_contents ? web_contents->GetWeakPtr() : nullptr) {}
-  ~CscPermissionButton() override = default;
+  ~CscIndicatorButton() override = default;
 
   void Click(infobars::InfoBar* infobar) override {
     if (!web_contents_) {
@@ -187,9 +187,9 @@
   bool IsEnabled() const override { return true; }
 
   ui::ImageModel GetImage() const override {
-    return ui::ImageModel::FromVectorIcon(vector_icons::kTouchpadMouseIcon,
-                                          ui::kColorSysPrimary,
-                                          kCscPermissionButtonIconHeight);
+    return ui::ImageModel::FromVectorIcon(
+        vector_icons::kTouchpadMouseIcon, ui::kColorSysPrimary,
+        kCapturedSurfaceControlIndicatorButtonIconHeight);
   }
 
  private:
@@ -322,8 +322,7 @@
   if (role_ == TabRole::kCapturingTab && captured_surface_control_active &&
       base::FeatureList::IsEnabled(
           features::kCapturedSurfaceControlStickyPermissions)) {
-    csc_permission_button_ =
-        std::make_unique<CscPermissionButton>(web_contents);
+    csc_indicator_button_ = std::make_unique<CscIndicatorButton>(web_contents);
   }
 }
 
@@ -379,9 +378,9 @@
       DCHECK(quick_nav_button_);
       return quick_nav_button_->GetLabel();
 
-    case kCscPermission:
-      DCHECK(csc_permission_button_);
-      return csc_permission_button_->GetLabel();
+    case kCapturedSurfaceControlIndicator:
+      DCHECK(csc_indicator_button_);
+      return csc_indicator_button_->GetLabel();
   }
   NOTREACHED_NORETURN();
 }
@@ -405,9 +404,9 @@
       DCHECK(quick_nav_button_);
       return quick_nav_button_->GetImage();
 
-    case kCscPermission:
-      DCHECK(csc_permission_button_);
-      return csc_permission_button_->GetImage();
+    case kCapturedSurfaceControlIndicator:
+      DCHECK(csc_indicator_button_);
+      return csc_indicator_button_->GetImage();
   }
   NOTREACHED_NORETURN();
 }
@@ -428,9 +427,9 @@
       DCHECK(quick_nav_button_);
       return quick_nav_button_->IsEnabled();
 
-    case kCscPermission:
-      DCHECK(csc_permission_button_);
-      return csc_permission_button_->IsEnabled();
+    case kCapturedSurfaceControlIndicator:
+      DCHECK(csc_indicator_button_);
+      return csc_indicator_button_->IsEnabled();
   }
   NOTREACHED_NORETURN();
 }
@@ -452,9 +451,9 @@
       DCHECK(quick_nav_button_);
       return quick_nav_button_->GetTooltip();
 
-    case kCscPermission:
-      DCHECK(csc_permission_button_);
-      return csc_permission_button_->GetTooltip();
+    case kCapturedSurfaceControlIndicator:
+      DCHECK(csc_indicator_button_);
+      return csc_indicator_button_->GetTooltip();
   }
   NOTREACHED_NORETURN();
 }
@@ -462,7 +461,7 @@
 int TabSharingInfoBarDelegate::GetButtons() const {
   return kStop | (share_this_tab_instead_button_ ? kShareThisTabInstead : 0) |
          (quick_nav_button_ ? kQuickNav : 0) |
-         (csc_permission_button_ ? kCscPermission : 0);
+         (csc_indicator_button_ ? kCapturedSurfaceControlIndicator : 0);
 }
 
 void TabSharingInfoBarDelegate::Stop() {
@@ -481,8 +480,8 @@
 
 void TabSharingInfoBarDelegate::
     OnCapturedSurfaceControlActivityIndicatorPressed() {
-  DCHECK(csc_permission_button_);
-  csc_permission_button_->Click(infobar());
+  DCHECK(csc_indicator_button_);
+  csc_indicator_button_->Click(infobar());
 }
 
 bool TabSharingInfoBarDelegate::IsCloseable() const {
diff --git a/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.h b/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.h
index dcfc899..4358010 100644
--- a/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.h
+++ b/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate.h
@@ -53,8 +53,7 @@
     kStop = 1 << 0,
     kShareThisTabInstead = 1 << 1,
     kQuickNav = 1 << 2,
-    // TODO(crbug.com/1466247): Rename to kCapturedSurfaceControlIndicator.
-    kCscPermission = 1 << 3,
+    kCapturedSurfaceControlIndicator = 1 << 3,
   };
 
   enum class ButtonState {
@@ -82,7 +81,7 @@
   class TabSharingInfoBarDelegateButton;
   class ShareTabInsteadButton;
   class SwitchToTabButton;
-  class CscPermissionButton;
+  class CscIndicatorButton;
 
   // Creates a tab sharing infobar, which has 1-2 buttons.
   //
@@ -163,9 +162,7 @@
 
   std::unique_ptr<ShareTabInsteadButton> share_this_tab_instead_button_;
   std::unique_ptr<SwitchToTabButton> quick_nav_button_;
-  // TODO(crbug.com/324468211): Rename both class and member to remove the word
-  // "permission".
-  std::unique_ptr<CscPermissionButton> csc_permission_button_;
+  std::unique_ptr<CscIndicatorButton> csc_indicator_button_;
 };
 
 std::unique_ptr<infobars::InfoBar> CreateTabSharingInfoBar(
diff --git a/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate_unittest.cc b/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate_unittest.cc
index 0f3c8b5..229dc958 100644
--- a/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate_unittest.cc
+++ b/chrome/browser/ui/tab_sharing/tab_sharing_infobar_delegate_unittest.cc
@@ -192,11 +192,11 @@
                 IDS_TAB_SHARING_INFOBAR_SHARING_ANOTHER_UNTITLED_TAB_LABEL,
                 kAppName));
 
-  const int expected_buttons = TabSharingInfoBarDelegate::kStop |
-                               TabSharingInfoBarDelegate::kQuickNav |
-                               (captured_surface_control_active_
-                                    ? TabSharingInfoBarDelegate::kCscPermission
-                                    : 0);
+  const int expected_buttons =
+      TabSharingInfoBarDelegate::kStop | TabSharingInfoBarDelegate::kQuickNav |
+      (captured_surface_control_active_
+           ? TabSharingInfoBarDelegate::kCapturedSurfaceControlIndicator
+           : 0);
   EXPECT_EQ(delegate->GetButtons(), expected_buttons);
   EXPECT_EQ(delegate->GetButtonLabel(TabSharingInfoBarDelegate::kStop),
             l10n_util::GetStringUTF16(IDS_TAB_SHARING_INFOBAR_STOP_BUTTON));
@@ -208,7 +208,8 @@
 
   if (captured_surface_control_active_) {
     EXPECT_EQ(
-        delegate->GetButtonLabel(TabSharingInfoBarDelegate::kCscPermission),
+        delegate->GetButtonLabel(
+            TabSharingInfoBarDelegate::kCapturedSurfaceControlIndicator),
         l10n_util::GetStringUTF16(
             IDS_TAB_SHARING_INFOBAR_CAPTURED_SURFACE_CONTROL_PERMISSION_BUTTON));
   }
diff --git a/chrome/browser/ui/views/editor_menu/editor_menu_promo_card_view.cc b/chrome/browser/ui/views/editor_menu/editor_menu_promo_card_view.cc
index d48410f..fedd043 100644
--- a/chrome/browser/ui/views/editor_menu/editor_menu_promo_card_view.cc
+++ b/chrome/browser/ui/views/editor_menu/editor_menu_promo_card_view.cc
@@ -42,6 +42,8 @@
 namespace {
 
 constexpr char kWidgetName[] = "EditorMenuPromoCardViewWidget";
+constexpr char16_t kCardShownAnnouncement[] =
+    u"Help Me Write, press tab to focus the Help Me Write card.";
 
 constexpr int kPromoCardIconSizeDip = 20;
 
@@ -160,6 +162,14 @@
   return true;
 }
 
+void EditorMenuPromoCardView::OnWidgetVisibilityChanged(views::Widget* widget,
+                                                        bool visible) {
+  if (visible && !queued_announcement_) {
+    GetViewAccessibility().AnnounceAlert(kCardShownAnnouncement);
+    queued_announcement_ = true;
+  }
+}
+
 void EditorMenuPromoCardView::UpdateBounds(
     const gfx::Rect& anchor_view_bounds) {
   GetWidget()->SetBounds(GetEditorMenuBounds(anchor_view_bounds, this));
diff --git a/chrome/browser/ui/views/editor_menu/editor_menu_promo_card_view.h b/chrome/browser/ui/views/editor_menu/editor_menu_promo_card_view.h
index 3ad8e58..e633e15 100644
--- a/chrome/browser/ui/views/editor_menu/editor_menu_promo_card_view.h
+++ b/chrome/browser/ui/views/editor_menu/editor_menu_promo_card_view.h
@@ -51,6 +51,7 @@
   void OnWidgetDestroying(views::Widget* widget) override;
   void OnWidgetActivationChanged(views::Widget* widget, bool active) override;
   bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
+  void OnWidgetVisibilityChanged(views::Widget* widget, bool visible) override;
 
   void UpdateBounds(const gfx::Rect& anchor_view_bounds);
 
@@ -74,6 +75,8 @@
   raw_ptr<views::MdTextButton> dismiss_button_ = nullptr;
   raw_ptr<views::MdTextButton> try_it_button_ = nullptr;
 
+  bool queued_announcement_ = false;
+
   base::ScopedObservation<views::Widget, views::WidgetObserver>
       widget_observation_{this};
 
diff --git a/chrome/browser/ui/views/editor_menu/editor_menu_view.cc b/chrome/browser/ui/views/editor_menu/editor_menu_view.cc
index 868c887..2e085a95 100644
--- a/chrome/browser/ui/views/editor_menu/editor_menu_view.cc
+++ b/chrome/browser/ui/views/editor_menu/editor_menu_view.cc
@@ -51,6 +51,8 @@
 namespace {
 
 constexpr char kWidgetName[] = "EditorMenuViewWidget";
+constexpr char16_t kCardShownAnnouncement[] =
+    u"Help Me Write, press tab to focus the Help Me Write card.";
 
 constexpr gfx::Insets kTitleContainerInsets = gfx::Insets::TLBR(12, 16, 12, 14);
 
@@ -159,6 +161,11 @@
                                                bool visible) {
   CHECK(delegate_);
   delegate_->OnEditorMenuVisibilityChanged(visible);
+
+  if (visible && !queued_announcement_) {
+    GetViewAccessibility().AnnounceAlert(kCardShownAnnouncement);
+    queued_announcement_ = true;
+  }
 }
 
 void EditorMenuView::UpdateBounds(const gfx::Rect& anchor_view_bounds) {
diff --git a/chrome/browser/ui/views/editor_menu/editor_menu_view.h b/chrome/browser/ui/views/editor_menu/editor_menu_view.h
index 5012a51..1f132547 100644
--- a/chrome/browser/ui/views/editor_menu/editor_menu_view.h
+++ b/chrome/browser/ui/views/editor_menu/editor_menu_view.h
@@ -92,6 +92,8 @@
 
   raw_ptr<EditorMenuTextfieldView> textfield_ = nullptr;
 
+  bool queued_announcement_ = false;
+
   base::WeakPtrFactory<EditorMenuView> weak_factory_{this};
 };
 
diff --git a/chrome/browser/ui/views/passwords/password_save_update_view.cc b/chrome/browser/ui/views/passwords/password_save_update_view.cc
index 90120f5..2fb969c 100644
--- a/chrome/browser/ui/views/passwords/password_save_update_view.cc
+++ b/chrome/browser/ui/views/passwords/password_save_update_view.cc
@@ -11,6 +11,7 @@
 
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/signin_promo_util.h"
 #include "chrome/browser/ui/browser_element_identifiers.h"
 #include "chrome/browser/ui/hats/hats_service.h"
 #include "chrome/browser/ui/hats/hats_service_factory.h"
@@ -21,12 +22,14 @@
 #include "chrome/browser/ui/views/chrome_typography.h"
 #include "chrome/browser/ui/views/passwords/credentials_item_view.h"
 #include "chrome/browser/ui/views/passwords/views_utils.h"
+#include "chrome/browser/ui/views/promos/autofill_bubble_signin_promo_view.h"
 #include "chrome/browser/ui/views/user_education/browser_feature_promo_controller.h"
 #include "chrome/grit/branded_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
 #include "components/feature_engagement/public/feature_constants.h"
 #include "components/feature_engagement/public/tracker.h"
+#include "components/signin/public/base/signin_buildflags.h"
 #include "components/user_education/common/feature_promo_specification.h"
 #include "components/user_education/common/help_bubble_params.h"
 #include "content/public/browser/storage_partition.h"
@@ -44,6 +47,7 @@
 #include "ui/views/interaction/element_tracker_views.h"
 #include "ui/views/layout/fill_layout.h"
 #include "ui/views/layout/flex_layout.h"
+#include "ui/views/view_class_properties.h"
 
 // TODO(crbug.com/1077706): come up with a more general solution for this.
 // This layout auto-resizes the host view to always adapt to changes in the size
@@ -189,8 +193,12 @@
       (dialog->controller_.*func)();
     };
 
-    SetAcceptCallback(base::BindOnce(button_clicked, base::Unretained(this),
-                                     &Controller::OnSaveClicked));
+    SetAcceptCallbackWithClose(
+        base::BindRepeating(button_clicked, base::Unretained(this),
+                            &Controller::OnSaveClicked)
+            .Then(base::BindRepeating(
+                &PasswordSaveUpdateView::CloseOrReplaceWithPromo,
+                base::Unretained(this))));
     SetCancelCallback(base::BindOnce(
         button_clicked, base::Unretained(this),
         is_update_bubble_ ? &Controller::OnNoThanksClicked
@@ -224,6 +232,48 @@
   return &controller_;
 }
 
+bool PasswordSaveUpdateView::CloseOrReplaceWithPromo() {
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+  // Close the bubble if the sign in promo should not be shown.
+  if (!signin::ShouldShowSignInPromo(
+          *controller_.GetProfile(),
+          signin::SignInAutofillBubblePromoType::Passwords)) {
+    return true;
+  }
+
+  // Remove current elements.
+  animating_layout_for_iph_observation_.Reset();
+  animating_layout_for_username_dropdown_observation_.reset();
+  username_dropdown_ = nullptr;
+  password_dropdown_ = nullptr;
+  destination_dropdown_ = nullptr;
+  accessibility_alert_ = nullptr;
+  RemoveAllChildViews();
+  SetLayoutManager(std::make_unique<views::FillLayout>());
+  SetShowIcon(false);
+  SetButtons(ui::DIALOG_BUTTON_NONE);
+  GetBubbleFrameView()->SetFootnoteView(nullptr);
+
+  // TODO(crbug/319411476): Should be changed to the correct string, moved
+  // inside the AutofillBubbleSignInPromoView and depending on autofill type.
+  SetTitle(IDS_PASSWORD_GENERATION_HELP_TEXT_TRUSTED_ADVICE);
+
+  // Show the sign in promo.
+  auto sign_in_promo = std::make_unique<AutofillBubbleSignInPromoView>(
+      controller_.GetWebContents(),
+      signin::SignInAutofillBubblePromoType::Passwords);
+  AddChildView(std::move(sign_in_promo));
+  SizeToContents();
+
+  GetBubbleFrameView()->SetProperty(views::kElementIdentifierKey,
+                                    kPasswordBubble);
+
+  return false;
+#else
+  return true;
+#endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
+}
+
 void PasswordSaveUpdateView::DestinationChanged() {
   bool is_account_store_selected =
       destination_dropdown_->GetSelectedIndex() == 0u;
@@ -520,3 +570,5 @@
       },
       base::Unretained(this), std::move(pin)));
 }
+
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(PasswordSaveUpdateView, kPasswordBubble);
diff --git a/chrome/browser/ui/views/passwords/password_save_update_view.h b/chrome/browser/ui/views/passwords/password_save_update_view.h
index 73e08ba..447e9627 100644
--- a/chrome/browser/ui/views/passwords/password_save_update_view.h
+++ b/chrome/browser/ui/views/passwords/password_save_update_view.h
@@ -30,6 +30,8 @@
                                public views::WidgetObserver,
                                public views::AnimatingLayoutManager::Observer {
  public:
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kPasswordBubble);
+
   PasswordSaveUpdateView(content::WebContents* web_contents,
                          views::View* anchor_view,
                          DisplayReason reason);
@@ -61,6 +63,12 @@
   PasswordBubbleControllerBase* GetController() override;
   const PasswordBubbleControllerBase* GetController() const override;
 
+  // If the sign in promo should be shown, it will remove the current contents
+  // of the bubble and replace them with the sign in promo. Returns true if the
+  // bubble is not replaced with the promo, and therefore closed. Returns false
+  // if it is replaced, which will cause the bubble to stay open.
+  bool CloseOrReplaceWithPromo();
+
   // PasswordBubbleViewBase:
   views::View* GetInitiallyFocusedView() override;
   bool IsDialogButtonEnabled(ui::DialogButton button) const override;
diff --git a/chrome/browser/ui/views/promos/autofill_bubble_signin_promo_interactive_uitest.cc b/chrome/browser/ui/views/promos/autofill_bubble_signin_promo_interactive_uitest.cc
new file mode 100644
index 0000000..fd3ded1
--- /dev/null
+++ b/chrome/browser/ui/views/promos/autofill_bubble_signin_promo_interactive_uitest.cc
@@ -0,0 +1,310 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/password_manager/password_manager_test_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/chrome_signin_client_test_util.h"
+#include "chrome/browser/signin/dice_tab_helper.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
+#include "chrome/browser/ui/autofill/autofill_signin_promo_tab_helper.h"
+#include "chrome/browser/ui/passwords/manage_passwords_test.h"
+#include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
+#include "chrome/browser/ui/views/passwords/password_bubble_view_base.h"
+#include "chrome/browser/ui/views/passwords/password_save_update_view.h"
+#include "chrome/browser/ui/views/promos/autofill_bubble_signin_promo_view.h"
+#include "chrome/browser/ui/views/promos/bubble_signin_promo_signin_button_view.h"
+#include "chrome/test/base/interactive_test_utils.h"
+#include "chrome/test/base/profile_waiter.h"
+#include "components/password_manager/core/browser/password_form.h"
+#include "components/password_manager/core/browser/password_manager_test_utils.h"
+#include "components/password_manager/core/browser/password_store/test_password_store.h"
+#include "components/signin/public/base/consent_level.h"
+#include "components/signin/public/base/signin_pref_names.h"
+#include "components/signin/public/base/signin_switches.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
+#include "components/signin/public/identity_manager/identity_test_utils.h"
+#include "components/sync/base/features.h"
+#include "content/public/test/browser_test.h"
+
+namespace {
+constexpr char kButton[] = "SignInButton";
+}  // namespace
+
+MATCHER_P(FormMatches, form, "") {
+  return form.signon_realm == arg.signon_realm && form.url == arg.url &&
+         form.action == arg.action &&
+         form.username_element == arg.username_element &&
+         form.password_element == arg.password_element;
+}
+
+class AutofillBubbleSignInPromoInteractiveUITest : public ManagePasswordsTest {
+ public:
+  void SetUpInProcessBrowserTestFixture() override {
+    ManagePasswordsTest::SetUpInProcessBrowserTestFixture();
+    url_loader_factory_helper_.SetUp();
+    create_services_subscription_ =
+        BrowserContextDependencyManager::GetInstance()
+            ->RegisterCreateServicesCallbackForTesting(base::BindRepeating(
+                &AutofillBubbleSignInPromoInteractiveUITest::
+                    OnWillCreateBrowserContextServices,
+                base::Unretained(this)));
+  }
+
+  void OnWillCreateBrowserContextServices(content::BrowserContext* context) {
+    // Create password stores.
+    local_password_store_ = CreateAndUseTestPasswordStore(context);
+    account_password_store_ = CreateAndUseTestAccountPasswordStore(context);
+  }
+
+  // Trigger the password save by simulating an "Accept" in the password bubble,
+  // and wait for it to appear in the store. If |store| is kAccountStore, it
+  // will wait for a password to appear in the account store, if not, in the
+  // profile store.
+  void SavePassword(password_manager::PasswordForm::Store store);
+
+  // Perform a sign in with the password bubble access point and wait for an
+  // event in the account store.
+  void SignIn();
+
+  // Returns true if the current tab's URL is a sign in URL.
+  bool IsSignInURL();
+
+  // Returns true if there is a primary account without a refresh token in
+  // persistent error state.
+  bool IsSignedIn();
+
+  network::TestURLLoaderFactory* test_url_loader_factory() {
+    return url_loader_factory_helper_.test_url_loader_factory();
+  }
+
+  signin::IdentityManager* identity_manager() {
+    return IdentityManagerFactory::GetForProfile(browser()->profile());
+  }
+
+ protected:
+  base::test::ScopedFeatureList scoped_feature_list_{
+      switches::kExplicitBrowserSigninUIOnDesktop};
+
+  ChromeSigninClientWithURLLoaderHelper url_loader_factory_helper_;
+  base::CallbackListSubscription create_services_subscription_;
+  scoped_refptr<password_manager::TestPasswordStore> local_password_store_;
+  scoped_refptr<password_manager::TestPasswordStore> account_password_store_;
+};
+
+void AutofillBubbleSignInPromoInteractiveUITest::SavePassword(
+    password_manager::PasswordForm::Store store) {
+  auto store_waiter =
+      store == password_manager::PasswordForm::Store::kAccountStore
+          ? password_manager::PasswordStoreWaiter(account_password_store_.get())
+          : password_manager::PasswordStoreWaiter(local_password_store_.get());
+
+  PasswordBubbleViewBase* bubble =
+      PasswordBubbleViewBase::manage_password_bubble();
+  bubble->AcceptDialog();
+
+  store_waiter.WaitOrReturn();
+}
+
+void AutofillBubbleSignInPromoInteractiveUITest::SignIn() {
+  signin::MakeAccountAvailable(
+      identity_manager(),
+      signin::AccountAvailabilityOptionsBuilder(test_url_loader_factory())
+          .WithCookie()
+          .AsPrimary(signin::ConsentLevel::kSignin)
+          .WithAccessPoint(
+              signin_metrics::AccessPoint::ACCESS_POINT_PASSWORD_BUBBLE)
+          .Build("test@email.com"));
+}
+
+bool AutofillBubbleSignInPromoInteractiveUITest::IsSignInURL() {
+  DiceTabHelper* tab_helper = DiceTabHelper::FromWebContents(
+      browser()->tab_strip_model()->GetActiveWebContents());
+  return tab_helper->IsChromeSigninPage();
+}
+
+bool AutofillBubbleSignInPromoInteractiveUITest::IsSignedIn() {
+  return identity_manager()->HasPrimaryAccountWithRefreshToken(
+             signin::ConsentLevel::kSignin) &&
+         !identity_manager()->HasAccountWithRefreshTokenInPersistentErrorState(
+             identity_manager()->GetPrimaryAccountId(
+                 signin::ConsentLevel::kSignin));
+}
+
+IN_PROC_BROWSER_TEST_F(AutofillBubbleSignInPromoInteractiveUITest,
+                       SignInPromoNoAccountPresent) {
+  // Set up password and password stores.
+  GetController()->OnPasswordSubmitted(CreateFormManager(
+      local_password_store_.get(), account_password_store_.get()));
+
+  // Save the password and check that it was properly saved to profile store.
+  SavePassword(password_manager::PasswordForm::Store::kProfileStore);
+  EXPECT_EQ(1u, local_password_store_->stored_passwords().size());
+  EXPECT_EQ(0u, account_password_store_->stored_passwords().size());
+
+  // Wait for the bubble to be replaced with the sign in promo and click the
+  // sign in button.
+  RunTestSequence(
+      WaitForShow(BubbleSignInPromoSignInButtonView::kPromoSignInButton),
+      EnsurePresent(PasswordSaveUpdateView::kPasswordBubble),
+      SetOnIncompatibleAction(
+          OnIncompatibleAction::kIgnoreAndContinue,
+          "Screenshot can only run in pixel_tests on Windows."),
+      Screenshot(PasswordSaveUpdateView::kPasswordBubble, std::string(),
+                 "5231400"),
+      NameChildViewByType<views::MdTextButton>(
+          BubbleSignInPromoSignInButtonView::kPromoSignInButton, kButton),
+      PressButton(kButton).SetMustRemainVisible(false),
+      EnsureNotPresent(PasswordSaveUpdateView::kPasswordBubble));
+
+  // Check that clicking the sign in button navigated to a sign in page.
+  EXPECT_TRUE(IsSignInURL());
+
+  // Check that there is a helper attached to the sign in tab, because the
+  // password still needs to be moved.
+  EXPECT_TRUE(autofill::AutofillSigninPromoTabHelper::GetForWebContents(
+                  *browser()->tab_strip_model()->GetActiveWebContents())
+                  ->IsInitializedForTesting());
+
+  // Simulate a sign in event with the correct access point, which will move the
+  // password. Wait for the password to show up in account store.
+  auto account_store_waiter =
+      password_manager::PasswordStoreWaiter(account_password_store_.get());
+  SignIn();
+  account_store_waiter.WaitOrReturn();
+
+  // Check that the sign in was successful.
+  EXPECT_TRUE(IsSignedIn());
+
+  // Check that password was moved to account store.
+  EXPECT_EQ(0u, local_password_store_->stored_passwords().size());
+  EXPECT_EQ(1u, account_password_store_->stored_passwords().size());
+
+  auto found = account_password_store_->stored_passwords().find(
+      test_form()->signon_realm);
+  EXPECT_NE(account_password_store_->stored_passwords().end(), found);
+  EXPECT_THAT(found->second, testing::ElementsAre(FormMatches(*test_form())));
+}
+
+IN_PROC_BROWSER_TEST_F(AutofillBubbleSignInPromoInteractiveUITest,
+                       SignInPromoWithWebSignedInAccount) {
+  // Sign in with an account, but only on the web. The primary account is not
+  // set.
+  signin::MakeAccountAvailable(
+      identity_manager(),
+      signin::AccountAvailabilityOptionsBuilder(test_url_loader_factory())
+          .WithCookie()
+          .WithAccessPoint(signin_metrics::AccessPoint::ACCESS_POINT_WEB_SIGNIN)
+          .Build("test@email.com"));
+
+  // Set up password and password stores.
+  GetController()->OnPasswordSubmitted(CreateFormManager(
+      local_password_store_.get(), account_password_store_.get()));
+
+  // Save the password and check that it was properly saved to profile store.
+  SavePassword(password_manager::PasswordForm::Store::kProfileStore);
+  EXPECT_EQ(1u, local_password_store_->stored_passwords().size());
+  EXPECT_EQ(0u, account_password_store_->stored_passwords().size());
+
+  // Wait for the bubble to be replaced with the sign in promo and click the
+  // sign in button. This should directly sign the user in and move the
+  // password.
+  auto account_store_waiter =
+      password_manager::PasswordStoreWaiter(account_password_store_.get());
+  RunTestSequence(
+      WaitForShow(BubbleSignInPromoSignInButtonView::kPromoSignInButton),
+      EnsurePresent(PasswordSaveUpdateView::kPasswordBubble),
+      SetOnIncompatibleAction(
+          OnIncompatibleAction::kIgnoreAndContinue,
+          "Screenshot can only run in pixel_tests on Windows."),
+      Screenshot(PasswordSaveUpdateView::kPasswordBubble, std::string(),
+                 "5231400"),
+      NameChildViewByType<views::MdTextButton>(
+          BubbleSignInPromoSignInButtonView::kPromoSignInButton, kButton),
+      PressButton(kButton).SetMustRemainVisible(false),
+      EnsureNotPresent(PasswordSaveUpdateView::kPasswordBubble));
+  account_store_waiter.WaitOrReturn();
+
+  // Check that there is no helper attached to the sign in tab, because the
+  // password was already moved.
+  EXPECT_FALSE(autofill::AutofillSigninPromoTabHelper::GetForWebContents(
+                   *browser()->tab_strip_model()->GetActiveWebContents())
+                   ->IsInitializedForTesting());
+
+  // Check that the sign in was successful.
+  EXPECT_TRUE(IsSignedIn());
+
+  // Check that password was moved to account store.
+  EXPECT_EQ(0u, local_password_store_->stored_passwords().size());
+  EXPECT_EQ(1u, account_password_store_->stored_passwords().size());
+
+  auto found = account_password_store_->stored_passwords().find(
+      test_form()->signon_realm);
+  EXPECT_NE(account_password_store_->stored_passwords().end(), found);
+  EXPECT_THAT(found->second, testing::ElementsAre(FormMatches(*test_form())));
+}
+
+IN_PROC_BROWSER_TEST_F(AutofillBubbleSignInPromoInteractiveUITest,
+                       SignInPromoWithAccountSignInPaused) {
+  // Sign in with an account, and put its refresh token into an error
+  // state. This simulates the "sign in paused" state.
+  AccountInfo info = signin::MakePrimaryAccountAvailable(
+      identity_manager(), "test@email.com", signin::ConsentLevel::kSignin);
+  signin::UpdatePersistentErrorOfRefreshTokenForAccount(
+      identity_manager(), info.account_id,
+      GoogleServiceAuthError(
+          GoogleServiceAuthError::State::USER_NOT_SIGNED_UP));
+
+  // Set up password and password stores.
+  GetController()->OnPasswordSubmitted(CreateFormManager(
+      local_password_store_.get(), account_password_store_.get()));
+
+  // Simulate the use of account store.
+  SetupSaveToAccountStore();
+
+  // Save the password and check that it was properly saved to account store.
+  SavePassword(password_manager::PasswordForm::Store::kAccountStore);
+  EXPECT_EQ(0u, local_password_store_->stored_passwords().size());
+  EXPECT_EQ(1u, account_password_store_->stored_passwords().size());
+
+  // Wait for the bubble to be replaced with the sign in promo and click
+  // the sign in button.
+  RunTestSequence(
+      WaitForShow(BubbleSignInPromoSignInButtonView::kPromoSignInButton),
+      EnsurePresent(PasswordSaveUpdateView::kPasswordBubble),
+      SetOnIncompatibleAction(
+          OnIncompatibleAction::kIgnoreAndContinue,
+          "Screenshot can only run in pixel_tests on Windows."),
+      Screenshot(PasswordSaveUpdateView::kPasswordBubble, std::string(),
+                 "5231400"),
+      NameChildViewByType<views::MdTextButton>(
+          BubbleSignInPromoSignInButtonView::kPromoSignInButton, kButton),
+      PressButton(kButton).SetMustRemainVisible(false),
+      EnsureNotPresent(PasswordSaveUpdateView::kPasswordBubble));
+
+  // Check that clicking the sign in button navigated to a sign in page.
+  EXPECT_TRUE(IsSignInURL());
+
+  // Check that there is no helper attached to the sign in tab, because the
+  // password does not need to be moved.
+  EXPECT_FALSE(autofill::AutofillSigninPromoTabHelper::GetForWebContents(
+                   *browser()->tab_strip_model()->GetActiveWebContents())
+                   ->IsInitializedForTesting());
+
+  // Set a new refresh token for the primary account, which verifies the
+  // user's identity and signs them back in. The password will stay in the
+  // account store.
+  signin::SetRefreshTokenForPrimaryAccount(identity_manager());
+
+  // Check that the sign in was successful.
+  EXPECT_TRUE(IsSignedIn());
+
+  // Check that password is still account store.
+  EXPECT_EQ(0u, local_password_store_->stored_passwords().size());
+  EXPECT_EQ(1u, account_password_store_->stored_passwords().size());
+
+  auto found = account_password_store_->stored_passwords().find(
+      test_form()->signon_realm);
+  EXPECT_NE(account_password_store_->stored_passwords().end(), found);
+  EXPECT_THAT(found->second, testing::ElementsAre(FormMatches(*test_form())));
+}
diff --git a/chrome/browser/ui/views/promos/autofill_bubble_signin_promo_view.cc b/chrome/browser/ui/views/promos/autofill_bubble_signin_promo_view.cc
index b7f7c67b..d148565f 100644
--- a/chrome/browser/ui/views/promos/autofill_bubble_signin_promo_view.cc
+++ b/chrome/browser/ui/views/promos/autofill_bubble_signin_promo_view.cc
@@ -58,7 +58,7 @@
 
 AutofillBubbleSignInPromoView::AutofillBubbleSignInPromoView(
     content::WebContents* web_contents,
-    PromoType promo_type)
+    signin::SignInAutofillBubblePromoType promo_type)
     // TODO(crbug.com/319411728): Make this dependant on type (for now only
     // password).
     : controller_(PasswordsModelDelegateFromWebContents(web_contents)),
@@ -75,9 +75,9 @@
   int message_resource_id = 0;
   switch (promo_type_) {
     // TODO(crbug.com/319411728): Add the correct strings per type.
-    case PromoType::Payments:
-    case PromoType::Address:
-    case PromoType::Password:
+    case signin::SignInAutofillBubblePromoType::Payments:
+    case signin::SignInAutofillBubblePromoType::Addresses:
+    case signin::SignInAutofillBubblePromoType::Passwords:
       message_resource_id = IDS_PASSWORD_MANAGER_DICE_PROMO_SIGNIN_MESSAGE;
   }
   AddChildView(new BubbleSignInPromoView(
diff --git a/chrome/browser/ui/views/promos/autofill_bubble_signin_promo_view.h b/chrome/browser/ui/views/promos/autofill_bubble_signin_promo_view.h
index e2849a4..23ea590e 100644
--- a/chrome/browser/ui/views/promos/autofill_bubble_signin_promo_view.h
+++ b/chrome/browser/ui/views/promos/autofill_bubble_signin_promo_view.h
@@ -6,6 +6,8 @@
 #define CHROME_BROWSER_UI_VIEWS_PROMOS_AUTOFILL_BUBBLE_SIGNIN_PROMO_VIEW_H_
 
 #include <memory>
+
+#include "chrome/browser/signin/signin_promo_util.h"
 #include "chrome/browser/ui/autofill/autofill_bubble_signin_promo_controller.h"
 #include "chrome/browser/ui/signin/bubble_signin_promo_delegate.h"
 #include "ui/views/controls/button/button.h"
@@ -27,10 +29,9 @@
   METADATA_HEADER(AutofillBubbleSignInPromoView, views::View)
 
  public:
-  enum class PromoType { Password, Address, Payments };
-
-  explicit AutofillBubbleSignInPromoView(content::WebContents* web_contents,
-                                         PromoType promo_type);
+  explicit AutofillBubbleSignInPromoView(
+      content::WebContents* web_contents,
+      signin::SignInAutofillBubblePromoType promo_type);
   AutofillBubbleSignInPromoView(const AutofillBubbleSignInPromoView&) = delete;
   AutofillBubbleSignInPromoView& operator=(
       const AutofillBubbleSignInPromoView&) = delete;
@@ -42,7 +43,7 @@
   class DiceSigninPromoDelegate;
 
   autofill::AutofillBubbleSignInPromoController controller_;
-  const PromoType promo_type_;
+  const signin::SignInAutofillBubblePromoType promo_type_;
   std::unique_ptr<DiceSigninPromoDelegate> dice_sign_in_promo_delegate_;
 };
 
diff --git a/chrome/browser/ui/views/promos/bubble_signin_promo_signin_button_view.cc b/chrome/browser/ui/views/promos/bubble_signin_promo_signin_button_view.cc
index aad7125..135e8d21 100644
--- a/chrome/browser/ui/views/promos/bubble_signin_promo_signin_button_view.cc
+++ b/chrome/browser/ui/views/promos/bubble_signin_promo_signin_button_view.cc
@@ -20,7 +20,7 @@
 #include "ui/base/ui_base_types.h"
 #include "ui/gfx/canvas.h"
 #include "ui/views/border.h"
-#include "ui/views/controls/button/md_text_button.h"
+#include "ui/views/interaction/element_tracker_views.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/flex_layout.h"
 
@@ -38,6 +38,8 @@
                   l10n_util::GetStringUTF16(IDS_PROFILES_DICE_SIGNIN_BUTTON))
               .SetStyle(button_style))
       .BuildChildren();
+
+  SetProperty(views::kElementIdentifierKey, kPromoSignInButton);
 }
 
 BubbleSignInPromoSignInButtonView::BubbleSignInPromoSignInButtonView(
@@ -82,10 +84,15 @@
                            IDS_PROFILES_DICE_SIGNIN_BUTTON))
                        .SetStyle(ui::ButtonStyle::kProminent))
       .BuildChildren();
+
+  SetProperty(views::kElementIdentifierKey, kPromoSignInButton);
 }
 
 BubbleSignInPromoSignInButtonView::
     ~BubbleSignInPromoSignInButtonView() = default;
 
+DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(BubbleSignInPromoSignInButtonView,
+                                      kPromoSignInButton);
+
 BEGIN_METADATA(BubbleSignInPromoSignInButtonView)
 END_METADATA
diff --git a/chrome/browser/ui/views/promos/bubble_signin_promo_signin_button_view.h b/chrome/browser/ui/views/promos/bubble_signin_promo_signin_button_view.h
index 710ec5d..127e1e9 100644
--- a/chrome/browser/ui/views/promos/bubble_signin_promo_signin_button_view.h
+++ b/chrome/browser/ui/views/promos/bubble_signin_promo_signin_button_view.h
@@ -10,8 +10,10 @@
 #include "base/memory/raw_ptr.h"
 #include "chrome/browser/ui/views/controls/hover_button.h"
 #include "components/signin/public/identity_manager/account_info.h"
+#include "ui/base/interaction/element_tracker.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/button/md_text_button.h"
 #include "ui/views/metadata/view_factory.h"
 #include "ui/views/view.h"
 
@@ -22,6 +24,8 @@
   METADATA_HEADER(BubbleSignInPromoSignInButtonView, views::View)
 
  public:
+  DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kPromoSignInButton);
+
   // Create a non-personalized sign-in button with |button_style|.
   // |callback| is called every time the user interacts with this button.
   explicit BubbleSignInPromoSignInButtonView(
diff --git a/chrome/browser/ui/views/promos/bubble_signin_promo_view.cc b/chrome/browser/ui/views/promos/bubble_signin_promo_view.cc
index 6cde544..b596e421 100644
--- a/chrome/browser/ui/views/promos/bubble_signin_promo_view.cc
+++ b/chrome/browser/ui/views/promos/bubble_signin_promo_view.cc
@@ -26,6 +26,7 @@
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/flex_layout.h"
+#include "ui/views/widget/widget.h"
 
 BubbleSignInPromoView::BubbleSignInPromoView(
     Profile* profile,
@@ -133,6 +134,7 @@
 void BubbleSignInPromoView::SignIn() {
   std::optional<AccountInfo> account = signin_button_view_->account();
   delegate_->OnSignIn(account.value_or(AccountInfo()));
+  GetWidget()->Close();
 }
 
 BEGIN_METADATA(BubbleSignInPromoView)
diff --git a/chrome/browser/ui/views/tab_sharing/tab_sharing_infobar.cc b/chrome/browser/ui/views/tab_sharing/tab_sharing_infobar.cc
index be7e066e..19b2260 100644
--- a/chrome/browser/ui/views/tab_sharing/tab_sharing_infobar.cc
+++ b/chrome/browser/ui/views/tab_sharing/tab_sharing_infobar.cc
@@ -26,7 +26,8 @@
 #include "ui/views/view_class_properties.h"
 
 namespace {
-constexpr auto kCscPermissionButtonInsets = gfx::Insets::VH(4, 8);
+constexpr auto kCapturedSurfaceControlIndicatorButtonInsets =
+    gfx::Insets::VH(4, 8);
 }
 
 TabSharingInfoBar::TabSharingInfoBar(
@@ -42,7 +43,7 @@
                                  int button_context =
                                      views::style::CONTEXT_BUTTON_MD) {
     const bool use_text_color_for_icon =
-        type != TabSharingInfoBarDelegate::kCscPermission;
+        type != TabSharingInfoBarDelegate::kCapturedSurfaceControlIndicator;
     auto* button = AddChildView(std::make_unique<views::MdTextButton>(
         base::BindRepeating(click_function, base::Unretained(this)),
         delegate_ptr->GetButtonLabel(type), button_context,
@@ -81,16 +82,17 @@
                       &TabSharingInfoBar::QuickNavButtonPressed);
   }
 
-  if (buttons & TabSharingInfoBarDelegate::kCscPermission) {
-    csc_permission_button_ = create_button(
-        TabSharingInfoBarDelegate::kCscPermission,
+  if (buttons & TabSharingInfoBarDelegate::kCapturedSurfaceControlIndicator) {
+    csc_indicator_button_ = create_button(
+        TabSharingInfoBarDelegate::kCapturedSurfaceControlIndicator,
         &TabSharingInfoBar::OnCapturedSurfaceControlActivityIndicatorPressed,
         CONTEXT_OMNIBOX_PRIMARY);
-    csc_permission_button_->SetStyle(ui::ButtonStyle::kDefault);
-    csc_permission_button_->SetCornerRadius(
+    csc_indicator_button_->SetStyle(ui::ButtonStyle::kDefault);
+    csc_indicator_button_->SetCornerRadius(
         GetLayoutConstant(TOOLBAR_CORNER_RADIUS));
-    csc_permission_button_->SetCustomPadding(kCscPermissionButtonInsets);
-    csc_permission_button_->SetTextColorId(
+    csc_indicator_button_->SetCustomPadding(
+        kCapturedSurfaceControlIndicatorButtonInsets);
+    csc_indicator_button_->SetTextColorId(
         views::Button::ButtonState::STATE_NORMAL, ui::kColorSysOnSurface);
   }
 
@@ -116,8 +118,8 @@
     quick_nav_button_->SizeToPreferredSize();
   }
 
-  if (csc_permission_button_) {
-    csc_permission_button_->SizeToPreferredSize();
+  if (csc_indicator_button_) {
+    csc_indicator_button_->SizeToPreferredSize();
   }
 
   int x = GetStartX();
@@ -148,8 +150,8 @@
   if (quick_nav_button_) {
     order_of_buttons.push_back(quick_nav_button_);
   }
-  if (csc_permission_button_) {
-    order_of_buttons.push_back(csc_permission_button_);
+  if (csc_indicator_button_) {
+    order_of_buttons.push_back(csc_indicator_button_);
   }
 
   if (!views::PlatformStyle::kIsOkButtonLeading) {
@@ -213,7 +215,7 @@
 
   const int button_count =
       (stop_button_ ? 1 : 0) + (share_this_tab_instead_button_ ? 1 : 0) +
-      (quick_nav_button_ ? 1 : 0) + (csc_permission_button_ ? 1 : 0);
+      (quick_nav_button_ ? 1 : 0) + (csc_indicator_button_ ? 1 : 0);
 
   int width =
       (label_->GetText().empty() || button_count == 0) ? 0 : label_spacing;
@@ -225,7 +227,7 @@
                ? share_this_tab_instead_button_->width()
                : 0;
   width += quick_nav_button_ ? quick_nav_button_->width() : 0;
-  width += csc_permission_button_ ? csc_permission_button_->width() : 0;
+  width += csc_indicator_button_ ? csc_indicator_button_->width() : 0;
 
   return width + ((width && !link_->GetText().empty()) ? label_spacing : 0);
 }
diff --git a/chrome/browser/ui/views/tab_sharing/tab_sharing_infobar.h b/chrome/browser/ui/views/tab_sharing/tab_sharing_infobar.h
index ccde616..c7066e5 100644
--- a/chrome/browser/ui/views/tab_sharing/tab_sharing_infobar.h
+++ b/chrome/browser/ui/views/tab_sharing/tab_sharing_infobar.h
@@ -55,7 +55,7 @@
   raw_ptr<views::MdTextButton> stop_button_ = nullptr;
   raw_ptr<views::MdTextButton> share_this_tab_instead_button_ = nullptr;
   raw_ptr<views::MdTextButton> quick_nav_button_ = nullptr;
-  raw_ptr<views::MdTextButton> csc_permission_button_ = nullptr;
+  raw_ptr<views::MdTextButton> csc_indicator_button_ = nullptr;
   raw_ptr<views::Link> link_ = nullptr;
 };
 
diff --git a/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views_browsertest.cc b/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views_browsertest.cc
index bf3f7324..d4e6cbc 100644
--- a/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views_browsertest.cc
+++ b/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views_browsertest.cc
@@ -124,24 +124,24 @@
       ->GetButtonImage(TabSharingInfoBarDelegate::InfoBarButton::kQuickNav);
 }
 
-// TODO(crbug.com/1466247): Rename to "...Indicator".
-bool HasCscPermissionButton(Browser* browser, int tab) {
+bool HasCscIndicatorButton(Browser* browser, int tab) {
   return GetDelegate(browser, tab)->GetButtons() &
-         TabSharingInfoBarDelegate::InfoBarButton::kCscPermission;
+         TabSharingInfoBarDelegate::InfoBarButton::
+             kCapturedSurfaceControlIndicator;
 }
 
-std::u16string GetCscPermissionButtonLabel(Browser* browser, int tab) {
-  DCHECK(HasCscPermissionButton(browser, tab));  // Test error otherwise.
+std::u16string GetCscIndicatorButtonLabel(Browser* browser, int tab) {
+  DCHECK(HasCscIndicatorButton(browser, tab));  // Test error otherwise.
   return GetDelegate(browser, tab)
-      ->GetButtonLabel(
-          TabSharingInfoBarDelegate::InfoBarButton::kCscPermission);
+      ->GetButtonLabel(TabSharingInfoBarDelegate::InfoBarButton::
+                           kCapturedSurfaceControlIndicator);
 }
 
-ui::ImageModel GetCscPermissionButtonImage(Browser* browser, int tab) {
-  DCHECK(HasCscPermissionButton(browser, tab));  // Test error otherwise.
+ui::ImageModel GetCscIndicatorButtonImage(Browser* browser, int tab) {
+  DCHECK(HasCscIndicatorButton(browser, tab));  // Test error otherwise.
   return GetDelegate(browser, tab)
-      ->GetButtonImage(
-          TabSharingInfoBarDelegate::InfoBarButton::kCscPermission);
+      ->GetButtonImage(TabSharingInfoBarDelegate::InfoBarButton::
+                           kCapturedSurfaceControlIndicator);
 }
 
 std::u16string GetExpectedSwitchToMessage(Browser* browser, int tab) {
@@ -317,7 +317,7 @@
       if (i == capturing_tab && i == captured_tab) {
         // Self-capture.
         EXPECT_FALSE(HasShareThisTabInsteadButton(browser, i));
-        EXPECT_FALSE(HasCscPermissionButton(browser, i));
+        EXPECT_FALSE(HasCscIndicatorButton(browser, i));
       } else if (i == capturing_tab) {
         // Capturing-tab's infobar.
         ASSERT_TRUE(HasQuickNavButton(browser, i));
@@ -325,14 +325,14 @@
                   GetExpectedSwitchToMessage(browser, captured_tab));
         EXPECT_EQ(GetQuickNavButtonImage(browser, i),
                   GetFaviconAssociatedWith(browser, captured_tab));
-        EXPECT_EQ(HasCscPermissionButton(browser, i),
+        EXPECT_EQ(HasCscIndicatorButton(browser, i),
                   has_captured_surface_control_indicator);
-        if (HasCscPermissionButton(browser, i)) {
+        if (HasCscIndicatorButton(browser, i)) {
           EXPECT_EQ(
-              GetCscPermissionButtonLabel(browser, i),
+              GetCscIndicatorButtonLabel(browser, i),
               l10n_util::GetStringUTF16(
                   IDS_TAB_SHARING_INFOBAR_CAPTURED_SURFACE_CONTROL_PERMISSION_BUTTON));
-          EXPECT_EQ(GetCscPermissionButtonImage(browser, i),
+          EXPECT_EQ(GetCscIndicatorButtonImage(browser, i),
                     ui::ImageModel::FromVectorIcon(
                         vector_icons::kTouchpadMouseIcon, ui::kColorSysPrimary,
                         /*icon_size=*/16));
@@ -344,7 +344,7 @@
                   GetExpectedSwitchToMessage(browser, capturing_tab));
         EXPECT_EQ(GetQuickNavButtonImage(browser, i),
                   GetFaviconAssociatedWith(browser, capturing_tab));
-        EXPECT_FALSE(HasCscPermissionButton(browser, i));
+        EXPECT_FALSE(HasCscIndicatorButton(browser, i));
       } else if (infobar_manager->infobars().size() > 0) {
         // Any other infobar.
         ASSERT_TRUE(HasShareThisTabInsteadButton(browser, i));
@@ -355,7 +355,7 @@
         EXPECT_EQ(ShareThisTabInsteadButtonIsEnabled(browser, i),
                   i != tab_with_disabled_button)
             << "Tab: " << i;
-        EXPECT_FALSE(HasCscPermissionButton(browser, i));
+        EXPECT_FALSE(HasCscIndicatorButton(browser, i));
       }
     }
   }
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index 67f4cb23..aeaf2c77 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -1879,16 +1879,35 @@
 void TabDragController::AttachTabsToNewBrowserOnDrop() {
   DCHECK(!attached_context_hidden_);
 
+  // TODO(crbug.com/40238145): `CreateBrowserForDrag()` does almost the same as
+  // this method. Factor out the common parts into a separate method.
+
+  // Find if there's a controlling app, and thus we should open an app window.
+  Browser* from_browser = BrowserView::GetBrowserViewForNativeWindow(
+                              GetAttachedBrowserWidget()->GetNativeWindow())
+                              ->browser();
+  const std::optional<webapps::AppId> controlling_app =
+      GetControllingAppForDrag(from_browser);
+  const bool open_as_web_app = controlling_app.has_value();
+
+  Browser::CreateParams create_params =
+      open_as_web_app
+          ? Browser::CreateParams::CreateForApp(
+                web_app::GenerateApplicationNameFromAppId(
+                    controlling_app.value()),
+                /* trusted_source=*/true, gfx::Rect(), from_browser->profile(),
+                /* user_gesture=*/true)
+          : from_browser->create_params();
+
   views::Widget* widget = attached_context_->GetWidget();
   gfx::Rect window_bounds(widget->GetRestoredBounds());
   window_bounds.set_origin(GetWindowCreatePoint(last_point_in_screen_));
 
-  Browser::CreateParams create_params =
-      BrowserView::GetBrowserViewForNativeWindow(
-          GetAttachedBrowserWidget()->GetNativeWindow())
-          ->browser()
-          ->create_params();
-  create_params.initial_bounds = window_bounds;
+  // Web app windows have their own initial size independent of the source
+  // browser window.
+  if (!open_as_web_app) {
+    create_params.initial_bounds = window_bounds;
+  }
 
   // Don't copy the initial workspace since the *current* workspace might be
   // different and copying the workspace will move the tab to the initial one.
@@ -1900,9 +1919,12 @@
   create_params.user_title = std::string();
 
   Browser* browser = Browser::Create(create_params);
-  // If the window is created maximized then the bounds we supplied are ignored.
-  // We need to reset them again so they are honored.
-  browser->window()->SetBounds(window_bounds);
+
+  if (!open_as_web_app) {
+    // If the window is created maximized then the bounds we supplied are
+    // ignored. We need to reset them again so they are honored.
+    browser->window()->SetBounds(window_bounds);
+  }
 
   auto* new_context = BrowserView::GetBrowserViewForBrowser(browser)
                           ->tabstrip()
@@ -2415,6 +2437,9 @@
     const gfx::Point& point_in_screen,
     gfx::Vector2d* drag_offset,
     std::vector<gfx::Rect>* drag_bounds) {
+  // TODO(crbug.com/40238145): `AttachTabsToNewBrowserOnDrop()` does almost the
+  // same as this method. Factor out the common parts into a separate method.
+
   source->GetWidget()
       ->GetCompositor()
       ->RequestSuccessfulPresentationTimeForNextFrame(base::BindOnce(
@@ -2446,10 +2471,7 @@
                     controlling_app.value()),
                 /* trusted_source=*/true, gfx::Rect(), from_browser->profile(),
                 /* user_gesture=*/true)
-          : BrowserView::GetBrowserViewForNativeWindow(
-                GetAttachedBrowserWidget()->GetNativeWindow())
-                ->browser()
-                ->create_params();
+          : from_browser->create_params();
 
   // Web app windows have their own initial size independent of the source
   // browser window.
diff --git a/chrome/browser/ui/webui/ash/app_install/app_install_ui.cc b/chrome/browser/ui/webui/ash/app_install/app_install_ui.cc
index 511a95c..3da9a76 100644
--- a/chrome/browser/ui/webui/ash/app_install/app_install_ui.cc
+++ b/chrome/browser/ui/webui/ash/app_install/app_install_ui.cc
@@ -46,6 +46,7 @@
       {"noAppDataDescription", IDS_APP_INSTALL_DIALOG_NO_APP_DATA_DESCRIPTION},
       {"tryAgain", IDS_APP_INSTALL_DIALOG_TRY_AGAIN_BUTTON_LABEL},
       {"failedInstall", IDS_APP_INSTALL_DIALOG_FAILED_INSTALL_TITLE},
+      {"iconAlt", IDS_APP_INSTALL_DIALOG_APP_ICON_ALT},
   };
 
   source->AddLocalizedStrings(kStrings);
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.cc b/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.cc
index 57cb8b98..2701baa 100644
--- a/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.cc
+++ b/chrome/browser/ui/webui/ash/cloud_upload/drive_upload_handler.cc
@@ -574,12 +574,6 @@
       } else {
         LOG(ERROR) << "Unexpected alternate URL - Drive editing unavailable: "
                    << hosted_url.host();
-        // TODO(b/323452926): Remove DumpWithoutCrashing() once sure the
-        // introduction of kFileNotAnOfficeFile fixed the only cause of
-        // kUnexpectedAlternateUrlHost.
-        SCOPED_CRASH_KEY_STRING64("OfficeUpload", "UnexpectedHost",
-                                  hosted_url.host());
-        base::debug::DumpWithoutCrashing();
         OnEndCopy(OfficeFilesUploadResult::kUnexpectedAlternateUrlHost);
       }
     } else {
diff --git a/chrome/browser/ui/webui/ash/settings/pages/device/inputs_section.cc b/chrome/browser/ui/webui/ash/settings/pages/device/inputs_section.cc
index 8bf9ff6..dde36e8 100644
--- a/chrome/browser/ui/webui/ash/settings/pages/device/inputs_section.cc
+++ b/chrome/browser/ui/webui/ash/settings/pages/device/inputs_section.cc
@@ -480,9 +480,6 @@
       "onDeviceGrammarCheckEnabled",
       base::FeatureList::IsEnabled(features::kOnDeviceGrammarCheck));
 
-  // TODO: b/332967598 - Remove obsolete pre-LanguagePacks code in Settings.
-  html_source->AddBoolean("languagePacksHandwritingEnabled", true);
-
   html_source->AddBoolean(
       "systemJapanesePhysicalTyping",
       base::FeatureList::IsEnabled(features::kSystemJapanesePhysicalTyping));
diff --git a/chrome/browser/ui/webui/cr_components/most_visited/most_visited_handler.cc b/chrome/browser/ui/webui/cr_components/most_visited/most_visited_handler.cc
index cb991ce..6f4219b 100644
--- a/chrome/browser/ui/webui/cr_components/most_visited/most_visited_handler.cc
+++ b/chrome/browser/ui/webui/cr_components/most_visited/most_visited_handler.cc
@@ -210,14 +210,36 @@
 void MostVisitedHandler::PrerenderMostVisitedTile(
     most_visited::mojom::MostVisitedTilePtr tile,
     bool is_hover_trigger) {
-  if (base::FeatureList::IsEnabled(features::kNewTabPageTriggerForPrerender2)) {
-    PrerenderManager::CreateForWebContents(web_contents_);
-    auto* prerender_manager = PrerenderManager::FromWebContents(web_contents_);
-    prerender_handle_ = prerender_manager->StartPrerenderNewTabPage(
-        tile->url, is_hover_trigger
-                       ? chrome_preloading_predictor::kMouseHoverOnNewTabPage
-                       : chrome_preloading_predictor::kPointerDownOnNewTabPage);
+  if (!base::FeatureList::IsEnabled(
+          features::kNewTabPageTriggerForPrerender2)) {
+    page_handler_.ReportBadMessage(
+        "PrerenderMostVisitedTile is only expected to be called "
+        "when kNewTabPageTriggerForPrerender2 is true.");
+    return;
   }
+
+  if (is_hover_trigger &&
+      !features::kPrerenderNewTabPageOnMouseHoverTrigger.Get()) {
+    page_handler_.ReportBadMessage(
+        "PrerenderMostVisitedTile by hovering is only expected to be called "
+        "when kPrerenderNewTabPageOnMouseHoverTrigger is true.");
+    return;
+  }
+
+  if (!is_hover_trigger &&
+      !features::kPrerenderNewTabPageOnMousePressedTrigger.Get()) {
+    page_handler_.ReportBadMessage(
+        "PrerenderMostVisitedTile by pressing is only expected to be called "
+        "when kPrerenderNewTabPageOnMousePressedTrigger is true.");
+    return;
+  }
+  PrerenderManager::CreateForWebContents(web_contents_);
+  auto* prerender_manager = PrerenderManager::FromWebContents(web_contents_);
+
+  prerender_handle_ = prerender_manager->StartPrerenderNewTabPage(
+      tile->url, is_hover_trigger
+                     ? chrome_preloading_predictor::kMouseHoverOnNewTabPage
+                     : chrome_preloading_predictor::kPointerDownOnNewTabPage);
 }
 
 void MostVisitedHandler::PreconnectMostVisitedTile(
@@ -240,11 +262,17 @@
 }
 
 void MostVisitedHandler::CancelPrerender() {
-  if (base::FeatureList::IsEnabled(features::kNewTabPageTriggerForPrerender2)) {
-    auto* prerender_manager = PrerenderManager::FromWebContents(web_contents_);
-    prerender_manager->StopPrerenderNewTabPage(prerender_handle_);
-    prerender_handle_ = nullptr;
+  if (!base::FeatureList::IsEnabled(
+          features::kNewTabPageTriggerForPrerender2)) {
+    page_handler_.ReportBadMessage(
+        "CancelPrerender is only expected to be called "
+        "when kNewTabPageTriggerForPrerender2 is true.");
+    return;
   }
+
+  auto* prerender_manager = PrerenderManager::FromWebContents(web_contents_);
+  prerender_manager->StopPrerenderNewTabPage(prerender_handle_);
+  prerender_handle_ = nullptr;
 }
 
 void MostVisitedHandler::OnURLsAvailable(
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
index 184294d..aba0818 100644
--- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
+++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
@@ -209,15 +209,20 @@
       base::FeatureList::IsEnabled(
           ntp_features::kNtpHandleMostVisitedNavigationExplicitly));
 
-  source->AddBoolean(
-      "prerenderEnabled",
-      base::FeatureList::IsEnabled(features::kNewTabPageTriggerForPrerender2));
   source->AddInteger(
       "prerenderStartTimeThreshold",
       features::kNewTabPagePrerenderStartDelayOnMouseHoverByMiliSeconds.Get());
   source->AddInteger(
       "preconnectStartTimeThreshold",
       features::kNewTabPagePreconnectStartDelayOnMouseHoverByMiliSeconds.Get());
+  source->AddBoolean(
+      "prerenderOnPressEnabled",
+      base::FeatureList::IsEnabled(features::kNewTabPageTriggerForPrerender2) &&
+          features::kPrerenderNewTabPageOnMousePressedTrigger.Get());
+  source->AddBoolean(
+      "prerenderOnHoverEnabled",
+      base::FeatureList::IsEnabled(features::kNewTabPageTriggerForPrerender2) &&
+          features::kPrerenderNewTabPageOnMouseHoverTrigger.Get());
 
   source->AddBoolean(
       "oneGoogleBarEnabled",
diff --git a/chrome/browser/ui/webui/new_tab_page_third_party/new_tab_page_third_party_ui.cc b/chrome/browser/ui/webui/new_tab_page_third_party/new_tab_page_third_party_ui.cc
index 78def7b..0dd899ee 100644
--- a/chrome/browser/ui/webui/new_tab_page_third_party/new_tab_page_third_party_ui.cc
+++ b/chrome/browser/ui/webui/new_tab_page_third_party/new_tab_page_third_party_ui.cc
@@ -102,15 +102,20 @@
       base::FeatureList::IsEnabled(
           ntp_features::kNtpHandleMostVisitedNavigationExplicitly));
 
-  source->AddBoolean(
-      "prerenderEnabled",
-      base::FeatureList::IsEnabled(features::kNewTabPageTriggerForPrerender2));
   source->AddInteger(
       "prerenderStartTimeThreshold",
       features::kNewTabPagePrerenderStartDelayOnMouseHoverByMiliSeconds.Get());
   source->AddInteger(
       "preconnectStartTimeThreshold",
       features::kNewTabPagePreconnectStartDelayOnMouseHoverByMiliSeconds.Get());
+  source->AddBoolean(
+      "prerenderOnPressEnabled",
+      base::FeatureList::IsEnabled(features::kNewTabPageTriggerForPrerender2) &&
+          features::kPrerenderNewTabPageOnMousePressedTrigger.Get());
+  source->AddBoolean(
+      "prerenderOnHoverEnabled",
+      base::FeatureList::IsEnabled(features::kNewTabPageTriggerForPrerender2) &&
+          features::kPrerenderNewTabPageOnMouseHoverTrigger.Get());
 
   // Needed by <cr-most-visited> but not used in
   // chrome://new-tab-page-third-party/.
diff --git a/chrome/browser/webauthn/chrome_webauthn_autofill_interactive_uitest.cc b/chrome/browser/webauthn/chrome_webauthn_autofill_interactive_uitest.cc
index 12875b0..c598ed6 100644
--- a/chrome/browser/webauthn/chrome_webauthn_autofill_interactive_uitest.cc
+++ b/chrome/browser/webauthn/chrome_webauthn_autofill_interactive_uitest.cc
@@ -495,6 +495,11 @@
   ASSERT_TRUE(message_queue.WaitForMessage(&result));
   EXPECT_EQ(result, "\"webauthn: OK\"");
 
+  // Tapping a GPM passkey will not automatically hide the popup
+  // because the enclave might still be loading. Manually hide the
+  // popup so that the autofill client can be destroyed, avoiding
+  // a DCHECK on test tear down.
+  autofill_client->HideAutofillPopup(autofill::PopupHidingReason::kTabGone);
   // The tracker outlives the test. Clean up the device_info to avoid flakiness.
   tracker->Remove(&device_info);
 }
@@ -573,6 +578,11 @@
   ASSERT_TRUE(message_queue.WaitForMessage(&result));
   EXPECT_EQ(result, "\"webauthn: OK\"");
 
+  // Tapping a GPM passkey will not automatically hide the popup
+  // because the enclave might still be loading. Manually hide the
+  // popup so that the autofill client can be destroyed, avoiding
+  // a DCHECK on test tear down.
+  autofill_client->HideAutofillPopup(autofill::PopupHidingReason::kTabGone);
   // The tracker outlives the test. Clean up the device_info to avoid flakiness.
   tracker->Remove(&device_info);
 }
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index f680c1a..33b8b21 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1712793593-cae4312ebe70db70f6fca21a4ec89014b47d3a0e-25ba3307b92317024b267f58a62418fb6ca41e8a.profdata
+chrome-android32-main-1712815180-314d5587d1fc94c56c5e984b44aa07e9ac33f88c-8feabe72a1885ec60963e9baa5f1eabb967e9e0a.profdata
diff --git a/chrome/build/android-arm64.pgo.txt b/chrome/build/android-arm64.pgo.txt
index 4d18475..a3ca9578 100644
--- a/chrome/build/android-arm64.pgo.txt
+++ b/chrome/build/android-arm64.pgo.txt
@@ -1 +1 @@
-chrome-android64-main-1712779168-f3aed91a650e73b32c48eb6fe5f7d160154ef49f-70851099c78cdb9e06f8342fa6cf601d695d013d.profdata
+chrome-android64-main-1712807836-8484cbd6b3d4debb46ae14fc9dd17efc63331ad7-0d379889bb749cb52bdb96a980d32cb4d4191e0f.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 9319e183..6063a7b 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1712793593-0ba967a28b8dcac8770bbabddb038eac1cac9eca-25ba3307b92317024b267f58a62418fb6ca41e8a.profdata
+chrome-linux-main-1712815180-fffbbf7d74598dc14032933eca0e3369cfd33bce-8feabe72a1885ec60963e9baa5f1eabb967e9e0a.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index e2d3b74..07c0410 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1712807836-f6aa73235f0783aa3cf386b9fd46ade573c05dac-0d379889bb749cb52bdb96a980d32cb4d4191e0f.profdata
+chrome-mac-arm-main-1712829497-104978b514c7a5706388bf8c6cfc48aff306784d-dc61398475d19cc11c474daccfa5d29e3b54c300.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index eec67a37..964d1ba6 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1712793593-3f36a4e2a9c0646e8878aec063cc3aa5c3ff9fbf-25ba3307b92317024b267f58a62418fb6ca41e8a.profdata
+chrome-win-arm64-main-1712815180-a3d29fb05007016d06e9760c9e7f7d1cce74cc05-8feabe72a1885ec60963e9baa5f1eabb967e9e0a.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index abe942e..f110feb 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1712793593-2b0a15c5023bd513fd76d858c4221945c4696080-25ba3307b92317024b267f58a62418fb6ca41e8a.profdata
+chrome-win32-main-1712815180-3f61f648bdce6773948ec882ba987cb044f287f7-8feabe72a1885ec60963e9baa5f1eabb967e9e0a.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 4bf9e79..f46bbc6a 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1712782756-7d62838f9169aa3b8e50f4ed0eccbf8c67d51dd1-953fc520cbcd7ba90b383a4e0e8c11ebc9d399b1.profdata
+chrome-win64-main-1712815180-5159e4b56178f1dd6f40aed6c4927b6838cf62d1-8feabe72a1885ec60963e9baa5f1eabb967e9e0a.profdata
diff --git a/chrome/common/chromeos/extensions/api/diagnostics.idl b/chrome/common/chromeos/extensions/api/diagnostics.idl
index f39ae776..13203cb5 100644
--- a/chrome/common/chromeos/extensions/api/diagnostics.idl
+++ b/chrome/common/chromeos/extensions/api/diagnostics.idl
@@ -178,9 +178,27 @@
     DOMString? uuid;
   };
 
+  enum NetworkBandwidthRoutineRunningType {
+    download,
+    upload
+  };
+
+  dictionary NetworkBandwidthRoutineRunningInfo {
+    // The type of test that routine is running.
+    NetworkBandwidthRoutineRunningType type;
+    // The current network speed in Kbps.
+    double speedKbps;
+  };
+
+  // This is a union type. Exactly one field should be set.
+  dictionary RoutineRunningInfoUnion {
+    NetworkBandwidthRoutineRunningInfo? networkBandwidth;
+  };
+
   dictionary RoutineRunningInfo {
     DOMString? uuid;
     long? percentage;
+    RoutineRunningInfoUnion? info;
   };
 
   enum RoutineWaitingReason {
@@ -363,17 +381,29 @@
   dictionary CreateFanRoutineArguments {
   };
 
+  dictionary CreateNetworkBandwidthRoutineArguments {
+  };
+
+  dictionary NetworkBandwidthRoutineFinishedDetail {
+    // Average download speed in Kbit/s.
+    double downloadSpeedKbps;
+    // Average upload speed in Kbit/s.
+    double uploadSpeedKbps;
+  };
+
   // This is a union type. Exactly one field should be set.
   dictionary CreateRoutineArgumentsUnion {
     CreateMemoryRoutineArguments? memory;
     CreateVolumeButtonRoutineArguments? volumeButton;
     CreateFanRoutineArguments? fan;
+    CreateNetworkBandwidthRoutineArguments? networkBandwidth;
   };
 
   // This is a union type. Exactly one field should be set.
   dictionary RoutineFinishedDetailUnion {
     MemoryRoutineFinishedDetail? memory;
     FanRoutineFinishedDetail? fan;
+    NetworkBandwidthRoutineFinishedDetail? networkBandwidth;
   };
 
   dictionary RoutineFinishedInfo {
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index afb83e27..5186d02 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -651,7 +651,8 @@
       "7FE4A999359A456C4B0FB7B7AD85CEA29CA50519", // Login screen APIs test extension
       "3F5995FE79A861F019C6F093BEF98D73FA9D3A5F", // Login screen APIs in-session test extension
       // Only has access to login.exitCurrentSession
-      "8ECFC754A70BE499325FA4BB705E62EFEEC1BC80"  // b/314208017
+      "8ECFC754A70BE499325FA4BB705E62EFEEC1BC80", // b/314208017
+      "ECD28F2B60BDB3B4E566D6C60BD88BE0774044C1"  // b/314208017
     ]
   }],
   "loginScreenStorage": {
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index 52b0fa44..150fe60 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -528,6 +528,14 @@
       "3F5995FE79A861F019C6F093BEF98D73FA9D3A5F", // Login screen APIs in-session test extension
       "8ECFC754A70BE499325FA4BB705E62EFEEC1BC80"  // b/314208017
     ]
+  }, {
+    "channel": "stable",
+    "extension_types": ["platform_app"],
+    "location": "policy",
+    "platforms": ["chromeos", "lacros"],
+    "allowlist": [
+      "ECD28F2B60BDB3B4E566D6C60BD88BE0774044C1"  // b/314208017
+    ]
   }],
   "loginScreenStorage": [{
     "channel": "stable",
diff --git a/chrome/renderer/autofill/form_autofill_browsertest.cc b/chrome/renderer/autofill/form_autofill_browsertest.cc
index 51979716..7082a04d3 100644
--- a/chrome/renderer/autofill/form_autofill_browsertest.cc
+++ b/chrome/renderer/autofill/form_autofill_browsertest.cc
@@ -1193,7 +1193,7 @@
       expected.value = ASCIIToUTF16(placeholder_lastname);
     } else {
       expected.label.clear();
-      expected.value.clear();
+      expected.value = u"";
     }
     expected.is_autofilled = false;
     EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[1]);
@@ -1209,7 +1209,7 @@
       expected.value = ASCIIToUTF16(placeholder_email);
     } else {
       expected.label.clear();
-      expected.value.clear();
+      expected.value = u"";
     }
     expected.is_autofilled = false;
     EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[2]);
@@ -1880,12 +1880,12 @@
 
     expected.id_attribute = u"firstname";
     expected.name = expected.id_attribute;
-    expected.value.clear();
+    expected.value = u"";
     EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[0]);
 
     expected.id_attribute = u"lastname";
     expected.name = expected.id_attribute;
-    expected.value.clear();
+    expected.value = u"";
     EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[1]);
 
     expected.id_attribute = u"noAC";
@@ -1906,7 +1906,7 @@
     expected.max_length = 0;
     expected.id_attribute = u"month";
     expected.name = expected.id_attribute;
-    expected.value.clear();
+    expected.value = u"";
     expected.label.clear();
     EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[4]);
 
@@ -1920,7 +1920,7 @@
     expected.id_attribute = u"textarea";
     expected.max_length = FormFieldData::kDefaultMaxLength;
     expected.name = expected.id_attribute;
-    expected.value.clear();
+    expected.value = u"";
     expected.label.clear();
     EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[6]);
 
@@ -2096,14 +2096,14 @@
 
     expected.id_attribute = u"firstname";
     expected.name = expected.id_attribute;
-    expected.value.clear();
+    expected.value = u"";
     expected.form_control_type = FormControlType::kInputText;
     expected.max_length = FormFieldData::kDefaultMaxLength;
     EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[0]);
 
     expected.id_attribute = u"lastname";
     expected.name = expected.id_attribute;
-    expected.value.clear();
+    expected.value = u"";
     expected.form_control_type = FormControlType::kInputText;
     expected.max_length = FormFieldData::kDefaultMaxLength;
     EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[1]);
@@ -2378,7 +2378,7 @@
   expected.id_attribute = u"element";
   expected.name = expected.id_attribute;
 
-  expected.value.clear();
+  expected.value = u"";
   EXPECT_FORM_FIELD_DATA_EQUALS(expected, result1);
 
   FormFieldData result2;
@@ -2528,7 +2528,7 @@
   FormFieldData result3;
   WebFormControlElementToFormField(WebFormElement(), element, nullptr,
                                    {ExtractOption::kOptions}, &result3);
-  expected.value.clear();
+  expected.value = u"";
   EXPECT_FORM_FIELD_DATA_EQUALS(expected, result3);
 
   ASSERT_EQ(2U, result3.options.size());
diff --git a/chrome/services/sharing/nearby/platform/ble_v2_gatt_server.cc b/chrome/services/sharing/nearby/platform/ble_v2_gatt_server.cc
index 66d7044..593d164 100644
--- a/chrome/services/sharing/nearby/platform/ble_v2_gatt_server.cc
+++ b/chrome/services/sharing/nearby/platform/ble_v2_gatt_server.cc
@@ -202,12 +202,9 @@
 }
 
 void BleV2GattServer::Stop() {
-  VLOG(1) << __func__;
-
-  // Clearing the `uuid_to_gatt_service_map_` destroys all `GattService`s owned
-  // by `BleV2GattServer`, which also includes destroying their underlying
-  // `GattService` Mojo remotes.
-  uuid_to_gatt_service_map_.clear();
+  // TODO(b/311430390): Implement to call on the Mojo remote to stop the GATT
+  // server.
+  NOTIMPLEMENTED();
 }
 
 BleV2GattServer::GattService::GattService() = default;
diff --git a/chrome/services/sharing/nearby/platform/ble_v2_gatt_server_unittest.cc b/chrome/services/sharing/nearby/platform/ble_v2_gatt_server_unittest.cc
index fbba36e5..d313535 100644
--- a/chrome/services/sharing/nearby/platform/ble_v2_gatt_server_unittest.cc
+++ b/chrome/services/sharing/nearby/platform/ble_v2_gatt_server_unittest.cc
@@ -261,27 +261,4 @@
             read_result->get_error_code());
 }
 
-TEST_F(BleV2GattServerTest, Stop) {
-  auto fake_gatt_service = std::make_unique<bluetooth::FakeGattService>();
-  fake_gatt_service->SetCreateCharacteristicResult(/*success=*/true);
-
-  base::RunLoop run_loop;
-  bool fake_gatt_service_destroyed = false;
-  fake_gatt_service->SetOnDestroyedCallback(base::BindLambdaForTesting([&]() {
-    fake_gatt_service_destroyed = true;
-    run_loop.Quit();
-  }));
-
-  fake_adapter_->SetCreateLocalGattServiceResult(
-      /*gatt_service=*/std::move(fake_gatt_service));
-  CallCreateCharacteristic(
-      /*characteristic_uuid=*/kCharacteristicUuid1,
-      /*expected_success=*/true);
-
-  // Expect the underlying objects to have been destroyed.
-  ble_v2_gatt_server_->Stop();
-  run_loop.Run();
-  EXPECT_TRUE(fake_gatt_service_destroyed);
-}
-
 }  // namespace nearby::chrome
diff --git a/chrome/services/sharing/nearby/test_support/fake_gatt_service.cc b/chrome/services/sharing/nearby/test_support/fake_gatt_service.cc
index 1f6f9e8..a06aa86 100644
--- a/chrome/services/sharing/nearby/test_support/fake_gatt_service.cc
+++ b/chrome/services/sharing/nearby/test_support/fake_gatt_service.cc
@@ -14,11 +14,7 @@
 
 FakeGattService::FakeGattService() = default;
 
-FakeGattService::~FakeGattService() {
-  if (on_destroyed_callback_) {
-    std::move(on_destroyed_callback_).Run();
-  }
-}
+FakeGattService::~FakeGattService() = default;
 
 void FakeGattService::CreateCharacteristic(
     const device::BluetoothUUID& characteristic_uuid,
diff --git a/chrome/services/sharing/nearby/test_support/fake_gatt_service.h b/chrome/services/sharing/nearby/test_support/fake_gatt_service.h
index 8587d91..1820338 100644
--- a/chrome/services/sharing/nearby/test_support/fake_gatt_service.h
+++ b/chrome/services/sharing/nearby/test_support/fake_gatt_service.h
@@ -37,10 +37,6 @@
   void SetCreateCharacteristicResult(bool success);
   int GetNumCharacteristicUuids() { return characteristic_uuids_.size(); }
 
-  void SetOnDestroyedCallback(base::OnceClosure callback) {
-    on_destroyed_callback_ = std::move(callback);
-  }
-
  private:
   void OnLocalCharacteristicReadResponse(
       ValueCallback callback,
@@ -49,7 +45,6 @@
   std::vector<device::BluetoothUUID> characteristic_uuids_;
   mojo::Remote<mojom::GattServiceObserver> observer_remote_;
   bool set_create_characteristic_result_ = false;
-  base::OnceClosure on_destroyed_callback_;
   mojo::Receiver<mojom::GattService> gatt_server_{this};
 };
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index d22b695..ececc04 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -6460,6 +6460,7 @@
     "../browser/trusted_vault/trusted_vault_encryption_keys_tab_helper_unittest.cc",
     "../browser/ui/autofill/autofill_client_provider_unittest.cc",
     "../browser/ui/autofill/autofill_popup_controller_impl_unittest.cc",
+    "../browser/ui/autofill/autofill_popup_controller_unittest.cc",
     "../browser/ui/autofill/chrome_autofill_client_unittest.cc",
     "../browser/ui/autofill/payments/card_unmask_authentication_selection_dialog_controller_impl_unittest.cc",
     "../browser/ui/autofill/payments/chrome_payments_autofill_client_unittest.cc",
@@ -10325,7 +10326,13 @@
 
 static_library("test_support_unit") {
   testonly = true
-  sources = [ "base/run_all_unittests.cc" ]
+  sources = [
+    "../browser/ui/autofill/autofill_popup_controller_test_base.cc",
+    "../browser/ui/autofill/autofill_popup_controller_test_base.h",
+    "../browser/ui/autofill/mock_autofill_popup_view.cc",
+    "../browser/ui/autofill/mock_autofill_popup_view.h",
+    "base/run_all_unittests.cc",
+  ]
 
   public_deps = [
     ":test_support",
@@ -10336,10 +10343,13 @@
     "//chrome/common",
     "//mojo/core/test:test_support",
   ]
-  deps = []
+  deps = [
+    "//chrome/browser/autofill",
+    "//components/autofill/content/browser:test_support",
+  ]
 
   if (is_win) {
-    deps = [ "//chrome/install_static/test:test_support" ]
+    deps += [ "//chrome/install_static/test:test_support" ]
   }
 
   if (is_chromeos_ash) {
@@ -10362,6 +10372,10 @@
     deps += [ "//chromeos/lacros:test_support" ]
   }
 
+  if (is_android) {
+    deps += [ "//chrome/browser/keyboard_accessory/test_utils/android" ]
+  }
+
   if (enable_bound_session_credentials) {
     sources += [
       "../browser/signin/bound_session_credentials/fake_bound_session_cookie_refresh_service.cc",
@@ -10892,6 +10906,10 @@
       ]
     }
 
+    if (enable_dice_support) {
+      sources += [ "../browser/ui/views/promos/autofill_bubble_signin_promo_interactive_uitest.cc" ]
+    }
+
     configs += [ "//build/config:precompiled_headers" ]
     if ((is_linux || is_chromeos) && !is_component_build) {
       configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ]
diff --git a/chrome/test/chromedriver/client/chromedriver.py b/chrome/test/chromedriver/client/chromedriver.py
index 0517afc..e5ef4ddc 100644
--- a/chrome/test/chromedriver/client/chromedriver.py
+++ b/chrome/test/chromedriver/client/chromedriver.py
@@ -599,6 +599,12 @@
   def FullScreenWindow(self):
     return self.ExecuteCommand(Command.FULLSCREEN_WINDOW)
 
+  def SetDevicePosture(self, posture):
+    return self.ExecuteCommand(Command.SET_DEVICE_POSTURE, {'posture': posture})
+
+  def ClearDevicePosture(self):
+    return self.ExecuteCommand(Command.CLEAR_DEVICE_POSTURE)
+
   def TakeScreenshot(self):
     return self.ExecuteCommand(Command.SCREENSHOT)
 
diff --git a/chrome/test/chromedriver/client/command_executor.py b/chrome/test/chromedriver/client/command_executor.py
index 6ed6cf1..12f75abe 100644
--- a/chrome/test/chromedriver/client/command_executor.py
+++ b/chrome/test/chromedriver/client/command_executor.py
@@ -118,6 +118,10 @@
       _Method.POST, '/session/:sessionId/window/minimize')
   FULLSCREEN_WINDOW = (
       _Method.POST, '/session/:sessionId/window/fullscreen')
+  SET_DEVICE_POSTURE = (
+      _Method.POST, '/session/:sessionId/deviceposture')
+  CLEAR_DEVICE_POSTURE = (
+      _Method.DELETE, '/session/:sessionId/deviceposture')
   CLOSE = (_Method.DELETE, '/session/:sessionId/window')
   DRAG_ELEMENT = (_Method.POST, '/session/:sessionId/element/:id/drag')
   GET_ELEMENT_VALUE_OF_CSS_PROPERTY = (
diff --git a/chrome/test/chromedriver/server/http_handler.cc b/chrome/test/chromedriver/server/http_handler.cc
index e436d70..89c0303 100644
--- a/chrome/test/chromedriver/server/http_handler.cc
+++ b/chrome/test/chromedriver/server/http_handler.cc
@@ -1041,6 +1041,17 @@
                      WrapToCommand("SetPermission",
                                    base::BindRepeating(&ExecuteSetPermission))),
 
+      // Extensions for Device Posture API:
+      // https://w3c.github.io/device-posture/#automation
+      CommandMapping(
+          kPost, "session/:sessionId/deviceposture",
+          WrapToCommand("SetDevicePosture",
+                        base::BindRepeating(&ExecuteSetDevicePosture))),
+      CommandMapping(
+          kDelete, "session/:sessionId/deviceposture",
+          WrapToCommand("ClearDevicePosture",
+                        base::BindRepeating(&ExecuteClearDevicePosture))),
+
       //
       // Non-standard extension commands
       //
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 507e779e..1a3cbb4 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -4859,6 +4859,60 @@
         "This sensor type is not being overridden with a virtual sensor",
         self._driver.UpdateVirtualSensor, 'ambient-light', {'illuminance': 42})
 
+  def testSetDevicePosture(self):
+    self._driver.Load(
+        self.GetHttpsUrlForFile('/chromedriver/device_posture_test.html'))
+    self._driver.ExecuteScript('addDevicePostureEventListener()')
+    original_posture = self._driver.ExecuteScript(
+        'return navigator.devicePosture.type')
+    posture = 'folded' if original_posture == 'continuous' else 'continuous'
+    self._driver.SetDevicePosture(posture)
+    self.assertTrue(
+        self.WaitForCondition(lambda: self._driver.ExecuteScript(
+            'return postures.length === 1')))
+    self.assertNotEqual(original_posture,
+                        self._driver.ExecuteScript('return postures.at(-1)'))
+    self._driver.SetDevicePosture(original_posture)
+    self.assertTrue(
+        self.WaitForCondition(lambda: self._driver.ExecuteScript(
+            'return postures.length === 2')))
+    self.assertEqual(original_posture,
+                     self._driver.ExecuteScript('return postures.at(-1)'))
+
+  def testSetDevicePostureInvalidArgument(self):
+    self.assertRaisesRegex(
+        chromedriver.InvalidArgument,
+        "Invalid posture type",
+        self._driver.SetDevicePosture, 'invalid-posture')
+
+  def testClearDevicePosture(self):
+    self._driver.Load(
+        self.GetHttpsUrlForFile('/chromedriver/device_posture_test.html'))
+    self._driver.ExecuteScript('addDevicePostureEventListener()')
+    original_posture = self._driver.ExecuteScript(
+        'return navigator.devicePosture.type')
+    posture = 'folded' if original_posture == 'continuous' else 'continuous'
+    self._driver.SetDevicePosture(posture)
+    self.assertTrue(
+        self.WaitForCondition(lambda: self._driver.ExecuteScript(
+            'return postures.length === 1')))
+    self.assertNotEqual(original_posture,
+                        self._driver.ExecuteScript('return postures.at(-1)'))
+    self._driver.ClearDevicePosture()
+    self.assertTrue(
+        self.WaitForCondition(lambda: self._driver.ExecuteScript(
+            'return postures.length === 2')))
+    self.assertEqual(original_posture,
+                     self._driver.ExecuteScript('return postures.at(-1)'))
+
+  def testClearDevicePostureWithoutSetDevicePosture(self):
+    self._driver.Load(
+        self.GetHttpsUrlForFile('/chromedriver/device_posture_test.html'))
+    self._driver.ExecuteScript('addDevicePostureEventListener()')
+    self._driver.ClearDevicePosture()
+    self.assertFalse(
+        self.WaitForCondition(lambda: self._driver.ExecuteScript(
+            'return postures.length === 1')))
 
 # Tests in the following class are expected to be moved to ChromeDriverTest
 # class when we no longer support the legacy mode.
diff --git a/chrome/test/chromedriver/window_commands.cc b/chrome/test/chromedriver/window_commands.cc
index 4ad21999..4f5502b 100644
--- a/chrome/test/chromedriver/window_commands.cc
+++ b/chrome/test/chromedriver/window_commands.cc
@@ -2897,3 +2897,26 @@
   auto dict = std::make_unique<base::Value::Dict>(descriptor->Clone());
   return session->chrome->SetPermission(std::move(dict), valid_state, web_view);
 }
+
+Status ExecuteSetDevicePosture(Session* session,
+                               WebView* web_view,
+                               const base::Value::Dict& params,
+                               std::unique_ptr<base::Value>* value,
+                               Timeout* timeout) {
+  const std::string* posture = params.FindString("posture");
+  if (!posture) {
+    return Status(kInvalidArgument, "'posture' must be a string");
+  }
+  base::Value::Dict args;
+  args.Set("posture", base::Value::Dict().Set("type", *posture));
+  return web_view->SendCommand("Emulation.setDevicePostureOverride", args);
+}
+
+Status ExecuteClearDevicePosture(Session* session,
+                                 WebView* web_view,
+                                 const base::Value::Dict& params,
+                                 std::unique_ptr<base::Value>* value,
+                                 Timeout* timeout) {
+  return web_view->SendCommand("Emulation.clearDevicePostureOverride",
+                               base::Value::Dict());
+}
diff --git a/chrome/test/chromedriver/window_commands.h b/chrome/test/chromedriver/window_commands.h
index 908a39f..b615321d 100644
--- a/chrome/test/chromedriver/window_commands.h
+++ b/chrome/test/chromedriver/window_commands.h
@@ -415,6 +415,18 @@
                                std::unique_ptr<base::Value>* value,
                                Timeout* timeout);
 
+Status ExecuteSetDevicePosture(Session* session,
+                               WebView* web_view,
+                               const base::Value::Dict& params,
+                               std::unique_ptr<base::Value>* value,
+                               Timeout* timeout);
+
+Status ExecuteClearDevicePosture(Session* session,
+                                 WebView* web_view,
+                                 const base::Value::Dict& params,
+                                 std::unique_ptr<base::Value>* value,
+                                 Timeout* timeout);
+
 // Sets the sink to be used when the web page invokes Presentation or Remote
 // Playback API. Uses the "sinkName" value in |params|.
 Status ExecuteSetSinkToUse(Session* session,
diff --git a/chrome/test/data/chromedriver/device_posture_test.html b/chrome/test/data/chromedriver/device_posture_test.html
new file mode 100644
index 0000000..ba0e586
--- /dev/null
+++ b/chrome/test/data/chromedriver/device_posture_test.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script>
+const postures = [];
+
+function addDevicePostureEventListener() {
+  navigator.devicePosture.addEventListener("change", () => {
+    postures.push(navigator.devicePosture.type);
+  });
+}
+</script>
diff --git a/chrome/test/data/webui/cr_components/cr_components_browsertest.cc b/chrome/test/data/webui/cr_components/cr_components_browsertest.cc
index 03fe133..edf15de 100644
--- a/chrome/test/data/webui/cr_components/cr_components_browsertest.cc
+++ b/chrome/test/data/webui/cr_components/cr_components_browsertest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/browser/browser_features.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/test/base/web_ui_mocha_browser_test.h"
 #include "components/history_clusters/core/features.h"
@@ -172,11 +173,6 @@
   RunTest("cr_components/most_visited_test.js", "runMochaSuite('Theming');");
 }
 
-IN_PROC_BROWSER_TEST_F(CrComponentsMostVisitedTest, Prerendering) {
-  RunTest("cr_components/most_visited_test.js",
-          "runMochaSuite('Prerendering');");
-}
-
 typedef WebUIMochaBrowserTest CrComponentsThemeColorPickerTest;
 IN_PROC_BROWSER_TEST_F(CrComponentsThemeColorPickerTest, ThemeColor) {
   set_test_loader_host(chrome::kChromeUICustomizeChromeSidePanelHost);
@@ -201,3 +197,24 @@
   RunTest("cr_components/theme_color_picker/theme_hue_slider_dialog_test.js",
           "mocha.run()");
 }
+
+class CrComponentsPrerenderTest : public CrComponentsMostVisitedTest {
+ protected:
+  CrComponentsPrerenderTest() {
+    const std::map<std::string, std::string> params = {
+        {"prerender_start_delay_on_mouse_hover_ms", "0"},
+        {"preconnect_start_delay_on_mouse_hover_ms", "0"},
+        {"prerender_new_tab_page_on_mouse_pressed_trigger", "true"},
+        {"prerender_new_tab_page_on_mouse_hover_trigger", "true"}};
+    scoped_feature_list_.InitAndEnableFeatureWithParameters(
+        features::kNewTabPageTriggerForPrerender2, params);
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(CrComponentsPrerenderTest, Prerendering) {
+  RunTest("cr_components/most_visited_test.js",
+          "runMochaSuite('Prerendering');");
+}
diff --git a/chrome/test/data/webui/cr_components/most_visited_test.ts b/chrome/test/data/webui/cr_components/most_visited_test.ts
index d1eba7d..dbeec2d4 100644
--- a/chrome/test/data/webui/cr_components/most_visited_test.ts
+++ b/chrome/test/data/webui/cr_components/most_visited_test.ts
@@ -1254,35 +1254,12 @@
 });
 
 suite('Prerendering', () => {
-  suiteSetup(() => {
-    loadTimeData.overrideValues({
-      prerenderEnabled: true,
-      preconnectStartTimeThreshold: 0,
-      prerenderStartTimeThreshold: 0,
-    });
-  });
+  suiteSetup(() => {});
 
   setup(() => {
     setUpTest(/*singleRow=*/ false, /*reflowOnOverflow=*/ false);
   });
 
-  test('preconnect', async () => {
-    // Arrange.
-    await addTiles(1);
-
-    // Act.
-    const tileLink = queryTiles()[0]!.querySelector('a')!;
-    // Prevent triggering a navigation, which would break the test.
-    tileLink.href = '#';
-    // Simulate a mousedown event.
-    const mouseEvent = document.createEvent('MouseEvents');
-    mouseEvent.initEvent('mouseenter', true, true);
-    tileLink.dispatchEvent(mouseEvent);
-
-    // Make sure preconnect has been triggered.
-    await handler.whenCalled('preconnectMostVisitedTile');
-  });
-
   test('onMouseHover Trigger', async () => {
     // Arrange.
     await addTiles(1);
@@ -1296,7 +1273,8 @@
     mouseEvent.initEvent('mouseenter', true, true);
     tileLink.dispatchEvent(mouseEvent);
 
-    // Make sure Prerendering has been triggered.
+    // Make sure both preconnect and prerender have been triggered.
+    await handler.whenCalled('preconnectMostVisitedTile');
     await handler.whenCalled('prerenderMostVisitedTile');
   });
 
diff --git a/chrome/test/data/webui/settings/chromeos/os_languages_page/input_page_test.ts b/chrome/test/data/webui/settings/chromeos/os_languages_page/input_page_test.ts
index 73356d6..59ebd79 100644
--- a/chrome/test/data/webui/settings/chromeos/os_languages_page/input_page_test.ts
+++ b/chrome/test/data/webui/settings/chromeos/os_languages_page/input_page_test.ts
@@ -122,21 +122,12 @@
   });
 
   suite('language pack notice', () => {
-    test('is shown when needed', async () => {
-      loadTimeData.overrideValues({languagePacksHandwritingEnabled: true});
+    test('is shown', async () => {
       await createInputPage();
 
       assertTrue(isVisible(
           inputPage.shadowRoot!.querySelector('#languagePacksNotice')));
     });
-
-    test('is hidden when needed', async () => {
-      loadTimeData.overrideValues({languagePacksHandwritingEnabled: false});
-      await createInputPage();
-
-      assertFalse(isVisible(
-          inputPage.shadowRoot!.querySelector('#languagePacksNotice')));
-    });
   });
 
   suite('input method list', () => {
@@ -639,10 +630,6 @@
     });
 
     test('when clicking on "learn more" about language packs', async () => {
-      inputPage.set('shouldShowLanguagePacksNotice_', true);
-      loadTimeData.overrideValues({languagePacksHandwritingEnabled: true});
-      flush();
-
       const languagePacksNotice =
           inputPage.shadowRoot!.querySelector('#languagePacksNotice');
       assertTrue(!!languagePacksNotice);
diff --git a/chrome/test/fuzzing/renderer_fuzzing/BUILD.gn b/chrome/test/fuzzing/renderer_fuzzing/BUILD.gn
index df0e18fe..f6decf8 100644
--- a/chrome/test/fuzzing/renderer_fuzzing/BUILD.gn
+++ b/chrome/test/fuzzing/renderer_fuzzing/BUILD.gn
@@ -4,7 +4,8 @@
 
 import("//chrome/test/fuzzing/in_process_fuzzer.gni")
 import("//chrome/test/fuzzing/renderer_fuzzing/in_process_renderer_fuzzing.gni")
-import("//chrome/test/fuzzing/renderer_fuzzing/mojom_interfaces.gni")
+import(
+    "//chrome/test/fuzzing/renderer_fuzzing/ipc_fuzzing/mojom_interfaces.gni")
 
 group("test") {
   testonly = true
@@ -18,25 +19,54 @@
       "//base",
       "//chrome/test:test_support",
       "//chrome/test/fuzzing:in_process_fuzzer_runner",
+      "//chrome/test/fuzzing:in_process_proto_fuzzer_runner",
       "//testing/libfuzzer:renderer_fuzzing",
     ]
   }
 }
 
 if (!is_android) {
+  action("renderer_in_process_mojolpm_fuzzer_generator") {
+    testonly = true
+    script = "//chrome/test/fuzzing/renderer_fuzzing/ipc_fuzzing/generate_testcase.py"
+    args = [
+      "-n",
+      "renderer_in_process_mojolpm_fuzzer",
+      "-d",
+      rebase_path("${target_gen_dir}/", root_gen_dir),
+      "-o",
+      rebase_path("${target_gen_dir}/testcase.h", root_build_dir),
+      "-c",
+    ]
+    foreach(interface, blink_browser_exposed_interfaces) {
+      args += [ interface[1] ]
+    }
+    args += [ "-p" ]
+    foreach(interface, process_browser_exposed_interfaces) {
+      args += [ interface[1] ]
+    }
+    outputs = [ "${target_gen_dir}/testcase.h" ]
+  }
   in_process_renderer_mojolpm_generated_fuzzer(
       "renderer_in_process_mojolpm_fuzzer") {
     sources = [ "renderer_in_process_mojolpm_fuzzer.cc" ]
 
     interfaces = blink_browser_exposed_interfaces
+    interfaces += process_browser_exposed_interfaces
 
     deps = [
+      ":renderer_in_process_mojolpm_fuzzer_generator",
       "//chrome/test:test_support",
       "//chrome/test/fuzzing:in_process_proto_fuzzer_runner",
+      "//components/metrics/public/mojom:single_sample_metrics_mojo_bindings_mojolpm",
+      "//content/common:mojo_bindings_mojolpm",
       "//content/test/fuzzer:mojolpm_fuzzer_support",
+      "//media/mojo/mojom:mojom_mojolpm",
+      "//services/resource_coordinator/public/mojom:mojom_mojolpm",
       "//testing/libfuzzer:renderer_fuzzing",
       "//testing/libfuzzer/proto:url_proto_converter",
       "//third_party/blink/public/common:storage_key_proto_converter",
+      "//third_party/blink/public/mojom:embedded_frame_sink_mojo_bindings_mojolpm",
       "//third_party/blink/public/mojom:mojom_core_mojolpm",
       "//third_party/blink/public/mojom:mojom_modules_mojolpm",
       "//third_party/blink/public/mojom:mojom_platform_mojolpm",
@@ -44,6 +74,11 @@
     ]
 
     proto_deps = [
+      "//components/metrics/public/mojom:single_sample_metrics_mojo_bindings_mojolpm",
+      "//content/common:mojo_bindings_mojolpm",
+      "//media/mojo/mojom:mojom_mojolpm",
+      "//services/resource_coordinator/public/mojom:mojom_mojolpm",
+      "//third_party/blink/public/mojom:embedded_frame_sink_mojo_bindings_mojolpm",
       "//third_party/blink/public/mojom:mojom_core_mojolpm",
       "//third_party/blink/public/mojom:mojom_modules_mojolpm",
       "//third_party/blink/public/mojom:mojom_platform_mojolpm",
diff --git a/chrome/test/fuzzing/renderer_fuzzing/in_process_renderer_fuzzing.h b/chrome/test/fuzzing/renderer_fuzzing/in_process_renderer_fuzzing.h
index 2054bf0..f46b82c 100644
--- a/chrome/test/fuzzing/renderer_fuzzing/in_process_renderer_fuzzing.h
+++ b/chrome/test/fuzzing/renderer_fuzzing/in_process_renderer_fuzzing.h
@@ -8,6 +8,7 @@
 #include "base/base64.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/fuzzing/in_process_fuzzer.h"
+#include "chrome/test/fuzzing/in_process_proto_fuzzer.h"
 #include "content/public/test/browser_test_utils.h"
 #include "testing/libfuzzer/renderer_fuzzing/renderer_fuzzing.h"
 
diff --git a/chrome/test/fuzzing/renderer_fuzzing/ipc_fuzzing/generate_testcase.py b/chrome/test/fuzzing/renderer_fuzzing/ipc_fuzzing/generate_testcase.py
new file mode 100755
index 0000000..873aea3
--- /dev/null
+++ b/chrome/test/fuzzing/renderer_fuzzing/ipc_fuzzing/generate_testcase.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python3
+#
+# Copyright 2024 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""MojoLPM Testcase Generator
+
+This script must be used with MojoLPMGenerator and a RendererFuzzer. It
+generates code to handle interface creation requested by MojoLPM by using the
+interface brokers provided by the internal RendererFuzzer mechanism.
+
+This script uses the jinja2 and the `testcase.h.tmpl` template to generate C++
+code. A class named `RendererTestcase` will be created.
+"""
+
+from __future__ import annotations
+
+import abc
+import argparse
+import dataclasses
+import os
+import pathlib
+import re
+import sys
+
+import typing
+import enum
+
+# Copied from //mojo/public/tools/mojom/mojom/fileutil.py.
+def AddLocalRepoThirdPartyDirToModulePath():
+  """Helper function to find the top-level directory of this script's repository
+  assuming the script falls somewhere within a 'chrome' directory, and insert
+  the top-level 'third_party' directory early in the module search path. Used to
+  ensure that third-party dependencies provided within the repository itself
+  (e.g. Chromium sources include snapshots of jinja2 and ply) are preferred over
+  locally installed system library packages."""
+  def _GetDirAbove(dirname: str):
+    """Returns the directory "above" this file containing |dirname| (which must
+    also be "above" this file)."""
+    path = os.path.abspath(__file__)
+    while True:
+      path, tail = os.path.split(path)
+      if not tail:
+        return None
+      if tail == dirname:
+        return path
+
+  toplevel_dir = _GetDirAbove('chrome')
+  if toplevel_dir:
+    sys.path.insert(1, os.path.join(toplevel_dir, 'third_party'))
+
+# This is needed in order to be able to import jinja2.
+AddLocalRepoThirdPartyDirToModulePath()
+
+import jinja2
+
+def split_interface_name(interface: str):
+  """Helper that splits a qualified mojo interface name into a dictionary
+  containing the key 'name' that contains the name of the interface, and the
+  key 'namespace' that contains its mojo namespace.
+
+  Args:
+      interface (str): the qualified interface name
+
+  Returns:
+      a dict containing the actual interface name and its namespace.
+  """
+  return {
+    "name": interface.split(".")[-1],
+    "namespace": "::".join(interface.split(".")[:-1]),
+  }
+
+def snake_to_camel_case(snake_str: str) -> str:
+  """Snake case to camel case conversion.
+
+  Args:
+      snake_str: the snake case identifier to convert.
+
+  Returns:
+     `snake_str` converted to a camel case identifier.
+  """
+  return "".join(x.capitalize() for x in snake_str.lower().split("_"))
+
+def main():
+  parser = argparse.ArgumentParser(
+      description='Generate an IPC fuzzer based on MojoLPM Generator.')
+  parser.add_argument(
+      '-c',
+      '--context',
+      default=[],
+      nargs='+',
+      required=True,
+      help="Context bound interfaces to fuzz.")
+  parser.add_argument(
+      '-p',
+      '--process',
+      default=[],
+      nargs='+',
+      required=True,
+      help="Process bound interfaces to fuzz.")
+  parser.add_argument(
+      '-d',
+      '--fuzzer_dir',
+      required=True,
+      help="The directory in which the MojoLPMGenerator fuzzer is generated.")
+  parser.add_argument(
+      '-n',
+      '--name',
+      required=True,
+      help="""The name of the MojoLPMGenerator fuzzing target.
+      This will used to deduce the name of the generated MojoLPM testcase.""")
+  parser.add_argument(
+      '-o',
+      '--output',
+      required=True,
+      help="Output file name.")
+
+  args = parser.parse_args()
+  template_dir = os.path.dirname(os.path.abspath(__file__))
+  environment = jinja2.Environment(loader=jinja2.FileSystemLoader(
+      template_dir))
+  template = environment.get_template('testcase.h.tmpl')
+  fuzzer_path = os.path.join(args.fuzzer_dir, args.name)
+  fuzzer_name = snake_to_camel_case(args.name)
+  mojolpm_classname = f"mojolpmgenerator::{fuzzer_name}Testcase"
+  context = {
+    "filename": args.output,
+    "mojolpm_generator_filepath": f"{fuzzer_path}.h",
+    "mojolpm_generator_classname": mojolpm_classname,
+    "process_interfaces": [split_interface_name(p) for p in args.process],
+    "context_interfaces": [split_interface_name(c) for c in args.context],
+  }
+  with pathlib.Path(args.output).open(mode="w") as f:
+    f.write(template.render(context))
+
+if __name__ == "__main__":
+  main()
diff --git a/chrome/test/fuzzing/renderer_fuzzing/ipc_fuzzing/mojom_interfaces.gni b/chrome/test/fuzzing/renderer_fuzzing/ipc_fuzzing/mojom_interfaces.gni
new file mode 100644
index 0000000..debb352
--- /dev/null
+++ b/chrome/test/fuzzing/renderer_fuzzing/ipc_fuzzing/mojom_interfaces.gni
@@ -0,0 +1,490 @@
+# Context exposed interfaces
+# As for now, those are the blink interfaces exposed via Document/Frames
+# defined at https://source.chromium.org/chromium/chromium/src/+/main:content/browser/browser_interface_binders.cc;l=740;bpv=1;bpt=1
+# At some point, this will be automatically generated based on what's contained
+# in this function. This only demonstrates how this could be done.
+blink_browser_exposed_interfaces = [
+  [
+    "//third_party/blink/public/mojom/interest_group/ad_auction_service.mojom",
+    "blink.mojom.AdAuctionService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/preloading/anchor_element_interaction_host.mojom",
+    "blink.mojom.AnchorElementInteractionHost",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/loader/navigation_predictor.mojom",
+    "blink.mojom.AnchorElementMetricsHost",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/webaudio/audio_context_manager.mojom",
+    "blink.mojom.AudioContextManager",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/webauthn/authenticator.mojom",
+    "blink.mojom.Authenticator",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/background_fetch/background_fetch.mojom",
+    "blink.mojom.BackgroundFetchService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/blob/blob_url_store.mojom",
+    "blink.mojom.BlobURLStore",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/browsing_topics/browsing_topics.mojom",
+    "blink.mojom.BrowsingTopicsDocumentService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/buckets/bucket_manager_host.mojom",
+    "blink.mojom.BucketManagerHost",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/cache_storage/cache_storage.mojom",
+    "blink.mojom.CacheStorage",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/clipboard/clipboard.mojom",
+    "blink.mojom.ClipboardHost",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/loader/code_cache.mojom",
+    "blink.mojom.CodeCacheHost",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/choosers/color_chooser.mojom",
+    "blink.mojom.ColorChooserFactory",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/contacts/contacts_manager.mojom",
+    "blink.mojom.ContactsManager",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/content_index/content_index.mojom",
+    "blink.mojom.ContentIndexService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/loader/content_security_notifier.mojom",
+    "blink.mojom.ContentSecurityNotifier",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/cookie_store/cookie_store.mojom",
+    "blink.mojom.CookieStore",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/credentialmanagement/credential_manager.mojom",
+    "blink.mojom.CredentialManager",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/worker/dedicated_worker_host_factory.mojom",
+    "blink.mojom.DedicatedWorkerHostFactory",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/device/device.mojom",
+    "blink.mojom.DeviceAPIService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/device_posture/device_posture_provider.mojom",
+    "blink.mojom.DevicePostureProvider",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/webid/digital_identity_request.mojom",
+    "blink.mojom.DigitalIdentityRequest",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/direct_sockets/direct_sockets.mojom",
+    "blink.mojom.DirectSocketsService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/choosers/color_chooser.mojom",
+    "blink.mojom.EyeDropperChooser",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/feature_observer/feature_observer.mojom",
+    "blink.mojom.FeatureObserver",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/webid/federated_auth_request.mojom",
+    "blink.mojom.FederatedAuthRequest",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/choosers/file_chooser.mojom",
+    "blink.mojom.FileChooser",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/file_system_access/file_system_access_manager.mojom",
+    "blink.mojom.FileSystemAccessManager",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/filesystem/file_system.mojom",
+    "blink.mojom.FileSystemManager",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/file/file_utilities.mojom",
+    "blink.mojom.FileUtilitiesHost",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/font_access/font_access.mojom",
+    "blink.mojom.FontAccessManager",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/geolocation/geolocation_service.mojom",
+    "blink.mojom.GeolocationService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/hid/hid.mojom",
+    "blink.mojom.HidService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/indexeddb/indexeddb.mojom",
+    "blink.mojom.IDBFactory",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/idle/idle_manager.mojom",
+    "blink.mojom.IdleManager",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/installedapp/installed_app_provider.mojom",
+    "blink.mojom.InstalledAppProvider",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/keyboard_lock/keyboard_lock.mojom",
+    "blink.mojom.KeyboardLockService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/lcp_critical_path_predictor/lcp_critical_path_predictor.mojom",
+    "blink.mojom.LCPCriticalPathPredictorHost",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/locks/lock_manager.mojom",
+    "blink.mojom.LockManager",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/device/device.mojom",
+    "blink.mojom.ManagedConfigurationService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/mediastream/media_devices.mojom",
+    "blink.mojom.MediaDevicesDispatcherHost",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/mediasession/media_session.mojom",
+    "blink.mojom.MediaSessionService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/mediastream/media_stream.mojom",
+    "blink.mojom.MediaStreamDispatcherHost",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/model_execution/model_manager.mojom",
+    "blink.mojom.ModelManager",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/frame/frame.mojom",
+    "blink.mojom.NonAssociatedLocalFrameHost",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/prerender/prerender.mojom",
+    "blink.mojom.NoStatePrefetchProcessor",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/notifications/notification_service.mojom",
+    "blink.mojom.NotificationService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/background_sync/background_sync.mojom",
+    "blink.mojom.OneShotBackgroundSyncService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/origin_trial_state/origin_trial_state_host.mojom",
+    "blink.mojom.OriginTrialStateHost",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/peerconnection/peer_connection_tracker.mojom",
+    "blink.mojom.PeerConnectionTrackerHost",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/background_sync/background_sync.mojom",
+    "blink.mojom.PeriodicBackgroundSyncService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/permissions/permission.mojom",
+    "blink.mojom.PermissionService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/picture_in_picture/picture_in_picture.mojom",
+    "blink.mojom.PictureInPictureService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/presentation/presentation.mojom",
+    "blink.mojom.PresentationService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/push_messaging/push_messaging.mojom",
+    "blink.mojom.PushMessaging",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/quota/quota_manager_host.mojom",
+    "blink.mojom.QuotaManagerHost",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/render_accessibility.mojom",
+    "blink.mojom.RenderAccessibilityHost",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom",
+    "blink.mojom.RendererAudioInputStreamFactory",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/media/renderer_audio_output_stream_factory.mojom",
+    "blink.mojom.RendererAudioOutputStreamFactory",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/reporting/reporting.mojom",
+    "blink.mojom.ReportingServiceProxy",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/serial/serial.mojom",
+    "blink.mojom.SerialService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/worker/shared_worker_connector.mojom",
+    "blink.mojom.SharedWorkerConnector",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom",
+    "blink.mojom.SpeculationHost",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/speech/speech_recognizer.mojom",
+    "blink.mojom.SpeechRecognizer",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/speech/speech_synthesis.mojom",
+    "blink.mojom.SpeechSynthesis",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/storage_access/storage_access_handle.mojom",
+    "blink.mojom.StorageAccessHandle",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/input/input_host.mojom",
+    "blink.mojom.TextSuggestionHost",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/wake_lock/wake_lock.mojom",
+    "blink.mojom.WakeLockService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/bluetooth/web_bluetooth.mojom",
+    "blink.mojom.WebBluetoothService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/sms/webotp_service.mojom",
+    "blink.mojom.WebOTPService",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/sensor/web_sensor_provider.mojom",
+    "blink.mojom.WebSensorProvider",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/websockets/websocket_connector.mojom",
+    "blink.mojom.WebSocketConnector",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/webtransport/web_transport_connector.mojom",
+    "blink.mojom.WebTransportConnector",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/usb/web_usb_service.mojom",
+    "blink.mojom.WebUsbService",
+    "Remote",
+  ],
+]
+
+process_browser_exposed_interfaces = [
+  [
+    "//third_party/blink/public/mojom/blob/blob_registry.mojom",
+    "blink.mojom.BlobRegistry",
+    "Remote",
+  ],
+  [
+    "//content/common/render_message_filter.mojom",
+    "content.mojom.RenderMessageFilter",
+    "Remote",
+  ],
+  [
+    "//services/device/public/mojom/time_zone_monitor.mojom",
+    "device.mojom.TimeZoneMonitor",
+    "Remote",
+  ],
+  [
+    "//services/device/public/mojom/power_monitor.mojom",
+    "device.mojom.PowerMonitor",
+    "Remote",
+  ],
+  [
+    "//services/device/public/mojom/screen_orientation.mojom",
+    "device.mojom.ScreenOrientationListener",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/frame_sinks/embedded_frame_sink.mojom",
+    "blink.mojom.EmbeddedFrameSinkProvider",
+    "Remote",
+  ],
+  [
+    "//services/viz/public/mojom/compositing/compositing_mode_watcher.mojom",
+    "viz.mojom.CompositingModeReporter",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/dom_storage/dom_storage.mojom",
+    "blink.mojom.DomStorageProvider",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/webdatabase/web_database.mojom",
+    "blink.mojom.WebDatabaseHost",
+    "Remote",
+  ],
+  [
+    "//services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom",
+    "memory_instrumentation.mojom.CoordinatorConnector",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/mime/mime_registry.mojom",
+    "blink.mojom.MimeRegistry",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/hyphenation/hyphenation.mojom",
+    "blink.mojom.Hyphenation",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/font_unique_name_lookup/font_unique_name_lookup.mojom",
+    "blink.mojom.FontUniqueNameLookup",
+    "Remote",
+  ],
+  [
+    "//services/viz/public/mojom/gpu.mojom",
+    "viz.mojom.Gpu",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/gpu/gpu.mojom",
+    "blink.mojom.GpuDataManager",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/mediastream/media_stream.mojom",
+    "blink.mojom.MediaStreamTrackMetricsHost",
+    "Remote",
+  ],
+  [
+    "//components/metrics/public/mojom/single_sample_metrics.mojom",
+    "metrics.mojom.SingleSampleMetricsProvider",
+    "Remote",
+  ],
+  [
+    "//content/common/media/media_log_records.mojom",
+    "content.mojom.MediaInternalLogRecords",
+    "Remote",
+  ],
+  [
+    "//content/common/field_trial_recorder.mojom",
+    "content.mojom.FieldTrialRecorder",
+    "Remote",
+  ],
+  [
+    "//media/mojo/mojom/interface_factory.mojom",
+    "media.mojom.InterfaceFactory",
+    "Remote",
+  ],
+  [
+    "//media/mojo/mojom/video_encoder_metrics_provider.mojom",
+    "media.mojom.VideoEncoderMetricsProvider",
+    "Remote",
+  ],
+  [
+    "//third_party/blink/public/mojom/mediastream/aec_dump.mojom",
+    "blink.mojom.AecDumpManager",
+    "Remote",
+  ],
+]
diff --git a/chrome/test/fuzzing/renderer_fuzzing/ipc_fuzzing/testcase.h.tmpl b/chrome/test/fuzzing/renderer_fuzzing/ipc_fuzzing/testcase.h.tmpl
new file mode 100644
index 0000000..e1514e86
--- /dev/null
+++ b/chrome/test/fuzzing/renderer_fuzzing/ipc_fuzzing/testcase.h.tmpl
@@ -0,0 +1,173 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+{%- set header_guard = "%s_"|format(
+        filename|upper|replace("/","_")|replace(".","_")|
+            replace("-", "_")) %}
+
+#ifndef {{header_guard}}
+#define {{header_guard}}
+
+#include "{{mojolpm_generator_filepath}}"
+
+#include "base/functional/bind.h"
+#include "mojo/public/tools/fuzzers/mojolpm.h"
+
+class RendererTestcase
+    : public {{mojolpm_generator_classname}} {
+ public:
+  explicit RendererTestcase(
+      std::unique_ptr<ProtoTestcase> testcase,
+      const blink::BrowserInterfaceBrokerProxy* context_interface_broker_proxy,
+      blink::ThreadSafeBrowserInterfaceBrokerProxy*
+          process_interface_broker_proxy);
+  ~RendererTestcase() override;
+
+  scoped_refptr<base::SequencedTaskRunner> GetFuzzerTaskRunner() override;
+  void SetUp(base::OnceClosure done_closure) override;
+  void TearDown(base::OnceClosure done_closure) override;
+{% for interface in context_interfaces %}
+  void HandleNew{{interface.name}}Action(
+      uint32_t id,
+      base::OnceClosure done_closure) override;
+{% endfor %}
+
+{% for interface in process_interfaces %}
+  void HandleNew{{interface.name}}Action(
+      uint32_t id,
+      base::OnceClosure done_closure) override;
+{% endfor %}
+
+ private:
+  void SetUpOnFuzzerThread(base::OnceClosure done_closure);
+  void TearDownOnFuzzerThread(base::OnceClosure done_closure);
+
+  template <typename T>
+  void NewProcessInterface(uint32_t id, base::OnceClosure done_closure);
+  template <typename T>
+  void NewContextInterface(uint32_t id, base::OnceClosure done_closure);
+
+  // This is different to the "normal" MojoLPM testcase model, since we need
+  // to also own the lifetime of the protobuf object, when it's normally owned
+  // by libfuzzer.
+  std::unique_ptr<ProtoTestcase> proto_testcase_ptr_;
+
+  // Bindings
+  raw_ptr<const blink::BrowserInterfaceBrokerProxy>
+      context_interface_broker_proxy_;
+  raw_ptr<blink::ThreadSafeBrowserInterfaceBrokerProxy>
+      process_interface_broker_proxy_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+};
+
+namespace {
+
+scoped_refptr<base::SequencedTaskRunner> GetFuzzerTaskRunnerImpl() {
+  // XXX: This should be main thread? IO thread? Probably doesn't
+  // actually matter.
+  static scoped_refptr<base::SequencedTaskRunner> fuzzer_task_runner =
+      base::SequencedTaskRunner::GetCurrentDefault();
+  return fuzzer_task_runner;
+}
+
+}  // anonymous namespace
+
+{% for interface in context_interfaces %}
+void RendererTestcase::HandleNew{{interface.name}}Action(
+    uint32_t id,
+    base::OnceClosure done_closure) {
+  NewContextInterface<{{interface.namespace}}::{{interface.name}}>(id, std::move(done_closure));
+}
+{% endfor %}
+
+{% for interface in process_interfaces %}
+void RendererTestcase::HandleNew{{interface.name}}Action(
+    uint32_t id,
+    base::OnceClosure done_closure) {
+  NewProcessInterface<{{interface.namespace}}::{{interface.name}}>(id, std::move(done_closure));
+}
+{% endfor %}
+
+
+scoped_refptr<base::SequencedTaskRunner>
+RendererTestcase::GetFuzzerTaskRunner() {
+  return GetFuzzerTaskRunnerImpl();
+}
+
+RendererTestcase::RendererTestcase(
+    std::unique_ptr<ProtoTestcase> testcase,
+    const blink::BrowserInterfaceBrokerProxy* context_interface_broker_proxy,
+    blink::ThreadSafeBrowserInterfaceBrokerProxy*
+        process_interface_broker_proxy)
+    : {{mojolpm_generator_classname}}(*testcase.get()),
+      proto_testcase_ptr_(std::move(testcase)),
+      context_interface_broker_proxy_(context_interface_broker_proxy),
+      process_interface_broker_proxy_(process_interface_broker_proxy) {
+  // RendererTestcase is created on the main thread, but the actions that
+  // we want to validate the sequencing of take place on the fuzzer sequence.
+  DETACH_FROM_SEQUENCE(sequence_checker_);
+}
+
+RendererTestcase::~RendererTestcase() {}
+
+void RendererTestcase::SetUp(base::OnceClosure done_closure) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  GetFuzzerTaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&RendererTestcase::SetUpOnFuzzerThread,
+                     base::Unretained(this), std::move(done_closure)));
+}
+
+void RendererTestcase::TearDown(base::OnceClosure done_closure) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  GetFuzzerTaskRunner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&RendererTestcase::TearDownOnFuzzerThread,
+                     base::Unretained(this), std::move(done_closure)));
+}
+
+void RendererTestcase::SetUpOnFuzzerThread(base::OnceClosure done_closure) {
+  mojolpm::GetContext()->StartTestcase();
+
+  std::move(done_closure).Run();
+}
+
+void RendererTestcase::TearDownOnFuzzerThread(base::OnceClosure done_closure) {
+  mojolpm::GetContext()->EndTestcase();
+
+  std::move(done_closure).Run();
+}
+
+template <typename T>
+void RendererTestcase::NewProcessInterface(uint32_t id,
+                                           base::OnceClosure done_closure) {
+  mojo::Remote<T> remote;
+  mojo::GenericPendingReceiver receiver = remote.BindNewPipeAndPassReceiver();
+
+  process_interface_broker_proxy_->GetInterface(std::move(receiver));
+  CHECK(remote.is_bound() && remote.is_connected());
+
+  mojolpm::GetContext()->AddInstance(id, std::move(remote));
+
+  std::move(done_closure).Run();
+}
+
+template <typename T>
+void RendererTestcase::NewContextInterface(uint32_t id,
+                                           base::OnceClosure done_closure) {
+  mojo::Remote<T> remote;
+  mojo::GenericPendingReceiver receiver = remote.BindNewPipeAndPassReceiver();
+
+  context_interface_broker_proxy_->GetInterface(std::move(receiver));
+  CHECK(remote.is_bound() && remote.is_connected());
+
+  mojolpm::GetContext()->AddInstance(id, std::move(remote));
+
+  std::move(done_closure).Run();
+}
+
+#endif  // {{header_guard}}
diff --git a/chrome/test/fuzzing/renderer_fuzzing/mojom_interfaces.gni b/chrome/test/fuzzing/renderer_fuzzing/mojom_interfaces.gni
deleted file mode 100644
index 0111067..0000000
--- a/chrome/test/fuzzing/renderer_fuzzing/mojom_interfaces.gni
+++ /dev/null
@@ -1,382 +0,0 @@
-# Context exposed interfaces
-# As for now, those are the blink interfaces exposed via Document/Frames
-# defined at https://source.chromium.org/chromium/chromium/src/+/main:content/browser/browser_interface_binders.cc;l=740;bpv=1;bpt=1
-# At some point, this will be automatically generated based on what's contained
-# in this function. This only demonstrates how this could be done.
-blink_browser_exposed_interfaces = [
-  [
-    "//third_party/blink/public/mojom/blob/blob_registry.mojom",
-    "BlobRegistry",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/interest_group/ad_auction_service.mojom",
-    "AdAuctionService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/preloading/anchor_element_interaction_host.mojom",
-    "AnchorElementInteractionHost",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/loader/navigation_predictor.mojom",
-    "AnchorElementMetricsHost",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/webaudio/audio_context_manager.mojom",
-    "AudioContextManager",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/webauthn/authenticator.mojom",
-    "Authenticator",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/background_fetch/background_fetch.mojom",
-    "BackgroundFetchService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/blob/blob_url_store.mojom",
-    "BlobURLStore",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/browsing_topics/browsing_topics.mojom",
-    "BrowsingTopicsDocumentService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/buckets/bucket_manager_host.mojom",
-    "BucketManagerHost",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/cache_storage/cache_storage.mojom",
-    "CacheStorage",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/clipboard/clipboard.mojom",
-    "ClipboardHost",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/loader/code_cache.mojom",
-    "CodeCacheHost",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/choosers/color_chooser.mojom",
-    "ColorChooserFactory",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/contacts/contacts_manager.mojom",
-    "ContactsManager",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/content_index/content_index.mojom",
-    "ContentIndexService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/loader/content_security_notifier.mojom",
-    "ContentSecurityNotifier",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/cookie_store/cookie_store.mojom",
-    "CookieStore",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/credentialmanagement/credential_manager.mojom",
-    "CredentialManager",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/worker/dedicated_worker_host_factory.mojom",
-    "DedicatedWorkerHostFactory",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/device/device.mojom",
-    "DeviceAPIService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/device_posture/device_posture_provider.mojom",
-    "DevicePostureProvider",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/webid/digital_identity_request.mojom",
-    "DigitalIdentityRequest",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/direct_sockets/direct_sockets.mojom",
-    "DirectSocketsService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/choosers/color_chooser.mojom",
-    "EyeDropperChooser",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/feature_observer/feature_observer.mojom",
-    "FeatureObserver",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/webid/federated_auth_request.mojom",
-    "FederatedAuthRequest",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/choosers/file_chooser.mojom",
-    "FileChooser",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/file_system_access/file_system_access_manager.mojom",
-    "FileSystemAccessManager",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/filesystem/file_system.mojom",
-    "FileSystemManager",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/file/file_utilities.mojom",
-    "FileUtilitiesHost",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/font_access/font_access.mojom",
-    "FontAccessManager",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/geolocation/geolocation_service.mojom",
-    "GeolocationService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/hid/hid.mojom",
-    "HidService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/indexeddb/indexeddb.mojom",
-    "IDBFactory",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/idle/idle_manager.mojom",
-    "IdleManager",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/installedapp/installed_app_provider.mojom",
-    "InstalledAppProvider",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/keyboard_lock/keyboard_lock.mojom",
-    "KeyboardLockService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/lcp_critical_path_predictor/lcp_critical_path_predictor.mojom",
-    "LCPCriticalPathPredictorHost",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/locks/lock_manager.mojom",
-    "LockManager",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/device/device.mojom",
-    "ManagedConfigurationService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/mediastream/media_devices.mojom",
-    "MediaDevicesDispatcherHost",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/mediasession/media_session.mojom",
-    "MediaSessionService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/mediastream/media_stream.mojom",
-    "MediaStreamDispatcherHost",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/model_execution/model_manager.mojom",
-    "ModelManager",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/frame/frame.mojom",
-    "NonAssociatedLocalFrameHost",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/prerender/prerender.mojom",
-    "NoStatePrefetchProcessor",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/notifications/notification_service.mojom",
-    "NotificationService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/background_sync/background_sync.mojom",
-    "OneShotBackgroundSyncService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/origin_trial_state/origin_trial_state_host.mojom",
-    "OriginTrialStateHost",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/peerconnection/peer_connection_tracker.mojom",
-    "PeerConnectionTrackerHost",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/background_sync/background_sync.mojom",
-    "PeriodicBackgroundSyncService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/permissions/permission.mojom",
-    "PermissionService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/picture_in_picture/picture_in_picture.mojom",
-    "PictureInPictureService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/presentation/presentation.mojom",
-    "PresentationService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/push_messaging/push_messaging.mojom",
-    "PushMessaging",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/quota/quota_manager_host.mojom",
-    "QuotaManagerHost",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/render_accessibility.mojom",
-    "RenderAccessibilityHost",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom",
-    "RendererAudioInputStreamFactory",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/media/renderer_audio_output_stream_factory.mojom",
-    "RendererAudioOutputStreamFactory",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/reporting/reporting.mojom",
-    "ReportingServiceProxy",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/serial/serial.mojom",
-    "SerialService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/worker/shared_worker_connector.mojom",
-    "SharedWorkerConnector",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/speculation_rules/speculation_rules.mojom",
-    "SpeculationHost",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/speech/speech_recognizer.mojom",
-    "SpeechRecognizer",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/speech/speech_synthesis.mojom",
-    "SpeechSynthesis",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/storage_access/storage_access_handle.mojom",
-    "StorageAccessHandle",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/input/input_host.mojom",
-    "TextSuggestionHost",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/wake_lock/wake_lock.mojom",
-    "WakeLockService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/bluetooth/web_bluetooth.mojom",
-    "WebBluetoothService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/sms/webotp_service.mojom",
-    "WebOTPService",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/sensor/web_sensor_provider.mojom",
-    "WebSensorProvider",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/websockets/websocket_connector.mojom",
-    "WebSocketConnector",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/webtransport/web_transport_connector.mojom",
-    "WebTransportConnector",
-    "Remote",
-  ],
-  [
-    "//third_party/blink/public/mojom/usb/web_usb_service.mojom",
-    "WebUsbService",
-    "Remote",
-  ],
-]
diff --git a/chrome/test/fuzzing/renderer_fuzzing/renderer_in_process_mojolpm_fuzzer.cc b/chrome/test/fuzzing/renderer_fuzzing/renderer_in_process_mojolpm_fuzzer.cc
index cb24c92..8b8ef0c 100644
--- a/chrome/test/fuzzing/renderer_fuzzing/renderer_in_process_mojolpm_fuzzer.cc
+++ b/chrome/test/fuzzing/renderer_fuzzing/renderer_in_process_mojolpm_fuzzer.cc
@@ -2,886 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/test/fuzzing/renderer_fuzzing/renderer_in_process_mojolpm_fuzzer.h"
-
-#include "base/base64.h"
 #include "base/functional/bind.h"
-#include "base/memory/weak_ptr.h"
-#include "base/strings/escape.h"
-#include "base/test/bind.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "chrome/test/fuzzing/in_process_proto_fuzzer.h"
 #include "chrome/test/fuzzing/renderer_fuzzing/in_process_renderer_fuzzing.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/test/browser_test_utils.h"
-#include "mojo/public/tools/fuzzers/mojolpm.h"
-#include "testing/libfuzzer/proto/lpm_interface.h"
+#include "chrome/test/fuzzing/renderer_fuzzing/testcase.h"
 #include "testing/libfuzzer/renderer_fuzzing/renderer_fuzzing.h"
-#include "third_party/blink/public/mojom/blob/blob_registry.mojom-mojolpm.h"
-#include "third_party/blink/public/web/web_testing_support.h"
-
-// This class fuzzes mojo interfaces exposed by the browser process to the
-// renderer process using MojoLPM.
-// It runs in the renderer process, and is fed testcases by the fuzzer
-// running in the browser process.
-// It currently uses MojoLPMGenerator in order to remove all the unnecessary
-// boilerplate implied by using MojoLPM.
-class RendererTestcase
-    : public mojolpmgenerator::RendererInProcessMojolpmFuzzerTestcase {
- public:
-  explicit RendererTestcase(
-      std::unique_ptr<ProtoTestcase> testcase,
-      const blink::BrowserInterfaceBrokerProxy* context_interface_broker_proxy,
-      blink::ThreadSafeBrowserInterfaceBrokerProxy*
-          process_interface_broker_proxy);
-  ~RendererTestcase() override;
-
-  scoped_refptr<base::SequencedTaskRunner> GetFuzzerTaskRunner() override;
-  void SetUp(base::OnceClosure done_closure) override;
-  void TearDown(base::OnceClosure done_closure) override;
-  void HandleNewBlobRegistryAction(uint32_t id,
-                                   base::OnceClosure done_closure) override;
-  // At some point, this will be automatically generated. As for now, we want
-  // to try fuzzing a larger part of the IPC surface.
-  void HandleNewAdAuctionServiceAction(uint32_t id,
-                                       base::OnceClosure done_closure) override;
-  void HandleNewAnchorElementInteractionHostAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewAnchorElementMetricsHostAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewAudioContextManagerAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewAuthenticatorAction(uint32_t id,
-                                    base::OnceClosure done_closure) override;
-  void HandleNewBackgroundFetchServiceAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewBlobURLStoreAction(uint32_t id,
-                                   base::OnceClosure done_closure) override;
-  void HandleNewBrowsingTopicsDocumentServiceAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewBucketManagerHostAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewCacheStorageAction(uint32_t id,
-                                   base::OnceClosure done_closure) override;
-  void HandleNewClipboardHostAction(uint32_t id,
-                                    base::OnceClosure done_closure) override;
-  void HandleNewCodeCacheHostAction(uint32_t id,
-                                    base::OnceClosure done_closure) override;
-  void HandleNewColorChooserFactoryAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewContactsManagerAction(uint32_t id,
-                                      base::OnceClosure done_closure) override;
-  void HandleNewContentIndexServiceAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewContentSecurityNotifierAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewCookieStoreAction(uint32_t id,
-                                  base::OnceClosure done_closure) override;
-  void HandleNewCredentialManagerAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewDedicatedWorkerHostFactoryAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewDeviceAPIServiceAction(uint32_t id,
-                                       base::OnceClosure done_closure) override;
-  void HandleNewDevicePostureProviderAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewDigitalIdentityRequestAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewDirectSocketsServiceAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewEyeDropperChooserAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewFeatureObserverAction(uint32_t id,
-                                      base::OnceClosure done_closure) override;
-  void HandleNewFederatedAuthRequestAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewFileChooserAction(uint32_t id,
-                                  base::OnceClosure done_closure) override;
-  void HandleNewFileSystemAccessManagerAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewFileSystemManagerAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewFileUtilitiesHostAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewFontAccessManagerAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewGeolocationServiceAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewHidServiceAction(uint32_t id,
-                                 base::OnceClosure done_closure) override;
-  void HandleNewIDBFactoryAction(uint32_t id,
-                                 base::OnceClosure done_closure) override;
-  void HandleNewIdleManagerAction(uint32_t id,
-                                  base::OnceClosure done_closure) override;
-  void HandleNewInstalledAppProviderAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewKeyboardLockServiceAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewLCPCriticalPathPredictorHostAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewLockManagerAction(uint32_t id,
-                                  base::OnceClosure done_closure) override;
-  void HandleNewManagedConfigurationServiceAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewMediaDevicesDispatcherHostAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewMediaSessionServiceAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewMediaStreamDispatcherHostAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewModelManagerAction(uint32_t id,
-                                   base::OnceClosure done_closure) override;
-  void HandleNewNonAssociatedLocalFrameHostAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewNoStatePrefetchProcessorAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewNotificationServiceAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewOneShotBackgroundSyncServiceAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewOriginTrialStateHostAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewPeerConnectionTrackerHostAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewPeriodicBackgroundSyncServiceAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewPermissionServiceAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewPictureInPictureServiceAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewPresentationServiceAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewPushMessagingAction(uint32_t id,
-                                    base::OnceClosure done_closure) override;
-  void HandleNewQuotaManagerHostAction(uint32_t id,
-                                       base::OnceClosure done_closure) override;
-  void HandleNewRenderAccessibilityHostAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewRendererAudioInputStreamFactoryAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewRendererAudioOutputStreamFactoryAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewReportingServiceProxyAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewSerialServiceAction(uint32_t id,
-                                    base::OnceClosure done_closure) override;
-  void HandleNewSharedWorkerConnectorAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewSpeculationHostAction(uint32_t id,
-                                      base::OnceClosure done_closure) override;
-  void HandleNewSpeechRecognizerAction(uint32_t id,
-                                       base::OnceClosure done_closure) override;
-  void HandleNewSpeechSynthesisAction(uint32_t id,
-                                      base::OnceClosure done_closure) override;
-  void HandleNewStorageAccessHandleAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewTextSuggestionHostAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewWakeLockServiceAction(uint32_t id,
-                                      base::OnceClosure done_closure) override;
-  void HandleNewWebBluetoothServiceAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewWebOTPServiceAction(uint32_t id,
-                                    base::OnceClosure done_closure) override;
-  void HandleNewWebSensorProviderAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewWebSocketConnectorAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewWebTransportConnectorAction(
-      uint32_t id,
-      base::OnceClosure done_closure) override;
-  void HandleNewWebUsbServiceAction(uint32_t id,
-                                    base::OnceClosure done_closure) override;
-
- private:
-  void SetUpOnFuzzerThread(base::OnceClosure done_closure);
-  void TearDownOnFuzzerThread(base::OnceClosure done_closure);
-
-  template <typename T>
-  void NewProcessInterface(uint32_t id, base::OnceClosure done_closure);
-  template <typename T>
-  void NewContextInterface(uint32_t id, base::OnceClosure done_closure);
-
-  // This is different to the "normal" MojoLPM testcase model, since we need
-  // to also own the lifetime of the protobuf object, when it's normally owned
-  // by libfuzzer.
-  std::unique_ptr<ProtoTestcase> proto_testcase_ptr_;
-
-  // Bindings
-  [[maybe_unused]] raw_ptr<const blink::BrowserInterfaceBrokerProxy>
-      context_interface_broker_proxy_;
-  [[maybe_unused]] raw_ptr<blink::ThreadSafeBrowserInterfaceBrokerProxy>
-      process_interface_broker_proxy_;
-
-  SEQUENCE_CHECKER(sequence_checker_);
-};
-
-namespace {
-
-scoped_refptr<base::SequencedTaskRunner> GetFuzzerTaskRunnerImpl() {
-  // XXX: This should be main thread? IO thread? Probably doesn't
-  // actually matter.
-  static scoped_refptr<base::SequencedTaskRunner> fuzzer_task_runner =
-      base::SequencedTaskRunner::GetCurrentDefault();
-  return fuzzer_task_runner;
-}
-
-}  // anonymous namespace
-
-void RendererTestcase::HandleNewBlobRegistryAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewProcessInterface<::blink::mojom::BlobRegistry>(id,
-                                                    std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewAdAuctionServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::AdAuctionService>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewAnchorElementInteractionHostAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::AnchorElementInteractionHost>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewAnchorElementMetricsHostAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::AnchorElementMetricsHost>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewAudioContextManagerAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::AudioContextManager>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewAuthenticatorAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::Authenticator>(id,
-                                                     std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewBackgroundFetchServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::BackgroundFetchService>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewBlobURLStoreAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::BlobURLStore>(id,
-                                                    std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewBrowsingTopicsDocumentServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::BrowsingTopicsDocumentService>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewBucketManagerHostAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::BucketManagerHost>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewCacheStorageAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::CacheStorage>(id,
-                                                    std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewClipboardHostAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::ClipboardHost>(id,
-                                                     std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewCodeCacheHostAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::CodeCacheHost>(id,
-                                                     std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewColorChooserFactoryAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::ColorChooserFactory>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewContactsManagerAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::ContactsManager>(id,
-                                                       std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewContentIndexServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::ContentIndexService>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewContentSecurityNotifierAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::ContentSecurityNotifier>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewCookieStoreAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::CookieStore>(id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewCredentialManagerAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::CredentialManager>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewDedicatedWorkerHostFactoryAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::DedicatedWorkerHostFactory>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewDeviceAPIServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::DeviceAPIService>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewDevicePostureProviderAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::DevicePostureProvider>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewDigitalIdentityRequestAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::DigitalIdentityRequest>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewDirectSocketsServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::DirectSocketsService>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewEyeDropperChooserAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::EyeDropperChooser>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewFeatureObserverAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::FeatureObserver>(id,
-                                                       std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewFederatedAuthRequestAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::FederatedAuthRequest>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewFileChooserAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::FileChooser>(id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewFileSystemAccessManagerAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::FileSystemAccessManager>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewFileSystemManagerAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::FileSystemManager>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewFileUtilitiesHostAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::FileUtilitiesHost>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewFontAccessManagerAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::FontAccessManager>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewGeolocationServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::GeolocationService>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewHidServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::HidService>(id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewIDBFactoryAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::IDBFactory>(id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewIdleManagerAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::IdleManager>(id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewInstalledAppProviderAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::InstalledAppProvider>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewKeyboardLockServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::KeyboardLockService>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewLockManagerAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::LockManager>(id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewLCPCriticalPathPredictorHostAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::LCPCriticalPathPredictorHost>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewManagedConfigurationServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::ManagedConfigurationService>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewMediaDevicesDispatcherHostAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::MediaDevicesDispatcherHost>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewMediaSessionServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::MediaSessionService>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewMediaStreamDispatcherHostAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::MediaStreamDispatcherHost>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewModelManagerAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::ModelManager>(id,
-                                                    std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewNonAssociatedLocalFrameHostAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::NonAssociatedLocalFrameHost>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewNoStatePrefetchProcessorAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::NoStatePrefetchProcessor>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewNotificationServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::NotificationService>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewOneShotBackgroundSyncServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::OneShotBackgroundSyncService>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewOriginTrialStateHostAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::OriginTrialStateHost>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewPeerConnectionTrackerHostAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::PeerConnectionTrackerHost>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewPeriodicBackgroundSyncServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::PeriodicBackgroundSyncService>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewPermissionServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::PermissionService>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewPictureInPictureServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::PictureInPictureService>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewPresentationServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::PresentationService>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewPushMessagingAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::PushMessaging>(id,
-                                                     std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewQuotaManagerHostAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::QuotaManagerHost>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewRenderAccessibilityHostAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::RenderAccessibilityHost>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewRendererAudioInputStreamFactoryAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::RendererAudioInputStreamFactory>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewRendererAudioOutputStreamFactoryAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::RendererAudioOutputStreamFactory>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewReportingServiceProxyAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::ReportingServiceProxy>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewSerialServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::SerialService>(id,
-                                                     std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewSharedWorkerConnectorAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::SharedWorkerConnector>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewSpeculationHostAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::SpeculationHost>(id,
-                                                       std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewSpeechRecognizerAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::SpeechRecognizer>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewSpeechSynthesisAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::SpeechSynthesis>(id,
-                                                       std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewStorageAccessHandleAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::StorageAccessHandle>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewTextSuggestionHostAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::TextSuggestionHost>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewWakeLockServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::WakeLockService>(id,
-                                                       std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewWebBluetoothServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::WebBluetoothService>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewWebOTPServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::WebOTPService>(id,
-                                                     std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewWebSensorProviderAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::WebSensorProvider>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewWebSocketConnectorAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::WebSocketConnector>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewWebTransportConnectorAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::WebTransportConnector>(
-      id, std::move(done_closure));
-}
-
-void RendererTestcase::HandleNewWebUsbServiceAction(
-    uint32_t id,
-    base::OnceClosure done_closure) {
-  NewContextInterface<::blink::mojom::WebUsbService>(id,
-                                                     std::move(done_closure));
-}
-
-scoped_refptr<base::SequencedTaskRunner>
-RendererTestcase::GetFuzzerTaskRunner() {
-  return GetFuzzerTaskRunnerImpl();
-}
-
-RendererTestcase::RendererTestcase(
-    std::unique_ptr<ProtoTestcase> testcase,
-    const blink::BrowserInterfaceBrokerProxy* context_interface_broker_proxy,
-    blink::ThreadSafeBrowserInterfaceBrokerProxy*
-        process_interface_broker_proxy)
-    : mojolpmgenerator::RendererInProcessMojolpmFuzzerTestcase(*testcase.get()),
-      proto_testcase_ptr_(std::move(testcase)),
-      context_interface_broker_proxy_(context_interface_broker_proxy),
-      process_interface_broker_proxy_(process_interface_broker_proxy) {
-  // RendererTestcase is created on the main thread, but the actions that
-  // we want to validate the sequencing of take place on the fuzzer sequence.
-  DETACH_FROM_SEQUENCE(sequence_checker_);
-}
-
-RendererTestcase::~RendererTestcase() {}
-
-void RendererTestcase::SetUp(base::OnceClosure done_closure) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  GetFuzzerTaskRunner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&RendererTestcase::SetUpOnFuzzerThread,
-                     base::Unretained(this), std::move(done_closure)));
-}
-
-void RendererTestcase::TearDown(base::OnceClosure done_closure) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  GetFuzzerTaskRunner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&RendererTestcase::TearDownOnFuzzerThread,
-                     base::Unretained(this), std::move(done_closure)));
-}
-
-void RendererTestcase::SetUpOnFuzzerThread(base::OnceClosure done_closure) {
-  mojolpm::GetContext()->StartTestcase();
-
-  std::move(done_closure).Run();
-}
-
-void RendererTestcase::TearDownOnFuzzerThread(base::OnceClosure done_closure) {
-  mojolpm::GetContext()->EndTestcase();
-
-  std::move(done_closure).Run();
-}
-
-template <typename T>
-void RendererTestcase::NewProcessInterface(uint32_t id,
-                                           base::OnceClosure done_closure) {
-  mojo::Remote<T> remote;
-  mojo::GenericPendingReceiver receiver = remote.BindNewPipeAndPassReceiver();
-
-  process_interface_broker_proxy_->GetInterface(std::move(receiver));
-  CHECK(remote.is_bound() && remote.is_connected());
-
-  mojolpm::GetContext()->AddInstance(id, std::move(remote));
-
-  std::move(done_closure).Run();
-}
-
-template <typename T>
-void RendererTestcase::NewContextInterface(uint32_t id,
-                                           base::OnceClosure done_closure) {
-  mojo::Remote<T> remote;
-  mojo::GenericPendingReceiver receiver = remote.BindNewPipeAndPassReceiver();
-
-  context_interface_broker_proxy_->GetInterface(std::move(receiver));
-  CHECK(remote.is_bound() && remote.is_connected());
-
-  mojolpm::GetContext()->AddInstance(id, std::move(remote));
-
-  std::move(done_closure).Run();
-}
 
 // `RendererFuzzingAdapter` will be allocated by the internal renderer fuzzing
 // mechanism. It is statically allocated, and will remain alive until the
 // fuzzing process shuts down.
-// Unfortunately, we cannot merge this class with `RendererTestcase`, because
-// the latter needs to have a different lifetime. Indeed, it needs to be
-// recreated for every fuzzing iteration, so that MojoLPM remains deterministic
-// across runs for a given testcase.
+// This interacts with the generated RendererTestcase MojoLPM fuzzer.
 class RendererFuzzingAdapter : public RendererFuzzerBase {
  public:
   using FuzzCase = RendererTestcase::ProtoTestcase;
@@ -899,11 +28,11 @@
           std::move(proto_testcase_ptr), context_interface_broker_proxy,
           process_interface_broker_proxy);
 
-      GetFuzzerTaskRunnerImpl()->PostTask(
+      ptr->GetFuzzerTaskRunner()->PostTask(
           FROM_HERE,
           base::BindOnce(
               &mojolpm::RunTestcase<RendererTestcase>,
-              base::Unretained(ptr.get()), GetFuzzerTaskRunnerImpl(),
+              base::Unretained(ptr.get()), ptr->GetFuzzerTaskRunner(),
               std::move(done_closure)
                   .Then(base::OnceClosure(
                       base::DoNothingWithBoundArgs(std::move(ptr))))));
diff --git a/chromeos/ash/services/cros_healthd/public/mojom/cros_healthd_routines.mojom b/chromeos/ash/services/cros_healthd/public/mojom/cros_healthd_routines.mojom
index 6ffd0e0..67ee9c4 100644
--- a/chromeos/ash/services/cros_healthd/public/mojom/cros_healthd_routines.mojom
+++ b/chromeos/ash/services/cros_healthd/public/mojom/cros_healthd_routines.mojom
@@ -330,7 +330,7 @@
   mojo_base.mojom.TimeDelta? exec_duration@0;
 };
 
-// This routine checks the network bandwidth and report the speed info.
+// This routine checks the network bandwidth and reports the speed info.
 //
 // NextMinVersion: 1, NextIndex: 0
 [Stable]
@@ -450,7 +450,7 @@
   };
   Type type@0;
 
-  // The current network speed in Kbps.
+  // The current network speed in kbit/s.
   double speed_kbps@1;
 };
 
@@ -947,8 +947,8 @@
 // NextMinVersion: 1, NextIndex: 2
 [Stable]
 struct NetworkBandwidthRoutineDetail {
-  // Average download speed in Kbit/s.
+  // Average download speed in kbit/s.
   double download_speed_kbps@0;
-  // Average upload speed in Kbit/s.
+  // Average upload speed in kbit/s.
   double upload_speed_kbps@1;
 };
diff --git a/chromeos/crosapi/mojom/crosapi.mojom b/chromeos/crosapi/mojom/crosapi.mojom
index bfc5c7f..fbd5a6e 100644
--- a/chromeos/crosapi/mojom/crosapi.mojom
+++ b/chromeos/crosapi/mojom/crosapi.mojom
@@ -1807,7 +1807,7 @@
  RenamedFrom="crosapi.mojom.LacrosChromeService"]
 interface BrowserService {
   // Removed method. No longer used.
-  REMOVED_0@0() => (pending_receiver<Crosapi> receiver);
+  REMOVED_0@0();
   REMOVED_2@2(BrowserInitParams params);
 
   // Opens a new window in the browser with the profile that matches
diff --git a/chromeos/crosapi/mojom/telemetry_diagnostic_routine_service.mojom b/chromeos/crosapi/mojom/telemetry_diagnostic_routine_service.mojom
index 3d2dfee..9892cba 100644
--- a/chromeos/crosapi/mojom/telemetry_diagnostic_routine_service.mojom
+++ b/chromeos/crosapi/mojom/telemetry_diagnostic_routine_service.mojom
@@ -128,9 +128,15 @@
   TelemetryDiagnosticLedColor color@1;
 };
 
+// This routine checks the network bandwidth and reports the speed info.
+//
+// NextMinVersion: 1, NextIndex: 0
+[Stable]
+struct TelemetryDiagnosticNetworkBandwidthRoutineArgument {};
+
 // Argument types for the possible routines the routine control API can create.
 //
-// NextMinVersion: 5, NextIndex: 5
+// NextMinVersion: 6, NextIndex: 6
 [Stable, Extensible]
 union TelemetryDiagnosticRoutineArgument {
   // Default field is required by extensible unions for backward compatibility.
@@ -144,6 +150,9 @@
   [MinVersion=3] TelemetryDiagnosticFanRoutineArgument fan@3;
   // Arguments to create a LED lit up routine.
   [MinVersion=4] TelemetryDiagnosticLedLitUpRoutineArgument led_lit_up@4;
+  // Arguments to create a network bandwidth routine.
+  [MinVersion=5]
+  TelemetryDiagnosticNetworkBandwidthRoutineArgument network_bandwidth@5;
 };
 
 // Routine has been initialized but not yet started.
@@ -152,11 +161,48 @@
 [Stable]
 struct TelemetryDiagnosticRoutineStateInitialized {};
 
+// Running info regarding network bandwidth routine.
+//
+// NextMinVersion: 1, NextIndex: 2
+[Stable]
+struct TelemetryDiagnosticNetworkBandwidthRoutineRunningInfo {
+  // The type of test that routine is running.
+  //
+  // NextMinVersion: 1, NextIndex: 3
+  [Stable, Extensible]
+  enum Type {
+    [Default] kUnmappedEnumField = 0,
+    // Routine is running download test.
+    kDownload = 1,
+    // Routine is running upload test.
+    kUpload = 2,
+  };
+  Type type@0;
+
+  // The current network speed in kbit/s.
+  double speed_kbps@1;
+};
+
+// Routine running info. Note that not every routine provides info during the
+// running state.
+//
+// NextMinVersion: 1, NextIndex: 2
+[Stable]
+union TelemetryDiagnosticRoutineRunningInfo {
+  // Default field is required by extensible unions for backward compatibility.
+  // Any unrecognized Mojo field will deserialize to this field. Don't use this.
+  [Default] bool unrecognizedArgument @0;
+  // Running info of network bandwidth routine.
+  TelemetryDiagnosticNetworkBandwidthRoutineRunningInfo network_bandwidth@1;
+};
+
 // Routine is currently running.
 //
-// NextMinVersion: 1, NextIndex: 0
+// NextMinVersion: 2, NextIndex: 1
 [Stable]
-struct TelemetryDiagnosticRoutineStateRunning {};
+struct TelemetryDiagnosticRoutineStateRunning {
+  [MinVersion=1] TelemetryDiagnosticRoutineRunningInfo? info@0;
+};
 
 // Details to reply to a routine requesting to check the LED lit up state.
 //
@@ -378,9 +424,20 @@
   TelemetryDiagnosticHardwarePresenceStatus fan_count_status@2;
 };
 
+// Details regarding network bandwidth routine.
+//
+// NextMinVersion: 1, NextIndex: 2
+[Stable]
+struct TelemetryDiagnosticNetworkBandwidthRoutineDetail {
+  // Average download speed in kbit/s.
+  double download_speed_kbps@0;
+  // Average upload speed in kbit/s.
+  double upload_speed_kbps@1;
+};
+
 // Details about a finished routine.
 //
-// NextMinVersion: 4, NextIndex: 4
+// NextMinVersion: 5, NextIndex: 5
 [Stable, Extensible]
 union TelemetryDiagnosticRoutineDetail {
   // Default field is required by extensible unions for backward compatibility.
@@ -392,6 +449,9 @@
   [MinVersion=2] TelemetryDiagnosticVolumeButtonRoutineDetail volume_button@2;
   // Details of a completed fan routine.
   [MinVersion=3] TelemetryDiagnosticFanRoutineDetail fan@3;
+  // Details of a completed network bandwidth routine.
+  [MinVersion=4]
+  TelemetryDiagnosticNetworkBandwidthRoutineDetail network_bandwidth@4;
 };
 
 // Information about a finished routine.
diff --git a/clank b/clank
index 682118a..2d1d020 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 682118afe56ac594ac2a4343274a9bed1dac8710
+Subproject commit 2d1d020843dabd7ef41ae7a261f81b381281dbf4
diff --git a/components/autofill/content/renderer/autofill_agent_browsertest.cc b/components/autofill/content/renderer/autofill_agent_browsertest.cc
index a1c49bc..d021f3b 100644
--- a/components/autofill/content/renderer/autofill_agent_browsertest.cc
+++ b/components/autofill/content/renderer/autofill_agent_browsertest.cc
@@ -663,7 +663,7 @@
   ASSERT_FALSE(field.IsNull());
 
   std::u16string prior_value = form.fields[0].value;
-  form.fields[0].value += u"AUTOFILLED";
+  form.fields[0].value = form.fields[0].value + u"AUTOFILLED";
   form.fields[0].is_autofilled = true;
 
   ASSERT_EQ(field.GetAutofillState(), blink::WebAutofillState::kNotFilled);
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 2bf5c73..194c70f4 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -360,6 +360,8 @@
     "metrics/payments/wallet_usage_data_metrics.h",
     "metrics/placeholder_metrics.cc",
     "metrics/placeholder_metrics.h",
+    "metrics/profile_deduplication_metrics.cc",
+    "metrics/profile_deduplication_metrics.h",
     "metrics/profile_import_metrics.cc",
     "metrics/profile_import_metrics.h",
     "metrics/profile_token_quality_metrics.cc",
diff --git a/components/autofill/core/browser/address_data_manager.cc b/components/autofill/core/browser/address_data_manager.cc
index 9f5d3da..492a1d20 100644
--- a/components/autofill/core/browser/address_data_manager.cc
+++ b/components/autofill/core/browser/address_data_manager.cc
@@ -13,6 +13,7 @@
 #include "base/ranges/algorithm.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/geo/country_data.h"
+#include "components/autofill/core/browser/metrics/profile_deduplication_metrics.h"
 #include "components/autofill/core/browser/metrics/profile_token_quality_metrics.h"
 #include "components/autofill/core/browser/metrics/stored_profile_metrics.h"
 #include "components/autofill/core/browser/webdata/addresses/contact_info_precondition_checker.h"
@@ -530,6 +531,20 @@
   return prefs::IsAutofillProfileEnabled(pref_service_);
 }
 
+bool AddressDataManager::IsSyncFeatureEnabledForAutofill() const {
+  // TODO(crbug.com/40066949): Remove this method in favor of
+  // `IsUserSelectableTypeEnabled` once ConsentLevel::kSync and
+  // SyncService::IsSyncFeatureEnabled() are deleted from the codebase.
+  return sync_service_ != nullptr && sync_service_->IsSyncFeatureEnabled() &&
+         IsAutofillUserSelectableTypeEnabled();
+}
+
+bool AddressDataManager::IsAutofillUserSelectableTypeEnabled() const {
+  return sync_service_ != nullptr &&
+         sync_service_->GetUserSettings()->GetSelectedTypes().Has(
+             syncer::UserSelectableType::kAutofill);
+}
+
 void AddressDataManager::SetAutofillSelectableTypeEnabled(bool enabled) {
   if (sync_service_ != nullptr) {
     sync_service_->GetUserSettings()->SetSelectedType(
@@ -730,6 +745,10 @@
   const std::vector<AutofillProfile*> profiles = GetProfiles();
   autofill_metrics::LogStoredProfileMetrics(profiles);
   autofill_metrics::LogStoredProfileTokenQualityMetrics(profiles);
+  if (base::FeatureList::IsEnabled(
+          features::kAutofillLogDeduplicationMetrics)) {
+    autofill_metrics::LogDeduplicationStartupMetrics(profiles, app_locale_);
+  }
   autofill_metrics::LogLocalProfileSupersetMetrics(std::move(profiles),
                                                    app_locale_);
 }
diff --git a/components/autofill/core/browser/address_data_manager.h b/components/autofill/core/browser/address_data_manager.h
index 94cddd8a..aabdc3471 100644
--- a/components/autofill/core/browser/address_data_manager.h
+++ b/components/autofill/core/browser/address_data_manager.h
@@ -227,6 +227,15 @@
   // Returns the value of the AutofillProfileEnabled pref.
   virtual bool IsAutofillProfileEnabled() const;
 
+  // Returns true if Sync-the-feature is enabled and
+  // UserSelectableType::kAutofill is among the user's selected data types.
+  // TODO(crbug.com/40066949): Remove this method once ConsentLevel::kSync and
+  // SyncService::IsSyncFeatureEnabled() are deleted from the codebase.
+  bool IsSyncFeatureEnabledForAutofill() const;
+
+  // Returns true if `syncer::UserSelectableType::kAutofill` is enabled.
+  bool IsAutofillUserSelectableTypeEnabled() const;
+
   // Sets the Sync UserSelectableType::kAutofill toggle value.
   // TODO(crbug.com/1502843): Used for the toggle on the Autofill Settings page
   // only. It controls syncing of autofill data stored in user accounts for
diff --git a/components/autofill/core/browser/form_forest.cc b/components/autofill/core/browser/form_forest.cc
index 6ee2d671..ed88395d 100644
--- a/components/autofill/core/browser/form_forest.cc
+++ b/components/autofill/core/browser/form_forest.cc
@@ -601,7 +601,7 @@
 
     renderer_form->fields.push_back(browser_field);
     if (!IsSafeToFill(renderer_form->fields.back())) {
-      renderer_form->fields.back().value.clear();
+      renderer_form->fields.back().value = u"";
     } else {
       result.safe_fields.insert(browser_field.global_id());
     }
diff --git a/components/autofill/core/browser/form_forest_unittest.cc b/components/autofill/core/browser/form_forest_unittest.cc
index bd15709d..96542bf9 100644
--- a/components/autofill/core/browser/form_forest_unittest.cc
+++ b/components/autofill/core/browser/form_forest_unittest.cc
@@ -1544,10 +1544,10 @@
       WithValues(GetMockedForm("child2"), Profile(2))};
   // Clear sensitive fields: the credit card number (field index 2) and CVC
   // (field index 5) in the two main-origin forms.
-  expectation[0].fields[2].value.clear();
-  expectation[0].fields[5].value.clear();
-  expectation[1].fields[2].value.clear();
-  expectation[1].fields[5].value.clear();
+  expectation[0].fields[2].value = u"";
+  expectation[0].fields[5].value = u"";
+  expectation[1].fields[2].value = u"";
+  expectation[1].fields[5].value = u"";
   EXPECT_THAT(GetRendererFormsOfBrowserForm("main", Origin(kIframeUrl),
                                             FieldTypeMap("main")),
               UnorderedArrayEquals(expectation));
diff --git a/components/autofill/core/browser/metrics/profile_deduplication_metrics.cc b/components/autofill/core/browser/metrics/profile_deduplication_metrics.cc
new file mode 100644
index 0000000..aa154b8
--- /dev/null
+++ b/components/autofill/core/browser/metrics/profile_deduplication_metrics.cc
@@ -0,0 +1,54 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/metrics/profile_deduplication_metrics.h"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "base/functional/bind.h"
+#include "base/task/thread_pool.h"
+#include "components/autofill/core/browser/address_data_cleaner.h"
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
+#include "components/autofill/core/browser/data_model/autofill_profile_comparator.h"
+#include "components/autofill/core/browser/field_types.h"
+
+namespace autofill::autofill_metrics {
+
+namespace {
+
+void LogDeduplicationStartupMetricsForProfile(
+    const AutofillProfile& profile,
+    std::vector<FieldTypeSet> min_incompatible_sets) {
+  // TODO(b/325452461): Implement metrics.
+}
+
+}  // namespace
+
+void LogDeduplicationStartupMetrics(
+    const std::vector<AutofillProfile*>& profiles,
+    const std::string& app_locale) {
+  auto log_metrics = [](std::vector<AutofillProfile> profiles,
+                        const std::string& app_locale) {
+    AutofillProfileComparator comparator(app_locale);
+    for (AutofillProfile& profile : profiles) {
+      LogDeduplicationStartupMetricsForProfile(
+          profile, AddressDataCleaner::CalculateMinimalIncompatibleTypeSets(
+                       profile, profiles, comparator));
+    }
+  };
+  // Since computing the metrics is quadratic in `profiles.size()`, it is done
+  // on a background thread. Create a copy of the `profiles`, to avoid passing
+  // pointers between threads.
+  std::vector<AutofillProfile> profiles_copy;
+  for (const AutofillProfile* profile : profiles) {
+    profiles_copy.push_back(*profile);
+  }
+  base::ThreadPool::PostTask(
+      FROM_HERE,
+      base::BindOnce(log_metrics, std::move(profiles_copy), app_locale));
+}
+
+}  // namespace autofill::autofill_metrics
diff --git a/components/autofill/core/browser/metrics/profile_deduplication_metrics.h b/components/autofill/core/browser/metrics/profile_deduplication_metrics.h
new file mode 100644
index 0000000..e606861
--- /dev/null
+++ b/components/autofill/core/browser/metrics/profile_deduplication_metrics.h
@@ -0,0 +1,23 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_METRICS_PROFILE_DEDUPLICATION_METRICS_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_METRICS_PROFILE_DEDUPLICATION_METRICS_H_
+
+#include <string>
+#include <vector>
+
+#include "components/autofill/core/browser/data_model/autofill_profile.h"
+
+namespace autofill::autofill_metrics {
+
+// Logs various metrics around quasi duplicates (= profiles that are duplicates
+// except for a small number of types).
+void LogDeduplicationStartupMetrics(
+    const std::vector<AutofillProfile*>& profiles,
+    const std::string& app_locale);
+
+}  // namespace autofill::autofill_metrics
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_METRICS_PROFILE_DEDUPLICATION_METRICS_H_
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index 3076efd8..f526526 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -444,20 +444,6 @@
   return experiment_country_code_;
 }
 
-bool PersonalDataManager::IsSyncFeatureEnabledForAutofill() const {
-  // TODO(crbug.com/40066949): Remove this method in favor of
-  // `IsUserSelectableTypeEnabled` once ConsentLevel::kSync and
-  // SyncService::IsSyncFeatureEnabled() are deleted from the codebase.
-  return sync_service_ != nullptr && sync_service_->IsSyncFeatureEnabled() &&
-         IsUserSelectableTypeEnabled(syncer::UserSelectableType::kAutofill);
-}
-
-bool PersonalDataManager::IsUserSelectableTypeEnabled(
-    syncer::UserSelectableType type) const {
-  return sync_service_ != nullptr &&
-         sync_service_->GetUserSettings()->GetSelectedTypes().Has(type);
-}
-
 void PersonalDataManager::SetPaymentMethodsMandatoryReauthEnabled(
     bool enabled) {
   payments_data_manager_->SetPaymentMethodsMandatoryReauthEnabled(enabled);
diff --git a/components/autofill/core/browser/personal_data_manager.h b/components/autofill/core/browser/personal_data_manager.h
index dc1efc0..72fa955 100644
--- a/components/autofill/core/browser/personal_data_manager.h
+++ b/components/autofill/core/browser/personal_data_manager.h
@@ -413,15 +413,6 @@
   // database by adding, updating and removing credit cards.
   void SetCreditCards(std::vector<CreditCard>* credit_cards);
 
-  // Returns true if Sync-the-feature is enabled and
-  // UserSelectableType::kAutofill is among the user's selected data types.
-  // TODO(crbug.com/40066949): Remove this method once ConsentLevel::kSync and
-  // SyncService::IsSyncFeatureEnabled() are deleted from the codebase.
-  bool IsSyncFeatureEnabledForAutofill() const;
-
-  // Returns true if the user's selectable `type` is enabled.
-  bool IsUserSelectableTypeEnabled(syncer::UserSelectableType type) const;
-
   // TODO(b/322170538): Deprecated. Use the functions in
   // `payments_data_manager()` instead. Some callers on iOS still rely on this.
   void SetPaymentMethodsMandatoryReauthEnabled(bool enabled);
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index 7db12ea..f4028d6 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -678,6 +678,13 @@
     kAutofillEnableCacheForRegexMatchingCacheSizeParam{
         &kAutofillEnableCacheForRegexMatching, "cache_size", 300};
 
+// When enabled, various deduplication related metrics are logged on startup
+// and on import.
+// TODO(b/325452461): Remove once rolled out.
+BASE_FEATURE(kAutofillLogDeduplicationMetrics,
+             "AutofillLogDeduplicationMetrics",
+             base::FEATURE_DISABLED_BY_DEFAULT);
+
 #if BUILDFLAG(IS_ANDROID)
 // Controls the whether the Chrome may provide a virtual view structure for
 // Android Autofill.
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index 66ac142..27eb8bc 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -220,6 +220,8 @@
 COMPONENT_EXPORT(AUTOFILL)
 extern const base::FeatureParam<int>
     kAutofillEnableCacheForRegexMatchingCacheSizeParam;
+COMPONENT_EXPORT(AUTOFILL)
+BASE_DECLARE_FEATURE(kAutofillLogDeduplicationMetrics);
 
 #if BUILDFLAG(IS_ANDROID)
 COMPONENT_EXPORT(AUTOFILL)
diff --git a/components/autofill/core/common/autofill_test_utils.cc b/components/autofill/core/common/autofill_test_utils.cc
index 7bf087e..facfe8d 100644
--- a/components/autofill/core/common/autofill_test_utils.cc
+++ b/components/autofill/core/common/autofill_test_utils.cc
@@ -106,7 +106,7 @@
 
 FormData WithoutValues(FormData form) {
   for (FormFieldData& field : form.fields) {
-    field.value.clear();
+    field.value = u"";
   }
   return form;
 }
diff --git a/components/autofill/core/common/form_field_data.cc b/components/autofill/core/common/form_field_data.cc
index aaa8ff4f..41fb278 100644
--- a/components/autofill/core/common/form_field_data.cc
+++ b/components/autofill/core/common/form_field_data.cc
@@ -94,14 +94,16 @@
 bool DeserializeSection1(base::PickleIterator* iter,
                          FormFieldData* field_data) {
   std::string form_control_type;
+  std::u16string value;
   bool success = iter->ReadString16(&field_data->label) &&
                  iter->ReadString16(&field_data->name) &&
-                 iter->ReadString16(&field_data->value) &&
+                 iter->ReadString16(&value) &&
                  iter->ReadString(&form_control_type) &&
                  iter->ReadString(&field_data->autocomplete_attribute) &&
                  iter->ReadUInt64(&field_data->max_length) &&
                  iter->ReadBool(&field_data->is_autofilled);
   if (success) {
+    field_data->value = std::move(value);
     // Form control types are serialized as strings for legacy reasons.
     // TODO(crbug.com/1353392,crbug.com/1482526): Why does the Password Manager
     // (de)serialize form control types? Remove it or migrate it to the enum
diff --git a/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc b/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
index 4c3156f..5358defd 100644
--- a/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
+++ b/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
@@ -175,8 +175,11 @@
     return false;
   if (!data.ReadNameAttribute(&out->name_attribute))
     return false;
-  if (!data.ReadValue(&out->value))
+  std::u16string value;
+  if (!data.ReadValue(&value)) {
     return false;
+  }
+  out->value = std::move(value);
   if (!data.ReadSelectedText(&out->selected_text)) {
     return false;
   }
diff --git a/components/gwp_asan/client/sampling_helpers.cc b/components/gwp_asan/client/sampling_helpers.cc
index 84afb30..3c19e55d 100644
--- a/components/gwp_asan/client/sampling_helpers.cc
+++ b/components/gwp_asan/client/sampling_helpers.cc
@@ -67,6 +67,9 @@
     return base::DoNothing();
   }
 
+  // N.B. we call `FactoryGet()` here to avoid doing it inside the
+  // callback body, which could result in re-entrancy issues.
+  // See https://crbug.com/331729344 for details.
   const std::string histogram_name =
       base::StrCat({"Security.GwpAsan.AllocatorOom.", allocator_name, ".",
                     process_str.value()});
diff --git a/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc b/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc
index e8de949..ab9f085 100644
--- a/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc
+++ b/components/page_load_metrics/browser/observers/use_counter/ukm_features.cc
@@ -293,9 +293,6 @@
           WebFeature::kTopicsAPI_BrowsingTopics_Method,
           WebFeature::kHTMLFencedFrameElement,
           WebFeature::kAuthorizationCrossOrigin,
-          WebFeature::kServiceWorkerBypassFetchHandlerForMainResource,
-          WebFeature::
-              kServiceWorkerBypassFetchHandlerForMainResourceByOriginTrial,
           WebFeature::kCascadedCSSZoomNotEqualToOne,
           WebFeature::kV8Window_QueryLocalFonts_Method,
           WebFeature::kHiddenUntilFoundAttribute,
diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn
index dfa79bcb..91723f6 100644
--- a/components/password_manager/core/browser/BUILD.gn
+++ b/components/password_manager/core/browser/BUILD.gn
@@ -81,6 +81,7 @@
     "password_check_referrer_android.h",
     "password_counter.cc",
     "password_counter.h",
+    "password_cross_domain_confirmation_popup_controller.h",
     "password_feature_manager.h",
     "password_feature_manager_impl.cc",
     "password_feature_manager_impl.h",
diff --git a/components/password_manager/core/browser/features/password_features.cc b/components/password_manager/core/browser/features/password_features.cc
index 9b6466c..0a07525 100644
--- a/components/password_manager/core/browser/features/password_features.cc
+++ b/components/password_manager/core/browser/features/password_features.cc
@@ -168,10 +168,6 @@
              "UsernameFirstFlowFallbackCrowdsourcing",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kUsernameFirstFlowHonorAutocomplete,
-             "UsernameFirstFlowHonorAutocomplete",
-             base::FEATURE_ENABLED_BY_DEFAULT);
-
 BASE_FEATURE(kUsernameFirstFlowStoreSeveralValues,
              "UsernameFirstFlowStoreSeveralValues",
              base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/components/password_manager/core/browser/features/password_features.h b/components/password_manager/core/browser/features/password_features.h
index 3c44058c..696ce75 100644
--- a/components/password_manager/core/browser/features/password_features.h
+++ b/components/password_manager/core/browser/features/password_features.h
@@ -154,10 +154,6 @@
 // we don't need additional signals.
 BASE_DECLARE_FEATURE(kUsernameFirstFlowFallbackCrowdsourcing);
 
-// Enables suggesting username in the save/update prompt in the case of
-// autocomplete="username".
-BASE_DECLARE_FEATURE(kUsernameFirstFlowHonorAutocomplete);
-
 // Enables storing more possible username values in the LRU cache. Part of the
 // `kUsernameFirstFlowWithIntermediateValues` feature.
 BASE_DECLARE_FEATURE(kUsernameFirstFlowStoreSeveralValues);
diff --git a/components/password_manager/core/browser/form_saver_impl.cc b/components/password_manager/core/browser/form_saver_impl.cc
index 5b3e96f..732712b 100644
--- a/components/password_manager/core/browser/form_saver_impl.cc
+++ b/components/password_manager/core/browser/form_saver_impl.cc
@@ -30,7 +30,7 @@
   form->main_frame_origin = url::Origin();
   for (FormFieldData& field : form->fields) {
     field.label.clear();
-    field.value.clear();
+    field.value = u"";
     field.autocomplete_attribute.clear();
     field.options.clear();
     field.placeholder.clear();
diff --git a/components/password_manager/core/browser/password_cross_domain_confirmation_popup_controller.h b/components/password_manager/core/browser/password_cross_domain_confirmation_popup_controller.h
new file mode 100644
index 0000000..ca0d22b
--- /dev/null
+++ b/components/password_manager/core/browser/password_cross_domain_confirmation_popup_controller.h
@@ -0,0 +1,40 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_CROSS_DOMAIN_CONFIRMATION_POPUP_CONTROLLER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_CROSS_DOMAIN_CONFIRMATION_POPUP_CONTROLLER_H_
+
+#include "base/functional/callback_forward.h"
+#include "base/i18n/rtl.h"
+#include "components/autofill/core/browser/ui/popup_hiding_reasons.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "url/gurl.h"
+
+namespace password_manager {
+
+// The controller of the cross domain usage confirmation popup. It provides API
+// to Show/Hide the popup and get the user's decision (via a callback).
+class PasswordCrossDomainConfirmationPopupController {
+ public:
+  virtual ~PasswordCrossDomainConfirmationPopupController() = default;
+
+  virtual void Hide(autofill::PopupHidingReason reason) = 0;
+
+  // Creates and shows a popup pointing to `element_bounds` and presenting
+  // a message regarding cross domain password usage. `domain` is the domain
+  // of the current web site the popup is triggered on. `password_domain` is
+  // the domain of the web site the password was originally stored on.
+  // `confirmation_callback` is called if the user confirms the action, if
+  // the user cancels it, the popup is silently hidden.
+  // If the popup is already shown, it gets hidden and a new one shows up.
+  virtual void Show(const gfx::RectF& element_bounds,
+                    base::i18n::TextDirection text_direction,
+                    const GURL& domain,
+                    const std::u16string& password_origin,
+                    base::OnceClosure confirmation_callback) = 0;
+};
+
+}  // namespace password_manager
+
+#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_CROSS_DOMAIN_CONFIRMATION_POPUP_CONTROLLER_H_
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc
index 415c2e81..9601cb5e 100644
--- a/components/password_manager/core/browser/password_form_manager.cc
+++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -186,9 +186,7 @@
             PasswordFormHadMatchingUsername(true)};
   }
   if (candidate_username.autocomplete_attribute_has_username &&
-      !candidate_username.HasServerPrediction() &&
-      base::FeatureList::IsEnabled(
-          password_manager::features::kUsernameFirstFlowHonorAutocomplete)) {
+      !candidate_username.HasServerPrediction()) {
     return {UsernameFoundOutsideOfFormType::kUsernameAutocomplete,
             PasswordFormHadMatchingUsername(false)};
   }
diff --git a/components/password_manager/core/browser/password_form_manager_unittest.cc b/components/password_manager/core/browser/password_form_manager_unittest.cc
index 22664e7..2400510a 100644
--- a/components/password_manager/core/browser/password_form_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -2006,7 +2006,8 @@
     CreateFormManager(observed_form_);
     form_manager_->PresaveGeneratedPassword(submitted_form.form_data,
                                             submitted_form.password_value);
-    form_data.fields[kPasswordFieldIndex].value += u"1";
+    form_data.fields[kPasswordFieldIndex].value =
+        form_data.fields[kPasswordFieldIndex].value + u"1";
     submitted_form.password_value = form_data.fields[kPasswordFieldIndex].value;
     form_manager_->PresaveGeneratedPassword(submitted_form.form_data,
                                             submitted_form.password_value);
@@ -2021,7 +2022,8 @@
     CreateFormManager(observed_form_);
     form_manager_->PresaveGeneratedPassword(submitted_form.form_data,
                                             submitted_form.password_value);
-    form_data.fields[kPasswordFieldIndex].value += u"2";
+    form_data.fields[kPasswordFieldIndex].value =
+        form_data.fields[kPasswordFieldIndex].value + u"2";
     submitted_form.password_value = form_data.fields[kPasswordFieldIndex].value;
     form_manager_->PresaveGeneratedPassword(submitted_form.form_data,
                                             submitted_form.password_value);
@@ -3596,9 +3598,6 @@
 // Tests that boolean representing autocomplete = "username" is taken into
 // consideration when offering username in prompt in username first flow.
 TEST_P(PasswordFormManagerTest, PossibleUsernameFromAutocomplete) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(
-      features::kUsernameFirstFlowHonorAutocomplete);
 
   // A single password form is loaded on the page.
   FormData submitted_form = observed_form_only_password_fields_;
diff --git a/components/password_manager/core/browser/password_manager_client.h b/components/password_manager/core/browser/password_manager_client.h
index ce3cb5f..eb6e84b 100644
--- a/components/password_manager/core/browser/password_manager_client.h
+++ b/components/password_manager/core/browser/password_manager_client.h
@@ -29,6 +29,14 @@
 #include "components/sync/service/sync_service.h"
 #include "net/cert/cert_status_flags.h"
 
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || \
+    BUILDFLAG(IS_CHROMEOS)
+#include "base/i18n/rtl.h"
+#include "components/password_manager/core/browser/password_cross_domain_confirmation_popup_controller.h"
+#include "ui/gfx/geometry/rect_f.h"
+#endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) ||
+        // BUILDFLAG(IS_CHROMEOS)
+
 class PrefService;
 
 namespace affiliations {
@@ -494,6 +502,18 @@
 
   // Refreshes password manager settings stored in prefs.
   virtual void RefreshPasswordManagerSettingsIfNeeded() const;
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || \
+    BUILDFLAG(IS_CHROMEOS)
+  // Creates and show the cross domain confirmation popup.
+  virtual std::unique_ptr<PasswordCrossDomainConfirmationPopupController>
+  ShowCrossDomainConfirmationPopup(const gfx::RectF& element_bounds,
+                                   base::i18n::TextDirection text_direction,
+                                   const GURL& domain,
+                                   const std::u16string& password_origin,
+                                   base::OnceClosure confirmation_callback) = 0;
+#endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) ||
+        // BUILDFLAG(IS_CHROMEOS)
 };
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc
index af5a431d..5b10439 100644
--- a/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -317,7 +317,7 @@
   form->main_frame_origin = url::Origin();
   for (FormFieldData& field : form->fields) {
     field.label.clear();
-    field.value.clear();
+    field.value = u"";
     field.autocomplete_attribute.clear();
     field.options.clear();
     field.placeholder.clear();
@@ -1340,7 +1340,7 @@
   // The user deletes the password, no manuall fallback should be shown.
   PasswordForm empty_password_form(form);
   empty_password_form.password_value.clear();
-  empty_password_form.form_data.fields[1].value.clear();
+  empty_password_form.form_data.fields[1].value = u"";
   EXPECT_CALL(client_, ShowManualFallbackForSaving).Times(0);
   EXPECT_CALL(client_, HideManualFallbackForSaving);
   manager()->OnInformAboutUserInput(&driver_, empty_password_form.form_data);
@@ -2886,7 +2886,7 @@
   PasswordForm form(MakeFormWithOnlyNewPasswordField());
   form.username_element.clear();
   form.username_value.clear();
-  form.form_data.fields[0].value.clear();
+  form.form_data.fields[0].value = u"";
   std::vector<FormData> observed = {form.form_data};
 
   // Emulate page load.
@@ -2899,7 +2899,7 @@
   OnPasswordFormSubmitted(form.form_data);
 
   // JavaScript cleared field values.
-  observed[0].fields[1].value.clear();
+  observed[0].fields[1].value = u"";
 
   // Check success of the submission.
   std::unique_ptr<PasswordFormManagerForUI> form_manager_to_save;
@@ -2919,7 +2919,7 @@
   std::vector<FormData> observed;
   FormData form_data(MakeSimpleGAIAFormData());
   // Simulate that no username is found.
-  form_data.fields[0].value.clear();
+  form_data.fields[0].value = u"";
   observed.push_back(form_data);
   manager()->OnPasswordFormsRendered(&driver_, observed);
 
@@ -4655,8 +4655,7 @@
   feature_list.InitWithFeatures(
       /*enabled_features=*/
       {password_manager::features::kUsernameFirstFlowStoreSeveralValues,
-       password_manager::features::kUsernameFirstFlowWithIntermediateValues,
-       password_manager::features::kUsernameFirstFlowHonorAutocomplete},
+       password_manager::features::kUsernameFirstFlowWithIntermediateValues},
       /*disabled_features_*/ {});
   // Simulate the user typed a previously not saved username in the username
   // form.
@@ -5282,9 +5281,9 @@
 
     manager()->OnInformAboutUserInput(&driver_, form_data);
 
-    form_data.fields[0].value.clear();
+    form_data.fields[0].value = u"";
     if (new_password_field_was_cleared)
-      form_data.fields[1].value.clear();
+      form_data.fields[1].value = u"";
 
     std::unique_ptr<PasswordFormManagerForUI> form_manager_to_save;
     if (new_password_field_was_cleared) {
diff --git a/components/password_manager/core/browser/stub_password_manager_client.cc b/components/password_manager/core/browser/stub_password_manager_client.cc
index 1c6a6b91..29b1612 100644
--- a/components/password_manager/core/browser/stub_password_manager_client.cc
+++ b/components/password_manager/core/browser/stub_password_manager_client.cc
@@ -174,4 +174,19 @@
   return version_info::Channel::UNKNOWN;
 }
 
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || \
+    BUILDFLAG(IS_CHROMEOS)
+std::unique_ptr<
+    password_manager::PasswordCrossDomainConfirmationPopupController>
+StubPasswordManagerClient::ShowCrossDomainConfirmationPopup(
+    const gfx::RectF& element_bounds,
+    base::i18n::TextDirection text_direction,
+    const GURL& domain,
+    const std::u16string& password_origin,
+    base::OnceClosure confirmation_callback) {
+  return nullptr;
+}
+#endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) ||
+        // BUILDFLAG(IS_CHROMEOS)
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/stub_password_manager_client.h b/components/password_manager/core/browser/stub_password_manager_client.h
index 6562080..6b4acb90 100644
--- a/components/password_manager/core/browser/stub_password_manager_client.h
+++ b/components/password_manager/core/browser/stub_password_manager_client.h
@@ -73,6 +73,18 @@
   const MockPasswordFeatureManager* GetPasswordFeatureManager() const override;
   MockPasswordFeatureManager* GetPasswordFeatureManager();
   version_info::Channel GetChannel() const override;
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || \
+    BUILDFLAG(IS_CHROMEOS)
+  std::unique_ptr<
+      password_manager::PasswordCrossDomainConfirmationPopupController>
+  ShowCrossDomainConfirmationPopup(
+      const gfx::RectF& element_bounds,
+      base::i18n::TextDirection text_direction,
+      const GURL& domain,
+      const std::u16string& password_origin,
+      base::OnceClosure confirmation_callback) override;
+#endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) ||
+        // BUILDFLAG(IS_CHROMEOS)
 
   safe_browsing::PasswordProtectionService* GetPasswordProtectionService()
       const override;
diff --git a/components/plus_addresses/webdata/plus_address_table.cc b/components/plus_addresses/webdata/plus_address_table.cc
index 61579e7..a5f8be46 100644
--- a/components/plus_addresses/webdata/plus_address_table.cc
+++ b/components/plus_addresses/webdata/plus_address_table.cc
@@ -4,6 +4,7 @@
 
 #include "components/plus_addresses/webdata/plus_address_table.h"
 
+#include <optional>
 #include <vector>
 
 #include "base/check_op.h"
@@ -139,6 +140,24 @@
   return result;
 }
 
+std::optional<PlusProfile> PlusAddressTable::GetPlusProfileForId(
+    const std::string& profile_id) const {
+  sql::Statement query(db_->GetUniqueStatement(
+      base::StringPrintf("SELECT %s, %s, %s FROM %s WHERE %s=?", kProfileId,
+                         kFacet, kPlusAddress, kPlusAddressTable, kProfileId)
+          .c_str()));
+  query.BindString(0, profile_id);
+  if (!query.Step()) {
+    return std::nullopt;
+  }
+  return PlusProfile{
+      .profile_id = query.ColumnString(0),
+      .facet = query.ColumnString(1),
+      .plus_address = query.ColumnString(2),
+      .is_confirmed = true,
+  };
+}
+
 bool PlusAddressTable::AddOrUpdatePlusProfile(const PlusProfile& profile) {
   CHECK(profile.is_confirmed);
   sql::Statement query(db_->GetUniqueStatement(
diff --git a/components/plus_addresses/webdata/plus_address_table.h b/components/plus_addresses/webdata/plus_address_table.h
index 44792ea..2ddb00e 100644
--- a/components/plus_addresses/webdata/plus_address_table.h
+++ b/components/plus_addresses/webdata/plus_address_table.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_PLUS_ADDRESSES_WEBDATA_PLUS_ADDRESS_TABLE_H_
 #define COMPONENTS_PLUS_ADDRESSES_WEBDATA_PLUS_ADDRESS_TABLE_H_
 
+#include <optional>
 #include <vector>
 
 #include "components/plus_addresses/plus_address_types.h"
@@ -58,6 +59,11 @@
   // Returns all stored PlusProfiles - or an empty vector if reading fails.
   std::vector<PlusProfile> GetPlusProfiles() const;
 
+  // Returns the profile with the given `profile_id` or std::nullopt if it
+  // doesn't exist.
+  std::optional<PlusProfile> GetPlusProfileForId(
+      const std::string& profile_id) const;
+
   // Adds `profile` to the database, if a profile with the same `profile_id`
   // doesn't already exist. Otherwise, updates the existing `profile`.
   // Returns true if the operation succeeded.
diff --git a/components/plus_addresses/webdata/plus_address_table_unittest.cc b/components/plus_addresses/webdata/plus_address_table_unittest.cc
index 1d6a95c..eaf73e7e 100644
--- a/components/plus_addresses/webdata/plus_address_table_unittest.cc
+++ b/components/plus_addresses/webdata/plus_address_table_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "components/plus_addresses/webdata/plus_address_table.h"
 
+#include <optional>
+
 #include "base/files/scoped_temp_dir.h"
 #include "components/plus_addresses/plus_address_test_utils.h"
 #include "components/plus_addresses/plus_address_types.h"
@@ -49,6 +51,16 @@
               testing::UnorderedElementsAre(profile1, profile2));
 }
 
+TEST_F(PlusAddressTableTest, GetPlusProfileForId) {
+  const PlusProfile profile1 = test::CreatePlusProfile();
+  const PlusProfile profile2 = test::CreatePlusProfile2();
+  ASSERT_TRUE(table_.AddOrUpdatePlusProfile(profile1));
+  ASSERT_TRUE(table_.AddOrUpdatePlusProfile(profile2));
+  EXPECT_EQ(table_.GetPlusProfileForId(profile1.profile_id), profile1);
+  EXPECT_EQ(table_.GetPlusProfileForId(profile2.profile_id), profile2);
+  EXPECT_EQ(table_.GetPlusProfileForId("invalid_id"), std::nullopt);
+}
+
 TEST_F(PlusAddressTableTest, AddOrUpdatePlusProfile) {
   PlusProfile profile1 = test::CreatePlusProfile();
   PlusProfile profile2 = test::CreatePlusProfile2();
diff --git a/components/signin/public/identity_manager/account_info.cc b/components/signin/public/identity_manager/account_info.cc
index 9532067..6b89fe7 100644
--- a/components/signin/public/identity_manager/account_info.cc
+++ b/components/signin/public/identity_manager/account_info.cc
@@ -183,7 +183,7 @@
 base::android::ScopedJavaLocalRef<jobject> ConvertToJavaCoreAccountInfo(
     JNIEnv* env,
     const CoreAccountInfo& account_info) {
-  DCHECK(!account_info.IsEmpty());
+  CHECK(!account_info.IsEmpty());
   return signin::Java_CoreAccountInfo_Constructor(
       env, ConvertToJavaCoreAccountId(env, account_info.account_id),
       base::android::ConvertUTF8ToJavaString(env, account_info.email),
@@ -193,7 +193,7 @@
 base::android::ScopedJavaLocalRef<jobject> ConvertToJavaAccountInfo(
     JNIEnv* env,
     const AccountInfo& account_info) {
-  DCHECK(!account_info.IsEmpty());
+  CHECK(!account_info.IsEmpty());
   gfx::Image avatar_image = account_info.account_image;
   return signin::Java_AccountInfo_Constructor(
       env, ConvertToJavaCoreAccountId(env, account_info.account_id),
@@ -210,7 +210,7 @@
 base::android::ScopedJavaLocalRef<jobject> ConvertToJavaCoreAccountId(
     JNIEnv* env,
     const CoreAccountId& account_id) {
-  DCHECK(!account_id.empty());
+  CHECK(!account_id.empty());
   return signin::Java_CoreAccountId_Constructor(
       env, base::android::ConvertUTF8ToJavaString(env, account_id.ToString()));
 }
@@ -218,7 +218,7 @@
 CoreAccountInfo ConvertFromJavaCoreAccountInfo(
     JNIEnv* env,
     const base::android::JavaRef<jobject>& j_core_account_info) {
-  DCHECK(j_core_account_info);
+  CHECK(j_core_account_info);
   CoreAccountInfo account;
   account.account_id = ConvertFromJavaCoreAccountId(
       env, signin::Java_CoreAccountInfo_getId(env, j_core_account_info));
@@ -232,7 +232,7 @@
 CoreAccountId ConvertFromJavaCoreAccountId(
     JNIEnv* env,
     const base::android::JavaRef<jobject>& j_core_account_id) {
-  DCHECK(j_core_account_id);
+  CHECK(j_core_account_id);
   CoreAccountId id =
       CoreAccountId::FromString(base::android::ConvertJavaStringToUTF8(
           signin::Java_CoreAccountId_getId(env, j_core_account_id)));
diff --git a/components/sync/base/features.cc b/components/sync/base/features.cc
index 720c774..4eedefa 100644
--- a/components/sync/base/features.cc
+++ b/components/sync/base/features.cc
@@ -211,7 +211,7 @@
 #if BUILDFLAG(IS_ANDROID)
 BASE_FEATURE(kSyncShowIdentityErrorsForSignedInUsers,
              "SyncShowIdentityErrorsForSignedInUsers",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 #endif  // BUILDFLAG(IS_ANDROID)
 
 BASE_FEATURE(kSyncRememberCustomPassphraseAfterSignout,
diff --git a/components/web_package/DEPS b/components/web_package/DEPS
index 682d8ff..e2e6e32 100644
--- a/components/web_package/DEPS
+++ b/components/web_package/DEPS
@@ -10,7 +10,7 @@
   "web_bundle_parser_fuzzer\.cc": [
     "+mojo/core/embedder/embedder.h",
   ],
-  "(web_bundle_signer|signed_web_bundle_signature_verifier).cc": [
+  "(web_bundle_signer|signed_web_bundle_signature_verifier|signed_web_bundle_id).cc": [
     "+crypto",
   ],
   "(integrity_block_parser|ed25519_public_key|ed25519_signature|web_bundle_parser_unittest|web_bundle_signer|signed_web_bundle_signature_verifier)\.cc": [
diff --git a/components/web_package/signed_web_bundles/signed_web_bundle_id.cc b/components/web_package/signed_web_bundles/signed_web_bundle_id.cc
index 7d1dada8..a157689 100644
--- a/components/web_package/signed_web_bundles/signed_web_bundle_id.cc
+++ b/components/web_package/signed_web_bundles/signed_web_bundle_id.cc
@@ -8,13 +8,13 @@
 
 #include "base/containers/span.h"
 #include "base/functional/bind.h"
-#include "base/rand_util.h"
 #include "base/ranges/algorithm.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/types/expected.h"
 #include "components/base32/base32.h"
+#include "crypto/random.h"
 
 namespace web_package {
 
@@ -48,12 +48,10 @@
   auto decoded_span = base::make_span(decoded_id);
   auto type_suffix = decoded_span.last<kTypeSuffixLength>();
   if (base::ranges::equal(type_suffix, kTypeDevelopment)) {
-    return SignedWebBundleId(Type::kDevelopment, encoded_id,
-                             decoded_span.first<kDecodedIdLength>());
+    return SignedWebBundleId(Type::kDevelopment, encoded_id);
   }
   if (base::ranges::equal(type_suffix, kTypeEd25519PublicKey)) {
-    return SignedWebBundleId(Type::kEd25519PublicKey, encoded_id,
-                             decoded_span.first<kDecodedIdLength>());
+    return SignedWebBundleId(Type::kEd25519PublicKey, encoded_id);
   }
   return base::unexpected("The signed web bundle ID has an unknown type.");
 }
@@ -69,7 +67,7 @@
   auto encoded_id_uppercase = base32::Base32Encode(
       decoded_id, base32::Base32EncodePolicy::OMIT_PADDING);
   auto encoded_id = base::ToLowerASCII(encoded_id_uppercase);
-  return SignedWebBundleId(Type::kEd25519PublicKey, encoded_id, decoded_id);
+  return SignedWebBundleId(Type::kEd25519PublicKey, encoded_id);
 }
 
 // static
@@ -82,24 +80,18 @@
   auto encoded_id_uppercase = base32::Base32Encode(
       decoded_id, base32::Base32EncodePolicy::OMIT_PADDING);
   auto encoded_id = base::ToLowerASCII(encoded_id_uppercase);
-  return SignedWebBundleId(Type::kDevelopment, encoded_id, decoded_id);
+  return SignedWebBundleId(Type::kDevelopment, encoded_id);
 }
 
 // static
-SignedWebBundleId SignedWebBundleId::CreateRandomForDevelopment(
-    base::RepeatingCallback<void(base::span<uint8_t>)> random_generator) {
+SignedWebBundleId SignedWebBundleId::CreateRandomForDevelopment() {
   std::array<uint8_t, kDecodedIdLength - kTypeSuffixLength> random_bytes;
-  random_generator.Run(random_bytes);
+  crypto::RandBytes(random_bytes);
   return CreateForDevelopment(random_bytes);
 }
 
-SignedWebBundleId::SignedWebBundleId(
-    Type type,
-    base::StringPiece encoded_id,
-    base::span<const uint8_t, kDecodedIdLength> decoded_id)
-    : type_(type), encoded_id_(encoded_id) {
-  base::ranges::copy(decoded_id, decoded_id_.begin());
-}
+SignedWebBundleId::SignedWebBundleId(Type type, base::StringPiece encoded_id)
+    : type_(type), encoded_id_(encoded_id) {}
 
 SignedWebBundleId::SignedWebBundleId(const SignedWebBundleId& other) = default;
 SignedWebBundleId& SignedWebBundleId::operator=(
@@ -111,13 +103,4 @@
   return os << id.id();
 }
 
-// static
-base::RepeatingCallback<void(base::span<uint8_t>)>
-SignedWebBundleId::GetDefaultRandomGenerator() {
-  // TODO(crbug.com/1490484): Remove the static_cast once all callers of
-  // base::RandBytes are migrated to the span variant.
-  return base::BindRepeating(
-      static_cast<void (*)(base::span<uint8_t>)>(&base::RandBytes));
-}
-
 }  // namespace web_package
diff --git a/components/web_package/signed_web_bundles/signed_web_bundle_id.h b/components/web_package/signed_web_bundles/signed_web_bundle_id.h
index 418a1b10..f311585 100644
--- a/components/web_package/signed_web_bundles/signed_web_bundle_id.h
+++ b/components/web_package/signed_web_bundles/signed_web_bundle_id.h
@@ -57,9 +57,7 @@
   static SignedWebBundleId CreateForDevelopment(
       base::span<const uint8_t, kDecodedIdLength - kTypeSuffixLength> data);
 
-  static SignedWebBundleId CreateRandomForDevelopment(
-      base::RepeatingCallback<void(base::span<uint8_t>)> random_generator =
-          GetDefaultRandomGenerator());
+  static SignedWebBundleId CreateRandomForDevelopment();
 
   SignedWebBundleId(const SignedWebBundleId& other);
   SignedWebBundleId& operator=(const SignedWebBundleId& other);
@@ -70,32 +68,16 @@
 
   const std::string& id() const { return encoded_id_; }
 
-  bool operator<(const SignedWebBundleId& other) const {
-    return decoded_id_ < other.decoded_id_;
-  }
-
-  bool operator==(const SignedWebBundleId& other) const {
-    return decoded_id_ == other.decoded_id_;
-  }
-
-  bool operator!=(const SignedWebBundleId& other) const {
-    return !(*this == other);
-  }
+  auto operator<=>(const SignedWebBundleId&) const = default;
 
   friend std::ostream& operator<<(std::ostream& os,
                                   const SignedWebBundleId& id);
 
  private:
-  SignedWebBundleId(Type type,
-                    base::StringPiece encoded_id,
-                    base::span<const uint8_t, kDecodedIdLength> decoded_id);
+  SignedWebBundleId(Type type, base::StringPiece encoded_id);
 
   Type type_;
   std::string encoded_id_;
-  std::array<uint8_t, kDecodedIdLength> decoded_id_;
-
-  static base::RepeatingCallback<void(base::span<uint8_t>)>
-  GetDefaultRandomGenerator();
 };
 
 }  // namespace web_package
diff --git a/components/web_package/signed_web_bundles/signed_web_bundle_id_unittest.cc b/components/web_package/signed_web_bundles/signed_web_bundle_id_unittest.cc
index 7924e0d7..a1fc419e 100644
--- a/components/web_package/signed_web_bundles/signed_web_bundle_id_unittest.cc
+++ b/components/web_package/signed_web_bundles/signed_web_bundle_id_unittest.cc
@@ -146,23 +146,9 @@
   EXPECT_EQ(id.id(), kDevelopmentSignedWebBundleId);
 }
 
-TEST(SignedWebBundleIdTest, CreateRandomForDevelopmentDefaultGenerator) {
+TEST(SignedWebBundleIdTest, CreateRandomForDevelopment) {
   auto id = SignedWebBundleId::CreateRandomForDevelopment();
   EXPECT_EQ(id.type(), SignedWebBundleId::Type::kDevelopment);
 }
 
-TEST(SignedWebBundleIdTest, CreateRandomForDevelopmentCustomGenerator) {
-  auto custom_callback =
-      base::BindLambdaForTesting([](base::span<uint8_t> buffer) -> void {
-        DCHECK_EQ(buffer.size(), kDevelopmentBytes.size());
-        base::ranges::copy(kDevelopmentBytes, buffer.begin());
-      });
-
-  SignedWebBundleId id =
-      SignedWebBundleId::CreateRandomForDevelopment(custom_callback);
-
-  EXPECT_EQ(id.type(), SignedWebBundleId::Type::kDevelopment);
-  EXPECT_EQ(id.id(), kDevelopmentSignedWebBundleId);
-}
-
 }  // namespace web_package
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc
index 391e7ce8..faa4e5c 100644
--- a/content/app/content_main_runner_impl.cc
+++ b/content/app/content_main_runner_impl.cc
@@ -10,6 +10,7 @@
 
 #include <memory>
 #include <string>
+#include <string_view>
 #include <tuple>
 #include <utility>
 #include <vector>
@@ -521,7 +522,7 @@
 void CreateChildThreadPool(const std::string& process_type) {
   // Thread pool should only be initialized once.
   DCHECK(!base::ThreadPoolInstance::Get());
-  base::StringPiece thread_pool_name;
+  std::string_view thread_pool_name;
   if (process_type == switches::kGpuProcess)
     thread_pool_name = "GPU";
   else if (process_type == switches::kRendererProcess)
diff --git a/content/app/content_main_runner_impl_browsertest.cc b/content/app/content_main_runner_impl_browsertest.cc
index 7db2ca05..75b3797 100644
--- a/content/app/content_main_runner_impl_browsertest.cc
+++ b/content/app/content_main_runner_impl_browsertest.cc
@@ -9,7 +9,6 @@
 #include "base/command_line.h"
 #include "base/feature_list.h"
 #include "base/functional/overloaded.h"
-#include "base/strings/string_piece.h"
 #include "base/task/thread_pool/thread_pool_instance.h"
 #include "build/build_config.h"
 #include "content/public/app/content_main_delegate.h"
diff --git a/content/browser/accessibility/browser_accessibility_state_impl.cc b/content/browser/accessibility/browser_accessibility_state_impl.cc
index db788fd..83ec1d82 100644
--- a/content/browser/accessibility/browser_accessibility_state_impl.cc
+++ b/content/browser/accessibility/browser_accessibility_state_impl.cc
@@ -144,7 +144,7 @@
 const int ModeCollectionForTarget::kUserDataKey;
 
 // Returns a subset of `mode` for delivery to a WebContents.
-ui::AXMode FilterAccessibilityMode(ui::AXMode mode) {
+ui::AXMode FilterAccessibilityModeInvariants(ui::AXMode mode) {
   // Strip kLabelImages if kScreenReader is absent.
   // TODO(grt): kLabelImages is a feature of //chrome. Find a way to
   // achieve this filtering without teaching //content about it. Perhaps via
@@ -435,8 +435,9 @@
 
 ui::AXMode BrowserAccessibilityStateImpl::GetAccessibilityModeForBrowserContext(
     BrowserContext* browser_context) {
-  return GetAccessibilityMode() |
-         ModeCollectionForTarget::GetAccessibilityMode(browser_context);
+  return FilterAccessibilityModeInvariants(
+      GetAccessibilityMode() |
+      ModeCollectionForTarget::GetAccessibilityMode(browser_context));
 }
 
 void BrowserAccessibilityStateImpl::OnUserInputEvent() {
@@ -607,7 +608,7 @@
       WebContentsImpl::GetAllWebContents(),
       [new_mode](WebContentsImpl* web_contents) {
         if (!web_contents->IsBeingDestroyed()) {
-          web_contents->SetAccessibilityMode(FilterAccessibilityMode(
+          web_contents->SetAccessibilityMode(FilterAccessibilityModeInvariants(
               new_mode |
               ModeCollectionForTarget::GetAccessibilityMode(
                   web_contents->GetBrowserContext()) |
@@ -657,7 +658,7 @@
       [browser_context, mode_for_context](WebContentsImpl* web_contents) {
         if (!web_contents->IsBeingDestroyed() &&
             web_contents->GetBrowserContext() == browser_context) {
-          web_contents->SetAccessibilityMode(FilterAccessibilityMode(
+          web_contents->SetAccessibilityMode(FilterAccessibilityModeInvariants(
               mode_for_context |
               ModeCollectionForTarget::GetAccessibilityMode(web_contents)));
         }
@@ -684,11 +685,11 @@
   // Combine the effective modes for the process, `web_contents`'s
   // BrowserContext, and for `web_contents.
   static_cast<WebContentsImpl*>(web_contents)
-      ->SetAccessibilityMode(
-          FilterAccessibilityMode(GetAccessibilityMode() |
-                                  ModeCollectionForTarget::GetAccessibilityMode(
-                                      web_contents->GetBrowserContext()) |
-                                  new_mode));
+      ->SetAccessibilityMode(FilterAccessibilityModeInvariants(
+          GetAccessibilityMode() |
+          ModeCollectionForTarget::GetAccessibilityMode(
+              web_contents->GetBrowserContext()) |
+          new_mode));
 }
 
 void BrowserAccessibilityStateImpl::CallInitBackgroundTasksForTesting(
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index e2559d5..6321af8 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -517,7 +517,8 @@
               url_loader_factory::ContentClientParams(
                   browser_context_, frame_tree_node->current_frame_host(),
                   frame_tree_node->current_frame_host()->GetProcess()->GetID(),
-                  url::Origin(), ukm::SourceIdObj::FromInt64(ukm_source_id_),
+                  resource_request_->request_initiator.value_or(url::Origin()),
+                  ukm::SourceIdObj::FromInt64(ukm_source_id_),
                   /*bypass_redirect_checks=*/nullptr,
                   frame_tree_node->navigation_request()->GetNavigationId(),
                   GetUIThreadTaskRunner(
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index f2ab588..1ecee562 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -4936,319 +4936,6 @@
 
 #endif  // !BUILDFLAG(IS_ANDROID)
 
-class ServiceWorkerBypassFetchHandlerTest
-    : public ServiceWorkerBrowserTest,
-      public testing::WithParamInterface<
-          std::tuple<bool,
-                     bool,
-                     features::ServiceWorkerBypassFetchHandlerTarget>> {
- public:
-  ServiceWorkerBypassFetchHandlerTest() {
-    feature_list_.InitWithFeaturesAndParameters(
-        {{features::kServiceWorkerBypassFetchHandler,
-          {{"strategy", ShouldUseAllowListStrategy() ? "allowlist" : "optin"},
-           {"bypass_for", BypassFetchHandlerTargetStr()}}},
-         {features::kServiceWorkerBypassFetchHandlerHashStrings,
-          {{"script_checksum_to_bypass",
-            ShouldUseValidChecksum() ? kValidChecksum : kInvalidChecksum}}}},
-        {});
-  }
-  ~ServiceWorkerBypassFetchHandlerTest() override = default;
-
-  WebContents* web_contents() const { return shell()->web_contents(); }
-
-  RenderFrameHost* GetPrimaryMainFrame() {
-    return web_contents()->GetPrimaryMainFrame();
-  }
-
- protected:
-  bool ShouldUseValidChecksum() { return std::get<0>(GetParam()); }
-  bool ShouldUseAllowListStrategy() { return std::get<1>(GetParam()); }
-  features::ServiceWorkerBypassFetchHandlerTarget BypassFetchHandlerTarget() {
-    return std::get<2>(GetParam());
-  }
-  std::string BypassFetchHandlerTargetStr() {
-    switch (BypassFetchHandlerTarget()) {
-      case features::ServiceWorkerBypassFetchHandlerTarget::kMainResource:
-        return "main_resource";
-      case features::ServiceWorkerBypassFetchHandlerTarget::
-          kAllOnlyIfServiceWorkerNotStarted:
-        return "all_only_if_service_worker_not_started";
-      case features::ServiceWorkerBypassFetchHandlerTarget::kSubResource:
-        return "sub_resource";
-      case features::ServiceWorkerBypassFetchHandlerTarget::
-          kAllWithRaceNetworkRequest:
-        return "all_with_race_network_request";
-    }
-  }
-
- private:
-  base::test::ScopedFeatureList feature_list_;
-  std::string kValidChecksum =
-      "B437DA0A66F805F079E1F371F2BFAEF4A35BB9AEEA0A85827B954B05F6D63C6C";
-  std::string kInvalidChecksum = "";
-};
-
-INSTANTIATE_TEST_SUITE_P(
-    All,
-    ServiceWorkerBypassFetchHandlerTest,
-    testing::Combine(
-        testing::Bool(),
-        testing::Bool(),
-        testing::Values(
-            features::ServiceWorkerBypassFetchHandlerTarget::kMainResource,
-            features::ServiceWorkerBypassFetchHandlerTarget::
-                kAllOnlyIfServiceWorkerNotStarted,
-            features::ServiceWorkerBypassFetchHandlerTarget::kSubResource)));
-
-IN_PROC_BROWSER_TEST_P(ServiceWorkerBypassFetchHandlerTest, All) {
-  StartServerAndNavigateToSetup();
-
-  const GURL create_service_worker_url(embedded_test_server()->GetURL(
-      "/service_worker/create_service_worker.html"));
-  const GURL out_scope_url(embedded_test_server()->GetURL("/empty.html"));
-  // |in_scope_url| is a page that has more than one subresources.
-  const GURL in_scope_url(
-      embedded_test_server()->GetURL("/service_worker/with_subresources.html"));
-
-  // Register a service worker.
-  WorkerRunningStatusObserver observer1(public_context());
-  EXPECT_TRUE(NavigateToURL(shell(), create_service_worker_url));
-  EXPECT_EQ("DONE",
-            EvalJs(GetPrimaryMainFrame(),
-                   "register('/service_worker/fetch_event_pass_through.js')"));
-  observer1.WaitUntilRunning();
-  scoped_refptr<ServiceWorkerVersion> version =
-      wrapper()->GetLiveVersion(observer1.version_id());
-  EXPECT_EQ(blink::EmbeddedWorkerStatus::kRunning, version->running_status());
-
-  // Stop the current running service worker.
-  StopServiceWorker(version.get());
-  EXPECT_EQ(blink::EmbeddedWorkerStatus::kStopped, version->running_status());
-
-  // Navigate away from the service worker's scope.
-  EXPECT_TRUE(NavigateToURL(shell(), out_scope_url));
-  EXPECT_EQ(blink::EmbeddedWorkerStatus::kStopped, version->running_status());
-
-  // This script asks the service worker what fetch events it saw.
-  const std::string script = R"(
-      (async () => {
-        const saw_message = new Promise(resolve => {
-          navigator.serviceWorker.onmessage = event => {
-            resolve(event.data);
-          };
-        });
-        const registration = await navigator.serviceWorker.ready;
-        registration.active.postMessage('');
-        const message = await saw_message;
-        return message.length;
-      })();
-  )";
-
-  // Navigate to the service worker's scope.
-  WorkerRunningStatusObserver observer2(public_context());
-  EXPECT_TRUE(NavigateToURL(shell(), in_scope_url));
-
-  switch (BypassFetchHandlerTarget()) {
-    case features::ServiceWorkerBypassFetchHandlerTarget::kMainResource:
-      if (ShouldUseAllowListStrategy()) {
-        if (ShouldUseValidChecksum()) {
-          // If bypassing is allowed, the service worker was bypassed and the
-          // navigation request shouldn't be handled by the fetch handler.
-          // 2 from subresources.
-          EXPECT_EQ(2, EvalJs(GetPrimaryMainFrame(), script));
-        } else {
-          // If bypassing is not allowed, the navigation request should be
-          // handled by the fetch handler. 3 = main + subresources
-          EXPECT_EQ(3, EvalJs(GetPrimaryMainFrame(), script));
-        }
-      } else {
-        // If the allowlist isn't used, the service worker was bypassed and the
-        // navigation request shouldn't be handled by the fetch handler.
-        EXPECT_EQ(2, EvalJs(GetPrimaryMainFrame(), script));
-      }
-      break;
-    case features::ServiceWorkerBypassFetchHandlerTarget::
-        kAllOnlyIfServiceWorkerNotStarted:
-      // TODO(crbug.com/1371756): Consider supporing the allowlist if needed.
-
-      // this option doesn't involve a fetch handler at all when the
-      // ServiceWorker is not started yet while the navigation happens.
-      EXPECT_EQ(0, EvalJs(GetPrimaryMainFrame(), script));
-
-      // Wait until running.
-      observer2.WaitUntilRunning();
-      version = wrapper()->GetLiveVersion(observer2.version_id());
-      EXPECT_EQ(blink::EmbeddedWorkerStatus::kRunning,
-                version->running_status());
-
-      // The handler is not used for subsequent requests even if the
-      // worker has already started.
-      EXPECT_TRUE(
-          ExecJs(GetPrimaryMainFrame(), "fetch('/service_worker/empty.html')"));
-      EXPECT_EQ(0, EvalJs(GetPrimaryMainFrame(), script));
-
-      // Navigate to the page again while the ServicWorker is running.
-      EXPECT_TRUE(NavigateToURL(shell(), in_scope_url));
-      // Expect both the main resource and subresource are handled.
-      EXPECT_EQ(3, EvalJs(GetPrimaryMainFrame(), script));
-      break;
-    case features::ServiceWorkerBypassFetchHandlerTarget::kSubResource:
-      if (ShouldUseAllowListStrategy()) {
-        if (ShouldUseValidChecksum()) {
-          // If bypassing is allowed, subresources shouldn't be handled by the
-          // fetch handler.
-          // 1 = main resource
-          EXPECT_EQ(1, EvalJs(GetPrimaryMainFrame(), script));
-        } else {
-          // If bypassing is not allowed, subresources should be handled by the
-          // fetch handler.
-          // 3 = main + subresources
-          EXPECT_EQ(3, EvalJs(GetPrimaryMainFrame(), script));
-        }
-      } else {
-        // The service worker handles the navigation request, but bypasses fetch
-        // handlers for subsequent subresources.
-        EXPECT_EQ(1, EvalJs(GetPrimaryMainFrame(), script));
-      }
-      break;
-    case features::ServiceWorkerBypassFetchHandlerTarget::
-        kAllWithRaceNetworkRequest:
-      // This case is tested in ServiceWorkerRaceNetworkRequestBrowserTest.
-      NOTREACHED();
-      break;
-  }
-}
-
-class ServiceWorkerBypassFetchHandlerOriginTrialTest
-    : public ServiceWorkerBrowserTest {
- public:
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    // The public key for the default privatey key used by the
-    // tools/origin_trials/generate_token.py tool.
-    static constexpr char kOriginTrialTestPublicKey[] =
-        "dRCs+TocuKkocNKa0AtZ4awrt9XKH2SQCI6o4FY6BNA=";
-    command_line->AppendSwitchASCII("origin-trial-public-key",
-                                    kOriginTrialTestPublicKey);
-  }
-  WebContents* web_contents() const { return shell()->web_contents(); }
-
-  RenderFrameHost* GetPrimaryMainFrame() {
-    return web_contents()->GetPrimaryMainFrame();
-  }
-};
-
-IN_PROC_BROWSER_TEST_F(ServiceWorkerBypassFetchHandlerOriginTrialTest,
-                       BypassFetchHandlerForMainResource) {
-  embedded_test_server()->StartAcceptingConnections();
-
-  // The URL that was used to register the Origin Trial token.
-  static constexpr char kOriginUrl[] = "https://127.0.0.1:44444";
-  // Generated by running (in tools/origin_trials):
-  // tools/origin_trials/generate_token.py https://127.0.0.1:44444 \
-  // ServiceWorkerBypassFetchHandlerForMainResource \
-  // --expire-timestamp=2000000000
-  static constexpr char kOriginTrialToken[] =
-      "A7lJi6aWVTbSCCs9Ju3k4SKBnTzE/"
-      "9j7OMHWdF2pjJLLZU5Fdt7IzilJOFp37hMyoeIUq4gCTdb9wSIC9jhU/"
-      "wgAAAB4eyJvcmlnaW4iOiAiaHR0cHM6Ly8xMjcuMC4wLjE6NDQ0NDQiLCAiZmVhdHVyZSI6I"
-      "CJTZXJ2aWNlV29ya2VyQnlwYXNzRmV0Y2hIYW5kbGVyRm9yTWFpblJlc291cmNlIiwgImV4c"
-      "GlyeSI6IDIwMDAwMDAwMDB9";
-
-  const GURL main_page_url(
-      base::StrCat({kOriginUrl, "/create_service_worker.html"}));
-  const GURL service_worker_url(
-      base::StrCat({kOriginUrl, "/fetch_event_pass_through.js"}));
-
-  std::map<GURL, int /* number_of_invocations */> expected_request_urls = {
-      {main_page_url, 2},
-      {service_worker_url, 1},
-  };
-
-  base::RunLoop run_loop;
-
-  // The origin trial token is associated with an origin. We can't guarantee the
-  // EmbeddedTestServer to use a specific port. So the URLLoaderInterceptor is
-  // used instead.
-  URLLoaderInterceptor service_worker_loader(base::BindLambdaForTesting(
-      [&](URLLoaderInterceptor::RequestParams* params) {
-        auto it = expected_request_urls.find(params->url_request.url);
-        if (it == expected_request_urls.end()) {
-          return false;
-        }
-
-        const std::string content_type =
-            base::EndsWith(params->url_request.url.path_piece(), ".js")
-                ? "text/javascript"
-                : "text/html";
-
-        const std::string origin_trial_token =
-            params->url_request.url == service_worker_url ? kOriginTrialToken
-                                                          : "";
-
-        const std::string headers = base::ReplaceStringPlaceholders(
-            "HTTP/1.1 200 OK\n"
-            "Content-type: $1\n"
-            "Origin-Trial: $2\n"
-            "\n",
-            {content_type, origin_trial_token}, {});
-
-        URLLoaderInterceptor::WriteResponse(
-            "content/test/data/service_worker" + params->url_request.url.path(),
-            params->client.get(), &headers, std::optional<net::SSLInfo>(),
-            params->url_request.url);
-
-        if (--it->second == 0) {
-          expected_request_urls.erase(it);
-        }
-        if (expected_request_urls.empty()) {
-          run_loop.Quit();
-        }
-        return true;
-      }));
-
-  // Register a service worker.
-  WorkerRunningStatusObserver observer(public_context());
-  EXPECT_TRUE(NavigateToURL(shell(), main_page_url));
-  EXPECT_EQ("DONE", EvalJs(GetPrimaryMainFrame(),
-                           "register('/fetch_event_pass_through.js')"));
-  observer.WaitUntilRunning();
-  scoped_refptr<ServiceWorkerVersion> version =
-      wrapper()->GetLiveVersion(observer.version_id());
-  EXPECT_EQ(blink::EmbeddedWorkerStatus::kRunning, version->running_status());
-
-  // Stop the current running service worker.
-  StopServiceWorker(version.get());
-  EXPECT_EQ(blink::EmbeddedWorkerStatus::kStopped, version->running_status());
-
-  // Navigate away from the service worker's scope.
-  EXPECT_TRUE(
-      NavigateToURL(shell(), embedded_test_server()->GetURL("/empty.html")));
-  EXPECT_EQ(blink::EmbeddedWorkerStatus::kStopped, version->running_status());
-
-  // Navigate to the service worker's scope.
-  EXPECT_TRUE(NavigateToURL(shell(), main_page_url));
-
-  // The service worker was bypassed and the navigation request shouldn't be
-  // handled by the fetch handler.
-  // The script asks the service worker what fetch events it saw.
-  EXPECT_EQ(0, EvalJs(GetPrimaryMainFrame(), R"(
-      (async () => {
-        const saw_message = new Promise(resolve => {
-          navigator.serviceWorker.onmessage = event => {
-            resolve(event.data);
-          };
-        });
-        const registration = await navigator.serviceWorker.ready;
-        registration.active.postMessage('');
-        const message = await saw_message;
-        return message.length;
-      })();
-  )"));
-
-  run_loop.Run();
-}
-
 class ServiceWorkerSkipEmptyFetchHandlerBrowserTest
     : public ServiceWorkerBrowserTest {
  public:
@@ -5373,22 +5060,22 @@
       ServiceWorkerVersion::FetchHandlerType::kEmptyFetchHandler, 1);
 }
 
-// Test class for BestEffortServiceWorker (crbug.com/1420517) browsertest.
-class ServiceWorkerRaceNetworkRequestBrowserTest
+// Browser test for the Static Routing API's `race-network-and-fetch-handler`
+// source.
+class ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest
     : public ServiceWorkerBrowserTest {
  public:
-  ServiceWorkerRaceNetworkRequestBrowserTest()
+  static constexpr char kSwScriptUrl[] =
+      "/service_worker/static_router_race_match_all.js";
+
+  ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest()
       : https_server_(std::make_unique<net::EmbeddedTestServer>(
             net::EmbeddedTestServer::TYPE_HTTPS)) {
-    feature_list_.InitWithFeaturesAndParameters(
-        {{features::kServiceWorkerBypassFetchHandler,
-          {{"strategy", "optin"},
-           {"bypass_for", "all_with_race_network_request"}}}},
-        {});
     RaceNetworkRequestWriteBufferManager::SetDataPipeCapacityBytesForTesting(
         1024);
   }
-  ~ServiceWorkerRaceNetworkRequestBrowserTest() override = default;
+  ~ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest()
+      override = default;
 
   WebContents* web_contents() const { return shell()->web_contents(); }
 
@@ -5397,13 +5084,13 @@
   }
 
   scoped_refptr<ServiceWorkerVersion> SetupAndRegisterServiceWorker() {
-    StartServerAndNavigateToSetup();
-    return RegisterRaceNetowrkRequestServiceWorker(embedded_test_server());
+    return SetupAndRegisterServiceWorkerInternal(kSwScriptUrl);
   }
 
   scoped_refptr<ServiceWorkerVersion>
   SetupAndRegisterServiceWorkerWithHTTPSServer() {
-    return RegisterRaceNetowrkRequestServiceWorker(https_server());
+    return RegisterRaceNetowrkRequestServiceWorker(https_server(),
+                                                   kSwScriptUrl);
   }
 
   EvalJsResult GetInnerText() {
@@ -5431,6 +5118,13 @@
     RegisterRequestHandlerForSlowResponsePage(https_server());
   }
 
+  scoped_refptr<ServiceWorkerVersion> SetupAndRegisterServiceWorkerInternal(
+      const std::string& script_url) {
+    StartServerAndNavigateToSetup();
+    return RegisterRaceNetowrkRequestServiceWorker(embedded_test_server(),
+                                                   script_url);
+  }
+
  private:
   void RegisterRequestHandlerForSlowResponsePage(
       net::EmbeddedTestServer* test_server) {
@@ -5503,7 +5197,8 @@
   void RegisterRequestMonitorForRequestCount(
       net::EmbeddedTestServer* test_server) {
     test_server->RegisterRequestMonitor(base::BindRepeating(
-        &ServiceWorkerRaceNetworkRequestBrowserTest::MonitorRequestHandler,
+        &ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest::
+            MonitorRequestHandler,
         base::Unretained(this)));
   }
   void MonitorRequestHandler(const net::test_server::HttpRequest& request) {
@@ -5511,16 +5206,16 @@
   }
 
   scoped_refptr<ServiceWorkerVersion> RegisterRaceNetowrkRequestServiceWorker(
-      net::EmbeddedTestServer* test_server) {
+      net::EmbeddedTestServer* test_server,
+      const std::string& script_url) {
     const GURL create_service_worker_url(
         test_server->GetURL("/service_worker/create_service_worker.html"));
 
     // Register a service worker.
     WorkerRunningStatusObserver observer1(public_context());
     EXPECT_TRUE(NavigateToURL(shell(), create_service_worker_url));
-    EXPECT_EQ("DONE",
-              EvalJs(GetPrimaryMainFrame(),
-                     "register('/service_worker/race_network_request.js')"));
+    EXPECT_EQ("DONE", EvalJs(GetPrimaryMainFrame(),
+                             base::StrCat({"register('", script_url, "')"})));
     observer1.WaitUntilRunning();
     scoped_refptr<ServiceWorkerVersion> version =
         wrapper()->GetLiveVersion(observer1.version_id());
@@ -5539,8 +5234,9 @@
   std::unique_ptr<net::EmbeddedTestServer> https_server_;
 };
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       NetworkRequest_Wins) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    NetworkRequest_Wins) {
   // Register the ServiceWorker and navigate to the in scope URL.
   SetupAndRegisterServiceWorker();
   // Capture the response head.
@@ -5562,8 +5258,9 @@
             observer.GetNormalizedResponseHeader("X-Response-From"));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       NetworkRequest_Wins_MarkedAsSecure) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    NetworkRequest_Wins_MarkedAsSecure) {
   // Register the ServiceWorker and navigate to the in scope URL.
   StartServerAndNavigateToSetup();
   ASSERT_TRUE(https_server()->Start());
@@ -5586,8 +5283,9 @@
   CheckPageIsMarkedSecure(shell(), https_server()->GetCertificate());
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       NetworkRequest_Wins_MimeTypeSniffed) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    NetworkRequest_Wins_MimeTypeSniffed) {
   // Register the ServiceWorker and navigate to the in scope URL.
   StartServerAndNavigateToSetup();
 
@@ -5619,8 +5317,9 @@
             GetInnerText());
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       NetworkRequest_Wins_Fetch_No_Respond) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    NetworkRequest_Wins_Fetch_No_Respond) {
   // Register the ServiceWorker and navigate to the in scope URL.
   SetupAndRegisterServiceWorker();
   NavigateToURLBlockUntilNavigationsComplete(
@@ -5636,8 +5335,9 @@
 // TODO(crbug.com/1491332) Add tests for
 // kURLLoadOptionSendSSLInfoForCertificateError
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       NetworkRequest_Wins_NotFound_FetchHandler_Respond) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    NetworkRequest_Wins_NotFound_FetchHandler_Respond) {
   SetupAndRegisterServiceWorker();
 
   // Network request is faster, but the response is not found.
@@ -5653,8 +5353,9 @@
             GetInnerText());
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       NetworkRequest_Wins_NotFound_FetchHandler_NotRespond) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    NetworkRequest_Wins_NotFound_FetchHandler_NotRespond) {
   SetupAndRegisterServiceWorker();
 
   // If the fallback request is not found. Then expect 404.
@@ -5674,8 +5375,9 @@
 #define MAYBE_NetworkRequest_Wins_FetchHandler_Fallback \
   NetworkRequest_Wins_FetchHandler_Fallback
 #endif
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       MAYBE_NetworkRequest_Wins_FetchHandler_Fallback) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    MAYBE_NetworkRequest_Wins_FetchHandler_Fallback) {
   // If RaceNetworkRequest comes first, there is a network error, and the fetch
   // handler result is a fallback. In this case the response from
   // RaceNetworkRequest is not used, because we need to support the case when
@@ -5698,8 +5400,9 @@
   EXPECT_EQ(2, GetRequestCount(relative_url));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       NetworkRequest_Wins_FetchHandler_Fallback_LargeData) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    NetworkRequest_Wins_FetchHandler_Fallback_LargeData) {
   SetupAndRegisterServiceWorker();
   const std::string relative_url =
       "/service_worker/mock_response?sw_fallback&sw_slow&server_large_data";
@@ -5712,8 +5415,9 @@
             observer.GetNormalizedResponseHeader("X-Response-From"));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       NetworkRequest_Wins_Post) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    NetworkRequest_Wins_Post) {
   SetupAndRegisterServiceWorker();
   const std::string action = "/service_worker/mock_response?sw_slow&sw_respond";
   EXPECT_TRUE(ExecJs(GetPrimaryMainFrame(),
@@ -5738,8 +5442,9 @@
 #else
 #define MAYBE_NetworkRequest_Wins_Redirect NetworkRequest_Wins_Redirect
 #endif
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       MAYBE_NetworkRequest_Wins_Redirect) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    MAYBE_NetworkRequest_Wins_Redirect) {
   SetupAndRegisterServiceWorker();
   const std::string path =
       "/service_worker/mock_response?server_redirect&sw_slow&sw_respond";
@@ -5767,8 +5472,9 @@
 #define MAYBE_NetworkRequest_Wins_Redirect_PassThrough \
   NetworkRequest_Wins_Redirect_PassThrough
 #endif
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       MAYBE_NetworkRequest_Wins_Redirect_PassThrough) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    MAYBE_NetworkRequest_Wins_Redirect_PassThrough) {
   SetupAndRegisterServiceWorker();
   const std::string path =
       "/service_worker/mock_response?server_redirect&sw_slow&sw_pass_through";
@@ -5789,8 +5495,9 @@
   EXPECT_EQ(1, GetRequestCount(path_after_redirect));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       FetchHandler_Wins) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    FetchHandler_Wins) {
   SetupAndRegisterServiceWorker();
   // Need to navigate to the page with slow response.
   const GURL slow_url = embedded_test_server()->GetURL(
@@ -5810,8 +5517,9 @@
             observer.GetNormalizedResponseHeader("X-Response-From"));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       FetchHandler_Wins_Fallback) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    FetchHandler_Wins_Fallback) {
   SetupAndRegisterServiceWorker();
   // Fetch handler will fallback. This case the response from RaceNetworkRequest
   // is returned as a final response.
@@ -5832,8 +5540,9 @@
   EXPECT_FALSE(NavigateToURL(shell(), slow_url));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       FetchHandler_Wins_NotFound) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    FetchHandler_Wins_NotFound) {
   SetupAndRegisterServiceWorker();
   const GURL slow_url = embedded_test_server()->GetURL(
       "/service_worker/mock_response?server_slow&server_notfound&sw_fallback");
@@ -5850,8 +5559,9 @@
 #else
 #define MAYBE_FetchHandler_Wins_Redirect FetchHandler_Wins_Redirect
 #endif
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       MAYBE_FetchHandler_Wins_Redirect) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    MAYBE_FetchHandler_Wins_Redirect) {
   SetupAndRegisterServiceWorker();
   const std::string path =
       "/service_worker/mock_response?server_redirect&server_slow&sw_respond";
@@ -5876,8 +5586,9 @@
 #define MAYBE_FetchHandler_Wins_Redirect_PassThrough \
   FetchHandler_Wins_Redirect_PassThrough
 #endif
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       MAYBE_FetchHandler_Wins_Redirect_PassThrough) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    MAYBE_FetchHandler_Wins_Redirect_PassThrough) {
   SetupAndRegisterServiceWorker();
   const std::string path =
       "/service_worker/"
@@ -5898,8 +5609,9 @@
   EXPECT_EQ(1, GetRequestCount(path_after_redirect));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       FetchHandler_PassThrough) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    FetchHandler_PassThrough) {
   // Register the ServiceWorker and navigate to the in scope URL.
   scoped_refptr<ServiceWorkerVersion> version = SetupAndRegisterServiceWorker();
   // Capture the response head.
@@ -5928,8 +5640,9 @@
   EXPECT_EQ(1, GetRequestCount(relative_url));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       FetchHandler_PassThrough_Clone) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    FetchHandler_PassThrough_Clone) {
   // Register the ServiceWorker and navigate to the in scope URL.
   scoped_refptr<ServiceWorkerVersion> version = SetupAndRegisterServiceWorker();
   // URL which create a cloned request and pass-through.
@@ -5963,8 +5676,9 @@
 #else
 #define MAYBE_Subresource_NetworkRequest_Wins Subresource_NetworkRequest_Wins
 #endif
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       MAYBE_Subresource_NetworkRequest_Wins) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    MAYBE_Subresource_NetworkRequest_Wins) {
   SetupAndRegisterServiceWorker();
   WorkerRunningStatusObserver observer(public_context());
   ReloadBlockUntilNavigationsComplete(shell(), 1);
@@ -5977,8 +5691,9 @@
              "=> response.text())"));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       Subresource_NetworkRequest_Wins_Fetch_No_Respond) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    Subresource_NetworkRequest_Wins_Fetch_No_Respond) {
   SetupAndRegisterServiceWorker();
   WorkerRunningStatusObserver observer(public_context());
   ReloadBlockUntilNavigationsComplete(shell(), 1);
@@ -5990,8 +5705,9 @@
              "=> response.text())"));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       Subresource_NetworkRequest_Wins_NotFound) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    Subresource_NetworkRequest_Wins_NotFound) {
   SetupAndRegisterServiceWorker();
   WorkerRunningStatusObserver observer(public_context());
   ReloadBlockUntilNavigationsComplete(shell(), 1);
@@ -6012,8 +5728,9 @@
                         "server_notfound').then(response => response.status)"));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       Subresource_NetworkRequest_Wins_FetchHandler_Fallback) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    Subresource_NetworkRequest_Wins_FetchHandler_Fallback) {
   SetupAndRegisterServiceWorker();
   // Network request is faster, and the fetch handler will fallback.
   // This case the response from RaceNetworkRequset is used.
@@ -6025,7 +5742,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(
-    ServiceWorkerRaceNetworkRequestBrowserTest,
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
     Subresource_NetworkRequest_Wins_FetchHandler_Fallback_LargeData) {
   SetupAndRegisterServiceWorker();
   EXPECT_EQ("race-network-request-with-large-data",
@@ -6036,7 +5753,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(
-    ServiceWorkerRaceNetworkRequestBrowserTest,
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
     Subresource_NetworkRequest_Wins_FetchHandler_Fallback_Redirect) {
   SetupAndRegisterServiceWorker();
   WorkerRunningStatusObserver observer(public_context());
@@ -6061,8 +5778,9 @@
   EXPECT_EQ(1, GetRequestCount(path_after_redirect));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       Subresource_NetworkRequest_Wins_Post) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    Subresource_NetworkRequest_Wins_Post) {
   SetupAndRegisterServiceWorker();
   ReloadBlockUntilNavigationsComplete(shell(), 1);
 
@@ -6080,8 +5798,9 @@
             EvalJs(GetPrimaryMainFrame(), script));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       Subresource_Redirect_Multiple) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    Subresource_Redirect_Multiple) {
   SetupAndRegisterServiceWorker();
   ReloadBlockUntilNavigationsComplete(shell(), 1);
 
@@ -6111,8 +5830,9 @@
 #define MAYBE_Subresource_NetworkRequest_Wins_Redirect \
   Subresource_NetworkRequest_Wins_Redirect
 #endif
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       MAYBE_Subresource_NetworkRequest_Wins_Redirect) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    MAYBE_Subresource_NetworkRequest_Wins_Redirect) {
   SetupAndRegisterServiceWorker();
   ReloadBlockUntilNavigationsComplete(shell(), 1);
 
@@ -6140,7 +5860,7 @@
   Subresource_NetworkRequest_Wins_Redirect_PassThrough
 #endif
 IN_PROC_BROWSER_TEST_F(
-    ServiceWorkerRaceNetworkRequestBrowserTest,
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
     MAYBE_Subresource_NetworkRequest_Wins_Redirect_PassThrough) {
   SetupAndRegisterServiceWorker();
   ReloadBlockUntilNavigationsComplete(shell(), 1);
@@ -6163,8 +5883,9 @@
   EXPECT_EQ(1, GetRequestCount(path_after_redirect));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       Subresource_FetchHandler_Wins) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    Subresource_FetchHandler_Wins) {
   SetupAndRegisterServiceWorker();
   WorkerRunningStatusObserver observer(public_context());
   ReloadBlockUntilNavigationsComplete(shell(), 1);
@@ -6178,8 +5899,9 @@
                    "response.text())"));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       Subresource_FetchHandler_Wins_Fallback) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    Subresource_FetchHandler_Wins_Fallback) {
   SetupAndRegisterServiceWorker();
   WorkerRunningStatusObserver observer(public_context());
   ReloadBlockUntilNavigationsComplete(shell(), 1);
@@ -6203,8 +5925,9 @@
   EXPECT_FALSE(ExecJs(GetPrimaryMainFrame(), "fetch('" + relative_url + "')"));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       Subresource_FetchHandler_Wins_Fallback_Redirect) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    Subresource_FetchHandler_Wins_Fallback_Redirect) {
   SetupAndRegisterServiceWorker();
   WorkerRunningStatusObserver observer(public_context());
   ReloadBlockUntilNavigationsComplete(shell(), 1);
@@ -6227,8 +5950,9 @@
   EXPECT_EQ(1, GetRequestCount(path_after_redirect));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       Subresource_FetchHandler_Wins_NotFound) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    Subresource_FetchHandler_Wins_NotFound) {
   SetupAndRegisterServiceWorker();
   WorkerRunningStatusObserver observer(public_context());
   ReloadBlockUntilNavigationsComplete(shell(), 1);
@@ -6251,8 +5975,9 @@
 #define MAYBE_Subresource_FetchHandler_Wins_Redirect \
   Subresource_FetchHandler_Wins_Redirect
 #endif
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       MAYBE_Subresource_FetchHandler_Wins_Redirect) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    MAYBE_Subresource_FetchHandler_Wins_Redirect) {
   SetupAndRegisterServiceWorker();
   ReloadBlockUntilNavigationsComplete(shell(), 1);
 
@@ -6280,7 +6005,7 @@
   Subresource_FetchHandler_Wins_Redirect_PassThrough
 #endif
 IN_PROC_BROWSER_TEST_F(
-    ServiceWorkerRaceNetworkRequestBrowserTest,
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
     MAYBE_Subresource_FetchHandler_Wins_Redirect_PassThrough) {
   SetupAndRegisterServiceWorker();
   ReloadBlockUntilNavigationsComplete(shell(), 1);
@@ -6304,8 +6029,9 @@
   EXPECT_EQ(1, GetRequestCount(path_after_redirect));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestBrowserTest,
-                       Subresource_FetchHandler_PassThrough) {
+IN_PROC_BROWSER_TEST_F(
+    ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
+    Subresource_FetchHandler_PassThrough) {
   SetupAndRegisterServiceWorker();
   WorkerRunningStatusObserver observer(public_context());
   ReloadBlockUntilNavigationsComplete(shell(), 1);
@@ -6330,20 +6056,26 @@
 }
 
 class ServiceWorkerAutoPreloadBrowserTest
-    : public ServiceWorkerRaceNetworkRequestBrowserTest,
+    : public ServiceWorkerStaticRouterRaceNetworkAndFetchHandlerSourceBrowserTest,
       public testing::WithParamInterface<bool> {
  public:
+  static constexpr char kSwScriptUrl[] = "/service_worker/auto_preload.js";
+
   ServiceWorkerAutoPreloadBrowserTest() {
     feature_list_.InitWithFeaturesAndParameters(
         {{features::kServiceWorkerAutoPreload,
           {{"use_two_phase_write", GetParam() ? "true" : "false"}}}},
-        {{features::kServiceWorkerBypassFetchHandler}});
+        {});
     RaceNetworkRequestWriteBufferManager::SetDataPipeCapacityBytesForTesting(
         1024);
   }
 
   ~ServiceWorkerAutoPreloadBrowserTest() override = default;
 
+  scoped_refptr<ServiceWorkerVersion> SetupAndRegisterServiceWorker() {
+    return SetupAndRegisterServiceWorkerInternal(kSwScriptUrl);
+  }
+
  private:
   base::test::ScopedFeatureList feature_list_;
 };
@@ -6595,9 +6327,8 @@
         blocked_host(), "/service_worker/create_service_worker.html"));
     WorkerRunningStatusObserver observer1(public_context());
     EXPECT_TRUE(NavigateToURL(shell(), create_service_worker_url));
-    EXPECT_EQ("DONE",
-              EvalJs(GetPrimaryMainFrame(),
-                     "register('/service_worker/race_network_request.js')"));
+    EXPECT_EQ("DONE", EvalJs(GetPrimaryMainFrame(),
+                             "register('/service_worker/auto_preload.js')"));
     observer1.WaitUntilRunning();
   }
 
@@ -6767,150 +6498,83 @@
             observer.GetNormalizedResponseHeader("X-Response-From"));
 }
 
-class ServiceWorkerRaceNetworkRequestOriginTrialBrowserTest
-    : public ServiceWorkerRaceNetworkRequestBrowserTest {
+class ServiceWorkerAutoPreloadAllowListBrowserTest
+    : public ServiceWorkerAutoPreloadBrowserTest {
  public:
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    // The public key for the default privatey key used by the
-    // tools/origin_trials/generate_token.py tool.
-    static constexpr char kOriginTrialTestPublicKey[] =
-        "dRCs+TocuKkocNKa0AtZ4awrt9XKH2SQCI6o4FY6BNA=";
-    command_line->AppendSwitchASCII("origin-trial-public-key",
-                                    kOriginTrialTestPublicKey);
+  ServiceWorkerAutoPreloadAllowListBrowserTest() {
+    feature_list_.InitWithFeaturesAndParameters(
+        {{features::kServiceWorkerAutoPreload,
+          {{"use_allowlist", "true"}, {"use_two_phase_write", "false"}}},
+         {features::kServiceWorkerBypassFetchHandlerHashStrings,
+          {{"script_checksum_to_bypass",
+            ShouldUseValidChecksum() ? kValidChecksum : kInvalidChecksum}}}},
+        {});
   }
+  ~ServiceWorkerAutoPreloadAllowListBrowserTest() override = default;
+
+  WebContents* web_contents() const { return shell()->web_contents(); }
+
+  RenderFrameHost* GetPrimaryMainFrame() {
+    return web_contents()->GetPrimaryMainFrame();
+  }
+
+ protected:
+  bool ShouldUseValidChecksum() { return GetParam(); }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+  std::string kValidChecksum =
+      "042D3C49B5FA366582CEBA01E6E3DCD6259531CCAF64B26635B7F0C11C18BE0D";
+  std::string kInvalidChecksum = "";
 };
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestOriginTrialBrowserTest,
-                       RaceNetworkRequest) {
-  embedded_test_server()->StartAcceptingConnections();
+INSTANTIATE_TEST_SUITE_P(ALL,
+                         ServiceWorkerAutoPreloadAllowListBrowserTest,
+                         testing::Bool());
 
-  // The URL that was used to register the Origin Trial token.
-  static constexpr char kOriginUrl[] = "https://127.0.0.1:44444";
-  // Generated by running (in tools/origin_trials):
-  // tools/origin_trials/generate_token.py https://127.0.0.1:44444 \
-  // ServiceWorkerBypassFetchHandlerWithRaceNetworkRequest \
-  // --expire-timestamp=2000000000
-  static constexpr char kOriginTrialToken[] =
-      "AywPGgJULst8eq0LDwGqFRqFTfbNIq+"
-      "dDh6BpmDRZxazAjL8JCiXtp51bRuaG7X7pxz35vwQ9+5hEPLLW0DMKA4AAAB/"
-      "eyJvcmlnaW4iOiAiaHR0cHM6Ly8xMjcuMC4wLjE6NDQ0NDQiLCAiZmVhdHVyZSI6ICJTZXJ2"
-      "aWNlV29ya2VyQnlwYXNzRmV0Y2hIYW5kbGVyV2l0aFJhY2VOZXR3b3JrUmVxdWVzdCIsICJl"
-      "eHBpcnkiOiAyMDAwMDAwMDAwfQ==";
+IN_PROC_BROWSER_TEST_P(ServiceWorkerAutoPreloadAllowListBrowserTest,
+                       EnableAutoPreloadIfScriptIsAllowed) {
+  SetupAndRegisterServiceWorker();
+  const std::string relative_url = "/service_worker/mock_response?sw_respond";
+  const GURL test_url = embedded_test_server()->GetURL(relative_url);
+  NavigationHandleObserver observer(web_contents(), test_url);
+  WorkerRunningStatusObserver service_worker_running_status_observer(
+      public_context());
+  NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
+  EXPECT_TRUE(observer.has_committed());
+  service_worker_running_status_observer.WaitUntilRunning();
 
-  const GURL main_page_url(
-      base::StrCat({kOriginUrl, "/create_service_worker.html"}));
-  const GURL main_page_url_with_params(
-      base::StrCat({main_page_url.spec(), "?sw_slow&sw_respond"}));
-  const GURL service_worker_url(
-      base::StrCat({kOriginUrl, "/race_network_request.js"}));
-  const GURL subresource_url_with_params(
-      base::StrCat({kOriginUrl, "/hello-from-sw.txt?sw_slow&sw_respond"}));
-
-  std::map<GURL, int /* number_of_invocations */> expected_request_urls = {
-      {main_page_url, 1},
-      {main_page_url_with_params, 1},
-      {subresource_url_with_params, 1},
-      {service_worker_url, 1},
-  };
-
-  base::RunLoop run_loop;
-
-  // The origin trial token is associated with an origin. We can't guarantee the
-  // EmbeddedTestServer to use a specific port. So the URLLoaderInterceptor is
-  // used instead.
-  URLLoaderInterceptor service_worker_loader(base::BindLambdaForTesting(
-      [&](URLLoaderInterceptor::RequestParams* params) {
-        auto it = expected_request_urls.find(params->url_request.url);
-        if (it == expected_request_urls.end()) {
-          return false;
-        }
-
-        const std::string content_type =
-            base::EndsWith(params->url_request.url.path_piece(), ".js")
-                ? "text/javascript"
-                : "text/html";
-
-        const std::string origin_trial_token =
-            params->url_request.url == service_worker_url ? kOriginTrialToken
-                                                          : "";
-
-        const std::string headers = base::ReplaceStringPlaceholders(
-            "HTTP/1.1 200 OK\n"
-            "Content-type: $1\n"
-            "Origin-Trial: $2\n"
-            "\n",
-            {content_type, origin_trial_token}, {});
-
-        URLLoaderInterceptor::WriteResponse(
-            "content/test/data/service_worker" + params->url_request.url.path(),
-            params->client.get(), &headers, std::optional<net::SSLInfo>(),
-            params->url_request.url);
-
-        if (--it->second == 0) {
-          expected_request_urls.erase(it);
-        }
-        if (expected_request_urls.empty()) {
-          run_loop.Quit();
-        }
-        return true;
-      }));
-
-  // Register a service worker.
-  WorkerRunningStatusObserver observer(public_context());
-  EXPECT_TRUE(NavigateToURL(shell(), main_page_url));
-  EXPECT_EQ("DONE", EvalJs(GetPrimaryMainFrame(),
-                           "register('/race_network_request.js')"));
-  observer.WaitUntilRunning();
-  scoped_refptr<ServiceWorkerVersion> version =
-      wrapper()->GetLiveVersion(observer.version_id());
-  EXPECT_EQ(blink::EmbeddedWorkerStatus::kRunning, version->running_status());
-
-  // Stop the current running service worker.
-  StopServiceWorker(version.get());
-  EXPECT_EQ(blink::EmbeddedWorkerStatus::kStopped, version->running_status());
-
-  // Navigate away from the service worker's scope.
-  EXPECT_TRUE(
-      NavigateToURL(shell(), embedded_test_server()->GetURL("/empty.html")));
-  EXPECT_EQ(blink::EmbeddedWorkerStatus::kStopped, version->running_status());
-
-  // Navigate to the service worker's scope.
-  EXPECT_TRUE(NavigateToURL(shell(), main_page_url_with_params));
-
-  // ServiceWorker will respond after the delay, so we expect the response from
-  // the network request initiated by the RaceNetworkRequest mode comes first.
-  EXPECT_EQ("create service worker",
-            EvalJs(GetPrimaryMainFrame(), "document.title"));
-  EXPECT_EQ(
-      "hello from the service worker\n",
-      EvalJs(GetPrimaryMainFrame(),
-             "fetch('/hello-from-sw.txt?sw_slow&sw_respond').then(response "
-             "=> response.text())"));
-
-  run_loop.Run();
+  // The final response comes from the fetch handler, which returns a custom
+  // response without requiring network request. Expect the network request by
+  // the AutoPrealod feature only when the script checksum is in the allowlist.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(ShouldUseValidChecksum() ? 1 : 0, GetRequestCount(relative_url));
+  EXPECT_EQ("[ServiceWorkerRaceNetworkRequest] Response from the fetch handler",
+            GetInnerText());
 }
 
-class ServiceWorkerRaceNetworkRequestOptOutBrowserTest
-    : public ServiceWorkerRaceNetworkRequestBrowserTest {
+class ServiceWorkerAutoPreloadOptOutBrowserTest
+    : public ServiceWorkerAutoPreloadBrowserTest {
  public:
-  ServiceWorkerRaceNetworkRequestOptOutBrowserTest() {
+  ServiceWorkerAutoPreloadOptOutBrowserTest() {
     feature_list_.InitWithFeaturesAndParameters(
         {
-            {features::kServiceWorkerBypassFetchHandler,
-             {{"strategy", "optin"},
-              {"bypass_for", "all_with_race_network_request"}}},
-            {features::kServiceWorkerStaticRouter, {}},
+            {features::kServiceWorkerAutoPreload, {{"strategy", "optin"}}},
             {blink::features::kServiceWorkerStaticRouterNotConditionEnabled,
              {}},
         },
         {});
   }
-  ~ServiceWorkerRaceNetworkRequestOptOutBrowserTest() override = default;
+  ~ServiceWorkerAutoPreloadOptOutBrowserTest() override = default;
 
   base::test::ScopedFeatureList feature_list_;
 };
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestOptOutBrowserTest,
+INSTANTIATE_TEST_SUITE_P(ALL,
+                         ServiceWorkerAutoPreloadOptOutBrowserTest,
+                         testing::Bool());
+
+IN_PROC_BROWSER_TEST_P(ServiceWorkerAutoPreloadOptOutBrowserTest,
                        MainResourceFetchHandlerShouldNotRace) {
   SetupAndRegisterServiceWorker();
   const std::string relative_url = "/service_worker/no_race?sw_slow&sw_respond";
@@ -6937,7 +6601,7 @@
   EXPECT_EQ(0, GetRequestCount(relative_url));
 }
 
-IN_PROC_BROWSER_TEST_F(ServiceWorkerRaceNetworkRequestOptOutBrowserTest,
+IN_PROC_BROWSER_TEST_P(ServiceWorkerAutoPreloadOptOutBrowserTest,
                        SubresourceFetchHandlerShouldNotRace) {
   SetupAndRegisterServiceWorker();
   WorkerRunningStatusObserver observer(public_context());
@@ -7089,7 +6753,7 @@
     } else if (type == TestType::kRaceNetworkAndFetch) {
       ASSERT_EQ("DONE",
                 EvalJs(GetPrimaryMainFrame(),
-                       "register('/service_worker/race_network_request.js')"));
+                       "register('/service_worker/static_router_race.js')"));
     }
     observer1.WaitUntilRunning();
     active_version_ = wrapper()->GetLiveVersion(observer1.version_id());
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.cc b/content/browser/service_worker/service_worker_controllee_request_handler.cc
index bbe546d..9d52914 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -87,72 +87,6 @@
       return "empty fetch handler";
   }
 }
-
-bool ShouldBypassFetchHandlerForMainResource(ServiceWorkerVersion& version) {
-  if (!base::FeatureList::IsEnabled(
-          features::kServiceWorkerBypassFetchHandler)) {
-    return false;
-  }
-
-  if (features::kServiceWorkerBypassFetchHandlerTarget.Get() !=
-      features::ServiceWorkerBypassFetchHandlerTarget::kMainResource) {
-    return false;
-  }
-
-  // If the feature is enabled, the main resource request bypasses ServiceWorker
-  // and starts the worker in parallel for subsequent subresources.
-  switch (features::kServiceWorkerBypassFetchHandlerStrategy.Get()) {
-    // kFeatureOptIn means that the feature relies on the manual feature
-    // toggle from about://flags etc, which is triggered by developers. We
-    // bypass fetch handler regardless of the url matching in this case.
-    case features::ServiceWorkerBypassFetchHandlerStrategy::kFeatureOptIn:
-      RecordSkipReason(
-          ServiceWorkerControlleeRequestHandler::FetchHandlerSkipReason::
-              kMainResourceSkippedDueToFeatureFlag);
-      return true;
-    // If kAllowList, the allowlist should be specified. In this case, main
-    // resource fetch handlers are bypassed only when the sha256 checksum of the
-    // script is in the allowlist.
-    case features::ServiceWorkerBypassFetchHandlerStrategy::kAllowList:
-      if (content::service_worker_loader_helpers::
-              FetchHandlerBypassedHashStrings()
-                  .contains(version.sha256_script_checksum())) {
-        version.CountFeature(
-            blink::mojom::WebFeature::
-                kServiceWorkerBypassFetchHandlerForMainResource);
-        RecordSkipReason(
-            ServiceWorkerControlleeRequestHandler::FetchHandlerSkipReason::
-                kMainResourceSkippedBecauseMatchedWithAllowedScriptList);
-        return true;
-      }
-      return false;
-  }
-
-  NOTREACHED();
-  return false;
-}
-
-bool ShouldBypassFetchHandlerForMainResourceByOriginTrial(
-    ServiceWorkerVersion& version) {
-  if (version.origin_trial_tokens() &&
-      version.origin_trial_tokens()->contains(
-          "ServiceWorkerBypassFetchHandlerForMainResource")) {
-    RecordSkipReason(
-        ServiceWorkerControlleeRequestHandler::FetchHandlerSkipReason::
-            kMainResourceSkippedDueToOriginTrial);
-    // The UseCounter for
-    // kServiceWorkerBypassFetchHandlerForMainResourceByOriginTrial should only
-    // capture the usage of this feature invoked by the Origin Trial for the OT
-    // measurement purpose.
-    version.CountFeature(
-        blink::mojom::WebFeature::
-            kServiceWorkerBypassFetchHandlerForMainResourceByOriginTrial);
-    return true;
-  }
-
-  return false;
-}
-
 }  // namespace
 
 std::optional<int> ServiceWorkerControlleeRequestHandler::
@@ -572,62 +506,6 @@
       return;
     }
     case ServiceWorkerVersion::FetchHandlerType::kNotSkippable: {
-      // When FetchHandlerType::kNotSkippable, then check if the fetch handler
-      // should bypassed or not. First, check the origin trial token. If there
-      // is no valid origin trial token, then check the eligibility based on the
-      // feature flag and the url.
-      if (ShouldBypassFetchHandlerForMainResourceByOriginTrial(
-              *active_version) ||
-          ShouldBypassFetchHandlerForMainResource(*active_version)) {
-        // If true, the main resource request bypasses ServiceWorker and starts
-        // the worker in parallel for subsequent subresources.
-        CompleteWithoutLoader();
-        MaybeStartServiceWorker(
-            std::move(active_version),
-            ServiceWorkerMetrics::EventType::BYPASS_MAIN_RESOURCE);
-        return;
-      }
-      // If the feature param ServiceWorkerBypassFetchHandlerTarget is
-      // |kAllOnlyIfServiceWorkerNotStarted| takes effect and the ServiceWorker
-      // isn't started yet, skip the fetch handler and then start the
-      // ServiceWorker.
-      if (base::FeatureList::IsEnabled(
-              features::kServiceWorkerBypassFetchHandler) &&
-          features::kServiceWorkerBypassFetchHandlerTarget.Get() ==
-              features::ServiceWorkerBypassFetchHandlerTarget::
-                  kAllOnlyIfServiceWorkerNotStarted) {
-        switch (active_version->running_status()) {
-          case blink::EmbeddedWorkerStatus::kStopped:
-          case blink::EmbeddedWorkerStatus::kStopping:
-          case blink::EmbeddedWorkerStatus::kStarting:
-            // If the status is STARTING, the Serviceworker is not actually
-            // started yet. So it makes sense to skip the fetch handler.
-            active_version->set_fetch_handler_bypass_option(
-                blink::mojom::ServiceWorkerFetchHandlerBypassOption::
-                    kBypassOnlyIfServiceWorkerNotStarted);
-            CompleteWithoutLoader();
-            RecordSkipReason(
-                active_version->running_status() ==
-                        blink::EmbeddedWorkerStatus::kStarting
-                    ? FetchHandlerSkipReason::
-                          kBypassFetchHandlerForAllOnlyIfServiceWorkerNotStarted_Status_Starting
-                    : FetchHandlerSkipReason::
-                          kBypassFetchHandlerForAllOnlyIfServiceWorkerNotStarted_Status_Stop);
-            base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-                FROM_HERE,
-                base::BindOnce(&ServiceWorkerControlleeRequestHandler::
-                                   MaybeStartServiceWorker,
-                               weak_factory_.GetWeakPtr(),
-                               std::move(active_version),
-                               ServiceWorkerMetrics::EventType::
-                                   BYPASS_ONLY_IF_SERVICE_WORKER_NOT_STARTED));
-            return;
-          case blink::EmbeddedWorkerStatus::kRunning:
-            active_version->set_fetch_handler_bypass_option(
-                blink::mojom::ServiceWorkerFetchHandlerBypassOption::kDefault);
-            break;
-        }
-      }
       // Otherwise, record the skip reason as kNotSkipped.
       RecordSkipReason(FetchHandlerSkipReason::kNotSkipped);
       TRACE_EVENT_WITH_FLOW1(
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.h b/content/browser/service_worker/service_worker_controllee_request_handler.h
index 1f5c9029..0ab206f6 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler.h
+++ b/content/browser/service_worker/service_worker_controllee_request_handler.h
@@ -62,15 +62,15 @@
     kNoFetchHandler = 0,
     kNotSkipped = 1,
     kSkippedForEmptyFetchHandler = 2,
-    kMainResourceSkippedDueToOriginTrial = 3,
-    kMainResourceSkippedDueToFeatureFlag = 4,
+    // kMainResourceSkippedDueToOriginTrial = 3,
+    // kMainResourceSkippedDueToFeatureFlag = 4,
     // kMainResourceSkippedBecauseMatchedWithAllowedOriginList = 5,
-    kMainResourceSkippedBecauseMatchedWithAllowedScriptList = 6,
-    kBypassFetchHandlerForAllOnlyIfServiceWorkerNotStarted_Status_Stop = 7,
-    kBypassFetchHandlerForAllOnlyIfServiceWorkerNotStarted_Status_Starting = 8,
+    // kMainResourceSkippedBecauseMatchedWithAllowedScriptList = 6,
+    // kBypassFetchHandlerForAllOnlyIfServiceWorkerNotStarted_Status_Stop = 7,
+    // kBypassFetchHandlerForAllOnlyIfServiceWorkerNotStarted_Status_Starting =
+    // 8,
 
-    kMaxValue =
-        kBypassFetchHandlerForAllOnlyIfServiceWorkerNotStarted_Status_Starting,
+    kMaxValue = kSkippedForEmptyFetchHandler,
   };
 
   // Default duration to start fetch handler when service worker is started in
@@ -160,11 +160,8 @@
 
   // Runs after ServiceWorker has started.
   // Normally ServiceWorker starts before dispatching the main resource request,
-  // but if the ServiceWorkerBypassFetchHandler feature is enabled, we bypass
-  // the main resource request and then start ServiceWorker for subresources.
-  // Also, if we decided to start the service worker for
-  // the ServiceWorkerSkipEmptyFetchHandler feature and the browser handles
-  // an empty fetch handler, this runs after the service worker starts.
+  // but if the browser handles an empty fetch handler, this runs after the
+  // service worker starts.
   void DidStartWorker(blink::ServiceWorkerStatusCode status);
 
   int GetServiceWorkerForEmptyFetchHandlerDurationMs();
diff --git a/content/browser/service_worker/service_worker_main_resource_loader.cc b/content/browser/service_worker/service_worker_main_resource_loader.cc
index 8071590..e573273e 100644
--- a/content/browser/service_worker/service_worker_main_resource_loader.cc
+++ b/content/browser/service_worker/service_worker_main_resource_loader.cc
@@ -78,45 +78,12 @@
 // Check the eligibility based on the allowlist. This doesn't mean the
 // experiment is actually enabled. The eligibility is checked and UMA is
 // reported for the analysis purpose.
-bool HasRaceNetworkRequestEligibleScript(
-    scoped_refptr<ServiceWorkerVersion> version) {
+bool HasAutoPreloadEligibleScript(scoped_refptr<ServiceWorkerVersion> version) {
   return content::service_worker_loader_helpers::
       FetchHandlerBypassedHashStrings()
           .contains(version->sha256_script_checksum());
 }
 
-bool IsEligibleForRaceNetworkRequestByOriginTrial(
-    scoped_refptr<ServiceWorkerVersion> version) {
-  return version->origin_trial_tokens() &&
-         version->origin_trial_tokens()->contains(
-             "ServiceWorkerBypassFetchHandlerWithRaceNetworkRequest");
-}
-
-bool IsEligibleForRaceNetworkRequest(
-    scoped_refptr<ServiceWorkerVersion> version) {
-  if (!base::FeatureList::IsEnabled(
-          features::kServiceWorkerBypassFetchHandler)) {
-    return false;
-  }
-  if (features::kServiceWorkerBypassFetchHandlerTarget.Get() !=
-      features::ServiceWorkerBypassFetchHandlerTarget::
-          kAllWithRaceNetworkRequest) {
-    return false;
-  }
-
-  switch (features::kServiceWorkerBypassFetchHandlerStrategy.Get()) {
-    // kFeatureOptIn means that the feature relies on the manual feature
-    // toggle from about://flags etc, which is triggered by developers.
-    case features::ServiceWorkerBypassFetchHandlerStrategy::kFeatureOptIn:
-      return true;
-    // If kAllowList, the allowlist should be specified. In this case,
-    // RaceNetworkRequest is allowed only when the sha256 checksum of the
-    // script is in the allowlist.
-    case features::ServiceWorkerBypassFetchHandlerStrategy::kAllowList:
-      return HasRaceNetworkRequestEligibleScript(version);
-  }
-}
-
 std::string GetContainerHostClientId(int frame_tree_node_id) {
   std::string client_uuid;
   auto* frame_tree_node = FrameTreeNode::GloballyFindByID(frame_tree_node_id);
@@ -451,39 +418,34 @@
   switch (race_network_request_mode) {
     case RaceNetworkRequestMode::kForced:
       if (StartRaceNetworkRequest(context_wrapper, version)) {
-        return;
+        SetDispatchedPreloadType(DispatchedPreloadType::kRaceNetworkRequest);
       }
       break;
     case RaceNetworkRequestMode::kDefault:
-      if (MaybeStartRaceNetworkRequest(context_wrapper, version)) {
-        return;
+      if (base::GetFieldTrialParamByFeatureAsBool(
+              features::kServiceWorkerAutoPreload, "respect_navigation_preload",
+              /*default_value=*/true)) {
+        // Prioritize NavigationPreload than AutoPreload if the
+        // respect_navigation_preload feature param is true.
+        if (MaybeStartNavigationPreload(context_wrapper)) {
+          return;
+        }
+        if (MaybeStartAutoPreload(context_wrapper, version)) {
+          return;
+        }
+      } else {
+        if (MaybeStartAutoPreload(context_wrapper, version)) {
+          return;
+        }
+        if (MaybeStartNavigationPreload(context_wrapper)) {
+          return;
+        }
       }
       break;
     case RaceNetworkRequestMode::kSkipped:
+      MaybeStartNavigationPreload(context_wrapper);
       break;
   }
-
-  bool respect_navigation_preload = base::GetFieldTrialParamByFeatureAsBool(
-      features::kServiceWorkerAutoPreload, "respect_navigation_preload",
-      /*default_value=*/true);
-
-  if (respect_navigation_preload) {
-    // Prioritize NavigationPreload than AutoPreload if the
-    // respect_navigation_preload feature param is true.
-    if (MaybeStartNavigationPreload(context_wrapper)) {
-      return;
-    }
-    if (MaybeStartAutoPreload(context_wrapper, version)) {
-      return;
-    }
-  } else {
-    if (MaybeStartAutoPreload(context_wrapper, version)) {
-      return;
-    }
-    if (MaybeStartNavigationPreload(context_wrapper)) {
-      return;
-    }
-  }
 }
 
 bool ServiceWorkerMainResourceLoader::MaybeStartAutoPreload(
@@ -501,7 +463,7 @@
   bool use_allowlist = base::GetFieldTrialParamByFeatureAsBool(
       features::kServiceWorkerAutoPreload, "use_allowlist",
       /*default_value=*/false);
-  if (use_allowlist && !HasRaceNetworkRequestEligibleScript(version)) {
+  if (use_allowlist && !HasAutoPreloadEligibleScript(version)) {
     return false;
   }
 
@@ -553,42 +515,6 @@
   return result;
 }
 
-bool ServiceWorkerMainResourceLoader::MaybeStartRaceNetworkRequest(
-    scoped_refptr<ServiceWorkerContextWrapper> context,
-    scoped_refptr<ServiceWorkerVersion> version) {
-  bool is_enabled_by_feature_flag = IsEligibleForRaceNetworkRequest(version);
-  bool is_enabled_by_origin_trial =
-      IsEligibleForRaceNetworkRequestByOriginTrial(version);
-
-  if (!(is_enabled_by_feature_flag || is_enabled_by_origin_trial)) {
-    // Even if the feature is not enabled, if the SW has an eligible script, set
-    // the option as |kRaceNetworkRequestHoldback| for the measuring purpose.
-    if (HasRaceNetworkRequestEligibleScript(version)) {
-      version->set_fetch_handler_bypass_option(
-          blink::mojom::ServiceWorkerFetchHandlerBypassOption::
-              kRaceNetworkRequestHoldback);
-    }
-    return false;
-  }
-
-  bool result = StartRaceNetworkRequest(context, version);
-  if (is_enabled_by_origin_trial) {
-    version->CountFeature(
-        blink::mojom::WebFeature::
-            kServiceWorkerBypassFetchHandlerForAllWithRaceNetworkRequestByOriginTrial);
-  } else if (is_enabled_by_feature_flag) {
-    version->CountFeature(
-        blink::mojom::WebFeature::
-            kServiceWorkerBypassFetchHandlerForAllWithRaceNetworkRequest);
-  }
-
-  if (result) {
-    SetDispatchedPreloadType(DispatchedPreloadType::kRaceNetworkRequest);
-  }
-
-  return result;
-}
-
 bool ServiceWorkerMainResourceLoader::StartRaceNetworkRequest(
     scoped_refptr<ServiceWorkerContextWrapper> context,
     scoped_refptr<ServiceWorkerVersion> version) {
diff --git a/content/browser/service_worker/service_worker_main_resource_loader.h b/content/browser/service_worker/service_worker_main_resource_loader.h
index 0f621ed..c7f1cf8 100644
--- a/content/browser/service_worker/service_worker_main_resource_loader.h
+++ b/content/browser/service_worker/service_worker_main_resource_loader.h
@@ -229,10 +229,6 @@
       scoped_refptr<ServiceWorkerContextWrapper> context_wrapper,
       scoped_refptr<ServiceWorkerVersion> version);
 
-  bool MaybeStartRaceNetworkRequest(
-      scoped_refptr<ServiceWorkerContextWrapper> context_wrapper,
-      scoped_refptr<ServiceWorkerVersion> version);
-
   // Returns false if fails to start the race network request.
   // The caller should run the regular path instead.
   bool StartRaceNetworkRequest(
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h
index 0460688..3ded083c 100644
--- a/content/browser/service_worker/service_worker_version.h
+++ b/content/browser/service_worker/service_worker_version.h
@@ -241,8 +241,8 @@
   void set_fetch_handler_type(FetchHandlerType fetch_handler_type);
 
   // Return the option indicating how the fetch handler should be bypassed.
-  // ServiceWorkerBypassFetchHandler feature uses this to let the renderer know
-  // to bypass fetch handlers for subresources.
+  // This is used to let the renderer know to bypass fetch handlers for
+  // subresources.
   FetchHandlerBypassOption fetch_handler_bypass_option() {
     return fetch_handler_bypass_option_;
   }
diff --git a/content/child/blink_platform_impl.cc b/content/child/blink_platform_impl.cc
index 3f5849a..a67c09e5 100644
--- a/content/child/blink_platform_impl.cc
+++ b/content/child/blink_platform_impl.cc
@@ -7,6 +7,7 @@
 #include <math.h>
 
 #include <memory>
+#include <string_view>
 #include <vector>
 
 #include "base/command_line.h"
@@ -20,7 +21,6 @@
 #include "base/run_loop.h"
 #include "base/sequence_checker.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/lock.h"
@@ -160,7 +160,7 @@
 WebData BlinkPlatformImpl::GetDataResource(
     int resource_id,
     ui::ResourceScaleFactor scale_factor) {
-  base::StringPiece resource =
+  std::string_view resource =
       GetContentClient()->GetDataResource(resource_id, scale_factor);
   return WebData(resource.data(), resource.size());
 }
diff --git a/content/child/dwrite_font_proxy/dwrite_localized_strings_win.cc b/content/child/dwrite_font_proxy/dwrite_localized_strings_win.cc
index 8fb97bd6..c7fff85 100644
--- a/content/child/dwrite_font_proxy/dwrite_localized_strings_win.cc
+++ b/content/child/dwrite_font_proxy/dwrite_localized_strings_win.cc
@@ -4,10 +4,9 @@
 
 #include "content/child/dwrite_font_proxy/dwrite_localized_strings_win.h"
 
-#include "base/strings/string_piece.h"
-
 #include <stddef.h>
 
+#include <string_view>
 
 namespace content {
 
@@ -19,7 +18,7 @@
                                                UINT32* index,
                                                BOOL* exists) {
   static_assert(sizeof(WCHAR) == sizeof(char16_t), "WCHAR should be UTF-16.");
-  const base::StringPiece16 locale_name_str(
+  const std::u16string_view locale_name_str(
       reinterpret_cast<const char16_t*>(locale_name));
   for (size_t n = 0; n < strings_.size(); ++n) {
     if (strings_[n].first == locale_name_str) {
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 500bc649..671eec05 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -340,8 +340,6 @@
 #endif
           {wf::EnableRemoveMobileViewportDoubleTap,
            raw_ref(features::kRemoveMobileViewportDoubleTap)},
-          {wf::EnableServiceWorkerBypassFetchHandler,
-           raw_ref(features::kServiceWorkerBypassFetchHandler)},
           {wf::EnableServiceWorkerStaticRouter,
            raw_ref(features::kServiceWorkerStaticRouter)},
       };
diff --git a/content/common/content_switches_internal.cc b/content/common/content_switches_internal.cc
index 4f6a4731..2ff46a1 100644
--- a/content/common/content_switches_internal.cc
+++ b/content/common/content_switches_internal.cc
@@ -43,7 +43,7 @@
 
 #if BUILDFLAG(IS_WIN)
 
-std::wstring ToNativeString(base::StringPiece string) {
+std::wstring ToNativeString(std::string_view string) {
   return base::ASCIIToWide(string);
 }
 
diff --git a/content/common/service_worker/race_network_request_url_loader_client.cc b/content/common/service_worker/race_network_request_url_loader_client.cc
index 78c279b..86ec1d1a 100644
--- a/content/common/service_worker/race_network_request_url_loader_client.cc
+++ b/content/common/service_worker/race_network_request_url_loader_client.cc
@@ -874,8 +874,9 @@
         "This request is issued by a navigation to fetch the content of the "
         "page that is being navigated to, or by a renderer to fetch "
         "subresources in the case where a service worker has been registered "
-        "for the page and the ServiceWorkerBypassFetchHandler feature and the "
-        "RaceNetworkRequest param are enabled."
+        "for the page and the ServiceWorkerAutoPreload feature is enabled, or "
+        "`race-network-and-fetch-handler` source in the Service Worker Static "
+        "Routing API is specified."
       trigger:
         "Navigating Chrome (by clicking on a link, bookmark, history item, "
         "using session restore, etc) and subsequent resource loading."
diff --git a/content/public/browser/authenticator_request_client_delegate.cc b/content/public/browser/authenticator_request_client_delegate.cc
index 79446c9..26b3b74 100644
--- a/content/public/browser/authenticator_request_client_delegate.cc
+++ b/content/public/browser/authenticator_request_client_delegate.cc
@@ -4,11 +4,11 @@
 
 #include "content/public/browser/authenticator_request_client_delegate.h"
 
+#include <string_view>
 #include <utility>
 
 #include "base/functional/callback.h"
 #include "base/functional/callback_helpers.h"
-#include "base/strings/string_piece.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "content/browser/webauth/authenticator_environment.h"
@@ -215,7 +215,7 @@
     const device::FidoAuthenticator& authenticator) {}
 
 void AuthenticatorRequestClientDelegate::FidoAuthenticatorRemoved(
-    base::StringPiece device_id) {}
+    std::string_view device_id) {}
 
 bool AuthenticatorRequestClientDelegate::SupportsPIN() const {
   return false;
diff --git a/content/public/browser/authenticator_request_client_delegate.h b/content/public/browser/authenticator_request_client_delegate.h
index 12d0bc2..186e501 100644
--- a/content/public/browser/authenticator_request_client_delegate.h
+++ b/content/public/browser/authenticator_request_client_delegate.h
@@ -7,6 +7,7 @@
 
 #include <optional>
 #include <string>
+#include <string_view>
 
 #include "base/containers/span.h"
 #include "base/functional/callback_forward.h"
@@ -369,7 +370,7 @@
   void BluetoothAdapterPowerChanged(bool is_powered_on) override;
   void FidoAuthenticatorAdded(
       const device::FidoAuthenticator& authenticator) override;
-  void FidoAuthenticatorRemoved(base::StringPiece device_id) override;
+  void FidoAuthenticatorRemoved(std::string_view device_id) override;
   bool SupportsPIN() const override;
   void CollectPIN(
       CollectPINOptions options,
diff --git a/content/public/browser/back_forward_cache.h b/content/public/browser/back_forward_cache.h
index 388d89a..f2671c8cc 100644
--- a/content/public/browser/back_forward_cache.h
+++ b/content/public/browser/back_forward_cache.h
@@ -10,7 +10,6 @@
 #include <optional>
 #include <set>
 
-#include "base/strings/string_piece.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/global_routing_id.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
diff --git a/content/public/browser/background_tracing_manager.h b/content/public/browser/background_tracing_manager.h
index ad0f038d2..2f5ca395 100644
--- a/content/public/browser/background_tracing_manager.h
+++ b/content/public/browser/background_tracing_manager.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/strings/string_piece.h"
 #include "base/time/time.h"
 #include "base/token.h"
 #include "base/trace_event/trace_event_impl.h"
diff --git a/content/public/browser/child_process_security_policy.h b/content/public/browser/child_process_security_policy.h
index 186baf81a..4c1312c 100644
--- a/content/public/browser/child_process_security_policy.h
+++ b/content/public/browser/child_process_security_policy.h
@@ -7,6 +7,7 @@
 
 #include <optional>
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include "content/common/content_export.h"
@@ -340,7 +341,7 @@
   // Note that wildcards can only be added using this version of
   // AddFutureIsolatedOrigins(); they cannot be specified in a url::Origin().
   virtual void AddFutureIsolatedOrigins(
-      base::StringPiece origins_to_add,
+      std::string_view origins_to_add,
       IsolatedOriginSource source,
       BrowserContext* browser_context = nullptr) = 0;
 
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 3888089..5fb0d5f 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -5,6 +5,7 @@
 #include "content/public/browser/content_browser_client.h"
 
 #include <optional>
+#include <string_view>
 #include <utility>
 
 #include "base/check.h"
@@ -13,7 +14,6 @@
 #include "base/functional/callback_helpers.h"
 #include "base/no_destructor.h"
 #include "base/notreached.h"
-#include "base/strings/string_piece.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/thread_pool/thread_pool_instance.h"
 #include "base/values.h"
@@ -186,13 +186,13 @@
 }
 
 bool ContentBrowserClient::ShouldTreatURLSchemeAsFirstPartyWhenTopLevel(
-    base::StringPiece scheme,
+    std::string_view scheme,
     bool is_embedded_origin_secure) {
   return false;
 }
 
 bool ContentBrowserClient::ShouldIgnoreSameSiteCookieRestrictionsWhenTopLevel(
-    base::StringPiece scheme,
+    std::string_view scheme,
     bool is_embedded_origin_secure) {
   return false;
 }
@@ -1188,7 +1188,7 @@
   return false;
 }
 
-bool ContentBrowserClient::CreateThreadPool(base::StringPiece name) {
+bool ContentBrowserClient::CreateThreadPool(std::string_view name) {
   base::ThreadPoolInstance::Create(name);
   return true;
 }
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 0956279..9983d8b 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -12,13 +12,13 @@
 #include <optional>
 #include <set>
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include "base/containers/flat_map.h"
 #include "base/containers/flat_set.h"
 #include "base/functional/callback_forward.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/strings/string_piece.h"
 #include "base/time/time.h"
 #include "base/types/strong_alias.h"
 #include "base/values.h"
@@ -461,7 +461,7 @@
   // matching_scheme_cookies_allowed_schemes, but maybe we should remove that
   // anyway.
   virtual bool ShouldTreatURLSchemeAsFirstPartyWhenTopLevel(
-      base::StringPiece scheme,
+      std::string_view scheme,
       bool is_embedded_origin_secure);
 
   // Similar to the above. Returns whether SameSite cookie restrictions should
@@ -472,7 +472,7 @@
   // be different, as SameSite restrictions and third-party cookie blocking are
   // related but have different semantics.
   virtual bool ShouldIgnoreSameSiteCookieRestrictionsWhenTopLevel(
-      base::StringPiece scheme,
+      std::string_view scheme,
       bool is_embedded_origin_secure);
 
   // Gets a user friendly display name for a given |site_url| to be used in the
@@ -2164,7 +2164,7 @@
   // ThreadPoolInstance was created.
   // Note: the embedder should *not* start the ThreadPoolInstance for
   // BrowserMainLoop, BrowserMainLoop itself is responsible for that.
-  virtual bool CreateThreadPool(base::StringPiece name);
+  virtual bool CreateThreadPool(std::string_view name);
 
   // Returns true if the tab security level is acceptable to allow WebAuthn
   // requests, false otherwise. This is not attached to
diff --git a/content/public/browser/document_service.h b/content/public/browser/document_service.h
index 81dc8237..f0bb70a 100644
--- a/content/public/browser/document_service.h
+++ b/content/public/browser/document_service.h
@@ -6,12 +6,12 @@
 #define CONTENT_PUBLIC_BROWSER_DOCUMENT_SERVICE_H_
 
 #include <cstdint>
+#include <string_view>
 #include <utility>
 
 #include "base/check.h"
 #include "base/compiler_specific.h"
 #include "base/functional/bind.h"
-#include "base/strings/string_piece.h"
 #include "base/threading/thread_checker.h"
 #include "content/public/browser/document_service_internal.h"
 #include "content/public/browser/render_frame_host.h"
@@ -128,7 +128,7 @@
   //
   // Prefer over `mojo::ReportBadMessage()`, since using this method avoids the
   // need to run any pending reply callbacks with placeholder arguments.
-  NOT_TAIL_CALLED void ReportBadMessageAndDeleteThis(base::StringPiece error) {
+  NOT_TAIL_CALLED void ReportBadMessageAndDeleteThis(std::string_view error) {
     receiver_.ReportBadMessage(error);
     delete this;
   }
@@ -136,7 +136,7 @@
   // Resets the `mojo::Receiver` with a `reason` and `description` and deletes
   // `this`.
   void ResetWithReasonAndDeleteThis(uint32_t reason,
-                                    base::StringPiece description) {
+                                    std::string_view description) {
     receiver_.ResetWithReason(reason, description);
     delete this;
   }
diff --git a/content/public/browser/gpu_utils.cc b/content/public/browser/gpu_utils.cc
index 9e464331..6b5339b 100644
--- a/content/public/browser/gpu_utils.cc
+++ b/content/public/browser/gpu_utils.cc
@@ -5,6 +5,7 @@
 #include "content/public/browser/gpu_utils.h"
 
 #include <string>
+#include <string_view>
 
 #include "base/command_line.h"
 #include "base/functional/bind.h"
@@ -42,7 +43,7 @@
 }
 
 bool GetUintFromSwitch(const base::CommandLine* command_line,
-                       const base::StringPiece& switch_string,
+                       const std::string_view& switch_string,
                        uint32_t* value) {
   std::string switch_value(command_line->GetSwitchValueASCII(switch_string));
   return base::StringToUint(switch_value, value);
diff --git a/content/public/browser/mojo_binder_policy_map.h b/content/public/browser/mojo_binder_policy_map.h
index 1c92eed..778d9b9 100644
--- a/content/public/browser/mojo_binder_policy_map.h
+++ b/content/public/browser/mojo_binder_policy_map.h
@@ -5,8 +5,9 @@
 #ifndef CONTENT_PUBLIC_BROWSER_MOJO_BINDER_POLICY_MAP_H_
 #define CONTENT_PUBLIC_BROWSER_MOJO_BINDER_POLICY_MAP_H_
 
+#include <string_view>
+
 #include "base/check_op.h"
-#include "base/strings/string_piece.h"
 #include "content/common/content_export.h"
 
 namespace content {
@@ -67,10 +68,10 @@
   }
 
  private:
-  virtual void SetPolicyByName(const base::StringPiece& name,
+  virtual void SetPolicyByName(const std::string_view& name,
                                MojoBinderAssociatedPolicy policy) = 0;
 
-  virtual void SetPolicyByName(const base::StringPiece& name,
+  virtual void SetPolicyByName(const std::string_view& name,
                                MojoBinderNonAssociatedPolicy policy) = 0;
 };
 
diff --git a/content/public/browser/origin_trials_controller_delegate.h b/content/public/browser/origin_trials_controller_delegate.h
index 230b9cd8..0e75d479 100644
--- a/content/public/browser/origin_trials_controller_delegate.h
+++ b/content/public/browser/origin_trials_controller_delegate.h
@@ -9,7 +9,6 @@
 
 #include "base/containers/flat_set.h"
 #include "base/observer_list_types.h"
-#include "base/strings/string_piece.h"
 #include "base/time/time.h"
 #include "content/common/content_export.h"
 #include "third_party/blink/public/mojom/origin_trial_feature/origin_trial_feature.mojom-shared.h"
diff --git a/content/public/browser/service_process_host.h b/content/public/browser/service_process_host.h
index f39b0299..0062d2c 100644
--- a/content/public/browser/service_process_host.h
+++ b/content/public/browser/service_process_host.h
@@ -15,7 +15,6 @@
 #include "base/functional/callback.h"
 #include "base/observer_list_types.h"
 #include "base/process/process_handle.h"
-#include "base/strings/string_piece.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/service_process_info.h"
 #include "mojo/public/cpp/bindings/generic_pending_receiver.h"
diff --git a/content/public/browser/web_contents_media_capture_id.cc b/content/public/browser/web_contents_media_capture_id.cc
index 44cb121..4f83528a 100644
--- a/content/public/browser/web_contents_media_capture_id.cc
+++ b/content/public/browser/web_contents_media_capture_id.cc
@@ -4,10 +4,10 @@
 
 #include "content/public/browser/web_contents_media_capture_id.h"
 
+#include <string_view>
 #include <tuple>
 
 #include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 
 namespace {
@@ -29,12 +29,12 @@
   if (sep_pos == std::string::npos)
     return false;
 
-  const base::StringPiece component1(device_id.data(), sep_pos);
+  const std::string_view component1(device_id.data(), sep_pos);
   size_t end_pos = device_id.find('?');
   if (end_pos == std::string::npos)
     end_pos = device_id.length();
-  const base::StringPiece component2(device_id.data() + sep_pos + 1,
-                                     end_pos - sep_pos - 1);
+  const std::string_view component2(device_id.data() + sep_pos + 1,
+                                    end_pos - sep_pos - 1);
 
   return (base::StringToInt(component1, render_process_id) &&
           base::StringToInt(component2, main_render_frame_id));
@@ -57,8 +57,8 @@
     option_pos_end = device_id.find(kOptionSeparator, option_pos + 1);
     if (option_pos_end == std::string::npos)
       option_pos_end = device_id.length();
-    const base::StringPiece component(device_id.data() + option_pos + 1,
-                                      option_pos_end - option_pos - 1);
+    const std::string_view component(device_id.data() + option_pos + 1,
+                                     option_pos_end - option_pos - 1);
 
     if (component.compare(kDisableLocalEchoFlag) == 0)
       *disable_local_echo = true;
diff --git a/content/public/browser/web_ui.h b/content/public/browser/web_ui.h
index 1f517a28..6d2eea5 100644
--- a/content/public/browser/web_ui.h
+++ b/content/public/browser/web_ui.h
@@ -7,12 +7,12 @@
 
 #include <memory>
 #include <string>
+#include <string_view>
 #include <utility>
 #include <vector>
 
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
-#include "base/strings/string_piece.h"
 #include "base/values.h"
 #include "content/common/content_export.h"
 #include "ui/base/page_transition_types.h"
@@ -41,9 +41,9 @@
   // Returns JavaScript code that, when executed, calls the function specified
   // by |function_name| with the arguments specified in |arg_list|.
   static std::u16string GetJavascriptCall(
-      base::StringPiece function_name,
+      std::string_view function_name,
       base::span<const base::ValueView> arg_list);
-  static std::u16string GetJavascriptCall(base::StringPiece function_name,
+  static std::u16string GetJavascriptCall(std::string_view function_name,
                                           const base::Value::List& arg_list);
 
   virtual ~WebUI() {}
@@ -88,12 +88,12 @@
   // the call has no effect.
   using MessageCallback =
       base::RepeatingCallback<void(const base::Value::List&)>;
-  virtual void RegisterMessageCallback(base::StringPiece message,
+  virtual void RegisterMessageCallback(std::string_view message,
                                        MessageCallback callback) = 0;
 
   template <typename... Args>
   void RegisterHandlerCallback(
-      base::StringPiece message,
+      std::string_view message,
       base::RepeatingCallback<void(Args...)> callback) {
     RegisterMessageCallback(
         message, base::BindRepeating(
@@ -121,15 +121,14 @@
   //
   // All function names in WebUI must consist of only ASCII characters.
   // There are variants for calls with more arguments.
-  virtual void CallJavascriptFunctionUnsafe(
-      base::StringPiece function_name) = 0;
+  virtual void CallJavascriptFunctionUnsafe(std::string_view function_name) = 0;
 
   virtual void CallJavascriptFunctionUnsafe(
-      base::StringPiece function_name,
+      std::string_view function_name,
       base::span<const base::ValueView> args) = 0;
 
   template <typename... Args>
-  void CallJavascriptFunctionUnsafe(base::StringPiece function_name,
+  void CallJavascriptFunctionUnsafe(std::string_view function_name,
                                     const base::ValueView arg1,
                                     const Args&... arg) {
     base::ValueView args[] = {arg1, arg...};
@@ -155,7 +154,7 @@
   template <size_t... Is, typename... Args>
   struct Call<std::index_sequence<Is...>, Args...> {
     static void Impl(base::RepeatingCallback<void(Args...)> callback,
-                     base::StringPiece message,
+                     std::string_view message,
                      const base::Value::List& list) {
       CHECK_EQ(list.size(), sizeof...(Args)) << message;
       callback.Run(GetValue<Args>(list[Is])...);
diff --git a/content/public/browser/web_ui_data_source.h b/content/public/browser/web_ui_data_source.h
index 193cddab..1420dc7 100644
--- a/content/public/browser/web_ui_data_source.h
+++ b/content/public/browser/web_ui_data_source.h
@@ -9,11 +9,11 @@
 
 #include <memory>
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include "base/containers/span.h"
 #include "base/functional/callback.h"
-#include "base/strings/string_piece.h"
 #include "base/values.h"
 #include "content/common/content_export.h"
 #include "services/network/public/mojom/content_security_policy.mojom-forward.h"
@@ -49,15 +49,15 @@
                                     const base::Value::Dict& update);
 
   // Adds a string keyed to its name to our dictionary.
-  virtual void AddString(base::StringPiece name,
+  virtual void AddString(std::string_view name,
                          const std::u16string& value) = 0;
 
   // Adds a string keyed to its name to our dictionary.
-  virtual void AddString(base::StringPiece name, const std::string& value) = 0;
+  virtual void AddString(std::string_view name, const std::string& value) = 0;
 
   // Adds a localized string with resource |ids| keyed to its name to our
   // dictionary.
-  virtual void AddLocalizedString(base::StringPiece name, int ids) = 0;
+  virtual void AddLocalizedString(std::string_view name, int ids) = 0;
 
   // Calls AddLocalizedString() in a for-loop for |strings|. Reduces code size
   // vs. reimplementing the same for-loop.
@@ -69,22 +69,22 @@
       const base::Value::Dict& localized_strings) = 0;
 
   // Adds a boolean keyed to its name to our dictionary.
-  virtual void AddBoolean(base::StringPiece name, bool value) = 0;
+  virtual void AddBoolean(std::string_view name, bool value) = 0;
 
   // Adds a signed 32-bit integer keyed to its name to our dictionary. Larger
   // integers may not be exactly representable in JavaScript. See
   // MAX_SAFE_INTEGER in /v8/src/globals.h.
-  virtual void AddInteger(base::StringPiece name, int32_t value) = 0;
+  virtual void AddInteger(std::string_view name, int32_t value) = 0;
 
   // Adds a double keyed to its name  to our dictionary.
-  virtual void AddDouble(base::StringPiece name, double value) = 0;
+  virtual void AddDouble(std::string_view name, double value) = 0;
 
   // Call this to enable a virtual "strings.js" (or "strings.m.js" for modules)
   // URL that provides translations and dynamic data when requested.
   virtual void UseStringsJs() = 0;
 
   // Adds a mapping between a path name and a resource to return.
-  virtual void AddResourcePath(base::StringPiece path, int resource_id) = 0;
+  virtual void AddResourcePath(std::string_view path, int resource_id) = 0;
 
   // Calls AddResourcePath() in a for-loop for |paths|. Reduces code size vs.
   // reimplementing the same for-loop.
@@ -148,7 +148,7 @@
   virtual std::string GetSource() = 0;
 
   // Set supported scheme if not one of the default supported schemes.
-  virtual void SetSupportedScheme(base::StringPiece scheme) = 0;
+  virtual void SetSupportedScheme(std::string_view scheme) = 0;
 };
 
 }  // namespace content
diff --git a/content/public/browser/web_ui_message_handler.h b/content/public/browser/web_ui_message_handler.h
index 0e7c23d6..04b32a8 100644
--- a/content/public/browser/web_ui_message_handler.h
+++ b/content/public/browser/web_ui_message_handler.h
@@ -6,6 +6,7 @@
 #define CONTENT_PUBLIC_BROWSER_WEB_UI_MESSAGE_HANDLER_H_
 
 #include <ostream>
+#include <string_view>
 
 #include "base/check.h"
 #include "base/gtest_prod_util.h"
@@ -88,8 +89,7 @@
   // Helper method for notifying Javascript listeners added with
   // cr.addWebUIListener() (defined in cr.js).
   template <typename... Values>
-  void FireWebUIListener(base::StringPiece event_name,
-                         const Values&... values) {
+  void FireWebUIListener(std::string_view event_name, const Values&... values) {
     // cr.webUIListenerCallback is a global JS function exposed from cr.js.
     CallJavascriptFunction("cr.webUIListenerCallback", base::Value(event_name),
                            values...);
@@ -102,7 +102,7 @@
   // All function names in WebUI must consist of only ASCII characters.
   // These functions will crash if JavaScript is not currently allowed.
   template <typename... Values>
-  void CallJavascriptFunction(base::StringPiece function_name,
+  void CallJavascriptFunction(std::string_view function_name,
                               const Values&... values) {
     CHECK(IsJavascriptAllowed()) << "Cannot CallJavascriptFunction before "
                                     "explicitly allowing JavaScript.";
diff --git a/content/public/browser/webui_config.cc b/content/public/browser/webui_config.cc
index 96a947c..e9b4330 100644
--- a/content/public/browser/webui_config.cc
+++ b/content/public/browser/webui_config.cc
@@ -4,9 +4,11 @@
 
 #include "content/public/browser/webui_config.h"
 
+#include <string_view>
+
 namespace content {
 
-WebUIConfig::WebUIConfig(base::StringPiece scheme, base::StringPiece host)
+WebUIConfig::WebUIConfig(std::string_view scheme, std::string_view host)
     : scheme_(scheme), host_(host) {}
 
 WebUIConfig::~WebUIConfig() = default;
diff --git a/content/public/browser/webui_config.h b/content/public/browser/webui_config.h
index e138e57..a6ae1c2 100644
--- a/content/public/browser/webui_config.h
+++ b/content/public/browser/webui_config.h
@@ -7,8 +7,8 @@
 
 #include <memory>
 #include <string>
+#include <string_view>
 
-#include "base/strings/string_piece.h"
 #include "content/common/content_export.h"
 #include "url/gurl.h"
 
@@ -31,7 +31,7 @@
 // all existing WebUI pages use this.
 class CONTENT_EXPORT WebUIConfig {
  public:
-  explicit WebUIConfig(base::StringPiece scheme, base::StringPiece host);
+  explicit WebUIConfig(std::string_view scheme, std::string_view host);
   virtual ~WebUIConfig();
   WebUIConfig(const WebUIConfig&) = delete;
   WebUIConfig& operator=(const WebUIConfig&) = delete;
@@ -76,7 +76,7 @@
 template <typename T>
 class CONTENT_EXPORT DefaultWebUIConfig : public WebUIConfig {
  public:
-  explicit DefaultWebUIConfig(base::StringPiece scheme, base::StringPiece host)
+  explicit DefaultWebUIConfig(std::string_view scheme, std::string_view host)
       : WebUIConfig(scheme, host) {}
   ~DefaultWebUIConfig() override = default;
 
diff --git a/content/public/common/content_client.cc b/content/public/common/content_client.cc
index 617960a..c558c75 100644
--- a/content/public/common/content_client.cc
+++ b/content/public/common/content_client.cc
@@ -4,10 +4,11 @@
 
 #include "content/public/common/content_client.h"
 
+#include <string_view>
+
 #include "base/memory/ref_counted_memory.h"
 #include "base/no_destructor.h"
 #include "base/notreached.h"
-#include "base/strings/string_piece.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/values.h"
@@ -108,10 +109,10 @@
   return std::u16string();
 }
 
-base::StringPiece ContentClient::GetDataResource(
+std::string_view ContentClient::GetDataResource(
     int resource_id,
     ui::ResourceScaleFactor scale_factor) {
-  return base::StringPiece();
+  return std::string_view();
 }
 
 base::RefCountedMemory* ContentClient::GetDataResourceBytes(int resource_id) {
diff --git a/content/public/common/content_client.h b/content/public/common/content_client.h
index 2387517..42d7889 100644
--- a/content/public/common/content_client.h
+++ b/content/public/common/content_client.h
@@ -7,11 +7,11 @@
 
 #include <set>
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include "base/memory/raw_ptr.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/strings/string_piece.h"
 #include "build/build_config.h"
 #include "content/common/content_export.h"
 #include "mojo/public/cpp/system/message_pipe.h"
@@ -167,7 +167,7 @@
                                             const std::u16string& replacement);
 
   // Return the contents of a resource in a StringPiece given the resource id.
-  virtual base::StringPiece GetDataResource(
+  virtual std::string_view GetDataResource(
       int resource_id,
       ui::ResourceScaleFactor scale_factor);
 
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index e8553ec..5f083d5e 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -837,48 +837,6 @@
         &kProcessPerSiteUpToMainFrameThreshold,
         "ProcessPerSiteMainFrameAllowDevToolsAttached", false};
 
-// Enables bypassing the service worker fetch handler. This feature starts the
-// service worker for subsequent requests.
-BASE_FEATURE(kServiceWorkerBypassFetchHandler,
-             "ServiceWorkerBypassFetchHandler",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
-const base::FeatureParam<ServiceWorkerBypassFetchHandlerStrategy>::Option
-    service_worker_bypass_fetch_handler_strategy_options[] = {
-        {ServiceWorkerBypassFetchHandlerStrategy::kFeatureOptIn, "optin"},
-        {ServiceWorkerBypassFetchHandlerStrategy::kAllowList, "allowlist"}};
-const base::FeatureParam<ServiceWorkerBypassFetchHandlerStrategy>
-    kServiceWorkerBypassFetchHandlerStrategy{
-        &kServiceWorkerBypassFetchHandler, "strategy",
-        ServiceWorkerBypassFetchHandlerStrategy::kFeatureOptIn,
-        &service_worker_bypass_fetch_handler_strategy_options};
-
-const base::FeatureParam<ServiceWorkerBypassFetchHandlerTarget>::Option
-    service_worker_bypass_fetch_handler_target_options[] = {
-        {
-            ServiceWorkerBypassFetchHandlerTarget::kMainResource,
-            "main_resource",
-        },
-        {
-            ServiceWorkerBypassFetchHandlerTarget::
-                kAllOnlyIfServiceWorkerNotStarted,
-            "all_only_if_service_worker_not_started",
-        },
-        {
-            ServiceWorkerBypassFetchHandlerTarget::kAllWithRaceNetworkRequest,
-            "all_with_race_network_request",
-        },
-        {
-            ServiceWorkerBypassFetchHandlerTarget::kSubResource,
-            "sub_resource",
-        },
-};
-const base::FeatureParam<ServiceWorkerBypassFetchHandlerTarget>
-    kServiceWorkerBypassFetchHandlerTarget{
-        &kServiceWorkerBypassFetchHandler, "bypass_for",
-        ServiceWorkerBypassFetchHandlerTarget::kMainResource,
-        &service_worker_bypass_fetch_handler_target_options};
-
 // Enables ServiceWorker static routing API.
 // https://github.com/WICG/service-worker-static-routing-api
 BASE_FEATURE(kServiceWorkerStaticRouter,
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index eea5cdde..8ce1af1 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -208,53 +208,6 @@
 CONTENT_EXPORT extern const base::FeatureParam<base::TimeDelta>
     kSiteIsolationForCrossOriginOpenerPolicyExpirationTimeoutParam;
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kDisableProcessReuse);
-CONTENT_EXPORT BASE_DECLARE_FEATURE(kServiceWorkerBypassFetchHandler);
-// ServiceWorkerBypassFetchHandlerStrategy provides the info how to decide if
-// the request should bypass fetch handlers or not.
-enum class ServiceWorkerBypassFetchHandlerStrategy {
-  // Use the allowlist provided by
-  // kServiceWorkerBypassFetchHandlerBypassedOrigins. If the request url's
-  // origin is in the list, fetch handlers are bypassed.
-  kAllowList,
-
-  // This option is to run the feature locally for the debugging purpose. It is
-  // used for the feature toggle in about:flags etc. It simply bypasses fetch
-  // handlers for all the main resource requests regardless of the url while the
-  // feature is enabled.
-  //
-  // This is set as a default value, but the origin trial uses a different
-  // mechanism to enable the feature per origin. When the feature is enabled by
-  // the origin trial, ServiceWorkerVersion in content/browser should contain
-  // the origin trial token. If the browser successfully confirm the token,
-  // fetch handlers are always bypassed regardless of
-  // ServiceWorkerBypassFetchHandlerStrategy.
-  kFeatureOptIn,
-};
-CONTENT_EXPORT extern const base::FeatureParam<
-    ServiceWorkerBypassFetchHandlerStrategy>
-    kServiceWorkerBypassFetchHandlerStrategy;
-enum class ServiceWorkerBypassFetchHandlerTarget {
-  // Bypass fetch handlers for main resource (navigation) requests. Fetch
-  // handlers will be bypassed regardless of the current ServiceWorker running
-  // status.
-  kMainResource,
-  // If the ServiceWorker is not started yet when the main resource request
-  // happens, it bypasses fetch handlers for the main resource and subsequent
-  // subresources. If the ServiceWorker is running, it invokes fetch handlers as
-  // usual.
-  kAllOnlyIfServiceWorkerNotStarted,
-  // BestEffortServiceWorker(crbug.com/1420517). It allows the browser to
-  // dispatch a request directly to the network even if there is a registered
-  // ServiceWorker. This behavior races the network request and the
-  // ServiceWorker fetch handler and uses the result of whichever is faster.
-  kAllWithRaceNetworkRequest,
-  // Bypass fetch handlers for subresource requests. Fetch handlers will be
-  // bypassed regardless of the current ServiceWorker running status.
-  kSubResource,
-};
-CONTENT_EXPORT extern const base::FeatureParam<
-    ServiceWorkerBypassFetchHandlerTarget>
-    kServiceWorkerBypassFetchHandlerTarget;
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kServiceWorkerStaticRouter);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kUserMediaCaptureOnFocus);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kWebLockScreenApi);
diff --git a/content/public/common/pseudonymization_util.cc b/content/public/common/pseudonymization_util.cc
index 3ebf6e2d..04c5ad5d 100644
--- a/content/public/common/pseudonymization_util.cc
+++ b/content/public/common/pseudonymization_util.cc
@@ -6,20 +6,21 @@
 
 #include <string.h>
 
+#include <string_view>
+
 #include "base/hash/sha1.h"
-#include "base/strings/string_piece.h"
 #include "content/common/pseudonymization_salt.h"
 
 namespace content {
 
 // static
 uint32_t PseudonymizationUtil::PseudonymizeStringForTesting(
-    base::StringPiece string) {
+    std::string_view string) {
   return PseudonymizeString(string);
 }
 
 // static
-uint32_t PseudonymizationUtil::PseudonymizeString(base::StringPiece string) {
+uint32_t PseudonymizationUtil::PseudonymizeString(std::string_view string) {
   // Include `string` in the SHA1 hash.
   base::SHA1Context sha1_context;
   base::SHA1Init(sha1_context);
@@ -32,7 +33,7 @@
   // retained or sent anywhere).
   uint32_t salt = GetPseudonymizationSalt();
   base::SHA1Update(
-      base::StringPiece(reinterpret_cast<const char*>(&salt), sizeof(salt)),
+      std::string_view(reinterpret_cast<const char*>(&salt), sizeof(salt)),
       sha1_context);
 
   // Compute the SHA1 hash.
diff --git a/content/public/common/pseudonymization_util.h b/content/public/common/pseudonymization_util.h
index 5a919e9..e73602a 100644
--- a/content/public/common/pseudonymization_util.h
+++ b/content/public/common/pseudonymization_util.h
@@ -5,10 +5,10 @@
 #ifndef CONTENT_PUBLIC_COMMON_PSEUDONYMIZATION_UTIL_H_
 #define CONTENT_PUBLIC_COMMON_PSEUDONYMIZATION_UTIL_H_
 
-#include "stdint.h"
+#include <string_view>
 
-#include "base/strings/string_piece.h"
 #include "content/common/content_export.h"
+#include "stdint.h"
 
 // Forward-declarations of classes approved for using the PseudonymizationUtil.
 //
@@ -31,7 +31,7 @@
  public:
   // This is a test only interface that is identical to the public interface,
   // but does not require friending.
-  static uint32_t PseudonymizeStringForTesting(base::StringPiece string);
+  static uint32_t PseudonymizeStringForTesting(std::string_view string);
 
  private:
   // Pseudonymizes the input `string` by passing it through a one-way hash
@@ -46,7 +46,7 @@
   // and Renderer processes).
   //
   // This method is thread-safe - it can be called on any thread.
-  static uint32_t PseudonymizeString(base::StringPiece string);
+  static uint32_t PseudonymizeString(std::string_view string);
 
   // NOTE: All usages of the PseudonymizationUtil class should be reviewed by
   // chrome-privacy-core@google.com (and when approved added to the friend list
diff --git a/content/public/common/user_agent.h b/content/public/common/user_agent.h
index 714ad81..323f5db4 100644
--- a/content/public/common/user_agent.h
+++ b/content/public/common/user_agent.h
@@ -7,7 +7,6 @@
 
 #include <string>
 
-#include "base/strings/string_piece.h"
 #include "build/build_config.h"
 #include "content/common/content_export.h"
 
diff --git a/content/public/test/back_forward_cache_util.h b/content/public/test/back_forward_cache_util.h
index 4b65bb2..6031eba1 100644
--- a/content/public/test/back_forward_cache_util.h
+++ b/content/public/test/back_forward_cache_util.h
@@ -8,7 +8,6 @@
 #include <memory>
 
 #include "base/feature_list.h"
-#include "base/strings/string_piece.h"
 #include "base/test/scoped_feature_list.h"
 #include "content/public/browser/back_forward_cache.h"
 
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index 96a94fc..0c518ce 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -8,6 +8,7 @@
 
 #include <cstdint>
 #include <set>
+#include <string_view>
 #include <tuple>
 #include <utility>
 
@@ -27,7 +28,6 @@
 #include "base/strings/pattern.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
@@ -351,7 +351,7 @@
 
   // Replace the host of the URL with the one passed in the URL.
   GURL::Replacements replace_host;
-  replace_host.SetHostStr(base::StringPiece(params).substr(0, slash));
+  replace_host.SetHostStr(std::string_view(params).substr(0, slash));
   GURL redirect_server =
       test_server->base_url().ReplaceComponents(replace_host);
 
@@ -653,7 +653,7 @@
 }
 
 bool NavigateIframeToURL(WebContents* web_contents,
-                         base::StringPiece iframe_id,
+                         std::string_view iframe_id,
                          const GURL& url) {
   TestNavigationObserver load_observer(web_contents);
   bool result = BeginNavigateIframeToURL(web_contents, iframe_id, url);
@@ -662,7 +662,7 @@
 }
 
 bool BeginNavigateIframeToURL(WebContents* web_contents,
-                              base::StringPiece iframe_id,
+                              std::string_view iframe_id,
                               const GURL& url) {
   std::string script =
       base::StrCat({"setTimeout(\"var iframes = document.getElementById('",
@@ -707,7 +707,7 @@
 }
 
 GURL GetFileUrlWithQuery(const base::FilePath& path,
-                         base::StringPiece query_string) {
+                         std::string_view query_string) {
   GURL url = net::FilePathToFileURL(path);
   if (!query_string.empty()) {
     GURL::Replacements replacements;
@@ -970,7 +970,7 @@
 
 gfx::PointF GetCenterCoordinatesOfElementWithId(
     const ToRenderFrameHost& adapter,
-    base::StringPiece id) {
+    std::string_view id) {
   float x =
       EvalJs(adapter, JsReplace("const bounds = "
                                 "document.getElementById($1)."
@@ -989,7 +989,7 @@
 }
 
 void SimulateMouseClickOrTapElementWithId(content::WebContents* web_contents,
-                                          base::StringPiece id) {
+                                          std::string_view id) {
   gfx::Point point = gfx::ToFlooredPoint(
       GetCenterCoordinatesOfElementWithId(web_contents, id));
 
@@ -1427,7 +1427,7 @@
 }
 
 void ExecuteScriptAsync(const ToRenderFrameHost& adapter,
-                        base::StringPiece script) {
+                        std::string_view script) {
   // Prerendering pages will never have user gesture.
   if (adapter.render_frame_host()->GetLifecycleState() ==
       RenderFrameHost::LifecycleState::kPrerendering) {
@@ -1439,13 +1439,13 @@
 }
 
 void ExecuteScriptAsyncWithoutUserGesture(const ToRenderFrameHost& adapter,
-                                          base::StringPiece script) {
+                                          std::string_view script) {
   adapter.render_frame_host()->ExecuteJavaScriptForTests(
       base::UTF8ToUTF16(script), base::NullCallback());
 }
 
 // EvalJsResult methods.
-EvalJsResult::EvalJsResult(base::Value value, base::StringPiece error)
+EvalJsResult::EvalJsResult(base::Value value, std::string_view error)
     : value(error.empty() ? std::move(value) : base::Value()), error(error) {}
 
 EvalJsResult::EvalJsResult(const EvalJsResult& other)
@@ -1519,9 +1519,9 @@
 //
 // TODO(nick): Elide snippets to 80 chars, since it is common for sources to not
 // include newlines.
-std::string AnnotateAndAdjustJsStackTraces(base::StringPiece js_error,
+std::string AnnotateAndAdjustJsStackTraces(std::string_view js_error,
                                            std::string source_name,
-                                           base::StringPiece source,
+                                           std::string_view source,
                                            int column_adjustment_for_line_one) {
   // Escape wildcards in |source_name| for use in MatchPattern.
   base::ReplaceChars(source_name, "\\", "\\\\", &source_name);
@@ -1529,7 +1529,7 @@
   base::ReplaceChars(source_name, "?", "\\?", &source_name);
 
   // This vector maps line numbers to the corresponding text in |source|.
-  const std::vector<base::StringPiece> source_lines = base::SplitStringPiece(
+  const std::vector<std::string_view> source_lines = base::SplitStringPiece(
       source, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
 
   // |source_frame_pattern| should match any line that looks like a stack frame
@@ -1540,19 +1540,19 @@
   // This is the amount of indentation that is applied to the lines of inserted
   // annotations.
   const std::string indent(8, ' ');
-  const base::StringPiece elision_mark = "";
+  const std::string_view elision_mark = "";
 
   // Loop over each line of |js_error|, and append each to |annotated_error| --
   // possibly rewriting to include extra context.
   std::ostringstream annotated_error;
-  for (const base::StringPiece& error_line : base::SplitStringPiece(
+  for (const std::string_view& error_line : base::SplitStringPiece(
            js_error, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL)) {
     // Does this look like a stack frame whose URL source matches |source_name|?
     if (base::MatchPattern(error_line, source_frame_pattern)) {
       // When a match occurs, annotate the stack trace with the corresponding
       // line from |source|, along with a ^^^ underneath, indicating the column
       // position.
-      std::vector<base::StringPiece> error_line_parts = base::SplitStringPiece(
+      std::vector<std::string_view> error_line_parts = base::SplitStringPiece(
           error_line, ":", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
       CHECK_GE(error_line_parts.size(), 2u);
 
@@ -1680,8 +1680,8 @@
 
 EvalJsResult EvalJsRunner(
     const ToRenderFrameHost& execution_target,
-    base::StringPiece script,
-    base::StringPiece source_url,
+    std::string_view script,
+    std::string_view source_url,
     int options,
     int32_t world_id,
     base::OnceClosure after_script_invoke = base::DoNothing()) {
@@ -1732,7 +1732,7 @@
 }  // namespace
 
 ::testing::AssertionResult ExecJs(const ToRenderFrameHost& execution_target,
-                                  base::StringPiece script,
+                                  std::string_view script,
                                   int options,
                                   int32_t world_id) {
   // TODO(nick): Do we care enough about folks shooting themselves in the foot
@@ -1748,7 +1748,7 @@
 }
 
 EvalJsResult EvalJs(const ToRenderFrameHost& execution_target,
-                    base::StringPiece script,
+                    std::string_view script,
                     int options,
                     int32_t world_id,
                     base::OnceClosure after_script_invoke) {
@@ -1771,8 +1771,8 @@
 
 EvalJsResult EvalJsAfterLifecycleUpdate(
     const ToRenderFrameHost& execution_target,
-    base::StringPiece raf_script,
-    base::StringPiece script,
+    std::string_view raf_script,
+    std::string_view script,
     int options,
     int32_t world_id) {
   TRACE_EVENT2("test", "EvalJsAfterLifecycleUpdate", "raf_script", raf_script,
@@ -1840,7 +1840,7 @@
   return rfh;
 }
 
-bool FrameMatchesName(base::StringPiece name, RenderFrameHost* frame) {
+bool FrameMatchesName(std::string_view name, RenderFrameHost* frame) {
   return frame->GetFrameName() == name;
 }
 
@@ -2102,7 +2102,7 @@
 }
 
 bool AccessibilityTreeContainsNodeWithName(BrowserAccessibility* node,
-                                           base::StringPiece name) {
+                                           std::string_view name) {
   // If an image annotation is set, it plays the same role as a name, so it
   // makes sense to check both in the same test helper.
   if (node->GetStringAttribute(ax::mojom::StringAttribute::kName) == name ||
@@ -2123,7 +2123,7 @@
 }
 
 void WaitForAccessibilityTreeToContainNodeWithName(WebContents* web_contents,
-                                                   base::StringPiece name) {
+                                                   std::string_view name) {
   WebContentsImpl* web_contents_impl =
       static_cast<WebContentsImpl*>(web_contents);
   RenderFrameHostImpl* main_frame = static_cast<RenderFrameHostImpl*>(
@@ -2424,7 +2424,7 @@
 
 RenderProcessHostKillWaiter::RenderProcessHostKillWaiter(
     RenderProcessHost* render_process_host,
-    base::StringPiece uma_name)
+    std::string_view uma_name)
     : exit_watcher_(render_process_host,
                     RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT),
       uma_name_(uma_name) {}
@@ -3567,7 +3567,7 @@
 void DevToolsInspectorLogWatcher::DispatchProtocolMessage(
     DevToolsAgentHost* host,
     base::span<const uint8_t> message) {
-  base::StringPiece message_str(reinterpret_cast<const char*>(message.data()),
+  std::string_view message_str(reinterpret_cast<const char*>(message.data()),
                                 message.size());
   auto parsed_message =
       std::move(base::JSONReader::Read(message_str)->GetDict());
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h
index 0d104b32..d7e7400 100644
--- a/content/public/test/browser_test_utils.h
+++ b/content/public/test/browser_test_utils.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <optional>
 #include <string>
+#include <string_view>
 #include <utility>
 #include <vector>
 
@@ -23,7 +24,6 @@
 #include "base/process/process.h"
 #include "base/run_loop.h"
 #include "base/scoped_observation.h"
-#include "base/strings/string_piece.h"
 #include "base/template_util.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/types/strong_alias.h"
@@ -256,18 +256,18 @@
 // necessary, a user activation can be triggered right before calling this
 // method, e.g. by calling |ExecJs(frame_tree_node, "")|.
 bool NavigateIframeToURL(WebContents* web_contents,
-                         base::StringPiece iframe_id,
+                         std::string_view iframe_id,
                          const GURL& url);
 
 // Similar to |NavigateIframeToURL()| but returns as soon as the navigation is
 // initiated.
 bool BeginNavigateIframeToURL(WebContents* web_contents,
-                              base::StringPiece iframe_id,
+                              std::string_view iframe_id,
                               const GURL& url);
 
 // Generate a URL for a file path including a query string.
 GURL GetFileUrlWithQuery(const base::FilePath& path,
-                         base::StringPiece query_string);
+                         std::string_view query_string);
 
 // Checks whether the page type of the last committed navigation entry matches
 // |page_type|.
@@ -359,12 +359,12 @@
 // friendly by taking zooming into account.
 gfx::PointF GetCenterCoordinatesOfElementWithId(
     const ToRenderFrameHost& adapter,
-    base::StringPiece id);
+    std::string_view id);
 
 // Retrieves the center coordinates of the element with id |id| and simulates a
 // mouse click there using SimulateMouseClickAt().
 void SimulateMouseClickOrTapElementWithId(content::WebContents* web_contents,
-                                          base::StringPiece id);
+                                          std::string_view id);
 
 // Simulates asynchronously a mouse enter/move/leave event. The mouse event is
 // routed through RenderWidgetHostInputEventRouter and thus can target OOPIFs.
@@ -622,12 +622,12 @@
 // - EvalJs (if you want to retrieve a value)
 // - DOMMessageQueue (to manually wait for domAutomationController.send(...))
 void ExecuteScriptAsync(const ToRenderFrameHost& adapter,
-                        base::StringPiece script);
+                        std::string_view script);
 
 // Same as `content::ExecuteScriptAsync()`, but doesn't send a user gesture to
 // the renderer.
 void ExecuteScriptAsyncWithoutUserGesture(const ToRenderFrameHost& adapter,
-                                          base::StringPiece script);
+                                          std::string_view script);
 
 // JsLiteralHelper is a helper class that determines what types are legal to
 // pass to StringifyJsLiteral. Legal types include int, string, StringPiece,
@@ -705,7 +705,7 @@
 // This becomes "window.location.reload(true);" -- because bool values are
 // supported by base::Value. Numbers, lists, and dicts also work.
 template <typename... Args>
-std::string JsReplace(base::StringPiece script_template, Args&&... args) {
+std::string JsReplace(std::string_view script_template, Args&&... args) {
   base::Value::List values =
       ListValueOf(std::forward<Args>(args)...).TakeList();
   std::vector<std::string> replacements(values.size());
@@ -744,7 +744,7 @@
 
   // Creates an EvalJs result. If |error| is non-empty, |value| will be
   // ignored.
-  EvalJsResult(base::Value value, base::StringPiece error);
+  EvalJsResult(base::Value value, std::string_view error);
 
   // Copy ctor.
   EvalJsResult(const EvalJsResult& value);
@@ -906,7 +906,7 @@
 // It is guaranteed that EvalJs works even when the target frame is frozen.
 [[nodiscard]] EvalJsResult EvalJs(
     const ToRenderFrameHost& execution_target,
-    base::StringPiece script,
+    std::string_view script,
     int options = EXECUTE_SCRIPT_DEFAULT_OPTIONS,
     int32_t world_id = ISOLATED_WORLD_ID_GLOBAL,
     base::OnceClosure after_script_invoke = base::DoNothing());
@@ -918,8 +918,8 @@
 // processed by the browser.
 [[nodiscard]] EvalJsResult EvalJsAfterLifecycleUpdate(
     const ToRenderFrameHost& execution_target,
-    base::StringPiece raf_script,
-    base::StringPiece script,
+    std::string_view raf_script,
+    std::string_view script,
     int options = EXECUTE_SCRIPT_DEFAULT_OPTIONS,
     int32_t world_id = ISOLATED_WORLD_ID_GLOBAL);
 
@@ -933,7 +933,7 @@
 // until it resolves (by default).
 [[nodiscard]] ::testing::AssertionResult ExecJs(
     const ToRenderFrameHost& execution_target,
-    base::StringPiece script,
+    std::string_view script,
     int options = EXECUTE_SCRIPT_DEFAULT_OPTIONS,
     int32_t world_id = ISOLATED_WORLD_ID_GLOBAL);
 
@@ -952,7 +952,7 @@
     base::RepeatingCallback<bool(RenderFrameHost*)> predicate);
 
 // Predicates for use with FrameMatchingPredicate[OrNullPtr]().
-bool FrameMatchesName(base::StringPiece name, RenderFrameHost* frame);
+bool FrameMatchesName(std::string_view name, RenderFrameHost* frame);
 bool FrameIsChildOfMainFrame(RenderFrameHost* frame);
 bool FrameHasSourceUrl(const GURL& url, RenderFrameHost* frame);
 
@@ -1077,7 +1077,7 @@
 // WaitForAccessibilityTreeToChange, above, and then checks again.
 // Keeps looping until the text is found (or the test times out).
 void WaitForAccessibilityTreeToContainNodeWithName(WebContents* web_contents,
-                                                   base::StringPiece name);
+                                                   std::string_view name);
 
 // Get a snapshot of a web page's accessibility tree.
 ui::AXTreeUpdate GetAccessibilityTreeSnapshot(WebContents* web_contents);
@@ -1249,7 +1249,7 @@
   // |uma_name| is the name of the histogram from which the |bad_message_reason|
   // can be extracted.
   RenderProcessHostKillWaiter(RenderProcessHost* render_process_host,
-                              base::StringPiece uma_name);
+                              std::string_view uma_name);
 
   RenderProcessHostKillWaiter(const RenderProcessHostKillWaiter&) = delete;
   RenderProcessHostKillWaiter& operator=(const RenderProcessHostKillWaiter&) =
diff --git a/content/public/test/content_browser_test_content_browser_client.cc b/content/public/test/content_browser_test_content_browser_client.cc
index a6d58e47..44d6198f 100644
--- a/content/public/test/content_browser_test_content_browser_client.cc
+++ b/content/public/test/content_browser_test_content_browser_client.cc
@@ -4,6 +4,8 @@
 
 #include "content/public/test/content_browser_test_content_browser_client.h"
 
+#include <string_view>
+
 #include "base/test/task_environment.h"
 #include "content/public/common/content_client.h"
 
@@ -32,7 +34,7 @@
 }
 
 bool ContentBrowserTestContentBrowserClient::CreateThreadPool(
-    base::StringPiece name) {
+    std::string_view name) {
   // Injects a test TaskTracker to watch for long-running tasks and produce a
   // useful timeout message in order to find the cause of flaky timeout tests.
   base::test::TaskEnvironment::CreateThreadPool();
diff --git a/content/public/test/content_browser_test_content_browser_client.h b/content/public/test/content_browser_test_content_browser_client.h
index 833e9f3a..5940061 100644
--- a/content/public/test/content_browser_test_content_browser_client.h
+++ b/content/public/test/content_browser_test_content_browser_client.h
@@ -5,6 +5,8 @@
 #ifndef CONTENT_PUBLIC_TEST_CONTENT_BROWSER_TEST_CONTENT_BROWSER_CLIENT_H_
 #define CONTENT_PUBLIC_TEST_CONTENT_BROWSER_TEST_CONTENT_BROWSER_CLIENT_H_
 
+#include <string_view>
+
 #include "content/shell/browser/shell_content_browser_client.h"
 
 namespace content {
@@ -19,7 +21,7 @@
   ContentBrowserTestContentBrowserClient();
   ~ContentBrowserTestContentBrowserClient() override;
 
-  bool CreateThreadPool(base::StringPiece name) override;
+  bool CreateThreadPool(std::string_view name) override;
   void OnNetworkServiceCreated(
       network::mojom::NetworkService* network_service) override;
 };
diff --git a/content/public/test/content_test_suite_base.cc b/content/public/test/content_test_suite_base.cc
index ecbbe6ff..62829d2 100644
--- a/content/public/test/content_test_suite_base.cc
+++ b/content/public/test/content_test_suite_base.cc
@@ -11,7 +11,6 @@
 #include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/path_service.h"
-#include "base/strings/string_piece.h"
 #include "base/test/test_suite.h"
 #include "build/build_config.h"
 #include "content/browser/gpu/gpu_main_thread_factory.h"
diff --git a/content/public/test/scoped_page_focus_override.cc b/content/public/test/scoped_page_focus_override.cc
index 2e9c4d08..e3f8803 100644
--- a/content/public/test/scoped_page_focus_override.cc
+++ b/content/public/test/scoped_page_focus_override.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <optional>
 #include <string>
+#include <string_view>
 
 #include "base/containers/span.h"
 #include "base/functional/callback.h"
@@ -33,8 +34,8 @@
 void ScopedPageFocusOverride::DispatchProtocolMessage(
     DevToolsAgentHost* agent_host,
     base::span<const uint8_t> message) {
-  base::StringPiece message_str(reinterpret_cast<const char*>(message.data()),
-                                message.size());
+  std::string_view message_str(reinterpret_cast<const char*>(message.data()),
+                               message.size());
   std::optional<base::Value> parsed_message =
       base::JSONReader::Read(message_str);
   ASSERT_TRUE(parsed_message.has_value());
diff --git a/content/public/test/test_devtools_protocol_client.cc b/content/public/test/test_devtools_protocol_client.cc
index c5fefc9..14fdff1 100644
--- a/content/public/test/test_devtools_protocol_client.cc
+++ b/content/public/test/test_devtools_protocol_client.cc
@@ -5,6 +5,7 @@
 #include "content/public/test/test_devtools_protocol_client.h"
 
 #include <memory>
+#include <string_view>
 
 #include "base/auto_reset.h"
 #include "base/json/json_reader.h"
@@ -152,8 +153,8 @@
 void TestDevToolsProtocolClient::DispatchProtocolMessage(
     DevToolsAgentHost* agent_host,
     base::span<const uint8_t> message) {
-  base::StringPiece message_str(reinterpret_cast<const char*>(message.data()),
-                                message.size());
+  std::string_view message_str(reinterpret_cast<const char*>(message.data()),
+                               message.size());
   base::Value parsed = *base::JSONReader::Read(message_str);
   if (std::optional<int> id = parsed.GetDict().FindInt("id")) {
     received_responses_count_++;
diff --git a/content/public/test/test_web_ui.cc b/content/public/test/test_web_ui.cc
index 1a17b54..eafb973 100644
--- a/content/public/test/test_web_ui.cc
+++ b/content/public/test/test_web_ui.cc
@@ -4,13 +4,13 @@
 
 #include "content/public/test/test_web_ui.h"
 
+#include <string_view>
 #include <utility>
 
 #include "base/functional/callback.h"
 #include "base/memory/ptr_util.h"
 #include "base/no_destructor.h"
 #include "base/notreached.h"
-#include "base/strings/string_piece.h"
 #include "content/public/browser/web_ui_controller.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
@@ -90,7 +90,7 @@
   handlers_.push_back(std::move(handler));
 }
 
-void TestWebUI::RegisterMessageCallback(base::StringPiece message,
+void TestWebUI::RegisterMessageCallback(std::string_view message,
                                         MessageCallback callback) {
   message_callbacks_[static_cast<std::string>(message)].push_back(
       std::move(callback));
@@ -113,13 +113,13 @@
   return true;
 }
 
-void TestWebUI::CallJavascriptFunctionUnsafe(base::StringPiece function_name) {
+void TestWebUI::CallJavascriptFunctionUnsafe(std::string_view function_name) {
   call_data_.push_back(base::WrapUnique(new CallData(function_name)));
   OnJavascriptCall(*call_data_.back());
 }
 
 void TestWebUI::CallJavascriptFunctionUnsafe(
-    base::StringPiece function_name,
+    std::string_view function_name,
     base::span<const base::ValueView> args) {
   call_data_.push_back(base::WrapUnique(new CallData(function_name)));
   for (const auto& arg : args) {
@@ -138,7 +138,7 @@
   return &handlers_;
 }
 
-TestWebUI::CallData::CallData(base::StringPiece function_name)
+TestWebUI::CallData::CallData(std::string_view function_name)
     : function_name_(function_name.data(), function_name.size()) {}
 
 TestWebUI::CallData::~CallData() {
diff --git a/content/public/test/test_web_ui.h b/content/public/test/test_web_ui.h
index d78dcf2..a89e775 100644
--- a/content/public/test/test_web_ui.h
+++ b/content/public/test/test_web_ui.h
@@ -6,6 +6,7 @@
 #define CONTENT_PUBLIC_TEST_TEST_WEB_UI_H_
 
 #include <memory>
+#include <string_view>
 #include <vector>
 
 #include "base/containers/flat_map.h"
@@ -53,22 +54,22 @@
   const std::vector<std::string>& GetRequestableSchemes() override;
   void AddRequestableScheme(const char* scheme) override;
   void AddMessageHandler(std::unique_ptr<WebUIMessageHandler> handler) override;
-  void RegisterMessageCallback(base::StringPiece message,
+  void RegisterMessageCallback(std::string_view message,
                                MessageCallback callback) override;
   void ProcessWebUIMessage(const GURL& source_url,
                            const std::string& message,
                            base::Value::List args) override;
   bool CanCallJavascript() override;
-  void CallJavascriptFunctionUnsafe(base::StringPiece function_name) override;
+  void CallJavascriptFunctionUnsafe(std::string_view function_name) override;
   void CallJavascriptFunctionUnsafe(
-      base::StringPiece function_name,
+      std::string_view function_name,
       base::span<const base::ValueView> args) override;
   std::vector<std::unique_ptr<WebUIMessageHandler>>* GetHandlersForTesting()
       override;
 
   class CallData {
    public:
-    explicit CallData(base::StringPiece function_name);
+    explicit CallData(std::string_view function_name);
     ~CallData();
 
     void AppendArgument(base::Value arg);
diff --git a/content/public/test/url_loader_interceptor.cc b/content/public/test/url_loader_interceptor.cc
index 7bad6b3..b262c24 100644
--- a/content/public/test/url_loader_interceptor.cc
+++ b/content/public/test/url_loader_interceptor.cc
@@ -5,6 +5,7 @@
 #include "content/public/test/url_loader_interceptor.h"
 
 #include <string>
+#include <string_view>
 #include <utility>
 
 #include "base/containers/unique_ptr_adapters.h"
@@ -467,8 +468,8 @@
 }
 
 void URLLoaderInterceptor::WriteResponse(
-    base::StringPiece headers,
-    base::StringPiece body,
+    std::string_view headers,
+    std::string_view body,
     network::mojom::URLLoaderClient* client,
     std::optional<net::SSLInfo> ssl_info,
     std::optional<GURL> url) {
diff --git a/content/public/test/url_loader_interceptor.h b/content/public/test/url_loader_interceptor.h
index 8422a5f5..f623bf24 100644
--- a/content/public/test/url_loader_interceptor.h
+++ b/content/public/test/url_loader_interceptor.h
@@ -9,11 +9,11 @@
 #include <optional>
 #include <set>
 #include <string>
+#include <string_view>
 
 #include "base/files/file_path.h"
 #include "base/functional/callback_helpers.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/strings/string_piece.h"
 #include "base/synchronization/lock.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -120,8 +120,8 @@
   // Helper methods for use when intercepting.
   // Writes the given response body, header, and SSL Info to `client`.
   // If `url` is present, also computes the ParsedHeaders for the response.
-  static void WriteResponse(base::StringPiece headers,
-                            base::StringPiece body,
+  static void WriteResponse(std::string_view headers,
+                            std::string_view body,
                             network::mojom::URLLoaderClient* client,
                             std::optional<net::SSLInfo> ssl_info = std::nullopt,
                             std::optional<GURL> url = std::nullopt);
diff --git a/content/public/test/web_ui_browsertest_util.cc b/content/public/test/web_ui_browsertest_util.cc
index 5710948..c0baed3 100644
--- a/content/public/test/web_ui_browsertest_util.cc
+++ b/content/public/test/web_ui_browsertest_util.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <string>
+#include <string_view>
 
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -233,7 +234,7 @@
               url::kStandardSchemeSeparator + host_and_path);
 }
 
-TestWebUIConfig::TestWebUIConfig(base::StringPiece host)
+TestWebUIConfig::TestWebUIConfig(std::string_view host)
     : WebUIConfig(content::kChromeUIScheme, host) {}
 
 std::unique_ptr<WebUIController> TestWebUIConfig::CreateWebUIController(
diff --git a/content/public/test/web_ui_browsertest_util.h b/content/public/test/web_ui_browsertest_util.h
index 02731a5..9cdaf34 100644
--- a/content/public/test/web_ui_browsertest_util.h
+++ b/content/public/test/web_ui_browsertest_util.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <optional>
 #include <string>
+#include <string_view>
 #include <utility>
 
 #include "content/public/browser/web_ui_controller.h"
@@ -46,7 +47,7 @@
 
 class TestWebUIConfig : public content::WebUIConfig {
  public:
-  explicit TestWebUIConfig(base::StringPiece host);
+  explicit TestWebUIConfig(std::string_view host);
 
   ~TestWebUIConfig() override = default;
 
diff --git a/content/renderer/accessibility/annotations/ax_image_annotator.cc b/content/renderer/accessibility/annotations/ax_image_annotator.cc
index 2ff1771..bb6c8a4 100644
--- a/content/renderer/accessibility/annotations/ax_image_annotator.cc
+++ b/content/renderer/accessibility/annotations/ax_image_annotator.cc
@@ -5,6 +5,7 @@
 #include "content/renderer/accessibility/annotations/ax_image_annotator.h"
 
 #include <string>
+#include <string_view>
 #include <utility>
 #include <vector>
 
@@ -58,7 +59,7 @@
 
 int GetMessageIdForIconEnum(const std::string& icon_type) {
   static constexpr auto kIconTypeToMessageIdMap =
-      base::MakeFixedFlatMap<base::StringPiece, int>({
+      base::MakeFixedFlatMap<std::string_view, int>({
           {"ICON_PLUS", IDS_AX_IMAGE_ANNOTATION_ICON_PLUS},
           {"ICON_ARROW_BACKWARD", IDS_AX_IMAGE_ANNOTATION_ICON_ARROW_BACKWARD},
           {"ICON_ARROW_FORWARD", IDS_AX_IMAGE_ANNOTATION_ICON_ARROW_FORWARD},
diff --git a/content/renderer/accessibility/annotations/ax_image_stopwords.cc b/content/renderer/accessibility/annotations/ax_image_stopwords.cc
index 0187f8a..cb6b9b2 100644
--- a/content/renderer/accessibility/annotations/ax_image_stopwords.cc
+++ b/content/renderer/accessibility/annotations/ax_image_stopwords.cc
@@ -5,6 +5,7 @@
 #include "content/renderer/accessibility/annotations/ax_image_stopwords.h"
 
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include "base/containers/contains.h"
@@ -12,7 +13,6 @@
 #include "base/i18n/case_conversion.h"
 #include "base/i18n/char_iterator.h"
 #include "base/no_destructor.h"
-#include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
 #include "third_party/icu/source/common/unicode/uchar.h"
@@ -507,7 +507,7 @@
   // because it avoids ever needing to copy any of the strings; each StringPiece
   // is just a pointer into kImageStopwordsUtf8 and flat_set acts like a set but
   // basically just does a binary search.
-  std::vector<base::StringPiece> stopwords =
+  std::vector<std::string_view> stopwords =
       base::SplitStringPiece(kImageStopwordsUtf8, "\n", base::TRIM_WHITESPACE,
                              base::SPLIT_WANT_NONEMPTY);
 
diff --git a/content/renderer/accessibility/annotations/ax_image_stopwords.h b/content/renderer/accessibility/annotations/ax_image_stopwords.h
index 02fbd118..013bfbd5 100644
--- a/content/renderer/accessibility/annotations/ax_image_stopwords.h
+++ b/content/renderer/accessibility/annotations/ax_image_stopwords.h
@@ -5,9 +5,10 @@
 #ifndef CONTENT_RENDERER_ACCESSIBILITY_ANNOTATIONS_AX_IMAGE_STOPWORDS_H_
 #define CONTENT_RENDERER_ACCESSIBILITY_ANNOTATIONS_AX_IMAGE_STOPWORDS_H_
 
+#include <string_view>
+
 #include "base/containers/flat_set.h"
 #include "base/no_destructor.h"
-#include "base/strings/string_piece.h"
 #include "content/common/content_export.h"
 
 namespace content {
@@ -62,7 +63,7 @@
   AXImageStopwords();
   ~AXImageStopwords();
 
-  base::flat_set<base::StringPiece> stopword_set_;
+  base::flat_set<std::string_view> stopword_set_;
 };
 
 }  // namespace content
diff --git a/content/renderer/gpu_benchmarking_extension.cc b/content/renderer/gpu_benchmarking_extension.cc
index e2e3881..da85268d 100644
--- a/content/renderer/gpu_benchmarking_extension.cc
+++ b/content/renderer/gpu_benchmarking_extension.cc
@@ -8,6 +8,7 @@
 
 #include <memory>
 #include <string>
+#include <string_view>
 #include <tuple>
 #include <utility>
 #include <vector>
@@ -351,7 +352,7 @@
   return std::nullopt;
 }
 
-int ToKeyModifiers(const base::StringPiece& key) {
+int ToKeyModifiers(const std::string_view& key) {
   if (key == "Alt")
     return blink::WebInputEvent::kAltKey;
   if (key == "Control")
@@ -370,7 +371,7 @@
   return 0;
 }
 
-int ToButtonModifiers(const base::StringPiece& button) {
+int ToButtonModifiers(const std::string_view& button) {
   if (button == "Left")
     return blink::WebMouseEvent::kLeftButtonDown;
   if (button == "Middle")
@@ -850,9 +851,9 @@
     return false;
   gfx::Vector2dF fling_velocity(0, 0);
   int modifiers = 0;
-  std::vector<base::StringPiece> key_list = base::SplitStringPiece(
+  std::vector<std::string_view> key_list = base::SplitStringPiece(
       keys_value, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-  for (const base::StringPiece& key : key_list) {
+  for (const std::string_view& key : key_list) {
     int key_modifier = ToKeyModifiers(key);
     if (key_modifier == 0) {
       return false;
@@ -938,9 +939,9 @@
   gfx::Vector2dF distances(pixels_to_scroll_x, pixels_to_scroll_y);
   gfx::Vector2dF fling_velocity(0, 0);
   int modifiers = 0;
-  std::vector<base::StringPiece> key_list = base::SplitStringPiece(
+  std::vector<std::string_view> key_list = base::SplitStringPiece(
       keys_value, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-  for (const base::StringPiece& key : key_list) {
+  for (const std::string_view& key : key_list) {
     int key_modifier = ToKeyModifiers(key);
     if (key_modifier == 0) {
       return false;
@@ -948,9 +949,9 @@
     modifiers |= key_modifier;
   }
 
-  std::vector<base::StringPiece> button_list = base::SplitStringPiece(
+  std::vector<std::string_view> button_list = base::SplitStringPiece(
       buttons_value, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-  for (const base::StringPiece& button : button_list) {
+  for (const std::string_view& button : button_list) {
     int button_modifier = ToButtonModifiers(button);
     if (button_modifier == 0) {
       return false;
diff --git a/content/renderer/pepper/event_conversion.cc b/content/renderer/pepper/event_conversion.cc
index ee6b1909d..a2cb3ef 100644
--- a/content/renderer/pepper/event_conversion.cc
+++ b/content/renderer/pepper/event_conversion.cc
@@ -11,6 +11,7 @@
 #include <algorithm>
 #include <memory>
 #include <string>
+#include <string_view>
 
 #include "base/check_op.h"
 #include "base/feature_list.h"
@@ -192,7 +193,7 @@
 
   // Make a separate InputEventData for each Unicode character in the input.
   for (base::i18n::UTF16CharIterator iter(
-           base::StringPiece16(key_event.text, utf16_char_count));
+           std::u16string_view(key_event.text, utf16_char_count));
        !iter.end(); iter.Advance()) {
     InputEventData result = GetEventWithCommonFieldsAndType(event);
     result.event_modifiers = ConvertEventModifiers(key_event.GetModifiers());
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 66b99f7..0f373870 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -40,7 +40,6 @@
 #include "base/ranges/algorithm.h"
 #include "base/run_loop.h"
 #include "base/strings/strcat.h"
-#include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -1448,7 +1447,7 @@
 }
 
 bool RenderFrameImpl::UniqueNameFrameAdapter::IsCandidateUnique(
-    base::StringPiece name) const {
+    std::string_view name) const {
   // This method is currently O(N), where N = number of frames in the tree.
   DCHECK(!name.empty());
 
@@ -1484,7 +1483,7 @@
 std::vector<std::string>
 RenderFrameImpl::UniqueNameFrameAdapter::CollectAncestorNames(
     BeginPoint begin_point,
-    bool (*should_stop)(base::StringPiece)) const {
+    bool (*should_stop)(std::string_view)) const {
   std::vector<std::string> result;
   for (blink::WebFrame* frame = begin_point == BeginPoint::kParentFrame
                                     ? GetWebFrame()->Parent()
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index d45223d..47100d8 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -1234,12 +1234,12 @@
 
     // FrameAdapter overrides:
     bool IsMainFrame() const override;
-    bool IsCandidateUnique(base::StringPiece name) const override;
+    bool IsCandidateUnique(std::string_view name) const override;
     int GetSiblingCount() const override;
     int GetChildCount() const override;
     std::vector<std::string> CollectAncestorNames(
         BeginPoint begin_point,
-        bool (*should_stop)(base::StringPiece)) const override;
+        bool (*should_stop)(std::string_view)) const override;
     std::vector<int> GetFramePosition(BeginPoint begin_point) const override;
 
    private:
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index b4032a579..77dfb48 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -8,6 +8,7 @@
 #include <map>
 #include <memory>
 #include <string>
+#include <string_view>
 #include <utility>
 #include <vector>
 
@@ -411,7 +412,7 @@
     return true;
 
   if (!sanitized_host.empty()) {
-    std::vector<base::StringPiece> host_tokens = base::SplitStringPiece(
+    std::vector<std::string_view> host_tokens = base::SplitStringPiece(
         sanitized_host, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
 
     if (host_tokens.size() >= 2) {
diff --git a/content/renderer/sandbox_mac_v2_unittest.mm b/content/renderer/sandbox_mac_v2_unittest.mm
index dcb3abe..26136d52 100644
--- a/content/renderer/sandbox_mac_v2_unittest.mm
+++ b/content/renderer/sandbox_mac_v2_unittest.mm
@@ -13,6 +13,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <string_view>
+
 #include "base/apple/bundle_locations.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
@@ -114,8 +116,8 @@
   CHECK(result) << error;
 
   // Test the properties of the sandbox profile.
-  constexpr base::StringPiece log_msg = "logged";
-  CHECK(base::WriteFile(log_file, base::StringPiece(log_msg)));
+  constexpr std::string_view log_msg = "logged";
+  CHECK(base::WriteFile(log_file, std::string_view(log_msg)));
   // Log file is write only.
   char read_buf[log_msg.size()];
   CHECK_EQ(-1, base::ReadFile(log_file, read_buf, sizeof(read_buf)));
diff --git a/content/renderer/service_worker/service_worker_provider_context.cc b/content/renderer/service_worker/service_worker_provider_context.cc
index e2146f1..59f28043 100644
--- a/content/renderer/service_worker/service_worker_provider_context.cc
+++ b/content/renderer/service_worker/service_worker_provider_context.cc
@@ -64,36 +64,6 @@
           std::move(pending_fallback_factory)),
       std::move(receiver), std::move(task_runner));
 }
-
-// Returns the set of hash strings of fetch handlers which can be bypassed.
-const base::flat_set<std::string> FetchHandlerBypassedHashStrings() {
-  const static base::NoDestructor<base::flat_set<std::string>> result(
-      base::SplitString(
-          features::kServiceWorkerBypassFetchHandlerBypassedHashStrings.Get(),
-          ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY));
-
-  return *result;
-}
-
-bool ShouldBypassFetchHandlerForSubresource(
-    std::optional<std::string> sha256_script_checksum) {
-  if (!base::FeatureList::IsEnabled(
-          features::kServiceWorkerBypassFetchHandler)) {
-    return false;
-  }
-  if (features::kServiceWorkerBypassFetchHandlerTarget.Get() !=
-      features::ServiceWorkerBypassFetchHandlerTarget::kSubResource) {
-    return false;
-  }
-
-  switch (features::kServiceWorkerBypassFetchHandlerStrategy.Get()) {
-    case features::ServiceWorkerBypassFetchHandlerStrategy::kFeatureOptIn:
-      return true;
-    case features::ServiceWorkerBypassFetchHandlerStrategy::kAllowList:
-      return FetchHandlerBypassedHashStrings().contains(sha256_script_checksum);
-  }
-}
-
 }  // namespace
 
 ServiceWorkerProviderContext::ServiceWorkerProviderContext(
@@ -158,21 +128,6 @@
           blink::mojom::WebFeature::kServiceWorkerSkippedForSubresourceLoad);
       return nullptr;
     }
-
-    if (fetch_handler_bypass_option_ ==
-        blink::mojom::ServiceWorkerFetchHandlerBypassOption::
-            kBypassOnlyIfServiceWorkerNotStarted) {
-      // If the fetch handler for the main resource is skipped by
-      // ServiceWorkerBypassFetchHandler, the fetch handler doesn't handle
-      // subresources too.
-      return nullptr;
-    }
-
-    if (ShouldBypassFetchHandlerForSubresource(sha256_script_checksum_)) {
-      CountFeature(blink::mojom::WebFeature::
-                       kServiceWorkerBypassFetchHandlerForSubResource);
-      return nullptr;
-    }
   }
 
   if (!subresource_loader_factory_) {
diff --git a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
index 6c83cc7c..141f382 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
@@ -18,6 +18,7 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
+#include "content/common/features.h"
 #include "content/public/common/content_features.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/renderer/service_worker/controller_service_worker_connector.h"
@@ -978,9 +979,7 @@
        DropController_RestartFetchEvent_RaceNetworkRequest) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeatureWithParameters(
-      features::kServiceWorkerBypassFetchHandler,
-      {{"strategy", "opt-in"},
-       {"bypass_for", "all_with_race_network_request"}});
+      features::kServiceWorkerAutoPreload, {{"strategy", "opt-in"}});
 
   mojo::Remote<network::mojom::URLLoaderFactory> factory =
       CreateSubresourceLoaderFactory();
diff --git a/content/renderer/v8_value_converter_impl.cc b/content/renderer/v8_value_converter_impl.cc
index 19b30cdc..277dc47 100644
--- a/content/renderer/v8_value_converter_impl.cc
+++ b/content/renderer/v8_value_converter_impl.cc
@@ -10,6 +10,7 @@
 #include <cmath>
 #include <memory>
 #include <string>
+#include <string_view>
 #include <utility>
 #include <vector>
 
@@ -261,7 +262,7 @@
       return v8::Number::New(isolate, value);
     }
 
-    v8::Local<v8::Value> operator()(base::StringPiece value) {
+    v8::Local<v8::Value> operator()(std::string_view value) {
       return v8::String::NewFromUtf8(isolate, value.data(),
                                      v8::NewStringType::kNormal, value.length())
           .ToLocalChecked();
diff --git a/content/services/auction_worklet/auction_v8_helper.cc b/content/services/auction_worklet/auction_v8_helper.cc
index 6002aae..26479c1 100644
--- a/content/services/auction_worklet/auction_v8_helper.cc
+++ b/content/services/auction_worklet/auction_v8_helper.cc
@@ -6,6 +6,7 @@
 
 #include <limits>
 #include <memory>
+#include <string_view>
 #include <utility>
 
 #include "base/check.h"
@@ -401,7 +402,7 @@
 }
 
 v8::MaybeLocal<v8::String> AuctionV8Helper::CreateUtf8String(
-    base::StringPiece utf8_string) {
+    std::string_view utf8_string) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!base::IsStringUTF8(utf8_string))
     return v8::MaybeLocal<v8::String>();
@@ -412,7 +413,7 @@
 
 v8::MaybeLocal<v8::Value> AuctionV8Helper::CreateValueFromJson(
     v8::Local<v8::Context> context,
-    base::StringPiece utf8_json) {
+    std::string_view utf8_json) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   v8::Local<v8::String> v8_string;
   if (!CreateUtf8String(utf8_json).ToLocal(&v8_string))
@@ -420,7 +421,7 @@
   return v8::JSON::Parse(context, v8_string);
 }
 
-bool AuctionV8Helper::AppendUtf8StringValue(base::StringPiece utf8_string,
+bool AuctionV8Helper::AppendUtf8StringValue(std::string_view utf8_string,
                                             v8::LocalVector<v8::Value>* args) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   v8::Local<v8::String> value;
@@ -431,7 +432,7 @@
 }
 
 bool AuctionV8Helper::AppendJsonValue(v8::Local<v8::Context> context,
-                                      base::StringPiece utf8_json,
+                                      std::string_view utf8_json,
                                       v8::LocalVector<v8::Value>* args) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   v8::Local<v8::Value> value;
@@ -441,7 +442,7 @@
   return true;
 }
 
-bool AuctionV8Helper::InsertValue(base::StringPiece key,
+bool AuctionV8Helper::InsertValue(std::string_view key,
                                   v8::Local<v8::Value> value,
                                   v8::Local<v8::Object> object) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -454,8 +455,8 @@
 }
 
 bool AuctionV8Helper::InsertJsonValue(v8::Local<v8::Context> context,
-                                      base::StringPiece key,
-                                      base::StringPiece utf8_json,
+                                      std::string_view key,
+                                      std::string_view utf8_json,
                                       v8::Local<v8::Object> object) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   v8::Local<v8::Value> v8_value;
@@ -653,7 +654,7 @@
     v8::Local<v8::Context> context,
     const DebugId* debug_id,
     const std::string& script_name,
-    base::StringPiece function_name,
+    std::string_view function_name,
     base::span<v8::Local<v8::Value>> args,
     TimeLimit* script_timeout,
     std::vector<std::string>& error_out) {
diff --git a/content/services/auction_worklet/auction_v8_helper.h b/content/services/auction_worklet/auction_v8_helper.h
index 58dcfa3..78ff16c 100644
--- a/content/services/auction_worklet/auction_v8_helper.h
+++ b/content/services/auction_worklet/auction_v8_helper.h
@@ -9,6 +9,7 @@
 #include <memory>
 #include <optional>
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include "base/containers/span.h"
@@ -18,7 +19,6 @@
 #include "base/memory/ref_counted_delete_on_sequence.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/sequence_checker.h"
-#include "base/strings/string_piece.h"
 #include "base/synchronization/lock.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/single_thread_task_runner.h"
@@ -227,32 +227,32 @@
 
   // Attempts to create a v8::String from a UTF-8 string. Returns empty string
   // if input is not UTF-8.
-  v8::MaybeLocal<v8::String> CreateUtf8String(base::StringPiece utf8_string);
+  v8::MaybeLocal<v8::String> CreateUtf8String(std::string_view utf8_string);
 
   // The passed in JSON must be a valid UTF-8 JSON string.
   v8::MaybeLocal<v8::Value> CreateValueFromJson(v8::Local<v8::Context> context,
-                                                base::StringPiece utf8_json);
+                                                std::string_view utf8_json);
 
   // Convenience wrappers around the above Create* methods. Attempt to create
   // the corresponding value type and append it to the passed in argument
   // vector. Useful for assembling arguments to a Javascript function. Return
   // false on failure.
-  [[nodiscard]] bool AppendUtf8StringValue(base::StringPiece utf8_string,
+  [[nodiscard]] bool AppendUtf8StringValue(std::string_view utf8_string,
                                            v8::LocalVector<v8::Value>* args);
   [[nodiscard]] bool AppendJsonValue(v8::Local<v8::Context> context,
-                                     base::StringPiece utf8_json,
+                                     std::string_view utf8_json,
                                      v8::LocalVector<v8::Value>* args);
 
   // Convenience wrapper that adds the specified value into the provided Object.
-  [[nodiscard]] bool InsertValue(base::StringPiece key,
+  [[nodiscard]] bool InsertValue(std::string_view key,
                                  v8::Local<v8::Value> value,
                                  v8::Local<v8::Object> object);
 
   // Convenience wrapper that creates an Object by parsing `utf8_json` as JSON
   // and then inserts it into the provided Object.
   [[nodiscard]] bool InsertJsonValue(v8::Local<v8::Context> context,
-                                     base::StringPiece key,
-                                     base::StringPiece utf8_json,
+                                     std::string_view key,
+                                     std::string_view utf8_json,
                                      v8::Local<v8::Object> object);
 
   enum class ExtractJsonResult { kSuccess, kFailure, kTimeout };
@@ -361,7 +361,7 @@
   v8::MaybeLocal<v8::Value> CallFunction(v8::Local<v8::Context> context,
                                          const DebugId* debug_id,
                                          const std::string& script_name,
-                                         base::StringPiece function_name,
+                                         std::string_view function_name,
                                          base::span<v8::Local<v8::Value>> args,
                                          TimeLimit* script_timeout,
                                          std::vector<std::string>& error_out);
diff --git a/content/services/auction_worklet/auction_v8_inspector_util.cc b/content/services/auction_worklet/auction_v8_inspector_util.cc
index 18b68965..8f248b5 100644
--- a/content/services/auction_worklet/auction_v8_inspector_util.cc
+++ b/content/services/auction_worklet/auction_v8_inspector_util.cc
@@ -7,6 +7,7 @@
 #include <stdint.h>
 
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include "base/strings/utf_string_conversions.h"
@@ -17,7 +18,7 @@
   if (s.is8Bit()) {
     return std::vector<uint8_t>(s.characters8(), s.characters8() + s.length());
   } else {
-    std::string converted = base::UTF16ToUTF8(base::StringPiece16(
+    std::string converted = base::UTF16ToUTF8(std::u16string_view(
         reinterpret_cast<const char16_t*>(s.characters16()), s.length()));
     const uint8_t* data = reinterpret_cast<const uint8_t*>(converted.data());
     return std::vector<uint8_t>(data, data + converted.size());
diff --git a/content/services/auction_worklet/lazy_filler.cc b/content/services/auction_worklet/lazy_filler.cc
index 13e37bb..16d827c8 100644
--- a/content/services/auction_worklet/lazy_filler.cc
+++ b/content/services/auction_worklet/lazy_filler.cc
@@ -28,7 +28,7 @@
 }
 
 bool LazyFiller::DefineLazyAttribute(v8::Local<v8::Object> object,
-                                     base::StringPiece name,
+                                     std::string_view name,
                                      v8::AccessorNameGetterCallback getter) {
   v8::Isolate* isolate = v8_helper_->isolate();
 
@@ -44,7 +44,7 @@
 bool LazyFiller::DefineLazyAttributeWithMetadata(
     v8::Local<v8::Object> object,
     v8::Local<v8::Value> metadata,
-    base::StringPiece name,
+    std::string_view name,
     v8::AccessorNameGetterCallback getter,
     v8::Local<v8::ObjectTemplate>& lazy_filler_template) {
   v8::Isolate* isolate = v8_helper_->isolate();
diff --git a/content/services/auction_worklet/lazy_filler.h b/content/services/auction_worklet/lazy_filler.h
index 39a0756..1ef85e7 100644
--- a/content/services/auction_worklet/lazy_filler.h
+++ b/content/services/auction_worklet/lazy_filler.h
@@ -8,7 +8,6 @@
 #include <string_view>
 
 #include "base/memory/raw_ptr.h"
-#include "base/strings/string_piece.h"
 #include "v8/include/v8-external.h"
 #include "v8/include/v8-forward.h"
 #include "v8/include/v8-function-callback.h"
@@ -68,7 +67,7 @@
                         v8::Local<v8::Value> result);
 
   bool DefineLazyAttribute(v8::Local<v8::Object> object,
-                           base::StringPiece name,
+                           std::string_view name,
                            v8::AccessorNameGetterCallback getter);
 
   // `lazy_filler_template` is used to construct an internal v8 object with a
@@ -78,7 +77,7 @@
   bool DefineLazyAttributeWithMetadata(
       v8::Local<v8::Object> object,
       v8::Local<v8::Value> metadata,
-      base::StringPiece name,
+      std::string_view name,
       v8::AccessorNameGetterCallback getter,
       v8::Local<v8::ObjectTemplate>& lazy_filler_template);
 
diff --git a/content/services/auction_worklet/public/cpp/auction_downloader.cc b/content/services/auction_worklet/public/cpp/auction_downloader.cc
index 6dcc89e..93b28ae 100644
--- a/content/services/auction_worklet/public/cpp/auction_downloader.cc
+++ b/content/services/auction_worklet/public/cpp/auction_downloader.cc
@@ -7,6 +7,7 @@
 #include <cstddef>
 #include <memory>
 #include <string>
+#include <string_view>
 #include <utility>
 
 #include "base/functional/bind.h"
@@ -68,14 +69,14 @@
 // Returns the MIME type string to send for the Accept header for `mime_type`.
 // These are the official IANA MIME type strings, though other MIME type strings
 // are allows in the response.
-base::StringPiece MimeTypeToString(AuctionDownloader::MimeType mime_type) {
+std::string_view MimeTypeToString(AuctionDownloader::MimeType mime_type) {
   switch (mime_type) {
     case AuctionDownloader::MimeType::kJavascript:
-      return base::StringPiece("application/javascript");
+      return std::string_view("application/javascript");
     case AuctionDownloader::MimeType::kJson:
-      return base::StringPiece("application/json");
+      return std::string_view("application/json");
     case AuctionDownloader::MimeType::kWebAssembly:
-      return base::StringPiece(kWebAssemblyMime);
+      return std::string_view(kWebAssemblyMime);
   }
 }
 
@@ -107,7 +108,7 @@
 
 // Checks if `charset` is a valid charset, in lowercase ASCII. Takes `body` as
 // well, to ensure it uses the specified charset.
-bool IsAllowedCharset(base::StringPiece charset, const std::string& body) {
+bool IsAllowedCharset(std::string_view charset, const std::string& body) {
   if (charset == "utf-8" || charset.empty()) {
     return base::IsStringUTF8(body);
   } else if (charset == "us-ascii") {
diff --git a/content/services/auction_worklet/seller_lazy_filler.cc b/content/services/auction_worklet/seller_lazy_filler.cc
index 5e40cd5..3ac3439 100644
--- a/content/services/auction_worklet/seller_lazy_filler.cc
+++ b/content/services/auction_worklet/seller_lazy_filler.cc
@@ -110,7 +110,7 @@
 
 bool InsertPrioritySignals(
     AuctionV8Helper* v8_helper,
-    base::StringPiece key,
+    std::string_view key,
     const base::flat_map<std::string, double>& priority_signals,
     v8::Local<v8::Object> object) {
   v8::Isolate* isolate = v8_helper->isolate();
diff --git a/content/services/auction_worklet/seller_worklet.cc b/content/services/auction_worklet/seller_worklet.cc
index cb05a30b..8a65226 100644
--- a/content/services/auction_worklet/seller_worklet.cc
+++ b/content/services/auction_worklet/seller_worklet.cc
@@ -11,6 +11,7 @@
 #include <memory>
 #include <optional>
 #include <string>
+#include <string_view>
 #include <utility>
 #include <vector>
 
@@ -310,7 +311,7 @@
     std::optional<blink::AdCurrency> expected_seller_currency,
     std::optional<blink::AdCurrency> component_expect_bid_currency,
     const GURL& script_url,
-    base::StringPiece bid_label,
+    std::string_view bid_label,
     std::vector<std::string>& errors_out) {
   if (!blink::VerifyAdCurrencyCode(expected_seller_currency,
                                    provided_currency)) {
diff --git a/content/services/auction_worklet/webidl_compat_unittest.cc b/content/services/auction_worklet/webidl_compat_unittest.cc
index 5cd5b519..950eb868 100644
--- a/content/services/auction_worklet/webidl_compat_unittest.cc
+++ b/content/services/auction_worklet/webidl_compat_unittest.cc
@@ -7,6 +7,7 @@
 #include <cmath>
 #include <initializer_list>
 #include <memory>
+#include <string_view>
 
 #include "base/check.h"
 #include "base/strings/strcat.h"
@@ -100,7 +101,7 @@
   }
 
   bool GetSequence(DictConverter* converter,
-                   base::StringPiece field,
+                   std::string_view field,
                    v8::LocalVector<v8::Value>& out) {
     out.clear();  // For tests that re-use `out`.
     bool got_it = false;
diff --git a/content/shell/browser/fuchsia_view_presenter.cc b/content/shell/browser/fuchsia_view_presenter.cc
index d5b8679..ca59f19 100644
--- a/content/shell/browser/fuchsia_view_presenter.cc
+++ b/content/shell/browser/fuchsia_view_presenter.cc
@@ -11,7 +11,6 @@
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/location.h"
-#include "base/strings/string_piece.h"
 #include "ui/platform_window/fuchsia/initialize_presenter_api_view.h"
 
 namespace content {
diff --git a/content/shell/browser/shell.h b/content/shell/browser/shell.h
index c217090..c96e6cc5 100644
--- a/content/shell/browser/shell.h
+++ b/content/shell/browser/shell.h
@@ -13,7 +13,6 @@
 #include "base/functional/callback_forward.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/strings/string_piece.h"
 #include "build/build_config.h"
 #include "content/public/browser/session_storage_namespace.h"
 #include "content/public/browser/web_contents_delegate.h"
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc
index 5a87ec33..5f2cc5ce 100644
--- a/content/shell/browser/shell_content_browser_client.cc
+++ b/content/shell/browser/shell_content_browser_client.cc
@@ -9,6 +9,7 @@
 #include <functional>
 #include <memory>
 #include <string>
+#include <string_view>
 #include <utility>
 #include <vector>
 
@@ -23,7 +24,6 @@
 #include "base/no_destructor.h"
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequence_local_storage_slot.h"
@@ -239,11 +239,11 @@
       base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
           switches::kIsolatedContextOrigins));
 
-  std::vector<base::StringPiece> origin_strings = base::SplitStringPiece(
+  std::vector<std::string_view> origin_strings = base::SplitStringPiece(
       cmdline_origins, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
 
   base::flat_set<url::Origin> origin_set;
-  for (const base::StringPiece& origin_string : origin_strings) {
+  for (const std::string_view& origin_string : origin_strings) {
     url::Origin allowed_origin = url::Origin::Create(GURL(origin_string));
     if (!allowed_origin.opaque()) {
       origin_set.insert(allowed_origin);
diff --git a/content/shell/browser/shell_devtools_bindings.cc b/content/shell/browser/shell_devtools_bindings.cc
index a528b235..9b91a8a 100644
--- a/content/shell/browser/shell_devtools_bindings.cc
+++ b/content/shell/browser/shell_devtools_bindings.cc
@@ -6,6 +6,7 @@
 
 #include <stddef.h>
 
+#include <string_view>
 #include <utility>
 #include <vector>
 
@@ -20,7 +21,6 @@
 #include "base/no_destructor.h"
 #include "base/ranges/algorithm.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/uuid.h"
@@ -117,7 +117,7 @@
     response_headers_ = response_head.headers;
   }
 
-  void OnDataReceived(base::StringPiece chunk,
+  void OnDataReceived(std::string_view chunk,
                       base::OnceClosure resume) override {
     base::Value chunkValue;
 
@@ -401,8 +401,8 @@
 void ShellDevToolsBindings::DispatchProtocolMessage(
     DevToolsAgentHost* agent_host,
     base::span<const uint8_t> message) {
-  base::StringPiece str_message(reinterpret_cast<const char*>(message.data()),
-                                message.size());
+  std::string_view str_message(reinterpret_cast<const char*>(message.data()),
+                               message.size());
   if (str_message.length() < kShellMaxMessageChunkSize) {
     CallClientFunction("DevToolsAPI", "dispatchMessage",
                        base::Value(std::string(str_message)));
@@ -410,7 +410,7 @@
     size_t total_size = str_message.length();
     for (size_t pos = 0; pos < str_message.length();
          pos += kShellMaxMessageChunkSize) {
-      base::StringPiece str_message_chunk =
+      std::string_view str_message_chunk =
           str_message.substr(pos, kShellMaxMessageChunkSize);
 
       CallClientFunction(
diff --git a/content/shell/browser/shell_platform_delegate_android.cc b/content/shell/browser/shell_platform_delegate_android.cc
index 37297f1..0115366 100644
--- a/content/shell/browser/shell_platform_delegate_android.cc
+++ b/content/shell/browser/shell_platform_delegate_android.cc
@@ -11,7 +11,6 @@
 #include "base/command_line.h"
 #include "base/containers/contains.h"
 #include "base/notreached.h"
-#include "base/strings/string_piece.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
diff --git a/content/shell/common/shell_content_client.cc b/content/shell/common/shell_content_client.cc
index 71c04cb..2af9f0b 100644
--- a/content/shell/common/shell_content_client.cc
+++ b/content/shell/common/shell_content_client.cc
@@ -4,8 +4,9 @@
 
 #include "content/shell/common/shell_content_client.h"
 
+#include <string_view>
+
 #include "base/command_line.h"
-#include "base/strings/string_piece.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "build/build_config.h"
@@ -44,7 +45,7 @@
   return l10n_util::GetStringUTF16(message_id);
 }
 
-base::StringPiece ShellContentClient::GetDataResource(
+std::string_view ShellContentClient::GetDataResource(
     int resource_id,
     ui::ResourceScaleFactor scale_factor) {
   return ui::ResourceBundle::GetSharedInstance().GetRawDataResourceForScale(
diff --git a/content/shell/common/shell_content_client.h b/content/shell/common/shell_content_client.h
index 31cd0f69..954c922 100644
--- a/content/shell/common/shell_content_client.h
+++ b/content/shell/common/shell_content_client.h
@@ -6,6 +6,7 @@
 #define CONTENT_SHELL_COMMON_SHELL_CONTENT_CLIENT_H_
 
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include "content/public/common/content_client.h"
@@ -19,7 +20,7 @@
   ~ShellContentClient() override;
 
   std::u16string GetLocalizedString(int message_id) override;
-  base::StringPiece GetDataResource(
+  std::string_view GetDataResource(
       int resource_id,
       ui::ResourceScaleFactor scale_factor) override;
   base::RefCountedMemory* GetDataResourceBytes(int resource_id) override;
diff --git a/content/shell/common/shell_origin_trial_policy.h b/content/shell/common/shell_origin_trial_policy.h
index 5dd0756e..2a1e22c 100644
--- a/content/shell/common/shell_origin_trial_policy.h
+++ b/content/shell/common/shell_origin_trial_policy.h
@@ -7,7 +7,6 @@
 
 #include <vector>
 
-#include "base/strings/string_piece.h"
 #include "third_party/blink/public/common/origin_trials/origin_trial_policy.h"
 
 namespace content {
diff --git a/content/test/content_test_bundle_data.filelist b/content/test/content_test_bundle_data.filelist
index 51a8b65..aebd91f 100644
--- a/content/test/content_test_bundle_data.filelist
+++ b/content/test/content_test_bundle_data.filelist
@@ -7160,6 +7160,7 @@
 data/send-beacon.html
 data/service_worker/add_save_data_to_title.js
 data/service_worker/add_save_data_to_title.js.mock-http-headers
+data/service_worker/auto_preload.js
 data/service_worker/cached_fetch_event.js
 data/service_worker/client_api_worker.js
 data/service_worker/clients_claim_worker.js
@@ -7229,7 +7230,7 @@
 data/service_worker/non_function_fetch_event.js
 data/service_worker/one_subframe.html
 data/service_worker/race_network_request.html
-data/service_worker/race_network_request.js
+data/service_worker/race_network_request_base.js
 data/service_worker/race_network_request_from_fetch_handler.html
 data/service_worker/request_navigate.html
 data/service_worker/request_origin_worker.js
@@ -7238,6 +7239,8 @@
 data/service_worker/static_import_worker.js
 data/service_worker/static_router.js
 data/service_worker/static_router_no_handler.js
+data/service_worker/static_router_race.js
+data/service_worker/static_router_race_match_all.js
 data/service_worker/sync.js.mock-http-headers
 data/service_worker/throttling_blocking_cache_addall_sw.js
 data/service_worker/throttling_blocking_sw.js
diff --git a/content/test/data/service_worker/auto_preload.js b/content/test/data/service_worker/auto_preload.js
new file mode 100644
index 0000000..eb9dad2
--- /dev/null
+++ b/content/test/data/service_worker/auto_preload.js
@@ -0,0 +1,16 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+importScripts('./race_network_request_base.js');
+
+self.addEventListener('install', e => {
+  e.addRoutes([
+    {
+      condition: {
+        urlPattern: {pathname: "/service_worker/no_race"}
+      },
+      source: "fetch-event"
+    }
+  ]);
+  self.skipWaiting();
+});
diff --git a/content/test/data/service_worker/race_network_request.js b/content/test/data/service_worker/race_network_request_base.js
similarity index 72%
rename from content/test/data/service_worker/race_network_request.js
rename to content/test/data/service_worker/race_network_request_base.js
index 3267dda..16b3fac 100644
--- a/content/test/data/service_worker/race_network_request.js
+++ b/content/test/data/service_worker/race_network_request_base.js
@@ -1,4 +1,4 @@
-// Copyright 2023 The Chromium Authors
+// Copyright 2024 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 const composeCustomResponse = () => {
@@ -16,26 +16,6 @@
       options);
 };
 
-self.addEventListener('install', e => {
-  if (e.addRoutes) {
-    e.addRoutes([
-      {
-        condition: {
-          urlPattern: {pathname: "/service_worker/race_network_and_fetch"}
-        },
-        source: "race-network-and-fetch-handler"
-      },
-      {
-        condition: {
-          urlPattern: {pathname: "/service_worker/no_race"}
-        },
-        source: "fetch-event"
-      }
-    ]);
-  }
-  self.skipWaiting();
-});
-
 self.addEventListener('activate', e => {
   e.waitUntil(clients.claim());
 });
diff --git a/content/test/data/service_worker/static_router_race.js b/content/test/data/service_worker/static_router_race.js
new file mode 100644
index 0000000..2a04fc9
--- /dev/null
+++ b/content/test/data/service_worker/static_router_race.js
@@ -0,0 +1,22 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+importScripts('./race_network_request_base.js');
+
+self.addEventListener('install', e => {
+  e.addRoutes([
+    {
+      condition: {
+        urlPattern: {pathname: "/service_worker/race_network_and_fetch"}
+      },
+      source: "race-network-and-fetch-handler"
+    },
+    {
+      condition: {
+        urlPattern: {pathname: "/service_worker/no_race"}
+      },
+      source: "fetch-event"
+    }
+  ]);
+  self.skipWaiting();
+});
diff --git a/content/test/data/service_worker/static_router_race_match_all.js b/content/test/data/service_worker/static_router_race_match_all.js
new file mode 100644
index 0000000..b061a5f
--- /dev/null
+++ b/content/test/data/service_worker/static_router_race_match_all.js
@@ -0,0 +1,14 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+importScripts('./race_network_request_base.js');
+
+self.addEventListener('install', e => {
+  e.addRoutes({
+    condition: {
+      urlPattern: new URLPattern({})
+    },
+    source: "race-network-and-fetch-handler"
+  });
+  self.skipWaiting();
+});
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 f3fc292..8546982 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
@@ -451,7 +451,6 @@
 ####################
 
 crbug.com/angleproject/4417 [ win angle-d3d11 ] conformance2/rendering/framebuffer-render-to-layer-angle-issue.html [ Failure ]
-crbug.com/angleproject/7109 [ angle-d3d11 win10 ] conformance2/renderbuffers/invalidate-framebuffer.html [ Failure ]
 crbug.com/angleproject/1465 [ win angle-d3d11 ] conformance2/glsl3/tricky-loop-conditions.html [ Failure ]
 
 ## Win / NVIDIA ##
@@ -469,24 +468,8 @@
 # wildcard flaky suppression for all of the tests.
 crbug.com/483282 [ angle-d3d11 win amd ] conformance2/rendering/blitframebuffer-stencil-only.html [ Failure ]
 
-# Failing on AMD RX 5500 XT
-crbug.com/1152597 [ win amd-0x7340 angle-d3d11 ] conformance/renderbuffers/framebuffer-state-restoration.html [ Failure ]
-crbug.com/1152599 [ win amd-0x7340 angle-d3d11 ] conformance/rendering/polygon-offset.html [ Failure ]
-crbug.com/1409858 [ win amd-0x7340 angle-d3d11 ] conformance/context/context-attributes-alpha-depth-stencil-antialias.html [ Failure ]
-crbug.com/1152603 [ win amd-0x7340 angle-d3d11 ] conformance2/renderbuffers/multisampled-depth-renderbuffer-initialization.html [ Failure ]
-crbug.com/1152606 [ win amd-0x7340 angle-d3d11 ] deqp/functional/gles3/fboinvalidate/* [ Failure ]
-crbug.com/1152606 [ win amd-0x7340 angle-d3d11 ] deqp/functional/gles3/fbomultisample.2_samples.html [ Failure ]
-crbug.com/1152606 [ win amd-0x7340 angle-d3d11 ] deqp/functional/gles3/fborender/shared_colorbuffer_01.html [ Failure ]
-crbug.com/1152606 [ win amd-0x7340 angle-d3d11 ] deqp/functional/gles3/fborender/shared_colorbuffer_02.html [ Failure ]
-crbug.com/1152606 [ win amd-0x7340 angle-d3d11 ] deqp/functional/gles3/framebufferblit/depth_stencil.html [ Failure ]
-crbug.com/1499404 [ win amd-0x7340 angle-d3d11 ] conformance2/textures/misc/tex-srgb-mipmap.html [ Failure ]
 
-# New extensions failing on Win/AMD
-crbug.com/1473838 [ win amd-0x7340 angle-d3d11 ] conformance/extensions/ext-clip-control.html [ Failure ]
-crbug.com/1473838 [ win amd-0x7340 angle-d3d11 ] conformance/extensions/webgl-polygon-mode.html [ Failure ]
 
-# D3D11 / AMD RX 5500 XT / Passthrough command decoder
-crbug.com/1159539 [ win amd-0x7340 angle-d3d11 passthrough ] deqp/functional/gles3/fborender/recreate_color_* [ RetryOnFailure ]
 
 ## Win / Intel ##
 
@@ -494,7 +477,6 @@
 ## Win / Adreno 690 / D3D11
 crbug.com/1523062 [ win11 qualcomm-0x41333430 angle-d3d11 ] conformance/rendering/bind-framebuffer-flush-bug.html [ Failure ]
 crbug.com/1523062 [ win11 qualcomm-0x41333430 angle-d3d11 ] conformance/textures/misc/mipmap-fbo.html [ Failure ]
-crbug.com/1523062 [ win11 qualcomm-0x41333430 angle-d3d11 ] conformance/textures/misc/texture-mips.html [ Failure ]
 crbug.com/1523323 [ win11 qualcomm-0x41333430 angle-d3d11 ] deqp/functional/gles3/transformfeedback/basic_types_interleaved_lines.html [ Failure ]
 crbug.com/1523323 [ win11 qualcomm-0x41333430 angle-d3d11 ] deqp/functional/gles3/transformfeedback/basic_types_interleaved_points.html [ Failure ]
 crbug.com/1523323 [ win11 qualcomm-0x41333430 angle-d3d11 ] deqp/functional/gles3/transformfeedback/basic_types_interleaved_triangles.html [ Failure ]
@@ -523,7 +505,6 @@
 crbug.com/41496352 [ win11 qualcomm-0x41333430 angle-d3d11 ] deqp/functional/gles3/shaderprecision_float.html [ RetryOnFailure ]
 crbug.com/329211596 [ win11 qualcomm-0x41333430 angle-d3d11 ] deqp/functional/gles3/shaderprecision_int.html [ RetryOnFailure ]
 crbug.com/329211596 [ win11 qualcomm-0x41333430 angle-d3d11 ] deqp/functional/gles3/shaderprecision_uint.html [ RetryOnFailure ]
-crbug.com/323824490 [ win11 qualcomm-0x41333430 angle-d3d11 ] conformance/ogles/GL/ceil/ceil_001_to_006.html [ RetryOnFailure ]
 
 # Graphite
 crbug.com/329322651 [ win graphite-enabled ] conformance/textures/misc/texture-corner-case-videos.html [ Failure ]
@@ -572,7 +553,7 @@
 crbug.com/1316389 [ amd-0x67ef angle-metal passthrough ventura ] deqp/functional/gles3/transformfeedback/random_separate_points.html [ Failure ]
 crbug.com/1487266 [ amd-0x679e angle-metal monterey passthrough release ] deqp/functional/gles3/texturefiltering/2d_array_combinations_05.html [ Failure ]
 
-crbug.com/328100306 [ angle-metal graphite-enabled intel-0x3e9b sonoma ] conformance/glsl/bugs/sampler-array-using-loop-index.html [ Failure ]
+crbug.com/328100306 [ amd-0x67ef angle-metal graphite-enabled sonoma ] conformance/glsl/bugs/sampler-array-using-loop-index.html [ Failure ]
 
 ## SkiaGraphite on Metal AMD ##
 
@@ -621,8 +602,6 @@
 
 ## Metal Graphite ##
 
-crbug.com/329285449 [ mac angle-metal graphite-enabled apple ] conformance/textures/misc/texture-active-bind.html [ RetryOnFailure ]
-crbug.com/329285449 [ mac angle-metal graphite-enabled intel-0x3e9b ] conformance/textures/misc/texture-active-bind.html [ RetryOnFailure ]
 
 ######################################################################
 # Mac failures (mainly OpenGL; some need to be reevaluated on Metal) #
@@ -657,7 +636,7 @@
 crbug.com/795052 [ mac nvidia-0xfe9 ] conformance2/uniforms/draw-with-uniform-blocks.html [ Failure ]
 crbug.com/1457723 [ bigsur nvidia-0xfe9 angle-opengl ] conformance2/textures/canvas_sub_rectangle/tex-3d-* [ Failure ]
 crbug.com/1475765 [ bigsur nvidia-0xfe9 angle-opengl ] conformance/textures/canvas_sub_rectangle/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html [ Failure ]
-crbug.com/1475765 [ bigsur nvidia-0xfe9 angle-opengl ] conformance2/textures/canvas_sub_rectangle/tex-2d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html [ Failure ]
+crbug.com/1475765 [ angle-opengl bigsur nvidia-0xfe9 nvidia_lt_31.0.15.4601 ] conformance2/textures/canvas_sub_rectangle/tex-2d-rgb5_a1-rgba-unsigned_short_5_5_5_1.html [ Failure ]
 crbug.com/1488444 [ mac-x86_64 nvidia-0xfe9 angle-opengl passthrough ] conformance2/rendering/vertex-id-large-count.html [ Failure ]
 
 ## Mac AMD ##
@@ -899,7 +878,6 @@
 crbug.com/1488973 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance/glsl/bugs/constant-precision-qualifier.html [ Failure ]
 crbug.com/1488978 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance/limits/gl-max-texture-dimensions.html [ Failure ]
 crbug.com/1488979 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance/misc/shader-precision-format.html [ Failure ]
-crbug.com/1492240 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance2/extensions/ext-disjoint-timer-query-webgl2.html [ Failure ]
 crbug.com/1492241 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance/rendering/clear-default-framebuffer-with-scissor-test.html [ Failure ]
 crbug.com/1492242 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance2/buffers/uniform-buffers.html [ Failure ]
 crbug.com/1492245 [ chromeos cros-chrome chromeos-board-jacuzzi ] conformance2/extensions/oes-sample-variables.html [ Failure ]
@@ -955,7 +933,6 @@
 
 crbug.com/326490772 [ chromeos lacros-chrome chromeos-board-jacuzzi passthrough ] conformance2/extensions/webgl-shader-pixel-local-storage.html [ Failure ]
 crbug.com/326490772 [ chromeos lacros-chrome chromeos-board-jacuzzi passthrough ] conformance2/glsl3/texture-bias.html [ Failure ]
-crbug.com/326490772 [ chromeos lacros-chrome chromeos-board-jacuzzi passthrough ] conformance/rendering/clear-default-framebuffer-with-scissor-test.html [ Failure ]
 crbug.com/326490772 [ chromeos lacros-chrome chromeos-board-jacuzzi passthrough ] conformance2/extensions/oes-sample-variables.html [ Failure ]
 
 ##############################
diff --git a/content/test/mock_reduce_accept_language_controller_delegate.cc b/content/test/mock_reduce_accept_language_controller_delegate.cc
index a0bf384..fbc9690 100644
--- a/content/test/mock_reduce_accept_language_controller_delegate.cc
+++ b/content/test/mock_reduce_accept_language_controller_delegate.cc
@@ -4,6 +4,8 @@
 
 #include "content/test/mock_reduce_accept_language_controller_delegate.h"
 
+#include <string_view>
+
 #include "base/strings/string_split.h"
 #include "content/public/common/origin_util.h"
 #include "net/http/http_util.h"
@@ -13,7 +15,7 @@
 
 namespace {
 
-std::string GetFirstLanguage(base::StringPiece language_list) {
+std::string GetFirstLanguage(std::string_view language_list) {
   auto end = language_list.find(",");
   return std::string(language_list.substr(0, end));
 }
diff --git a/content/test/test_content_client.cc b/content/test/test_content_client.cc
index cbb4e73..99f5e34 100644
--- a/content/test/test_content_client.cc
+++ b/content/test/test_content_client.cc
@@ -4,6 +4,8 @@
 
 #include "content/test/test_content_client.h"
 
+#include <string_view>
+
 #include "ui/base/resource/resource_bundle.h"
 
 namespace content {
@@ -12,7 +14,7 @@
 
 TestContentClient::~TestContentClient() = default;
 
-base::StringPiece TestContentClient::GetDataResource(
+std::string_view TestContentClient::GetDataResource(
     int resource_id,
     ui::ResourceScaleFactor scale_factor) {
   return ui::ResourceBundle::GetSharedInstance().GetRawDataResourceForScale(
diff --git a/content/test/test_content_client.h b/content/test/test_content_client.h
index 3c87423..6778f07 100644
--- a/content/test/test_content_client.h
+++ b/content/test/test_content_client.h
@@ -5,6 +5,8 @@
 #ifndef CONTENT_TEST_TEST_CONTENT_CLIENT_H_
 #define CONTENT_TEST_TEST_CONTENT_CLIENT_H_
 
+#include <string_view>
+
 #include "content/public/common/content_client.h"
 
 namespace content {
@@ -19,7 +21,7 @@
   ~TestContentClient() override;
 
   // ContentClient:
-  base::StringPiece GetDataResource(
+  std::string_view GetDataResource(
       int resource_id,
       ui::ResourceScaleFactor scale_factor) override;
   base::RefCountedMemory* GetDataResourceBytes(int resource_id) override;
diff --git a/content/web_test/browser/devtools_protocol_test_bindings.cc b/content/web_test/browser/devtools_protocol_test_bindings.cc
index 42cdd37..b1ccde0 100644
--- a/content/web_test/browser/devtools_protocol_test_bindings.cc
+++ b/content/web_test/browser/devtools_protocol_test_bindings.cc
@@ -4,6 +4,8 @@
 
 #include "content/web_test/browser/devtools_protocol_test_bindings.h"
 
+#include <string_view>
+
 #include "base/command_line.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
@@ -175,7 +177,7 @@
   if (log_enabled_) {
     NOTREACHED_NORETURN() << "Unexpected messages dispatched by the browser";
   }
-  base::StringPiece str_message(reinterpret_cast<const char*>(message.data()),
+  std::string_view str_message(reinterpret_cast<const char*>(message.data()),
                                 message.size());
   WebTestControlHost::Get()->PrintMessageToStderr(
       "Protocol message: " + std::string(str_message) + "\n");
diff --git a/content/web_test/browser/web_test_bluetooth_adapter_provider.cc b/content/web_test/browser/web_test_bluetooth_adapter_provider.cc
index d06fc6d..f2adc3a 100644
--- a/content/web_test/browser/web_test_bluetooth_adapter_provider.cc
+++ b/content/web_test/browser/web_test_bluetooth_adapter_provider.cc
@@ -34,7 +34,6 @@
 
 namespace {
 
-using ::base::StringPiece;
 using ::base::test::RunOnceCallback;
 using ::device::BluetoothAdapter;
 using ::device::BluetoothDevice;
diff --git a/content/web_test/browser/web_test_control_host.cc b/content/web_test/browser/web_test_control_host.cc
index 414beb6..4bff48d 100644
--- a/content/web_test/browser/web_test_control_host.cc
+++ b/content/web_test/browser/web_test_control_host.cc
@@ -15,6 +15,7 @@
 #include <queue>
 #include <set>
 #include <string>
+#include <string_view>
 #include <utility>
 #include <vector>
 
@@ -448,7 +449,7 @@
   *output_ << "Content-Transfer-Encoding: base64\n";
 
   std::string data_base64 = base::Base64Encode(
-      base::StringPiece(reinterpret_cast<const char*>(&data[0]), data.size()));
+      std::string_view(reinterpret_cast<const char*>(&data[0]), data.size()));
 
   *output_ << "Content-Length: " << data_base64.length() << "\n";
   output_->write(data_base64.c_str(), data_base64.length());
diff --git a/content/web_test/common/web_test_string_util.cc b/content/web_test/common/web_test_string_util.cc
index 22e1567..bb20d0e 100644
--- a/content/web_test/common/web_test_string_util.cc
+++ b/content/web_test/common/web_test_string_util.cc
@@ -6,6 +6,8 @@
 
 #include <stddef.h>
 
+#include <string_view>
+
 #include "base/containers/heap_array.h"
 #include "base/lazy_instance.h"
 #include "base/rand_util.h"
@@ -17,8 +19,8 @@
 
 namespace {
 
-constexpr base::StringPiece kWebTestsPattern = "/web_tests/";
-constexpr base::StringPiece kFileURLPattern = "file://";
+constexpr std::string_view kWebTestsPattern = "/web_tests/";
+constexpr std::string_view kFileURLPattern = "file://";
 const char* kFileTestPrefix = "(file test):";
 const char* kPolicyDownload = "download";
 const char* kPolicyCurrentTab = "current tab";
@@ -37,7 +39,7 @@
   if (base::StartsWith(url, kFileURLPattern)) {
     // Adjust the file URL by removing the part depending on the testing
     // environment.
-    size_t pos = base::StringPiece(url).find(kWebTestsPattern);
+    size_t pos = std::string_view(url).find(kWebTestsPattern);
     if (pos != std::string::npos)
       result.replace(0, pos + kWebTestsPattern.size(), kFileTestPrefix);
   }
diff --git a/content/web_test/renderer/blink_test_helpers.cc b/content/web_test/renderer/blink_test_helpers.cc
index b44dcea6..7c78ae7 100644
--- a/content/web_test/renderer/blink_test_helpers.cc
+++ b/content/web_test/renderer/blink_test_helpers.cc
@@ -4,10 +4,11 @@
 
 #include "content/web_test/renderer/blink_test_helpers.h"
 
+#include <string_view>
+
 #include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/path_service.h"
-#include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
@@ -27,7 +28,7 @@
 
 namespace {
 
-constexpr base::StringPiece kFileScheme = "file:///";
+constexpr std::string_view kFileScheme = "file:///";
 
 base::FilePath GetWebTestsFilePath() {
   static base::FilePath path;
@@ -63,7 +64,7 @@
 // the WPT test directory.
 //
 // Note that this doesn't apply when the WPT tests are run by the python script.
-WebURL RewriteWPTAbsolutePath(base::StringPiece utf8_url) {
+WebURL RewriteWPTAbsolutePath(std::string_view utf8_url) {
   if (!base::StartsWith(utf8_url, kFileScheme, base::CompareCase::SENSITIVE) ||
       utf8_url.find("/web_tests/") != std::string::npos) {
     return WebURL(GURL(utf8_url));
@@ -74,9 +75,9 @@
   static constexpr size_t kFileSchemeAndDriveLen = kFileScheme.size() + 3;
   if (utf8_url.size() <= kFileSchemeAndDriveLen)
     return WebURL();
-  base::StringPiece path = utf8_url.substr(kFileSchemeAndDriveLen);
+  std::string_view path = utf8_url.substr(kFileSchemeAndDriveLen);
 #else
-  base::StringPiece path = utf8_url.substr(kFileScheme.size());
+  std::string_view path = utf8_url.substr(kFileScheme.size());
 #endif
   base::FilePath new_path = GetExternalWPTFilePath().AppendASCII(path);
   return WebURL(net::FilePathToFileURL(new_path));
@@ -126,11 +127,11 @@
   return result;
 }
 
-WebURL RewriteWebTestsURL(base::StringPiece utf8_url, bool is_wpt_mode) {
+WebURL RewriteWebTestsURL(std::string_view utf8_url, bool is_wpt_mode) {
   if (is_wpt_mode)
     return RewriteWPTAbsolutePath(utf8_url);
 
-  static constexpr base::StringPiece kGenPrefix = "file:///gen/";
+  static constexpr std::string_view kGenPrefix = "file:///gen/";
 
   // Map "file:///gen/" to "file://<build directory>/gen/".
   if (base::StartsWith(utf8_url, kGenPrefix, base::CompareCase::SENSITIVE)) {
@@ -142,7 +143,7 @@
     return WebURL(GURL(new_url));
   }
 
-  static constexpr base::StringPiece kPrefix = "file:///tmp/web_tests/";
+  static constexpr std::string_view kPrefix = "file:///tmp/web_tests/";
 
   if (!base::StartsWith(utf8_url, kPrefix, base::CompareCase::SENSITIVE))
     return WebURL(GURL(utf8_url));
@@ -153,11 +154,11 @@
   return WebURL(GURL(new_url));
 }
 
-WebURL RewriteFileURLToLocalResource(base::StringPiece resource) {
+WebURL RewriteFileURLToLocalResource(std::string_view resource) {
   return RewriteWebTestsURL(resource, /*is_wpt_mode=*/false);
 }
 
-bool IsWebPlatformTest(base::StringPiece test_url) {
+bool IsWebPlatformTest(std::string_view test_url) {
   // ://web-platform.test is a part of the http/https URL of a wpt test run by
   // the python script.
   return test_url.find("://web-platform.test") != std::string::npos ||
diff --git a/content/web_test/renderer/blink_test_helpers.h b/content/web_test/renderer/blink_test_helpers.h
index 6622da9..e05eb541 100644
--- a/content/web_test/renderer/blink_test_helpers.h
+++ b/content/web_test/renderer/blink_test_helpers.h
@@ -5,7 +5,8 @@
 #ifndef CONTENT_WEB_TEST_RENDERER_BLINK_TEST_HELPERS_H_
 #define CONTENT_WEB_TEST_RENDERER_BLINK_TEST_HELPERS_H_
 
-#include "base/strings/string_piece.h"
+#include <string_view>
+
 #include "third_party/blink/public/platform/web_url.h"
 
 namespace blink {
@@ -32,13 +33,13 @@
 //    to a temporary file under the web_tests directory.
 // 3. If the URL starts with file:///gen/, then return a file URL to the file
 //    under the gen/ directory of the build out.
-blink::WebURL RewriteWebTestsURL(base::StringPiece utf8_url, bool is_wpt_mode);
+blink::WebURL RewriteWebTestsURL(std::string_view utf8_url, bool is_wpt_mode);
 
 // Applies the rewrite rules except 1 of RewriteWebTestsURL().
-blink::WebURL RewriteFileURLToLocalResource(base::StringPiece resource);
+blink::WebURL RewriteFileURLToLocalResource(std::string_view resource);
 
 // Returns true if |test_url| points to a web platform test (WPT).
-bool IsWebPlatformTest(base::StringPiece test_url);
+bool IsWebPlatformTest(std::string_view test_url);
 
 }  // namespace content
 
diff --git a/content/web_test/renderer/fake_subresource_filter.cc b/content/web_test/renderer/fake_subresource_filter.cc
index 5fe6aed..aa90cc3 100644
--- a/content/web_test/renderer/fake_subresource_filter.cc
+++ b/content/web_test/renderer/fake_subresource_filter.cc
@@ -4,6 +4,8 @@
 
 #include "content/web_test/renderer/fake_subresource_filter.h"
 
+#include <string_view>
+
 #include "base/ranges/algorithm.h"
 #include "base/strings/string_util.h"
 #include "third_party/blink/public/platform/web_url.h"
@@ -40,7 +42,7 @@
 blink::WebDocumentSubresourceFilter::LoadPolicy
 FakeSubresourceFilter::GetLoadPolicyImpl(const blink::WebURL& url) {
   GURL gurl(url);
-  base::StringPiece path(gurl.path_piece());
+  std::string_view path(gurl.path_piece());
 
   // Allows things not listed in |disallowed_path_suffixes_|.
   if (base::ranges::none_of(
diff --git a/content/web_test/renderer/test_runner.cc b/content/web_test/renderer/test_runner.cc
index b29938b..0cd72b5 100644
--- a/content/web_test/renderer/test_runner.cc
+++ b/content/web_test/renderer/test_runner.cc
@@ -9,6 +9,7 @@
 #include <algorithm>
 #include <clocale>
 #include <limits>
+#include <string_view>
 #include <utility>
 #include <vector>
 
@@ -19,7 +20,6 @@
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind.h"
@@ -2781,15 +2781,15 @@
 printing::PageRanges TestRunner::GetPrintingPageRanges(
     blink::WebLocalFrame* frame) const {
   const std::string page_ranges_string = GetPageRangesStringFromMetadata(frame);
-  const std::vector<base::StringPiece> range_strings =
+  const std::vector<std::string_view> range_strings =
       base::SplitStringPiece(page_ranges_string, ",", base::TRIM_WHITESPACE,
                              base::SPLIT_WANT_NONEMPTY);
   printing::PageRanges result;
 
-  for (const base::StringPiece& range_string : range_strings) {
+  for (const std::string_view& range_string : range_strings) {
     // The format for each range is "<int> | <int>? - <int>?" where the page
     // numbers are 1-indexed.
-    const std::vector<base::StringPiece> page_strings = base::SplitStringPiece(
+    const std::vector<std::string_view> page_strings = base::SplitStringPiece(
         range_string, "-", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
     bool invalid = false;
 
diff --git a/content/web_test/renderer/test_websocket_handshake_throttle_provider.cc b/content/web_test/renderer/test_websocket_handshake_throttle_provider.cc
index e56c55b..bdeb093a 100644
--- a/content/web_test/renderer/test_websocket_handshake_throttle_provider.cc
+++ b/content/web_test/renderer/test_websocket_handshake_throttle_provider.cc
@@ -4,10 +4,11 @@
 
 #include "content/web_test/renderer/test_websocket_handshake_throttle_provider.h"
 
+#include <string_view>
+
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
@@ -29,13 +30,13 @@
   url::Component query = url.parsed_for_possibly_invalid_spec().query;
   url::Component key;
   url::Component value;
-  base::StringPiece spec = url.possibly_invalid_spec();
+  std::string_view spec = url.possibly_invalid_spec();
   while (url::ExtractQueryKeyValue(spec, &query, &key, &value)) {
-    base::StringPiece key_piece = spec.substr(key.begin, key.len);
+    std::string_view key_piece = spec.substr(key.begin, key.len);
     if (key_piece != "content-shell-websocket-delay-ms")
       continue;
 
-    base::StringPiece value_piece = spec.substr(value.begin, value.len);
+    std::string_view value_piece = spec.substr(value.begin, value.len);
     int value_int;
     if (!base::StringToInt(value_piece, &value_int) || value_int < 0)
       return base::TimeDelta();
diff --git a/docs/telemetry_extension/api_overview.md b/docs/telemetry_extension/api_overview.md
index 346f2bf..d68ca27 100644
--- a/docs/telemetry_extension/api_overview.md
+++ b/docs/telemetry_extension/api_overview.md
@@ -374,14 +374,19 @@
 | buttonType | VolumeButtonType | The volume button to be tested |
 | timeoutSeconds | number | Length of time to listen to the volume button events. The value should be positive and less or equal to 600 seconds |
 
+### CreateNetworkBandwidthRoutineArguments
+| Property Name | Type | Description |
+------------ | ------- | ----------- |
+
 ### CreateRoutineArgumentsUnion
 This is a union type. Exactly one field is set.
 
-| Property Name | Type | Released in Chrome version | Description |
------------- | ------- | ----------- | ----------- |
-| memory | CreateMemoryRoutineArguments | M125 | Arguments to create a memory routine |
-| volumeButton | CreateVolumeButtonRoutineArguments | M125 | Arguments to create a volume button routine |
-| fan | CreateFanRoutineArguments | M125 | Arguments to create a fan routine |
+| Property Name | Type | Released in Chrome version | Description | Additional permission needed to access |
+------------ | ------- | ----------- | ----------- | ----------- |
+| memory | CreateMemoryRoutineArguments | M125 | Arguments to create a memory routine | None |
+| volumeButton | CreateVolumeButtonRoutineArguments | M125 | Arguments to create a volume button routine | None |
+| fan | CreateFanRoutineArguments | M125 | Arguments to create a fan routine | None |
+| networkBandwidth | CreateNetworkBandwidthRoutineArguments | M125 | Arguments to create a network bandwidth routine | `os.diagnostics.network_info_mlab` |
 
 ### CreateRoutineResponse
 | Property Name | Type | Description |
diff --git a/infra/config/generated/builders/build/linux-chromeos-build-perf-siso/properties.json b/infra/config/generated/builders/build/linux-chromeos-build-perf-siso/properties.json
index 68522486..7294a8b 100644
--- a/infra/config/generated/builders/build/linux-chromeos-build-perf-siso/properties.json
+++ b/infra/config/generated/builders/build/linux-chromeos-build-perf-siso/properties.json
@@ -59,7 +59,9 @@
     ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
-    "experiments": [],
+    "experiments": [
+      "no-fallback"
+    ],
     "project": "rbe-chromium-untrusted"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/build/mac-build-perf-siso/properties.json b/infra/config/generated/builders/build/mac-build-perf-siso/properties.json
index d0896ff..2e69767 100644
--- a/infra/config/generated/builders/build/mac-build-perf-siso/properties.json
+++ b/infra/config/generated/builders/build/mac-build-perf-siso/properties.json
@@ -60,7 +60,9 @@
     ],
     "enable_cloud_profiler": true,
     "enable_cloud_trace": true,
-    "experiments": [],
+    "experiments": [
+      "no-fallback"
+    ],
     "project": "rbe-chromium-untrusted"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/linux-full-remote-rel/properties.json b/infra/config/generated/builders/try/linux-full-remote-rel/properties.json
index b317759..7280dc9 100644
--- a/infra/config/generated/builders/try/linux-full-remote-rel/properties.json
+++ b/infra/config/generated/builders/try/linux-full-remote-rel/properties.json
@@ -153,7 +153,8 @@
           "builder": "Linux Tests",
           "project": "chromium"
         }
-      ]
+      ],
+      "is_compile_only": true
     }
   },
   "$build/code_coverage": {
diff --git a/infra/config/generated/testing/test_suites.pyl b/infra/config/generated/testing/test_suites.pyl
index 9a0f7ec..f7b0405 100644
--- a/infra/config/generated/testing/test_suites.pyl
+++ b/infra/config/generated/testing/test_suites.pyl
@@ -1976,6 +1976,28 @@
       },
     },
 
+    'devtools_web_isolated_scripts': {
+      'blink_web_tests': {
+        'results_handler': 'layout tests',
+        'mixins': [
+          'has_native_resultdb_integration',
+          'blink_tests_write_run_histories',
+        ],
+        'args': [
+          '--num-retries=3',
+        ],
+        'swarming': {
+          'shards': 5,
+        },
+        'merge': {
+          'script': '//third_party/blink/tools/merge_web_test_results.py',
+          'args': [
+            '--verbose',
+          ],
+        },
+      },
+    },
+
     'devtools_webkit_isolated_scripts': {
       'blink_web_tests': {
         'results_handler': 'layout tests',
diff --git a/infra/config/generated/testing/variants.pyl b/infra/config/generated/testing/variants.pyl
index d457a9a..1d11ec4 100644
--- a/infra/config/generated/testing/variants.pyl
+++ b/infra/config/generated/testing/variants.pyl
@@ -267,16 +267,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'identifier': 'Lacros version skew testing ash canary',
-    'description': 'Run with ash-chrome version 125.0.6411.0',
+    'description': 'Run with ash-chrome version 125.0.6412.0',
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v125.0.6411.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v125.0.6412.0/test_ash_chrome',
     ],
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v125.0.6411.0',
-          'revision': 'version:125.0.6411.0',
+          'location': 'lacros_version_skew_tests_v125.0.6412.0',
+          'revision': 'version:125.0.6412.0',
         },
       ],
     },
diff --git a/infra/config/subprojects/build/build.star b/infra/config/subprojects/build/build.star
index 9bcc2f7..b617dc1 100644
--- a/infra/config/subprojects/build/build.star
+++ b/infra/config/subprojects/build/build.star
@@ -368,6 +368,7 @@
         category = "cros",
         short_name = "siso",
     ),
+    siso_experiments = ["no-fallback"],
 )
 
 cq_build_perf_builder(
@@ -435,6 +436,7 @@
         category = "mac",
         short_name = "siso",
     ),
+    siso_experiments = ["no-fallback"],
 )
 
 cq_build_perf_builder(
diff --git a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
index da1c3db..9e0c544 100644
--- a/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
+++ b/infra/config/subprojects/chromium/try/tryserver.chromium.linux.star
@@ -393,6 +393,9 @@
     name = "linux-full-remote-rel",
     description_html = "Experimental " + linkify_builder("try", "linux-rel", "chromium") + " builder with more kinds of remote actions. e.g. remote linking",
     mirrors = builder_config.copy_from("linux-rel"),
+    builder_config_settings = builder_config.try_settings(
+        is_compile_only = True,
+    ),
     gn_args = "try/linux-rel",
     compilator = "linux-full-remote-rel-compilator",
     contact_team_email = "chrome-build-team@google.com",
diff --git a/infra/config/targets/basic_suites.star b/infra/config/targets/basic_suites.star
index e5d6b0b..14820f0f 100644
--- a/infra/config/targets/basic_suites.star
+++ b/infra/config/targets/basic_suites.star
@@ -1859,6 +1859,17 @@
 )
 
 targets.legacy_basic_suite(
+    name = "devtools_web_isolated_scripts",
+    tests = {
+        "blink_web_tests": targets.legacy_test_config(
+            swarming = targets.swarming(
+                shards = 5,
+            ),
+        ),
+    },
+)
+
+targets.legacy_basic_suite(
     name = "devtools_webkit_isolated_scripts",
     tests = {
         "blink_web_tests": targets.legacy_test_config(
diff --git a/infra/config/targets/lacros-version-skew-variants.json b/infra/config/targets/lacros-version-skew-variants.json
index a5519a0..0ce3610 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_v125.0.6411.0/test_ash_chrome"
+      "--ash-chrome-path-override=../../lacros_version_skew_tests_v125.0.6412.0/test_ash_chrome"
     ],
-    "description": "Run with ash-chrome version 125.0.6411.0",
+    "description": "Run with ash-chrome version 125.0.6412.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_v125.0.6411.0",
-          "revision": "version:125.0.6411.0"
+          "location": "lacros_version_skew_tests_v125.0.6412.0",
+          "revision": "version:125.0.6412.0"
         }
       ]
     }
diff --git a/ios/chrome/app/application_delegate/app_state.h b/ios/chrome/app/application_delegate/app_state.h
index fbc105e..89260d6e 100644
--- a/ios/chrome/app/application_delegate/app_state.h
+++ b/ios/chrome/app/application_delegate/app_state.h
@@ -13,7 +13,6 @@
 #import "ios/chrome/browser/ui/scoped_iphone_portrait_only/iphone_portrait_only_manager.h"
 #import "ios/chrome/browser/ui/scoped_ui_blocker/ui_blocker_manager.h"
 
-@class AppState;
 class ChromeBrowserState;
 @class CommandDispatcher;
 @class SceneState;
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 6e52b27..c12a6d6 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -351,6 +351,8 @@
 // Handles collecting metrics on user triggered screenshots
 @property(nonatomic, strong)
     ScreenshotMetricsRecorder* screenshotMetricsRecorder;
+// Cleanup any persisted data for the session restration on disk.
+- (void)cleanupSessionStateCache;
 // Cleanup snapshots on disk.
 - (void)cleanupSnapshots;
 // Cleanup discarded sessions on disk.
@@ -1087,19 +1089,10 @@
 }
 
 - (void)scheduleSessionStateCacheCleanup {
-  // TODO(crbug.com/325612229): Refactor this to handle multiple browser states.
-  // Consider dedicated handling in DeferredInitializationRunner.
   [[DeferredInitializationRunner sharedInstance]
       enqueueBlockNamed:kPurgeWebSessionStates
                   block:^{
-                    ChromeBrowserState* browserState =
-                        self.appState.mainBrowserState;
-
-                    if (browserState) {
-                      SessionRestorationServiceFactory::GetForBrowserState(
-                          browserState)
-                          ->PurgeUnassociatedData(base::DoNothing());
-                    }
+                    [self cleanupSessionStateCache];
                   }];
 }
 
@@ -1416,6 +1409,17 @@
 
 #pragma mark - Helper methods.
 
+- (void)cleanupSessionStateCache {
+  std::vector<ChromeBrowserState*> loadedBrowserStates =
+      GetApplicationContext()
+          ->GetChromeBrowserStateManager()
+          ->GetLoadedBrowserStates();
+  for (ChromeBrowserState* browserState : loadedBrowserStates) {
+    SessionRestorationServiceFactory::GetForBrowserState(browserState)
+        ->PurgeUnassociatedData(base::DoNothing());
+  }
+}
+
 - (void)cleanupSnapshots {
   // TODO(crbug.com/1116496): Browsers for disconnected scenes are not in the
   // BrowserList, so this may not reach all folders.
diff --git a/ios/chrome/browser/ui/menu/action_factory.mm b/ios/chrome/browser/ui/menu/action_factory.mm
index 46ffe2f..3b5cc4ad 100644
--- a/ios/chrome/browser/ui/menu/action_factory.mm
+++ b/ios/chrome/browser/ui/menu/action_factory.mm
@@ -380,11 +380,13 @@
                                                    block:addTabToNewGroupBlock];
   }
 
-  UIImage* image = DefaultSymbolWithPointSize(kMoveTabToGroupActionSymbol,
-                                              kSymbolActionPointSize);
-
   NSMutableArray<UIMenuElement*>* groupsMenu = [[NSMutableArray alloc] init];
 
+  UIImage* circleImage =
+      DefaultSymbolWithPointSize(kCircleFillSymbol, kSymbolActionPointSize);
+  circleImage =
+      [circleImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
+
   for (const TabGroup* group : groups) {
     NSString* title = group->GetTitle();
     ProceduralBlock groupBlock = ^{
@@ -395,7 +397,7 @@
 
     UIAction* groupAction =
         [self actionWithTitle:title
-                        image:nil
+                        image:[circleImage imageWithTintColor:group->GetColor()]
                          type:MenuActionType::AddTabToExistingGroup
                         block:groupBlock];
     [groupsMenu addObject:groupAction];
@@ -418,6 +420,9 @@
     menu
   ];
 
+  UIImage* image = DefaultSymbolWithPointSize(kMoveTabToGroupActionSymbol,
+                                              kSymbolActionPointSize);
+
   return [UIMenu
       menuWithTitle:l10n_util::GetPluralNSStringF(
                         IDS_IOS_CONTENT_CONTEXT_ADDTABTOTABGROUP, tabsNumber)
diff --git a/ios/chrome/browser/ui/menu/action_factory_unittest.mm b/ios/chrome/browser/ui/menu/action_factory_unittest.mm
index 156a58d..d9e7762 100644
--- a/ios/chrome/browser/ui/menu/action_factory_unittest.mm
+++ b/ios/chrome/browser/ui/menu/action_factory_unittest.mm
@@ -473,7 +473,9 @@
   NSMutableSet* titles = [NSMutableSet set];
   for (UIMenuElement* group in submenu.children) {
     [titles addObject:group.title];
-    EXPECT_EQ(nil, group.image);
+    // The image should be colorful circle but it is hard to test. Just check
+    // non-nil.
+    EXPECT_NE(nil, group.image);
   }
 
   EXPECT_EQ(2u, titles.count);
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_profile_table_view_controller.mm b/ios/chrome/browser/ui/settings/autofill/autofill_profile_table_view_controller.mm
index f14dd81..b87c088 100644
--- a/ios/chrome/browser/ui/settings/autofill/autofill_profile_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_profile_table_view_controller.mm
@@ -540,7 +540,8 @@
       authenticationService->GetPrimaryIdentity(signin::ConsentLevel::kSignin);
   if (identity) {
     self.userEmail = identity.userEmail;
-    self.syncEnabled = _personalDataManager->IsSyncFeatureEnabledForAutofill();
+    self.syncEnabled = _personalDataManager->address_data_manager()
+                           .IsSyncFeatureEnabledForAutofill();
   }
 }
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/tab_groups/create_tab_group_view_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/tab_groups/create_tab_group_view_controller.mm
index 7723f9ee..6de4cc7 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/tab_groups/create_tab_group_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/tab_groups/create_tab_group_view_controller.mm
@@ -277,9 +277,7 @@
   UIFontDescriptor* boldDescriptor = [[UIFontDescriptor
       preferredFontDescriptorWithTextStyle:UIFontTextStyleBody]
       fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold];
-  UIFont* fontAttribute =
-      isCompact ? [UIFont fontWithDescriptor:boldDescriptor size:0.0]
-                : [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
+  UIFont* fontAttribute = [UIFont fontWithDescriptor:boldDescriptor size:0.0];
   NSDictionary* attributes = @{
     NSFontAttributeName : fontAttribute,
     NSForegroundColorAttributeName : textColor
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/tab_groups/tab_group_view_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/tab_groups/tab_group_view_controller.mm
index d966328..63b06ff4 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/tab_groups/tab_group_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/tab_groups/tab_group_view_controller.mm
@@ -33,6 +33,7 @@
 constexpr CGFloat kSubTitleHorizontalPadding = 7;
 constexpr CGFloat kThreeDotButtonSize = 19;
 constexpr CGFloat kTitleBackgroundCornerRadius = 17;
+constexpr CGFloat kPlusImageSize = 20;
 }  // namespace
 
 @interface TabGroupViewController () <UINavigationBarDelegate>
@@ -232,10 +233,12 @@
 // Returns the navigation item which contain the plus button.
 - (UINavigationItem*)configuredPlusButton {
   UINavigationItem* plus = [[UINavigationItem alloc] init];
-  plus.rightBarButtonItem = [[UIBarButtonItem alloc]
-      initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
-                           target:self
-                           action:@selector(didTapPlusButton)];
+  UIImage* plusImage = DefaultSymbolWithPointSize(kPlusSymbol, kPlusImageSize);
+  plus.rightBarButtonItem =
+      [[UIBarButtonItem alloc] initWithImage:plusImage
+                                       style:UIBarButtonItemStylePlain
+                                      target:self
+                                      action:@selector(didTapPlusButton)];
   return plus;
 }
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
index d64ffa7..1fe848c8 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/tab_grid_coordinator.mm
@@ -1012,10 +1012,12 @@
   switch (page) {
     case TabGridPageIncognitoTabs:
       DCHECK_GT(self.incognitoBrowser->GetWebStateList()->count(), 0);
+      self.activePage = page;
       activeBrowser = self.incognitoBrowser;
       break;
     case TabGridPageRegularTabs:
       DCHECK_GT(self.regularBrowser->GetWebStateList()->count(), 0);
+      self.activePage = page;
       activeBrowser = self.regularBrowser;
       break;
     case TabGridPageRemoteTabs:
diff --git a/ios_internal b/ios_internal
index c448ce7..debd0ef 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit c448ce76c3e84201da5db9ac4a2a579c2fabfdf3
+Subproject commit debd0ef81bb8df6520b9cc80141ec587cd8e1c56
diff --git a/media/audio/reconfigurable_audio_bus_pool_unittest.cc b/media/audio/reconfigurable_audio_bus_pool_unittest.cc
index 17a3013ea..8244912 100644
--- a/media/audio/reconfigurable_audio_bus_pool_unittest.cc
+++ b/media/audio/reconfigurable_audio_bus_pool_unittest.cc
@@ -85,18 +85,12 @@
   reconfigurable_audio_bus_pool_->InsertAudioBus(std::move(first_audio_bus));
   AudioBus* second_audio_bus_ptr = second_audio_bus.get();
   reconfigurable_audio_bus_pool_->InsertAudioBus(std::move(second_audio_bus));
-  AudioBus* third_audio_bus_ptr = third_audio_bus.get();
   reconfigurable_audio_bus_pool_->InsertAudioBus(std::move(third_audio_bus));
 
   EXPECT_EQ(second_audio_bus_ptr,
             reconfigurable_audio_bus_pool_->GetAudioBus().get());
   EXPECT_EQ(first_audio_bus_ptr,
             reconfigurable_audio_bus_pool_->GetAudioBus().get());
-
-  // The third audio bus was not recycled because the max capacity of the pool
-  // is 2.
-  EXPECT_NE(third_audio_bus_ptr,
-            reconfigurable_audio_bus_pool_->GetAudioBus().get());
 }
 
 }  // namespace media
diff --git a/net/dns/host_cache.cc b/net/dns/host_cache.cc
index 3b22bd2..b52e943 100644
--- a/net/dns/host_cache.cc
+++ b/net/dns/host_cache.cc
@@ -270,14 +270,14 @@
 }
 
 HostCache::Entry::Entry(
-    std::set<std::unique_ptr<HostResolverInternalResult>> results,
+    const std::set<std::unique_ptr<HostResolverInternalResult>>& results,
     base::Time now,
     base::TimeTicks now_ticks,
     Source empty_source) {
-  std::unique_ptr<HostResolverInternalResult> data_result;
-  std::unique_ptr<HostResolverInternalResult> metadata_result;
-  std::unique_ptr<HostResolverInternalResult> error_result;
-  std::vector<std::unique_ptr<HostResolverInternalResult>> alias_results;
+  const HostResolverInternalResult* data_result = nullptr;
+  const HostResolverInternalResult* metadata_result = nullptr;
+  const HostResolverInternalResult* error_result = nullptr;
+  std::vector<const HostResolverInternalResult*> alias_results;
 
   std::optional<base::TimeDelta> smallest_ttl =
       TtlFromInternalResults(results, now, now_ticks);
@@ -304,18 +304,18 @@
     switch (result->type()) {
       case HostResolverInternalResult::Type::kData:
         DCHECK(!data_result);  // Expect at most one data result.
-        data_result = std::move(results.extract(result).value());
+        data_result = result.get();
         break;
       case HostResolverInternalResult::Type::kMetadata:
         DCHECK(!metadata_result);  // Expect at most one metadata result.
-        metadata_result = std::move(results.extract(result).value());
+        metadata_result = result.get();
         break;
       case HostResolverInternalResult::Type::kError:
         DCHECK(!error_result);  // Expect at most one error result.
-        error_result = std::move(results.extract(result).value());
+        error_result = result.get();
         break;
       case HostResolverInternalResult::Type::kAlias:
-        alias_results.push_back(std::move(results.extract(result).value()));
+        alias_results.emplace_back(result.get());
         break;
     }
 
@@ -362,7 +362,7 @@
     hostnames_ = data_result->AsData().hosts();
     canonical_names_ = {data_result->domain_name()};
 
-    for (const auto& alias_result : alias_results) {
+    for (const auto* alias_result : alias_results) {
       aliases_.insert(alias_result->domain_name());
       aliases_.insert(alias_result->AsAlias().alias_target());
     }
diff --git a/net/dns/host_cache.h b/net/dns/host_cache.h
index 9f5449da..6a9735b8 100644
--- a/net/dns/host_cache.h
+++ b/net/dns/host_cache.h
@@ -160,7 +160,7 @@
     // results extracted from a single DnsTransaction. `empty_source` is Source
     // to assume if `results` is empty of any results from which Source can be
     // read.
-    Entry(std::set<std::unique_ptr<HostResolverInternalResult>> results,
+    Entry(const std::set<std::unique_ptr<HostResolverInternalResult>>& results,
           base::Time now,
           base::TimeTicks now_ticks,
           Source empty_source = SOURCE_UNKNOWN);
diff --git a/net/dns/host_resolver_dns_task.cc b/net/dns/host_resolver_dns_task.cc
index 4e89cdd..cde346bb 100644
--- a/net/dns/host_resolver_dns_task.cc
+++ b/net/dns/host_resolver_dns_task.cc
@@ -113,6 +113,21 @@
 
 }  // namespace
 
+HostResolverDnsTask::SingleTransactionResults::SingleTransactionResults(
+    DnsQueryType query_type,
+    Results results)
+    : query_type(query_type), results(std::move(results)) {}
+
+HostResolverDnsTask::SingleTransactionResults::~SingleTransactionResults() =
+    default;
+
+HostResolverDnsTask::SingleTransactionResults::SingleTransactionResults(
+    SingleTransactionResults&&) = default;
+
+HostResolverDnsTask::SingleTransactionResults&
+HostResolverDnsTask::SingleTransactionResults::operator=(
+    SingleTransactionResults&&) = default;
+
 HostResolverDnsTask::TransactionInfo::TransactionInfo(
     DnsQueryType type,
     TransactionErrorBehavior error_behavior)
@@ -352,10 +367,13 @@
     }
   }
 
+  // Clear in-progress and scheduled transactions so that
+  // OnTransactionsFinished() doesn't call delegate's
+  // OnIntermediateTransactionComplete().
   transactions_needed_.clear();
   transactions_in_progress_.clear();
 
-  OnTransactionsFinished();
+  OnTransactionsFinished(/*single_transaction_results=*/std::nullopt);
 }
 
 void HostResolverDnsTask::OnDnsTransactionComplete(
@@ -738,8 +756,8 @@
 
   // TODO(crbug.com/1381506): Use new results type directly instead of
   // converting to HostCache::Entry.
-  HostCache::Entry legacy_results(std::move(transaction_results),
-                                  base::Time::Now(), tick_clock_->NowTicks(),
+  HostCache::Entry legacy_results(transaction_results, base::Time::Now(),
+                                  tick_clock_->NowTicks(),
                                   HostCache::Entry::SOURCE_DNS);
 
   // Merge results with saved results from previous transactions.
@@ -777,13 +795,18 @@
   }
 
   saved_results_ = std::move(legacy_results);
-  OnTransactionsFinished();
+
+  OnTransactionsFinished(SingleTransactionResults(
+      transaction_info.type, std::move(transaction_results)));
 }
 
-void HostResolverDnsTask::OnTransactionsFinished() {
+void HostResolverDnsTask::OnTransactionsFinished(
+    std::optional<SingleTransactionResults> single_transaction_results) {
   if (!transactions_in_progress_.empty() || !transactions_needed_.empty()) {
-    delegate_->OnIntermediateTransactionsComplete();
     MaybeStartTimeoutTimer();
+    delegate_->OnIntermediateTransactionsComplete(
+        std::move(single_transaction_results));
+    // `this` may be deleted by `delegate_`. Do not add code below.
     return;
   }
 
@@ -883,7 +906,7 @@
     saved_results_is_failure_ = true;
 
     CancelNonFatalTransactions();
-    OnTransactionsFinished();
+    OnTransactionsFinished(/*single_transaction_results=*/std::nullopt);
     return;
   }
 
diff --git a/net/dns/host_resolver_dns_task.h b/net/dns/host_resolver_dns_task.h
index e4314af8..7630249 100644
--- a/net/dns/host_resolver_dns_task.h
+++ b/net/dns/host_resolver_dns_task.h
@@ -43,6 +43,24 @@
 class NET_EXPORT_PRIVATE HostResolverDnsTask
     : public base::SupportsWeakPtr<HostResolverDnsTask> {
  public:
+  using Results = std::set<std::unique_ptr<HostResolverInternalResult>>;
+
+  // Represents a single transaction results.
+  struct SingleTransactionResults {
+    SingleTransactionResults(DnsQueryType query_type, Results results);
+    ~SingleTransactionResults();
+
+    SingleTransactionResults(SingleTransactionResults&&);
+    SingleTransactionResults& operator=(SingleTransactionResults&&);
+
+    SingleTransactionResults(const SingleTransactionResults&) = delete;
+    SingleTransactionResults& operator=(const SingleTransactionResults&) =
+        delete;
+
+    DnsQueryType query_type;
+    Results results;
+  };
+
   class Delegate {
    public:
     virtual void OnDnsTaskComplete(base::TimeTicks start_time,
@@ -50,10 +68,13 @@
                                    HostCache::Entry results,
                                    bool secure) = 0;
 
-    // Called when one or more transactions complete or get cancelled, but only
-    // if more transactions are needed. If no more transactions are needed,
-    // expect `OnDnsTaskComplete()` to be called instead.
-    virtual void OnIntermediateTransactionsComplete() = 0;
+    // Called when one transaction completes successfully, or one more
+    // transactions get cancelled, but only if more transactions are
+    // needed. If no more transactions are needed, expect `OnDnsTaskComplete()`
+    // to be called instead. `single_transaction_results` is passed only when
+    // one transaction completes successfully.
+    virtual void OnIntermediateTransactionsComplete(
+        std::optional<SingleTransactionResults> single_transaction_results) = 0;
 
     virtual RequestPriority priority() const = 0;
 
@@ -94,8 +115,6 @@
   void StartNextTransaction();
 
  private:
-  using Results = std::set<std::unique_ptr<HostResolverInternalResult>>;
-
   enum class TransactionErrorBehavior {
     // Errors lead to task fallback (immediately unless another pending/started
     // transaction has the `kFatalOrEmpty` behavior).
@@ -164,7 +183,8 @@
   void HandleTransactionResults(TransactionInfo transaction_info,
                                 Results transaction_results);
 
-  void OnTransactionsFinished();
+  void OnTransactionsFinished(
+      std::optional<SingleTransactionResults> single_transaction_results);
 
   void OnSortComplete(base::TimeTicks sort_start_time,
                       HostCache::Entry results,
diff --git a/net/dns/host_resolver_manager_job.cc b/net/dns/host_resolver_manager_job.cc
index 3cb4e408..0d2daeb 100644
--- a/net/dns/host_resolver_manager_job.cc
+++ b/net/dns/host_resolver_manager_job.cc
@@ -741,7 +741,9 @@
                    secure ? TaskType::SECURE_DNS : TaskType::DNS);
 }
 
-void HostResolverManager::Job::OnIntermediateTransactionsComplete() {
+void HostResolverManager::Job::OnIntermediateTransactionsComplete(
+    std::optional<HostResolverDnsTask::SingleTransactionResults>
+        single_transaction_results) {
   if (dispatched_) {
     DCHECK_GE(num_occupied_job_slots_,
               dns_task_->num_transactions_in_progress());
@@ -770,6 +772,10 @@
   } else if (dns_task_->num_additional_transactions_needed() >= 1) {
     dns_task_->StartNextTransaction();
   }
+
+  // TODO(crbug.com/41493696): Use `single_transaction_results` for the
+  // ServiceEndpointRequest API. Be sure to handle the case where `this` was
+  // deleted while processing the intermediate results.
 }
 
 void HostResolverManager::Job::AddTransactionTimeQueued(
diff --git a/net/dns/host_resolver_manager_job.h b/net/dns/host_resolver_manager_job.h
index 4535262..3055e39 100644
--- a/net/dns/host_resolver_manager_job.h
+++ b/net/dns/host_resolver_manager_job.h
@@ -217,7 +217,9 @@
                          bool allow_fallback,
                          HostCache::Entry results,
                          bool secure) override;
-  void OnIntermediateTransactionsComplete() override;
+  void OnIntermediateTransactionsComplete(
+      std::optional<HostResolverDnsTask::SingleTransactionResults>
+          single_transaction_results) override;
   void AddTransactionTimeQueued(base::TimeDelta time_queued) override;
 
   void StartMdnsTask();
diff --git a/net/third_party/quiche/src b/net/third_party/quiche/src
index acbdda4..718c901 160000
--- a/net/third_party/quiche/src
+++ b/net/third_party/quiche/src
@@ -1 +1 @@
-Subproject commit acbdda4e4aa43e72a19aa72115b71e8eba57babb
+Subproject commit 718c9019fe67253ca9aa76498dff0f35ef97b15e
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 343081e..ec639872 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -29,6 +29,7 @@
 #include "base/ranges/algorithm.h"
 #include "base/sequence_checker.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/current_thread.h"
 #include "base/task/sequenced_task_runner.h"
@@ -444,13 +445,12 @@
 }
 
 std::string HashesToBase64String(const net::HashValueVector& hashes) {
-  std::string str;
-  for (size_t i = 0; i != hashes.size(); ++i) {
-    if (i != 0)
-      str += ",";
-    str += hashes[i].ToString();
+  std::vector<std::string> strings;
+  strings.reserve(hashes.size());
+  for (const auto& hash : hashes) {
+    strings.push_back(hash.ToString());
   }
-  return str;
+  return base::JoinString(strings, ",");
 }
 
 #if BUILDFLAG(IS_CT_SUPPORTED)
@@ -643,7 +643,8 @@
   url_request_context_owner_ = MakeURLRequestContext(
       std::move(url_loader_factory_for_cert_net_fetcher),
       session_cleanup_cookie_store,
-      std::move(on_url_request_context_builder_configured));
+      std::move(on_url_request_context_builder_configured),
+      params_->bound_network);
   url_request_context_ = url_request_context_owner_.url_request_context.get();
 
   cookie_manager_ = std::make_unique<CookieManager>(
@@ -2309,11 +2310,17 @@
         url_loader_factory_for_cert_net_fetcher,
     scoped_refptr<SessionCleanupCookieStore> session_cleanup_cookie_store,
     OnURLRequestContextBuilderConfiguredCallback
-        on_url_request_context_builder_configured) {
+        on_url_request_context_builder_configured,
+    net::handles::NetworkHandle bound_network) {
   URLRequestContextBuilderMojo builder;
   const base::CommandLine* command_line =
       base::CommandLine::ForCurrentProcess();
 
+  bool is_network_bound = bound_network != net::handles::kInvalidNetworkHandle;
+  if (is_network_bound) {
+    builder.BindToNetwork(bound_network);
+  }
+
   std::unique_ptr<net::CertVerifier> cert_verifier;
   if (g_cert_verifier_for_testing) {
     cert_verifier = std::make_unique<WrappedTestingCertVerifier>();
@@ -2402,10 +2409,15 @@
   if (network_service_) {
     net_log = network_service_->net_log();
     builder.set_net_log(net_log);
-    builder.set_host_resolver_manager(
-        network_service_->host_resolver_manager());
-    builder.set_host_resolver_factory(
-        network_service_->host_resolver_factory());
+    if (!is_network_bound) {
+      // Network bound URLRequestContexts build and configure their own special
+      // HostResolverManager and HostResolver. So, don't inject the
+      // NetworkService one even if NetworkService is enabled.
+      builder.set_host_resolver_manager(
+          network_service_->host_resolver_manager());
+      builder.set_host_resolver_factory(
+          network_service_->host_resolver_factory());
+    }
     builder.SetHttpAuthHandlerFactory(
         network_service_->CreateHttpAuthHandlerFactory(this));
     builder.set_network_quality_estimator(
@@ -2487,6 +2499,8 @@
       cache_params.type =
           net::URLRequestContextBuilder::HttpCacheParams::IN_MEMORY;
     } else {
+      // Network-bound NetworkContexts should not persist state on disk.
+      CHECK(!is_network_bound);
       cache_params.path = params_->file_paths->http_cache_directory->path();
       cache_params.type = network_session_configurator::ChooseCacheType();
       if (params_->http_cache_file_operations_factory) {
@@ -2532,6 +2546,8 @@
                           &network::mojom::NetworkContextFilePaths::
                               http_server_properties_file_name,
                           http_server_properties_file_name)) {
+    // Network-bound NetworkContexts should not persist state on disk.
+    CHECK(!is_network_bound);
     scoped_refptr<JsonPrefStore> json_pref_store(new JsonPrefStore(
         http_server_properties_file_name, nullptr,
         base::ThreadPool::CreateSequencedTaskRunner(
@@ -2559,6 +2575,8 @@
                           &network::mojom::NetworkContextFilePaths::
                               transport_security_persister_file_name,
                           transport_security_persister_file_name)) {
+    // Network-bound NetworkContexts should not persist state on disk.
+    CHECK(!is_network_bound);
     builder.set_transport_security_persister_file_path(
         transport_security_persister_file_name);
   }
@@ -2589,6 +2607,8 @@
                               reporting_and_nel_store_database_name,
                           reporting_and_nel_store_database_name) &&
       (reporting_enabled || nel_enabled)) {
+    // Network-bound NetworkContexts should not persist state on disk.
+    CHECK(!is_network_bound);
     scoped_refptr<base::SequencedTaskRunner> client_task_runner =
         base::SingleThreadTaskRunner::GetCurrentDefault();
     scoped_refptr<base::SequencedTaskRunner> background_task_runner =
diff --git a/services/network/network_context.h b/services/network/network_context.h
index 598cd51..acd59fe 100644
--- a/services/network/network_context.h
+++ b/services/network/network_context.h
@@ -685,7 +685,8 @@
           url_loader_factory_for_cert_net_fetcher,
       scoped_refptr<SessionCleanupCookieStore>,
       OnURLRequestContextBuilderConfiguredCallback
-          on_url_request_context_builder_configured);
+          on_url_request_context_builder_configured,
+      net::handles::NetworkHandle bound_network);
   scoped_refptr<SessionCleanupCookieStore> MakeSessionCleanupCookieStore()
       const;
 
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index c5ab0e4d..0c7a743 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -65,6 +65,7 @@
 #include "net/base/http_user_agent_settings.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/isolation_info.h"
+#include "net/base/mock_network_change_notifier.h"
 #include "net/base/net_errors.h"
 #include "net/base/network_change_notifier.h"
 #include "net/base/network_isolation_key.h"
@@ -173,6 +174,10 @@
 #include "services/network/public/mojom/p2p_trusted.mojom.h"
 #endif  // BUILDFLAG(IS_P2P_ENABLED)
 
+#if BUILDFLAG(IS_ANDROID)
+#include "base/android/build_info.h"
+#endif  // BUILDFLAG(IS_ANDROID)
+
 namespace network {
 
 namespace {
@@ -713,6 +718,44 @@
   }
 }
 
+TEST_F(NetworkContextTest, BoundNetwork) {
+#if BUILDFLAG(IS_ANDROID)
+  if (base::android::BuildInfo::GetInstance()->sdk_int() <
+      base::android::SDK_VERSION_MARSHMALLOW) {
+    GTEST_SKIP()
+        << "bound_network is supported starting from Android Marshmallow";
+  }
+
+  // The actual network handle doesn't really matter, this test just wants to
+  // confirm that it is correctly passed down to the owned URLRequestContext.
+  constexpr net::handles::NetworkHandle network = 2;
+  auto scoped_mock_network_change_notifier =
+      std::make_unique<net::test::ScopedMockNetworkChangeNotifier>();
+  auto* mock_ncn =
+      scoped_mock_network_change_notifier->mock_network_change_notifier();
+  mock_ncn->ForceNetworkHandlesSupported();
+
+  mojom::NetworkContextParamsPtr context_params =
+      CreateNetworkContextParamsForTesting();
+  context_params->bound_network = network;
+  std::unique_ptr<NetworkContext> network_context =
+      CreateContextWithParams(std::move(context_params));
+
+  EXPECT_EQ(network_context->url_request_context()->bound_network(), network);
+  EXPECT_EQ(network_context->url_request_context()
+                ->host_resolver()
+                ->GetTargetNetworkForTesting(),
+            network);
+  EXPECT_EQ(network_context->url_request_context()
+                ->host_resolver()
+                ->GetManagerForTesting()
+                ->target_network_for_testing(),
+            network);
+#else   // !BUILDFLAG(IS_ANDROID)
+  GTEST_SKIP() << "bound_network is supported only on Android";
+#endif  // BUILDFLAG(IS_ANDROID)
+}
+
 TEST_F(NetworkContextTest, UnhandedProtocols) {
   const GURL kUnsupportedUrls[] = {
       // These are handled outside the network service.
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index 5010e07..76a41bf 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -601,6 +601,15 @@
 
   // Enables Device Bound Session Credential for this network context.
   bool device_bound_sessions_enabled = false;
+
+  // Represents a net::handles::NetworkHandle.
+  // If != net::handles::kInvalidNetworkHandle (== -1), then the NetworkContext
+  // built out of this will own a URLRequestContext bound to that network (refer
+  // to net::UrlRequestContextBuilder::bindToNetwork documentation). This
+  // effectively means that URLLoaderFactories, returned by the NetworkContext
+  // created out of this, will perform all network request using only
+  // |bound_network|.
+  int64 bound_network = -1;
 };
 
 struct NetworkConditions {
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index fea2751..6b12440b 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -5484,9 +5484,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_v125.0.6411.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v125.0.6412.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 125.0.6411.0",
+        "description": "Run with ash-chrome version 125.0.6412.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5496,8 +5496,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v125.0.6411.0",
-              "revision": "version:125.0.6411.0"
+              "location": "lacros_version_skew_tests_v125.0.6412.0",
+              "revision": "version:125.0.6412.0"
             }
           ],
           "dimensions": {
@@ -5640,9 +5640,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_v125.0.6411.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v125.0.6412.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 125.0.6411.0",
+        "description": "Run with ash-chrome version 125.0.6412.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5652,8 +5652,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v125.0.6411.0",
-              "revision": "version:125.0.6411.0"
+              "location": "lacros_version_skew_tests_v125.0.6412.0",
+              "revision": "version:125.0.6412.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json
index 8c6a9c4..0000f76 100644
--- a/testing/buildbot/chromium.coverage.json
+++ b/testing/buildbot/chromium.coverage.json
@@ -19715,9 +19715,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_v125.0.6411.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v125.0.6412.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 125.0.6411.0",
+        "description": "Run with ash-chrome version 125.0.6412.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -19727,8 +19727,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v125.0.6411.0",
-              "revision": "version:125.0.6411.0"
+              "location": "lacros_version_skew_tests_v125.0.6412.0",
+              "revision": "version:125.0.6412.0"
             }
           ],
           "dimensions": {
@@ -19865,9 +19865,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_v125.0.6411.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v125.0.6412.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 125.0.6411.0",
+        "description": "Run with ash-chrome version 125.0.6412.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -19877,8 +19877,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v125.0.6411.0",
-              "revision": "version:125.0.6411.0"
+              "location": "lacros_version_skew_tests_v125.0.6412.0",
+              "revision": "version:125.0.6412.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 9cc35d3a..14698c0 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -41638,9 +41638,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_v125.0.6411.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v125.0.6412.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 125.0.6411.0",
+        "description": "Run with ash-chrome version 125.0.6412.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -41649,8 +41649,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v125.0.6411.0",
-              "revision": "version:125.0.6411.0"
+              "location": "lacros_version_skew_tests_v125.0.6412.0",
+              "revision": "version:125.0.6412.0"
             }
           ],
           "dimensions": {
@@ -41788,9 +41788,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_v125.0.6411.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v125.0.6412.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 125.0.6411.0",
+        "description": "Run with ash-chrome version 125.0.6412.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -41799,8 +41799,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v125.0.6411.0",
-              "revision": "version:125.0.6411.0"
+              "location": "lacros_version_skew_tests_v125.0.6412.0",
+              "revision": "version:125.0.6412.0"
             }
           ],
           "dimensions": {
@@ -43137,9 +43137,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_v125.0.6411.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v125.0.6412.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 125.0.6411.0",
+        "description": "Run with ash-chrome version 125.0.6412.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -43149,8 +43149,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v125.0.6411.0",
-              "revision": "version:125.0.6411.0"
+              "location": "lacros_version_skew_tests_v125.0.6412.0",
+              "revision": "version:125.0.6412.0"
             }
           ],
           "dimensions": {
@@ -43293,9 +43293,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_v125.0.6411.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v125.0.6412.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 125.0.6411.0",
+        "description": "Run with ash-chrome version 125.0.6412.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -43305,8 +43305,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v125.0.6411.0",
-              "revision": "version:125.0.6411.0"
+              "location": "lacros_version_skew_tests_v125.0.6412.0",
+              "revision": "version:125.0.6412.0"
             }
           ],
           "dimensions": {
@@ -44618,9 +44618,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_v125.0.6411.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v125.0.6412.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 125.0.6411.0",
+        "description": "Run with ash-chrome version 125.0.6412.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -44629,8 +44629,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v125.0.6411.0",
-              "revision": "version:125.0.6411.0"
+              "location": "lacros_version_skew_tests_v125.0.6412.0",
+              "revision": "version:125.0.6412.0"
             }
           ],
           "dimensions": {
@@ -44768,9 +44768,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_v125.0.6411.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v125.0.6412.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 125.0.6411.0",
+        "description": "Run with ash-chrome version 125.0.6412.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -44779,8 +44779,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v125.0.6411.0",
-              "revision": "version:125.0.6411.0"
+              "location": "lacros_version_skew_tests_v125.0.6412.0",
+              "revision": "version:125.0.6412.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index b952614..0e168b03 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -15765,12 +15765,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_v125.0.6411.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v125.0.6412.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 125.0.6411.0",
+        "description": "Run with ash-chrome version 125.0.6412.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -15780,8 +15780,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v125.0.6411.0",
-              "revision": "version:125.0.6411.0"
+              "location": "lacros_version_skew_tests_v125.0.6412.0",
+              "revision": "version:125.0.6412.0"
             }
           ],
           "dimensions": {
@@ -15941,12 +15941,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_v125.0.6411.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v125.0.6412.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 125.0.6411.0",
+        "description": "Run with ash-chrome version 125.0.6412.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -15956,8 +15956,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v125.0.6411.0",
-              "revision": "version:125.0.6411.0"
+              "location": "lacros_version_skew_tests_v125.0.6412.0",
+              "revision": "version:125.0.6412.0"
             }
           ],
           "dimensions": {
diff --git a/testing/buildbot/client.devtools-frontend.integration.json b/testing/buildbot/client.devtools-frontend.integration.json
index 0b5e9ba2..b96e927 100644
--- a/testing/buildbot/client.devtools-frontend.integration.json
+++ b/testing/buildbot/client.devtools-frontend.integration.json
@@ -65,33 +65,6 @@
         },
         "test": "blink_web_tests",
         "test_id_prefix": "ninja://:blink_web_tests/"
-      },
-      {
-        "args": [
-          "--num-retries=3",
-          "--write-run-histories-to=${ISOLATED_OUTDIR}/run_histories.json"
-        ],
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "blink_wpt_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "dimensions": {
-            "os": "Ubuntu-22.04"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 7
-        },
-        "test": "blink_wpt_tests",
-        "test_id_prefix": "ninja://:blink_wpt_tests/"
       }
     ]
   },
@@ -159,33 +132,6 @@
         },
         "test": "blink_web_tests",
         "test_id_prefix": "ninja://:blink_web_tests/"
-      },
-      {
-        "args": [
-          "--num-retries=3",
-          "--write-run-histories-to=${ISOLATED_OUTDIR}/run_histories.json"
-        ],
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "blink_wpt_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "dimensions": {
-            "os": "Ubuntu-22.04"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 7
-        },
-        "test": "blink_wpt_tests",
-        "test_id_prefix": "ninja://:blink_wpt_tests/"
       }
     ]
   }
diff --git a/testing/buildbot/filters/pixel_tests.filter b/testing/buildbot/filters/pixel_tests.filter
index 8b0658d..0308380 100644
--- a/testing/buildbot/filters/pixel_tests.filter
+++ b/testing/buildbot/filters/pixel_tests.filter
@@ -11,6 +11,7 @@
 AppInfoDialogBrowserTest.*
 AppMenuBrowserTest*.InvokeUi_*
 AskGoogleForSuggestionsDialogTest.*
+AutofillBubbleSignInPromoInteractiveUITest.*
 BookmarkBubbleViewBrowserTest.*
 BookmarkEditorViewBrowserTest.*
 BubbleFrameViewBrowserTest.*
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 9a0f7ec..f7b0405 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -1976,6 +1976,28 @@
       },
     },
 
+    'devtools_web_isolated_scripts': {
+      'blink_web_tests': {
+        'results_handler': 'layout tests',
+        'mixins': [
+          'has_native_resultdb_integration',
+          'blink_tests_write_run_histories',
+        ],
+        'args': [
+          '--num-retries=3',
+        ],
+        'swarming': {
+          'shards': 5,
+        },
+        'merge': {
+          'script': '//third_party/blink/tools/merge_web_test_results.py',
+          'args': [
+            '--verbose',
+          ],
+        },
+      },
+    },
+
     'devtools_webkit_isolated_scripts': {
       'blink_web_tests': {
         'results_handler': 'layout tests',
diff --git a/testing/buildbot/tryserver.devtools-frontend.json b/testing/buildbot/tryserver.devtools-frontend.json
index 6fab82c..8f3137b 100644
--- a/testing/buildbot/tryserver.devtools-frontend.json
+++ b/testing/buildbot/tryserver.devtools-frontend.json
@@ -131,33 +131,6 @@
         },
         "test": "blink_web_tests",
         "test_id_prefix": "ninja://:blink_web_tests/"
-      },
-      {
-        "args": [
-          "--num-retries=3",
-          "--write-run-histories-to=${ISOLATED_OUTDIR}/run_histories.json"
-        ],
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "blink_wpt_tests",
-        "resultdb": {
-          "enable": true,
-          "has_native_resultdb_integration": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "dimensions": {
-            "os": "Ubuntu-22.04"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 7
-        },
-        "test": "blink_wpt_tests",
-        "test_id_prefix": "ninja://:blink_wpt_tests/"
       }
     ]
   }
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index d457a9a..1d11ec4 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -267,16 +267,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'identifier': 'Lacros version skew testing ash canary',
-    'description': 'Run with ash-chrome version 125.0.6411.0',
+    'description': 'Run with ash-chrome version 125.0.6412.0',
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v125.0.6411.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v125.0.6412.0/test_ash_chrome',
     ],
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v125.0.6411.0',
-          'revision': 'version:125.0.6411.0',
+          'location': 'lacros_version_skew_tests_v125.0.6412.0',
+          'revision': 'version:125.0.6412.0',
         },
       ],
     },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index e74c9f1e..70ed4f9c 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -6240,7 +6240,7 @@
         'additional_compile_targets': ['blink_tests'],
         'test_suites': {
           'gtest_tests': 'devtools_gtests',
-          'isolated_scripts': 'devtools_webkit_isolated_scripts',
+          'isolated_scripts': 'devtools_web_isolated_scripts',
         },
       },
       'DevTools Linux Fastbuild': {
@@ -6250,7 +6250,7 @@
         'additional_compile_targets': ['blink_tests'],
         'test_suites': {
           'gtest_tests': 'devtools_gtests',
-          'isolated_scripts': 'devtools_webkit_isolated_scripts',
+          'isolated_scripts': 'devtools_web_isolated_scripts',
         },
       },
     },
@@ -7062,7 +7062,7 @@
         ],
         'test_suites': {
           'gtest_tests': 'devtools_browser_tests_suite',
-          'isolated_scripts': 'devtools_webkit_isolated_scripts',
+          'isolated_scripts': 'devtools_web_isolated_scripts',
         },
       },
       'devtools_frontend_linux_blink_light_rel_fastbuild': {
@@ -7071,7 +7071,7 @@
         ],
         'test_suites': {
           'gtest_tests': 'devtools_browser_tests_suite',
-          'isolated_scripts': 'devtools_webkit_isolated_scripts',
+          'isolated_scripts': 'devtools_web_isolated_scripts',
         },
       },
       'devtools_frontend_linux_blink_rel': {
@@ -7079,7 +7079,7 @@
           'linux-jammy',
         ],
         'test_suites': {
-          'isolated_scripts': 'devtools_webkit_isolated_scripts',
+          'isolated_scripts': 'devtools_web_isolated_scripts',
         },
       },
     }
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index db4063f4..7571b675 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -18592,21 +18592,6 @@
             ]
         }
     ],
-    "SyncShowIdentityErrorsForSignedInUsers": [
-        {
-            "platforms": [
-                "android"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "SyncShowIdentityErrorsForSignedInUsers"
-                    ]
-                }
-            ]
-        }
-    ],
     "SysUiHoldbackStudy": [
         {
             "platforms": [
diff --git a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
index 1fd8eaf..2ba9490 100644
--- a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
+++ b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
@@ -3748,7 +3748,7 @@
   kCSSAtRuleSwash = 4407 ,
   kCSSAtRuleOrnaments = 4408,
   kCSSAtRuleAnnotation = 4409,
-  kServiceWorkerBypassFetchHandlerForMainResource = 4410,
+  kOBSOLETE_ServiceWorkerBypassFetchHandlerForMainResource = 4410,
   kV8Document_HasPrivateToken_Method = 4411,
   kServiceWorkerSkippedForEmptyFetchHandler = 4412,
   kImageSet = 4413,
@@ -3799,7 +3799,7 @@
   kOptionLabelInQuirksMode = 4454,
   kParseFromStringIncludeShadows = 4455,
   kWebAppManifestScopeExtensions = 4456,
-  kServiceWorkerBypassFetchHandlerForMainResourceByOriginTrial = 4457,
+  kOBSOLETE_ServiceWorkerBypassFetchHandlerForMainResourceByOriginTrial = 4457,
   kOBSOLETE_V8RegExpUnicodeSetIncompatibilitiesWithUnicodeMode = 4458,
   kFedCmAutoReauthn = 4459,
   kTopicsAPIFetch = 4460,
@@ -3829,7 +3829,7 @@
   kRTCPeerConnectionLegacyGetStatsTrial = 4482,
   kExecutedEmptyJavaScriptURLFromFrame = 4483,
   kExecutedJavaScriptURLFromFrame = 4484,
-  kServiceWorkerBypassFetchHandlerForSubResource = 4485,
+  kOBSOLETE_ServiceWorkerBypassFetchHandlerForSubResource = 4485,
   kCSSAtRuleStartingStyle = 4486,
   kPrivateAggregationApiFledgeExtensions = 4487,
   kDeprecatedInterestGroupDailyUpdateUrl = 4488,
@@ -3894,7 +3894,7 @@
   kOBSOLETE_TextWrapBalanceFail = 4545,
   kAttributionReportingCrossAppWeb = 4546,
   kSecurePaymentConfirmationActivationlessShow = 4547,
-  kServiceWorkerBypassFetchHandlerForAllWithRaceNetworkRequest = 4548,
+  kOBSOLETE_ServiceWorkerBypassFetchHandlerForAllWithRaceNetworkRequest = 4548,
   // The items above roughly this point are available in the M114 branch.
 
   kFlexIntrinsicSizesCacheMiss = 4549,
@@ -3907,7 +3907,7 @@
   kCSSValueAppearanceSliderVertical = 4556,
   kCSSValueAppearanceSliderthumbHorizontal = 4557,
   kCSSValueAppearanceSliderthumbVertical = 4558,
-  kServiceWorkerBypassFetchHandlerForAllWithRaceNetworkRequestByOriginTrial = 4559,
+  kOBSOLETE_ServiceWorkerBypassFetchHandlerForAllWithRaceNetworkRequestByOriginTrial = 4559,
   kOBSOLETE_EventTimingPaintedPresentationPromiseResolvedWithEarlierPromiseUnresolved = 4560,
   kLinkRelPreloadAsFont = 4561,
   kCrossWindowAccessToBrowserGeneratedDocument = 4562,
diff --git a/third_party/blink/renderer/core/css/css_to_length_conversion_data.cc b/third_party/blink/renderer/core/css/css_to_length_conversion_data.cc
index b44b536..a1638a79 100644
--- a/third_party/blink/renderer/core/css/css_to_length_conversion_data.cc
+++ b/third_party/blink/renderer/core/css/css_to_length_conversion_data.cc
@@ -34,7 +34,6 @@
 #include "third_party/blink/renderer/core/css/container_query.h"
 #include "third_party/blink/renderer/core/css/container_query_evaluator.h"
 #include "third_party/blink/renderer/core/css/css_resolution_units.h"
-#include "third_party/blink/renderer/core/css/out_of_flow_data.h"
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
@@ -295,19 +294,12 @@
 }
 
 CSSToLengthConversionData::AnchorData::AnchorData(
-    Element* anchored,
     AnchorEvaluator* evaluator,
     const ScopedCSSName* position_anchor,
     const std::optional<InsetAreaOffsets>& inset_area_offsets)
     : evaluator_(evaluator),
       position_anchor_(position_anchor),
-      inset_area_offsets_(inset_area_offsets) {
-  if (!evaluator_ && anchored) {
-    if (OutOfFlowData* out_of_flow_data = anchored->GetOutOfFlowData()) {
-      evaluator_ = &out_of_flow_data->GetAnchorResults();
-    }
-  }
-}
+      inset_area_offsets_(inset_area_offsets) {}
 
 CSSToLengthConversionData::CSSToLengthConversionData(
     WritingMode writing_mode,
diff --git a/third_party/blink/renderer/core/css/css_to_length_conversion_data.h b/third_party/blink/renderer/core/css/css_to_length_conversion_data.h
index a357fb26..17a56fb 100644
--- a/third_party/blink/renderer/core/css/css_to_length_conversion_data.h
+++ b/third_party/blink/renderer/core/css/css_to_length_conversion_data.h
@@ -251,8 +251,7 @@
 
    public:
     AnchorData() = default;
-    AnchorData(Element* anchored,
-               AnchorEvaluator*,
+    AnchorData(AnchorEvaluator*,
                const ScopedCSSName* position_anchor,
                const std::optional<InsetAreaOffsets>&);
     AnchorEvaluator* GetEvaluator() const { return evaluator_; }
diff --git a/third_party/blink/renderer/core/css/css_to_length_conversion_data_test.cc b/third_party/blink/renderer/core/css/css_to_length_conversion_data_test.cc
index f7dda468..7b95bc3 100644
--- a/third_party/blink/renderer/core/css/css_to_length_conversion_data_test.cc
+++ b/third_party/blink/renderer/core/css/css_to_length_conversion_data_test.cc
@@ -98,7 +98,7 @@
         CSSToLengthConversionData::ViewportSize(GetDocument().GetLayoutView()),
         CSSToLengthConversionData::ContainerSizes(),
         CSSToLengthConversionData::AnchorData(
-            div, options.anchor_evaluator,
+            options.anchor_evaluator,
             /* position_anchor */ nullptr,
             /* inset_area_offsets */ std::nullopt),
         options.data_zoom.value_or(div->GetComputedStyle()->EffectiveZoom()),
@@ -554,7 +554,7 @@
       CSSToLengthConversionData::ViewportSize(GetDocument().GetLayoutView()),
       CSSToLengthConversionData::ContainerSizes(child),
       CSSToLengthConversionData::AnchorData(
-          child, nullptr,
+          nullptr,
           /* position_anchor */ nullptr,
           /* inset_area_offsets */ std::nullopt),
       child->GetComputedStyle()->EffectiveZoom(), flags);
diff --git a/third_party/blink/renderer/core/css/element_rule_collector.cc b/third_party/blink/renderer/core/css/element_rule_collector.cc
index a383f67..0388ef6 100644
--- a/third_party/blink/renderer/core/css/element_rule_collector.cc
+++ b/third_party/blink/renderer/core/css/element_rule_collector.cc
@@ -396,6 +396,12 @@
   if (!property_set) {
     return;
   }
+  if (!style_recalc_context_.is_interleaved_oof) {
+    // TODO(crbug.com/333608683): The anchor result cache is currently disabled
+    // for non-OOF recalcs to work around invalidation problems. See
+    // `ComputeAnchorEvaluator` in style_resolver_state.cc for more information.
+    return;
+  }
   auto link_match_type = static_cast<unsigned>(CSSSelector::kMatchAll);
   result_.AddMatchedProperties(
       property_set, CascadeOrigin::kAuthor,
@@ -410,6 +416,12 @@
   if (!property_set) {
     return;
   }
+  if (!style_recalc_context_.is_interleaved_oof) {
+    // TODO(crbug.com/333608683): The anchor result cache is currently disabled
+    // for non-OOF recalcs to work around invalidation problems. See
+    // `ComputeAnchorEvaluator` in style_resolver_state.cc for more information.
+    return;
+  }
   auto link_match_type = static_cast<unsigned>(CSSSelector::kMatchAll);
   result_.AddMatchedProperties(
       property_set, CascadeOrigin::kAuthor,
diff --git a/third_party/blink/renderer/core/css/properties/css_color_function_parser.cc b/third_party/blink/renderer/core/css/properties/css_color_function_parser.cc
index d9e66eb..f8dd56c 100644
--- a/third_party/blink/renderer/core/css/properties/css_color_function_parser.cc
+++ b/third_party/blink/renderer/core/css/properties/css_color_function_parser.cc
@@ -658,6 +658,9 @@
   // The parsing was successful, so we need to consume the input.
   input_range = range;
 
+  // TODO(b/40949047): Counters for out-of-gamut are disabled because of
+  // repeated merge-conflict creating reverts. Remove this parameter.
+  const bool kEnableCounters = false;
   if (is_relative_color_) {
     context.Count(WebFeature::kCSSRelativeColor);
   } else {
@@ -668,16 +671,20 @@
       case Color::ColorSpace::kA98RGB:
       case Color::ColorSpace::kProPhotoRGB:
       case Color::ColorSpace::kRec2020:
-        context.Count(WebFeature::kCSSColor_SpaceRGB);
-        if (!IsInGamutRec2020(result)) {
-          context.Count(WebFeature::kCSSColor_SpaceRGB_outOfRec2020);
+        if (kEnableCounters) {
+          context.Count(WebFeature::kCSSColor_SpaceRGB);
+          if (!IsInGamutRec2020(result)) {
+            context.Count(WebFeature::kCSSColor_SpaceRGB_outOfRec2020);
+          }
         }
         break;
       case Color::ColorSpace::kOklab:
       case Color::ColorSpace::kOklch:
-        context.Count(WebFeature::kCSSColor_SpaceOkLxx);
-        if (!IsInGamutRec2020(result)) {
-          context.Count(WebFeature::kCSSColor_SpaceOkLxx_outOfRec2020);
+        if (kEnableCounters) {
+          context.Count(WebFeature::kCSSColor_SpaceOkLxx);
+          if (!IsInGamutRec2020(result)) {
+            context.Count(WebFeature::kCSSColor_SpaceOkLxx_outOfRec2020);
+          }
         }
         break;
       case Color::ColorSpace::kXYZD50:
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc b/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
index 6194e869..e7ad1867 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
@@ -27,6 +27,7 @@
 #include "third_party/blink/renderer/core/core_probes_inl.h"
 #include "third_party/blink/renderer/core/css/css_light_dark_value_pair.h"
 #include "third_party/blink/renderer/core/css/css_property_value_set.h"
+#include "third_party/blink/renderer/core/css/out_of_flow_data.h"
 #include "third_party/blink/renderer/core/dom/node.h"
 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/dom/pseudo_element.h"
@@ -50,6 +51,49 @@
   return styled_element;
 }
 
+AnchorEvaluator* ComputeAnchorEvaluator(
+    Element* styled_element,
+    const StyleRecalcContext* style_recalc_context) {
+  if (!style_recalc_context) {
+    return nullptr;
+  }
+  if (style_recalc_context->anchor_evaluator) {
+    return style_recalc_context->anchor_evaluator;
+  }
+  if (style_recalc_context->is_interleaved_oof) {
+    // If we don't have an anchor evaluator, then we're resolving the style for
+    // a descendant of the anchored element. Normally, if that descendant is
+    // also anchored, then we'd enter UpdateStyleForOutOfFlow separately for
+    // that descendant, but this is not the case for ::backdrop, where
+    // UpdateStyleForOutOfFlow calls appear in the reverse order. For example:
+    //
+    //  - Say ::backdrop and its <dialog> are both absolutely positioned,
+    //    and <dialog> uses the anchor attribute.
+    //  - We get a call to UpdateStyleForOutOfFlow to ::backdrop first,
+    //    which evaluates any anchor queries correctly for ::backdrop.
+    //  - We then get another call to UpdateStyleForOutOfFlow for <dialog>,
+    //    which also updates the ::backdrop (again), but this time we lose the
+    //    AnchorEvaluator on our way into ::backdrop. (This is the correct
+    //    behavior as the AnchorEvaluator passed into UpdateStyleForOutOfFlow is
+    //    only supposed to apply to the interleaving root itself).
+    //
+    // For this reason, we use the AnchorResults (the most recently seen anchor
+    // query results) as the AnchorEvaluator if we end up with no (incoming)
+    // AnchorEvaluator during is_interleaved_oof.
+    //
+    // The AnchorResults cache was originally implemented as an optimization for
+    // regular style recalcs, but is currently disabled due to issues with
+    // invalidation.
+    //
+    // TODO(crbug.com/333608683): Make use of AnchorResults for regular recalcs.
+    if (styled_element) {
+      OutOfFlowData* out_of_flow_data = styled_element->GetOutOfFlowData();
+      return out_of_flow_data ? &out_of_flow_data->GetAnchorResults() : nullptr;
+    }
+  }
+  return nullptr;
+}
+
 }  // namespace
 
 StyleResolverState::StyleResolverState(
@@ -75,9 +119,8 @@
       container_unit_context_(style_recalc_context
                                   ? style_recalc_context->container
                                   : element.ParentOrShadowHostElement()),
-      anchor_evaluator_(style_recalc_context
-                            ? style_recalc_context->anchor_evaluator
-                            : nullptr),
+      anchor_evaluator_(
+          ComputeAnchorEvaluator(styled_element_, style_recalc_context)),
       originating_element_style_(style_request.originating_element_style),
       is_for_highlight_(IsHighlightPseudoElement(style_request.pseudo_id)),
       uses_highlight_pseudo_inheritance_(
@@ -161,7 +204,7 @@
       *style_builder_, ParentStyle(), RootElementStyle(),
       GetDocument().GetStyleEngine().GetViewportSize(),
       CSSToLengthConversionData::ContainerSizes(container_unit_context_),
-      CSSToLengthConversionData::AnchorData(styled_element_, anchor_evaluator_,
+      CSSToLengthConversionData::AnchorData(anchor_evaluator_,
                                             StyleBuilder().PositionAnchor(),
                                             StyleBuilder().InsetAreaOffsets()),
       StyleBuilder().EffectiveZoom(), length_conversion_flags_);
@@ -183,7 +226,7 @@
   CSSToLengthConversionData::ContainerSizes container_sizes(
       container_unit_context_);
   CSSToLengthConversionData::AnchorData anchor_data(
-      styled_element_, anchor_evaluator_, StyleBuilder().PositionAnchor(),
+      anchor_evaluator_, StyleBuilder().PositionAnchor(),
       StyleBuilder().InsetAreaOffsets());
   return CSSToLengthConversionData(
       StyleBuilder().GetWritingMode(), font_sizes, line_height_size,
@@ -285,7 +328,7 @@
     StyleBuilder().SetPositionAnchor(position_anchor);
     css_to_length_conversion_data_.SetAnchorData(
         CSSToLengthConversionData::AnchorData(
-            styled_element_, anchor_evaluator_, position_anchor,
+            anchor_evaluator_, position_anchor,
             StyleBuilder().InsetAreaOffsets()));
   }
 }
@@ -295,9 +338,9 @@
   if (StyleBuilder().InsetAreaOffsets() != inset_area_offsets) {
     StyleBuilder().SetInsetAreaOffsets(inset_area_offsets);
     css_to_length_conversion_data_.SetAnchorData(
-        CSSToLengthConversionData::AnchorData(
-            styled_element_, anchor_evaluator_, StyleBuilder().PositionAnchor(),
-            inset_area_offsets));
+        CSSToLengthConversionData::AnchorData(anchor_evaluator_,
+                                              StyleBuilder().PositionAnchor(),
+                                              inset_area_offsets));
   }
 }
 
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc b/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc
index e6d28fea..f55130a8 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver_test.cc
@@ -52,12 +52,13 @@
 
 class StyleResolverTest : public PageTestBase {
  protected:
-  const ComputedStyle* StyleForId(const char* id) {
+  const ComputedStyle* StyleForId(
+      const char* id,
+      StyleRecalcContext style_recalc_context = {}) {
     Element* element = GetElementById(id);
-    StyleRecalcContext recalc_context;
-    recalc_context.old_style = element->GetComputedStyle();
+    style_recalc_context.old_style = element->GetComputedStyle();
     const auto* style = GetStyleEngine().GetStyleResolver().ResolveStyle(
-        element, recalc_context);
+        element, style_recalc_context);
     DCHECK(style);
     return style;
   }
@@ -1939,18 +1940,28 @@
   // the AnchorResults.
   OutOfFlowData* out_of_flow_data = anchored->GetOutOfFlowData();
   ASSERT_TRUE(out_of_flow_data);
-  EXPECT_FALSE(out_of_flow_data->GetAnchorResults().IsEmpty());
+  AnchorResults& anchor_results = out_of_flow_data->GetAnchorResults();
+  EXPECT_FALSE(anchor_results.IsEmpty());
 
-  // Calls StyleResolver::ResolveStyle with a nullptr AnchorEvaluator.
-  const ComputedStyle* non_interleaved_style = StyleForId("anchored");
-  ASSERT_TRUE(non_interleaved_style);
+  const ComputedStyle* old_style = anchored->GetComputedStyle();
 
-  // Results should be the same as before, because we're fetching them
-  // from the AnchorResults on OutOfFlowData.
-  EXPECT_EQ("300px", ComputedValue("left", *non_interleaved_style));
-  EXPECT_EQ("450px", ComputedValue("top", *non_interleaved_style));
-  EXPECT_EQ("150px", ComputedValue("width", *non_interleaved_style));
-  EXPECT_EQ("100px", ComputedValue("height", *non_interleaved_style));
+  // Freshen the style using the previous results as the evaluator.
+  // We are using a copy, because UpdateStyleForOutOfFlow clears the results
+  // on the element's OutOfFlowData.
+  AnchorResults anchor_results_copy(anchor_results);
+  GetStyleEngine().UpdateStyleForOutOfFlow(
+      *anchored, /* try_set */ nullptr, kNoTryTactics,
+      /* anchor_evaluator */ &anchor_results_copy);
+
+  // We should have created a new ComputedStyle object with the same computed
+  // values as before.
+  const ComputedStyle* new_style = anchored->GetComputedStyle();
+  ASSERT_TRUE(new_style);
+  EXPECT_NE(old_style, new_style);
+  EXPECT_EQ("300px", ComputedValue("left", *new_style));
+  EXPECT_EQ("450px", ComputedValue("top", *new_style));
+  EXPECT_EQ("150px", ComputedValue("width", *new_style));
+  EXPECT_EQ("100px", ComputedValue("height", *new_style));
 }
 
 TEST_P(ParameterizedStyleResolverTest, NoCascadeLayers) {
@@ -3324,63 +3335,6 @@
   }
 }
 
-TEST_P(ParameterizedStyleResolverTest,
-       PositionFallback_PersistentPositionTrySet) {
-  ScopedCSSAnchorPositioningForTest enabled(true);
-  ScopedCSSAnchorPositioningCascadeFallbackForTest cascade(true);
-
-  SetBodyInnerHTML(R"HTML(
-    <style>
-      @position-try --f1 { left: 100px; }
-      @position-try --f2 { top: 100px; }
-      #target {
-        position: absolute;
-        left: 400000px;
-        position-try-options: --f1, --f2;
-      }
-    </style>
-    <div id="target"></div>
-  )HTML");
-
-  UpdateAllLifecyclePhasesForTest();
-
-  Element* target = GetElementById("target");
-  const ComputedStyle* style = target->GetComputedStyle();
-  ASSERT_TRUE(style);
-  EXPECT_EQ(Length::Fixed(100), GetLeft(*style));
-  EXPECT_EQ(Length::Auto(), GetTop(*style));
-  EXPECT_TRUE(target->GetOutOfFlowData() &&
-              target->GetOutOfFlowData()->GetTryPropertyValueSet());
-
-  // The set should be cleared when 'position-try-options' is cleared.
-  target->SetInlineStyleProperty(CSSPropertyID::kPositionTryOptions, "none");
-  UpdateAllLifecyclePhasesForTest();
-  style = target->GetComputedStyle();
-  EXPECT_EQ(Length::Fixed(400000), GetLeft(*style));
-  EXPECT_EQ(Length::Auto(), GetTop(*style));
-  EXPECT_FALSE(target->GetOutOfFlowData() &&
-               target->GetOutOfFlowData()->GetTryPropertyValueSet());
-
-  target->SetInlineStyleProperty(CSSPropertyID::kPositionTryOptions,
-                                 "--f1, --f2");
-  UpdateAllLifecyclePhasesForTest();
-  style = target->GetComputedStyle();
-  EXPECT_EQ(Length::Fixed(100), GetLeft(*style));
-  EXPECT_EQ(Length::Auto(), GetTop(*style));
-  EXPECT_TRUE(target->GetOutOfFlowData() &&
-              target->GetOutOfFlowData()->GetTryPropertyValueSet());
-
-  // The set should also be cleared when referencing a non-existent fallback.
-  target->SetInlineStyleProperty(CSSPropertyID::kPositionTryOptions,
-                                 "--unknown");
-  UpdateAllLifecyclePhasesForTest();
-  style = target->GetComputedStyle();
-  EXPECT_EQ(Length::Fixed(400000), GetLeft(*style));
-  EXPECT_EQ(Length::Auto(), GetTop(*style));
-  EXPECT_FALSE(target->GetOutOfFlowData() &&
-               target->GetOutOfFlowData()->GetTryPropertyValueSet());
-}
-
 TEST_P(ParameterizedStyleResolverTest, PositionTry_PaintInvalidation) {
   ScopedCSSAnchorPositioningForTest enabled(true);
   ScopedCSSAnchorPositioningCascadeFallbackForTest cascade(true);
@@ -3445,7 +3399,8 @@
   ASSERT_TRUE(try_set);
 
   div->EnsureOutOfFlowData().SetTryPropertyValueSet(try_set);
-  const ComputedStyle* try_style = StyleForId("div");
+  const ComputedStyle* try_style =
+      StyleForId("div", StyleRecalcContext{.is_interleaved_oof = true});
   ASSERT_TRUE(try_style);
   EXPECT_EQ("20px", ComputedValue("left", *try_style));
   EXPECT_EQ("30px", ComputedValue("right", *try_style));
@@ -3476,7 +3431,8 @@
   ASSERT_TRUE(try_set);
 
   div->EnsureOutOfFlowData().SetTryPropertyValueSet(try_set);
-  const ComputedStyle* try_style = StyleForId("div");
+  const ComputedStyle* try_style =
+      StyleForId("div", StyleRecalcContext{.is_interleaved_oof = true});
   ASSERT_TRUE(try_style);
   EXPECT_EQ("10px", ComputedValue("left", *try_style));
   EXPECT_EQ("30px", ComputedValue("right", *try_style));
@@ -3507,7 +3463,8 @@
   ASSERT_TRUE(try_set);
 
   div->EnsureOutOfFlowData().SetTryPropertyValueSet(try_set);
-  const ComputedStyle* try_style = StyleForId("div");
+  const ComputedStyle* try_style =
+      StyleForId("div", StyleRecalcContext{.is_interleaved_oof = true});
   ASSERT_TRUE(try_style);
   EXPECT_EQ("auto", ComputedValue("left", *try_style));
   EXPECT_EQ("30px", ComputedValue("right", *try_style));
@@ -3539,7 +3496,8 @@
   ASSERT_TRUE(try_set);
 
   div->EnsureOutOfFlowData().SetTryPropertyValueSet(try_set);
-  const ComputedStyle* try_style = StyleForId("div");
+  const ComputedStyle* try_style =
+      StyleForId("div", StyleRecalcContext{.is_interleaved_oof = true});
   ASSERT_TRUE(try_style);
   EXPECT_EQ("10px", ComputedValue("left", *try_style));
   EXPECT_EQ("auto", ComputedValue("right", *try_style));
@@ -3574,7 +3532,8 @@
 
   div->SetInlineStyleProperty(CSSPropertyID::kPosition, "static");
   div->EnsureOutOfFlowData().SetTryPropertyValueSet(try_set);
-  const ComputedStyle* try_style = StyleForId("div");
+  const ComputedStyle* try_style =
+      StyleForId("div", StyleRecalcContext{.is_interleaved_oof = true});
   ASSERT_TRUE(try_style);
   EXPECT_EQ("10px", ComputedValue("left", *try_style));
   EXPECT_EQ("auto", ComputedValue("right", *try_style));
@@ -3619,7 +3578,8 @@
   ASSERT_TRUE(try_tactics_set);
   div->EnsureOutOfFlowData().SetTryTacticsPropertyValueSet(try_tactics_set);
 
-  const ComputedStyle* try_style = StyleForId("div");
+  const ComputedStyle* try_style =
+      StyleForId("div", StyleRecalcContext{.is_interleaved_oof = true});
   ASSERT_TRUE(try_style);
   EXPECT_EQ("200px", ComputedValue("left", *try_style));
   EXPECT_EQ("100px", ComputedValue("right", *try_style));
diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc
index b0787edc..057118f0 100644
--- a/third_party/blink/renderer/core/css/style_engine.cc
+++ b/third_party/blink/renderer/core/css/style_engine.cc
@@ -3470,18 +3470,12 @@
                                           const TryTacticList& tactic_list,
                                           AnchorEvaluator* anchor_evaluator) {
   // Note that we enter this function for any OOF element, not just those that
-  // use position-try-options. Therefore, it's important to return immediately
-  // without doing any work when `try_set` and `existing_try_set` both are
-  // nullptr.
+  // use position-try-options. Therefore, it's important to return without
+  // doing style recalc when anchor positioning features are not in use.
 
-  const CSSPropertyValueSet* existing_try_set = nullptr;
-  const CSSPropertyValueSet* existing_try_tactics_set = nullptr;
-
-  OutOfFlowData* out_of_flow_data = element.GetOutOfFlowData();
-  if (out_of_flow_data) {
-    existing_try_set = out_of_flow_data->GetTryPropertyValueSet();
-    existing_try_tactics_set =
-        out_of_flow_data->GetTryTacticsPropertyValueSet();
+  if (OutOfFlowData* out_of_flow_data = element.GetOutOfFlowData()) {
+    out_of_flow_data->SetTryPropertyValueSet(nullptr);
+    out_of_flow_data->SetTryTacticsPropertyValueSet(nullptr);
   }
 
   const CSSPropertyValueSet* try_tactics_set =
@@ -3489,11 +3483,11 @@
 
   bool needs_update = false;
 
-  if (existing_try_set != try_set) {
+  if (try_set) {
     element.EnsureOutOfFlowData().SetTryPropertyValueSet(try_set);
     needs_update = true;
   }
-  if (existing_try_tactics_set != try_tactics_set) {
+  if (try_tactics_set) {
     element.EnsureOutOfFlowData().SetTryTacticsPropertyValueSet(
         try_tactics_set);
     needs_update = true;
@@ -3506,16 +3500,12 @@
     needs_update = true;
   }
   if (element.ComputedStyleRef().HasAnchorFunctions()) {
-    AnchorResults& anchor_results =
-        element.EnsureOutOfFlowData().GetAnchorResults();
-    if (anchor_results.IsEmpty() ||
-        anchor_results.IsAnyResultDifferent(element.ComputedStyleRef(),
-                                            anchor_evaluator)) {
-      needs_update = true;
-    }
+    needs_update = true;
   }
 
   if (!needs_update) {
+    CHECK(!try_set);
+    CHECK(!try_tactics_set);
     return;
   }
 
@@ -3524,13 +3514,11 @@
   // - The existing AnchorResults are immediately cleared, and
   // - The result of any Evaluate() call made will be stored
   //   in the AnchorResults.
+  //
+  // TODO(crbug.com/333608683): The results of ResultCachingAnchorEvaluator is
+  // currently not used outside of tests.
   ResultCachingAnchorEvaluator result_caching_anchor_evaluator(
       anchor_evaluator, element.EnsureOutOfFlowData().GetAnchorResults());
-
-  // The last seen `try_set` is persisted on Element, such that subsequent
-  // regular style recalcs can continue to include this set.
-  element.EnsureOutOfFlowData().SetTryPropertyValueSet(try_set);
-
   base::AutoReset<bool> pt_recalc(&in_position_try_style_recalc_, true);
 
   UpdateViewportSize();
diff --git a/third_party/blink/renderer/core/css/style_engine_test.cc b/third_party/blink/renderer/core/css/style_engine_test.cc
index 903fd39f..47a7ef95 100644
--- a/third_party/blink/renderer/core/css/style_engine_test.cc
+++ b/third_party/blink/renderer/core/css/style_engine_test.cc
@@ -4556,45 +4556,6 @@
   EXPECT_FALSE(GetDocument().NeedsLayoutTreeUpdateForNode(*a));
 }
 
-TEST_F(StyleEngineTest, UpdateStyleForOutOfFlow_TacticsCache) {
-  GetDocument().body()->setInnerHTML(R"HTML(
-    <style>
-      #anchored {
-        position: absolute;
-        width: 100px;
-        height: 100px;
-      }
-    </style>
-    <div id=anchored>Foo</div>
-  )HTML");
-
-  UpdateAllLifecyclePhases();
-
-  Element* anchored = GetDocument().getElementById(AtomicString("anchored"));
-  ASSERT_TRUE(anchored);
-
-  auto tactic =
-      TryTacticList{TryTactic::kFlipBlock, TryTactic::kNone, TryTactic::kNone};
-
-  GetStyleEngine().SetStatsEnabled(true);
-  StyleResolverStats* stats = GetStyleEngine().Stats();
-  ASSERT_TRUE(stats);
-  EXPECT_EQ(0u, stats->elements_styled);
-
-  GetStyleEngine().UpdateStyleForOutOfFlow(*anchored,
-                                           /* try_set */ nullptr, tactic,
-                                           /* anchor_evaluator */ nullptr);
-
-  EXPECT_EQ(1u, stats->elements_styled);
-
-  // The same call again should not recalc any elements.
-  GetStyleEngine().UpdateStyleForOutOfFlow(*anchored,
-                                           /* try_set */ nullptr, tactic,
-                                           /* anchor_evaluator */ nullptr);
-
-  EXPECT_EQ(1u, stats->elements_styled);
-}
-
 TEST_F(StyleEngineTest, UpdateStyleAndLayoutTreeWithAnchorQuery) {
   GetDocument().documentElement()->setInnerHTML(R"HTML(
     <style>
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
index 0374589..d24a76b 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -2853,8 +2853,6 @@
       GetPage()->GetPageLifecycleState()->is_in_back_forward_cache) {
     return WebInputEventResult::kNotHandled;
   }
-  // Input events should not be routed to a prerendered page.
-  CHECK(!GetPage()->IsPrerendering());
 
   if (WebDevToolsAgentImpl* devtools = LocalRootImpl()->DevToolsAgentImpl()) {
     auto result = devtools->HandleInputEvent(input_event);
diff --git a/third_party/blink/renderer/core/layout/inline/inline_node.cc b/third_party/blink/renderer/core/layout/inline/inline_node.cc
index 0cea526..fd5b961 100644
--- a/third_party/blink/renderer/core/layout/inline/inline_node.cc
+++ b/third_party/blink/renderer/core/layout/inline/inline_node.cc
@@ -19,6 +19,7 @@
 #include "third_party/blink/renderer/core/layout/inline/initial_letter_utils.h"
 #include "third_party/blink/renderer/core/layout/inline/inline_break_token.h"
 #include "third_party/blink/renderer/core/layout/inline/inline_item.h"
+#include "third_party/blink/renderer/core/layout/inline/inline_item_result_ruby_column.h"
 #include "third_party/blink/renderer/core/layout/inline/inline_items_builder.h"
 #include "third_party/blink/renderer/core/layout/inline/inline_layout_algorithm.h"
 #include "third_party/blink/renderer/core/layout/inline/inline_text_auto_space.h"
@@ -1797,6 +1798,7 @@
     const LineBreaker::MaxSizeCache& max_size_cache;
     FloatsMaxSize* floats;
     bool is_after_break = true;
+    wtf_size_t annotation_nesting_level = 0;
 
     explicit MaxSizeFromMinSize(const InlineItemsData& items_data,
                                 const LineBreaker::MaxSizeCache& max_size_cache,
@@ -1812,7 +1814,14 @@
     void AddTextUntil(const InlineItem* end) {
       DCHECK(end);
       for (; next_item != end; ++next_item) {
-        if (next_item->Type() == InlineItem::kText && next_item->Length()) {
+        if (next_item->Type() == InlineItem::kOpenTag &&
+            next_item->GetLayoutObject()->IsInlineRubyText()) {
+          ++annotation_nesting_level;
+        } else if (next_item->Type() == InlineItem::kCloseTag &&
+                   next_item->GetLayoutObject()->IsInlineRubyText()) {
+          --annotation_nesting_level;
+        } else if (next_item->Type() == InlineItem::kText &&
+                   next_item->Length() && annotation_nesting_level == 0) {
           DCHECK(next_item->TextShapeResult());
           const ShapeResult& shape_result = *next_item->TextShapeResult();
           position += shape_result.SnappedWidth().ClampNegativeToZero();
@@ -1858,6 +1867,17 @@
         is_after_break = false;
       }
 
+      ComputeFromMinSizeInternal(line_info);
+
+      // Compute the forced break after all results were handled, because
+      // when close tags appear after a forced break, they are included in
+      // the line, and they may have inline sizes. crbug.com/991320.
+      if (line_info.HasForcedBreak()) {
+        ForceLineBreak(line_info);
+      }
+    }
+
+    void ComputeFromMinSizeInternal(const LineInfo& line_info) {
       for (const InlineItemResult& result : line_info.Results()) {
         const InlineItem& item = *result.item;
         if (item.Type() == InlineItem::kText) {
@@ -1893,13 +1913,12 @@
             continue;
           }
         }
+        if (item.Type() == InlineItem::kOpenRubyColumn && result.ruby_column) {
+          ComputeFromMinSizeInternal(result.ruby_column->base_line);
+          continue;
+        }
         position += result.inline_size;
       }
-      // Compute the forced break after all results were handled, because
-      // when close tags appear after a forced break, they are included in
-      // the line, and they may have inline sizes. crbug.com/991320.
-      if (line_info.HasForcedBreak())
-        ForceLineBreak(line_info);
     }
   };
 
@@ -1974,7 +1993,8 @@
           // `box-decoration-break: clone` clones box decorations to each
           // fragment (line) that we cannot compute max-content from
           // min-content.
-          !line_breaker.HasClonedBoxDecorations();
+          !line_breaker.HasClonedBoxDecorations() &&
+          !line_breaker.MayHaveRubyOverhang();
       if (can_compute_max_size_from_min_size)
         max_size_from_min_size.ComputeFromMinSize(line_info);
     } else {
diff --git a/third_party/blink/renderer/core/layout/inline/line_breaker.cc b/third_party/blink/renderer/core/layout/inline/line_breaker.cc
index 543c7cb5..0721681e 100644
--- a/third_party/blink/renderer/core/layout/inline/line_breaker.cc
+++ b/third_party/blink/renderer/core/layout/inline/line_breaker.cc
@@ -733,6 +733,7 @@
   hyphen_index_.reset();
   has_any_hyphens_ = false;
   resume_block_in_inline_in_same_flow_ = false;
+  may_have_ruby_overhang_ = false;
 
   // Use 'text-indent' as the initial position. This lets tab positions to align
   // regardless of 'text-indent'.
@@ -2979,6 +2980,16 @@
   LayoutUnit ruby_size = MaxLineWidth(base_line_info, annotation_line_list);
 
   {
+    // Recreate lines because lines created with LineBreakerMode::kMaxContent
+    // are not usable in InlineLayoutAlgorithm.
+    base_line_info =
+        CreateSubLineInfo(base_start, base_end_index, LayoutUnit::NearlyMax());
+    for (wtf_size_t i = 0; i < annotation_data.size(); ++i) {
+      annotation_line_list[i] = CreateSubLineInfo(
+          annotation_data[i].start, annotation_data[i].end_item_index,
+          LayoutUnit::NearlyMax());
+    }
+
     AddRubyColumnResult(item, base_line_info, annotation_line_list,
                         annotation_data, ruby_size, *line_info);
     position_ += ruby_size;
@@ -3038,6 +3049,10 @@
   column_result->text_offset.end = annotation_line_list[0].EndTextOffset();
   column_result->should_create_line_box = true;
   column_result->can_break_after = CanBreakAfterRubyColumn(*column_result);
+
+  if (base_line_info.Width() < ruby_size) {
+    may_have_ruby_overhang_ = true;
+  }
   return column_result;
 }
 
diff --git a/third_party/blink/renderer/core/layout/inline/line_breaker.h b/third_party/blink/renderer/core/layout/inline/line_breaker.h
index 3f7ffcd..aed1a956 100644
--- a/third_party/blink/renderer/core/layout/inline/line_breaker.h
+++ b/third_party/blink/renderer/core/layout/inline/line_breaker.h
@@ -61,6 +61,9 @@
   // True if the last line has `box-decoration-break: clone`, which affected the
   // size.
   bool HasClonedBoxDecorations() const { return has_cloned_box_decorations_; }
+  // True if the last processed line might contain ruby overhang. It affects
+  // min-max computation.
+  bool MayHaveRubyOverhang() const { return may_have_ruby_overhang_; }
 
   // Compute the next line break point and produces InlineItemResults for
   // the line.
@@ -360,6 +363,8 @@
 
   // True if the resultant line contains a RubyColumn with inline-end overhang.
   bool maybe_have_end_overhang_ = false;
+  // True if the last processed line might contain ruby overhang.
+  bool may_have_ruby_overhang_ = false;
 
   // True if ShouldCreateNewSvgSegment() should be called.
   bool needs_svg_segmentation_ = false;
diff --git a/third_party/blink/renderer/core/layout/inline/logical_line_builder.cc b/third_party/blink/renderer/core/layout/inline/logical_line_builder.cc
index 7a81fd1..dbc09c29 100644
--- a/third_party/blink/renderer/core/layout/inline/logical_line_builder.cc
+++ b/third_party/blink/renderer/core/layout/inline/logical_line_builder.cc
@@ -155,7 +155,14 @@
       main_line_helper->PlaceBlockInInline(item, &item_result, line_box);
     } else if (item.Type() == InlineItem::kOpenRubyColumn) {
       DCHECK(RuntimeEnabledFeatures::RubyLineBreakableEnabled());
-      box = PlaceRubyColumn(line_info, item_result, *line_box, box);
+      if (item_result.ruby_column) {
+        box = PlaceRubyColumn(line_info, item_result, *line_box, box);
+      } else {
+        line_box->AddChild(item.BidiLevel());
+      }
+    } else if (item.Type() == InlineItem::kCloseRubyColumn) {
+      DCHECK(RuntimeEnabledFeatures::RubyLineBreakableEnabled());
+      line_box->AddChild(item.BidiLevel());
     } else if (item.Type() == InlineItem::kListMarker) {
       PlaceListMarker(item, &item_result);
     } else if (item.Type() == InlineItem::kOutOfFlowPositioned) {
diff --git a/third_party/blink/renderer/modules/mediastream/media_devices.cc b/third_party/blink/renderer/modules/mediastream/media_devices.cc
index 5fac6c32..3ca021cc 100644
--- a/third_party/blink/renderer/modules/mediastream/media_devices.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_devices.cc
@@ -645,11 +645,12 @@
     ExceptionState& exception_state) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   LocalDOMWindow* const window = DomWindow();
-  // This timeout of base::Seconds(6) is an initial value and based on the data
-  // in Media.MediaDevices.GetDisplayMedia.Latency, it should be iterated upon.
+  // Using timeout of base::Seconds(12) based on the
+  // Media.MediaDevices.GetDisplayMedia.Latency values. With the earlier value
+  // of base::Seconds(6), we got about 25% of results counted as kTimeout.
   auto* resolver = MakeGarbageCollected<
       ScriptPromiseResolverWithTracker<UserMediaRequestResult, MediaStream>>(
-      script_state, "Media.MediaDevices.GetDisplayMedia", base::Seconds(6));
+      script_state, "Media.MediaDevices.GetDisplayMedia", base::Seconds(12));
   auto promise = resolver->Promise();
 
   if (!window) {
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 e038b3ce..35049da 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
@@ -2191,9 +2191,7 @@
   auto validated_output = webnn::ValidateTransposeAndInferOutput(
       ConvertToComponentOperand(input), permutation);
   if (!validated_output.has_value()) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kDataError,
-        String::FromUTF8(validated_output.error()));
+    exception_state.ThrowTypeError(String::FromUTF8(validated_output.error()));
     return nullptr;
   }
 
@@ -2207,8 +2205,7 @@
       this, ComponentOperandTypeToBlink(validated_output->data_type),
       Vector<uint32_t>(validated_output->dimensions), transpose);
   if (!output.has_value()) {
-    exception_state.ThrowDOMException(DOMExceptionCode::kDataError,
-                                      output.error());
+    exception_state.ThrowTypeError(output.error());
     return nullptr;
   }
   transpose->Connect({input}, {output.value()});
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 41be54cf..c8b55ef0 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
@@ -2966,96 +2966,6 @@
   }
 }
 
-MLOperand* BuildTranspose(V8TestingScope& scope,
-                          MLGraphBuilder* builder,
-                          const MLOperand* input,
-                          const MLTransposeOptions* options) {
-  auto* output = builder->transpose(input, options, scope.GetExceptionState());
-  EXPECT_THAT(output, testing::NotNull());
-  EXPECT_EQ(output->Kind(), webnn::mojom::blink::Operand::Kind::kOutput);
-  EXPECT_EQ(output->DataType(), input->DataType());
-  auto* transpose = output->Operator();
-  EXPECT_THAT(transpose, testing::NotNull());
-  EXPECT_EQ(transpose->Kind(), webnn::mojom::blink::Operation::Tag::kTranspose);
-  EXPECT_TRUE(transpose->IsConnected());
-  EXPECT_THAT(transpose->Options(), testing::NotNull());
-  return output;
-}
-
-TEST_F(MLGraphBuilderTest, TransposeTest) {
-  V8TestingScope scope;
-  MLGraphBuilder* builder =
-      CreateMLGraphBuilder(scope.GetExecutionContext(), scope.GetScriptState(),
-                           scope.GetExceptionState());
-  {
-    // Test building transpose with default options.
-    auto* input = BuildInput(builder, "input", {1, 2, 3, 4},
-                             V8MLOperandDataType::Enum::kFloat32,
-                             scope.GetExceptionState());
-    auto* output = BuildTranspose(scope, builder, input);
-    EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({4, 3, 2, 1}));
-  }
-  {
-    // Test building transpose with permutation = {0, 2, 3, 1}.
-    auto* input = BuildInput(builder, "input", {1, 2, 3, 4},
-                             V8MLOperandDataType::Enum::kFloat32,
-                             scope.GetExceptionState());
-    auto* options = MLTransposeOptions::Create();
-    options->setPermutation({0, 2, 3, 1});
-    auto* output = BuildTranspose(scope, builder, input, options);
-    EXPECT_EQ(output->Dimensions(), Vector<uint32_t>({1, 3, 4, 2}));
-  }
-  {
-    // Test throwing error when the number of values in permutation is not the
-    // same as the rank of the input tensor.
-    auto* input = BuildInput(builder, "input", {1, 2, 4},
-                             V8MLOperandDataType::Enum::kInt32,
-                             scope.GetExceptionState());
-    auto* options = MLTransposeOptions::Create();
-    options->setPermutation({0, 2, 3, 1});
-    auto* output =
-        builder->transpose(input, options, scope.GetExceptionState());
-    EXPECT_THAT(output, testing::IsNull());
-    EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(),
-              DOMExceptionCode::kDataError);
-    EXPECT_EQ(
-        scope.GetExceptionState().Message(),
-        "The number of values in permutation must be the same as the rank "
-        "of the input tensor.");
-  }
-  {
-    // Test throwing error when two values in permutation are same.
-    auto* input = BuildInput(builder, "input", {1, 2, 3, 4},
-                             V8MLOperandDataType::Enum::kInt32,
-                             scope.GetExceptionState());
-    auto* options = MLTransposeOptions::Create();
-    options->setPermutation({0, 2, 3, 2});
-    auto* output =
-        builder->transpose(input, options, scope.GetExceptionState());
-    EXPECT_THAT(output, testing::IsNull());
-    EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(),
-              DOMExceptionCode::kDataError);
-    EXPECT_EQ(scope.GetExceptionState().Message(),
-              "Two or more values are same in the axes sequence.");
-  }
-  {
-    // Test throwing error when one value in permutation is greater than
-    // input_rank-1.
-    auto* input = BuildInput(builder, "input", {1, 2, 3, 4},
-                             V8MLOperandDataType::Enum::kInt32,
-                             scope.GetExceptionState());
-    auto* options = MLTransposeOptions::Create();
-    options->setPermutation({0, 1, 2, 4});
-    auto* output =
-        builder->transpose(input, options, scope.GetExceptionState());
-    EXPECT_THAT(output, testing::IsNull());
-    EXPECT_EQ(scope.GetExceptionState().CodeAs<DOMExceptionCode>(),
-              DOMExceptionCode::kDataError);
-    EXPECT_EQ(scope.GetExceptionState().Message(),
-              "The values in axes must be in the range [0, 4).");
-  }
-}
-
 MLOperand* BuildClamp(V8TestingScope& scope,
                       MLGraphBuilder* builder,
                       const MLOperand* input,
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.h b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.h
index 6de08296..b3f88e3a 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.h
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_test.h
@@ -26,7 +26,6 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_reduce_options.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_softplus_options.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_ml_split_options.h"
-#include "third_party/blink/renderer/bindings/modules/v8/v8_ml_transpose_options.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/modules/ml/webnn/ml_graph.h"
 #include "third_party/blink/renderer/modules/ml/webnn/ml_graph_builder_utils.h"
@@ -133,13 +132,6 @@
     MLGraphBuilder* builder,
     const MLOperand* input,
     const MLSoftplusOptions* options = MLSoftplusOptions::Create());
-
-MLOperand* BuildTranspose(
-    V8TestingScope& scope,
-    MLGraphBuilder* builder,
-    const MLOperand* input,
-    const MLTransposeOptions* options = MLTransposeOptions::Create());
-
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_ML_WEBNN_ML_GRAPH_BUILDER_TEST_H_
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo_test.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo_test.cc
index c400c427..6594680e 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo_test.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_mojo_test.cc
@@ -4073,97 +4073,6 @@
   }
 }
 
-struct TransposeTester {
-  OperandInfoBlink input;
-  std::optional<Vector<uint32_t>> permutation;
-  OperandInfoMojo expected_operand;
-  Vector<uint32_t> expected_permutation;
-
-  void Test(MLGraphTestMojo& helper,
-            V8TestingScope& scope,
-            MLGraphBuilder* builder) {
-    // Build the graph.
-    auto* input_operand =
-        BuildInput(builder, "input", input.dimensions, input.data_type,
-                   scope.GetExceptionState());
-    MLTransposeOptions* options = MLTransposeOptions::Create();
-    if (permutation.has_value()) {
-      options->setPermutation(permutation.value());
-    }
-    auto* output_operand =
-        builder->transpose(input_operand, options, scope.GetExceptionState());
-    auto [graph, error_name, error_message] =
-        helper.BuildGraph(scope, builder, {{"output", output_operand}});
-    ASSERT_THAT(graph, testing::NotNull());
-
-    auto graph_info = helper.GetGraphInfo();
-    // Verify the graph information of mojo are as expected.
-    ASSERT_EQ(graph_info->operations.size(), 1u);
-    auto& operation = graph_info->operations[0];
-    ASSERT_TRUE(operation->is_transpose());
-    auto& transpose = operation->get_transpose();
-
-    // Validate the permutation of transpose operation.
-    EXPECT_EQ(transpose->permutation, expected_permutation);
-
-    // Validate the input operand.
-    EXPECT_EQ(graph_info->input_operands.size(), 1u);
-    auto input_operand_id = graph_info->input_operands[0];
-    EXPECT_EQ(transpose->input_operand_id, input_operand_id);
-    auto input_operand_iter =
-        graph_info->id_to_operand_map.find(input_operand_id);
-    ASSERT_TRUE(input_operand_iter != graph_info->id_to_operand_map.end());
-    EXPECT_EQ(input_operand_iter->value->data_type, expected_operand.data_type);
-    EXPECT_EQ(input_operand_iter->value->dimensions, input.dimensions);
-
-    // Validate the output operand.
-    EXPECT_EQ(graph_info->output_operands.size(), 1u);
-    auto output_operand_id = graph_info->output_operands[0];
-    EXPECT_EQ(transpose->output_operand_id, output_operand_id);
-    auto output_operand_iter =
-        graph_info->id_to_operand_map.find(output_operand_id);
-    ASSERT_TRUE(output_operand_iter != graph_info->id_to_operand_map.end());
-    EXPECT_EQ(output_operand_iter->value->data_type,
-              expected_operand.data_type);
-    EXPECT_EQ(output_operand_iter->value->dimensions,
-              expected_operand.dimensions);
-  }
-};
-
-TEST_P(MLGraphTestMojo, TransposeTest) {
-  V8TestingScope scope;
-  // Bind fake WebNN Context in the service for testing.
-  ScopedWebNNServiceBinder scoped_setup_binder(*this, scope);
-
-  auto* options = MLContextOptions::Create();
-  // Create WebNN Context with GPU device type.
-  options->setDeviceType(V8MLDeviceType::Enum::kGpu);
-  auto* builder = CreateGraphBuilder(scope, options);
-  {
-    // Test transpose operator with default options.
-    TransposeTester{
-        .input = {.data_type = V8MLOperandDataType::Enum::kFloat32,
-                  .dimensions = {1, 2, 3, 4}},
-        .expected_operand = {.data_type =
-                                 blink_mojom::Operand::DataType::kFloat32,
-                             .dimensions = {4, 3, 2, 1}},
-        .expected_permutation = {3, 2, 1, 0}}
-        .Test(*this, scope, builder);
-  }
-  {
-    // Test transpose operator with a given permutation.
-    TransposeTester{
-        .input = {.data_type = V8MLOperandDataType::Enum::kFloat16,
-                  .dimensions = {1, 2, 3, 4}},
-        .permutation = Vector<uint32_t>{3, 0, 2, 1},
-        .expected_operand = {.data_type =
-                                 blink_mojom::Operand::DataType::kFloat16,
-                             .dimensions = {4, 1, 3, 2}},
-        .expected_permutation = {3, 0, 2, 1}}
-        .Test(*this, scope, builder);
-  }
-}
-
 struct ReduceTester {
   OperandInfoBlink input;
   std::optional<Vector<uint32_t>> axes;
diff --git a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
index 190c379..eced28c 100644
--- a/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
+++ b/third_party/blink/renderer/modules/ml/webnn/ml_graph_test.cc
@@ -1717,81 +1717,6 @@
 }
 
 template <typename T>
-struct TransposeTester {
-  OperandInfo<T> input;
-  Vector<T> expected;
-
-  void Test(MLGraphTest& helper,
-            V8TestingScope& scope,
-            MLGraphBuilder* builder,
-            MLTransposeOptions* options = MLTransposeOptions::Create()) {
-    auto* input_operand =
-        BuildInput(builder, "input", input.dimensions, input.data_type,
-                   scope.GetExceptionState());
-    auto* output_operand =
-        BuildTranspose(scope, builder, input_operand, options);
-    auto [graph, error_name, error_message] =
-        helper.BuildGraph(scope, builder, {{"output", output_operand}});
-    ASSERT_THAT(graph, testing::NotNull());
-
-    MLNamedArrayBufferViews inputs(
-        {{"input",
-          CreateArrayBufferViewForOperand(input_operand, input.values)}});
-    MLNamedArrayBufferViews outputs(
-        {{"output", CreateArrayBufferViewForOperand(output_operand)}});
-    std::tie(error_name, error_message) =
-        helper.ComputeGraph(scope, graph, inputs, outputs);
-    EXPECT_TRUE(error_name.IsNull());
-    auto results = GetArrayBufferViewValues<T>(outputs[0].second);
-    EXPECT_EQ(results, expected);
-  }
-};
-
-TEST_P(MLGraphTest, TransposeTest) {
-  V8TestingScope scope;
-  auto* builder =
-      CreateMLGraphBuilder(scope.GetExecutionContext(), scope.GetScriptState(),
-                           scope.GetExceptionState());
-  {
-    // Test transpose operator with default options.
-    auto* options = MLTransposeOptions::Create();
-    TransposeTester<float>{
-        .input = {.data_type = V8MLOperandDataType::Enum::kFloat32,
-                  .dimensions = {2, 3, 4},
-                  .values =
-                      {
-                          0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11,
-                          12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
-                      }},
-        .expected =
-            {
-                0, 12, 4, 16, 8,  20, 1, 13, 5, 17, 9,  21,
-                2, 14, 6, 18, 10, 22, 3, 15, 7, 19, 11, 23,
-            }}
-        .Test(*this, scope, builder, options);
-  }
-  {
-    // Test transpose with permutation = {0, 2, 1}.
-    auto* options = MLTransposeOptions::Create();
-    options->setPermutation({{0, 2, 1}});
-    TransposeTester<float>{
-        .input = {.data_type = V8MLOperandDataType::Enum::kFloat32,
-                  .dimensions = {2, 3, 4},
-                  .values =
-                      {
-                          0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11,
-                          12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
-                      }},
-        .expected =
-            {
-                0,  4,  8,  1,  5,  9,  2,  6,  10, 3,  7,  11,
-                12, 16, 20, 13, 17, 21, 14, 18, 22, 15, 19, 23,
-            }}
-        .Test(*this, scope, builder, options);
-  }
-}
-
-template <typename T>
 struct ConcatTester {
   Vector<OperandInfo<T>> inputs;
   uint32_t axis;
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
index d6d6df0..7f4308fa 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -1648,20 +1648,6 @@
               GetThread()->GetTaskRunner(TaskType::kNetworking));
   fetch_response_callbacks_.Set(event_id, WrapDisallowNew(std::move(remote)));
 
-  if (params->race_network_request_loader_factory) {
-    UseCounter::Count(
-        this,
-        // If the runtime flag is enabled, that means the feature is enabled via
-        // OriginTrial. We count the feature usage separatefy from the a/b
-        // experiment to monitor the actual usage respectively.
-        RuntimeEnabledFeatures::ServiceWorkerRaceNetworkRequestEnabled(
-            ExecutionContext::From(ScriptController()->GetScriptState()))
-            ? WebFeature::
-                  kServiceWorkerBypassFetchHandlerForAllWithRaceNetworkRequestByOriginTrial
-            : WebFeature::
-                  kServiceWorkerBypassFetchHandlerForAllWithRaceNetworkRequest);
-  }
-
   if (RequestedTermination()) {
     event_queue_->EnqueuePending(
         event_id,
diff --git a/third_party/blink/renderer/platform/network/DEPS b/third_party/blink/renderer/platform/network/DEPS
index f30e7c1..308e3bd 100644
--- a/third_party/blink/renderer/platform/network/DEPS
+++ b/third_party/blink/renderer/platform/network/DEPS
@@ -23,6 +23,7 @@
     "+third_party/blink/renderer/platform/loader",
     "+third_party/blink/renderer/platform/mojo/security_origin_mojom_traits.h",
     "+third_party/blink/renderer/platform/platform_export.h",
+    "+third_party/blink/renderer/platform/runtime_enabled_features.h",
     "+third_party/blink/renderer/platform/scheduler",
     "+third_party/blink/renderer/platform/wtf/shared_buffer.h",
     "+third_party/blink/renderer/platform/testing",
diff --git a/third_party/blink/renderer/platform/network/http_parsers.cc b/third_party/blink/renderer/platform/network/http_parsers.cc
index ac2a549..5264314 100644
--- a/third_party/blink/renderer/platform/network/http_parsers.cc
+++ b/third_party/blink/renderer/platform/network/http_parsers.cc
@@ -56,6 +56,7 @@
 #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
 #include "third_party/blink/renderer/platform/network/header_field_tokenizer.h"
 #include "third_party/blink/renderer/platform/network/http_names.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/date_math.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
@@ -370,8 +371,6 @@
   for (unsigned i = 0; i < source.length(); ++i) {
     UChar ch = source[i];
     if (ch == kFullstopCharacter) {
-      // TODO(tkent): According to the HTML specification, we should support
-      // only integers. However we support fractional numbers.
       if (++full_stop_count == 2)
         number_end = i;
     } else if (!IsASCIIDigit(ch)) {
@@ -380,6 +379,9 @@
   }
   bool ok;
   double time = source.Left(number_end).ToDouble(&ok);
+  if (RuntimeEnabledFeatures::MetaRefreshNoFractionalEnabled()) {
+    time = floor(time);
+  }
   if (!ok)
     return false;
   delay = base::Seconds(time);
diff --git a/third_party/blink/renderer/platform/network/http_parsers_test.cc b/third_party/blink/renderer/platform/network/http_parsers_test.cc
index 05a3d5af..623cef0 100644
--- a/third_party/blink/renderer/platform/network/http_parsers_test.cc
+++ b/third_party/blink/renderer/platform/network/http_parsers_test.cc
@@ -297,11 +297,11 @@
 
   EXPECT_TRUE(
       ParseHTTPRefresh("1.5; url=dest", IsASCIISpace<UChar>, delay, url));
-  EXPECT_EQ(base::Seconds(1.5), delay);
+  EXPECT_EQ(base::Seconds(1), delay);
   EXPECT_EQ("dest", url);
   EXPECT_TRUE(
       ParseHTTPRefresh("1.5.9; url=dest", IsASCIISpace<UChar>, delay, url));
-  EXPECT_EQ(base::Seconds(1.5), delay);
+  EXPECT_EQ(base::Seconds(1), delay);
   EXPECT_EQ("dest", url);
   EXPECT_TRUE(
       ParseHTTPRefresh("7..; url=dest", IsASCIISpace<UChar>, delay, url));
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index e2e0c93..a03bd97e 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1063,7 +1063,7 @@
     {
       // Explainer: https://drafts.csswg.org/css-values/#round-func
       name: "CSSSteppedValueFunctions",
-      status: "experimental",
+      status: "stable",
     },
     {
       name: "CSSStickyContainerQueries",
@@ -2448,6 +2448,13 @@
       name: "MessagePortCloseEvent",
       status: "test",
     },
+    // This is a killswitch for <meta http-equiv="refresh"> no
+    // longer accepting fractions, landed around M125.
+    // It can be removed in M127 if there are no problems.
+    {
+      name: "MetaRefreshNoFractional",
+      status: "stable",
+    },
     // This is enabled by default on Windows only. The only part that's
     // "experimental" is the support on other platforms.
     {
@@ -3460,22 +3467,10 @@
       base_feature: "none",
     },
     {
-      name: "ServiceWorkerBypassFetchHandler",
-      base_feature: "none",
-      origin_trial_feature_name: "ServiceWorkerBypassFetchHandlerForMainResource",
-      public: true,
-    },
-    {
       name: "ServiceWorkerClientLifecycleState",
       status: "experimental",
     },
     {
-      name: "ServiceWorkerRaceNetworkRequest",
-      base_feature: "none",
-      origin_trial_feature_name: "ServiceWorkerBypassFetchHandlerWithRaceNetworkRequest",
-      public: true,
-    },
-    {
       name: "ServiceWorkerStaticRouter",
       base_feature: "none",
       origin_trial_feature_name: "ServiceWorkerStaticRouter",
diff --git a/third_party/blink/web_tests/ChromeTestExpectations b/third_party/blink/web_tests/ChromeTestExpectations
index dfcccce7..dcdccc7 100644
--- a/third_party/blink/web_tests/ChromeTestExpectations
+++ b/third_party/blink/web_tests/ChromeTestExpectations
@@ -53,7 +53,7 @@
 crbug.com/324436866 external/wpt/webdriver/tests/classic/get_current_url/file.py [ Failure Pass Timeout ]
 crbug.com/626703 external/wpt/webdriver/tests/bidi/input/set_files/invalid.py [ Failure Timeout ]
 external/wpt/webdriver/tests/bidi/input/set_files/set_files.py [ Timeout ]
-[ Debug ] external/wpt/webdriver/tests/bidi/network/add_intercept/contexts.py [ Timeout ]
+[ Debug ] external/wpt/webdriver/tests/bidi/network/add_intercept/contexts.py [ Timeout Failure Pass ]
 [ Debug ] external/wpt/webdriver/tests/bidi/storage/delete_cookies/filter.py [ Timeout ]
 [ Debug ] external/wpt/webdriver/tests/bidi/storage/delete_cookies/invalid.py [ Timeout ]
 [ Debug ] external/wpt/webdriver/tests/bidi/storage/delete_cookies/partition.py [ Timeout ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 03ca2f5..f08c21e1 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -319,7 +319,7 @@
 crbug.com/309675 compositing/gestures/gesture-tapHighlight-simple-longPress.html [ Failure ]
 
 crbug.com/845267 [ Mac ] http/tests/inspector-protocol/page/page-lifecycleEvents.js [ Failure Pass ]
-crbug.com/1046784 http/tests/inspector-protocol/page/page-events-associated-isolation.js [ Failure Pass ]
+crbug.com/333842054 http/tests/inspector-protocol/page/page-events-associated-isolation.js [ Failure Pass ]
 
 # Counters failures to be fixed with new implementation
 crbug.com/990657 external/wpt/css/css-contain/contain-style-counters-004.html [ Failure ]
@@ -628,7 +628,7 @@
 
 crbug.com/898394 [ Debug ] virtual/android/url-bar/bottom-and-top-fixed-sticks-to-top.html [ Failure Timeout ]
 
-crbug.com/1046784 http/tests/devtools/elements/styles-3/styles-disable-then-delete.js [ Crash Failure Pass Timeout ]
+crbug.com/333831247 http/tests/devtools/elements/styles-3/styles-disable-then-delete.js [ Crash Failure Pass Timeout ]
 
 # Subpixel rounding differences that are incorrect.
 crbug.com/997202 compositing/overflow/scaled-overflow.html [ Failure ]
@@ -4197,7 +4197,7 @@
 crbug.com/1043675 [ Win ] svg/custom/svg-root-with-opacity.html [ Failure ]
 
 # Sheriff 2020-01-23
-crbug.com/1046784 http/tests/inspector-protocol/service-worker/target-reloaded-after-crash.js [ Failure Pass Timeout ]
+crbug.com/333831246 http/tests/inspector-protocol/service-worker/target-reloaded-after-crash.js [ Failure Pass Timeout ]
 
 # Sheriff 2020-01-28
 crbug.com/1046440 fast/loader/submit-form-while-parsing-2.html [ Failure Pass Timeout ]
@@ -4357,7 +4357,7 @@
 crbug.com/1071189 [ Debug Linux ] editing/selection/programmatic-selection-on-mac-is-directionless.html [ Pass Timeout ]
 
 # Sheriff 2020-05-27
-crbug.com/1046784 http/tests/devtools/elements/styles/stylesheet-tracking.js [ Failure Pass Timeout ]
+crbug.com/333787228 http/tests/devtools/elements/styles/stylesheet-tracking.js [ Failure Pass Timeout ]
 
 # Sheriff 2020-05-29
 crbug.com/1084637 compositing/video/video-reflection.html [ Failure Pass ]
@@ -4452,7 +4452,7 @@
 crbug.com/1042877 http/tests/security/mixedContent/strict-mode-image-reportonly.https.php [ Failure ]
 crbug.com/1042877 http/tests/security/mixedContent/strict-mode-via-pref-image-blocked.https.html [ Failure ]
 
-crbug.com/1046784 http/tests/devtools/sources/debugger/anonymous-script-with-source-map-breakpoint.js [ Failure Pass ]
+crbug.com/333787229 http/tests/devtools/sources/debugger/anonymous-script-with-source-map-breakpoint.js [ Failure Pass ]
 
 # Mixed content autoupgrades cause test to fail because test relied on http subresources to test a different origin, needs to be changed to not rely on HTTP URLs.
 crbug.com/1042877 http/tests/security/img-crossorigin-redirect-credentials.https.html [ Failure ]
@@ -4488,7 +4488,6 @@
 crbug.com/1150475 fast/dom/open-and-close-by-DOM.html [ Failure Pass ]
 
 #Sheriff 2020-11-23
-# Sheriff 2021-01-22 added Timeout per crbug.com/1046784:
 crbug.com/1149734 http/tests/devtools/sources/debugger-frameworks/frameworks-sourcemap.js [ Failure Pass ]
 crbug.com/1149734 http/tests/devtools/sources/debugger-ui/continue-to-location-markers.js [ Failure Pass Timeout ]
 crbug.com/1149734 http/tests/devtools/sources/debugger-ui/inline-scope-variables.js [ Failure Pass Timeout ]
@@ -6802,9 +6801,6 @@
 # May fail due to test framework issue. Disabling while this is being resolved.
 crbug.com/1367312 [ Win ] fast/dom/timer-throttling-hidden-page.html [ Failure Pass ]
 
-# Gardener: 2024-01-23
-crbug.com/1521090 [ Mac12 ] virtual/static-routing-api/http/tests/inspector-protocol/service-worker/tentative/static-router/receive-router-rules-on-update.js [ Failure Pass ]
-
 ### sheriff 2023-01-24
 crbug.com/1521311 http/tests/devtools/service-workers/sw-navigate-useragent.js [ Failure Pass ]
 
@@ -7166,6 +7162,58 @@
 crbug.com/332068449 [ Mac ] external/wpt/focus/cross-origin-ancestor-activeelement-after-child-lose-focus.sub.html [ Failure Pass ]
 crbug.com/330761492 external/wpt/html/editing/the-hidden-attribute/beforematch-scroll-to-text-fragment.html [ Failure Pass ]
 
+# RubyLineBreakable
+crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/br-clear-all-002.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/empty-ruby-text-container-abs.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/empty-ruby-text-container-float.html [ Crash ]
+crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/line-break-around-ruby-001.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/line-spacing.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/nested-ruby-pairing-001.html [ Crash Failure Timeout ]
+crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/ruby-align-001.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/ruby-align-001a.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/ruby-align-002.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/ruby-align-002a.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/ruby-base-container-float.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/ruby-bidi-003.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/ruby-float-handling-001.html [ Crash Failure ]
+crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/ruby-intra-level-whitespace-001.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/external/wpt/css/css-ruby/ruby-line-breaking-002.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/after-doesnt-crash.html [ Crash Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/base-shorter-than-text.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/before-doesnt-crash.html [ Crash Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/float-object-doesnt-crash.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/float-overhang-from-ruby-text.html [ Crash Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/line-break-ruby.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/modify-positioned-ruby-text-crash.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/nested-ruby.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/overhang-horizontal-no-overlap1.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/overhang-horizontal-no-overlap2.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/overhang-horizontal.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/overhang-vertical-no-overlap1.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/overhang-vertical-no-overlap2.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/overhang-vertical.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/percentage-height-child-crash.html [ Crash ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/position-after.html [ Crash ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-column-break.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-columns-spans.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-columns.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-empty-rt.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-first-letter.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-illegal-7.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-illegal-combined.html [ Crash Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-length.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-position-modern-japanese-fonts.html [ Crash Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-simple-rp.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-simple.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-text-before-after-content.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/ruby-trailing.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/rubyDOM-insert-rt-block-1.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/rubyDOM-insert-rt-block-2.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/rubyDOM-insert-rt-block-3.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/rubyDOM-insert-text2.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/select-ruby.html [ Failure ]
+crbug.com/324111880 virtual/ruby-lb/fast/ruby/split-ruby-column-percentage-height-descendant.html [ Failure ]
+
 # line-clamp
 crbug.com/40336192 external/wpt/css/css-overflow/line-clamp-001.tentative.html [ Failure ]
 crbug.com/40336192 external/wpt/css/css-overflow/line-clamp-004.tentative.html [ Failure ]
@@ -7252,10 +7300,9 @@
 
 # Branch Gardener 2024-04-10
 crbug.com/333639341 [ Fuchsia ] fast/writing-mode/english-lr-text.html [ Failure Pass ]
-crbug.com/333638402 [ Linux ] external/wpt/css/css-color/parsing/color-computed-color-function.html [ Failure ]
-crbug.com/333638402 [ Linux ] external/wpt/css/css-color/parsing/color-computed-lab.html [ Failure ]
-crbug.com/333638402 [ Linux ] external/wpt/css/css-color/parsing/color-valid-color-function.html [ Failure ]
-crbug.com/333638402 [ Linux ] external/wpt/css/css-color/parsing/color-valid-lab.html [ Failure ]
 
 # Gardener 2024-04-11
 crbug.com/333739617 [ Mac ] fast/peerconnection/RTCEncodedVideoFrameMetadata-timestamp.html [ Timeout ]
+
+# Test requires rebaseline after rolling V8.
+crbug.com/333182464 external/wpt/streams/readable-streams/global.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 6a6d5d4..71fb060f 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -2833,5 +2833,13 @@
     "bases": ["external/wpt/css/css-overflow", "fast/overflow"],
     "args": ["--enable-blink-features=CSSLineClamp"],
     "owners": ["abotella@igalia.com"]
+  },
+  {
+    "prefix": "ruby-lb",
+    "platforms": ["Mac"],
+    "bases": ["external/wpt/css/css-ruby", "fast/ruby"],
+    "args": ["--enable-blink-features=RubyLineBreakable"],
+    "owners": ["tkent@chromium.org"],
+    "expires": "Oct 10, 2024"
   }
 ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-anchor-position/base-style-invalidation.html b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/base-style-invalidation.html
new file mode 100644
index 0000000..8e8e69f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-anchor-position/base-style-invalidation.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<title>CSS Anchor Positioning: Invalidation from changing the base style</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/">
+<link rel="help" href="https://issues.chromium.org/issues/333608683">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+  @position-try --pt {
+    width: 50px; /* Undo force overflow */
+  }
+  #cb {
+    position: relative;
+    width: 200px;
+    height: 200px;
+    border: 1px solid black;
+  }
+  #anchor {
+    position: absolute;
+    left: 75px;
+    top: 75px;
+    width: 50px;
+    height: 50px;
+    background: coral;
+    anchor-name: --a;
+  }
+  #anchored {
+    position: absolute;
+    position-anchor: --a;
+    position-try-options: --pt flip-start;
+    inset: 0;
+    top: anchor(top);
+    bottom: anchor(bottom);
+    right: calc(anchor(left) + 5px);
+    width: 50px;
+    height: 50px;
+    background: skyblue;
+    justify-self: end;
+  }
+  #anchored.flip {
+    background: seagreen;
+    width: 300px; /* Force overflow */
+  }
+</style>
+<div id=cb>
+  <div id=anchor></div>
+  <div id=anchored></div>
+</div>
+<script>
+  test(() => {
+    // Initially to the left.
+    assert_equals(anchored.offsetLeft, 20);
+    assert_equals(anchored.offsetTop, 75);
+
+    // Flips to the right.
+    anchored.classList.toggle('flip');
+    assert_equals(anchored.offsetLeft, 75);
+    assert_equals(anchored.offsetTop, 20);
+
+    // Flips to the original position.
+    anchored.classList.toggle('flip');
+    assert_equals(anchored.offsetLeft, 20);
+    assert_equals(anchored.offsetTop, 75);
+  }, 'The chosen position options changes when the base style differs');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/meta/refresh-time.html b/third_party/blink/web_tests/external/wpt/html/meta/refresh-time.html
new file mode 100644
index 0000000..7aef126
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/meta/refresh-time.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test fractional values in meta http-equiv=refresh</title>
+<link rel="author" title="Psychpsyo"  href="mailto:psychpsyo@gmail.com">
+<link rel="help" href="https://html.spec.whatwg.org/#pragma-directives">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<script>
+  async function sleep(ms, test) {
+    return new Promise(resolve => {test.step_timeout(resolve, ms)});
+  }
+
+  promise_test(async test => {
+    const frame = document.createElement("iframe");
+    document.body.appendChild(frame);
+    frame.src = "resources/refresh1.html";
+    await sleep(500, test);
+    assert_equals(frame.contentWindow.document.title, "refresh 1");
+    await sleep(1000, test);
+    assert_equals(frame.contentWindow.document.title, "got refreshed");
+  }, "Ensure that refresh is observed");
+
+  promise_test(async test => {
+    const frame = document.createElement("iframe");
+    document.body.appendChild(frame);
+    frame.src = "resources/refresh.99.html";
+    await sleep(500, test);
+    assert_equals(frame.contentWindow.document.title, "got refreshed");
+  }, "Ensure that fractions in refresh time are ignored");
+
+  promise_test(async test => {
+    const frame = document.createElement("iframe");
+    document.body.appendChild(frame);
+    frame.src = "resources/refresh1.99.html";
+    await sleep(500, test);
+    assert_equals(frame.contentWindow.document.title, "refresh 1.99");
+    await sleep(1000, test);
+    assert_equals(frame.contentWindow.document.title, "got refreshed");
+  }, "Ensure that non-fractional part in refresh time does not get discarded");
+
+  promise_test(async test => {
+    const frame = document.createElement("iframe");
+    document.body.appendChild(frame);
+    frame.src = "resources/refresh1dotdot5dot.html";
+    await sleep(500, test);
+    assert_equals(frame.contentWindow.document.title, "refresh 1..5.");
+    await sleep(750, test);
+    assert_equals(frame.contentWindow.document.title, "got refreshed");
+  }, "Ensure that multiple periods in refresh time just get ignored");
+</script>
+</body>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/html/meta/resources/gotRefreshed.html b/third_party/blink/web_tests/external/wpt/html/meta/resources/gotRefreshed.html
new file mode 100644
index 0000000..c894269
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/meta/resources/gotRefreshed.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>got refreshed</title>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/html/meta/resources/refresh.99.html b/third_party/blink/web_tests/external/wpt/html/meta/resources/refresh.99.html
new file mode 100644
index 0000000..ca4e346
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/meta/resources/refresh.99.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>refresh .99</title>
+
+<meta http-equiv="refresh" content=".99;url=gotRefreshed.html">
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/html/meta/resources/refresh1.99.html b/third_party/blink/web_tests/external/wpt/html/meta/resources/refresh1.99.html
new file mode 100644
index 0000000..76121cfd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/meta/resources/refresh1.99.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>refresh 1.99</title>
+
+<meta http-equiv="refresh" content="1.99;url=gotRefreshed.html">
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/html/meta/resources/refresh1.html b/third_party/blink/web_tests/external/wpt/html/meta/resources/refresh1.html
new file mode 100644
index 0000000..14819dc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/meta/resources/refresh1.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>refresh 1</title>
+
+<meta http-equiv="refresh" content="1;url=gotRefreshed.html">
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/html/meta/resources/refresh1dotdot5dot.html b/third_party/blink/web_tests/external/wpt/html/meta/resources/refresh1dotdot5dot.html
new file mode 100644
index 0000000..085b9e9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/meta/resources/refresh1dotdot5dot.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>refresh 1..5.</title>
+
+<meta http-equiv="refresh" content="1..5.;url=gotRefreshed.html">
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/transpose.https.any.js b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/transpose.https.any.js
index 9ea5a5d..3475a427 100644
--- a/third_party/blink/web_tests/external/wpt/webnn/validation_tests/transpose.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/webnn/validation_tests/transpose.https.any.js
@@ -5,3 +5,54 @@
 'use strict';
 
 validateInputFromAnotherBuilder('transpose');
+
+const tests = [
+  {
+    name: '[transpose] Test building transpose with default options.',
+    input: {dataType: 'float32', dimensions: [1, 2, 3, 4]},
+    output: {dataType: 'float32', dimensions: [4, 3, 2, 1]}
+  },
+  {
+    name: '[transpose] Test building transpose with permutation=[0, 2, 3, 1].',
+    input: {dataType: 'float32', dimensions: [1, 2, 3, 4]},
+    options: {permutation: [0, 2, 3, 1]},
+    output: {dataType: 'float32', dimensions: [1, 3, 4, 2]}
+  },
+  {
+    name:
+        '[transpose] Throw if permutation\'s size is not the same as input\'s rank.',
+    input: {dataType: 'int32', dimensions: [1, 2, 4]},
+    options: {permutation: [0, 2, 3, 1]},
+  },
+  {
+    name: '[transpose] Throw if two values in permutation are same.',
+    input: {dataType: 'int32', dimensions: [1, 2, 3, 4]},
+    options: {permutation: [0, 2, 3, 2]},
+  },
+  {
+    name:
+        '[transpose] Throw if any value in permutation is not in the range [0,input\'s rank).',
+    input: {dataType: 'int32', dimensions: [1, 2, 3, 4]},
+    options: {permutation: [0, 1, 2, 4]},
+  },
+  {
+    name: '[transpose] Throw if any value in permutation is negative.',
+    input: {dataType: 'int32', dimensions: [1, 2, 3, 4]},
+    options: {permutation: [0, -1, 2, 3]},
+  }
+];
+
+tests.forEach(
+    test => promise_test(async t => {
+      const input = builder.input(
+          'input',
+          {dataType: test.input.dataType, dimensions: test.input.dimensions});
+      if (test.output) {
+        const output = builder.transpose(input, test.options);
+        assert_equals(output.dataType(), test.output.dataType);
+        assert_array_equals(output.shape(), test.output.dimensions);
+      } else {
+        assert_throws_js(
+            TypeError, () => builder.transpose(input, test.options));
+      }
+    }, test.name));
diff --git a/third_party/blink/web_tests/fast/url/invalid-urls-utf8-expected.txt b/third_party/blink/web_tests/fast/url/invalid-urls-utf8-expected.txt
index 20722e79..8d6f496b 100644
--- a/third_party/blink/web_tests/fast/url/invalid-urls-utf8-expected.txt
+++ b/third_party/blink/web_tests/fast/url/invalid-urls-utf8-expected.txt
@@ -8,11 +8,9 @@
 PASS src is expected
 PASS src is expected
 PASS src is expected
-FAIL src should be foo://tête à tête@host/. Was foo://t%C3%AAte %C3%A0 t%C3%AAte@host/.
-FAIL src should be foo://user:tête à tête@host/. Was foo://user:t%C3%AAte %C3%A0 t%C3%AAte@host/.
 PASS src is expected
 PASS src is expected
-FAIL src should be foo://user:password@[xxxxx]/tête à tête/. Was foo://user:password@[xxxxx]/t%C3%AAte %C3%A0 t%C3%AAte/.
+FAIL src should be     foo://user:password@[xxxxx]/    . Was foo://user:password@[xxxxx]/.
 FAIL src should be foo://user:password@[?tête à tête/. Was foo://user:password@[?t%C3%AAte%20%C3%A0%20t%C3%AAte/.
 FAIL src should be foo://user:password@[?tête à tête]/. Was foo://user:password@[?t%C3%AAte%20%C3%A0%20t%C3%AAte]/.
 FAIL src should be foo://user:password@host:tête à tête/. Was foo://user:password@host:t%C3%AAte %C3%A0 t%C3%AAte/.
diff --git a/third_party/blink/web_tests/fast/url/invalid-urls-utf8.html b/third_party/blink/web_tests/fast/url/invalid-urls-utf8.html
index d10be35d..b25b553 100644
--- a/third_party/blink/web_tests/fast/url/invalid-urls-utf8.html
+++ b/third_party/blink/web_tests/fast/url/invalid-urls-utf8.html
@@ -21,13 +21,11 @@
     'gopher:///',
     'ws:///',
     'wss:///',
+    '  wss:///  ',
 
     // Invalid Authority.
-    'foo://tête à tête@host/',
-    'foo://user:tête à tête@host/',
-    '    foo://<>@host/    ',
-    '    foo://user:<>@host/    ',
-    'foo://user:password@[xxxxx]/tête à tête/',
+    'foo://user:password@[xxxxx]/',
+    '    foo://user:password@[xxxxx]/    ',
 
     // The '?' is a path separator and make sure the hostname is not encoded in punicode. The hostname is an invalid IPV6 hostname.
     'foo://user:password@[?tête à tête/',
@@ -45,7 +43,7 @@
 
 for (var i = 0; i < testSet.length; ++i) {
     src = canonicalize(testSet[i]);
-    expected = testSet[i].trim();
+    expected = testSet[i];
     shouldBe('src', 'expected');
 }
 
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/receive-router-rules-on-update.js b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/receive-router-rules-on-update.js
index 866022d9..f97b510 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/receive-router-rules-on-update.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/tentative/static-router/receive-router-rules-on-update.js
@@ -1,7 +1,6 @@
 (async function(/** @type {import('test_runner').TestRunner} */ testRunner) {
-  var {page, session, dp} = await testRunner.startURL(
-      'resources/service-worker-with-static-router.html',
-      'Tests receiving static router rules from the service worker.');
+  const {dp, page} = await testRunner.startBlank(
+    'Tests receiving static router rules from the service worker.');
 
   async function waitForServiceWorkerActivation() {
     let versions = [];
@@ -13,9 +12,12 @@
   }
 
   await dp.Runtime.enable();
-  await dp.ServiceWorker.enable();
 
-  const versions = await waitForServiceWorkerActivation();
+  const versionsPromise = waitForServiceWorkerActivation();
+  await dp.ServiceWorker.enable();
+  await page.navigate('resources/service-worker-with-static-router.html');
+
+  const versions = await versionsPromise;
   testRunner.log(versions[0].routerRules);
   testRunner.completeTest();
 });
diff --git a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/fast/url/invalid-urls-utf8-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/fast/url/invalid-urls-utf8-expected.txt
index 6c10a121..d4675c36 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/url-non-special/fast/url/invalid-urls-utf8-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/virtual/url-non-special/fast/url/invalid-urls-utf8-expected.txt
@@ -8,10 +8,8 @@
 PASS src is expected
 PASS src is expected
 PASS src is expected
-FAIL src should be foo://tête à tête@host/. Was foo://t%C3%AAte%20%C3%A0%20t%C3%AAte@host/.
-FAIL src should be foo://user:tête à tête@host/. Was foo://user:t%C3%AAte%20%C3%A0%20t%C3%AAte@host/.
-FAIL src should be foo://<>@host/. Was foo://%3C%3E@host/.
-FAIL src should be foo://user:<>@host/. Was foo://user:%3C%3E@host/.
+PASS src is expected
+PASS src is expected
 PASS src is expected
 PASS src is expected
 PASS src is expected
diff --git a/third_party/blink/web_tests/virtual/ruby-lb/README.md b/third_party/blink/web_tests/virtual/ruby-lb/README.md
new file mode 100644
index 0000000..600b94f0
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/ruby-lb/README.md
@@ -0,0 +1,6 @@
+Tests for the RubyLineBreakable feature.
+
+The feature affects all <ruby> rendering, but it's under development. We don't
+want to enable the feature for all tests yet.
+
+crbug.com/324111880
diff --git a/third_party/fuzztest/BUILD.gn b/third_party/fuzztest/BUILD.gn
index aa1f99a..c3abf67f 100644
--- a/third_party/fuzztest/BUILD.gn
+++ b/third_party/fuzztest/BUILD.gn
@@ -214,6 +214,8 @@
     "src/fuzztest/domain.h",
     "src/fuzztest/domain_core.h",
     "src/fuzztest/fuzztest.h",
+    "src/fuzztest/fuzztest_macros.cc",
+    "src/fuzztest/fuzztest_macros.h",
     "src/fuzztest/googletest_fixture_adapter.h",
     "src/fuzztest/internal/any.h",
     "src/fuzztest/internal/centipede_adaptor.h",
diff --git a/third_party/fuzztest/src b/third_party/fuzztest/src
index d7c63cd..65354bf 160000
--- a/third_party/fuzztest/src
+++ b/third_party/fuzztest/src
@@ -1 +1 @@
-Subproject commit d7c63cd216941e297569428e40f9b8bc155e0423
+Subproject commit 65354bf09a2479945b4683c42948695d4f2f7c07
diff --git a/third_party/libsrtp b/third_party/libsrtp
index 5b7c744..7a7e64c 160000
--- a/third_party/libsrtp
+++ b/third_party/libsrtp
@@ -1 +1 @@
-Subproject commit 5b7c744eb8310250ccc534f3f86a2015b3887a0a
+Subproject commit 7a7e64c8b5a632f55929cb3bb7d3e6fb48c3205a
diff --git a/third_party/nearby/README.chromium b/third_party/nearby/README.chromium
index 5a9d3a1..2df1bcef 100644
--- a/third_party/nearby/README.chromium
+++ b/third_party/nearby/README.chromium
@@ -1,7 +1,7 @@
 Name: Nearby Connections Library
 Short Name: Nearby
 URL: https://github.com/google/nearby
-Version: 78505e91f7e054444030aec55110893b4fc62500
+Version: 03f0b3dae98d218e8420add5a13893822d290855
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
diff --git a/third_party/nearby/src b/third_party/nearby/src
index 78505e9..03f0b3d 160000
--- a/third_party/nearby/src
+++ b/third_party/nearby/src
@@ -1 +1 @@
-Subproject commit 78505e91f7e054444030aec55110893b4fc62500
+Subproject commit 03f0b3dae98d218e8420add5a13893822d290855
diff --git a/third_party/skia b/third_party/skia
index 28579a8..2a2fe43 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit 28579a88aa9c12ef23c1d3ab798aba40f85ea0d8
+Subproject commit 2a2fe430350798bf10c28ad55daf61c08c6a4121
diff --git a/third_party/webgpu-cts/src b/third_party/webgpu-cts/src
index acb4750..e5fb882 160000
--- a/third_party/webgpu-cts/src
+++ b/third_party/webgpu-cts/src
@@ -1 +1 @@
-Subproject commit acb475026d7ac90725c629ef3664267c7aed72a1
+Subproject commit e5fb8824ade85fae690f2bb45cc347a1398cca2f
diff --git a/third_party/webgpu-cts/ts_sources.txt b/third_party/webgpu-cts/ts_sources.txt
index ed6e32cd..390e30ca 100644
--- a/third_party/webgpu-cts/ts_sources.txt
+++ b/third_party/webgpu-cts/ts_sources.txt
@@ -772,7 +772,10 @@
 src/webgpu/shader/validation/expression/call/builtin/min.spec.ts
 src/webgpu/shader/validation/expression/call/builtin/modf.spec.ts
 src/webgpu/shader/validation/expression/call/builtin/normalize.spec.ts
+src/webgpu/shader/validation/expression/call/builtin/pack2x16snorm.spec.ts
+src/webgpu/shader/validation/expression/call/builtin/pack2x16unorm.spec.ts
 src/webgpu/shader/validation/expression/call/builtin/pack4x8snorm.spec.ts
+src/webgpu/shader/validation/expression/call/builtin/pack4x8unorm.spec.ts
 src/webgpu/shader/validation/expression/call/builtin/pack4xI8.spec.ts
 src/webgpu/shader/validation/expression/call/builtin/pack4xI8Clamp.spec.ts
 src/webgpu/shader/validation/expression/call/builtin/pack4xU8.spec.ts
diff --git a/third_party/webrtc b/third_party/webrtc
index 0bb59b4..f942a29 160000
--- a/third_party/webrtc
+++ b/third_party/webrtc
@@ -1 +1 @@
-Subproject commit 0bb59b4edd23d4e69de14b316312571146b6448d
+Subproject commit f942a2901aa45546ec525c0adf977071f312f6f3
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index bd2c8a0..2c0843a7 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -10913,7 +10913,8 @@
   <int value="4407" label="CSSAtRuleSwash"/>
   <int value="4408" label="CSSAtRuleOrnaments"/>
   <int value="4409" label="CSSAtRuleAnnotation"/>
-  <int value="4410" label="ServiceWorkerBypassFetchHandlerForMainResource"/>
+  <int value="4410"
+      label="OBSOLETE_ServiceWorkerBypassFetchHandlerForMainResource"/>
   <int value="4411" label="V8Document_HasPrivateToken_Method"/>
   <int value="4412" label="ServiceWorkerSkippedForEmptyFetchHandler"/>
   <int value="4413" label="ImageSet"/>
@@ -10967,7 +10968,7 @@
   <int value="4455" label="ParseFromStringIncludeShadows"/>
   <int value="4456" label="WebAppManifestScopeExtensions"/>
   <int value="4457"
-      label="ServiceWorkerBypassFetchHandlerForMainResourceByOriginTrial"/>
+      label="OBSOLETE_ServiceWorkerBypassFetchHandlerForMainResourceByOriginTrial"/>
   <int value="4458"
       label="OBSOLETE_V8RegExpUnicodeSetIncompatibilitiesWithUnicodeMode"/>
   <int value="4459" label="FedCmAutoReauthn"/>
@@ -10998,7 +10999,8 @@
   <int value="4482" label="RTCPeerConnectionLegacyGetStatsTrial"/>
   <int value="4483" label="ExecutedEmptyJavaScriptURLFromFrame"/>
   <int value="4484" label="ExecutedJavaScriptURLFromFrame"/>
-  <int value="4485" label="ServiceWorkerBypassFetchHandlerForSubResource"/>
+  <int value="4485"
+      label="OBSOLETE_ServiceWorkerBypassFetchHandlerForSubResource"/>
   <int value="4486" label="CSSAtRuleStartingStyle"/>
   <int value="4487" label="PrivateAggregationApiFledgeExtensions"/>
   <int value="4488" label="DeprecatedInterestGroupDailyUpdateUrl"/>
@@ -11063,7 +11065,7 @@
   <int value="4546" label="AttributionReportingCrossAppWeb"/>
   <int value="4547" label="SecurePaymentConfirmationActivationlessShow"/>
   <int value="4548"
-      label="ServiceWorkerBypassFetchHandlerForAllWithRaceNetworkRequest"/>
+      label="OBSOLETE_ServiceWorkerBypassFetchHandlerForAllWithRaceNetworkRequest"/>
   <int value="4549" label="FlexIntrinsicSizesCacheMiss"/>
   <int value="4550" label="CSSStyleContainerQuery"/>
   <int value="4551" label="CSSValueAppearanceMediaSlider"/>
@@ -11075,7 +11077,7 @@
   <int value="4557" label="CSSValueAppearanceSliderthumbHorizontal"/>
   <int value="4558" label="CSSValueAppearanceSliderthumbVertical"/>
   <int value="4559"
-      label="ServiceWorkerBypassFetchHandlerForAllWithRaceNetworkRequestByOriginTrial"/>
+      label="OBSOLETE_ServiceWorkerBypassFetchHandlerForAllWithRaceNetworkRequestByOriginTrial"/>
   <int value="4560"
       label="OBSOLETE_EventTimingPaintedPresentationPromiseResolvedWithEarlierPromiseUnresolved"/>
   <int value="4561" label="LinkRelPreloadAsFont"/>
diff --git a/tools/metrics/histograms/metadata/search/histograms.xml b/tools/metrics/histograms/metadata/search/histograms.xml
index 7e3ad0e..96682bd 100644
--- a/tools/metrics/histograms/metadata/search/histograms.xml
+++ b/tools/metrics/histograms/metadata/search/histograms.xml
@@ -1149,26 +1149,34 @@
 </histogram>
 
 <histogram name="Search.SearchEngineListedInPromoDialog"
-    enum="OmniboxSearchEngineType" expires_after="M81">
+    enum="OmniboxSearchEngineType" expires_after="M130">
 <!-- Name completed by histogram_suffixes name="SearchEnginePromoOrdering" and name="SearchEnginePromoDeviceType" -->
 
   <owner>yusufo@chromium.org</owner>
+  <owner>dgn@chromium.org</owner>
   <summary>
     The search engines listed in the options for search engine promo. This is an
     Android specific dialog prompting the user to pick a default search engine.
     The dialog was shown on a device that had Chrome before it was first
     introduced.
+
+    Warning: this histogram was expired from M81 to M124; data may be missing.
   </summary>
 </histogram>
 
 <histogram name="Search.SearchEngineSelectionInPromoDialog"
-    enum="OmniboxSearchEngineType" expires_after="M81">
+    enum="OmniboxSearchEngineType" expires_after="M130">
+<!-- Name completed by histogram_suffixes name="SearchEnginePromoDeviceType" -->
+
   <owner>yusufo@chromium.org</owner>
+  <owner>dgn@chromium.org</owner>
   <summary>
     The search engine selected by the user from the search engine promo. This is
     an Android specific dialog prompting the user to pick a default search
     engine. The dialog was shown on a device that had Chrome before it was first
     introduced.
+
+    Warning: this histogram was expired from M81 to M124; data may be missing.
   </summary>
 </histogram>
 
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index 8e9ba61d..69dc002d 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -383,7 +383,7 @@
  <item id="wallpaper_download_google_photo" added_in_milestone="102" content_hash_code="0565daa5" os_list="chromeos" file_path="ash/wallpaper/wallpaper_image_downloader.cc" />
  <item id="wallpaper_online_downloader" added_in_milestone="110" content_hash_code="00286fc5" os_list="chromeos" file_path="ash/wallpaper/wallpaper_image_downloader.cc" />
  <item id="chrome_support_tool_file_upload" added_in_milestone="113" content_hash_code="04a07122" os_list="chromeos" file_path="chrome/browser/policy/messaging_layer/upload/file_upload_impl.cc" />
- <item id="service_worker_race_network_request" added_in_milestone="113" content_hash_code="0090e590" os_list="linux,windows,android,chromeos" file_path="content/common/service_worker/race_network_request_url_loader_client.cc" />
+ <item id="service_worker_race_network_request" added_in_milestone="113" content_hash_code="01177377" os_list="linux,windows,android,chromeos" file_path="content/common/service_worker/race_network_request_url_loader_client.cc" />
  <item id="safe_browsing_ohttp_key_fetch" added_in_milestone="113" content_hash_code="0572fe6f" os_list="linux,windows,android,chromeos" file_path="components/safe_browsing/core/browser/hashprefix_realtime/ohttp_key_service.cc" />
  <item id="glanceables_tasks_integration" added_in_milestone="113" content_hash_code="033ddfed" os_list="chromeos" file_path="chrome/browser/ui/ash/glanceables/glanceables_keyed_service.cc" />
  <item id="bookmarks_image_fetcher" added_in_milestone="114" content_hash_code="01dd68ad" os_list="chromeos,linux,windows" file_path="chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc" />
diff --git a/ui/file_manager/file_manager/foreground/js/ui/command.ts b/ui/file_manager/file_manager/foreground/js/ui/command.ts
index 9b18124..343e7a5 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/command.ts
+++ b/ui/file_manager/file_manager/foreground/js/ui/command.ts
@@ -257,6 +257,12 @@
 
     for (const command of target.ownerDocument.querySelectorAll<Command>(
              'command')) {
+      if (!command.matchesEvent) {
+        // Because Command uses injected methods the <command> in the DOM might
+        // not have been initialized yet.
+        continue;
+      }
+
       if (!command.matchesEvent(e)) {
         continue;
       }
diff --git a/ui/file_manager/file_manager/foreground/js/ui/list_container.ts b/ui/file_manager/file_manager/foreground/js/ui/list_container.ts
index 51b9eab..50ec9db 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/list_container.ts
+++ b/ui/file_manager/file_manager/foreground/js/ui/list_container.ts
@@ -89,6 +89,20 @@
     this.table.list.id = 'file-list';
     this.grid.setAttribute('role', 'listbox');
     this.grid.id = 'file-list';
+
+    // Ensure the list and grid are marked ARIA single select for save as.
+    if (type === DialogType.SELECT_SAVEAS_FILE) {
+      const list = table.querySelector('#file-list');
+      list?.setAttribute('aria-multiselectable', 'false');
+      grid.setAttribute('aria-multiselectable', 'false');
+    }
+  }
+
+  /**
+   * Avoid adding event listeners in the constructor because the ListContainer
+   * isn't fully usable until setCurrentListType() is called.
+   */
+  private addEventListeners_() {
     this.element.addEventListener('keydown', this.onKeyDown_.bind(this));
     this.element.addEventListener('keypress', this.onKeyPress_.bind(this));
     this.element.addEventListener(
@@ -107,13 +121,6 @@
         setTimeout(() => this.allowContextMenuByTouch_ = false);
       }
     });
-
-    // Ensure the list and grid are marked ARIA single select for save as.
-    if (type === DialogType.SELECT_SAVEAS_FILE) {
-      const list = table.querySelector('#file-list');
-      list?.setAttribute('aria-multiselectable', 'false');
-      grid.setAttribute('aria-multiselectable', 'false');
-    }
   }
 
   get currentView(): FileTable|FileGrid {
@@ -160,6 +167,8 @@
     assert(this.dataModel);
     assert(this.selectionModel);
 
+    this.addEventListeners_();
+
     this.startBatchUpdates();
     this.currentListType = listType;
 
diff --git a/ui/webui/resources/cr_components/most_visited/most_visited.ts b/ui/webui/resources/cr_components/most_visited/most_visited.ts
index e3650445..bb502c4 100644
--- a/ui/webui/resources/cr_components/most_visited/most_visited.ts
+++ b/ui/webui/resources/cr_components/most_visited/most_visited.ts
@@ -250,7 +250,7 @@
   private mediaEventTracker_: EventTracker;
   private eventTracker_: EventTracker;
   private boundOnDocumentKeyDown_: (e: KeyboardEvent) => void;
-  private preloadingTimer_: undefined|ReturnType<typeof setTimeout>;
+  private prerenderTimer_: undefined|ReturnType<typeof setTimeout>;
   private preconnectTimer_: undefined|ReturnType<typeof setTimeout>;
 
   private get tileElements_() {
@@ -850,14 +850,18 @@
       return;
     }
 
-    if (loadTimeData.getBoolean('prerenderEnabled') &&
+    if (loadTimeData.getBoolean('prerenderOnHoverEnabled') &&
         loadTimeData.getInteger('prerenderStartTimeThreshold') >= 0) {
-      this.preloadingTimer_ = setTimeout(() => {
+      this.prerenderTimer_ = setTimeout(() => {
         this.pageHandler_.prerenderMostVisitedTile(e.model.item, true);
       }, loadTimeData.getInteger('prerenderStartTimeThreshold'));
     }
 
-    if (loadTimeData.getBoolean('prerenderEnabled') &&
+    // Preconnect is intended to be run on mouse hover when prerender is
+    // enabled, so it is allowed regardless of prerenderOnHoverEnabled or
+    // prerenderOnPressEnabled.
+    if ((loadTimeData.getBoolean('prerenderOnHoverEnabled') ||
+         loadTimeData.getBoolean('prerenderOnPressEnabled')) &&
         loadTimeData.getInteger('preconnectStartTimeThreshold') >= 0) {
       this.preconnectTimer_ = setTimeout(() => {
         this.pageHandler_.preconnectMostVisitedTile(e.model.item);
@@ -871,7 +875,7 @@
       return;
     }
 
-    if (loadTimeData.getBoolean('prerenderEnabled')) {
+    if (loadTimeData.getBoolean('prerenderOnPressEnabled')) {
       this.pageHandler_.prerenderMostVisitedTile(e.model.item, false);
     }
   }
@@ -882,11 +886,18 @@
       return;
     }
 
-    if (this.preloadingTimer_) {
-      clearTimeout(this.preloadingTimer_);
+    if (this.prerenderTimer_) {
+      clearTimeout(this.prerenderTimer_);
     }
 
-    this.pageHandler_.cancelPrerender();
+    if (this.preconnectTimer_) {
+      clearTimeout(this.preconnectTimer_);
+    }
+
+    if (loadTimeData.getBoolean('prerenderOnHoverEnabled') ||
+        loadTimeData.getBoolean('prerenderOnPressEnabled')) {
+      this.pageHandler_.cancelPrerender();
+    }
   }
 
   private onUndoClick_() {
diff --git a/v8 b/v8
index de7ce80..555084e 160000
--- a/v8
+++ b/v8
@@ -1 +1 @@
-Subproject commit de7ce8021831d4f3c4e49336623f25b2fc406fbc
+Subproject commit 555084e67f98736a41e52d13e485ab0febc3cbae