diff --git a/DEPS b/DEPS
index a7c1525..25f254d2 100644
--- a/DEPS
+++ b/DEPS
@@ -310,7 +310,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '964f26400b7aedf5926ceef6bece7c70c8d5b7d4',
+  'skia_revision': '860f12775838f6c80e25160a3b700323962507f3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -397,7 +397,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': 'f7ee7bf251df273feda918481ef9ca16c89c3e4c',
+  'devtools_frontend_revision': '677557c5395ebb258cfe8661bd3caf37430927ef',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -437,11 +437,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'fb6187bd3c69c696f907e18cfbd20ec44afd632d',
+  'dawn_revision': '408509f6297ac7cbaf8ecaacb3fffdeb100965de',
   # 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': 'f45df57a4b14efe5dbfd9064f09410c62e787300',
+  'quiche_revision': 'b1e7b2ca8a2f901a02a735e7bfaf64fb8ce0e3a6',
   # 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.
@@ -828,7 +828,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '9bf100a98392e75194382142036fdbe6e5555f83',
+    '4035f2035751cb9c46dc5be12f848b2479155435',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1270,7 +1270,7 @@
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
 
   'src/third_party/devtools-frontend-internal': {
-      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + 'a484f61316785ae7916142c8935d9223a4ecc377',
+      'url': Var('chrome_git') + '/devtools/devtools-internal.git' + '@' + '94f97d17b6b81f3f9aa8849cb40de605dd66d932',
     'condition': 'checkout_src_internal',
   },
 
@@ -1891,7 +1891,7 @@
 
   # Display server protocol for Linux.
   'src/third_party/wayland/src': {
-      'url': Var('chromium_git') + '/external/anongit.freedesktop.org/git/wayland/wayland.git' + '@' + '13c2f3dbfe4d7cc645a1984a8da357d1898665ba',
+      'url': Var('chromium_git') + '/external/anongit.freedesktop.org/git/wayland/wayland.git' + '@' + 'a8c7553ec9af6462474524fd2bb4e9a7dc7217dd',
       'condition': 'checkout_linux',
   },
 
@@ -1924,7 +1924,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'f3351ce131a724fe67449ae1b411eceff2d93159',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '612d0f9a06706b3896057e785601d0991c918494',
+    Var('webrtc_git') + '/src.git' + '@' + '4d752ec647ed3f43d0e43376ca3ce1ffee0fb9d8',
 
   # 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.
@@ -4211,7 +4211,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        'fbe701fcb62a6ea4b8f1800b5d105bd816bcddc1',
+        '2a3edac04c7ae1e48ac555a27ba95da500ad12ce',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 94e60c74..ac221e9 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -1478,12 +1478,6 @@
              "LacrosProfileMigrationForceOff",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
-// If enabled, use `MoveMigrator` instead of `CopyMigrator` to migrate data.
-// `MoveMigrator` moves data from ash to lacros instead of copying them.
-BASE_FEATURE(kLacrosMoveProfileMigration,
-             "LacrosMoveProfileMigration",
-             base::FEATURE_DISABLED_BY_DEFAULT);
-
 // If enabled, it is allowed to migrate data from lacros back to ash, provided
 // that other conditions are also met (e.g. the policy is enabled, or the
 // command line flag is passed).
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index c94b0a3..f56fd77 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -444,8 +444,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kLacrosProfileMigrationForceOff);
 COMPONENT_EXPORT(ASH_CONSTANTS)
-BASE_DECLARE_FEATURE(kLacrosMoveProfileMigration);
-COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kLacrosProfileBackwardMigration);
 COMPONENT_EXPORT(ASH_CONSTANTS)
 BASE_DECLARE_FEATURE(kLacrosSxSPrimaryRemove);
diff --git a/ash/shelf/scrollable_shelf_view_pixeltest.cc b/ash/shelf/scrollable_shelf_view_pixeltest.cc
index e264f44..5e1a59d 100644
--- a/ash/shelf/scrollable_shelf_view_pixeltest.cc
+++ b/ash/shelf/scrollable_shelf_view_pixeltest.cc
@@ -8,6 +8,8 @@
 #include "ash/shelf/test/shelf_test_base.h"
 #include "ash/test/pixel/ash_pixel_differ.h"
 #include "ash/test/pixel/ash_pixel_test_init_params.h"
+#include "base/test/scoped_feature_list.h"
+#include "chromeos/constants/chromeos_features.h"
 #include "ui/views/controls/menu/menu_item_view.h"
 #include "ui/views/controls/menu/submenu_view.h"
 
@@ -17,9 +19,13 @@
  public:
   // ScrollableShelfTestBase:
   void SetUp() override {
+    scoped_features_.InitAndEnableFeature(chromeos::features::kJelly);
     ShelfTestBase::SetUp();
     AddAppShortcutsUntilOverflow(/*use_alternative_color=*/true);
   }
+
+ private:
+  base::test::ScopedFeatureList scoped_features_;
 };
 
 class ScrollableShelfViewPixelRTLTest
@@ -41,7 +47,7 @@
 TEST_P(ScrollableShelfViewPixelRTLTest, Basics) {
   EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
       "overflow",
-      /*revision_number=*/2, GetPrimaryShelf()->GetWindow()));
+      /*revision_number=*/3, GetPrimaryShelf()->GetWindow()));
 
   ASSERT_TRUE(scrollable_shelf_view_->right_arrow());
   const gfx::Point right_arrow_center =
@@ -52,19 +58,19 @@
 
   EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
       "overflow_end",
-      /*revision_number=*/2, GetPrimaryShelf()->GetWindow()));
+      /*revision_number=*/3, GetPrimaryShelf()->GetWindow()));
 }
 
 TEST_P(ScrollableShelfViewPixelRTLTest, LeftRightShelfAlignment) {
   GetPrimaryShelf()->SetAlignment(ShelfAlignment::kLeft);
   EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
       "left_shelf_alignment",
-      /*revision_number=*/2, GetPrimaryShelf()->GetWindow()));
+      /*revision_number=*/3, GetPrimaryShelf()->GetWindow()));
 
   GetPrimaryShelf()->SetAlignment(ShelfAlignment::kRight);
   EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen(
       "right_shelf_alignment",
-      /*revision_number=*/2, GetPrimaryShelf()->GetWindow()));
+      /*revision_number=*/3, GetPrimaryShelf()->GetWindow()));
 }
 
 class ScrollableShelfViewWithGuestModePixelTest
diff --git a/ash/webui/camera_app_ui/resources/js/test/cca_type.ts b/ash/webui/camera_app_ui/resources/js/test/cca_type.ts
index defc450..080203df 100644
--- a/ash/webui/camera_app_ui/resources/js/test/cca_type.ts
+++ b/ash/webui/camera_app_ui/resources/js/test/cca_type.ts
@@ -47,6 +47,7 @@
   expertSaveMetadataOption: '#expert-save-metadata',
   expertShowMetadataOption: '#expert-show-metadata',
   feedbackButton: '#settings-feedback',
+  fps60Buttons: `.fps-60:not(.invisible)`,
   frontAspectRatioOptions:
       '#view-photo-aspect-ratio-settings .menu-item>input[data-facing="user"]',
   frontPhotoResolutionOptions:
diff --git a/ash/webui/camera_app_ui/resources/js/views/settings/video_resolution.ts b/ash/webui/camera_app_ui/resources/js/views/settings/video_resolution.ts
index 06e104f..37ce918 100644
--- a/ash/webui/camera_app_ui/resources/js/views/settings/video_resolution.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/settings/video_resolution.ts
@@ -102,20 +102,19 @@
     const constFpsOptions = option.fpsOptions.filter(
         (fpsOption) =>
             SUPPORTED_CONSTANT_FPS.some((fps) => fps === fpsOption.constFps));
-    const showFpsButton =
-        constFpsOptions.length > 1 && facing === Facing.EXTERNAL;
-    const isFPSEnabled =
-        expert.isEnabled(expert.ExpertOption.ENABLE_FPS_PICKER_FOR_BUILTIN);
     let resolution: Resolution|null = null;
     for (const fps of SUPPORTED_CONSTANT_FPS) {
       const fpsButton =
           dom.getFrom(optionElement, `.fps-${fps}`, HTMLButtonElement);
-      if (!isFPSEnabled) {
-        fpsButton.hidden = true;
-      } else if (!showFpsButton) {
+      if (constFpsOptions.length <= 1) {
         fpsButton.classList.add('invisible');
+        fpsButton.hidden = true;
+      } else if (facing === Facing.EXTERNAL) {
+        fpsButton.hidden = false;
+      } else {
+        fpsButton.hidden = !expert.isEnabled(
+            expert.ExpertOption.ENABLE_FPS_PICKER_FOR_BUILTIN);
       }
-
       const fpsOption =
           option.fpsOptions.find((fpsOption) => fpsOption.constFps === fps);
       const checked = fpsOption?.checked ?? false;
@@ -164,8 +163,6 @@
         event.preventDefault();
       });
     }
-
-    // TODO(b/215484798): Moves FPS toggle into video resolution settings.
     this.menu.appendChild(optionElement);
 
     if (input.checked && this.focusedDeviceId === deviceId) {
diff --git a/base/memory/raw_ptr_asan_bound_arg_tracker.cc b/base/memory/raw_ptr_asan_bound_arg_tracker.cc
index 670ac8c..a8cd5e2a 100644
--- a/base/memory/raw_ptr_asan_bound_arg_tracker.cc
+++ b/base/memory/raw_ptr_asan_bound_arg_tracker.cc
@@ -61,7 +61,7 @@
 
 void RawPtrAsanBoundArgTracker::Add(uintptr_t ptr) {
   if (ptr) {
-    protected_args_->push_back(ptr);
+    protected_args_.push_back(ptr);
   }
 }
 
diff --git a/base/memory/raw_ptr_asan_bound_arg_tracker.h b/base/memory/raw_ptr_asan_bound_arg_tracker.h
index 6841a6d..ab8d1cbe 100644
--- a/base/memory/raw_ptr_asan_bound_arg_tracker.h
+++ b/base/memory/raw_ptr_asan_bound_arg_tracker.h
@@ -14,8 +14,8 @@
 #include <vector>
 
 #include "base/base_export.h"
-#include "base/containers/stack_container.h"
 #include "base/memory/raw_ptr.h"
+#include "third_party/abseil-cpp/absl/container/inlined_vector.h"
 
 namespace base {
 namespace internal {
@@ -47,7 +47,7 @@
 class BASE_EXPORT RawPtrAsanBoundArgTracker {
  public:
   static constexpr size_t kInlineArgsCount = 3;
-  using ProtectedArgsVector = base::StackVector<uintptr_t, kInlineArgsCount>;
+  using ProtectedArgsVector = absl::InlinedVector<uintptr_t, kInlineArgsCount>;
 
   // Check whether ptr is an address inside an allocation pointed to by one of
   // the currently protected callback arguments. If it is, then this function
diff --git a/base/task/sequence_manager/task_queue_impl.cc b/base/task/sequence_manager/task_queue_impl.cc
index d882f8c..3ea4604d 100644
--- a/base/task/sequence_manager/task_queue_impl.cc
+++ b/base/task/sequence_manager/task_queue_impl.cc
@@ -11,7 +11,6 @@
 
 #include "base/check.h"
 #include "base/compiler_specific.h"
-#include "base/containers/stack_container.h"
 #include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/memory/scoped_refptr.h"
@@ -36,6 +35,7 @@
 #include "base/trace_event/base_tracing.h"
 #include "base/types/pass_key.h"
 #include "build/build_config.h"
+#include "third_party/abseil-cpp/absl/container/inlined_vector.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace base {
@@ -663,7 +663,7 @@
   // Because task destructors could have a side-effect of posting new tasks, we
   // move all the cancelled tasks into a temporary container before deleting
   // them. This is to avoid the queue from changing while iterating over it.
-  StackVector<Task, 8> tasks_to_delete;
+  absl::InlinedVector<Task, 8> tasks_to_delete;
 
   while (!main_thread_only().delayed_incoming_queue.empty()) {
     const Task& task = main_thread_only().delayed_incoming_queue.top();
@@ -671,11 +671,11 @@
     if (!task.task.IsCancelled())
       break;
 
-    tasks_to_delete->push_back(
+    tasks_to_delete.push_back(
         main_thread_only().delayed_incoming_queue.take_top());
   }
 
-  if (!tasks_to_delete->empty()) {
+  if (!tasks_to_delete.empty()) {
     UpdateWakeUp(lazy_now);
     return true;
   }
@@ -694,7 +694,7 @@
   // Because task destructors could have a side-effect of posting new tasks, we
   // move all the cancelled tasks into a temporary container before deleting
   // them. This is to avoid the queue from changing while iterating over it.
-  StackVector<Task, 8> tasks_to_delete;
+  absl::InlinedVector<Task, 8> tasks_to_delete;
 
   while (!main_thread_only().delayed_incoming_queue.empty()) {
     const Task& task = main_thread_only().delayed_incoming_queue.top();
@@ -707,7 +707,7 @@
 
     Task ready_task = main_thread_only().delayed_incoming_queue.take_top();
     if (is_cancelled) {
-      tasks_to_delete->push_back(std::move(ready_task));
+      tasks_to_delete.push_back(std::move(ready_task));
       continue;
     }
 
@@ -726,7 +726,7 @@
   }
 
   // Explicitly delete tasks last.
-  tasks_to_delete->clear();
+  tasks_to_delete.clear();
 
   UpdateWakeUp(lazy_now);
 }
diff --git a/base/task/sequence_manager/work_queue.cc b/base/task/sequence_manager/work_queue.cc
index 53d5aa2..11e44bb 100644
--- a/base/task/sequence_manager/work_queue.cc
+++ b/base/task/sequence_manager/work_queue.cc
@@ -4,13 +4,13 @@
 
 #include "base/task/sequence_manager/work_queue.h"
 
-#include "base/containers/stack_container.h"
 #include "base/debug/alias.h"
 #include "base/task/sequence_manager/fence.h"
 #include "base/task/sequence_manager/sequence_manager_impl.h"
 #include "base/task/sequence_manager/task_order.h"
 #include "base/task/sequence_manager/work_queue_sets.h"
 #include "build/build_config.h"
+#include "third_party/abseil-cpp/absl/container/inlined_vector.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace base {
@@ -227,16 +227,16 @@
   // Since task destructors could have a side-effect of deleting this task queue
   // we move cancelled tasks into a temporary container which can be emptied
   // without accessing |this|.
-  StackVector<Task, 8> tasks_to_delete;
+  absl::InlinedVector<Task, 8> tasks_to_delete;
 
   while (!tasks_.empty()) {
     const auto& pending_task = tasks_.front();
     if (pending_task.task && !pending_task.IsCanceled())
       break;
-    tasks_to_delete->push_back(std::move(tasks_.front()));
+    tasks_to_delete.push_back(std::move(tasks_.front()));
     tasks_.pop_front();
   }
-  if (!tasks_to_delete->empty()) {
+  if (!tasks_to_delete.empty()) {
     if (tasks_.empty()) {
       // NB delayed tasks are inserted via Push, no don't need to reload those.
       if (queue_type_ == QueueType::kImmediate) {
@@ -254,7 +254,7 @@
       work_queue_sets_->OnQueuesFrontTaskChanged(this);
     task_queue_->TraceQueueSize();
   }
-  return !tasks_to_delete->empty();
+  return !tasks_to_delete.empty();
 }
 
 void WorkQueue::AssignToWorkQueueSets(WorkQueueSets* work_queue_sets) {
diff --git a/chrome/VERSION b/chrome/VERSION
index 51ce61ee8..53254aff 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=117
 MINOR=0
-BUILD=5907
+BUILD=5908
 PATCH=0
diff --git a/chrome/android/profiles/arm.newest.txt b/chrome/android/profiles/arm.newest.txt
index 53b22872..1ac604e 100644
--- a/chrome/android/profiles/arm.newest.txt
+++ b/chrome/android/profiles/arm.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-117.0.5904.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-arm-117.0.5906.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 613ffab..9b0dae4 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-117.0.5904.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-117.0.5906.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index d2f7d58..458de0d 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -4266,10 +4266,6 @@
     {"uxstudy1", flag_descriptions::kUXStudy1Name,
      flag_descriptions::kUXStudy1Description, kOsCrOS,
      MULTI_VALUE_TYPE(kUXStudy1Choices)},
-    {"lacros-move-profile-migration",
-     flag_descriptions::kLacrosMoveProfileMigrationName,
-     flag_descriptions::kLacrosMoveProfileMigrationDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(ash::features::kLacrosMoveProfileMigration)},
     {"lacros-profile-migration-force-off",
      flag_descriptions::kLacrosProfileMigrationForceOffName,
      flag_descriptions::kLacrosProfileMigrationForceOffDescription, kOsCrOS,
diff --git a/chrome/browser/apps/app_service/app_icon/app_icon_loader.h b/chrome/browser/apps/app_service/app_icon/app_icon_loader.h
index f4bb7ba..c41fea0 100644
--- a/chrome/browser/apps/app_service/app_icon/app_icon_loader.h
+++ b/chrome/browser/apps/app_service/app_icon/app_icon_loader.h
@@ -216,7 +216,7 @@
 
   void MaybeLoadFallbackOrCompleteEmpty();
 
-  // ProfileManagerObserver overrides.
+  // ProfileObserver overrides.
   void OnProfileWillBeDestroyed(Profile* profile) override;
 
   // If non-null, points to the profile necessary to support the icon loading.
diff --git a/chrome/browser/ash/app_list/search/local_image_search/annotation_storage.cc b/chrome/browser/ash/app_list/search/local_image_search/annotation_storage.cc
index 9c56237..cfa71c2 100644
--- a/chrome/browser/ash/app_list/search/local_image_search/annotation_storage.cc
+++ b/chrome/browser/ash/app_list/search/local_image_search/annotation_storage.cc
@@ -34,6 +34,9 @@
 // The table cannot exist when calling this function.
 int CreateNewSchema(SqlDatabase* db) {
   DVLOG(1) << "Making a table";
+  if (!db) {
+    return 0;
+  }
 
   static constexpr char kQuery[] =
       // clang-format off
@@ -43,24 +46,27 @@
           "last_modified_time INTEGER NOT NULL,"
           "is_ignored INTEGER NOT NULL)";
   // clang-format on
-  sql::Statement statement = db->GetStatementForQuery(SQL_FROM_HERE, kQuery);
-  if (!statement.Run()) {
+  std::unique_ptr<sql::Statement> statement =
+      db->GetStatementForQuery(SQL_FROM_HERE, kQuery);
+  if (!statement || !statement->Run()) {
     return 0;
   }
 
   static constexpr char kQuery1[] =
       "CREATE INDEX ind_annotations_label ON annotations(label)";
 
-  sql::Statement statement1 = db->GetStatementForQuery(SQL_FROM_HERE, kQuery1);
-  if (!statement1.Run()) {
+  std::unique_ptr<sql::Statement> statement1 =
+      db->GetStatementForQuery(SQL_FROM_HERE, kQuery1);
+  if (!statement1 || !statement1->Run()) {
     return 0;
   }
 
   static constexpr char kQuery2[] =
       "CREATE INDEX ind_annotations_image_path ON annotations(image_path)";
 
-  sql::Statement statement2 = db->GetStatementForQuery(SQL_FROM_HERE, kQuery2);
-  if (!statement2.Run()) {
+  std::unique_ptr<sql::Statement> statement2 =
+      db->GetStatementForQuery(SQL_FROM_HERE, kQuery2);
+  if (!statement2 || !statement2->Run()) {
     return 0;
   }
 
@@ -68,13 +74,18 @@
 }
 
 int MigrateSchema(SqlDatabase* db, int current_version_number) {
+  if (!db) {
+    return 0;
+  }
+
   if (current_version_number == kVersionNumber) {
     return current_version_number;
   }
 
   static constexpr char kQuery[] = "DROP TABLE IF EXISTS annotations";
-  sql::Statement statement = db->GetStatementForQuery(SQL_FROM_HERE, kQuery);
-  if (!statement.Run()) {
+  std::unique_ptr<sql::Statement> statement =
+      db->GetStatementForQuery(SQL_FROM_HERE, kQuery);
+  if (!statement || !statement->Run()) {
     return 0;
   }
 
@@ -154,15 +165,18 @@
   // clang-format on
 
   for (const auto& annotation : image_info.annotations) {
-    sql::Statement statement =
+    std::unique_ptr<sql::Statement> statement =
         sql_database_->GetStatementForQuery(SQL_FROM_HERE, kQuery);
+    if (!statement) {
+      return;
+    }
     DVLOG(1) << annotation;
-    statement.BindString(0, annotation);
-    statement.BindString(1, image_info.path.value());
-    statement.BindTime(2, image_info.last_modified);
-    statement.BindInt(3, image_info.is_ignored);
+    statement->BindString(0, annotation);
+    statement->BindString(1, image_info.path.value());
+    statement->BindTime(2, image_info.last_modified);
+    statement->BindInt(3, image_info.is_ignored);
 
-    if (!statement.Run()) {
+    if (!statement->Run()) {
       // TODO(b/260646344): log to UMA instead.
       return;
     }
@@ -176,11 +190,15 @@
 
   static constexpr char kQuery[] = "DELETE FROM annotations WHERE image_path=?";
 
-  sql::Statement statement =
+  std::unique_ptr<sql::Statement> statement =
       sql_database_->GetStatementForQuery(SQL_FROM_HERE, kQuery);
-  statement.BindString(0, image_path.value());
+  if (!statement) {
+    return;
+  }
 
-  statement.Run();
+  statement->BindString(0, image_path.value());
+
+  statement->Run();
 }
 
 std::vector<ImageInfo> AnnotationStorage::GetAllAnnotations() {
@@ -194,17 +212,20 @@
           "ORDER BY label";
   // clang-format on
 
-  sql::Statement statement =
+  std::unique_ptr<sql::Statement> statement =
       sql_database_->GetStatementForQuery(SQL_FROM_HERE, kQuery);
+  if (!statement) {
+    return {};
+  }
 
   std::vector<ImageInfo> matched_paths;
-  while (statement.Step()) {
-    const base::FilePath path = base::FilePath(statement.ColumnString(1));
-    const base::Time time = statement.ColumnTime(2);
-    const bool is_ignored = statement.ColumnBool(3);
-    DVLOG(1) << "Select find: " << statement.ColumnString(0) << ", " << path
+  while (statement->Step()) {
+    const base::FilePath path = base::FilePath(statement->ColumnString(1));
+    const base::Time time = statement->ColumnTime(2);
+    const bool is_ignored = statement->ColumnBool(3);
+    DVLOG(1) << "Select find: " << statement->ColumnString(0) << ", " << path
              << ", " << time;
-    matched_paths.push_back({{statement.ColumnString(0)},
+    matched_paths.push_back({{statement->ColumnString(0)},
                              std::move(path),
                              std::move(time),
                              is_ignored});
@@ -227,18 +248,21 @@
           "ORDER BY label";
   // clang-format on
 
-  sql::Statement statement =
+  std::unique_ptr<sql::Statement> statement =
       sql_database_->GetStatementForQuery(SQL_FROM_HERE, kQuery);
-  statement.BindString(0, image_path.value());
+  if (!statement) {
+    return {};
+  }
+  statement->BindString(0, image_path.value());
 
   std::vector<ImageInfo> matched_paths;
-  while (statement.Step()) {
-    const base::FilePath path = base::FilePath(statement.ColumnString(1));
-    const base::Time time = statement.ColumnTime(2);
-    const bool is_ignored = statement.ColumnBool(3);
-    DVLOG(1) << "Select find: " << statement.ColumnString(0) << ", " << path
+  while (statement->Step()) {
+    const base::FilePath path = base::FilePath(statement->ColumnString(1));
+    const base::Time time = statement->ColumnTime(2);
+    const bool is_ignored = statement->ColumnBool(3);
+    DVLOG(1) << "Select find: " << statement->ColumnString(0) << ", " << path
              << ", " << time;
-    matched_paths.push_back({{statement.ColumnString(0)},
+    matched_paths.push_back({{statement->ColumnString(0)},
                              std::move(path),
                              std::move(time),
                              is_ignored});
@@ -263,25 +287,28 @@
           "ORDER BY image_path";
   // clang-format on
 
-  sql::Statement statement =
+  std::unique_ptr<sql::Statement> statement =
       sql_database_->GetStatementForQuery(SQL_FROM_HERE, kQuery);
-  statement.BindString(0, base::StrCat({"%", base::UTF16ToUTF8(query), "%"}));
+  if (!statement) {
+    return {};
+  }
+  statement->BindString(0, base::StrCat({"%", base::UTF16ToUTF8(query), "%"}));
 
   std::vector<FileSearchResult> matched_paths;
   TokenizedString tokenized_query(query);
   ash::string_matching::FuzzyTokenizedStringMatch fuzzy_match;
-  while (statement.Step()) {
+  while (statement->Step()) {
     double relevance = fuzzy_match.Relevance(
         tokenized_query,
-        TokenizedString(base::UTF8ToUTF16(statement.ColumnString(0))),
+        TokenizedString(base::UTF8ToUTF16(statement->ColumnString(0))),
         /*use_weighted_ratio=*/true);
     if (relevance < kRelevanceThreshold) {
       continue;
     }
 
-    const base::FilePath path = base::FilePath(statement.ColumnString(1));
-    const base::Time time = statement.ColumnTime(2);
-    DVLOG(1) << "Select: " << statement.ColumnString(0) << ", " << path << ", "
+    const base::FilePath path = base::FilePath(statement->ColumnString(1));
+    const base::Time time = statement->ColumnTime(2);
+    DVLOG(1) << "Select: " << statement->ColumnString(0) << ", " << path << ", "
              << time << " rl: " << relevance;
 
     if (matched_paths.empty() || matched_paths.back().file_path != path) {
diff --git a/chrome/browser/ash/app_list/search/local_image_search/annotation_storage_unittest.cc b/chrome/browser/ash/app_list/search/local_image_search/annotation_storage_unittest.cc
index e122a46..1b4e5622 100644
--- a/chrome/browser/ash/app_list/search/local_image_search/annotation_storage_unittest.cc
+++ b/chrome/browser/ash/app_list/search/local_image_search/annotation_storage_unittest.cc
@@ -26,7 +26,7 @@
             "CREATE TABLE test("
               "key TEXT NOT NULL)";
   // clang-format on
-  db->GetStatementForQuery(SQL_FROM_HERE, kQuery).Run();
+  db->GetStatementForQuery(SQL_FROM_HERE, kQuery)->Run();
   return 2;
 }
 
diff --git a/chrome/browser/ash/app_list/search/local_image_search/sql_database.cc b/chrome/browser/ash/app_list/search/local_image_search/sql_database.cc
index 758dbd1..cedf160 100644
--- a/chrome/browser/ash/app_list/search/local_image_search/sql_database.cc
+++ b/chrome/browser/ash/app_list/search/local_image_search/sql_database.cc
@@ -6,9 +6,7 @@
 
 #include "base/files/file_util.h"
 #include "base/logging.h"
-#include "sql/database.h"
 #include "sql/error_delegate_util.h"
-#include "sql/meta_table.h"
 #include "sql/statement.h"
 
 namespace app_list {
@@ -29,6 +27,8 @@
       migrate_table_schema_(std::move(migrate_table_schema)),
       path_to_db_(path_to_db),
       histogram_tag_(histogram_tag),
+      db_(sql::Database(sql::DatabaseOptions())),
+      meta_table_(sql::MetaTable()),
       current_version_number_(current_version_number) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
   DCHECK_GT(current_version_number_, 1);
@@ -39,7 +39,7 @@
 
 bool SqlDatabase::Initialize() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(db_ == nullptr);
+  DCHECK(!db_.is_open());
 
   const base::FilePath dir = path_to_db_.DirName();
   if (!base::PathExists(dir) && !base::CreateDirectory(dir)) {
@@ -47,66 +47,64 @@
     return false;
   }
 
-  db_ = std::make_unique<sql::Database>(sql::DatabaseOptions());
-  db_->set_histogram_tag(histogram_tag_);
-  meta_table_ = std::make_unique<sql::MetaTable>();
+  db_.set_histogram_tag(histogram_tag_);
 
-  // base::Unretained is safe because `this` owns (and therefore outlives) the
-  // sql::Database held by `db_`. That is, `db_` calls the error callback and
-  // if `this` destroyed then `db_` is destroyed, as well.
-  db_->set_error_callback(base::BindRepeating(&SqlDatabase::OnErrorCallback,
-                                              base::Unretained(this)));
-
-  if (!db_->Open(path_to_db_)) {
+  if (!db_.Open(path_to_db_)) {
     LOG(ERROR) << "Unable to open " << histogram_tag_ << " DB.";
-    // TODO(b/260646344): make a callback RecordOpenDBProblem();
-    return RazeDb();
-  }
-
-  // Either initializes a new meta table or loads it from the db if exists.
-  if (!meta_table_->Init(db_.get(), kUninitializedDbVersionNumber,
-                         kUninitializedDbVersionNumber)) {
+    RazeDb();
     return false;
   }
 
-  if (meta_table_->GetVersionNumber() == kUninitializedDbVersionNumber) {
-    const int new_version_number = create_table_schema_.Run(this);
-    DCHECK_GT(new_version_number, 1);
-    // TODO(crbug.com/1414092): Set the version numbers atomically with the
-    // schema within a transaction and check the return values instead of
-    // ignoring them.
-    std::ignore = meta_table_->SetVersionNumber(new_version_number);
-    std::ignore = meta_table_->SetCompatibleVersionNumber(new_version_number);
+  // Either initializes a new meta table or loads it from the db if exists.
+  if (!meta_table_.Init(&db_, kUninitializedDbVersionNumber,
+                        kUninitializedDbVersionNumber)) {
+    RazeDb();
+    return false;
+  }
+
+  if (meta_table_.GetVersionNumber() == current_version_number_) {
     return true;
   }
 
-  if (meta_table_->GetVersionNumber() == current_version_number_) {
+  if (meta_table_.GetVersionNumber() == kUninitializedDbVersionNumber) {
+    const int new_version_number = create_table_schema_.Run(this);
+    DCHECK_GT(new_version_number, 1);
+
+    if (!meta_table_.SetVersionNumber(new_version_number) ||
+        !meta_table_.SetCompatibleVersionNumber(new_version_number)) {
+      RazeDb();
+      return false;
+    }
     return true;
   }
 
   if (!MigrateDatabaseSchema()) {
     LOG(ERROR) << "Unable to migrate the schema for " << histogram_tag_;
-    // TODO(b/260646344): make a callback RecordDBMigrationProblem();
+    RazeDb();
     return false;
   }
-
+  // base::Unretained is safe because `this` owns (and therefore outlives) the
+  // sql::Database held by `db_`. That is, `db_` calls the error callback and
+  // if `this` destroyed then `db_` is destroyed, as well.
+  db_.set_error_callback(base::BindRepeating(&SqlDatabase::OnErrorCallback,
+                                             base::Unretained(this)));
   return true;
 }
 
 bool SqlDatabase::MigrateDatabaseSchema() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // May happen if the code migrated from dev to stable channel.
-  if (meta_table_->GetVersionNumber() > current_version_number_) {
-    LOG(ERROR) << histogram_tag_ << " database is too new. Razing.";
-    return RazeDb() && Initialize();
+  if (meta_table_.GetVersionNumber() > current_version_number_) {
+    LOG(ERROR) << histogram_tag_ << " database is too new. Deleting db.";
+    Close();
+    return sql::Database::Delete(path_to_db_) && Initialize();
   }
 
-  const int new_version_number =
-      migrate_table_schema_.Run(this, meta_table_->GetVersionNumber());
-  DCHECK_GT(new_version_number, 1);
-  if (new_version_number < meta_table_->GetVersionNumber()) {
-    LOG(ERROR) << "Failed to migrate the schema. Razing.";
-    return RazeDb() && Initialize();
+  if (migrate_table_schema_.Run(this, meta_table_.GetVersionNumber()) <
+      meta_table_.GetVersionNumber()) {
+    LOG(ERROR) << "Failed to migrate the schema. Deleting db.";
+    RazeDb();
+    return false;
   }
 
   return true;
@@ -114,42 +112,47 @@
 
 void SqlDatabase::Close() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  meta_table_->Reset();
-  db_.reset();
-  meta_table_.reset();
+  db_.reset_error_callback();
+  meta_table_.Reset();
+  db_.Close();
 }
 
 void SqlDatabase::OnErrorCallback(int error, sql::Statement* stmt) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  LOG(ERROR) << sql::ToSqliteResultCode(error);
+  LOG(ERROR) << "Error Code: " << sql::ToSqliteResultCode(error);
+  if (stmt) {
+    LOG(ERROR) << "Statement: " << stmt->GetSQLStatement();
+  }
   if (sql::IsErrorCatastrophic(error)) {
     LOG(ERROR) << "The error is catastrophic. Razing db.";
     RazeDb();
   }
 }
 
-sql::Statement SqlDatabase::GetStatementForQuery(
+std::unique_ptr<sql::Statement> SqlDatabase::GetStatementForQuery(
     const sql::StatementID& sql_from_here,
     const char* query) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!db_.is_open()) {
+    return nullptr;
+  }
+
   DVLOG(1) << "Making statement for query: " << query;
-  DCHECK(db_->IsSQLValid(query));
-  return sql::Statement(db_->GetCachedStatement(sql_from_here, query));
+  DCHECK(db_.IsSQLValid(query));
+  return std::make_unique<sql::Statement>(
+      db_.GetCachedStatement(sql_from_here, query));
 }
 
 bool SqlDatabase::RazeDb() {
   DVLOG(1) << "Razing db.";
-  if (db_ && db_->is_open()) {
+  meta_table_.Reset();
+  if (db_.is_open()) {
+    db_.Poison();
     // Sometimes it fails to do it due to locks or open handles.
-    if (!db_->Raze() && !sql::Database::Delete(path_to_db_)) {
+    if (!sql::Database::Delete(path_to_db_)) {
       return false;
     }
-    db_.reset();
-  }
-  if (meta_table_) {
-    meta_table_->Reset();
-    meta_table_.reset();
   }
   return true;
 }
diff --git a/chrome/browser/ash/app_list/search/local_image_search/sql_database.h b/chrome/browser/ash/app_list/search/local_image_search/sql_database.h
index 7bc493b..848ee29 100644
--- a/chrome/browser/ash/app_list/search/local_image_search/sql_database.h
+++ b/chrome/browser/ash/app_list/search/local_image_search/sql_database.h
@@ -11,12 +11,12 @@
 #include "base/files/file_path.h"
 #include "base/functional/callback.h"
 #include "base/sequence_checker.h"
+#include "sql/database.h"
+#include "sql/meta_table.h"
 
 namespace sql {
-class Database;
 class Statement;
 class StatementID;
-class MetaTable;
 }  // namespace sql
 
 namespace app_list {
@@ -37,16 +37,17 @@
   SqlDatabase(const SqlDatabase&) = delete;
   SqlDatabase& operator=(const SqlDatabase&) = delete;
 
-  // Opens and initializes the database.
-  bool Initialize();
+  // Opens or initializes the database.
+  [[nodiscard]] bool Initialize();
 
   // Must be called in the same sequence with `Initialize()`.
   void Close();
 
-  // Allows us to interact with the database. Returns a statement that can Bind*
-  // and Run().
-  sql::Statement GetStatementForQuery(const sql::StatementID& sql_from_here,
-                                      const char* query);
+  // Allows us to interact with the database. If the database is open, returns
+  // a statement that can Bind* and Run(), otherwise nullptr.
+  std::unique_ptr<sql::Statement> GetStatementForQuery(
+      const sql::StatementID& sql_from_here,
+      const char* query);
 
  private:
   void OnErrorCallback(int error, sql::Statement* stmt);
@@ -70,8 +71,8 @@
   // The identifying prefix for metrics.
   const std::string histogram_tag_;
 
-  std::unique_ptr<sql::Database> db_;
-  std::unique_ptr<sql::MetaTable> meta_table_;
+  sql::Database db_;
+  sql::MetaTable meta_table_;
 
   // The current schema version number of the database. It must be greater than
   // 1. Due to the implementation constraint of `sql::MetaTable` the version
diff --git a/chrome/browser/ash/app_list/search/local_image_search/sql_database_unittest.cc b/chrome/browser/ash/app_list/search/local_image_search/sql_database_unittest.cc
index fee57c9e..06359137 100644
--- a/chrome/browser/ash/app_list/search/local_image_search/sql_database_unittest.cc
+++ b/chrome/browser/ash/app_list/search/local_image_search/sql_database_unittest.cc
@@ -36,7 +36,7 @@
               "key TEXT NOT NULL,"
               "value TEXT NOT NULL)";
   // clang-format on
-  db->GetStatementForQuery(SQL_FROM_HERE, query).Run();
+  db->GetStatementForQuery(SQL_FROM_HERE, query)->Run();
   // Returns current version number
   return 3;
 }
@@ -47,7 +47,7 @@
             "CREATE TABLE test("
               "key TEXT NOT NULL)";
   // clang-format on
-  db->GetStatementForQuery(SQL_FROM_HERE, query).Run();
+  db->GetStatementForQuery(SQL_FROM_HERE, query)->Run();
   return 2;
 }
 
@@ -58,7 +58,7 @@
             "ALTER TABLE test "
               "ADD value TEXT";
   // clang-format on
-  db->GetStatementForQuery(SQL_FROM_HERE, query).Run();
+  db->GetStatementForQuery(SQL_FROM_HERE, query)->Run();
   return 3;
 }
 
@@ -91,74 +91,84 @@
 };
 
 TEST_F(SqlDatabaseTest, EmptyStorage) {
-  sql_database_->Initialize();
+  EXPECT_TRUE(sql_database_->Initialize());
 
   auto statement =
       sql_database_->GetStatementForQuery(SQL_FROM_HERE, SELECT_ALL_QUERY);
+  ASSERT_TRUE(statement);
 
-  while (statement.Step()) {
+  while (statement->Step()) {
     steps_ += 1;
   }
   EXPECT_EQ(steps_, 0);
-  EXPECT_TRUE(statement.Succeeded());
+  EXPECT_TRUE(statement->Succeeded());
 }
 
 TEST_F(SqlDatabaseTest, Insert) {
-  sql_database_->Initialize();
+  EXPECT_TRUE(sql_database_->Initialize());
 
   auto insert_statement =
       sql_database_->GetStatementForQuery(SQL_FROM_HERE, INSERT_QUERY);
-  insert_statement.BindString(0, "test");
-  insert_statement.BindString(1, "123");
-  EXPECT_TRUE(insert_statement.Run());
+  ASSERT_TRUE(insert_statement);
+
+  insert_statement->BindString(0, "test");
+  insert_statement->BindString(1, "123");
+  EXPECT_TRUE(insert_statement->Run());
 
   auto select_statement =
       sql_database_->GetStatementForQuery(SQL_FROM_HERE, SELECT_ALL_QUERY);
-  while (select_statement.Step()) {
-    EXPECT_EQ(select_statement.ColumnString(0), "test");
-    EXPECT_EQ(select_statement.ColumnString(1), "123");
+  ASSERT_TRUE(select_statement);
+
+  while (select_statement->Step()) {
+    EXPECT_EQ(select_statement->ColumnString(0), "test");
+    EXPECT_EQ(select_statement->ColumnString(1), "123");
     steps_ += 1;
   }
   // To make sure, it goes inside the loop.
   EXPECT_EQ(steps_, 1);
-  EXPECT_TRUE(select_statement.Succeeded());
+  EXPECT_TRUE(select_statement->Succeeded());
 }
 
 TEST_F(SqlDatabaseTest, Persistence) {
-  sql_database_->Initialize();
+  EXPECT_TRUE(sql_database_->Initialize());
 
   auto insert_statement =
       sql_database_->GetStatementForQuery(SQL_FROM_HERE, INSERT_QUERY);
-  insert_statement.BindString(0, "test");
-  insert_statement.BindString(1, "123");
-  EXPECT_TRUE(insert_statement.Run());
+  ASSERT_TRUE(insert_statement);
 
-  insert_statement.Clear();
+  insert_statement->BindString(0, "test");
+  insert_statement->BindString(1, "123");
+  EXPECT_TRUE(insert_statement->Run());
+
+  insert_statement->Clear();
   sql_database_->Close();
-  sql_database_->Initialize();
+  EXPECT_TRUE(sql_database_->Initialize());
 
   auto select_statement =
       sql_database_->GetStatementForQuery(SQL_FROM_HERE, SELECT_ALL_QUERY);
+  ASSERT_TRUE(select_statement);
 
-  while (select_statement.Step()) {
-    EXPECT_EQ(select_statement.ColumnString(0), "test");
-    EXPECT_EQ(select_statement.ColumnString(1), "123");
+  while (select_statement->Step()) {
+    EXPECT_EQ(select_statement->ColumnString(0), "test");
+    EXPECT_EQ(select_statement->ColumnString(1), "123");
     steps_ += 1;
   }
   EXPECT_EQ(steps_, 1);
-  EXPECT_TRUE(select_statement.Succeeded());
+  EXPECT_TRUE(select_statement->Succeeded());
 }
 
 TEST_F(SqlDatabaseTest, Downgrade) {
-  sql_database_->Initialize();
+  EXPECT_TRUE(sql_database_->Initialize());
 
   auto insert_statement =
       sql_database_->GetStatementForQuery(SQL_FROM_HERE, INSERT_QUERY);
-  insert_statement.BindString(0, "test");
-  insert_statement.BindString(1, "123");
-  EXPECT_TRUE(insert_statement.Run());
+  ASSERT_TRUE(insert_statement);
 
-  insert_statement.Clear();
+  insert_statement->BindString(0, "test");
+  insert_statement->BindString(1, "123");
+  EXPECT_TRUE(insert_statement->Run());
+
+  insert_statement->Clear();
   sql_database_->Close();
 
   sql_database_ = std::make_unique<SqlDatabase>(
@@ -167,30 +177,36 @@
       base::BindRepeating(MigrateOldTestSchema));
 
   // Should raze the current db and make an older version.
-  sql_database_->Initialize();
+  EXPECT_TRUE(sql_database_->Initialize());
 
   auto select_statement = sql_database_->GetStatementForQuery(
       SQL_FROM_HERE, "SELECT key FROM test");
-  while (select_statement.Step()) {
-    EXPECT_EQ(select_statement.ColumnString(0), "test");
+  ASSERT_TRUE(select_statement);
+
+  while (select_statement->Step()) {
+    EXPECT_EQ(select_statement->ColumnString(0), "test");
     steps_ += 0;
   }
   EXPECT_EQ(steps_, 0);
-  EXPECT_TRUE(select_statement.Succeeded());
+  EXPECT_TRUE(select_statement->Succeeded());
 
   auto insert_statement1 = sql_database_->GetStatementForQuery(
       SQL_FROM_HERE, "INSERT INTO test(key) VALUES(?)");
-  insert_statement1.BindString(0, "test");
-  EXPECT_TRUE(insert_statement1.Run());
+  ASSERT_TRUE(insert_statement1);
+
+  insert_statement1->BindString(0, "test");
+  EXPECT_TRUE(insert_statement1->Run());
 
   auto select_statement1 = sql_database_->GetStatementForQuery(
       SQL_FROM_HERE, "SELECT key FROM test");
-  while (select_statement1.Step()) {
-    EXPECT_EQ(select_statement1.ColumnString(0), "test");
+  ASSERT_TRUE(select_statement1);
+
+  while (select_statement1->Step()) {
+    EXPECT_EQ(select_statement1->ColumnString(0), "test");
     steps_ += 1;
   }
   EXPECT_EQ(steps_, 1);
-  EXPECT_TRUE(select_statement1.Succeeded());
+  EXPECT_TRUE(select_statement1->Succeeded());
 }
 
 TEST_F(SqlDatabaseTest, Upgrade) {
@@ -198,40 +214,57 @@
       test_directory_.AppendASCII("test.db"), /*histogram_tag=*/"test",
       /*current_version_number=*/2, base::BindRepeating(CreateOldTestSchema),
       base::BindRepeating(MigrateOldTestSchema));
-  sql_database_->Initialize();
+  EXPECT_TRUE(sql_database_->Initialize());
 
   auto insert_statement = sql_database_->GetStatementForQuery(
       SQL_FROM_HERE, "INSERT INTO test(key) VALUES(?)");
-  insert_statement.BindString(0, "test");
-  EXPECT_TRUE(insert_statement.Run());
+  ASSERT_TRUE(insert_statement);
 
-  insert_statement.Clear();
+  insert_statement->BindString(0, "test");
+  EXPECT_TRUE(insert_statement->Run());
+
+  insert_statement->Clear();
   sql_database_->Close();
 
   sql_database_ = std::make_unique<SqlDatabase>(
       test_directory_.AppendASCII("test.db"), /*histogram_tag=*/"test",
       /*current_version_number=*/3, base::BindRepeating(CreateTestSchema),
       base::BindRepeating(MigrateTestSchema));
-  sql_database_->Initialize();
+  EXPECT_TRUE(sql_database_->Initialize());
 
   auto insert_statement1 =
       sql_database_->GetStatementForQuery(SQL_FROM_HERE, INSERT_QUERY);
-  insert_statement1.BindString(0, "foo");
-  insert_statement1.BindString(1, "456");
-  EXPECT_TRUE(insert_statement1.Run());
+  ASSERT_TRUE(insert_statement1);
+
+  insert_statement1->BindString(0, "foo");
+  insert_statement1->BindString(1, "456");
+  EXPECT_TRUE(insert_statement1->Run());
 
   auto select_statement1 =
       sql_database_->GetStatementForQuery(SQL_FROM_HERE, SELECT_ALL_QUERY);
+  ASSERT_TRUE(select_statement1);
 
-  while (select_statement1.Step()) {
-    auto row = std::make_tuple(select_statement1.ColumnString(0),
-                               select_statement1.ColumnString(1));
+  while (select_statement1->Step()) {
+    auto row = std::make_tuple(select_statement1->ColumnString(0),
+                               select_statement1->ColumnString(1));
     EXPECT_THAT(row, testing::AnyOfArray({std::make_tuple("test", ""),
                                           std::make_tuple("foo", "456")}));
     steps_ += 1;
   }
   EXPECT_EQ(steps_, 2);
-  EXPECT_TRUE(select_statement1.Succeeded());
+  EXPECT_TRUE(select_statement1->Succeeded());
+}
+
+TEST_F(SqlDatabaseTest, InitializationFail) {
+  sql_database_ = std::make_unique<SqlDatabase>(
+      base::FilePath("/wrong_dir.db"), /*histogram_tag=*/"test",
+      /*current_version_number=*/3, base::BindRepeating(CreateTestSchema),
+      base::BindRepeating(MigrateTestSchema));
+  EXPECT_FALSE(sql_database_->Initialize());
+
+  auto statement =
+      sql_database_->GetStatementForQuery(SQL_FROM_HERE, SELECT_ALL_QUERY);
+  ASSERT_FALSE(statement);
 }
 
 }  // namespace
diff --git a/chrome/browser/ash/crosapi/browser_data_migrator.cc b/chrome/browser/ash/crosapi/browser_data_migrator.cc
index 0a69db0..9afb10b 100644
--- a/chrome/browser/ash/crosapi/browser_data_migrator.cc
+++ b/chrome/browser/ash/crosapi/browser_data_migrator.cc
@@ -362,8 +362,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
-void BrowserDataMigratorImpl::Migrate(crosapi::browser_util::MigrationMode mode,
-                                      MigrateCallback callback) {
+void BrowserDataMigratorImpl::Migrate(MigrateCallback callback) {
   DCHECK(local_state_);
   DCHECK(completion_callback_.is_null());
   completion_callback_ = std::move(callback);
@@ -375,14 +374,12 @@
   DCHECK(GetMigrationStep(local_state_) == MigrationStep::kRestartCalled);
   SetMigrationStep(local_state_, MigrationStep::kStarted);
 
-  DCHECK_EQ(mode, crosapi::browser_util::MigrationMode::kMove);
-
   LOG(WARNING) << "Initializing MoveMigrator.";
   migrator_delegate_ = std::make_unique<MoveMigrator>(
       original_profile_dir_, user_id_hash_, std::move(progress_tracker_),
       cancel_flag_, local_state_,
       base::BindOnce(&BrowserDataMigratorImpl::MigrateInternalFinishedUIThread,
-                     weak_factory_.GetWeakPtr(), mode));
+                     weak_factory_.GetWeakPtr()));
 
   migrator_delegate_->Migrate();
 }
@@ -393,7 +390,7 @@
 }
 
 void BrowserDataMigratorImpl::MigrateInternalFinishedUIThread(
-    crosapi::browser_util::MigrationMode mode,
+
     MigrationResult result) {
   DCHECK(local_state_);
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -416,7 +413,8 @@
 
   if (result.data_migration_result.kind == ResultKind::kSucceeded) {
     crosapi::browser_util::SetProfileMigrationCompletedForUser(
-        local_state_, user_id_hash_, mode);
+        local_state_, user_id_hash_,
+        crosapi::browser_util::MigrationMode::kMove);
 
     // Profile migration is marked as completed both when the migration is
     // performed (here) and for a new user without actually performing data
diff --git a/chrome/browser/ash/crosapi/browser_data_migrator.h b/chrome/browser/ash/crosapi/browser_data_migrator.h
index 5af222e1..f84872b 100644
--- a/chrome/browser/ash/crosapi/browser_data_migrator.h
+++ b/chrome/browser/ash/crosapi/browser_data_migrator.h
@@ -77,13 +77,9 @@
 
   virtual ~BrowserDataMigrator() = default;
 
-  // Carries out the migration with the mode specified by `MigrationMode`. It
-  // needs to be called on UI thread. |callback| will be called on the end of
-  // the migration procedure.
-  // TODO(crbug.com/1416750): Once `CopyMigrator` is removed, stop passing
-  // `MigrationMode` since there will only be one mode.
-  virtual void Migrate(crosapi::browser_util::MigrationMode mode,
-                       MigrateCallback callback) = 0;
+  // Carries out the migration. It needs to be called on UI thread. |callback|
+  // will be called at the end of the migration procedure.
+  virtual void Migrate(MigrateCallback callback) = 0;
 
   // Cancels the migration. This should be called on UI thread.
   // If this is called during the migration, it is expected that |callback|
@@ -182,8 +178,7 @@
       base::OnceCallback<void(bool, const absl::optional<uint64_t>&)> callback);
 
   // `BrowserDataMigrator` methods.
-  void Migrate(crosapi::browser_util::MigrationMode mode,
-               MigrateCallback callback) override;
+  void Migrate(MigrateCallback callback) override;
   void Cancel() override;
 
   // Registers boolean pref `kCheckForMigrationOnRestart` with default as false.
@@ -252,9 +247,7 @@
       crosapi::browser_util::PolicyInitState policy_init_state);
 
   // Called on UI thread once migration is finished.
-  void MigrateInternalFinishedUIThread(
-      crosapi::browser_util::MigrationMode mode,
-      MigrationResult result);
+  void MigrateInternalFinishedUIThread(MigrationResult result);
 
   // Path to the original profile data directory, which is directly under the
   // user data directory.
diff --git a/chrome/browser/ash/crosapi/browser_data_migrator_unittest.cc b/chrome/browser/ash/crosapi/browser_data_migrator_unittest.cc
index 171aa5d..19bce40 100644
--- a/chrome/browser/ash/crosapi/browser_data_migrator_unittest.cc
+++ b/chrome/browser/ash/crosapi/browser_data_migrator_unittest.cc
@@ -109,10 +109,8 @@
       std::make_unique<BrowserDataMigratorImpl>(
           from_dir_, user_id_hash, base::DoNothing(), &pref_service_);
   absl::optional<BrowserDataMigrator::Result> result;
-  migrator->Migrate(
-      crosapi::browser_util::MigrationMode::kMove,
-      base::BindLambdaForTesting([&out_result = result, &run_loop](
-                                     BrowserDataMigrator::Result result) {
+  migrator->Migrate(base::BindLambdaForTesting(
+      [&out_result = result, &run_loop](BrowserDataMigrator::Result result) {
         run_loop.Quit();
         out_result = result;
       }));
@@ -156,10 +154,8 @@
       std::make_unique<BrowserDataMigratorImpl>(
           from_dir_, user_id_hash, base::DoNothing(), &pref_service_);
   absl::optional<BrowserDataMigrator::Result> result;
-  migrator->Migrate(
-      crosapi::browser_util::MigrationMode::kMove,
-      base::BindLambdaForTesting([&out_result = result, &run_loop](
-                                     BrowserDataMigrator::Result result) {
+  migrator->Migrate(base::BindLambdaForTesting(
+      [&out_result = result, &run_loop](BrowserDataMigrator::Result result) {
         run_loop.Quit();
         out_result = result;
       }));
@@ -189,9 +185,6 @@
 }
 
 TEST_F(BrowserDataMigratorImplTest, MigrateOutOfDisk) {
-  base::test::ScopedFeatureList feature_list(
-      ash::features::kLacrosMoveProfileMigration);
-
   // Emulate the situation of out-of-disk.
   browser_data_migrator_util::ScopedExtraBytesRequiredToBeFreedForTesting
       scoped_extra_bytes(100);
@@ -209,10 +202,8 @@
       std::make_unique<BrowserDataMigratorImpl>(
           from_dir_, user_id_hash, base::DoNothing(), &pref_service_);
   absl::optional<BrowserDataMigrator::Result> result;
-  migrator->Migrate(
-      crosapi::browser_util::MigrationMode::kMove,
-      base::BindLambdaForTesting([&out_result = result, &run_loop](
-                                     BrowserDataMigrator::Result result) {
+  migrator->Migrate(base::BindLambdaForTesting(
+      [&out_result = result, &run_loop](BrowserDataMigrator::Result result) {
         run_loop.Quit();
         out_result = result;
       }));
diff --git a/chrome/browser/ash/crosapi/browser_manager.cc b/chrome/browser/ash/crosapi/browser_manager.cc
index 0ba1a97..53b62d7 100644
--- a/chrome/browser/ash/crosapi/browser_manager.cc
+++ b/chrome/browser/ash/crosapi/browser_manager.cc
@@ -578,7 +578,6 @@
     std::unique_ptr<BrowserLoader> browser_loader,
     component_updater::ComponentUpdateService* update_service)
     : browser_loader_(std::move(browser_loader)),
-      component_update_service_(update_service),
       environment_provider_(std::make_unique<EnvironmentProvider>()),
       launch_at_login_screen_(
           // NOTE: We only want to pre-launch Lacros if Ash is launched in login
diff --git a/chrome/browser/ash/crosapi/browser_manager.h b/chrome/browser/ash/crosapi/browser_manager.h
index 4c6b11d..c4d5c4d 100644
--- a/chrome/browser/ash/crosapi/browser_manager.h
+++ b/chrome/browser/ash/crosapi/browser_manager.h
@@ -722,10 +722,6 @@
 
   std::unique_ptr<crosapi::BrowserLoader> browser_loader_;
 
-  // May be null in tests.
-  const raw_ptr<ComponentUpdateService, ExperimentalAsh>
-      component_update_service_;
-
   // Delegate handling various concerns regarding the version service.
   std::unique_ptr<BrowserVersionServiceAsh::Delegate> version_service_delegate_;
 
diff --git a/chrome/browser/ash/crosapi/url_handler_ash.cc b/chrome/browser/ash/crosapi/url_handler_ash.cc
index 1d57e69..e593515 100644
--- a/chrome/browser/ash/crosapi/url_handler_ash.cc
+++ b/chrome/browser/ash/crosapi/url_handler_ash.cc
@@ -52,34 +52,6 @@
   return swa_manager ? swa_manager->GetSystemAppForURL(url) : absl::nullopt;
 }
 
-void OpenUrlInternalContinue(Profile* profile,
-                             GURL target_url,
-                             const GURL& original_url) {
-  DCHECK(ash::SystemWebAppManager::Get(profile)->IsAppEnabled(
-      ash::SystemWebAppType::OS_URL_HANDLER));
-
-  absl::optional<ash::SystemWebAppType> swa_type =
-      GetSystemAppForURL(profile, target_url);
-  if (!swa_type.has_value()) {
-    swa_type = ash::SystemWebAppType::OS_URL_HANDLER;
-  }
-
-  // This is a hack for chrome://camera-app URLs with queries, as sent by
-  // assistant.
-  // TODO(crbug.com/1445145): Figure out how to get rid of this.
-  if (*swa_type == ash::SystemWebAppType::CAMERA &&
-      !gurl_os_handler_utils::IsAshOsUrl(original_url)) {
-    target_url = original_url;
-  }
-
-  ash::SystemAppLaunchParams launch_params;
-  launch_params.url = target_url;
-  int64_t display_id =
-      display::Screen::GetScreen()->GetDisplayForNewWindows().id();
-  ash::LaunchSystemWebAppAsync(profile, *swa_type, launch_params,
-                               std::make_unique<apps::WindowInfo>(display_id));
-}
-
 }  // namespace
 
 // TODO(neis): Find a way to unify this code with the one in os_url_handler.cc.
@@ -102,10 +74,29 @@
     return false;
   }
 
-  // Wait for all SWAs to be registered before continuing.
-  ash::SystemWebAppManager::Get(profile)->on_apps_synchronized().Post(
-      FROM_HERE,
-      base::BindOnce(&OpenUrlInternalContinue, profile, target_url, url));
+  DCHECK(ash::SystemWebAppManager::Get(profile)->IsAppEnabled(
+      ash::SystemWebAppType::OS_URL_HANDLER));
+
+  absl::optional<ash::SystemWebAppType> swa_type =
+      GetSystemAppForURL(profile, target_url);
+  if (!swa_type.has_value()) {
+    swa_type = ash::SystemWebAppType::OS_URL_HANDLER;
+  }
+
+  // This is a hack for chrome://camera-app URLs with queries, as sent by
+  // assistant.
+  // TODO(crbug.com/1445145): Figure out how to get rid of this.
+  if (*swa_type == ash::SystemWebAppType::CAMERA &&
+      !gurl_os_handler_utils::IsAshOsUrl(url)) {
+    target_url = url;
+  }
+
+  ash::SystemAppLaunchParams launch_params;
+  launch_params.url = target_url;
+  int64_t display_id =
+      display::Screen::GetScreen()->GetDisplayForNewWindows().id();
+  ash::LaunchSystemWebAppAsync(profile, *swa_type, launch_params,
+                               std::make_unique<apps::WindowInfo>(display_id));
   return true;
 }
 
diff --git a/chrome/browser/ash/crostini/crostini_manager.cc b/chrome/browser/ash/crostini/crostini_manager.cc
index a1fde57..06ec406 100644
--- a/chrome/browser/ash/crostini/crostini_manager.cc
+++ b/chrome/browser/ash/crostini/crostini_manager.cc
@@ -3773,7 +3773,7 @@
   }
   if (CrostiniFeatures::Get()->IsPortForwardingAllowed(profile_)) {
     crostini::CrostiniPortForwarder::GetForProfile(profile_)
-        ->ActiveNetworksChanged(device->interface());
+        ->ActiveNetworksChanged(device->interface(), network->GetIpAddress());
   }
 }
 
diff --git a/chrome/browser/ash/crostini/crostini_port_forwarder.cc b/chrome/browser/ash/crostini/crostini_port_forwarder.cc
index c84b908..5fbc076 100644
--- a/chrome/browser/ash/crostini/crostini_port_forwarder.cc
+++ b/chrome/browser/ash/crostini/crostini_port_forwarder.cc
@@ -17,6 +17,9 @@
 #include "chrome/browser/ash/guest_os/guest_os_session_tracker.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
+#include "chromeos/ash/components/network/device_state.h"
+#include "chromeos/ash/components/network/network_handler.h"
+#include "chromeos/ash/components/network/network_state_handler.h"
 #include "chromeos/dbus/permission_broker/permission_broker_client.h"
 #include "components/prefs/scoped_user_pref_update.h"
 
@@ -71,6 +74,17 @@
 CrostiniPortForwarder::CrostiniPortForwarder(Profile* profile)
     : profile_(profile) {
   current_interface_ = kDefaultInterfaceToForward;
+  const ash::DeviceState* device =
+      ash::NetworkHandler::Get()->network_state_handler()->GetDeviceState(
+          current_interface_);
+  if (device) {
+    ip_address_ = device->GetIpAddressByType(shill::kTypeIPv4);
+    if (ip_address_.empty()) {
+      ip_address_ = device->GetIpAddressByType(shill::kTypeIPv6);
+    }
+  } else {
+    ip_address_ = "";
+  }
 }
 
 CrostiniPortForwarder::~CrostiniPortForwarder() = default;
@@ -387,6 +401,13 @@
   return forwarded_ports_list;
 }
 
+base::Value::List CrostiniPortForwarder::GetActiveNetworkInfo() {
+  base::Value::List network_info;
+  network_info.Append(base::Value(current_interface_));
+  network_info.Append(base::Value(ip_address_));
+  return network_info;
+}
+
 size_t CrostiniPortForwarder::GetNumberOfForwardedPortsForTesting() {
   return forwarded_ports_.size();
 }
@@ -405,7 +426,8 @@
 }
 
 void CrostiniPortForwarder::ActiveNetworksChanged(
-    const std::string& interface) {
+    const std::string& interface,
+    const std::string& ip_address) {
   if (interface.empty()) {
     return;
   }
@@ -413,7 +435,13 @@
     return;
   }
   current_interface_ = interface;
+  ip_address_ = ip_address;
   UpdateActivePortInterfaces();
+
+  for (auto& observer : observers_) {
+    observer.OnActiveNetworkChanged(base::Value(interface),
+                                    base::Value(ip_address));
+  }
 }
 
 // static
diff --git a/chrome/browser/ash/crostini/crostini_port_forwarder.h b/chrome/browser/ash/crostini/crostini_port_forwarder.h
index db504d86f..2ef0b0b 100644
--- a/chrome/browser/ash/crostini/crostini_port_forwarder.h
+++ b/chrome/browser/ash/crostini/crostini_port_forwarder.h
@@ -36,6 +36,8 @@
    public:
     // Called when a port's active state changes.
     virtual void OnActivePortsChanged(const base::Value::List& activePorts) = 0;
+    virtual void OnActiveNetworkChanged(const base::Value& interface,
+                                        const base::Value& ipAddress) = 0;
   };
 
   enum class Protocol {
@@ -106,11 +108,13 @@
   void DeactivateAllActivePorts(const guest_os::GuestId& container_id);
 
   base::Value::List GetActivePorts();
+  base::Value::List GetActiveNetworkInfo();
 
   size_t GetNumberOfForwardedPortsForTesting();
   absl::optional<base::Value> ReadPortPreferenceForTesting(
       const PortRuleKey& key);
-  void ActiveNetworksChanged(const std::string& interface);
+  void ActiveNetworksChanged(const std::string& interface,
+                             const std::string& ip_address);
 
   static CrostiniPortForwarder* GetForProfile(Profile* profile);
 
@@ -157,6 +161,7 @@
 
   // Current interface to forward ports on.
   std::string current_interface_;
+  std::string ip_address_;
 
   base::ObserverList<Observer> observers_;
 
diff --git a/chrome/browser/ash/crostini/crostini_port_forwarder_unittest.cc b/chrome/browser/ash/crostini/crostini_port_forwarder_unittest.cc
index 9d5f967b..71b8f7b 100644
--- a/chrome/browser/ash/crostini/crostini_port_forwarder_unittest.cc
+++ b/chrome/browser/ash/crostini/crostini_port_forwarder_unittest.cc
@@ -12,6 +12,7 @@
 #include "chromeos/ash/components/dbus/cicerone/cicerone_client.h"
 #include "chromeos/ash/components/dbus/concierge/concierge_client.h"
 #include "chromeos/ash/components/dbus/seneschal/seneschal_client.h"
+#include "chromeos/ash/components/network/network_handler_test_helper.h"
 #include "chromeos/dbus/permission_broker/fake_permission_broker_client.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -36,6 +37,9 @@
             guest_os::GuestId(kCrostiniDefaultVmType, "other", "other")),
         inactive_container_id_(
             guest_os::GuestId(kCrostiniDefaultVmType, "inactive", "inactive")) {
+    network_handler_helper_ = std::make_unique<ash::NetworkHandlerTestHelper>();
+    network_handler_helper_->AddDefaultProfiles();
+    network_handler_helper_->ResetDevicesAndServices();
   }
 
   CrostiniPortForwarderTest(const CrostiniPortForwarderTest&) = delete;
@@ -82,6 +86,10 @@
                 OnActivePortsChanged,
                 (const base::Value::List& activePorts),
                 (override));
+    MOCK_METHOD(void,
+                OnActiveNetworkChanged,
+                (const base::Value& interface, const base::Value& ipAddress),
+                (override));
   };
 
   Profile* profile() { return profile_.get(); }
@@ -186,6 +194,7 @@
 
   testing::NiceMock<MockPortObserver> mock_observer_;
 
+  std::unique_ptr<ash::NetworkHandlerTestHelper> network_handler_helper_;
   std::unique_ptr<CrostiniTestHelper> test_helper_;
   std::unique_ptr<TestingProfile> profile_;
   std::unique_ptr<CrostiniPortForwarder> crostini_port_forwarder_;
@@ -527,6 +536,7 @@
       GetPortKey(5001, Protocol::UDP, default_container_id_)};
   const char eth_interface[] = "eth0";
   EXPECT_CALL(mock_observer_, OnActivePortsChanged).Times(ports_to_add.size());
+  EXPECT_CALL(mock_observer_, OnActiveNetworkChanged).Times(2);
 
   // Add ports
   for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
@@ -548,7 +558,7 @@
   // required as ports are already being forwarded on kDefaultInterfaceToForward
   // by default.
   crostini_port_forwarder_->ActiveNetworksChanged(
-      crostini::kDefaultInterfaceToForward);
+      crostini::kDefaultInterfaceToForward, "127.0.0.1");
   for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
     MakePortPreferenceExpectation(port, /*exists=*/true,
                                   /*label=*/"");
@@ -561,7 +571,7 @@
   }
 
   // Request to update interface to "", invalid request, no change required.
-  crostini_port_forwarder_->ActiveNetworksChanged("");
+  crostini_port_forwarder_->ActiveNetworksChanged("", "");
   for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
     MakePortPreferenceExpectation(port, /*exists=*/true,
                                   /*label=*/"");
@@ -576,7 +586,26 @@
   // Request to update interface to eth_interface, ports are updated to use
   // the eth_interface and no longer use what they were using before
   // (kDefaultInterfaceToForward).
-  crostini_port_forwarder_->ActiveNetworksChanged(eth_interface);
+  crostini_port_forwarder_->ActiveNetworksChanged(eth_interface, "10.1.1.1");
+  for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
+    MakePortPreferenceExpectation(port, /*exists=*/true,
+                                  /*label=*/"");
+    // Deactivating forwarding on the previous interface is handled in Chromeos
+    // and by the lifelines used to track port rules. Until the port is released
+    // in Chromeos, both interfaces will be used.
+    MakePermissionBrokerPortForwardingExpectation(
+        /*port_number=*/port.port_number, /*protocol=*/port.protocol_type,
+        /*exists=*/true, /*interface=*/crostini::kDefaultInterfaceToForward);
+    MakePermissionBrokerPortForwardingExpectation(
+        /*port_number=*/port.port_number, /*protocol=*/port.protocol_type,
+        /*exists=*/true, /*interface=*/eth_interface);
+  }
+
+  // Request to update interface to kDefaultInterfaceToForward with an IPv6
+  // address. Needs a new interface because this is only called when interfaces
+  // changes.
+  crostini_port_forwarder_->ActiveNetworksChanged(kDefaultInterfaceToForward,
+                                                  "2001:db8:0:1");
   for (CrostiniPortForwarder::PortRuleKey& port : ports_to_add) {
     MakePortPreferenceExpectation(port, /*exists=*/true,
                                   /*label=*/"");
diff --git a/chrome/browser/ash/extensions/file_manager/drivefs_event_router.cc b/chrome/browser/ash/extensions/file_manager/drivefs_event_router.cc
index 268599d..378b018 100644
--- a/chrome/browser/ash/extensions/file_manager/drivefs_event_router.cc
+++ b/chrome/browser/ash/extensions/file_manager/drivefs_event_router.cc
@@ -179,10 +179,6 @@
     if (was_tracked) {
       // Stop tracking completed events but push it to subscribers.
       path_to_sync_state_.erase(previous_state_iter);
-    } else {
-      // If path wasn't tracked in the first place, don't report its completed
-      // event to subscribers.
-      return;
     }
   } else {
     path_to_sync_state_[path] = filtered_states.back();
diff --git a/chrome/browser/ash/file_manager/copy_or_move_io_task_impl.cc b/chrome/browser/ash/file_manager/copy_or_move_io_task_impl.cc
index e1c8d44..a02c4f6 100644
--- a/chrome/browser/ash/file_manager/copy_or_move_io_task_impl.cc
+++ b/chrome/browser/ash/file_manager/copy_or_move_io_task_impl.cc
@@ -243,7 +243,8 @@
   // present amongst other logged in users. Ensures managed user's files can't
   // be leaked to a non-managed user's ODFS b/278644796.
   if (ash::cloud_upload::UrlIsOnODFS(profile_,
-                                     progress_->GetDestinationFolder())) {
+                                     progress_->GetDestinationFolder()) &&
+      user_manager::UserManager::Get()->GetLoggedInUsers().size() > 1) {
     // Check none of the logged in users are managed.
     for (auto* user : user_manager::UserManager::Get()->GetLoggedInUsers()) {
       Profile* user_profile = Profile::FromBrowserContext(
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest.cc b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
index d9b823cc..1a9e42a6 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
@@ -572,9 +572,7 @@
       ::dlp::GetFilesSourcesResponse response;
       for (unsigned long i = 0; i < file_names->size(); i++) {
         auto* metadata = response.add_files_metadata();
-        auto inode = GetInodeValue(result.Append((*file_names)[i].GetString()));
-        EXPECT_TRUE(inode.has_value());
-        metadata->set_inode(inode.value());
+        metadata->set_path(result.Append((*file_names)[i].GetString()).value());
         metadata->set_source_url((*source_urls)[i].GetString());
       }
 
@@ -756,15 +754,6 @@
     return data_controls::Component::kUnknownComponent;
   }
 
-  // Returns the inode value for |path|, if found.
-  absl::optional<ino64_t> GetInodeValue(const base::FilePath& path) {
-    struct stat file_stats;
-    if (stat(path.value().c_str(), &file_stats) != 0) {
-      return absl::nullopt;
-    }
-    return file_stats.st_ino;
-  }
-
   // Invokes `callback` with the previously constructed `response`. Note that
   // the result doesn't depend on the value of `request`.
   void GetFilesSourcesMock(
@@ -1687,6 +1676,8 @@
             .EnableInlineSyncStatusProgressEvents(),
         TestCase("openDriveDocWhenOffline")
             .EnableBulkPinning()
+            .EnableInlineSyncStatusProgressEvents(),
+        TestCase("completedSyncStatusDismissesAfter300Ms")
             .EnableInlineSyncStatusProgressEvents()
         // TODO(b/189173190): Enable
         // TestCase("driveEnableDocsOfflineDialog"),
diff --git a/chrome/browser/ash/login/screens/lacros_data_migration_screen.cc b/chrome/browser/ash/login/screens/lacros_data_migration_screen.cc
index 6265cd9..a1a1fb5 100644
--- a/chrome/browser/ash/login/screens/lacros_data_migration_screen.cc
+++ b/chrome/browser/ash/login/screens/lacros_data_migration_screen.cc
@@ -131,8 +131,7 @@
     return;
   }
 
-  migrator_->Migrate(crosapi::browser_util::MigrationMode::kMove,
-                     base::BindOnce(&LacrosDataMigrationScreen::OnMigrated,
+  migrator_->Migrate(base::BindOnce(&LacrosDataMigrationScreen::OnMigrated,
                                     weak_factory_.GetWeakPtr()));
 
   if (LoginDisplayHost::default_host() &&
diff --git a/chrome/browser/ash/login/screens/lacros_data_migration_screen_browsertest.cc b/chrome/browser/ash/login/screens/lacros_data_migration_screen_browsertest.cc
index b7fe274..49e6e7c 100644
--- a/chrome/browser/ash/login/screens/lacros_data_migration_screen_browsertest.cc
+++ b/chrome/browser/ash/login/screens/lacros_data_migration_screen_browsertest.cc
@@ -46,8 +46,7 @@
 class FakeMigrator : public BrowserDataMigrator {
  public:
   // BrowserDataMigrator overrides.
-  void Migrate(crosapi::browser_util::MigrationMode mode,
-               MigrateCallback callback) override {
+  void Migrate(MigrateCallback callback) override {
     callback_ = std::move(callback);
   }
   void Cancel() override { cancel_called_ = true; }
diff --git a/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.cc b/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.cc
index 97091216..6b054b8 100644
--- a/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.cc
+++ b/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.cc
@@ -90,19 +90,6 @@
   return false;
 }
 
-// Returns inode value for local files.
-absl::optional<ino64_t> GetInodeValue(const base::FilePath& path) {
-  if (!IsInLocalFileSystem(path)) {
-    return absl::nullopt;
-  }
-
-  struct stat file_stats;
-  if (stat(path.value().c_str(), &file_stats) != 0) {
-    return absl::nullopt;
-  }
-  return file_stats.st_ino;
-}
-
 // Returns a `DlpFileDestination` with a source URL or component, based on
 // |app_update|. If neither URL nor component can be found, returns nullopt.
 absl::optional<DlpFileDestination> GetFileDestinationForApp(
@@ -135,15 +122,6 @@
   return absl::nullopt;
 }
 
-std::vector<absl::optional<ino64_t>> GetFilesInodes(
-    const std::vector<storage::FileSystemURL>& files) {
-  std::vector<absl::optional<ino64_t>> inodes;
-  for (const auto& file : files) {
-    inodes.push_back(GetInodeValue(file.path()));
-  }
-  return inodes;
-}
-
 // Returns |g_file_system_context_for_testing| if set, otherwise
 // it returns FileSystemContext* for the primary profile.
 storage::FileSystemContext* GetFileSystemContext() {
@@ -486,16 +464,15 @@
     return;
   }
 
-  std::vector<absl::optional<ino64_t>> inodes = GetFilesInodes(files);
   ::dlp::GetFilesSourcesRequest request;
-  for (const auto& inode : inodes) {
-    if (inode.has_value()) {
-      request.add_files_inodes(inode.value());
+  for (const auto& file : files) {
+    if (IsInLocalFileSystem(file.path())) {
+      request.add_files_paths(file.path().value());
     }
   }
   chromeos::DlpClient::Get()->GetFilesSources(
       request, base::BindOnce(&DlpFilesControllerAsh::ReturnDlpMetadata,
-                              weak_ptr_factory_.GetWeakPtr(), std::move(inodes),
+                              weak_ptr_factory_.GetWeakPtr(), std::move(files),
                               destination, std::move(result_callback)));
 }
 
@@ -1071,7 +1048,7 @@
 }
 
 void DlpFilesControllerAsh::ReturnDlpMetadata(
-    std::vector<absl::optional<ino64_t>> inodes,
+    const std::vector<storage::FileSystemURL>& files,
     absl::optional<DlpFileDestination> destination,
     GetDlpMetadataCallback result_callback,
     const ::dlp::GetFilesSourcesResponse response) {
@@ -1080,7 +1057,7 @@
                << response.error_message();
   }
 
-  base::flat_map<ino64_t, DlpFileMetadata> metadata_map;
+  base::flat_map<std::string, DlpFileMetadata> metadata_map;
   for (const auto& metadata : response.files_metadata()) {
     DlpRulesManager::Level level = rules_manager_->IsRestrictedByAnyRule(
         GURL(metadata.source_url()), DlpRulesManager::Restriction::kFiles,
@@ -1116,18 +1093,14 @@
     }
 
     metadata_map.emplace(
-        metadata.inode(),
+        metadata.path(),
         DlpFileMetadata(metadata.source_url(), metadata.referrer_url(),
                         is_dlp_restricted, is_restricted_for_destination));
   }
 
   std::vector<DlpFileMetadata> result;
-  for (const auto& inode : inodes) {
-    if (!inode.has_value()) {
-      result.emplace_back("", "", false, false);
-      continue;
-    }
-    auto metadata_itr = metadata_map.find(inode.value());
+  for (const auto& file : files) {
+    auto metadata_itr = metadata_map.find(file.path().value());
     if (metadata_itr == metadata_map.end()) {
       result.emplace_back("", "", false, false);
     } else {
diff --git a/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.h b/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.h
index 3f138dfd..dab31b3d 100644
--- a/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.h
+++ b/chrome/browser/ash/policy/dlp/dlp_files_controller_ash.h
@@ -231,7 +231,7 @@
                             FilterDisallowedUploadsCallback result_callback,
                             ::dlp::CheckFilesTransferResponse response);
 
-  void ReturnDlpMetadata(std::vector<absl::optional<ino64_t>> inodes,
+  void ReturnDlpMetadata(const std::vector<storage::FileSystemURL>& files,
                          absl::optional<DlpFileDestination> destination,
                          GetDlpMetadataCallback result_callback,
                          const ::dlp::GetFilesSourcesResponse response);
diff --git a/chrome/browser/ash/system_web_apps/apps/diagnostics_app_integration_browsertest.cc b/chrome/browser/ash/system_web_apps/apps/diagnostics_app_integration_browsertest.cc
index e819826..507625c 100644
--- a/chrome/browser/ash/system_web_apps/apps/diagnostics_app_integration_browsertest.cc
+++ b/chrome/browser/ash/system_web_apps/apps/diagnostics_app_integration_browsertest.cc
@@ -13,6 +13,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_navigation_observer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/window_open_disposition.h"
 #include "url/gurl.h"
@@ -73,7 +74,11 @@
 IN_PROC_BROWSER_TEST_P(DiagnosticsAppIntegrationTest, LaunchMetricsTest) {
   WaitForTestSystemAppInstall();
 
+  const GURL url(ash::kChromeUIDiagnosticsAppUrl);
+  content::TestNavigationObserver observer(url);
+  observer.StartWatchingNewWebContents();
   ash::LaunchSystemWebAppAsync(profile(), ash::SystemWebAppType::DIAGNOSTICS);
+  observer.Wait();
 
   histogram_tester_.ExpectUniqueSample(kFromChromeLaunch, kDiagnosticsApp, 1);
 }
diff --git a/chrome/browser/ash/system_web_apps/apps/shortcut_customization_app_integration_browsertest.cc b/chrome/browser/ash/system_web_apps/apps/shortcut_customization_app_integration_browsertest.cc
index 1d80c58..8e8029b0 100644
--- a/chrome/browser/ash/system_web_apps/apps/shortcut_customization_app_integration_browsertest.cc
+++ b/chrome/browser/ash/system_web_apps/apps/shortcut_customization_app_integration_browsertest.cc
@@ -55,8 +55,12 @@
                        LaunchMetricsTest) {
   WaitForTestSystemAppInstall();
 
+  const GURL url(ash::kChromeUIShortcutCustomizationAppURL);
+  content::TestNavigationObserver observer(url);
+  observer.StartWatchingNewWebContents();
   ash::LaunchSystemWebAppAsync(profile(),
                                ash::SystemWebAppType::SHORTCUT_CUSTOMIZATION);
+  observer.Wait();
 
   histogram_tester_.ExpectUniqueSample(
       "Apps.DefaultAppLaunch.FromChromeInternal", 44, 1);
diff --git a/chrome/browser/ash/video_conference/video_conference_integration_browsertest.cc b/chrome/browser/ash/video_conference/video_conference_integration_browsertest.cc
index 3f9c8c3..4a25da7f 100644
--- a/chrome/browser/ash/video_conference/video_conference_integration_browsertest.cc
+++ b/chrome/browser/ash/video_conference/video_conference_integration_browsertest.cc
@@ -219,8 +219,16 @@
   void SetUpCommandLine(base::CommandLine* command_line) override {
     command_line->AppendSwitch(
         ::ash::switches::kCameraEffectsSupportedByHardware);
-    // Used for bypassing tab capturing selection.
-    command_line->AppendSwitch(::switches::kThisTabCaptureAutoAccept);
+    // Flags use to automatically select the right desktop source and get
+    // around security restrictions.
+    // TODO(crbug.com/1459164): Use a less error-prone flag.
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+    command_line->AppendSwitchASCII(::switches::kAutoSelectDesktopCaptureSource,
+                                    "Display");
+#else
+    command_line->AppendSwitchASCII(::switches::kAutoSelectDesktopCaptureSource,
+                                    "Entire screen");
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
     // If in guest mode.
     if (std::get<1>(GetParam())) {
@@ -882,4 +890,38 @@
   EXPECT_TRUE(found_noise_cancellation_buttion);
 }
 
+IN_PROC_BROWSER_TEST_P(VideoConferenceIntegrationTest, StopAllScreenShare) {
+  // Open a tab.
+  content::WebContents* web_contents_1 =
+      NavigateTo("/video_conference_demo.html");
+
+  // Start the screen sharing.
+  StartScreenSharing(web_contents_1);
+  WAIT_FOR_CONDITION(GetVcTray()->GetVisible());
+
+  // Get the ReturnToApp Panel.
+  ClickButton(GetVcTray()->toggle_bubble_button());
+  WAIT_FOR_CONDITION(GetVcTray()->GetBubbleView()->GetVisible());
+
+  // Check that web_contents_1 is sharing screen.
+  auto buttons = GetReturnToAppButtons();
+  EXPECT_EQ(buttons.size(), 1u);
+  EXPECT_FALSE(buttons[0]->is_capturing_camera());
+  EXPECT_FALSE(buttons[0]->is_capturing_microphone());
+  EXPECT_TRUE(buttons[0]->is_capturing_screen());
+
+  // Hide the ReturnToApp Panel.
+  ClickButton(GetVcTray()->toggle_bubble_button());
+
+  // Click on the screen share button.
+  EXPECT_TRUE(share_bt_->is_capturing());
+  ClickButton(share_bt_);
+  WAIT_FOR_CONDITION(!share_bt_->is_capturing());
+
+  // Check that web_contents_1 has stopped sharing screen.
+  ClickButton(GetVcTray()->toggle_bubble_button());
+  WAIT_FOR_CONDITION(GetVcTray()->GetBubbleView()->GetVisible());
+  EXPECT_FALSE(GetReturnToAppButtons()[0]->is_capturing_screen());
+}
+
 }  // namespace ash::video_conference
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h b/chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h
index 3e2f43be6..a45bfba 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h
@@ -40,7 +40,6 @@
 constexpr DataType DATA_TYPE_ACCOUNT_PASSWORDS = DATA_TYPE_EMBEDDER_BEGIN << 11;
 constexpr DataType DATA_TYPE_LOCAL_CUSTOM_DICTIONARY = DATA_TYPE_EMBEDDER_BEGIN
                                                        << 12;
-constexpr DataType DATA_TYPE_CONTROLLED_FRAME = DATA_TYPE_EMBEDDER_BEGIN << 13;
 
 // Group datatypes.
 
@@ -55,7 +54,6 @@
 #endif
     DATA_TYPE_SITE_USAGE_DATA | DATA_TYPE_DURABLE_PERMISSION |
     DATA_TYPE_EXTERNAL_PROTOCOL_DATA | DATA_TYPE_ISOLATED_ORIGINS |
-    DATA_TYPE_CONTROLLED_FRAME |
     content::BrowsingDataRemover::DATA_TYPE_PRIVACY_SANDBOX;
 
 // Datatypes protected by Important Sites.
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
index e16c3ac..9991179a 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -158,13 +158,9 @@
 #endif  // BUILDFLAG(IS_ANDROID)
 
 #if !BUILDFLAG(IS_ANDROID)
-#include "chrome/browser/web_applications/web_app.h"
 #include "chrome/browser/web_applications/web_app_command_scheduler.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
-#include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/browser/web_applications/web_app_utils.h"
-#include "content/public/browser/isolated_web_apps_policy.h"
-#include "content/public/browser/storage_partition_config.h"
 #endif  // !BUILDFLAG(IS_ANDROID)
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
@@ -1277,59 +1273,6 @@
       (constants::DATA_TYPE_SITE_DATA | constants::DATA_TYPE_HISTORY)) {
     login_detection::prefs::RemoveLoginDetectionData(prefs);
   }
-
-#if !BUILDFLAG(IS_ANDROID)
-  //////////////////////////////////////////////////////////////////////////////
-  // Isolated Web Apps.
-  // If no StoragePartition was specified in the filter, make additional
-  // BrowsingDataRemover::Remove* calls for each StoragePartition of Isolated
-  // Web Apps (IWA) that match the filter.
-  //
-  // The data types specified in `remove_mask` will be removed from the
-  // primary StoragePartition of an IWA, but all data will be removed from
-  // Controlled Frame StoragePartitions if DATA_TYPE_CONTROLLED_FRAME is
-  // specified in `remove_mask`.
-  if (!filter_builder->GetStoragePartitionConfig().has_value() &&
-      content::IsolatedWebAppsPolicy::AreIsolatedWebAppsEnabled(profile_)) {
-    const web_app::WebAppRegistrar& web_app_registrar =
-        web_app::WebAppProvider::GetForLocalAppsUnchecked(profile_)
-            ->registrar_unsafe();
-    for (const web_app::WebApp& web_app : web_app_registrar.GetApps()) {
-      if (!web_app_registrar.IsIsolated(web_app.app_id()) ||
-          !filter.Run(web_app.scope())) {
-        continue;
-      }
-      std::vector<content::StoragePartitionConfig> partitions =
-          web_app_registrar.GetIsolatedWebAppStoragePartitionConfigs(
-              web_app.app_id());
-      for (const content::StoragePartitionConfig& partition : partitions) {
-        // The filter specified a StoragePartition, so only delete data that
-        // lives in a StoragePartition.
-        uint64_t iwa_remove_mask =
-            content::BrowsingDataRemover::DATA_TYPE_ON_STORAGE_PARTITION;
-        bool is_primary_partition = partition.partition_name().empty();
-        if (is_primary_partition) {
-          iwa_remove_mask &= remove_mask;
-        } else {
-          if (!(remove_mask & constants::DATA_TYPE_CONTROLLED_FRAME)) {
-            continue;
-          }
-          // For Controlled Frame partitions, all data should be deleted, so
-          // |iwa_remove_mask| should stay DATA_TYPE_ON_STORAGE_PARTITION.
-        }
-
-        // We can't wait for the `RemoveWithFilter` call to finish because
-        // BrowsingDataRemover doesn't support nested Remove calls.
-        auto iwa_filter_builder = content::BrowsingDataFilterBuilder::Create(
-            content::BrowsingDataFilterBuilder::Mode::kPreserve);
-        iwa_filter_builder->SetStoragePartitionConfig(partition);
-        profile_->GetBrowsingDataRemover()->RemoveWithFilter(
-            delete_begin, delete_end, iwa_remove_mask, origin_type_mask,
-            std::move(iwa_filter_builder));
-      }
-    }
-  }
-#endif  // !BUILDFLAG(IS_ANDROID)
 }
 
 void ChromeBrowsingDataRemoverDelegate::OnTaskStarted(
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index 1222b476..c68f036c 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -85,7 +85,6 @@
 #include "chrome/test/base/scoped_testing_local_state.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chrome/test/base/testing_profile_manager.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/data_model/autofill_profile.h"
 #include "components/autofill/core/browser/data_model/credit_card.h"
@@ -190,15 +189,10 @@
 #endif  // BUILDFLAG(IS_ANDROID)
 
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_LACROS)
-#include "base/test/test_future.h"
-#include "chrome/browser/ui/web_applications/test/isolated_web_app_test_utils.h"
-#include "chrome/browser/web_applications/isolated_web_apps/get_controlled_frame_partition_command.h"
-#include "chrome/browser/web_applications/locks/app_lock.h"
 #include "chrome/browser/web_applications/test/fake_web_app_provider.h"
 #include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
 #include "chrome/browser/web_applications/test/web_app_test_utils.h"
 #include "chrome/browser/web_applications/web_app.h"
-#include "chrome/browser/web_applications/web_app_command_scheduler.h"
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
 #endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_LACROS)
 
@@ -234,12 +228,6 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #endif  // BUILDFLAG(ENABLE_REPORTING)
 
-#if BUILDFLAG(ENABLE_NACL)
-#include "chrome/browser/nacl_host/nacl_browser_delegate_impl.h"
-#include "components/nacl/browser/nacl_browser.h"
-#include "components/nacl/common/buildflags.h"
-#endif  // BUILDFLAG(ENABLE_NACL)
-
 using content::BrowsingDataFilterBuilder;
 using domain_reliability::DomainReliabilityClearMode;
 using domain_reliability::DomainReliabilityMonitor;
@@ -254,7 +242,6 @@
 using testing::MatchResultListener;
 using testing::Return;
 using testing::SizeIs;
-using testing::UnorderedElementsAre;
 using testing::WithArgs;
 
 namespace constants = chrome_browsing_data_remover;
@@ -545,7 +532,16 @@
   RemoveUkmDataTester(const RemoveUkmDataTester&) = delete;
   RemoveUkmDataTester& operator=(const RemoveUkmDataTester&) = delete;
 
+  ~RemoveUkmDataTester() {
+    TestingBrowserProcess::GetGlobal()->SetProfileManager(nullptr);
+  }
+
   [[nodiscard]] bool Init(Profile* profile) {
+    // Setup required dependencies for segmentation platform:
+    EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
+    TestingBrowserProcess::GetGlobal()->SetProfileManager(
+        std::make_unique<FakeProfileManager>(temp_dir_.GetPath()));
+
     // Create the platform to kick off initialization.
     segmentation_platform::SegmentationPlatformServiceFactory::GetForProfile(
         profile);
@@ -578,6 +574,7 @@
 
  private:
   ukm::TestUkmRecorder ukm_recorder_;
+  base::ScopedTempDir temp_dir_;
   raw_ptr<history::HistoryService> history_service_;
   segmentation_platform::UkmDataManagerTestUtils test_utils_;
 
@@ -1210,20 +1207,6 @@
 
 }  // namespace autofill
 
-#if BUILDFLAG(ENABLE_NACL)
-class ScopedNaClBrowserDelegate {
- public:
-  ~ScopedNaClBrowserDelegate() {
-    nacl::NaClBrowser::ClearAndDeleteDelegateForTest();
-  }
-
-  void Init(ProfileManager* profile_manager) {
-    nacl::NaClBrowser::SetDelegate(
-        std::make_unique<NaClBrowserDelegateImpl>(profile_manager));
-  }
-};
-#endif  // BUILDFLAG(ENABLE_NACL)
-
 // Test Class -----------------------------------------------------------------
 
 class ChromeBrowsingDataRemoverDelegateTest : public testing::Test {
@@ -1244,41 +1227,39 @@
     // that initialize a ScopedFeatureList in their constructors can do so
     // before the code below potentially kicks off tasks on other threads that
     // check if a feature is enabled, to avoid tsan data races.
-    profile_manager_ = std::make_unique<TestingProfileManager>(
-        TestingBrowserProcess::GetGlobal());
-    CHECK(profile_manager_->SetUp());
-    profile_ = profile_manager_->CreateTestingProfile(
-        "test_profile",
-        {{StatefulSSLHostStateDelegateFactory::GetInstance(),
-          StatefulSSLHostStateDelegateFactory::GetDefaultFactoryForTesting()},
-         {BookmarkModelFactory::GetInstance(),
-          BookmarkModelFactory::GetDefaultFactory()},
-         {HistoryServiceFactory::GetInstance(),
-          HistoryServiceFactory::GetDefaultFactory()},
-         {FaviconServiceFactory::GetInstance(),
-          FaviconServiceFactory::GetDefaultFactory()},
-         {SpellcheckServiceFactory::GetInstance(),
-          base::BindRepeating([](content::BrowserContext* profile)
-                                  -> std::unique_ptr<KeyedService> {
-            return std::make_unique<SpellcheckService>(
-                static_cast<Profile*>(profile));
-          })},
-         {TrustedVaultServiceFactory::GetInstance(),
-          TrustedVaultServiceFactory::GetDefaultFactory()},
-         {SyncServiceFactory::GetInstance(),
-          SyncServiceFactory::GetDefaultFactory()},
-         {ChromeSigninClientFactory::GetInstance(),
-          base::BindRepeating(&signin::BuildTestSigninClient)},
-         {WebDataServiceFactory::GetInstance(),
-          WebDataServiceFactory::GetDefaultFactory()}});
-
-#if BUILDFLAG(ENABLE_NACL)
-    // Clearing Cache will clear PNACL cache, which needs this delegate set.
-    nacl_browser_delegate_.Init(profile_manager_->profile_manager());
-#endif  // BUILDFLAG(ENABLE_NACL)
+    profile_ =
+        TestingProfile::Builder()
+            .AddTestingFactory(
+                StatefulSSLHostStateDelegateFactory::GetInstance(),
+                StatefulSSLHostStateDelegateFactory::
+                    GetDefaultFactoryForTesting())
+            .AddTestingFactory(BookmarkModelFactory::GetInstance(),
+                               BookmarkModelFactory::GetDefaultFactory())
+            .AddTestingFactory(HistoryServiceFactory::GetInstance(),
+                               HistoryServiceFactory::GetDefaultFactory())
+            .AddTestingFactory(FaviconServiceFactory::GetInstance(),
+                               FaviconServiceFactory::GetDefaultFactory())
+            .AddTestingFactory(
+                SpellcheckServiceFactory::GetInstance(),
+                base::BindRepeating([](content::BrowserContext* profile)
+                                        -> std::unique_ptr<KeyedService> {
+                  return std::make_unique<SpellcheckService>(
+                      static_cast<Profile*>(profile));
+                }))
+            .AddTestingFactory(TrustedVaultServiceFactory::GetInstance(),
+                               TrustedVaultServiceFactory::GetDefaultFactory())
+            .AddTestingFactory(SyncServiceFactory::GetInstance(),
+                               SyncServiceFactory::GetDefaultFactory())
+            .AddTestingFactory(
+                ChromeSigninClientFactory::GetInstance(),
+                base::BindRepeating(&signin::BuildTestSigninClient))
+            .AddTestingFactory(WebDataServiceFactory::GetInstance(),
+                               WebDataServiceFactory::GetDefaultFactory())
+            .Build();
 
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_LACROS)
-    web_app::test::AwaitStartWebAppProviderAndSubsystems(profile_.get());
+    web_app_provider_ = web_app::FakeWebAppProvider::Get(profile_.get());
+    web_app_provider_->StartWithSubsystems();
 #endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_LACROS)
 
     remover_ = profile_->GetBrowsingDataRemover();
@@ -1302,6 +1283,9 @@
     ProtocolHandlerRegistryFactory::GetInstance()->SetTestingFactory(
         profile_.get(), base::BindRepeating(&BuildProtocolHandlerRegistry));
 
+    local_state_ = std::make_unique<ScopedTestingLocalState>(
+        TestingBrowserProcess::GetGlobal());
+
 #if BUILDFLAG(IS_ANDROID)
     static_cast<ChromeBrowsingDataRemoverDelegate*>(
         profile_->GetBrowsingDataRemoverDelegate())
@@ -1322,18 +1306,21 @@
     // the profile should fix the race.
     content::RunAllTasksUntilIdle();
 
-    // Drop unowned references before ProfileManager destroys owned references.
+    // Drop unowned references before profile destroys owned references.
     remover_ = nullptr;
-    profile_ = nullptr;
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_LACROS)
+    web_app_provider_ = nullptr;
+#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_LACROS)
 
     // TestingProfile contains a DOMStorageContext.  BrowserContext's destructor
     // posts a message to the WEBKIT thread to delete some of its member
     // variables. We need to ensure that the profile is destroyed, and that
     // the message loop is cleared out, before destroying the threads and loop.
     // Otherwise we leak memory.
-    profile_manager_.reset();
+    profile_.reset();
     base::RunLoop().RunUntilIdle();
 
+    local_state_.reset();
     TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr);
   }
 
@@ -1416,8 +1403,6 @@
 
   network::NetworkContext* network_context() { return network_context_.get(); }
 
-  TestingProfileManager* GetProfileManager() { return profile_manager_.get(); }
-
   TestingProfile* GetProfile() { return profile_.get(); }
 
   bool Match(const GURL& origin,
@@ -1431,6 +1416,10 @@
     return &task_environment_;
   }
 
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_LACROS)
+  web_app::FakeWebAppProvider* web_app_provider() { return web_app_provider_; }
+#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_LACROS)
+
  protected:
   // |feature_list_| needs to be destroyed after |task_environment_|, to avoid
   // tsan flakes caused by other tasks running while |feature_list_| is
@@ -1441,14 +1430,14 @@
   // Cached pointer to BrowsingDataRemover for access to testing methods.
   raw_ptr<content::BrowsingDataRemover> remover_;
 
-#if BUILDFLAG(ENABLE_NACL)
-  ScopedNaClBrowserDelegate nacl_browser_delegate_;
-#endif  // BUILDFLAG(ENABLE_NACL)
   content::BrowserTaskEnvironment task_environment_{
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
   std::unique_ptr<network::NetworkContext> network_context_;
-  std::unique_ptr<TestingProfileManager> profile_manager_;
-  raw_ptr<TestingProfile> profile_;  // Owned by `profile_manager_`.
+  std::unique_ptr<TestingProfile> profile_;
+  std::unique_ptr<ScopedTestingLocalState> local_state_;
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_LACROS)
+  raw_ptr<web_app::FakeWebAppProvider> web_app_provider_;
+#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_LACROS)
 };
 
 #if BUILDFLAG(ENABLE_REPORTING)
@@ -1561,7 +1550,7 @@
 
 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_LACROS)
 TEST_F(ChromeBrowsingDataRemoverDelegateTest, ClearWebAppData) {
-  auto* provider = web_app::FakeWebAppProvider::Get(GetProfile());
+  auto* provider = web_app_provider();
   ASSERT_TRUE(provider);
 
   // Make sure WebAppProvider's subsystems are ready.
@@ -1603,222 +1592,6 @@
 
   EXPECT_EQ(constants::DATA_TYPE_HISTORY, GetRemovalMask());
 }
-
-class IsolatedWebAppChromeBrowsingDataRemoverDelegateTest
-    : public ChromeBrowsingDataRemoverDelegateTest {
- public:
-  struct RemovalInfo {
-    uint64_t remove_mask;
-    absl::optional<content::StoragePartitionConfig> storage_partition_config =
-        absl::nullopt;
-  };
-
-  IsolatedWebAppChromeBrowsingDataRemoverDelegateTest() {
-    feature_list_.InitWithFeatures(
-        {features::kIsolatedWebApps, features::kIsolatedWebAppDevMode}, {});
-  }
-
- protected:
-  content::BrowsingDataRemover::DataType DATA_TYPE_INDEXED_DB =
-      content::BrowsingDataRemover::DATA_TYPE_INDEXED_DB;
-  content::BrowsingDataRemover::DataType DATA_TYPE_ON_STORAGE_PARTITION =
-      content::BrowsingDataRemover::DATA_TYPE_ON_STORAGE_PARTITION;
-  content::BrowsingDataRemover::DataType DATA_TYPE_SITE_DATA =
-      constants::DATA_TYPE_SITE_DATA;
-
-  web_app::IsolatedWebAppUrlInfo InstallIsolatedWebApp(const GURL& iwa_url) {
-    web_app::AddDummyIsolatedAppToRegistry(GetProfile(), iwa_url, "IWA Name");
-    return web_app::IsolatedWebAppUrlInfo::Create(iwa_url).value();
-  }
-
-  content::StoragePartitionConfig CreateControlledFrameStoragePartition(
-      const web_app::IsolatedWebAppUrlInfo& iwa_url_info,
-      const std::string& partition_name) {
-    auto* provider = web_app::FakeWebAppProvider::Get(GetProfile());
-    CHECK(provider);
-    base::test::TestFuture<absl::optional<content::StoragePartitionConfig>>
-        future;
-    provider->scheduler().ScheduleCallbackWithLock(
-        "GetControlledFramePartition",
-        std::make_unique<web_app::AppLockDescription>(iwa_url_info.app_id()),
-        base::BindOnce(&web_app::GetControlledFramePartitionWithLock,
-                       GetProfile(), iwa_url_info, partition_name,
-                       /*in_memory=*/false, future.GetCallback()),
-        FROM_HERE);
-    return future.Get().value();
-  }
-
-  std::vector<RemovalInfo> ClearDataAndWait(
-      const base::Time& delete_begin,
-      const base::Time& delete_end,
-      uint64_t remove_mask,
-      std::unique_ptr<BrowsingDataFilterBuilder> filter_builder) {
-    std::vector<RemovalInfo> removal_tasks;
-    base::RunLoop run_loop;
-    auto* browsing_data_remover = GetProfile()->GetBrowsingDataRemover();
-    browsing_data_remover->SetWouldCompleteCallbackForTesting(
-        base::BindLambdaForTesting([&](base::OnceClosure callback) {
-          removal_tasks.push_back(
-              {browsing_data_remover->GetLastUsedRemovalMaskForTesting(),
-               browsing_data_remover
-                   ->GetLastUsedStoragePartitionConfigForTesting()});
-          if (browsing_data_remover->GetPendingTaskCountForTesting() == 1) {
-            run_loop.Quit();
-          }
-          std::move(callback).Run();
-        }));
-
-    BlockUntilOriginDataRemoved(delete_begin, delete_end, remove_mask,
-                                std::move(filter_builder));
-    run_loop.Run();
-
-    browsing_data_remover->SetWouldCompleteCallbackForTesting(
-        base::DoNothing());
-    return removal_tasks;
-  }
-};
-bool operator==(
-    const IsolatedWebAppChromeBrowsingDataRemoverDelegateTest::RemovalInfo& a,
-    const IsolatedWebAppChromeBrowsingDataRemoverDelegateTest::RemovalInfo& b) {
-  return a.remove_mask == b.remove_mask &&
-         a.storage_partition_config == b.storage_partition_config;
-}
-
-TEST_F(IsolatedWebAppChromeBrowsingDataRemoverDelegateTest, ClearData) {
-  const GURL iwa_url1(
-      "isolated-app://"
-      "berugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic");
-  web_app::IsolatedWebAppUrlInfo iwa_url_info1 =
-      InstallIsolatedWebApp(iwa_url1);
-  content::StoragePartitionConfig controlled_frame_partition1 =
-      CreateControlledFrameStoragePartition(iwa_url_info1, "controlled_frame");
-
-  const GURL iwa_url2(
-      "isolated-app://"
-      "abcdefztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic");
-  web_app::IsolatedWebAppUrlInfo iwa_url_info2 =
-      InstallIsolatedWebApp(iwa_url2);
-
-  std::vector<RemovalInfo> removal_tasks =
-      ClearDataAndWait(base::Time(), base::Time::Max(), DATA_TYPE_SITE_DATA,
-                       BrowsingDataFilterBuilder::Create(
-                           BrowsingDataFilterBuilder::Mode::kPreserve));
-
-  EXPECT_THAT(
-      removal_tasks,
-      UnorderedElementsAre(
-          RemovalInfo{DATA_TYPE_SITE_DATA},
-          RemovalInfo{DATA_TYPE_ON_STORAGE_PARTITION & DATA_TYPE_SITE_DATA,
-                      iwa_url_info1.storage_partition_config(GetProfile())},
-          RemovalInfo{DATA_TYPE_ON_STORAGE_PARTITION,
-                      controlled_frame_partition1},
-          RemovalInfo{DATA_TYPE_ON_STORAGE_PARTITION & DATA_TYPE_SITE_DATA,
-                      iwa_url_info2.storage_partition_config(GetProfile())}));
-}
-
-TEST_F(IsolatedWebAppChromeBrowsingDataRemoverDelegateTest,
-       ControlledFramesNotClearedIfNotInFilter) {
-  const GURL iwa_url(
-      "isolated-app://"
-      "berugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic");
-  web_app::IsolatedWebAppUrlInfo iwa_url_info = InstallIsolatedWebApp(iwa_url);
-  content::StoragePartitionConfig controlled_frame_partition =
-      CreateControlledFrameStoragePartition(iwa_url_info, "controlled_frame");
-
-  std::vector<RemovalInfo> removal_tasks =
-      ClearDataAndWait(base::Time(), base::Time::Max(), DATA_TYPE_INDEXED_DB,
-                       BrowsingDataFilterBuilder::Create(
-                           BrowsingDataFilterBuilder::Mode::kPreserve));
-
-  EXPECT_THAT(
-      removal_tasks,
-      UnorderedElementsAre(
-          RemovalInfo{DATA_TYPE_INDEXED_DB},
-          RemovalInfo{DATA_TYPE_INDEXED_DB,
-                      iwa_url_info.storage_partition_config(GetProfile())}));
-}
-
-TEST_F(IsolatedWebAppChromeBrowsingDataRemoverDelegateTest,
-       FilterOriginRespected) {
-  const GURL iwa_url1(
-      "isolated-app://"
-      "berugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic");
-  web_app::IsolatedWebAppUrlInfo iwa_url_info1 =
-      InstallIsolatedWebApp(iwa_url1);
-
-  const GURL iwa_url2(
-      "isolated-app://"
-      "abcdefztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic");
-  web_app::IsolatedWebAppUrlInfo iwa_url_info2 =
-      InstallIsolatedWebApp(iwa_url2);
-
-  auto filter_builder = BrowsingDataFilterBuilder::Create(
-      BrowsingDataFilterBuilder::Mode::kDelete);
-  filter_builder->AddOrigin(iwa_url_info1.origin());
-  std::vector<RemovalInfo> removal_tasks =
-      ClearDataAndWait(base::Time(), base::Time::Max(), DATA_TYPE_INDEXED_DB,
-                       std::move(filter_builder));
-
-  EXPECT_THAT(
-      removal_tasks,
-      UnorderedElementsAre(
-          RemovalInfo{DATA_TYPE_INDEXED_DB},
-          RemovalInfo{DATA_TYPE_INDEXED_DB,
-                      iwa_url_info1.storage_partition_config(GetProfile())}));
-}
-
-TEST_F(IsolatedWebAppChromeBrowsingDataRemoverDelegateTest,
-       ControlledFramesIgnoreFilter) {
-  const GURL iwa_url(
-      "isolated-app://"
-      "berugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic");
-  web_app::IsolatedWebAppUrlInfo iwa_url_info = InstallIsolatedWebApp(iwa_url);
-  content::StoragePartitionConfig controlled_frame_partition =
-      CreateControlledFrameStoragePartition(iwa_url_info, "controlled_frame");
-
-  std::vector<RemovalInfo> removal_tasks =
-      ClearDataAndWait(base::Time(), base::Time::Max(),
-                       DATA_TYPE_INDEXED_DB | constants::DATA_TYPE_HISTORY |
-                           constants::DATA_TYPE_CONTROLLED_FRAME,
-                       BrowsingDataFilterBuilder::Create(
-                           BrowsingDataFilterBuilder::Mode::kPreserve));
-
-  EXPECT_THAT(
-      removal_tasks,
-      UnorderedElementsAre(
-          RemovalInfo{DATA_TYPE_INDEXED_DB | constants::DATA_TYPE_HISTORY |
-                      constants::DATA_TYPE_CONTROLLED_FRAME},
-          RemovalInfo{DATA_TYPE_INDEXED_DB,
-                      iwa_url_info.storage_partition_config(GetProfile())},
-          RemovalInfo{DATA_TYPE_ON_STORAGE_PARTITION,
-                      controlled_frame_partition}));
-}
-
-TEST_F(IsolatedWebAppChromeBrowsingDataRemoverDelegateTest,
-       TimeRangeSpecified) {
-  const GURL iwa_url(
-      "isolated-app://"
-      "berugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic");
-  web_app::IsolatedWebAppUrlInfo iwa_url_info = InstallIsolatedWebApp(iwa_url);
-  content::StoragePartitionConfig controlled_frame_partition =
-      CreateControlledFrameStoragePartition(iwa_url_info, "controlled_frame");
-
-  std::vector<RemovalInfo> removal_tasks = ClearDataAndWait(
-      AnHourAgo(), base::Time::Max(),
-      DATA_TYPE_INDEXED_DB | constants::DATA_TYPE_CONTROLLED_FRAME,
-      BrowsingDataFilterBuilder::Create(
-          BrowsingDataFilterBuilder::Mode::kPreserve));
-
-  EXPECT_THAT(
-      removal_tasks,
-      UnorderedElementsAre(
-          RemovalInfo{DATA_TYPE_INDEXED_DB |
-                      constants::DATA_TYPE_CONTROLLED_FRAME},
-          RemovalInfo{DATA_TYPE_INDEXED_DB,
-                      iwa_url_info.storage_partition_config(GetProfile())},
-          RemovalInfo{DATA_TYPE_ON_STORAGE_PARTITION,
-                      controlled_frame_partition}));
-}
 #endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_LACROS)
 
 TEST_F(ChromeBrowsingDataRemoverDelegateTest, RemoveHistoryForever) {
@@ -2159,22 +1932,14 @@
 // Regression test for: https://crbug.com/1207632.
 TEST_F(ChromeBrowsingDataRemoverDelegateTest,
        DeleteBookmarksDoesNothingWhenModelNotLoaded) {
-  TestingProfile* profile = GetProfileManager()->CreateTestingProfile(
-      "bookmark_profile", {{BookmarkModelFactory::GetInstance(),
-                            BookmarkModelFactory::GetDefaultFactory()}});
+  TestingProfile* profile = GetProfile();
   bookmarks::BookmarkModel* bookmark_model =
       BookmarkModelFactory::GetForBrowserContext(profile);
   // For this test to exercise the code path that lead to the crash the
   // model must not be loaded yet.
   EXPECT_FALSE(bookmark_model->loaded());
-
-  content::BrowsingDataRemover* remover = profile->GetBrowsingDataRemover();
-  content::BrowsingDataRemoverCompletionObserver completion_observer(remover);
-  remover->RemoveAndReply(
-      base::Time(), base::Time::Max(), constants::DATA_TYPE_BOOKMARKS,
-      content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB,
-      &completion_observer);
-  completion_observer.BlockUntilCompletion();
+  BlockUntilBrowsingDataRemoved(base::Time(), base::Time::Max(),
+                                constants::DATA_TYPE_BOOKMARKS, false);
   // No crash means test passes.
 }
 
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_files_controller.cc b/chrome/browser/chromeos/policy/dlp/dlp_files_controller.cc
index 2eef50a..feedcd4 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_files_controller.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_files_controller.cc
@@ -103,18 +103,6 @@
   return false;
 }
 
-absl::optional<ino64_t> GetInodeValue(const base::FilePath& path) {
-  if (!IsInLocalFileSystem(path)) {
-    return absl::nullopt;
-  }
-
-  struct stat file_stats;
-  if (stat(path.value().c_str(), &file_stats) != 0) {
-    return absl::nullopt;
-  }
-  return file_stats.st_ino;
-}
-
 }  // namespace
 
 DlpFilesController::FileDaemonInfo::FileDaemonInfo(
@@ -178,10 +166,9 @@
   if (!dst_component.has_value()) {
     // We allow internal copy, we still have to get the scopedFS
     // and we might need to copy the source URL information.
-    auto inode = GetInodeValue(source_file.path());
-    if (inode) {
+    if (IsInLocalFileSystem(source_file.path())) {
       ::dlp::GetFilesSourcesRequest request;
-      request.add_files_inodes(inode.value());
+      request.add_files_paths(source_file.path().value());
       chromeos::DlpClient::Get()->GetFilesSources(
           request,
           base::BindOnce(&GotFilesSourcesOfCopy, destination,
diff --git a/chrome/browser/chromeos/policy/dlp/dlp_files_controller_unittest.cc b/chrome/browser/chromeos/policy/dlp/dlp_files_controller_unittest.cc
index b3e5b4a..f7bdac7 100644
--- a/chrome/browser/chromeos/policy/dlp/dlp_files_controller_unittest.cc
+++ b/chrome/browser/chromeos/policy/dlp/dlp_files_controller_unittest.cc
@@ -32,15 +32,6 @@
 namespace policy {
 
 namespace {
-
-absl::optional<ino64_t> GetInodeValue(const base::FilePath& path) {
-  struct stat file_stats;
-  if (stat(path.value().c_str(), &file_stats) != 0) {
-    return absl::nullopt;
-  }
-  return file_stats.st_ino;
-}
-
 using FileDaemonInfo = policy::DlpFilesController::FileDaemonInfo;
 }  // namespace
 
@@ -170,16 +161,13 @@
       chromeos::DlpClient::GetFilesSourcesCallback)>
       get_files_source_call;
 
-  absl::optional<ino64_t> inode = GetInodeValue(src_file);
-  EXPECT_TRUE(inode.has_value());
-
   ::dlp::GetFilesSourcesResponse response;
   auto* metadata = response.add_files_metadata();
   metadata->set_source_url("http://some.url/path");
-  metadata->set_inode(inode.value());
+  metadata->set_path(src_file.value());
 
   ::dlp::GetFilesSourcesRequest request;
-  request.add_files_inodes(inode.value());
+  request.add_files_paths(src_file.value());
 
   EXPECT_CALL(get_files_source_call,
               Run(EqualsProto(request), base::test::IsNotNullCallback()))
@@ -258,15 +246,13 @@
       chromeos::DlpClient::GetFilesSourcesCallback)>
       get_files_source_call;
 
-  absl::optional<ino64_t> inode = GetInodeValue(src_file);
-  EXPECT_TRUE(inode.has_value());
   ::dlp::GetFilesSourcesResponse response;
   auto* metadata = response.add_files_metadata();
   metadata->set_source_url("");
-  metadata->set_inode(inode.value());
+  metadata->set_path(src_file.value());
 
   ::dlp::GetFilesSourcesRequest request;
-  request.add_files_inodes(inode.value());
+  request.add_files_paths(src_file.value());
 
   EXPECT_CALL(get_files_source_call,
               Run(EqualsProto(request), base::test::IsNotNullCallback()))
diff --git a/chrome/browser/enterprise/idle/action_runner_unittest.cc b/chrome/browser/enterprise/idle/action_runner_unittest.cc
index 07b029c..8b0a66a 100644
--- a/chrome/browser/enterprise/idle/action_runner_unittest.cc
+++ b/chrome/browser/enterprise/idle/action_runner_unittest.cc
@@ -327,11 +327,6 @@
   uint64_t GetLastUsedOriginTypeMaskForTesting() override {
     return origin_type_mask_;
   }
-  absl::optional<content::StoragePartitionConfig>
-  GetLastUsedStoragePartitionConfigForTesting() override {
-    return absl::nullopt;
-  }
-  uint64_t GetPendingTaskCountForTesting() override { return 0; }
 
   void SetFailedDataTypesForTesting(uint64_t failed_data_types) {
     failed_data_types_ = failed_data_types;
diff --git a/chrome/browser/feedback/show_feedback_page.cc b/chrome/browser/feedback/show_feedback_page.cc
index ba549105..0664dc69 100644
--- a/chrome/browser/feedback/show_feedback_page.cc
+++ b/chrome/browser/feedback/show_feedback_page.cc
@@ -191,13 +191,6 @@
                            description_placeholder_text, category_tag,
                            extra_diagnostics, std::move(autofill_metadata));
 }
-
-void LaunchFeedbackSWA(Profile* profile, const GURL& url) {
-  ash::SystemAppLaunchParams params;
-  params.url = url;
-  ash::LaunchSystemWebAppAsync(profile, ash::SystemWebAppType::OS_FEEDBACK,
-                               std::move(params));
-}
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if !BUILDFLAG(IS_CHROMEOS_LACROS)
@@ -237,21 +230,12 @@
       base::FeatureList::IsEnabled(ash::features::kOsFeedback)) {
     // TODO(crbug.com/1407646): Include autofill metadata into CrOS new feedback
     // tool.
-    GURL url = BuildFeedbackUrl(extra_diagnostics, description_template,
-                                description_placeholder_text, category_tag,
-                                page_url, source, std::move(autofill_metadata));
-
-    // Wait for all SWAs to be registered before continuing.
-    // TODO(b/286291927): Figure out how to get the SWA manager for the guest
-    // mode profile and perhaps other exotic ones.
-    ash::SystemWebAppManager* swa_manager =
-        ash::SystemWebAppManager::Get(profile);
-    if (swa_manager) {
-      swa_manager->on_apps_synchronized().Post(
-          FROM_HERE, base::BindOnce(&LaunchFeedbackSWA, profile, url));
-    } else {
-      LaunchFeedbackSWA(profile, url);
-    }
+    ash::SystemAppLaunchParams params;
+    params.url = BuildFeedbackUrl(
+        extra_diagnostics, description_template, description_placeholder_text,
+        category_tag, page_url, source, std::move(autofill_metadata));
+    ash::LaunchSystemWebAppAsync(profile, ash::SystemWebAppType::OS_FEEDBACK,
+                                 std::move(params));
     return;
   }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 48008d2..15fa5ad 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -6320,13 +6320,6 @@
     "Enables wayland logging for Lacros. This generates a significant amount "
     "of logs on disk. Logs are cleared after two restarts.";
 
-const char kLacrosMoveProfileMigrationName[] = "Enforce profile move migration";
-const char kLacrosMoveProfileMigrationDescription[] =
-    "Enforce Lacros profile move migration which moves files from Ash profile "
-    "directory to Lacros profile directory instead of copying. Please note "
-    "that disabling Lacros and falling back to Ash after move migration is not "
-    "supported.";
-
 const char kLacrosProfileMigrationForceOffName[] = "Disable profile migration";
 const char kLacrosProfileMigrationForceOffDescription[] =
     "Disables lacros profile migration. Lacros profile migration is being "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 15810a0..825cd7d 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -3585,9 +3585,6 @@
 extern const char kImeTrayHideVoiceButtonName[];
 extern const char kImeTrayHideVoiceButtonDescription[];
 
-extern const char kLacrosMoveProfileMigrationName[];
-extern const char kLacrosMoveProfileMigrationDescription[];
-
 extern const char kLacrosProfileMigrationForceOffName[];
 extern const char kLacrosProfileMigrationForceOffDescription[];
 
diff --git a/chrome/browser/media/cast_mirroring_service_host.cc b/chrome/browser/media/cast_mirroring_service_host.cc
index 51cb7e9..df78b37c 100644
--- a/chrome/browser/media/cast_mirroring_service_host.cc
+++ b/chrome/browser/media/cast_mirroring_service_host.cc
@@ -49,7 +49,9 @@
 #include "media/mojo/mojom/audio_data_pipe.mojom.h"
 #include "media/mojo/mojom/audio_input_stream.mojom.h"
 #include "media/mojo/mojom/audio_processing.mojom.h"
+#include "media/mojo/services/video_encoder_metrics_provider.h"
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 #include "services/network/public/mojom/network_service.mojom.h"
 #include "services/viz/public/mojom/gpu.mojom.h"
@@ -310,6 +312,12 @@
                      weak_factory_for_ui_.GetWeakPtr()));
 }
 
+void CastMirroringServiceHost::GetVideoEncoderMetricsProvider(
+    mojo::PendingReceiver<media::mojom::VideoEncoderMetricsProvider> receiver) {
+  media::VideoEncoderMetricsProvider::Create(ukm::NoURLSourceId(),
+                                             std::move(receiver));
+}
+
 void CastMirroringServiceHost::SetVideoCaptureHost(
     mojo::SelfOwnedReceiverRef<media::mojom::VideoCaptureHost>
         video_capture_host) {
diff --git a/chrome/browser/media/cast_mirroring_service_host.h b/chrome/browser/media/cast_mirroring_service_host.h
index 042cfc0..e1bb0d5 100644
--- a/chrome/browser/media/cast_mirroring_service_host.h
+++ b/chrome/browser/media/cast_mirroring_service_host.h
@@ -88,6 +88,9 @@
   void BindGpu(mojo::PendingReceiver<viz::mojom::Gpu> receiver) override;
   void GetVideoCaptureHost(
       mojo::PendingReceiver<media::mojom::VideoCaptureHost> receiver) override;
+  void GetVideoEncoderMetricsProvider(
+      mojo::PendingReceiver<media::mojom::VideoEncoderMetricsProvider> receiver)
+      override;
   void GetNetworkContext(
       mojo::PendingReceiver<network::mojom::NetworkContext> receiver) override;
   void CreateAudioStream(
diff --git a/chrome/browser/resources/ash/settings/crostini_page/crostini_browser_proxy.ts b/chrome/browser/resources/ash/settings/crostini_page/crostini_browser_proxy.ts
index ceac01b2..c36e748 100644
--- a/chrome/browser/resources/ash/settings/crostini_page/crostini_browser_proxy.ts
+++ b/chrome/browser/resources/ash/settings/crostini_page/crostini_browser_proxy.ts
@@ -214,6 +214,8 @@
 
   getCrostiniActivePorts(): Promise<CrostiniPortActiveSetting[]>;
 
+  getCrostiniActiveNetworkInfo(): Promise<string[]>;
+
   checkCrostiniIsRunning(): Promise<boolean>;
 
   /**
@@ -415,6 +417,10 @@
     return sendWithPromise('getCrostiniActivePorts');
   }
 
+  getCrostiniActiveNetworkInfo(): Promise<string[]> {
+    return sendWithPromise('getCrostiniActiveNetworkInfo');
+  }
+
   checkCrostiniIsRunning(): Promise<boolean> {
     return sendWithPromise('checkCrostiniIsRunning');
   }
diff --git a/chrome/browser/resources/ash/settings/crostini_page/crostini_port_forwarding.html b/chrome/browser/resources/ash/settings/crostini_page/crostini_port_forwarding.html
index 39ab369..7bc8fc3 100644
--- a/chrome/browser/resources/ash/settings/crostini_page/crostini_port_forwarding.html
+++ b/chrome/browser/resources/ash/settings/crostini_page/crostini_port_forwarding.html
@@ -31,6 +31,10 @@
     formal UI spec is received. */
   }
 
+  .interface-ip {
+    padding-inline-start: 24px;
+  }
+
   #addPort {
     padding-top: 10px;
   }
@@ -73,6 +77,11 @@
     </cr-icon-button>
   </template>
 </div>
+<template is="dom-if" if="[[activeInterface_]]" restamp>
+    <div id="interface-ip" class="settings-box continuation">
+        [[activeInterface_]]: [[activeIpAddress_]]
+    </div>
+</template>
 <template is="dom-if" if="[[!allPorts_.length]]" restamp>
   <div id="no-ports-text"
       class="settings-box continuation">
diff --git a/chrome/browser/resources/ash/settings/crostini_page/crostini_port_forwarding.ts b/chrome/browser/resources/ash/settings/crostini_page/crostini_port_forwarding.ts
index 48ea2f6..b340f78 100644
--- a/chrome/browser/resources/ash/settings/crostini_page/crostini_port_forwarding.ts
+++ b/chrome/browser/resources/ash/settings/crostini_page/crostini_port_forwarding.ts
@@ -86,6 +86,22 @@
           return [];
         },
       },
+
+      /**
+       * Current active network interface to be displayed.
+       */
+      activeInterface_: {
+        type: String,
+        value: '',
+      },
+
+      /**
+       * Current active network IP to be displayed.
+       */
+      activeIpAddress_: {
+        type: String,
+        value: '',
+      },
     };
   }
 
@@ -98,6 +114,8 @@
   private activePorts_: CrostiniPortActiveSetting[];
   private allContainers_: ContainerInfo[];
   private allPorts_: CrostiniPortSetting[];
+  private activeInterface_: string;
+  private activeIpAddress_: string;
   private browserProxy_: CrostiniBrowserProxy;
   private lastMenuOpenedPort_: CrostiniPortActiveSetting|null;
   private showAddPortDialog_: boolean;
@@ -126,11 +144,23 @@
     this.addWebUiListener(
         'crostini-container-info',
         (infos: ContainerInfo[]) => this.onContainerInfo_(infos));
+    this.addWebUiListener(
+        'crostini-active-network-info',
+        (iface: string, ipAddress: string) =>
+            this.onCrostiniActiveNetworkInfo_([iface, ipAddress]));
     this.browserProxy_.getCrostiniActivePorts().then(
         (ports) => this.onCrostiniPortsActiveStateChanged_(ports));
+    this.browserProxy_.getCrostiniActiveNetworkInfo().then(
+        (networkInfo: string[]) =>
+            this.onCrostiniActiveNetworkInfo_(networkInfo));
     this.browserProxy_.requestContainerInfo();
   }
 
+  private onCrostiniActiveNetworkInfo_(networkInfo: string[]) {
+    this.set('activeInterface_', networkInfo[0]);
+    this.set('activeIpAddress_', networkInfo[1]);
+  }
+
   private onContainerInfo_(containerInfos: ContainerInfo[]) {
     this.set('allContainers_', containerInfos);
   }
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/visit_tile.html b/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/visit_tile.html
index cf106ab2..cc19255 100644
--- a/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/visit_tile.html
+++ b/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/visit_tile.html
@@ -36,8 +36,6 @@
   }
 
   :host([images-enabled_]) #label-container {
-    background: linear-gradient(0, rgba(0, 0, 0, 0) 0%,
-      rgba(0, 0, 0, 0.4) 69.79%);
     border-radius: var(--ntp-module-item-border-radius);
     color: var(--color-new-tab-page-primary-foreground);
     display: flex;
@@ -49,6 +47,11 @@
     z-index: 1;
   }
 
+  :host([images-enabled_][image-url_]) #label-container {
+    background: linear-gradient(0, rgba(0, 0, 0, 0) 0%,
+      rgba(0, 0, 0, 0.4) 69.79%);
+  }
+
   /*TODO: mfacey@: Fix label size */
   #label {
     max-width: 100px;
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/visit_tile.ts b/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/visit_tile.ts
index 533e0129..78a6c46 100644
--- a/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/visit_tile.ts
+++ b/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/visit_tile.ts
@@ -58,6 +58,7 @@
       imageUrl_: {
         type: Object,
         value: null,
+        reflectToAttribute: true,
       },
 
       format: {
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 4fd521d..847e707 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3442,6 +3442,7 @@
       "//chromeos/ash/components/drivefs",
       "//chromeos/ash/components/drivefs/mojom:mojom",
       "//chromeos/ash/components/fwupd",
+      "//chromeos/ash/components/heatmap",
       "//chromeos/ash/components/human_presence",
       "//chromeos/ash/components/install_attributes",
       "//chromeos/ash/components/local_search_service/public/cpp",
diff --git a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
index 93e9001..64595d6 100644
--- a/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
+++ b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
@@ -72,6 +72,7 @@
 #include "chrome/browser/ui/views/select_file_dialog_extension_factory.h"
 #include "chrome/browser/ui/views/tabs/tab_scrubber_chromeos.h"
 #include "chromeos/ash/components/dbus/dbus_thread_manager.h"
+#include "chromeos/ash/components/heatmap/heatmap_palm_detector.h"
 #include "chromeos/ash/components/network/network_connect.h"
 #include "chromeos/ash/components/network/portal_detector/network_portal_detector.h"
 #include "chromeos/ash/services/bluetooth_config/fast_pair_delegate.h"
@@ -87,6 +88,7 @@
 #include "services/device/public/cpp/geolocation/geolocation_manager.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "ui/base/ime/ash/input_method_manager.h"
+#include "ui/ozone/public/ozone_platform.h"
 
 #if BUILDFLAG(ENABLE_WAYLAND_SERVER)
 #include "chrome/browser/exo_parts.h"
@@ -282,6 +284,9 @@
   // Create geolocation manager
   device::GeolocationManager::SetInstance(
       ash::SystemGeolocationSource::CreateGeolocationManagerOnAsh());
+
+  ui::OzonePlatform::GetInstance()->SetPalmDetector(
+      std::make_unique<ash::HeatmapPalmDetector>());
 }
 
 void ChromeBrowserMainExtraPartsAsh::PostProfileInit(Profile* profile,
diff --git a/chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.cc b/chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.cc
index 2eac080..9227b4ce 100644
--- a/chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.cc
+++ b/chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.cc
@@ -116,33 +116,16 @@
 }
 
 SystemAppLaunchParams::SystemAppLaunchParams() = default;
+SystemAppLaunchParams::SystemAppLaunchParams(
+    const SystemAppLaunchParams& params) = default;
 SystemAppLaunchParams::~SystemAppLaunchParams() = default;
 
-void LaunchSystemWebAppAsync(Profile* profile,
-                             const SystemWebAppType type,
-                             const SystemAppLaunchParams& params,
-                             apps::WindowInfoPtr window_info) {
-  DCHECK(profile);
-  // Terminal should be launched with crostini::LaunchTerminal*.
-  DCHECK(type != SystemWebAppType::TERMINAL);
-
-  // TODO(https://crbug.com/1135863): Implement a confirmation dialog when
-  // changing to a different profile.
-  Profile* profile_for_launch = GetProfileForSystemWebAppLaunch(profile);
-  if (profile_for_launch == nullptr) {
-    // We can't find a suitable profile to launch. Complain about this so we
-    // can identify the call site, and ask them to pick the right profile.
-    base::debug::DumpWithoutCrashing();
-
-    DVLOG(1)
-        << "LaunchSystemWebAppAsync is called on a profile that can't launch "
-           "system web apps. The launch request is ignored. Please check the "
-           "profile you are using is correct.";
-
-    // This will DCHECK in debug builds. But no-op in production builds.
-    NOTREACHED();
-
-    // Early return if we can't find a profile to launch.
+namespace {
+void LaunchSystemWebAppAsyncContinue(Profile* profile_for_launch,
+                                     const SystemWebAppType type,
+                                     const SystemAppLaunchParams& params,
+                                     apps::WindowInfoPtr window_info) {
+  if (profile_for_launch->ShutdownStarted()) {
     return;
   }
 
@@ -176,6 +159,47 @@
   app_service->Launch(*app_id, event_flags, params.launch_source,
                       std::move(window_info));
 }
+}  // namespace
+
+void LaunchSystemWebAppAsync(Profile* profile,
+                             const SystemWebAppType type,
+                             const SystemAppLaunchParams& params,
+                             apps::WindowInfoPtr window_info) {
+  DCHECK(profile);
+  // Terminal should be launched with crostini::LaunchTerminal*.
+  DCHECK(type != SystemWebAppType::TERMINAL);
+
+  // TODO(https://crbug.com/1135863): Implement a confirmation dialog when
+  // changing to a different profile.
+  Profile* profile_for_launch = GetProfileForSystemWebAppLaunch(profile);
+  if (profile_for_launch == nullptr) {
+    // We can't find a suitable profile to launch. Complain about this so we
+    // can identify the call site, and ask them to pick the right profile.
+    base::debug::DumpWithoutCrashing();
+
+    DVLOG(1)
+        << "LaunchSystemWebAppAsync is called on a profile that can't launch "
+           "system web apps. The launch request is ignored. Please check the "
+           "profile you are using is correct.";
+
+    // This will DCHECK in debug builds. But no-op in production builds.
+    NOTREACHED();
+
+    // Early return if we can't find a profile to launch.
+    return;
+  }
+
+  SystemWebAppManager* manager = SystemWebAppManager::Get(profile_for_launch);
+  if (!manager) {
+    return;
+  }
+
+  // Wait for all SWAs to be registered before continuing.
+  manager->on_apps_synchronized().Post(
+      FROM_HERE,
+      base::BindOnce(&LaunchSystemWebAppAsyncContinue, profile_for_launch, type,
+                     params, std::move(window_info)));
+}
 
 Browser* LaunchSystemWebAppImpl(Profile* profile,
                                 SystemWebAppType app_type,
diff --git a/chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h b/chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h
index 60c5a233..5cbe640 100644
--- a/chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h
+++ b/chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h
@@ -38,6 +38,7 @@
 // Additional parameters to control LaunchSystemAppAsync behaviors.
 struct SystemAppLaunchParams {
   SystemAppLaunchParams();
+  SystemAppLaunchParams(const SystemAppLaunchParams& params);
   ~SystemAppLaunchParams();
 
   // If provided launches System Apps into |url|, instead of its start_url (as
@@ -73,9 +74,9 @@
 // In tests, remember to use content::TestNavigationObserver to wait for the
 // navigation.
 //
-// NOTE: LaunchSystemWebAppAsync may have no effect if called before the initial
-// registration of system web apps has completed. To avoid this, first await the
-// ash::SystemWebAppManager::on_apps_synchronized event.
+// NOTE: LaunchSystemWebAppAsync waits for the initial registration of system
+// web apps to complete (the ash::SystemWebAppManager::on_apps_synchronized
+// event).
 void LaunchSystemWebAppAsync(
     Profile* profile,
     SystemWebAppType type,
diff --git a/chrome/browser/ui/webui/settings/ash/crostini_handler.cc b/chrome/browser/ui/webui/settings/ash/crostini_handler.cc
index df2fd3e6..c629792 100644
--- a/chrome/browser/ui/webui/settings/ash/crostini_handler.cc
+++ b/chrome/browser/ui/webui/settings/ash/crostini_handler.cc
@@ -31,6 +31,7 @@
 #include "chrome/browser/ui/views/crostini/crostini_uninstaller_view.h"
 #include "chrome/browser/ui/webui/ash/crostini_upgrader/crostini_upgrader_dialog.h"
 #include "chrome/common/pref_names.h"
+#include "chromeos/ash/components/network/network_handler.h"
 #include "components/prefs/pref_service.h"
 #include "components/services/app_service/public/cpp/intent_util.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -152,6 +153,10 @@
       base::BindRepeating(&CrostiniHandler::HandleGetCrostiniActivePorts,
                           handler_weak_ptr_factory_.GetWeakPtr()));
   web_ui()->RegisterMessageCallback(
+      "getCrostiniActiveNetworkInfo",
+      base::BindRepeating(&CrostiniHandler::HandleGetCrostiniActiveNetworkInfo,
+                          handler_weak_ptr_factory_.GetWeakPtr()));
+  web_ui()->RegisterMessageCallback(
       "checkCrostiniIsRunning",
       base::BindRepeating(&CrostiniHandler::HandleCheckCrostiniIsRunning,
                           handler_weak_ptr_factory_.GetWeakPtr()));
@@ -515,6 +520,11 @@
                     activePorts);
 }
 
+void CrostiniHandler::OnActiveNetworkChanged(const base::Value& interface,
+                                             const base::Value& ipAddress) {
+  FireWebUIListener("crostini-active-network-info", interface, ipAddress);
+}
+
 void CrostiniHandler::HandleAddCrostiniPortForward(
     const base::Value::List& args) {
   CHECK_EQ(5U, args.size());
@@ -677,6 +687,18 @@
           ->GetActivePorts());
 }
 
+void CrostiniHandler::HandleGetCrostiniActiveNetworkInfo(
+    const base::Value::List& args) {
+  AllowJavascript();
+  CHECK_EQ(1U, args.size());
+
+  std::string callback_id = args[0].GetString();
+  ResolveJavascriptCallback(
+      base::Value(callback_id),
+      crostini::CrostiniPortForwarder::GetForProfile(profile_)
+          ->GetActiveNetworkInfo());
+}
+
 void CrostiniHandler::HandleCheckCrostiniIsRunning(
     const base::Value::List& args) {
   AllowJavascript();
diff --git a/chrome/browser/ui/webui/settings/ash/crostini_handler.h b/chrome/browser/ui/webui/settings/ash/crostini_handler.h
index 2493b5f..6eda1869 100644
--- a/chrome/browser/ui/webui/settings/ash/crostini_handler.h
+++ b/chrome/browser/ui/webui/settings/ash/crostini_handler.h
@@ -18,6 +18,7 @@
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "chromeos/ash/components/dbus/session_manager/session_manager_client.h"
+#include "chromeos/ash/components/network/network_state_handler_observer.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/services/app_service/public/cpp/intent.h"
 
@@ -104,6 +105,8 @@
   void HandleRemoveAllCrostiniPortForwards(const base::Value::List& args);
   // CrostiniPortForwarder::Observer.
   void OnActivePortsChanged(const base::Value::List& activePorts) override;
+  void OnActiveNetworkChanged(const base::Value& interface,
+                              const base::Value& ipAddress) override;
   // Handles a request for activating an existing port.
   void HandleActivateCrostiniPortForward(const base::Value::List& args);
   // Handles a request for deactivating an existing port.
@@ -121,6 +124,8 @@
                                          bool succeeded);
   // Returns a list of currently forwarded ports.
   void HandleGetCrostiniActivePorts(const base::Value::List& args);
+  // Returns the current active network for forwarded ports.
+  void HandleGetCrostiniActiveNetworkInfo(const base::Value::List& args);
   // Checks if Crostini is running.
   void HandleCheckCrostiniIsRunning(const base::Value::List& args);
   // guest_os::ContainerStartedObserver
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index 97af49b..0b4d971 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -882,7 +882,6 @@
     "//chrome/app:command_ids",
     "//chrome/browser/apps/app_service",
     "//chrome/browser/apps/app_service:test_support",
-    "//chrome/browser/browsing_data:constants",
     "//chrome/browser/devtools:test_support",
     "//chrome/browser/profiles:profile",
     "//chrome/test:test_support",
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_browsing_data_browsertest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_browsing_data_browsertest.cc
index 3854ebe..f205c3f 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_browsing_data_browsertest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_browsing_data_browsertest.cc
@@ -6,12 +6,9 @@
 #include <string>
 
 #include "base/check_deref.h"
-#include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_future.h"
 #include "base/time/time.h"
-#include "chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h"
-#include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/web_applications/test/isolated_web_app_test_utils.h"
@@ -19,8 +16,6 @@
 #include "chrome/browser/web_applications/web_app_command_scheduler.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "components/services/storage/public/mojom/local_storage_control.mojom.h"
-#include "content/public/browser/browsing_data_filter_builder.h"
-#include "content/public/browser/browsing_data_remover.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
@@ -75,7 +70,7 @@
                                               : 0;
   }
 
-  void AddLocalStorageIfMissing(const content::ToRenderFrameHost& target) {
+  void AddUsageIfMissing(const content::ToRenderFrameHost& target) {
     EXPECT_TRUE(
         ExecJs(target, "localStorage.setItem('test', '!'.repeat(1000))"));
 
@@ -121,7 +116,7 @@
   EXPECT_THAT(GetIwaUsage(url_info), Eq(0));
 
   // Add some usage to the IWA and make sure it's counted.
-  AddLocalStorageIfMissing(web_contents);
+  AddUsageIfMissing(web_contents);
   EXPECT_THAT(GetIwaUsage(url_info), IsApproximately(1000));
 
   // Create a persisted <controlledframe>, add some usage to it.
@@ -129,7 +124,7 @@
                                     dev_server()->GetURL("/empty_title.html"),
                                     "persist:partition_name"));
   ASSERT_EQ(1UL, web_contents->GetInnerWebContents().size());
-  AddLocalStorageIfMissing(web_contents->GetInnerWebContents()[0]);
+  AddUsageIfMissing(web_contents->GetInnerWebContents()[0]);
   EXPECT_THAT(GetIwaUsage(url_info), IsApproximately(2000));
 
   // Create another persisted <controlledframe> with a different partition name.
@@ -137,49 +132,23 @@
                                     dev_server()->GetURL("/empty_title.html"),
                                     "persist:partition_name_2"));
   ASSERT_EQ(2UL, web_contents->GetInnerWebContents().size());
-  AddLocalStorageIfMissing(web_contents->GetInnerWebContents()[0]);
-  AddLocalStorageIfMissing(web_contents->GetInnerWebContents()[1]);
+  AddUsageIfMissing(web_contents->GetInnerWebContents()[0]);
+  AddUsageIfMissing(web_contents->GetInnerWebContents()[1]);
   EXPECT_THAT(GetIwaUsage(url_info), IsApproximately(3000));
 
   // Create an in-memory <controlledframe> that won't count towards IWA usage.
   ASSERT_TRUE(CreateControlledFrame(
       web_contents, dev_server()->GetURL("/empty_title.html"), "unpersisted"));
   ASSERT_EQ(3UL, web_contents->GetInnerWebContents().size());
-  AddLocalStorageIfMissing(web_contents->GetInnerWebContents()[0]);
-  AddLocalStorageIfMissing(web_contents->GetInnerWebContents()[1]);
-  AddLocalStorageIfMissing(web_contents->GetInnerWebContents()[2]);
+  AddUsageIfMissing(web_contents->GetInnerWebContents()[0]);
+  AddUsageIfMissing(web_contents->GetInnerWebContents()[1]);
+  AddUsageIfMissing(web_contents->GetInnerWebContents()[2]);
   EXPECT_THAT(GetIwaUsage(url_info), IsApproximately(3000));
 }
 
 class IsolatedWebAppBrowsingDataClearingTest
     : public IsolatedWebAppBrowsingDataTest {
  protected:
-  void ClearData(const IsolatedWebAppUrlInfo& url_info) {
-    base::RunLoop run_loop;
-    auto* browsing_data_remover = profile()->GetBrowsingDataRemover();
-    browsing_data_remover->SetWouldCompleteCallbackForTesting(
-        base::BindLambdaForTesting([&](base::OnceClosure callback) {
-          if (browsing_data_remover->GetPendingTaskCountForTesting() == 1) {
-            run_loop.Quit();
-          }
-          std::move(callback).Run();
-        }));
-
-    auto filter = content::BrowsingDataFilterBuilder::Create(
-        content::BrowsingDataFilterBuilder::Mode::kDelete);
-    filter->AddOrigin(url_info.origin());
-
-    browsing_data_remover->RemoveWithFilter(
-        /*delete_begin=*/base::Time(), /*delete_end=*/base::Time::Max(),
-        chrome_browsing_data_remover::DATA_TYPE_SITE_DATA &
-            ~content::BrowsingDataRemover::DATA_TYPE_COOKIES,
-        chrome_browsing_data_remover::ALL_ORIGIN_TYPES, std::move(filter));
-    run_loop.Run();
-
-    browsing_data_remover->SetWouldCompleteCallbackForTesting(
-        base::DoNothing());
-  }
-
   int64_t GetCacheSize(const IsolatedWebAppUrlInfo& url_info) {
     base::test::TestFuture<bool, int64_t> future;
 
@@ -239,40 +208,6 @@
   }
 };
 
-IN_PROC_BROWSER_TEST_F(IsolatedWebAppBrowsingDataClearingTest,
-                       LocalStorageCleared) {
-  // Install 2 IWAs and add data to each.
-  IsolatedWebAppUrlInfo url_info1 = InstallIsolatedWebApp();
-  Browser* browser1 = LaunchWebAppBrowserAndWait(url_info1.app_id());
-  content::WebContents* web_contents1 =
-      browser1->tab_strip_model()->GetActiveWebContents();
-
-  EXPECT_THAT(GetIwaUsage(url_info1), Eq(0));
-  AddLocalStorageIfMissing(web_contents1);
-  EXPECT_THAT(GetIwaUsage(url_info1), IsApproximately(1000));
-
-  IsolatedWebAppUrlInfo url_info2 = InstallIsolatedWebApp();
-  Browser* browser2 = LaunchWebAppBrowserAndWait(url_info2.app_id());
-  content::WebContents* web_contents2 =
-      browser2->tab_strip_model()->GetActiveWebContents();
-
-  EXPECT_THAT(GetIwaUsage(url_info2), Eq(0));
-  AddLocalStorageIfMissing(web_contents2);
-  EXPECT_THAT(GetIwaUsage(url_info2), IsApproximately(1000));
-
-  ASSERT_TRUE(CreateControlledFrame(web_contents2,
-                                    dev_server()->GetURL("/empty_title.html"),
-                                    "persist:partition_name"));
-  ASSERT_EQ(1UL, web_contents2->GetInnerWebContents().size());
-  AddLocalStorageIfMissing(web_contents2->GetInnerWebContents()[0]);
-  EXPECT_THAT(GetIwaUsage(url_info2), IsApproximately(2000));
-
-  ClearData(url_info2);
-
-  EXPECT_THAT(GetIwaUsage(url_info1), IsApproximately(1000));
-  EXPECT_THAT(GetIwaUsage(url_info2), Eq(0));
-}
-
 IN_PROC_BROWSER_TEST_F(IsolatedWebAppBrowsingDataClearingTest, CacheCleared) {
   IsolatedWebAppUrlInfo url_info = InstallIsolatedWebApp();
 
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory_browsertest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory_browsertest.cc
index 8ac53bf..cb663c4 100644
--- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory_browsertest.cc
+++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_loader_factory_browsertest.cc
@@ -102,7 +102,7 @@
 
   std::unique_ptr<KeyedService> CreateWebAppProvider(Profile* profile) {
     auto provider = std::make_unique<FakeWebAppProvider>(profile);
-    provider->SetDefaultFakeSubsystems();
+    provider->CreateFakeSubsystems();
     provider->Start();
 
     return provider;
diff --git a/chrome/browser/web_applications/preinstalled_web_app_window_experiment_browsertest.cc b/chrome/browser/web_applications/preinstalled_web_app_window_experiment_browsertest.cc
index 96935de..6517f9d 100644
--- a/chrome/browser/web_applications/preinstalled_web_app_window_experiment_browsertest.cc
+++ b/chrome/browser/web_applications/preinstalled_web_app_window_experiment_browsertest.cc
@@ -225,9 +225,9 @@
     auto provider = std::make_unique<FakeWebAppProvider>(profile);
 
     // Use default fakes for fake working sync system.
-    provider->SetDefaultFakeSubsystems();
+    provider->CreateFakeSubsystems();
 
-    // Added by `SetDefaultFakeSubsystems`. Re-enable default apps as
+    // Added by `CreateFakeSubsystems`. Re-enable default apps as
     // we wish to test effects on them.
     base::CommandLine::ForCurrentProcess()->RemoveSwitch(
         switches::kDisableDefaultApps);
diff --git a/chrome/browser/web_applications/test/fake_web_app_provider.cc b/chrome/browser/web_applications/test/fake_web_app_provider.cc
index 159736e..22e1d29 100644
--- a/chrome/browser/web_applications/test/fake_web_app_provider.cc
+++ b/chrome/browser/web_applications/test/fake_web_app_provider.cc
@@ -11,13 +11,11 @@
 #include "base/check.h"
 #include "base/command_line.h"
 #include "base/functional/bind.h"
-#include "base/functional/callback_helpers.h"
-#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/one_shot_event.h"
-#include "base/test/bind.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/externally_managed_app_manager.h"
+#include "chrome/browser/web_applications/file_utils_wrapper.h"
 #include "chrome/browser/web_applications/isolated_web_apps/install_isolated_web_app_from_command_line.h"
 #include "chrome/browser/web_applications/manifest_update_manager.h"
 #include "chrome/browser/web_applications/os_integration/os_integration_manager.h"
@@ -35,14 +33,13 @@
 #include "chrome/browser/web_applications/web_app_icon_manager.h"
 #include "chrome/browser/web_applications/web_app_install_finalizer.h"
 #include "chrome/browser/web_applications/web_app_install_manager.h"
+#include "chrome/browser/web_applications/web_app_origin_association_manager.h"
 #include "chrome/browser/web_applications/web_app_provider_factory.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
 #include "chrome/browser/web_applications/web_app_translation_manager.h"
 #include "chrome/browser/web_applications/web_app_ui_manager.h"
 #include "chrome/browser/web_applications/web_app_utils.h"
-#include "chrome/browser/web_applications/web_contents/web_app_data_retriever.h"
-#include "chrome/browser/web_applications/web_contents/web_app_url_loader.h"
 #include "chrome/browser/web_applications/web_contents/web_contents_manager.h"
 #include "chrome/common/chrome_switches.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
@@ -50,8 +47,9 @@
 #include "components/sync/test/mock_model_type_change_processor.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
-#if (BUILDFLAG(IS_CHROMEOS))
+#if BUILDFLAG(IS_CHROMEOS)
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager.h"
+#include "chrome/browser/web_applications/web_app_run_on_os_login_manager.h"
 #endif
 
 namespace web_app {
@@ -65,9 +63,9 @@
   // Do not call default production StartImpl if in TestingProfile.
   provider->SetRunSubsystemStartupTasks(false);
 
-  // TODO(crbug.com/973324): Consider calling `SetDefaultFakeSubsystems` in the
+  // TODO(crbug.com/973324): Consider calling `CreateFakeSubsystems` in the
   // constructor instead.
-  provider->SetDefaultFakeSubsystems();
+  provider->CreateFakeSubsystems();
   provider->ConnectSubsystems();
 
   return provider;
@@ -286,13 +284,12 @@
   Start();
 }
 
-void FakeWebAppProvider::SetDefaultFakeSubsystems() {
+void FakeWebAppProvider::CreateFakeSubsystems() {
   // Disable preinstalled apps by default as they add noise and time to tests
   // that don't need them.
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kDisableDefaultApps);
 
-  SetRegistrar(std::make_unique<WebAppRegistrarMutable>(profile_));
   SetDatabaseFactory(std::make_unique<FakeWebAppDatabaseFactory>());
 
   SetWebContentsManager(std::make_unique<FakeWebContentsManager>());
@@ -313,19 +310,8 @@
   SetExternallyManagedAppManager(
       std::make_unique<FakeExternallyManagedAppManager>(profile_));
 
-  SetWebAppPolicyManager(std::make_unique<WebAppPolicyManager>(profile_));
-
-  SetCommandManager(std::make_unique<WebAppCommandManager>(profile_));
-
-  SetPreinstalledWebAppManager(
-      std::make_unique<PreinstalledWebAppManager>(profile_));
-
-#if BUILDFLAG(IS_CHROMEOS)
-  SetIsolatedWebAppUpdateManager(
-      std::make_unique<IsolatedWebAppUpdateManager>(*profile_));
-  SetWebAppRunOnOsLoginManager(
-      std::make_unique<WebAppRunOnOsLoginManager>(command_scheduler_.get()));
-#endif
+  // Do not create real subsystems here. That will be done already by
+  // WebAppProvider::CreateSubsystems in the WebAppProvider constructor.
 
   ON_CALL(processor(), IsTrackingMetadata())
       .WillByDefault(testing::Return(true));
@@ -346,7 +332,7 @@
     externally_managed_app_manager_->Shutdown();
   if (manifest_update_manager_)
     manifest_update_manager_->Shutdown();
-#if (BUILDFLAG(IS_CHROMEOS))
+#if BUILDFLAG(IS_CHROMEOS)
   if (iwa_update_manager_) {
     iwa_update_manager_->Shutdown();
   }
diff --git a/chrome/browser/web_applications/test/fake_web_app_provider.h b/chrome/browser/web_applications/test/fake_web_app_provider.h
index aed1da6..a267841 100644
--- a/chrome/browser/web_applications/test/fake_web_app_provider.h
+++ b/chrome/browser/web_applications/test/fake_web_app_provider.h
@@ -10,15 +10,11 @@
 #include "base/callback_list.h"
 #include "base/functional/callback.h"
 #include "base/memory/scoped_refptr.h"
-#include "chrome/browser/web_applications/test/test_file_utils.h"
+#include "build/build_config.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "components/sync/test/mock_model_type_change_processor.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
-#if BUILDFLAG(IS_CHROMEOS)
-#include "chrome/browser/web_applications/web_app_run_on_os_login_manager.h"
-#endif
-
 class KeyedService;
 class Profile;
 
@@ -30,12 +26,17 @@
 
 class AbstractWebAppDatabaseFactory;
 class ExternallyManagedAppManager;
+class FileUtilsWrapper;
+class IsolatedWebAppCommandLineInstallManager;
+class IsolatedWebAppUpdateManager;
 class OsIntegrationManager;
 class PreinstalledWebAppManager;
 class WebAppCommandManager;
+class WebAppCommandScheduler;
 class WebAppIconManager;
 class WebAppInstallFinalizer;
 class WebAppInstallManager;
+class WebAppOriginAssociationManager;
 class WebAppPolicyManager;
 class WebAppRegistrarMutable;
 class WebAppSyncBridge;
@@ -43,6 +44,10 @@
 class WebAppUiManager;
 class WebContentsManager;
 
+#if BUILDFLAG(IS_CHROMEOS)
+class WebAppRunOnOsLoginManager;
+#endif
+
 // This is a tool that allows unit tests (enabled by default) and browser tests
 // (disabled by default) to use a 'fake' version of the WebAppProvider system.
 // This means that most of the dependencies are faked out. Specifically:
@@ -183,7 +188,7 @@
   void StartWithSubsystems();
 
   // Create and set default fake subsystems.
-  void SetDefaultFakeSubsystems();
+  void CreateFakeSubsystems();
 
   // Used to verify shutting down of WebAppUiManager.
   void ShutDownUiManagerForTesting();
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc
index 78dc42d..475a968 100644
--- a/chrome/browser/web_applications/web_app_provider.cc
+++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -53,7 +53,7 @@
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/web_contents.h"
 
-#if (BUILDFLAG(IS_CHROMEOS))
+#if BUILDFLAG(IS_CHROMEOS)
 #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_update_manager.h"
 #endif
 
@@ -220,7 +220,7 @@
   return *iwa_command_line_install_manager_;
 }
 
-#if (BUILDFLAG(IS_CHROMEOS))
+#if BUILDFLAG(IS_CHROMEOS)
 IsolatedWebAppUpdateManager& WebAppProvider::iwa_update_manager() {
   CheckIsConnected();
   return *iwa_update_manager_;
@@ -288,7 +288,7 @@
   ui_manager_->Shutdown();
   externally_managed_app_manager_->Shutdown();
   manifest_update_manager_->Shutdown();
-#if (BUILDFLAG(IS_CHROMEOS))
+#if BUILDFLAG(IS_CHROMEOS)
   iwa_update_manager_->Shutdown();
 #endif
   install_manager_->Shutdown();
@@ -319,7 +319,7 @@
   web_app_policy_manager_ = std::make_unique<WebAppPolicyManager>(profile);
   iwa_command_line_install_manager_ =
       std::make_unique<IsolatedWebAppCommandLineInstallManager>(*profile);
-#if (BUILDFLAG(IS_CHROMEOS))
+#if BUILDFLAG(IS_CHROMEOS)
   iwa_update_manager_ = std::make_unique<IsolatedWebAppUpdateManager>(*profile);
 #endif
   extensions_manager_ = std::make_unique<ExtensionsManager>(profile);
@@ -359,7 +359,7 @@
   origin_association_manager_ =
       std::make_unique<WebAppOriginAssociationManager>();
 
-#if (BUILDFLAG(IS_CHROMEOS))
+#if BUILDFLAG(IS_CHROMEOS)
   web_app_run_on_os_login_manager_ =
       std::make_unique<WebAppRunOnOsLoginManager>(command_scheduler_.get());
 #endif
@@ -387,7 +387,7 @@
   command_manager_->SetProvider(pass_key, *this);
   command_scheduler_->SetProvider(pass_key, *this);
   iwa_command_line_install_manager_->SetProvider(pass_key, *this);
-#if (BUILDFLAG(IS_CHROMEOS))
+#if BUILDFLAG(IS_CHROMEOS)
   iwa_update_manager_->SetProvider(pass_key, *this);
 #endif
   icon_manager_->SetProvider(pass_key, *this);
@@ -428,7 +428,7 @@
   web_app_policy_manager_->Start(external_manager_barrier);
   iwa_command_line_install_manager_->Start();
 
-#if (BUILDFLAG(IS_CHROMEOS))
+#if BUILDFLAG(IS_CHROMEOS)
   iwa_update_manager_->Start();
 
   on_external_managers_synchronized_.Post(
diff --git a/chrome/browser/web_applications/web_app_provider.h b/chrome/browser/web_applications/web_app_provider.h
index 0a80931b..28985b6 100644
--- a/chrome/browser/web_applications/web_app_provider.h
+++ b/chrome/browser/web_applications/web_app_provider.h
@@ -18,7 +18,7 @@
 #include "chrome/browser/web_applications/web_app_registrar.h"
 #include "components/keyed_service/core/keyed_service.h"
 
-#if (BUILDFLAG(IS_CHROMEOS))
+#if BUILDFLAG(IS_CHROMEOS)
 #include "chrome/browser/web_applications/web_app_run_on_os_login_manager.h"
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
@@ -37,7 +37,7 @@
 class AbstractWebAppDatabaseFactory;
 class ExtensionsManager;
 class IsolatedWebAppCommandLineInstallManager;
-#if (BUILDFLAG(IS_CHROMEOS))
+#if BUILDFLAG(IS_CHROMEOS)
 class IsolatedWebAppUpdateManager;
 #endif
 class ManifestUpdateManager;
@@ -154,7 +154,7 @@
   // Clients can use `IsolatedWebAppCommandLineInstallManager` to request the
   // installation of IWAs based on command line switches.
   IsolatedWebAppCommandLineInstallManager& iwa_command_line_install_manager();
-#if (BUILDFLAG(IS_CHROMEOS))
+#if BUILDFLAG(IS_CHROMEOS)
   // Keeps Isolated Web Apps up to date by regularly checking for updates,
   // downloading them, and applying them.
   // TODO(crbug.com/1458725): We currently only support automatic updates on
@@ -247,7 +247,7 @@
   std::unique_ptr<WebAppPolicyManager> web_app_policy_manager_;
   std::unique_ptr<IsolatedWebAppCommandLineInstallManager>
       iwa_command_line_install_manager_;
-#if (BUILDFLAG(IS_CHROMEOS))
+#if BUILDFLAG(IS_CHROMEOS)
   std::unique_ptr<IsolatedWebAppUpdateManager> iwa_update_manager_;
   std::unique_ptr<WebAppRunOnOsLoginManager> web_app_run_on_os_login_manager_;
 #endif  // BUILDFLAG(IS_CHROMEOS)
diff --git a/chrome/build/lacros-arm.pgo.txt b/chrome/build/lacros-arm.pgo.txt
index 405f436..33a35a1e 100644
--- a/chrome/build/lacros-arm.pgo.txt
+++ b/chrome/build/lacros-arm.pgo.txt
@@ -1 +1 @@
-chrome-chromeos-arm-generic-main-1690113600-caacd2b17b14052a6a364b2f6f1298b6bbb48135.profdata
+chrome-chromeos-arm-generic-main-1690156379-97ac2ab8a66719eb8f6aec662f9a5af873b64968.profdata
diff --git a/chrome/build/lacros-arm64.pgo.txt b/chrome/build/lacros-arm64.pgo.txt
index 5e912d3..21a334b 100644
--- a/chrome/build/lacros-arm64.pgo.txt
+++ b/chrome/build/lacros-arm64.pgo.txt
@@ -1 +1 @@
-chrome-chromeos-arm64-generic-main-1690113600-0ddb7da04aaccb3663a4178e28ceaffcd291b651.profdata
+chrome-chromeos-arm64-generic-main-1690156379-770d24ea37d44ee5ae5ade477c5db357e2179e15.profdata
diff --git a/chrome/build/lacros64.pgo.txt b/chrome/build/lacros64.pgo.txt
index 017ef021..fcf46c28 100644
--- a/chrome/build/lacros64.pgo.txt
+++ b/chrome/build/lacros64.pgo.txt
@@ -1 +1 @@
-chrome-chromeos-amd64-generic-main-1690113600-a1d73477bfbcbfccab7c5379aa03cbe6fd10e5bf.profdata
+chrome-chromeos-amd64-generic-main-1690156379-648492e5d6f0a70a64ac9c6b6cd439fb3e597132.profdata
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 374b57b..6cfa4878 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1690112712-cf39c9df0d18c7744dd6614265ea9cf6797f29e0.profdata
+chrome-linux-main-1690134415-023b3abe8da1638455bd4a6df9f5c2a5205c1268.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 2887f87..5cf8ba4 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1690126176-cb02b30eb700a947b6a68d65824adfed9266e6c2.profdata
+chrome-mac-arm-main-1690171179-16207763879088fb41430078a2ce372fbeef0563.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 24634b4..239c234c 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1690112712-e6c9c126d45e69b4a3f4f092329fe95874342b89.profdata
+chrome-mac-main-1690156379-6d9481a79cdd3839358b02625ca8b670898062d1.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 488d01f..d2937de 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1690123893-c611f38c703370c2cc5e170afb82548ff9df2151.profdata
+chrome-win32-main-1690167544-0d1ed3bbd220955ad6caa8eb2555e615fb7da2b1.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 0233547..b6aa737 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1690123893-efc0362f0b4d936a8395a4f962bcb5b030db7a37.profdata
+chrome-win64-main-1690167544-7505402de4c469792a781ac6f1a083f5e521c329.profdata
diff --git a/chrome/test/data/video_conference_demo.html b/chrome/test/data/video_conference_demo.html
index 32fef3a..02dcb9d4 100644
--- a/chrome/test/data/video_conference_demo.html
+++ b/chrome/test/data/video_conference_demo.html
@@ -25,7 +25,7 @@
             audio_track.stop();
         }
         async function startScreenSharing() {
-            let stream = await navigator.mediaDevices.getDisplayMedia({ preferCurrentTab: true })
+            let stream = await navigator.mediaDevices.getDisplayMedia({video: true});
             screen_track = stream.getTracks()[0]
         }
         function stopScreenSharing() {
diff --git a/chrome/test/data/webui/settings/chromeos/test_crostini_browser_proxy.js b/chrome/test/data/webui/settings/chromeos/test_crostini_browser_proxy.js
index f96f182..0e6bafe 100644
--- a/chrome/test/data/webui/settings/chromeos/test_crostini_browser_proxy.js
+++ b/chrome/test/data/webui/settings/chromeos/test_crostini_browser_proxy.js
@@ -25,6 +25,7 @@
       'activateCrostiniPortForward',
       'deactivateCrostiniPortForward',
       'getCrostiniActivePorts',
+      'getCrostiniActiveNetworkInfo',
       'checkCrostiniIsRunning',
       'shutdownCrostini',
       'setCrostiniMicSharingEnabled',
@@ -178,6 +179,11 @@
     return Promise.resolve([]);
   }
 
+  getCrostiniActiveNetworkInfo() {
+    this.methodCalled('getCrostiniActiveNetworkInfo');
+    return Promise.resolve([]);
+  }
+
   /** @override */
   getCrostiniDiskInfo(vmName, requestFullInfo) {
     this.methodCalled('getCrostiniDiskInfo', vmName, requestFullInfo);
diff --git a/chromeos/ash/components/heatmap/BUILD.gn b/chromeos/ash/components/heatmap/BUILD.gn
index 6da0ed1..0240fa9b 100644
--- a/chromeos/ash/components/heatmap/BUILD.gn
+++ b/chromeos/ash/components/heatmap/BUILD.gn
@@ -10,6 +10,8 @@
   sources = [
     "heatmap_ml_agent.cc",
     "heatmap_ml_agent.h",
+    "heatmap_palm_detector.cc",
+    "heatmap_palm_detector.h",
   ]
 
   deps = [
@@ -17,13 +19,17 @@
     "//chromeos/services/machine_learning/public/cpp",
     "//chromeos/services/machine_learning/public/mojom",
     "//mojo/public/cpp/bindings",
+    "//ui/ozone",
   ]
 }
 
 source_set("unit_tests") {
   testonly = true
 
-  sources = [ "heatmap_ml_agent_unittest.cc" ]
+  sources = [
+    "heatmap_ml_agent_unittest.cc",
+    "heatmap_palm_detector_unittest.cc",
+  ]
 
   deps = [
     ":heatmap",
diff --git a/chromeos/ash/components/heatmap/DEPS b/chromeos/ash/components/heatmap/DEPS
index 9f15fe7..31df707 100644
--- a/chromeos/ash/components/heatmap/DEPS
+++ b/chromeos/ash/components/heatmap/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
   "+content/public/test/browser_task_environment.h",
+  "+ui/ozone/public/palm_detector.h",
 ]
diff --git a/chromeos/ash/components/heatmap/heatmap_palm_detector.cc b/chromeos/ash/components/heatmap/heatmap_palm_detector.cc
new file mode 100644
index 0000000..f2c32f1
--- /dev/null
+++ b/chromeos/ash/components/heatmap/heatmap_palm_detector.cc
@@ -0,0 +1,26 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "chromeos/ash/components/heatmap/heatmap_palm_detector.h"
+
+namespace ash {
+
+HeatmapPalmDetector::HeatmapPalmDetector()
+    : ml_agent_(std::make_unique<HeatmapMlAgent>()) {}
+
+HeatmapPalmDetector::~HeatmapPalmDetector() = default;
+
+void HeatmapPalmDetector::DetectPalm(const std::vector<double>& data,
+                                     DetectionDoneCallback callback) {
+  ml_agent_->Execute(
+      data, base::BindOnce(&HeatmapPalmDetector::OnExecuteDone,
+                           weak_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void HeatmapPalmDetector::OnExecuteDone(DetectionDoneCallback callback,
+                                        absl::optional<double> result) {
+  std::move(callback).Run(result.value_or(0) > 0 ? DetectionResult::kPalm
+                                                 : DetectionResult::kNoPalm);
+}
+
+}  // namespace ash
diff --git a/chromeos/ash/components/heatmap/heatmap_palm_detector.h b/chromeos/ash/components/heatmap/heatmap_palm_detector.h
new file mode 100644
index 0000000..50badbae
--- /dev/null
+++ b/chromeos/ash/components/heatmap/heatmap_palm_detector.h
@@ -0,0 +1,35 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_ASH_COMPONENTS_HEATMAP_HEATMAP_PALM_DETECTOR_H_
+#define CHROMEOS_ASH_COMPONENTS_HEATMAP_HEATMAP_PALM_DETECTOR_H_
+
+#include "chromeos/ash/components/heatmap/heatmap_ml_agent.h"
+#include "ui/ozone/public/palm_detector.h"
+
+namespace ash {
+
+// A class that detects whether there is a palm in the given heatmap data calls
+// a provided callback method with the detection result.
+class HeatmapPalmDetector : public ui::PalmDetector {
+ public:
+  HeatmapPalmDetector();
+  ~HeatmapPalmDetector() override;
+
+  // ui::PalmDetector:
+  void DetectPalm(const std::vector<double>& data,
+                  DetectionDoneCallback callback) override;
+
+ private:
+  void OnExecuteDone(DetectionDoneCallback callback,
+                     absl::optional<double> result);
+
+  std::unique_ptr<HeatmapMlAgent> ml_agent_;
+
+  base::WeakPtrFactory<HeatmapPalmDetector> weak_factory_{this};
+};
+
+}  // namespace ash
+
+#endif  // CHROMEOS_ASH_COMPONENTS_HEATMAP_HEATMAP_PALM_DETECTOR_H_
diff --git a/chromeos/ash/components/heatmap/heatmap_palm_detector_unittest.cc b/chromeos/ash/components/heatmap/heatmap_palm_detector_unittest.cc
new file mode 100644
index 0000000..e492281
--- /dev/null
+++ b/chromeos/ash/components/heatmap/heatmap_palm_detector_unittest.cc
@@ -0,0 +1,76 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/ash/components/heatmap/heatmap_palm_detector.h"
+
+#include "base/run_loop.h"
+#include "chromeos/dbus/machine_learning/machine_learning_client.h"
+#include "chromeos/services/machine_learning/public/cpp/fake_service_connection.h"
+#include "chromeos/services/machine_learning/public/cpp/service_connection.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ash {
+namespace {
+
+using DetectionResult = ui::PalmDetector::DetectionResult;
+
+constexpr double kExpectedResult = 0.968;
+constexpr int kExpectedDataLength = 1600;
+
+class HeatmapPalmDetectorTest : public testing::Test {
+ public:
+  void SetUp() override {
+    chromeos::MachineLearningClient::InitializeFake();
+    chromeos::machine_learning::ServiceConnection::
+        UseFakeServiceConnectionForTesting(&fake_service_connection_);
+    chromeos::machine_learning::ServiceConnection::GetInstance()->Initialize();
+    fake_service_connection_.SetOutputValue(
+        std::vector<int64_t>{1L, 1L}, std::vector<double>{kExpectedResult});
+  }
+
+  void TearDown() override { chromeos::MachineLearningClient::Shutdown(); }
+
+ protected:
+  chromeos::machine_learning::FakeServiceConnectionImpl
+      fake_service_connection_;
+  content::BrowserTaskEnvironment task_environment_;
+};
+
+TEST_F(HeatmapPalmDetectorTest, DetectsPalm) {
+  HeatmapPalmDetector detector;
+  std::vector<double> data(kExpectedDataLength, 0);
+
+  bool callback_done = false;
+  detector.DetectPalm(data,
+                      base::BindOnce(
+                          [](bool* callback_done, DetectionResult result) {
+                            EXPECT_EQ(result, DetectionResult::kPalm);
+                            *callback_done = true;
+                          },
+                          &callback_done));
+
+  task_environment_.RunUntilIdle();
+  EXPECT_TRUE(callback_done);
+}
+
+TEST_F(HeatmapPalmDetectorTest, ReturnsNoPalmOnInvalidData) {
+  HeatmapPalmDetector detector;
+  std::vector<double> data;
+
+  bool callback_done = false;
+  detector.DetectPalm(data,
+                      base::BindOnce(
+                          [](bool* callback_done, DetectionResult result) {
+                            EXPECT_EQ(result, DetectionResult::kNoPalm);
+                            *callback_done = true;
+                          },
+                          &callback_done));
+
+  task_environment_.RunUntilIdle();
+  EXPECT_TRUE(callback_done);
+}
+
+}  // namespace
+}  // namespace ash
diff --git a/chromeos/dbus/dlp/fake_dlp_client.cc b/chromeos/dbus/dlp/fake_dlp_client.cc
index efd51f7..a44fbde 100644
--- a/chromeos/dbus/dlp/fake_dlp_client.cc
+++ b/chromeos/dbus/dlp/fake_dlp_client.cc
@@ -14,18 +14,6 @@
 
 namespace chromeos {
 
-namespace {
-
-ino_t GetInodeValue(const base::FilePath& path) {
-  struct stat file_stats;
-  if (stat(path.value().c_str(), &file_stats) != 0) {
-    return 0;
-  }
-  return file_stats.st_ino;
-}
-
-}  // namespace
-
 FakeDlpClient::FakeDlpClient() = default;
 
 FakeDlpClient::~FakeDlpClient() = default;
@@ -56,9 +44,8 @@
   }
   for (const dlp::AddFileRequest& file_request : request.add_file_requests()) {
     if (file_request.has_file_path() && file_request.has_source_url()) {
-      files_database_[GetInodeValue(base::FilePath(file_request.file_path()))] =
-          std::make_pair(file_request.source_url(),
-                         file_request.referrer_url());
+      files_database_[file_request.file_path()] = std::make_pair(
+          file_request.source_url(), file_request.referrer_url());
     }
   }
 
@@ -73,14 +60,14 @@
     return;
   }
   dlp::GetFilesSourcesResponse response;
-  for (const auto& file_inode : request.files_inodes()) {
-    auto file_itr = files_database_.find(file_inode);
+  for (const auto& file_path : request.files_paths()) {
+    auto file_itr = files_database_.find(file_path);
     if (file_itr == files_database_.end() && !fake_source_.has_value()) {
       continue;
     }
 
     dlp::FileMetadata* file_metadata = response.add_files_metadata();
-    file_metadata->set_inode(file_inode);
+    file_metadata->set_path(file_path);
     file_metadata->set_source_url(
         fake_source_.value_or(file_itr->second.first));
     file_metadata->set_referrer_url(file_itr->second.second);
diff --git a/chromeos/dbus/dlp/fake_dlp_client.h b/chromeos/dbus/dlp/fake_dlp_client.h
index f587c9a7..c3bbc76 100644
--- a/chromeos/dbus/dlp/fake_dlp_client.h
+++ b/chromeos/dbus/dlp/fake_dlp_client.h
@@ -58,8 +58,9 @@
   int set_dlp_files_policy_count_ = 0;
   bool file_access_allowed_ = true;
   bool is_alive_ = true;
-  // Map from inode number to a pair of source_url and referrer_url.
-  base::flat_map<ino_t, std::pair<std::string, std::string>> files_database_;
+  // Map from file path to a pair of source_url and referrer_url.
+  base::flat_map<std::string, std::pair<std::string, std::string>>
+      files_database_;
   absl::optional<std::string> fake_source_;
   absl::optional<dlp::CheckFilesTransferResponse>
       check_files_transfer_response_;
diff --git a/chromeos/profiles/arm-exp.afdo.newest.txt b/chromeos/profiles/arm-exp.afdo.newest.txt
index 62ae4ba..b4043a4 100644
--- a/chromeos/profiles/arm-exp.afdo.newest.txt
+++ b/chromeos/profiles/arm-exp.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-exp-117-5845.27-1689587007-benchmark-117.0.5896.0-r1-redacted.afdo.xz
+chromeos-chrome-arm-exp-117-5845.27-1689587007-benchmark-117.0.5905.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/arm.afdo.newest.txt b/chromeos/profiles/arm.afdo.newest.txt
index 24af5246..db659b1 100644
--- a/chromeos/profiles/arm.afdo.newest.txt
+++ b/chromeos/profiles/arm.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-arm-none-117-5845.27-1689593582-benchmark-117.0.5904.0-r1-redacted.afdo.xz
+chromeos-chrome-arm-none-117-5845.27-1689593582-benchmark-117.0.5905.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt
index 5f8b737..93a92aed 100644
--- a/chromeos/profiles/atom.afdo.newest.txt
+++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-atom-117-5845.27-1689587007-benchmark-117.0.5904.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-atom-117-5845.27-1689587007-benchmark-117.0.5905.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt
index 02b9628..09fbacd 100644
--- a/chromeos/profiles/bigcore.afdo.newest.txt
+++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-bigcore-117-5845.27-1689592369-benchmark-117.0.5904.0-r1-redacted.afdo.xz
+chromeos-chrome-amd64-bigcore-117-5845.27-1689592369-benchmark-117.0.5905.0-r1-redacted.afdo.xz
diff --git a/chromeos/tast_control.gni b/chromeos/tast_control.gni
index 2c48dbe..9e76d35 100644
--- a/chromeos/tast_control.gni
+++ b/chromeos/tast_control.gni
@@ -325,14 +325,8 @@
   "a11y.LiveCaption.lacros",
 
   # b/291854686
-  "inputs.InputMethodShelfInputs",
-  "inputs.VirtualKeyboardAutocorrect.*",
-  "inputs.VirtualKeyboardGlideTyping.*",
+  "inputs.VirtualKeyboardGlideTyping.clamshell_a11y_floating_lacros",
   "inputs.VirtualKeyboardHandwriting.docked",
-  "inputs.VirtualKeyboardHandwriting.floating",
-  "inputs.VirtualKeyboardTypingApps",
-  "inputs.VirtualKeyboardTypingOmnibox.a11y_lacros",
-  "inputs.VirtualKeyboardTypingUserMode.incognito",
 
   # b/287525851
   "arc.AudioValidity.playback",
@@ -380,15 +374,6 @@
   # https://crbug.com/1376638
   "lacros.AudioRecord",
 
-  # b/274158730
-  "tast.inputs.PhysicalKeyboardAutocorrect.*@jacuzzi",
-  "tast.inputs.PhysicalKeyboardShapeBasedChineseTyping.*@jacuzzi",
-  "tast.inputs.VirtualKeyboardTypingOmnibox.*@jacuzzi",
-  "tast.inputs.PhysicalKeyboardZhuyinTyping.*@jacuzzi",
-  "tast.inputs.VirtualKeyboardDeadKeys.*@jacuzzi",
-  "tast.inputs.PhysicalKeyboardShapeBasedChineseTyping.array_lacros",
-  "tast.inputs.VirtualKeyboardSpeech.lacros",
-
   # https://crbug.com/1440735
   "mlservice.WebHandwritingRecognition.lacros",
 
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc
index ae71c74..38e0529 100644
--- a/components/exo/client_controlled_shell_surface.cc
+++ b/components/exo/client_controlled_shell_surface.cc
@@ -1055,7 +1055,7 @@
       ScopedSetBoundsLocally scoped_set_bounds(this);
       window->SetBounds(gfx::Rect(origin, adjusted_bounds.size()));
     }
-    UpdateSurfaceBounds();
+    UpdateHostWindowOrigin();
     return;
   }
 
@@ -1076,7 +1076,7 @@
                         adjusted_bounds_in_display, 0);
   }
 
-  UpdateSurfaceBounds();
+  UpdateHostWindowOrigin();
 }
 
 gfx::Rect ClientControlledShellSurface::GetShadowBounds() const {
@@ -1440,7 +1440,7 @@
   UpdateAutoHideFrame();
 
   if (suppress_mouse_event)
-    UpdateSurfaceBounds();
+    UpdateHostWindowOrigin();
 }
 
 bool ClientControlledShellSurface::GetCanResizeFromSizeConstraints() const {
diff --git a/components/exo/input_method_surface.cc b/components/exo/input_method_surface.cc
index 5dd5697..9f4185b8 100644
--- a/components/exo/input_method_surface.cc
+++ b/components/exo/input_method_surface.cc
@@ -93,7 +93,7 @@
     return;
 
   widget_->SetBounds(bounds);
-  UpdateSurfaceBounds();
+  UpdateHostWindowOrigin();
 
   // Bounds change requests will be ignored in client side.
 }
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc
index 3ba286b..1758569 100644
--- a/components/exo/shell_surface.cc
+++ b/components/exo/shell_surface.cc
@@ -372,7 +372,7 @@
       base::AutoReset<bool> notify_bounds_changes(&notify_bounds_changes_,
                                                   false);
       widget_->SetBounds(new_widget_bounds);
-      UpdateSurfaceBounds();
+      UpdateHostWindowOrigin();
     }
   } else {
     SetParentWindow(nullptr);
@@ -477,7 +477,7 @@
     if (new_bounds.size() == old_bounds.size()) {
       if (!origin_change_callback_.is_null())
         origin_change_callback_.Run(GetClientBoundsInScreen(widget_).origin());
-      UpdateSurfaceBounds();
+      UpdateHostWindowOrigin();
       return;
     }
 
@@ -488,7 +488,7 @@
     origin_offset_ -= delta;
     pending_origin_offset_accumulator_ += delta;
 
-    UpdateSurfaceBounds();
+    UpdateHostWindowOrigin();
 
     // The shadow size may be updated to match the widget. Change it back
     // to the shadow content size. Note that this relies on wm::ShadowController
@@ -518,7 +518,7 @@
     old_screen_bounds_for_pending_move_ = gfx::Rect();
     origin_offset_ -= delta;
     pending_origin_offset_accumulator_ += delta;
-    UpdateSurfaceBounds();
+    UpdateHostWindowOrigin();
     UpdateShadow();
 
     if (!window_state_is_changing_)
@@ -690,7 +690,7 @@
   } else {
     widget_->SetBounds(bounds);
   }
-  UpdateSurfaceBounds();
+  UpdateHostWindowOrigin();
 
   notify_bounds_changes_ = true;
 }
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc
index dae16bf..69e5527 100644
--- a/components/exo/shell_surface_base.cc
+++ b/components/exo/shell_surface_base.cc
@@ -1059,7 +1059,7 @@
   // window is animating.
   set_bounds_is_dirty(true);
   UpdateWidgetBounds();
-  UpdateSurfaceBounds();
+  UpdateHostWindowOrigin();
 }
 
 void ShellSurfaceBase::OnSetFrameColors(SkColor active_color,
@@ -1752,7 +1752,7 @@
   SetWidgetBounds(adjusted_bounds, adjusted_bounds != *bounds);
 }
 
-void ShellSurfaceBase::UpdateSurfaceBounds() {
+void ShellSurfaceBase::UpdateHostWindowOrigin() {
   gfx::Point origin = GetClientViewBounds().origin();
 
   origin += GetSurfaceOrigin().OffsetFromOrigin();
@@ -2009,7 +2009,7 @@
   // type (e.g. caption height).
   UpdateFrameType();
   UpdateWidgetBounds();
-  UpdateHostWindowBounds();
+  UpdateHostWindowSizeAndRootSurfaceOrigin();
   gfx::Rect bounds = geometry_;
   if (!bounds.IsEmpty() && !widget_->GetNativeWindow()->GetProperty(
                                aura::client::kUseWindowBoundsForShadow)) {
@@ -2041,7 +2041,7 @@
     }
   }
 
-  UpdateSurfaceBounds();
+  UpdateHostWindowOrigin();
   UpdateShape();
 
   // Don't show yet if the shell surface doesn't have content or is minimized
diff --git a/components/exo/shell_surface_base.h b/components/exo/shell_surface_base.h
index ee56162..536af94 100644
--- a/components/exo/shell_surface_base.h
+++ b/components/exo/shell_surface_base.h
@@ -376,8 +376,8 @@
   virtual void SetWidgetBounds(const gfx::Rect& bounds,
                                bool adjusted_by_server) = 0;
 
-  // Updates the bounds of surface to match the current widget bounds.
-  void UpdateSurfaceBounds();
+  // Updates the bounds of host window to match the current widget bounds.
+  void UpdateHostWindowOrigin();
 
   // Creates, deletes and update the shadow bounds based on
   // |shadow_bounds_|.
diff --git a/components/exo/surface_tree_host.cc b/components/exo/surface_tree_host.cc
index d4cef16..d7427e9a 100644
--- a/components/exo/surface_tree_host.cc
+++ b/components/exo/surface_tree_host.cc
@@ -174,7 +174,7 @@
     root_surface_->window()->SetProperty(
         ui::kAXConsiderInvisibleAndIgnoreChildren, true);
     host_window_->AddChild(root_surface_->window());
-    UpdateHostWindowBounds();
+    UpdateHostWindowSizeAndRootSurfaceOrigin();
   }
   set_bounds_is_dirty(true);
 }
@@ -239,7 +239,7 @@
 
 void SurfaceTreeHost::OnSurfaceCommit() {
   root_surface_->CommitSurfaceHierarchy(false);
-  UpdateHostWindowBounds();
+  UpdateHostWindowSizeAndRootSurfaceOrigin();
 }
 
 bool SurfaceTreeHost::IsSurfaceSynchronized() const {
@@ -406,7 +406,7 @@
   layer_tree_frame_sink_holder_->SubmitCompositorFrame(std::move(frame));
 }
 
-void SurfaceTreeHost::UpdateHostWindowBounds() {
+void SurfaceTreeHost::UpdateHostWindowSizeAndRootSurfaceOrigin() {
   // This method applies multiple changes to the window tree. Use ScopedPause
   // to ensure that occlusion isn't recomputed before all changes have been
   // applied.
diff --git a/components/exo/surface_tree_host.h b/components/exo/surface_tree_host.h
index 3f9a55e..10546ef 100644
--- a/components/exo/surface_tree_host.h
+++ b/components/exo/surface_tree_host.h
@@ -155,7 +155,7 @@
   void SetLayerTreeFrameSinkHolderFactoryForTesting(
       LayerTreeFrameSinkHolderFactory frame_sink_holder_factory);
 
-  // Create a LayerTreeFrameSink for the |host_window_|.
+  // Creates a LayerTreeFrameSink for the |host_window_|.
   std::unique_ptr<cc::mojo_embedder::AsyncLayerTreeFrameSink>
   CreateLayerTreeFrameSink();
 
@@ -177,9 +177,10 @@
   // need to be released back to the client.
   void SubmitEmptyCompositorFrame();
 
-  // Update the host window's size to cover sufaces that must be visible and
+  // Updates the host window's size to cover surfaces that must be visible and
   // not clipped.
-  void UpdateHostWindowBounds();
+  // It also updates root surface origin accordingly to the origin.
+  void UpdateHostWindowSizeAndRootSurfaceOrigin();
 
   bool client_submits_surfaces_in_pixel_coordinates() const {
     return client_submits_surfaces_in_pixel_coordinates_;
@@ -195,7 +196,7 @@
   // the host window's layer's scale factor.
   virtual float GetScaleFactor() const;
 
-  // Set the appropriate transform for the given scale factor.
+  // Sets the appropriate transform for the given scale factor.
   // NOTE: This should only be done if the client submits in pixel coordinates.
   void SetScaleFactorTransform(float scale_factor);
 
@@ -204,7 +205,7 @@
   void UpdateLocalSurfaceIdFromParent(
       const viz::LocalSurfaceId& parent_local_surface_id);
 
-  // Change the local_surface_id as the viz::Surface property will change.
+  // Changes the local_surface_id as the viz::Surface property will change.
   void AllocateLocalSurfaceId();
 
   // If local_surface_id is newer than |host_window_|'s ui layer, push the
diff --git a/components/mirroring/mojom/resource_provider.mojom b/components/mirroring/mojom/resource_provider.mojom
index 278203ea..7125cf6 100644
--- a/components/mirroring/mojom/resource_provider.mojom
+++ b/components/mirroring/mojom/resource_provider.mojom
@@ -10,6 +10,7 @@
 import "media/mojo/mojom/audio_data_pipe.mojom";
 import "media/mojo/mojom/audio_input_stream.mojom";
 import "media/mojo/mojom/audio_parameters.mojom";
+import "media/mojo/mojom/video_encoder_metrics_provider.mojom";
 import "sandbox/policy/mojom/context.mojom";
 import "services/viz/public/mojom/gpu.mojom";
 
@@ -35,6 +36,12 @@
   // events (Start, Stop, etc) from its client in the renderer process.
   GetVideoCaptureHost(pending_receiver<media.mojom.VideoCaptureHost> receiver);
 
+  // Binds the media.mojom.VideoEncoderMetricsProvider pending receiver to its
+  // remote implementation in the browser process, so that video encoder usage
+  // in cast mirroring utility process can be recorded.
+  GetVideoEncoderMetricsProvider(
+      pending_receiver<media.mojom.VideoEncoderMetricsProvider> receiver);
+
   [AllowedContext=sandbox.mojom.Context.kPrivilegedUtility]
   GetNetworkContext(pending_receiver<network.mojom.NetworkContext> receiver);
   CreateAudioStream(pending_remote<AudioStreamCreatorClient> client,
diff --git a/components/mirroring/service/BUILD.gn b/components/mirroring/service/BUILD.gn
index d7d4050..205ad425 100644
--- a/components/mirroring/service/BUILD.gn
+++ b/components/mirroring/service/BUILD.gn
@@ -127,6 +127,7 @@
     "//media/cast:sender",
     "//media/cast:test_support",
     "//media/cast/openscreen:remoting_utils",
+    "//media/mojo:test_support",
     "//media/mojo/common",
     "//media/mojo/mojom",
     "//media/mojo/mojom:remoting",
diff --git a/components/mirroring/service/openscreen_session_host.cc b/components/mirroring/service/openscreen_session_host.cc
index 2bb730c8..9985c39b 100644
--- a/components/mirroring/service/openscreen_session_host.cc
+++ b/components/mirroring/service/openscreen_session_host.cc
@@ -50,6 +50,7 @@
 #include "media/cast/sender/video_sender.h"
 #include "media/gpu/gpu_video_accelerator_util.h"
 #include "media/mojo/clients/mojo_video_encode_accelerator.h"
+#include "media/mojo/clients/mojo_video_encoder_metrics_provider.h"
 #include "media/video/video_encode_accelerator.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "net/base/ip_endpoint.h"
@@ -488,6 +489,10 @@
   }
 
   if (senders.video_sender) {
+    mojo::PendingRemote<media::mojom::VideoEncoderMetricsProvider>
+        metrics_provider_pending_remote;
+    resource_provider_->GetVideoEncoderMetricsProvider(
+        metrics_provider_pending_remote.InitWithNewPipeAndPassReceiver());
     auto video_sender = std::make_unique<media::cast::VideoSender>(
         cast_environment_, *video_config,
         base::BindRepeating(&OpenscreenSessionHost::OnEncoderStatusChange,
@@ -496,6 +501,9 @@
             &OpenscreenSessionHost::CreateVideoEncodeAccelerator,
             weak_factory_.GetWeakPtr()),
         std::move(senders.video_sender),
+        std::make_unique<media::MojoVideoEncoderMetricsProvider>(
+            media::mojom::VideoEncoderUseCase::kCastMirroring,
+            std::move(metrics_provider_pending_remote)),
         base::BindRepeating(&OpenscreenSessionHost::SetTargetPlayoutDelay,
                             weak_factory_.GetWeakPtr()),
         base::BindRepeating(&OpenscreenSessionHost::ProcessFeedback,
diff --git a/components/mirroring/service/openscreen_session_host_unittest.cc b/components/mirroring/service/openscreen_session_host_unittest.cc
index 225195e..b1f5900 100644
--- a/components/mirroring/service/openscreen_session_host_unittest.cc
+++ b/components/mirroring/service/openscreen_session_host_unittest.cc
@@ -227,6 +227,10 @@
     OnGetVideoCaptureHost();
   }
 
+  void GetVideoEncoderMetricsProvider(
+      mojo::PendingReceiver<media::mojom::VideoEncoderMetricsProvider> receiver)
+      override {}
+
   void GetNetworkContext(
       mojo::PendingReceiver<network::mojom::NetworkContext> receiver) override {
     network_context_ =
diff --git a/components/mirroring/service/rtp_stream_unittest.cc b/components/mirroring/service/rtp_stream_unittest.cc
index 967aac8..8ac10f1 100644
--- a/components/mirroring/service/rtp_stream_unittest.cc
+++ b/components/mirroring/service/rtp_stream_unittest.cc
@@ -21,6 +21,7 @@
 #include "media/cast/test/utility/audio_utility.h"
 #include "media/cast/test/utility/default_config.h"
 #include "media/cast/test/utility/video_utility.h"
+#include "media/mojo/clients/mock_mojo_video_encoder_metrics_provider.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -149,8 +150,10 @@
 TEST_F(RtpStreamTest, VideoStreaming) {
   auto video_sender = std::make_unique<media::cast::VideoSender>(
       cast_environment_, media::cast::GetDefaultVideoSenderConfig(),
-      base::DoNothing(), base::DoNothing(), &transport_, base::DoNothing(),
-      base::DoNothing());
+      base::DoNothing(), base::DoNothing(), &transport_,
+      std::make_unique<media::MockMojoVideoEncoderMetricsProvider>(
+          media::mojom::VideoEncoderUseCase::kCastMirroring),
+      base::DoNothing(), base::DoNothing());
   VideoRtpStream video_stream(std::move(video_sender), client_.GetWeakPtr(),
                               base::Milliseconds(1));
   client_.SetVideoRtpStream(&video_stream);
@@ -162,8 +165,10 @@
 TEST_F(RtpStreamTest, VideoStreamEmitsFramesWhenNoUpdates) {
   auto video_sender = std::make_unique<media::cast::VideoSender>(
       cast_environment_, media::cast::GetDefaultVideoSenderConfig(),
-      base::DoNothing(), base::DoNothing(), &transport_, base::DoNothing(),
-      base::DoNothing());
+      base::DoNothing(), base::DoNothing(), &transport_,
+      std::make_unique<media::MockMojoVideoEncoderMetricsProvider>(
+          media::mojom::VideoEncoderUseCase::kCastMirroring),
+      base::DoNothing(), base::DoNothing());
   VideoRtpStream video_stream(std::move(video_sender), client_.GetWeakPtr(),
                               base::Milliseconds(1));
   client_.SetVideoRtpStream(&video_stream);
@@ -175,8 +180,10 @@
 TEST_F(RtpStreamTest, VideoStreamDoesNotRefreshWithZeroInterval) {
   auto video_sender = std::make_unique<media::cast::VideoSender>(
       cast_environment_, media::cast::GetDefaultVideoSenderConfig(),
-      base::DoNothing(), base::DoNothing(), &transport_, base::DoNothing(),
-      base::DoNothing());
+      base::DoNothing(), base::DoNothing(), &transport_,
+      std::make_unique<media::MockMojoVideoEncoderMetricsProvider>(
+          media::mojom::VideoEncoderUseCase::kCastMirroring),
+      base::DoNothing(), base::DoNothing());
   VideoRtpStream video_stream(std::move(video_sender), client_.GetWeakPtr(),
                               base::TimeDelta());
   client_.SetVideoRtpStream(&video_stream);
@@ -188,8 +195,10 @@
 TEST_F(RtpStreamTest, VideoStreamTimerNotRunningWhenNoFramesDelivered) {
   auto video_sender = std::make_unique<media::cast::VideoSender>(
       cast_environment_, media::cast::GetDefaultVideoSenderConfig(),
-      base::DoNothing(), base::DoNothing(), &transport_, base::DoNothing(),
-      base::DoNothing());
+      base::DoNothing(), base::DoNothing(), &transport_,
+      std::make_unique<media::MockMojoVideoEncoderMetricsProvider>(
+          media::mojom::VideoEncoderUseCase::kCastMirroring),
+      base::DoNothing(), base::DoNothing());
   VideoRtpStream video_stream(std::move(video_sender), client_.GetWeakPtr(),
                               base::Milliseconds(1));
   client_.SetVideoRtpStream(&video_stream);
@@ -205,8 +214,10 @@
 TEST_F(RtpStreamTest, VideoStreamTimerRestartsWhenFramesDeliveredAgain) {
   auto video_sender = std::make_unique<media::cast::VideoSender>(
       cast_environment_, media::cast::GetDefaultVideoSenderConfig(),
-      base::DoNothing(), base::DoNothing(), &transport_, base::DoNothing(),
-      base::DoNothing());
+      base::DoNothing(), base::DoNothing(), &transport_,
+      std::make_unique<media::MockMojoVideoEncoderMetricsProvider>(
+          media::mojom::VideoEncoderUseCase::kCastMirroring),
+      base::DoNothing(), base::DoNothing());
   VideoRtpStream video_stream(std::move(video_sender), client_.GetWeakPtr(),
                               base::Milliseconds(1));
   client_.SetVideoRtpStream(&video_stream);
diff --git a/components/mirroring/service/session.cc b/components/mirroring/service/session.cc
index af0926d..9ebe3c3 100644
--- a/components/mirroring/service/session.cc
+++ b/components/mirroring/service/session.cc
@@ -46,6 +46,7 @@
 #include "media/cast/sender/video_sender.h"
 #include "media/gpu/gpu_video_accelerator_util.h"
 #include "media/mojo/clients/mojo_video_encode_accelerator.h"
+#include "media/mojo/clients/mojo_video_encoder_metrics_provider.h"
 #include "media/remoting/device_capability_checker.h"
 #include "media/video/video_encode_accelerator.h"
 #include "mojo/public/cpp/system/platform_handle.h"
@@ -779,6 +780,10 @@
       base::UmaHistogramEnumeration(
           "CastStreaming.Sender.Video.NegotiatedCodec",
           ToVideoCodec(video_config->codec));
+      mojo::PendingRemote<media::mojom::VideoEncoderMetricsProvider>
+          metrics_provider_pending_remote;
+      resource_provider_->GetVideoEncoderMetricsProvider(
+          metrics_provider_pending_remote.InitWithNewPipeAndPassReceiver());
       auto video_sender = std::make_unique<media::cast::VideoSender>(
           cast_environment_, *video_config,
           base::BindRepeating(&Session::OnEncoderStatusChange,
@@ -786,6 +791,9 @@
           base::BindRepeating(&Session::CreateVideoEncodeAccelerator,
                               weak_factory_.GetWeakPtr()),
           cast_transport_.get(),
+          std::make_unique<media::MojoVideoEncoderMetricsProvider>(
+              media::mojom::VideoEncoderUseCase::kCastMirroring,
+              std::move(metrics_provider_pending_remote)),
           base::BindRepeating(&Session::SetTargetPlayoutDelay,
                               weak_factory_.GetWeakPtr()),
           base::BindRepeating(&Session::ProcessFeedback,
diff --git a/components/mirroring/service/session_unittest.cc b/components/mirroring/service/session_unittest.cc
index e45ef01..2e64c5d 100644
--- a/components/mirroring/service/session_unittest.cc
+++ b/components/mirroring/service/session_unittest.cc
@@ -177,6 +177,10 @@
     OnGetVideoCaptureHost();
   }
 
+  void GetVideoEncoderMetricsProvider(
+      mojo::PendingReceiver<media::mojom::VideoEncoderMetricsProvider> receiver)
+      override {}
+
   void GetNetworkContext(
       mojo::PendingReceiver<network::mojom::NetworkContext> receiver) override {
     network_context_ =
diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn
index 70f6761..de143af 100644
--- a/components/password_manager/core/browser/BUILD.gn
+++ b/components/password_manager/core/browser/BUILD.gn
@@ -242,7 +242,10 @@
     "sharing/password_sender_service_impl.h",
     "sharing/password_sharing_recipients_downloader.cc",
     "sharing/password_sharing_recipients_downloader.h",
+    "sharing/recipients_fetcher.cc",
     "sharing/recipients_fetcher.h",
+    "sharing/recipients_fetcher_impl.cc",
+    "sharing/recipients_fetcher_impl.h",
     "sharing/sharing_invitations.cc",
     "sharing/sharing_invitations.h",
     "smart_bubble_stats_store.h",
@@ -693,6 +696,7 @@
     "sharing/outgoing_password_sharing_invitation_sync_bridge_unittest.cc",
     "sharing/password_receiver_service_impl_unittest.cc",
     "sharing/password_sharing_recipients_downloader_unittest.cc",
+    "sharing/recipients_fetcher_impl_unittest.cc",
     "sql_table_builder_unittest.cc",
     "statistics_table_unittest.cc",
     "store_metrics_reporter_unittest.cc",
diff --git a/components/password_manager/core/browser/credential_manager_impl_unittest.cc b/components/password_manager/core/browser/credential_manager_impl_unittest.cc
index 30443f7..44d732f 100644
--- a/components/password_manager/core/browser/credential_manager_impl_unittest.cc
+++ b/components/password_manager/core/browser/credential_manager_impl_unittest.cc
@@ -10,6 +10,7 @@
 #include <memory>
 #include <string>
 #include <tuple>
+#include <utility>
 
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
@@ -30,6 +31,7 @@
 #include "components/password_manager/core/browser/leak_detection/leak_detection_request_utils.h"
 #include "components/password_manager/core/browser/leak_detection/mock_leak_detection_check_factory.h"
 #include "components/password_manager/core/browser/password_form.h"
+#include "components/password_manager/core/browser/password_form_manager_for_ui.h"
 #include "components/password_manager/core/browser/password_manager.h"
 #include "components/password_manager/core/browser/stub_password_manager_client.h"
 #include "components/password_manager/core/browser/test_password_store.h"
@@ -44,12 +46,13 @@
 #include "url/gurl.h"
 #include "url/url_constants.h"
 
-using testing::_;
-using testing::ElementsAre;
-using testing::NiceMock;
-using testing::Pair;
-using testing::Pointee;
-using testing::UnorderedElementsAre;
+using ::testing::_;
+using ::testing::ElementsAre;
+using ::testing::NiceMock;
+using ::testing::Pair;
+using ::testing::Pointee;
+using ::testing::Return;
+using ::testing::UnorderedElementsAre;
 
 namespace password_manager {
 
@@ -82,10 +85,10 @@
               (PasswordForm * form),
               ());
   MOCK_METHOD(void, NotifyStorePasswordCalled, (), (override));
-  MOCK_METHOD(void,
-              PromptUserToSavePasswordPtr,
-              (PasswordFormManagerForUI*),
-              ());
+  MOCK_METHOD(bool,
+              PromptUserToSaveOrUpdatePassword,
+              (std::unique_ptr<PasswordFormManagerForUI>, bool),
+              (override));
   MOCK_METHOD(bool,
               PromptUserToChooseCredentialsPtr,
               (const std::vector<PasswordForm*>& local_forms,
@@ -122,14 +125,6 @@
 
   bool IsAutoSignInEnabled() const override { return auto_sign_in_enabled_; }
 
-  bool PromptUserToSaveOrUpdatePassword(
-      std::unique_ptr<PasswordFormManagerForUI> manager,
-      bool update_password) override {
-    manager_.swap(manager);
-    PromptUserToSavePasswordPtr(manager_.get());
-    return true;
-  }
-
   void NotifyUserCouldBeAutoSignedIn(
       std::unique_ptr<PasswordForm> form) override {
     NotifyUserCouldBeAutoSignedInPtr(form.get());
@@ -177,8 +172,6 @@
     NotifyUserAutoSigninPtr();
   }
 
-  PasswordFormManagerForUI* pending_manager() const { return manager_.get(); }
-
   void set_zero_click_enabled(bool zero_click_enabled) {
     auto_sign_in_enabled_ = zero_click_enabled;
   }
@@ -196,7 +189,6 @@
   std::unique_ptr<TestingPrefServiceSimple> prefs_;
   raw_ptr<PasswordStoreInterface> profile_store_;
   raw_ptr<PasswordStoreInterface> account_store_;
-  std::unique_ptr<PasswordFormManagerForUI> manager_;
   PasswordManager password_manager_;
   GURL last_committed_url_{kTestWebOrigin};
   bool auto_sign_in_enabled_ = true;
@@ -223,6 +215,19 @@
   return https_url.ReplaceComponents(rep);
 }
 
+// Moves the `I`th argument to `*out` and returns `return_value`.
+//
+// `MoveArg` in base/test/gmock_move_support.h only works for functions that
+// return void. At the same time, `DoAll(MoveArg(), Return())` does not work,
+// because the first action only receives a read-only view of its arguments.
+template <size_t I = 0, typename T1, typename T2>
+auto MoveArgAndReturn(T1* out, T2&& return_value) {
+  return [out, value = std::forward<T2>(return_value)](auto&&... args) mutable {
+    *out = std::move(std::get<I>(std::tie(args...)));
+    return std::forward<T2>(value);
+  };
+}
+
 }  // namespace
 
 // Test param controls whether to enable the account storage feature.
@@ -261,10 +266,9 @@
     cm_service_impl_->set_leak_factory(
         std::make_unique<NiceMock<MockLeakDetectionCheckFactory>>());
 
-    ON_CALL(*client_, IsSavingAndFillingEnabled(_))
-        .WillByDefault(testing::Return(true));
-    ON_CALL(*client_, IsFillingEnabled(_)).WillByDefault(testing::Return(true));
-    ON_CALL(*client_, IsOffTheRecord()).WillByDefault(testing::Return(false));
+    ON_CALL(*client_, IsSavingAndFillingEnabled).WillByDefault(Return(true));
+    ON_CALL(*client_, IsFillingEnabled).WillByDefault(Return(true));
+    ON_CALL(*client_, IsOffTheRecord()).WillByDefault(Return(false));
 
     form_.username_value = u"Username";
     form_.display_name = u"Display Name";
@@ -341,9 +345,8 @@
     bool called = false;
     CredentialManagerError error;
     absl::optional<CredentialInfo> credential;
-    EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
-        .Times(testing::Exactly(0));
-    EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
+    EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr).Times(0);
+    EXPECT_CALL(*client_, NotifyUserAutoSigninPtr).Times(0);
     CallGet(
         mediation, include_passwords, federations,
         base::BindOnce(&GetCredentialCallback, &called, &error, &credential));
@@ -362,9 +365,8 @@
     bool called = false;
     CredentialManagerError error;
     absl::optional<CredentialInfo> credential;
-    EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
-        .Times(testing::Exactly(0));
-    EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(1));
+    EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr).Times(0);
+    EXPECT_CALL(*client_, NotifyUserAutoSigninPtr);
     CallGet(
         mediation, include_passwords, federations,
         base::BindOnce(&GetCredentialCallback, &called, &error, &credential));
@@ -452,7 +454,7 @@
 }
 
 TEST_P(CredentialManagerImplTest, CredentialManagerOnStoreEmptyCredential) {
-  EXPECT_CALL(*client_, PromptUserToSavePasswordPtr).Times(testing::Exactly(0));
+  EXPECT_CALL(*client_, PromptUserToSaveOrUpdatePassword).Times(0);
 
   bool called = false;
   auto info = CredentialInfo();
@@ -465,9 +467,10 @@
 
 TEST_P(CredentialManagerImplTest, CredentialManagerOnStore) {
   auto info = PasswordFormToCredentialInfo(form_);
-  EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
-      .Times(testing::Exactly(1));
-  EXPECT_CALL(*client_, NotifyStorePasswordCalled());
+  std::unique_ptr<PasswordFormManagerForUI> pending_manager;
+  EXPECT_CALL(*client_, PromptUserToSaveOrUpdatePassword)
+      .WillOnce(MoveArgAndReturn<0>(&pending_manager, true));
+  EXPECT_CALL(*client_, NotifyStorePasswordCalled);
 
   bool called = false;
   CallStore(info, base::BindOnce(&RespondCallback, &called));
@@ -478,7 +481,7 @@
 
   EXPECT_TRUE(called);
 
-  PasswordForm new_form = client_->pending_manager()->GetPendingCredentials();
+  PasswordForm new_form = pending_manager->GetPendingCredentials();
   EXPECT_EQ(form_.username_value, new_form.username_value);
   EXPECT_EQ(form_.display_name, new_form.display_name);
   EXPECT_EQ(form_.password_value, new_form.password_value);
@@ -491,8 +494,9 @@
 }
 
 TEST_P(CredentialManagerImplTest, CredentialManagerOnStoreFederated) {
-  EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
-      .Times(testing::Exactly(1));
+  std::unique_ptr<PasswordFormManagerForUI> pending_manager;
+  EXPECT_CALL(*client_, PromptUserToSaveOrUpdatePassword)
+      .WillOnce(MoveArgAndReturn<0>(&pending_manager, true));
   EXPECT_CALL(*client_, NotifyStorePasswordCalled());
 
   bool called = false;
@@ -508,7 +512,7 @@
 
   EXPECT_TRUE(called);
 
-  PasswordForm new_form = client_->pending_manager()->GetPendingCredentials();
+  PasswordForm new_form = pending_manager->GetPendingCredentials();
   EXPECT_EQ(form_.username_value, new_form.username_value);
   EXPECT_EQ(form_.display_name, new_form.display_name);
   EXPECT_EQ(form_.password_value, new_form.password_value);
@@ -531,8 +535,10 @@
       url::Origin::Create(GURL("https://google.com/"));
   federated.signon_realm = "federation://example.com/google.com";
   auto info = PasswordFormToCredentialInfo(federated);
-  EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_));
-  EXPECT_CALL(*client_, NotifyStorePasswordCalled());
+  std::unique_ptr<PasswordFormManagerForUI> pending_manager;
+  EXPECT_CALL(*client_, PromptUserToSaveOrUpdatePassword)
+      .WillOnce(MoveArgAndReturn<0>(&pending_manager, true));
+  EXPECT_CALL(*client_, NotifyStorePasswordCalled);
 
   bool called = false;
   CallStore(info, base::BindOnce(&RespondCallback, &called));
@@ -542,7 +548,7 @@
   RunAllPendingTasks();
 
   EXPECT_TRUE(called);
-  client_->pending_manager()->Save();
+  pending_manager->Save();
 
   RunAllPendingTasks();
   TestPasswordStore::PasswordMap passwords = store_->stored_passwords();
@@ -574,8 +580,8 @@
   info.password = u"Totally new password.";
   info.name = u"New Name";
   info.icon = GURL("https://example.com/icon.png");
-  EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_)).Times(0);
-  EXPECT_CALL(*client_, NotifyStorePasswordCalled());
+  EXPECT_CALL(*client_, PromptUserToSaveOrUpdatePassword).Times(0);
+  EXPECT_CALL(*client_, NotifyStorePasswordCalled);
   bool called = false;
   CallStore(info, base::BindOnce(&RespondCallback, &called));
 
@@ -608,9 +614,8 @@
   // credential with identical username and password should result in a silent
   // save without prompting the user.
   auto info = PasswordFormToCredentialInfo(form_);
-  EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
-      .Times(testing::Exactly(0));
-  EXPECT_CALL(*client_, NotifyStorePasswordCalled());
+  EXPECT_CALL(*client_, PromptUserToSaveOrUpdatePassword).Times(0);
+  EXPECT_CALL(*client_, NotifyStorePasswordCalled);
   bool called = false;
   CallStore(info, base::BindOnce(&RespondCallback, &called));
   RunAllPendingTasks();
@@ -635,9 +640,10 @@
   // credential but has a different username should prompt the user and not
   // result in a silent save.
   auto info = PasswordFormToCredentialInfo(form_);
-  EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
-      .Times(testing::Exactly(1));
-  EXPECT_CALL(*client_, NotifyStorePasswordCalled());
+  std::unique_ptr<PasswordFormManagerForUI> pending_manager;
+  EXPECT_CALL(*client_, PromptUserToSaveOrUpdatePassword)
+      .WillOnce(MoveArgAndReturn<0>(&pending_manager, true));
+  EXPECT_CALL(*client_, NotifyStorePasswordCalled);
   bool called = false;
   CallStore(info, base::BindOnce(&RespondCallback, &called));
   RunAllPendingTasks();
@@ -649,8 +655,7 @@
   EXPECT_EQ(1U, passwords.size());
   EXPECT_EQ(1U, passwords[psl_form.signon_realm].size());
 
-  const auto& pending_cred =
-      client_->pending_manager()->GetPendingCredentials();
+  const auto& pending_cred = pending_manager->GetPendingCredentials();
   EXPECT_EQ(info.id, pending_cred.username_value);
   EXPECT_EQ(info.password, pending_cred.password_value);
 }
@@ -667,9 +672,10 @@
   // credential but has a different password should prompt the user and not
   // result in a silent save.
   auto info = PasswordFormToCredentialInfo(form_);
-  EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
-      .Times(testing::Exactly(1));
-  EXPECT_CALL(*client_, NotifyStorePasswordCalled());
+  std::unique_ptr<PasswordFormManagerForUI> pending_manager;
+  EXPECT_CALL(*client_, PromptUserToSaveOrUpdatePassword)
+      .WillOnce(MoveArgAndReturn<0>(&pending_manager, true));
+  EXPECT_CALL(*client_, NotifyStorePasswordCalled);
   bool called = false;
   CallStore(info, base::BindOnce(&RespondCallback, &called));
   RunAllPendingTasks();
@@ -681,8 +687,7 @@
   EXPECT_EQ(1U, passwords.size());
   EXPECT_EQ(1U, passwords[psl_form.signon_realm].size());
 
-  const auto& pending_cred =
-      client_->pending_manager()->GetPendingCredentials();
+  const auto& pending_cred = pending_manager->GetPendingCredentials();
   EXPECT_EQ(info.id, pending_cred.username_value);
   EXPECT_EQ(info.password, pending_cred.password_value);
 }
@@ -696,7 +701,7 @@
   // the credential without prompting the user.
   auto info = PasswordFormToCredentialInfo(form_);
   bool called = false;
-  EXPECT_CALL(*client_, NotifyStorePasswordCalled());
+  EXPECT_CALL(*client_, NotifyStorePasswordCalled);
   CallStore(info, base::BindOnce(&RespondCallback, &called));
 
   // Allow the PasswordFormManager to talk to the password store, determine
@@ -722,7 +727,7 @@
   // the credential without prompting the user.
   auto info = PasswordFormToCredentialInfo(form_);
   bool called = false;
-  EXPECT_CALL(*client_, NotifyStorePasswordCalled());
+  EXPECT_CALL(*client_, NotifyStorePasswordCalled);
   CallStore(info, base::BindOnce(&RespondCallback, &called));
 
   // Allow the PasswordFormManager to talk to the password store, determine
@@ -747,9 +752,8 @@
   RunAllPendingTasks();
 
   std::vector<GURL> federations;
-  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
-      .Times(testing::Exactly(1));
-  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
+  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr);
+  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr).Times(0);
 
   bool called = false;
   CredentialManagerError error;
@@ -771,10 +775,9 @@
        CredentialManagerSignInWithSavingDisabledForCurrentPage) {
   auto info = PasswordFormToCredentialInfo(form_);
   EXPECT_CALL(*client_, IsSavingAndFillingEnabled(form_.url))
-      .WillRepeatedly(testing::Return(false));
-  EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
-      .Times(testing::Exactly(0));
-  EXPECT_CALL(*client_, NotifyStorePasswordCalled()).Times(0);
+      .WillRepeatedly(Return(false));
+  EXPECT_CALL(*client_, PromptUserToSaveOrUpdatePassword).Times(0);
+  EXPECT_CALL(*client_, NotifyStorePasswordCalled).Times(0);
 
   bool called = false;
   CallStore(info, base::BindOnce(&RespondCallback, &called));
@@ -782,7 +785,6 @@
   RunAllPendingTasks();
 
   EXPECT_TRUE(called);
-  EXPECT_FALSE(client_->pending_manager());
 }
 
 TEST_P(CredentialManagerImplTest, CredentialManagerOnPreventSilentAccess) {
@@ -819,8 +821,8 @@
 
 TEST_P(CredentialManagerImplTest,
        CredentialManagerOnPreventSilentAccessIncognito) {
-  EXPECT_CALL(*client_, IsSavingAndFillingEnabled(_))
-      .WillRepeatedly(testing::Return(false));
+  EXPECT_CALL(*client_, IsSavingAndFillingEnabled)
+      .WillRepeatedly(Return(false));
   store_->AddLogin(form_);
   RunAllPendingTasks();
 
@@ -843,7 +845,7 @@
 
 TEST_P(CredentialManagerImplTest,
        CredentialManagerOnPreventMediatedAccessIncognito) {
-  EXPECT_CALL(*client_, IsOffTheRecord()).WillRepeatedly(testing::Return(true));
+  EXPECT_CALL(*client_, IsOffTheRecord()).WillRepeatedly(Return(true));
   EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr).Times(0);
   store_->AddLogin(form_);
   RunAllPendingTasks();
@@ -903,11 +905,9 @@
 TEST_P(CredentialManagerImplTest,
        CredentialManagerOnRequestCredentialWithEmptyPasswordStore) {
   std::vector<GURL> federations;
-  EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
-      .Times(testing::Exactly(0));
-  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
-      .Times(testing::Exactly(0));
-  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
+  EXPECT_CALL(*client_, PromptUserToSaveOrUpdatePassword).Times(0);
+  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr).Times(0);
+  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr).Times(0);
 
   ExpectCredentialType(CredentialMediationRequirement::kOptional, true,
                        federations, CredentialType::CREDENTIAL_TYPE_EMPTY);
@@ -917,9 +917,8 @@
        CredentialManagerOnRequestCredentialWithEmptyUsernames) {
   form_.username_value.clear();
   store_->AddLogin(form_);
-  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
-      .Times(testing::Exactly(0));
-  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
+  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr).Times(0);
+  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr).Times(0);
 
   std::vector<GURL> federations;
   ExpectCredentialType(CredentialMediationRequirement::kOptional, true,
@@ -934,7 +933,7 @@
                             UnorderedElementsAre(Pointee(
                                 MatchesFormExceptStore(subdomain_form_))),
                             _, _));
-  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(0);
+  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr).Times(0);
 
   ExpectCredentialType(CredentialMediationRequirement::kOptional, true,
                        std::vector<GURL>(),
@@ -1031,11 +1030,9 @@
   store_->AddLogin(cross_origin_form_);
 
   std::vector<GURL> federations;
-  EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_))
-      .Times(testing::Exactly(0));
-  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
-      .Times(testing::Exactly(0));
-  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
+  EXPECT_CALL(*client_, PromptUserToSaveOrUpdatePassword).Times(0);
+  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr).Times(0);
+  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr).Times(0);
 
   ExpectCredentialType(CredentialMediationRequirement::kOptional, true,
                        federations, CredentialType::CREDENTIAL_TYPE_EMPTY);
@@ -1047,9 +1044,8 @@
   store_->AddLogin(form_);
 
   std::vector<GURL> federations;
-  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
-      .Times(testing::Exactly(1));
-  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
+  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr);
+  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr).Times(0);
 
   bool called = false;
   CredentialManagerError error;
@@ -1067,9 +1063,8 @@
     CredentialManagerImplTest,
     CredentialManagerOnRequestCredentialWithZeroClickOnlyEmptyPasswordStore) {
   std::vector<GURL> federations;
-  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
-      .Times(testing::Exactly(0));
-  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
+  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr).Times(0);
+  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr).Times(0);
 
   ExpectZeroClickSignInFailure(CredentialMediationRequirement::kSilent, true,
                                federations);
@@ -1082,7 +1077,7 @@
 
   std::vector<GURL> federations;
 
-  EXPECT_CALL(*client_, NotifyUserCouldBeAutoSignedInPtr(_)).Times(0);
+  EXPECT_CALL(*client_, NotifyUserCouldBeAutoSignedInPtr).Times(0);
 
   ExpectZeroClickSignInSuccess(CredentialMediationRequirement::kSilent, true,
                                federations,
@@ -1096,7 +1091,7 @@
 
   std::vector<GURL> federations;
 
-  EXPECT_CALL(*client_, NotifyUserCouldBeAutoSignedInPtr(_)).Times(0);
+  EXPECT_CALL(*client_, NotifyUserCouldBeAutoSignedInPtr).Times(0);
   ExpectZeroClickSignInFailure(CredentialMediationRequirement::kSilent, false,
                                federations);
 }
@@ -1111,7 +1106,7 @@
   std::vector<GURL> federations;
   federations.emplace_back("https://example.com/");
 
-  EXPECT_CALL(*client_, NotifyUserCouldBeAutoSignedInPtr(_)).Times(0);
+  EXPECT_CALL(*client_, NotifyUserCouldBeAutoSignedInPtr).Times(0);
 
   ExpectZeroClickSignInSuccess(CredentialMediationRequirement::kSilent, true,
                                federations,
@@ -1128,7 +1123,7 @@
   std::vector<GURL> federations;
   federations.emplace_back("https://not-example.com/");
 
-  EXPECT_CALL(*client_, NotifyUserCouldBeAutoSignedInPtr(_)).Times(0);
+  EXPECT_CALL(*client_, NotifyUserCouldBeAutoSignedInPtr).Times(0);
 
   ExpectZeroClickSignInFailure(CredentialMediationRequirement::kSilent, true,
                                federations);
@@ -1212,15 +1207,12 @@
 
 TEST_P(CredentialManagerImplTest, RequestCredentialWithoutFirstRun) {
   client_->set_first_run_seen(false);
-
   store_->AddLogin(form_);
-
   form_.match_type = PasswordForm::MatchType::kExact;
 
   std::vector<GURL> federations;
   EXPECT_CALL(*client_, NotifyUserCouldBeAutoSignedInPtr(
-                            Pointee(MatchesFormExceptStore(form_))))
-      .Times(1);
+                            Pointee(MatchesFormExceptStore(form_))));
 
   ExpectZeroClickSignInFailure(CredentialMediationRequirement::kSilent, true,
                                federations);
@@ -1228,16 +1220,13 @@
 
 TEST_P(CredentialManagerImplTest, RequestCredentialWithFirstRunAndSkip) {
   client_->set_first_run_seen(true);
-
   form_.skip_zero_click = true;
   store_->AddLogin(form_);
-
   form_.match_type = PasswordForm::MatchType::kExact;
 
   std::vector<GURL> federations;
   EXPECT_CALL(*client_, NotifyUserCouldBeAutoSignedInPtr(
-                            Pointee(MatchesFormExceptStore(form_))))
-      .Times(1);
+                            Pointee(MatchesFormExceptStore(form_))));
 
   ExpectZeroClickSignInFailure(CredentialMediationRequirement::kSilent, true,
                                federations);
@@ -1245,11 +1234,9 @@
 
 TEST_P(CredentialManagerImplTest, RequestCredentialWithTLSErrors) {
   // If we encounter TLS errors, we won't return credentials.
-  EXPECT_CALL(*client_, IsFillingEnabled(_))
-      .WillRepeatedly(testing::Return(false));
+  EXPECT_CALL(*client_, IsFillingEnabled).WillRepeatedly(Return(false));
 
   store_->AddLogin(form_);
-
   std::vector<GURL> federations;
 
   ExpectZeroClickSignInFailure(CredentialMediationRequirement::kSilent, true,
@@ -1262,9 +1249,8 @@
   store_->AddLogin(origin_path_form_);
 
   std::vector<GURL> federations;
-  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
-      .Times(testing::Exactly(0));
-  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
+  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr).Times(0);
+  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr).Times(0);
 
   // With two items in the password store, we shouldn't get credentials back.
   ExpectCredentialType(CredentialMediationRequirement::kSilent, true,
@@ -1278,9 +1264,8 @@
   store_->AddLogin(origin_path_form_);
 
   std::vector<GURL> federations;
-  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
-      .Times(testing::Exactly(0));
-  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
+  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr).Times(0);
+  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr).Times(0);
 
   // With two items in the password store, we shouldn't get credentials back,
   // even though only one item has |skip_zero_click| set |false|.
@@ -1296,9 +1281,8 @@
   store_->AddLogin(form_);
 
   std::vector<GURL> federations;
-  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
-      .Times(testing::Exactly(0));
-  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
+  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr).Times(0);
+  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr).Times(0);
 
   // We only have cross-origin zero-click credentials; they should not be
   // returned.
@@ -1312,9 +1296,8 @@
   store_->AddLogin(form_);
 
   std::vector<GURL> federations;
-  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
-      .Times(testing::Exactly(0));
-  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
+  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr).Times(0);
+  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr).Times(0);
 
   // 1st request.
   bool called_1 = false;
@@ -1331,9 +1314,8 @@
           base::BindOnce(&GetCredentialCallback, &called_2, &error_2,
                          &credential_2));
 
-  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
-      .Times(testing::Exactly(1));
-  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
+  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr);
+  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr).Times(0);
 
   // Execute the PasswordStore asynchronousness.
   RunAllPendingTasks();
@@ -1378,9 +1360,8 @@
   // MockPasswordManagerClient mocks a user choice, and when users choose a
   // credential (and have the global zero-click flag enabled), we make sure that
   // they'll be logged in again next time.
-  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
-      .Times(testing::Exactly(1));
-  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
+  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr);
+  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr).Times(0);
 
   bool called = false;
   CredentialManagerError error;
@@ -1418,9 +1399,8 @@
   // MockPasswordManagerClient mocks a user choice, and when users choose a
   // credential (and have the global zero-click flag enabled), we make sure that
   // they'll be logged in again next time.
-  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr)
-      .Times(testing::Exactly(1));
-  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
+  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr);
+  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr).Times(0);
 
   bool called = false;
   CredentialManagerError error;
@@ -1460,9 +1440,8 @@
   // MockPasswordManagerClient mocks a user choice, and when users choose a
   // credential (and have the global zero-click flag enabled), we make sure that
   // they'll be logged in again next time.
-  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr)
-      .Times(testing::Exactly(1));
-  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
+  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr);
+  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr).Times(0);
 
   bool called = false;
   CredentialManagerError error;
@@ -1485,13 +1464,12 @@
 }
 
 TEST_P(CredentialManagerImplTest, IncognitoZeroClickRequestCredential) {
-  EXPECT_CALL(*client_, IsOffTheRecord()).WillRepeatedly(testing::Return(true));
+  EXPECT_CALL(*client_, IsOffTheRecord()).WillRepeatedly(Return(true));
   store_->AddLogin(form_);
 
   std::vector<GURL> federations;
-  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
-      .Times(testing::Exactly(0));
-  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
+  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr).Times(0);
+  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr).Times(0);
 
   ExpectCredentialType(CredentialMediationRequirement::kSilent, true,
                        federations, CredentialType::CREDENTIAL_TYPE_EMPTY);
@@ -1628,9 +1606,8 @@
   CredentialManagerError error;
   absl::optional<CredentialInfo> credential;
 
-  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _))
-      .Times(testing::Exactly(1));
-  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(testing::Exactly(0));
+  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr);
+  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr).Times(0);
   CallGet(CredentialMediationRequirement::kRequired, true, federations,
           base::BindOnce(&GetCredentialCallback, &called, &error, &credential));
 
@@ -1650,7 +1627,9 @@
 }
 
 TEST_P(CredentialManagerImplTest, BlockedPasswordCredential) {
-  EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_));
+  std::unique_ptr<PasswordFormManagerForUI> pending_manager;
+  EXPECT_CALL(*client_, PromptUserToSaveOrUpdatePassword)
+      .WillOnce(MoveArgAndReturn<0>(&pending_manager, true));
 
   auto info = PasswordFormToCredentialInfo(form_);
   bool called = false;
@@ -1658,8 +1637,8 @@
   // Allow the PasswordFormManager to talk to the password store
   RunAllPendingTasks();
 
-  ASSERT_TRUE(client_->pending_manager());
-  client_->pending_manager()->Blocklist();
+  ASSERT_TRUE(pending_manager);
+  pending_manager->Blocklist();
   // Allow the PasswordFormManager to talk to the password store.
   RunAllPendingTasks();
 
@@ -1679,15 +1658,17 @@
   form_.password_value = std::u16string();
   form_.signon_realm = "federation://example.com/example.com";
 
-  EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_));
+  std::unique_ptr<PasswordFormManagerForUI> pending_manager;
+  EXPECT_CALL(*client_, PromptUserToSaveOrUpdatePassword)
+      .WillOnce(MoveArgAndReturn<0>(&pending_manager, true));
   auto info = PasswordFormToCredentialInfo(form_);
   bool called = false;
   CallStore(info, base::BindOnce(&RespondCallback, &called));
   // Allow the PasswordFormManager to talk to the password store
   RunAllPendingTasks();
 
-  ASSERT_TRUE(client_->pending_manager());
-  client_->pending_manager()->Blocklist();
+  ASSERT_TRUE(pending_manager);
+  pending_manager->Blocklist();
   // Allow the PasswordFormManager to talk to the password store.
   RunAllPendingTasks();
 
@@ -1713,13 +1694,15 @@
 
   auto info = PasswordFormToCredentialInfo(form_);
   bool called = false;
-  EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_));
+  std::unique_ptr<PasswordFormManagerForUI> pending_manager;
+  EXPECT_CALL(*client_, PromptUserToSaveOrUpdatePassword)
+      .WillOnce(MoveArgAndReturn<0>(&pending_manager, true));
   CallStore(info, base::BindOnce(&RespondCallback, &called));
   // Allow the PasswordFormManager to talk to the password store
   RunAllPendingTasks();
 
-  ASSERT_TRUE(client_->pending_manager());
-  EXPECT_TRUE(client_->pending_manager()->IsBlocklisted());
+  ASSERT_TRUE(pending_manager);
+  EXPECT_TRUE(pending_manager->IsBlocklisted());
 }
 
 TEST_P(CredentialManagerImplTest, RespectBlockedFederatedCredential) {
@@ -1734,13 +1717,15 @@
   form_.signon_realm = "federation://example.com/example.com";
   auto info = PasswordFormToCredentialInfo(form_);
   bool called = false;
-  EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_));
+  std::unique_ptr<PasswordFormManagerForUI> pending_manager;
+  EXPECT_CALL(*client_, PromptUserToSaveOrUpdatePassword)
+      .WillOnce(MoveArgAndReturn<0>(&pending_manager, true));
   CallStore(info, base::BindOnce(&RespondCallback, &called));
   // Allow the PasswordFormManager to talk to the password store
   RunAllPendingTasks();
 
-  ASSERT_TRUE(client_->pending_manager());
-  EXPECT_TRUE(client_->pending_manager()->IsBlocklisted());
+  ASSERT_TRUE(pending_manager);
+  EXPECT_TRUE(pending_manager->IsBlocklisted());
 }
 
 TEST_P(CredentialManagerImplTest,
@@ -1806,7 +1791,7 @@
               Start(LeakDetectionInitiator::kSignInCheck, form_.url,
                     form_.username_value, form_.password_value));
   EXPECT_CALL(*weak_factory, TryCreateLeakCheck)
-      .WillOnce(testing::Return(testing::ByMove(std::move(check_instance))));
+      .WillOnce(Return(testing::ByMove(std::move(check_instance))));
   CallStore(PasswordFormToCredentialInfo(form_), base::DoNothing());
 
   RunAllPendingTasks();
diff --git a/components/password_manager/core/browser/sharing/recipients_fetcher.cc b/components/password_manager/core/browser/sharing/recipients_fetcher.cc
new file mode 100644
index 0000000..4019de4
--- /dev/null
+++ b/components/password_manager/core/browser/sharing/recipients_fetcher.cc
@@ -0,0 +1,22 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/password_manager/core/browser/sharing/recipients_fetcher.h"
+
+namespace password_manager {
+
+RecipientInfo::RecipientInfo() = default;
+
+RecipientInfo::RecipientInfo(const RecipientInfo& other) = default;
+RecipientInfo::RecipientInfo(RecipientInfo&& other) = default;
+RecipientInfo& RecipientInfo::operator=(const RecipientInfo&) = default;
+RecipientInfo& RecipientInfo::operator=(RecipientInfo&&) = default;
+RecipientInfo::~RecipientInfo() = default;
+
+bool RecipientInfo::operator==(const RecipientInfo& other) const {
+  return user_id == other.user_id && user_name == other.user_name &&
+         email == other.email && profile_image_url == other.profile_image_url;
+}
+
+}  // namespace password_manager
diff --git a/components/password_manager/core/browser/sharing/recipients_fetcher.h b/components/password_manager/core/browser/sharing/recipients_fetcher.h
index 3996439..21eaf80e 100644
--- a/components/password_manager/core/browser/sharing/recipients_fetcher.h
+++ b/components/password_manager/core/browser/sharing/recipients_fetcher.h
@@ -9,18 +9,32 @@
 
 #include "base/functional/callback.h"
 
+namespace password_manager {
+
 // An Enum that contains possible request status values for a Fetch Recipients
 // request.
 enum class FetchFamilyMembersRequestStatus {
   kUnknown = 0,
   kSuccess = 1,
   kNetworkError = 2,
+  // The user (sending the request) is not part of a family circle.
   kNoFamily = 3,
-}
+  // A pending requests already exists. No new request was created.
+  kPendingRequest = 4,
+};
 
 // The RecipientInfo struct represents a recipient with whom the user can share
 // a password.
 struct RecipientInfo {
+  RecipientInfo();
+  RecipientInfo(const RecipientInfo&);
+  RecipientInfo(RecipientInfo&&);
+  RecipientInfo& operator=(const RecipientInfo&);
+  RecipientInfo& operator=(RecipientInfo&&);
+  ~RecipientInfo();
+
+  bool operator==(const RecipientInfo& other) const;
+
   // Recipient's user identifier (obfuscated Gaia ID).
   std::string user_id;
   // Recipients's user name for display in the UI.
@@ -32,7 +46,7 @@
 
   // TODO(crbug.com/1456309): Add a field for the public certificate after the
   // decision was made which type to use.
-}
+};
 
 // The RecipientsFetcher class defines the interface for fetching a list of
 // potential recipients with whom the user is able to share passwords.
@@ -45,11 +59,13 @@
   RecipientsFetcher() = default;
   RecipientsFetcher(const RecipientsFetcher&) = delete;
   RecipientsFetcher& operator=(const RecipientsFetcher&) = delete;
-  ~RecipientsFetcher() override = default;
+  virtual ~RecipientsFetcher() = default;
 
   // Fetches the list of family members from the server. The success status of
   // the request will be passed to the callback.
   virtual void FetchFamilyMembers(FetchFamilyMembersCallback callback) = 0;
 };
 
+}  // namespace password_manager
+
 #endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SHARING_RECIPIENTS_FETCHER_H_
diff --git a/components/password_manager/core/browser/sharing/recipients_fetcher_impl.cc b/components/password_manager/core/browser/sharing/recipients_fetcher_impl.cc
new file mode 100644
index 0000000..08e1fc9
--- /dev/null
+++ b/components/password_manager/core/browser/sharing/recipients_fetcher_impl.cc
@@ -0,0 +1,111 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/password_manager/core/browser/sharing/recipients_fetcher_impl.h"
+
+#include <memory>
+
+#include "base/functional/bind.h"
+#include "base/functional/callback_forward.h"
+#include "base/memory/raw_ptr.h"
+#include "components/password_manager/core/browser/sharing/password_sharing_recipients_downloader.h"
+#include "components/password_manager/core/browser/sharing/recipients_fetcher.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
+#include "net/http/http_status_code.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+
+using sync_pb::PasswordSharingRecipientsResponse;
+
+namespace password_manager {
+
+namespace {
+
+bool hasServerRequestCompletedWithSuccess(
+    const PasswordSharingRecipientsDownloader& request) {
+  return (request.GetHttpError() == net::HTTP_OK &&
+          request.GetNetError() == net::OK);
+}
+
+RecipientInfo ToRecipientInfo(const sync_pb::UserInfo& user_info) {
+  RecipientInfo recipient_info;
+  recipient_info.user_id = user_info.user_id();
+  recipient_info.user_name = user_info.user_display_info().display_name();
+  recipient_info.email = user_info.user_display_info().email();
+  recipient_info.profile_image_url =
+      user_info.user_display_info().profile_image_url();
+
+  // TODO(crbug.com/1456309) Add the Encryption Key once a decision has been
+  // made which type to use.
+  return recipient_info;
+}
+
+}  // Namespace
+
+RecipientsFetcherImpl::RecipientsFetcherImpl(
+    version_info::Channel channel,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+    raw_ptr<signin::IdentityManager> identity_manager)
+    : channel_(channel),
+      url_loader_factory_(url_loader_factory),
+      identity_manager_(identity_manager) {}
+
+RecipientsFetcherImpl::~RecipientsFetcherImpl() = default;
+
+void RecipientsFetcherImpl::FetchFamilyMembers(
+    FetchFamilyMembersCallback callback) {
+  // There can be only one request in flight at any point in time.
+  if (pending_request_) {
+    std::move(callback).Run(std::vector<RecipientInfo>(),
+                            FetchFamilyMembersRequestStatus::kPendingRequest);
+    return;
+  }
+
+  callback_ = std::move(callback);
+
+  pending_request_ = std::make_unique<PasswordSharingRecipientsDownloader>(
+      channel_, url_loader_factory_, identity_manager_.get());
+  pending_request_->Start(base::BindOnce(
+      &RecipientsFetcherImpl::ServerRequestCallback, base::Unretained(this)));
+}
+
+void RecipientsFetcherImpl::ServerRequestCallback() {
+  if (!hasServerRequestCompletedWithSuccess(*pending_request_)) {
+    std::move(callback_).Run(std::vector<RecipientInfo>(),
+                             FetchFamilyMembersRequestStatus::kNetworkError);
+    return;
+  }
+
+  absl::optional<sync_pb::PasswordSharingRecipientsResponse> server_response =
+      pending_request_->TakeResponse();
+  // Destroy the request object after the response was fetched otherwise no
+  // further call can be made.
+  pending_request_.reset();
+
+  CHECK(server_response.has_value());
+
+  switch (server_response->result()) {
+    case PasswordSharingRecipientsResponse::SUCCESS: {
+      std::vector<RecipientInfo> recipients;
+      for (const auto& recipient : server_response->recipients()) {
+        recipients.push_back(ToRecipientInfo(recipient));
+      }
+
+      std::move(callback_).Run(std::move(recipients),
+                               FetchFamilyMembersRequestStatus::kSuccess);
+      return;
+    }
+    case PasswordSharingRecipientsResponse::NOT_FAMILY_MEMBER: {
+      std::move(callback_).Run(std::vector<RecipientInfo>(),
+                               FetchFamilyMembersRequestStatus::kNoFamily);
+      return;
+    }
+    case PasswordSharingRecipientsResponse::UNKNOWN: {
+      std::move(callback_).Run(std::vector<RecipientInfo>(),
+                               FetchFamilyMembersRequestStatus::kUnknown);
+      return;
+    }
+  }
+}
+
+}  // namespace password_manager
diff --git a/components/password_manager/core/browser/sharing/recipients_fetcher_impl.h b/components/password_manager/core/browser/sharing/recipients_fetcher_impl.h
new file mode 100644
index 0000000..514c1cb6
--- /dev/null
+++ b/components/password_manager/core/browser/sharing/recipients_fetcher_impl.h
@@ -0,0 +1,58 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SHARING_RECIPIENTS_FETCHER_IMPL_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SHARING_RECIPIENTS_FETCHER_IMPL_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/memory/raw_ptr.h"
+#include "components/password_manager/core/browser/sharing/password_sharing_recipients_downloader.h"
+#include "components/password_manager/core/browser/sharing/recipients_fetcher.h"
+#include "components/version_info/channel.h"
+
+namespace network {
+class SharedURLLoaderFactory;
+}  // namespace network
+
+namespace signin {
+class IdentityManager;
+}  // namespace signin
+
+namespace password_manager {
+
+// The class is the implementation of the `RecipientFetcher` interface.
+class RecipientsFetcherImpl : public RecipientsFetcher {
+ public:
+  explicit RecipientsFetcherImpl(
+      version_info::Channel channel,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      raw_ptr<signin::IdentityManager> identity_manager);
+  RecipientsFetcherImpl(const RecipientsFetcherImpl&) = delete;
+  RecipientsFetcherImpl& operator=(const RecipientsFetcherImpl&) = delete;
+  ~RecipientsFetcherImpl() override;
+
+  // Fetches the Family Members including status about their capability for
+  // receiving Passwords.
+  // If a call to the server is already in flight, no new call will be issued
+  // for further consecutive method calls. The callback of concurrent calls will
+  // be run immediately with the status set to kPendingRequest, indicating that
+  // there is already an active request in flight.
+  void FetchFamilyMembers(FetchFamilyMembersCallback callback) override;
+
+ private:
+  void ServerRequestCallback();
+
+  const version_info::Channel channel_;
+  const scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+  const raw_ptr<signin::IdentityManager> identity_manager_;
+
+  FetchFamilyMembersCallback callback_;
+  std::unique_ptr<PasswordSharingRecipientsDownloader> pending_request_;
+};
+
+}  // namespace password_manager
+
+#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SHARING_RECIPIENTS_FETCHER_IMPL_H_
diff --git a/components/password_manager/core/browser/sharing/recipients_fetcher_impl_unittest.cc b/components/password_manager/core/browser/sharing/recipients_fetcher_impl_unittest.cc
new file mode 100644
index 0000000..05b0084
--- /dev/null
+++ b/components/password_manager/core/browser/sharing/recipients_fetcher_impl_unittest.cc
@@ -0,0 +1,203 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "components/password_manager/core/browser/sharing/recipients_fetcher_impl.h"
+
+#include <memory>
+
+#include "base/memory/raw_ptr.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/task/single_thread_task_runner.h"
+#include "base/test/mock_callback.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_simple_task_runner.h"
+#include "components/signin/public/identity_manager/identity_test_environment.h"
+#include "components/sync/protocol/password_sharing_recipients.pb.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace password_manager {
+
+namespace {
+
+using ::testing::_;
+using ::testing::ElementsAre;
+using ::testing::Eq;
+using ::testing::IsEmpty;
+using ::testing::StrictMock;
+
+// TODO(crbug.com/) Move this to a common test helper to simplyfy the setup in
+// tests and the maintainace later.
+void SetupIdentityEnvironment(
+    raw_ptr<signin::IdentityTestEnvironment> identity_test_env) {
+  identity_test_env->MakePrimaryAccountAvailable("test@email.com",
+                                                 signin::ConsentLevel::kSync);
+  identity_test_env->SetAutomaticIssueOfAccessTokens(true);
+}
+
+class RecipientsFetcherImplTest : public testing::Test {
+ public:
+  RecipientsFetcherImplTest() { SetupIdentityEnvironment(&identity_test_env_); }
+  ~RecipientsFetcherImplTest() override = default;
+
+  RecipientsFetcherImpl CreateRecipientFetcher() {
+    return RecipientsFetcherImpl(version_info::Channel::DEFAULT,
+                                 test_url_loader_factory_.GetSafeWeakWrapper(),
+                                 identity_test_env_.identity_manager());
+  }
+
+  void SetServerResponse(
+      const sync_pb::PasswordSharingRecipientsResponse& response) {
+    test_url_loader_factory_.AddResponse(
+        PasswordSharingRecipientsDownloader::GetPasswordSharingRecipientsURL(
+            version_info::Channel::DEFAULT)
+            .spec(),
+        response.SerializeAsString());
+  }
+
+ protected:
+  void RunUntilIdle() { task_environment_.RunUntilIdle(); }
+
+ private:
+  base::test::SingleThreadTaskEnvironment task_environment_;
+  network::TestURLLoaderFactory test_url_loader_factory_;
+  signin::IdentityTestEnvironment identity_test_env_;
+};
+
+// Tests the happy case in which the server returns a potential candidate to
+// share a password with. This is done by pre-configuring the expected server
+// response. In a real encironment the user the sends the request and the
+// returned conadiate also need ot be in the same family cicle.
+TEST_F(RecipientsFetcherImplTest, ShouldFetchRecpientInfoWhenRequestSucceeds) {
+  const std::string kTestUserId = "12345";
+  const std::string kTestUserName = "Theo Tester";
+  const std::string kTestEmail = "theo@example.com";
+  const std::string kTestProfileImageUrl =
+      "https://3837fjsdjaka.image.example.com";
+
+  // Create set the server response.
+  sync_pb::PasswordSharingRecipientsResponse response;
+  response.set_result(sync_pb::PasswordSharingRecipientsResponse::SUCCESS);
+
+  sync_pb::UserInfo* user_info = response.add_recipients();
+  user_info->set_user_id(kTestUserId);
+  user_info->mutable_user_display_info()->set_display_name(kTestUserName);
+  user_info->mutable_user_display_info()->set_email(kTestEmail);
+  user_info->mutable_user_display_info()->set_profile_image_url(
+      kTestProfileImageUrl);
+
+  SetServerResponse(response);
+
+  // Set up the expected callback.
+  RecipientInfo expected_recipient_info;
+  expected_recipient_info.user_id = kTestUserId;
+  expected_recipient_info.user_name = kTestUserName;
+  expected_recipient_info.email = kTestEmail;
+  expected_recipient_info.profile_image_url = kTestProfileImageUrl;
+  StrictMock<base::MockCallback<RecipientsFetcher::FetchFamilyMembersCallback>>
+      callback;
+  EXPECT_CALL(callback, Run(ElementsAre(expected_recipient_info),
+                            Eq(FetchFamilyMembersRequestStatus::kSuccess)));
+
+  // Create the RecipientFetcher and make a request.
+  RecipientsFetcherImpl recipient_fetcher = CreateRecipientFetcher();
+  recipient_fetcher.FetchFamilyMembers(callback.Get());
+
+  RunUntilIdle();
+}
+
+// Tests the scenario in which the sender of the request is not part of a family
+// circle. This is simulated by pre-configuring the expected server response.
+TEST_F(RecipientsFetcherImplTest,
+       ShouldReturnNotFamilyMemeberStatusIfUserIsNotInFamilyCircle) {
+  sync_pb::PasswordSharingRecipientsResponse response;
+  response.set_result(
+      sync_pb::PasswordSharingRecipientsResponse::NOT_FAMILY_MEMBER);
+  SetServerResponse(response);
+
+  StrictMock<base::MockCallback<RecipientsFetcher::FetchFamilyMembersCallback>>
+      callback;
+  EXPECT_CALL(callback,
+              Run(IsEmpty(), Eq(FetchFamilyMembersRequestStatus::kNoFamily)));
+
+  RecipientsFetcherImpl recipient_fetcher = CreateRecipientFetcher();
+  recipient_fetcher.FetchFamilyMembers(callback.Get());
+
+  RunUntilIdle();
+}
+
+TEST_F(RecipientsFetcherImplTest,
+       ShouldReturnUnknownStatusIfSyncRequestHasUnknownError) {
+  sync_pb::PasswordSharingRecipientsResponse response;
+  response.set_result(sync_pb::PasswordSharingRecipientsResponse::UNKNOWN);
+  SetServerResponse(response);
+
+  StrictMock<base::MockCallback<RecipientsFetcher::FetchFamilyMembersCallback>>
+      callback;
+  EXPECT_CALL(callback,
+              Run(IsEmpty(), Eq(FetchFamilyMembersRequestStatus::kUnknown)));
+
+  RecipientsFetcherImpl recipient_fetcher = CreateRecipientFetcher();
+  recipient_fetcher.FetchFamilyMembers(callback.Get());
+
+  RunUntilIdle();
+}
+
+// Tests that there can only be a single request active at any point in time.
+// Concurrent requests will be instantly completed with the request status set
+// to kPendingRequest.
+TEST_F(RecipientsFetcherImplTest, ShouldNotFetchRecipientIfPendingRequest) {
+  StrictMock<base::MockCallback<RecipientsFetcher::FetchFamilyMembersCallback>>
+      callback;
+  EXPECT_CALL(callback, Run(_, Eq(FetchFamilyMembersRequestStatus::kSuccess)));
+
+  StrictMock<base::MockCallback<RecipientsFetcher::FetchFamilyMembersCallback>>
+      callback2;
+  EXPECT_CALL(
+      callback2,
+      Run(IsEmpty(), Eq(FetchFamilyMembersRequestStatus::kPendingRequest)));
+
+  RecipientsFetcherImpl recipient_fetcher = CreateRecipientFetcher();
+  recipient_fetcher.FetchFamilyMembers(callback.Get());
+  recipient_fetcher.FetchFamilyMembers(callback2.Get());
+
+  sync_pb::PasswordSharingRecipientsResponse response;
+  response.set_result(sync_pb::PasswordSharingRecipientsResponse::SUCCESS);
+  SetServerResponse(response);
+
+  RunUntilIdle();
+}
+
+TEST_F(RecipientsFetcherImplTest,
+       ShouldFetchRecpientInfoWhenRequestSucceedsForConsequitiveRequests) {
+  StrictMock<base::MockCallback<RecipientsFetcher::FetchFamilyMembersCallback>>
+      callback;
+  EXPECT_CALL(callback, Run(_, Eq(FetchFamilyMembersRequestStatus::kSuccess)));
+
+  StrictMock<base::MockCallback<RecipientsFetcher::FetchFamilyMembersCallback>>
+      callback2;
+  EXPECT_CALL(callback2, Run(_, Eq(FetchFamilyMembersRequestStatus::kSuccess)));
+
+  RecipientsFetcherImpl recipient_fetcher = CreateRecipientFetcher();
+  recipient_fetcher.FetchFamilyMembers(callback.Get());
+
+  sync_pb::PasswordSharingRecipientsResponse response;
+  response.set_result(sync_pb::PasswordSharingRecipientsResponse::SUCCESS);
+  SetServerResponse(response);
+
+  RunUntilIdle();
+
+  recipient_fetcher.FetchFamilyMembers(callback2.Get());
+  RunUntilIdle();
+}
+
+// TODO(crbug.com/1454712) Implement test case once the error handling in the
+// PasswordSharingRecipientsDownloader is implemented.
+TEST_F(RecipientsFetcherImplTest, FetchRecipientDuringAuthError) {}
+
+}  // namespace
+
+}  // namespace password_manager
diff --git a/components/payments/core/features.cc b/components/payments/core/features.cc
index 23362cab..e8de292 100644
--- a/components/payments/core/features.cc
+++ b/components/payments/core/features.cc
@@ -25,7 +25,7 @@
 
 BASE_FEATURE(kAppStoreBilling,
              "AppStoreBilling",
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
              base::FEATURE_ENABLED_BY_DEFAULT
 #else
              base::FEATURE_DISABLED_BY_DEFAULT
diff --git a/components/viz/service/display/overlay_candidate_factory.cc b/components/viz/service/display/overlay_candidate_factory.cc
index d5a4fd5..83e1abd 100644
--- a/components/viz/service/display/overlay_candidate_factory.cc
+++ b/components/viz/service/display/overlay_candidate_factory.cc
@@ -391,17 +391,19 @@
   }
 
   if (context_.is_delegated_context) {
-    // Lacros cannot currently delegate clip rects on quads that extend outside
-    // the primary rect. This is because there are bugs that cause the Lacros
-    // window and drop shadow to move incorrectly in that case.
     const bool quad_within_window =
         primary_rect_.Contains(candidate.display_rect);
     const bool transform_supports_clipping =
         context_.supports_arbitrary_transform ||
         absl::holds_alternative<gfx::OverlayTransform>(candidate.transform);
     const bool has_content_clipping = quad->visible_rect != quad->rect;
+
+    // Out of window clipping is enabled on Lacros only when it is supported.
+    // TODO(crbug.com/1385509): Remove the condition on `quad_within_window`
+    // when M117 becomes widely supported.
     const bool can_delegate_clipping =
-        context_.supports_clip_rect && quad_within_window &&
+        context_.supports_clip_rect &&
+        (quad_within_window || context_.supports_out_of_window_clip_rect) &&
         transform_supports_clipping && !has_content_clipping;
     if (can_delegate_clipping) {
       if (candidate.clip_rect.has_value() && candidate.clip_rect->IsEmpty()) {
diff --git a/components/viz/service/display/overlay_candidate_factory.h b/components/viz/service/display/overlay_candidate_factory.h
index 5d5c506..0694000 100644
--- a/components/viz/service/display/overlay_candidate_factory.h
+++ b/components/viz/service/display/overlay_candidate_factory.h
@@ -49,6 +49,7 @@
   struct VIZ_SERVICE_EXPORT OverlayContext {
     bool is_delegated_context = false;
     bool supports_clip_rect = false;
+    bool supports_out_of_window_clip_rect = false;
     bool supports_arbitrary_transform = false;
     bool supports_rounded_display_masks = false;
     bool supports_mask_filter = false;
diff --git a/components/viz/service/display/overlay_candidate_factory_unittest.cc b/components/viz/service/display/overlay_candidate_factory_unittest.cc
index 39e0437..d870da6 100644
--- a/components/viz/service/display/overlay_candidate_factory_unittest.cc
+++ b/components/viz/service/display/overlay_candidate_factory_unittest.cc
@@ -41,6 +41,7 @@
 constexpr OverlayCandidateFactory::OverlayContext kOverlayContextForTesting{
     .is_delegated_context = true,
     .supports_clip_rect = true,
+    .supports_out_of_window_clip_rect = true,
     .supports_arbitrary_transform = true,
     .supports_rounded_display_masks = false};
 
@@ -364,6 +365,7 @@
   const OverlayCandidateFactory::OverlayContext context = {
       .is_delegated_context = true,
       .supports_clip_rect = false,
+      .supports_out_of_window_clip_rect = false,
       .supports_arbitrary_transform = true};
 
   EXPECT_DEATH(CreateCandidateFactory(
@@ -744,20 +746,22 @@
   AggregatedRenderPass render_pass;
   render_pass.SetNew(AggregatedRenderPassId::FromUnsafeValue(1),
                      gfx::Rect(0, 0, 100, 100), gfx::Rect(), gfx::Transform());
-  gfx::Rect rect(0, 0, 75, 75);
-  gfx::Rect clip(0, 0, 50, 50);
+  constexpr gfx::Rect kRect(0, 0, 75, 75);
+  constexpr gfx::Rect kClip(0, 0, 50, 50);
   // Transform up, outside the window.
   gfx::Transform transform;
   transform.Translate(gfx::Vector2dF(0, -30));
-  auto* quad = AddQuad(rect, transform, &render_pass, clip, rect);
+  auto* quad = AddQuad(kRect, transform, &render_pass, kClip, kRect);
 
   OverlayCandidateFactory noclip_factory = CreateCandidateFactory(
       render_pass, gfx::RectF(render_pass.output_rect),
       OverlayCandidateFactory::OverlayContext{.is_delegated_context = true});
-  OverlayCandidateFactory clip_factory = CreateCandidateFactory(
-      render_pass, gfx::RectF(render_pass.output_rect),
-      OverlayCandidateFactory::OverlayContext{.is_delegated_context = true,
-                                              .supports_clip_rect = true});
+  OverlayCandidateFactory clip_factory =
+      CreateCandidateFactory(render_pass, gfx::RectF(render_pass.output_rect),
+                             OverlayCandidateFactory::OverlayContext{
+                                 .is_delegated_context = true,
+                                 .supports_clip_rect = true,
+                                 .supports_out_of_window_clip_rect = true});
 
   OverlayCandidate no_clip_cand;
   OverlayCandidate clip_cand;
@@ -766,12 +770,13 @@
   ASSERT_EQ(clip_factory.FromDrawQuad(quad, clip_cand),
             OverlayCandidate::CandidateStatus::kSuccess);
 
-  // Clip rect can't be delegated because it's no within the window.
-  gfx::RectF clipped(0, 0, 50, 45);
-  EXPECT_RECTF_EQ(no_clip_cand.display_rect, clipped);
+  // Clip rect can be delegated if supported.
+  constexpr gfx::RectF kTransformedClip(0, 0, 50, 45);
+  constexpr gfx::RectF kTransformedRect(0, -30, 75, 75);
+  EXPECT_RECTF_EQ(no_clip_cand.display_rect, kTransformedClip);
   EXPECT_FALSE(no_clip_cand.clip_rect.has_value());
-  EXPECT_RECTF_EQ(clip_cand.display_rect, clipped);
-  EXPECT_FALSE(clip_cand.clip_rect.has_value());
+  EXPECT_RECTF_EQ(clip_cand.display_rect, kTransformedRect);
+  EXPECT_EQ(clip_cand.clip_rect.value(), kClip);
 }
 
 TEST_F(OverlayCandidateFactoryTest, ClipDelegation_VisibleRect) {
diff --git a/components/viz/service/display/overlay_processor_delegated.cc b/components/viz/service/display/overlay_processor_delegated.cc
index 9843742..d5c9e2c 100644
--- a/components/viz/service/display/overlay_processor_delegated.cc
+++ b/components/viz/service/display/overlay_processor_delegated.cc
@@ -96,13 +96,18 @@
                             shared_image_interface) {
   // TODO(msisov, petermcneeley): remove this once Wayland uses only delegated
   // context. May be null in tests.
-  if (ui::OzonePlatform::GetInstance()->GetOverlayManager())
+  if (ui::OzonePlatform::GetInstance()->GetOverlayManager()) {
     ui::OzonePlatform::GetInstance()
         ->GetOverlayManager()
         ->SetContextDelegated();
+  }
+
   supports_clip_rect_ = ui::OzonePlatform::GetInstance()
                             ->GetPlatformRuntimeProperties()
                             .supports_clip_rect;
+  supports_out_of_window_clip_rect_ = ui::OzonePlatform::GetInstance()
+                                          ->GetPlatformRuntimeProperties()
+                                          .supports_out_of_window_clip_rect;
   needs_background_image_ = ui::OzonePlatform::GetInstance()
                                 ->GetPlatformRuntimeProperties()
                                 .needs_background_image;
@@ -166,6 +171,7 @@
   const OverlayCandidateFactory::OverlayContext context = {
       .is_delegated_context = true,
       .supports_clip_rect = supports_clip_rect_,
+      .supports_out_of_window_clip_rect = supports_out_of_window_clip_rect_,
       .supports_mask_filter = true};
 
   OverlayCandidateFactory candidate_factory = OverlayCandidateFactory(
diff --git a/components/viz/service/display/overlay_processor_delegated.h b/components/viz/service/display/overlay_processor_delegated.h
index f27a0dc..32186e8 100644
--- a/components/viz/service/display/overlay_processor_delegated.h
+++ b/components/viz/service/display/overlay_processor_delegated.h
@@ -120,6 +120,7 @@
 
   DelegationStatus delegated_status_ = DelegationStatus::kCompositedOther;
   bool supports_clip_rect_ = false;
+  bool supports_out_of_window_clip_rect_ = false;
   bool needs_background_image_ = false;
   gfx::RectF unassigned_damage_;
   // Used to count the number of frames we should wait until allowing delegation
diff --git a/content/browser/browsing_data/browsing_data_remover_impl.cc b/content/browser/browsing_data/browsing_data_remover_impl.cc
index 9f09090..d1725fd 100644
--- a/content/browser/browsing_data/browsing_data_remover_impl.cc
+++ b/content/browser/browsing_data/browsing_data_remover_impl.cc
@@ -121,7 +121,6 @@
     : browser_context_(browser_context),
       remove_mask_(0xffffffffffffffffull),
       origin_type_mask_(0xffffffffffffffffull),
-      storage_partition_config_(absl::nullopt),
       is_removing_(false) {
   DCHECK(browser_context_);
 }
@@ -350,7 +349,6 @@
   delete_end_ = delete_end;
   remove_mask_ = remove_mask;
   origin_type_mask_ = origin_type_mask;
-  storage_partition_config_ = filter_builder->GetStoragePartitionConfig();
   failed_data_types_ = 0;
 
   // Record the combined deletion of cookies and cache.
@@ -704,15 +702,6 @@
   return origin_type_mask_;
 }
 
-absl::optional<StoragePartitionConfig>
-BrowsingDataRemoverImpl::GetLastUsedStoragePartitionConfigForTesting() {
-  return storage_partition_config_;
-}
-
-uint64_t BrowsingDataRemoverImpl::GetPendingTaskCountForTesting() {
-  return task_queue_.size();
-}
-
 BrowsingDataRemoverImpl::RemovalTask::RemovalTask(
     const base::Time& delete_begin,
     const base::Time& delete_end,
diff --git a/content/browser/browsing_data/browsing_data_remover_impl.h b/content/browser/browsing_data/browsing_data_remover_impl.h
index 5d80a41..b226e06 100644
--- a/content/browser/browsing_data/browsing_data_remover_impl.h
+++ b/content/browser/browsing_data/browsing_data_remover_impl.h
@@ -92,9 +92,6 @@
   const base::Time& GetLastUsedBeginTimeForTesting() override;
   uint64_t GetLastUsedRemovalMaskForTesting() override;
   uint64_t GetLastUsedOriginTypeMaskForTesting() override;
-  absl::optional<StoragePartitionConfig>
-  GetLastUsedStoragePartitionConfigForTesting() override;
-  uint64_t GetPendingTaskCountForTesting() override;
 
   void ClearClientHintCacheAndReply(const url::Origin& origin,
                                     base::OnceClosure callback);
@@ -254,11 +251,6 @@
   // From which types of origins should we remove data?
   uint64_t origin_type_mask_ = 0;
 
-  // The StoragePartition from which data should be removed, or the default
-  // if absent.
-  absl::optional<StoragePartitionConfig> storage_partition_config_ =
-      absl::nullopt;
-
   std::vector<std::string> domains_for_deferred_cookie_deletion_;
 
   // True if Remove has been invoked.
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index 2e12c01..4fc4183c 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -6995,64 +6995,6 @@
   EXPECT_FALSE(site_instance->GetProcess()->IsUnused());
 }
 
-class CacheTransparencyNavigationBrowserTest : public ContentBrowserTest {
- public:
-  CacheTransparencyNavigationBrowserTest() {
-    EXPECT_TRUE(embedded_test_server()->Start());
-
-    pervasive_payload_url_ = embedded_test_server()->GetURL(kPervasivePayload);
-    std::string pervasive_payloads_params = base::StrCat(
-        {"1,", pervasive_payload_url_.spec(),
-         ",2478392C652868C0AAF0316A28284610DBDACF02D66A00B39F3BA75D887F4829"});
-
-    feature_list_.InitWithFeaturesAndParameters(
-        {{network::features::kPervasivePayloadsList,
-          {{"pervasive-payloads", pervasive_payloads_params}}},
-         {network::features::kCacheTransparency, {}},
-         {net::features::kSplitCacheByNetworkIsolationKey, {}}},
-        {/* disabled_features */});
-    ForceInProcessNetworkService();
-  }
-
-  void ExpectCacheUsed() const {
-    histogram_tester_.ExpectUniqueSample(kCacheUsedHistogram, 0, 1);
-  }
-
-  void ExpectCacheNotUsed() const {
-    histogram_tester_.ExpectTotalCount(kCacheUsedHistogram, 0);
-  }
-
- private:
-  static constexpr char kPervasivePayload[] =
-      "/cache_transparency/pervasive.js";
-  static constexpr char kCacheUsedHistogram[] =
-      "Network.CacheTransparency2.SingleKeyedCacheIsUsed";
-
-  base::test::ScopedFeatureList feature_list_;
-  GURL pervasive_payload_url_;
-  base::HistogramTester histogram_tester_;
-};
-
-IN_PROC_BROWSER_TEST_F(CacheTransparencyNavigationBrowserTest,
-                       SuccessfulPervasivePayload) {
-  GURL url_main_document =
-      embedded_test_server()->GetURL("/cache_transparency/pervasive.html");
-
-  EXPECT_TRUE(NavigateToURL(shell(), url_main_document));
-
-  ExpectCacheUsed();
-}
-
-IN_PROC_BROWSER_TEST_F(CacheTransparencyNavigationBrowserTest,
-                       NotAPervasivePayload) {
-  GURL url_main_document =
-      embedded_test_server()->GetURL("/cache_transparency/cacheable.html");
-
-  EXPECT_TRUE(NavigateToURL(shell(), url_main_document));
-
-  ExpectCacheNotUsed();
-}
-
 class NavigationBrowserTestWarnSandboxIneffective
     : public NavigationBrowserTest {
  public:
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index d0b3352..78923d0 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -6338,7 +6338,9 @@
         [](const net::test_server::HttpRequest& request)
             -> std::unique_ptr<net::test_server::HttpResponse> {
           if (base::Contains(request.GetURL().path(),
-                             "/service_worker/direct")) {
+                             "/service_worker/direct") ||
+              base::Contains(request.GetURL().path(),
+                             "/service_worker/direct_if_not_running")) {
             auto http_response =
                 std::make_unique<net::test_server::BasicHttpResponse>();
             http_response->set_code(net::HTTP_OK);
@@ -6458,6 +6460,7 @@
   while (GetRequestCount(relative_url) != 2) {
     base::RunLoop().RunUntilIdle();
   }
+  // two fetches for clone.
   EXPECT_EQ(2, GetRequestCount(relative_url));
 }
 
@@ -6480,10 +6483,72 @@
   while (GetRequestCount(relative_url) != 2) {
     base::RunLoop().RunUntilIdle();
   }
+  // two fetches for clone.
   EXPECT_EQ(2, GetRequestCount(relative_url));
 }
 
-// two fetches for clone.
+IN_PROC_BROWSER_TEST_F(ServiceWorkerStaticRouterBrowserTest,
+                       MainResourceRunningStatus) {
+  SetupAndRegisterServiceWorker(TestType::kNetwork);
+  WorkerRunningStatusObserver observer(public_context());
+  const std::string relative_url = "/service_worker/direct_if_not_running";
+
+  // Initial state is stopped, and should go to network.
+  ASSERT_EQ(EmbeddedWorkerStatus::STOPPED, version()->running_status());
+  ASSERT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL(relative_url)));
+  EXPECT_EQ("[ServiceWorkerStaticRouter] Response from the network",
+            GetInnerText());
+  // The result should be got from the network.
+  EXPECT_EQ(1, GetRequestCount(relative_url));
+
+  // Since the ServiceWorker will start after using static routing,
+  // wait for that.
+  observer.WaitUntilRunning();
+  EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, version()->running_status());
+
+  // Ensure that the fetch handler is used this time.
+  ASSERT_TRUE(
+      NavigateToURL(shell(), embedded_test_server()->GetURL(relative_url)));
+  EXPECT_EQ("[ServiceWorkerStaticRouter] Response from the fetch handler",
+            GetInnerText());
+  // The result should not be got from the network, and access count
+  // should not change.
+  EXPECT_EQ(1, GetRequestCount(relative_url));
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerStaticRouterBrowserTest,
+                       SubresourceRunningStatus) {
+  const std::string relative_url = "/service_worker/direct_if_not_running";
+  SetupAndRegisterServiceWorker(TestType::kNetwork);
+  // Initial state is stopped, and should go to network.
+  ASSERT_EQ(EmbeddedWorkerStatus::STOPPED, version()->running_status());
+  ReloadBlockUntilNavigationsComplete(shell(), 1);
+  EXPECT_EQ("[ServiceWorkerStaticRouter] Response from the network",
+            EvalJs(GetPrimaryMainFrame(), "fetch('" + relative_url +
+                                              "').then(response => "
+                                              "response.text())"));
+  // The result should be got from the network.
+  EXPECT_EQ(1, GetRequestCount(relative_url));
+
+  // Start service worker, and the result should eventually got from
+  // the fetch handler.
+  EXPECT_EQ(StartServiceWorker(version().get()),
+            blink::ServiceWorkerStatusCode::kOk);
+  EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, version()->running_status());
+  // We know there is a delay to make the renderer know the running
+  // status. Or, test will timeout.
+  for (;;) {
+    auto result = EvalJs(GetPrimaryMainFrame(), "fetch('" + relative_url +
+                                                    "').then(response => "
+                                                    "response.text())");
+    if (result != "[ServiceWorkerStaticRouter] Response from the network") {
+      EXPECT_EQ("[ServiceWorkerStaticRouter] Response from the fetch handler",
+                result);
+      break;
+    }
+  }
+}
 
 class ServiceWorkerStaticRouterOriginTrialBrowserTest
     : public ServiceWorkerStaticRouterBrowserTest {
diff --git a/content/public/browser/browsing_data_remover.h b/content/public/browser/browsing_data_remover.h
index 067e45f..5110512 100644
--- a/content/public/browser/browsing_data_remover.h
+++ b/content/public/browser/browsing_data_remover.h
@@ -10,7 +10,6 @@
 #include "base/functional/callback_forward.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace storage {
 class SpecialStoragePolicy;
@@ -24,7 +23,6 @@
 
 class BrowsingDataFilterBuilder;
 class BrowsingDataRemoverDelegate;
-class StoragePartitionConfig;
 
 ////////////////////////////////////////////////////////////////////////////////
 // BrowsingDataRemover is responsible for removing data related to browsing:
@@ -287,9 +285,6 @@
   virtual const base::Time& GetLastUsedBeginTimeForTesting() = 0;
   virtual uint64_t GetLastUsedRemovalMaskForTesting() = 0;
   virtual uint64_t GetLastUsedOriginTypeMaskForTesting() = 0;
-  virtual absl::optional<StoragePartitionConfig>
-  GetLastUsedStoragePartitionConfigForTesting() = 0;
-  virtual uint64_t GetPendingTaskCountForTesting() = 0;
 };
 
 }  // namespace content
diff --git a/content/test/content_test_bundle_data.filelist b/content/test/content_test_bundle_data.filelist
index dc3e3178..d684e44 100644
--- a/content/test/content_test_bundle_data.filelist
+++ b/content/test/content_test_bundle_data.filelist
@@ -5296,11 +5296,9 @@
 data/cache_storage/storage_key/0430f1a484a0ea6d8de562488c5fbeec0111d16f/ba31f73b-95e8-44fb-a273-265e7e76f5ab/index
 data/cache_storage/storage_key/0430f1a484a0ea6d8de562488c5fbeec0111d16f/ba31f73b-95e8-44fb-a273-265e7e76f5ab/index-dir/the-real-index
 data/cache_storage/storage_key/0430f1a484a0ea6d8de562488c5fbeec0111d16f/index.txt
-data/cache_transparency/cacheable.html
 data/cache_transparency/cacheable.js
 data/cache_transparency/cacheable.js.mock-http-headers
 data/cache_transparency/cacheable2.html
-data/cache_transparency/pervasive.html
 data/cache_transparency/pervasive.js
 data/cache_transparency/pervasive.js.mock-http-headers
 data/cache_transparency/pervasive2.html
diff --git a/content/test/data/cache_transparency/cacheable.html b/content/test/data/cache_transparency/cacheable.html
deleted file mode 100644
index fe7d8988..0000000
--- a/content/test/data/cache_transparency/cacheable.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<html>
-  <head><title>Cacheable Test Page</title></head>
-  <body>
-    <script type="application/javascript" src="/cache_transparency/cacheable.js"></script>
-  </body>
-</html>
diff --git a/content/test/data/cache_transparency/pervasive.html b/content/test/data/cache_transparency/pervasive.html
deleted file mode 100644
index e86fd96e..0000000
--- a/content/test/data/cache_transparency/pervasive.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<html>
-  <head><title>Pervasive Payload Test page</title></head>
-  <body>
-    <script type="application/javascript" src="/cache_transparency/pervasive.js"></script>
-  </body>
-</html>
diff --git a/content/test/data/service_worker/static_router.js b/content/test/data/service_worker/static_router.js
index 6567f18..5e26845 100644
--- a/content/test/data/service_worker/static_router.js
+++ b/content/test/data/service_worker/static_router.js
@@ -17,13 +17,19 @@
 };
 
 self.addEventListener('install', e => {
-  e.registerRouter({
+  e.registerRouter([{
     condition: {
       urlPattern: "/service_worker/direct",
       requestMethod: "GET",
     },
     source: "network"
-  });
+  }, {
+    condition: {
+      urlPattern: "/service_worker/direct_if_not_running",
+      runningStatus: "not-running",
+    },
+    source: "network"
+  }]);
   self.skipWaiting();
 });
 
diff --git a/infra/config/generated/builders/try/android-10-arm64-rel/properties.json b/infra/config/generated/builders/try/android-10-arm64-rel/properties.json
index 53c75c5..1829b681 100644
--- a/infra/config/generated/builders/try/android-10-arm64-rel/properties.json
+++ b/infra/config/generated/builders/try/android-10-arm64-rel/properties.json
@@ -48,7 +48,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android-12-x64-rel-compilator/properties.json b/infra/config/generated/builders/try/android-12-x64-rel-compilator/properties.json
index b48d815..2e3474e 100644
--- a/infra/config/generated/builders/try/android-12-x64-rel-compilator/properties.json
+++ b/infra/config/generated/builders/try/android-12-x64-rel-compilator/properties.json
@@ -56,7 +56,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android-12l-x64-dbg/properties.json b/infra/config/generated/builders/try/android-12l-x64-dbg/properties.json
index e1f0fc78..496a99b 100644
--- a/infra/config/generated/builders/try/android-12l-x64-dbg/properties.json
+++ b/infra/config/generated/builders/try/android-12l-x64-dbg/properties.json
@@ -85,7 +85,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android-arm64-all-targets-dbg/properties.json b/infra/config/generated/builders/try/android-arm64-all-targets-dbg/properties.json
index 13e5bd0a..1bee996 100644
--- a/infra/config/generated/builders/try/android-arm64-all-targets-dbg/properties.json
+++ b/infra/config/generated/builders/try/android-arm64-all-targets-dbg/properties.json
@@ -46,7 +46,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android-arm64-rel-compilator/properties.json b/infra/config/generated/builders/try/android-arm64-rel-compilator/properties.json
index 5d9174f..8d05d553 100644
--- a/infra/config/generated/builders/try/android-arm64-rel-compilator/properties.json
+++ b/infra/config/generated/builders/try/android-arm64-rel-compilator/properties.json
@@ -96,7 +96,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android-chrome-pie-x86-wpt-fyi-rel/properties.json b/infra/config/generated/builders/try/android-chrome-pie-x86-wpt-fyi-rel/properties.json
index 2580ba4e..87724f9 100644
--- a/infra/config/generated/builders/try/android-chrome-pie-x86-wpt-fyi-rel/properties.json
+++ b/infra/config/generated/builders/try/android-chrome-pie-x86-wpt-fyi-rel/properties.json
@@ -46,7 +46,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android-code-coverage-native/properties.json b/infra/config/generated/builders/try/android-code-coverage-native/properties.json
index 1ab05b24..f5754a3 100644
--- a/infra/config/generated/builders/try/android-code-coverage-native/properties.json
+++ b/infra/config/generated/builders/try/android-code-coverage-native/properties.json
@@ -48,7 +48,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android-code-coverage/properties.json b/infra/config/generated/builders/try/android-code-coverage/properties.json
index ad2e49e..9f06548e3 100644
--- a/infra/config/generated/builders/try/android-code-coverage/properties.json
+++ b/infra/config/generated/builders/try/android-code-coverage/properties.json
@@ -47,7 +47,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android-fieldtrial-rel/properties.json b/infra/config/generated/builders/try/android-fieldtrial-rel/properties.json
index ae0e00a..bb452f8 100644
--- a/infra/config/generated/builders/try/android-fieldtrial-rel/properties.json
+++ b/infra/config/generated/builders/try/android-fieldtrial-rel/properties.json
@@ -46,7 +46,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android-inverse-fieldtrials-pie-x86-fyi-rel/properties.json b/infra/config/generated/builders/try/android-inverse-fieldtrials-pie-x86-fyi-rel/properties.json
index 01672fc..5570e13 100644
--- a/infra/config/generated/builders/try/android-inverse-fieldtrials-pie-x86-fyi-rel/properties.json
+++ b/infra/config/generated/builders/try/android-inverse-fieldtrials-pie-x86-fyi-rel/properties.json
@@ -46,7 +46,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android-nougat-x86-rel-compilator/properties.json b/infra/config/generated/builders/try/android-nougat-x86-rel-compilator/properties.json
index a260403d..b6545aad 100644
--- a/infra/config/generated/builders/try/android-nougat-x86-rel-compilator/properties.json
+++ b/infra/config/generated/builders/try/android-nougat-x86-rel-compilator/properties.json
@@ -57,7 +57,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android-official/properties.json b/infra/config/generated/builders/try/android-official/properties.json
index 5278fa87..a459c7f3 100644
--- a/infra/config/generated/builders/try/android-official/properties.json
+++ b/infra/config/generated/builders/try/android-official/properties.json
@@ -44,7 +44,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android-oreo-x86-rel/properties.json b/infra/config/generated/builders/try/android-oreo-x86-rel/properties.json
index 0a1f21d..dc1ba8b 100644
--- a/infra/config/generated/builders/try/android-oreo-x86-rel/properties.json
+++ b/infra/config/generated/builders/try/android-oreo-x86-rel/properties.json
@@ -44,7 +44,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android-perfetto-rel/properties.json b/infra/config/generated/builders/try/android-perfetto-rel/properties.json
index a5246a0..974914c 100644
--- a/infra/config/generated/builders/try/android-perfetto-rel/properties.json
+++ b/infra/config/generated/builders/try/android-perfetto-rel/properties.json
@@ -45,7 +45,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android-pie-arm64-dbg/properties.json b/infra/config/generated/builders/try/android-pie-arm64-dbg/properties.json
index cd46ac3..e51b37c 100644
--- a/infra/config/generated/builders/try/android-pie-arm64-dbg/properties.json
+++ b/infra/config/generated/builders/try/android-pie-arm64-dbg/properties.json
@@ -91,7 +91,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android-pie-x86-rel/properties.json b/infra/config/generated/builders/try/android-pie-x86-rel/properties.json
index 01672fc..5570e13 100644
--- a/infra/config/generated/builders/try/android-pie-x86-rel/properties.json
+++ b/infra/config/generated/builders/try/android-pie-x86-rel/properties.json
@@ -46,7 +46,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android-webview-10-x86-rel-tests/properties.json b/infra/config/generated/builders/try/android-webview-10-x86-rel-tests/properties.json
index b00185a4..7b893bf 100644
--- a/infra/config/generated/builders/try/android-webview-10-x86-rel-tests/properties.json
+++ b/infra/config/generated/builders/try/android-webview-10-x86-rel-tests/properties.json
@@ -82,7 +82,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android-x64-cast/properties.json b/infra/config/generated/builders/try/android-x64-cast/properties.json
index de82dde..383f788c 100644
--- a/infra/config/generated/builders/try/android-x64-cast/properties.json
+++ b/infra/config/generated/builders/try/android-x64-cast/properties.json
@@ -46,7 +46,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android_archive_rel_ng/properties.json b/infra/config/generated/builders/try/android_archive_rel_ng/properties.json
index ad3aa1c..a163cfe 100644
--- a/infra/config/generated/builders/try/android_archive_rel_ng/properties.json
+++ b/infra/config/generated/builders/try/android_archive_rel_ng/properties.json
@@ -46,7 +46,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android_arm64_dbg_recipe/properties.json b/infra/config/generated/builders/try/android_arm64_dbg_recipe/properties.json
index 971c4956..5f2f553 100644
--- a/infra/config/generated/builders/try/android_arm64_dbg_recipe/properties.json
+++ b/infra/config/generated/builders/try/android_arm64_dbg_recipe/properties.json
@@ -298,7 +298,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android_blink_rel/properties.json b/infra/config/generated/builders/try/android_blink_rel/properties.json
index 31f6017e..43eada9 100644
--- a/infra/config/generated/builders/try/android_blink_rel/properties.json
+++ b/infra/config/generated/builders/try/android_blink_rel/properties.json
@@ -45,7 +45,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android_compile_dbg/properties.json b/infra/config/generated/builders/try/android_compile_dbg/properties.json
index c02d488e..ebbb0cc 100644
--- a/infra/config/generated/builders/try/android_compile_dbg/properties.json
+++ b/infra/config/generated/builders/try/android_compile_dbg/properties.json
@@ -47,7 +47,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android_compile_x64_dbg/properties.json b/infra/config/generated/builders/try/android_compile_x64_dbg/properties.json
index 13c2dbe..0be46bcb 100644
--- a/infra/config/generated/builders/try/android_compile_x64_dbg/properties.json
+++ b/infra/config/generated/builders/try/android_compile_x64_dbg/properties.json
@@ -44,7 +44,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android_compile_x86_dbg/properties.json b/infra/config/generated/builders/try/android_compile_x86_dbg/properties.json
index 478a000..1d3ea7ee 100644
--- a/infra/config/generated/builders/try/android_compile_x86_dbg/properties.json
+++ b/infra/config/generated/builders/try/android_compile_x86_dbg/properties.json
@@ -44,7 +44,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android_cronet/properties.json b/infra/config/generated/builders/try/android_cronet/properties.json
index 91d6dd42..beaf14b 100644
--- a/infra/config/generated/builders/try/android_cronet/properties.json
+++ b/infra/config/generated/builders/try/android_cronet/properties.json
@@ -48,7 +48,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android_optional_gpu_tests_rel/properties.json b/infra/config/generated/builders/try/android_optional_gpu_tests_rel/properties.json
index 9821f573..52b550c 100644
--- a/infra/config/generated/builders/try/android_optional_gpu_tests_rel/properties.json
+++ b/infra/config/generated/builders/try/android_optional_gpu_tests_rel/properties.json
@@ -45,7 +45,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/android_unswarmed_pixel_aosp/properties.json b/infra/config/generated/builders/try/android_unswarmed_pixel_aosp/properties.json
index 45efd914b..05def69 100644
--- a/infra/config/generated/builders/try/android_unswarmed_pixel_aosp/properties.json
+++ b/infra/config/generated/builders/try/android_unswarmed_pixel_aosp/properties.json
@@ -91,7 +91,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/chromeos-amd64-generic-rel-compilator/properties.json b/infra/config/generated/builders/try/chromeos-amd64-generic-rel-compilator/properties.json
index 5ccb674..0e148e1 100644
--- a/infra/config/generated/builders/try/chromeos-amd64-generic-rel-compilator/properties.json
+++ b/infra/config/generated/builders/try/chromeos-amd64-generic-rel-compilator/properties.json
@@ -54,7 +54,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/fuchsia-arm64-cast-receiver-rel/properties.json b/infra/config/generated/builders/try/fuchsia-arm64-cast-receiver-rel/properties.json
index bd7e655..34d9fa9 100644
--- a/infra/config/generated/builders/try/fuchsia-arm64-cast-receiver-rel/properties.json
+++ b/infra/config/generated/builders/try/fuchsia-arm64-cast-receiver-rel/properties.json
@@ -45,7 +45,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/fuchsia-arm64-rel/properties.json b/infra/config/generated/builders/try/fuchsia-arm64-rel/properties.json
index 7f314d2..672c953c 100644
--- a/infra/config/generated/builders/try/fuchsia-arm64-rel/properties.json
+++ b/infra/config/generated/builders/try/fuchsia-arm64-rel/properties.json
@@ -45,7 +45,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/fuchsia-code-coverage/properties.json b/infra/config/generated/builders/try/fuchsia-code-coverage/properties.json
index 5b2c4684..4966af5 100644
--- a/infra/config/generated/builders/try/fuchsia-code-coverage/properties.json
+++ b/infra/config/generated/builders/try/fuchsia-code-coverage/properties.json
@@ -44,7 +44,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/fuchsia-compile-x64-dbg/properties.json b/infra/config/generated/builders/try/fuchsia-compile-x64-dbg/properties.json
index 12404d5..92b031f3 100644
--- a/infra/config/generated/builders/try/fuchsia-compile-x64-dbg/properties.json
+++ b/infra/config/generated/builders/try/fuchsia-compile-x64-dbg/properties.json
@@ -44,7 +44,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/fuchsia-fyi-arm64-dbg/properties.json b/infra/config/generated/builders/try/fuchsia-fyi-arm64-dbg/properties.json
index 7616884..443d782 100644
--- a/infra/config/generated/builders/try/fuchsia-fyi-arm64-dbg/properties.json
+++ b/infra/config/generated/builders/try/fuchsia-fyi-arm64-dbg/properties.json
@@ -46,7 +46,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/fuchsia-fyi-x64-dbg/properties.json b/infra/config/generated/builders/try/fuchsia-fyi-x64-dbg/properties.json
index 86803ee..5882ceab 100644
--- a/infra/config/generated/builders/try/fuchsia-fyi-x64-dbg/properties.json
+++ b/infra/config/generated/builders/try/fuchsia-fyi-x64-dbg/properties.json
@@ -44,7 +44,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/fuchsia-official/properties.json b/infra/config/generated/builders/try/fuchsia-official/properties.json
index 3655f245..2e245d9 100644
--- a/infra/config/generated/builders/try/fuchsia-official/properties.json
+++ b/infra/config/generated/builders/try/fuchsia-official/properties.json
@@ -42,7 +42,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/fuchsia-x64-cast-receiver-rel-compilator/properties.json b/infra/config/generated/builders/try/fuchsia-x64-cast-receiver-rel-compilator/properties.json
index 099017f..4369b26 100644
--- a/infra/config/generated/builders/try/fuchsia-x64-cast-receiver-rel-compilator/properties.json
+++ b/infra/config/generated/builders/try/fuchsia-x64-cast-receiver-rel-compilator/properties.json
@@ -50,7 +50,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/fuchsia-x64-rel/properties.json b/infra/config/generated/builders/try/fuchsia-x64-rel/properties.json
index c68ad8e95..b295d06c 100644
--- a/infra/config/generated/builders/try/fuchsia-x64-rel/properties.json
+++ b/infra/config/generated/builders/try/fuchsia-x64-rel/properties.json
@@ -43,7 +43,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/gpu-fyi-cq-android-arm64/properties.json b/infra/config/generated/builders/try/gpu-fyi-cq-android-arm64/properties.json
index 99ebf987..9a7be69 100644
--- a/infra/config/generated/builders/try/gpu-fyi-cq-android-arm64/properties.json
+++ b/infra/config/generated/builders/try/gpu-fyi-cq-android-arm64/properties.json
@@ -87,7 +87,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/ios-simulator-compilator/properties.json b/infra/config/generated/builders/try/ios-simulator-compilator/properties.json
index 88af662..4533cda 100644
--- a/infra/config/generated/builders/try/ios-simulator-compilator/properties.json
+++ b/infra/config/generated/builders/try/ios-simulator-compilator/properties.json
@@ -55,7 +55,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics",
     "scandeps_server": true
   },
diff --git a/infra/config/generated/builders/try/ios-simulator-cronet/properties.json b/infra/config/generated/builders/try/ios-simulator-cronet/properties.json
index a9defd2..b50706e2 100644
--- a/infra/config/generated/builders/try/ios-simulator-cronet/properties.json
+++ b/infra/config/generated/builders/try/ios-simulator-cronet/properties.json
@@ -44,7 +44,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics",
     "scandeps_server": true
   },
diff --git a/infra/config/generated/builders/try/linux-chromeos-compile-dbg/properties.json b/infra/config/generated/builders/try/linux-chromeos-compile-dbg/properties.json
index 2831044..2f21bfda 100644
--- a/infra/config/generated/builders/try/linux-chromeos-compile-dbg/properties.json
+++ b/infra/config/generated/builders/try/linux-chromeos-compile-dbg/properties.json
@@ -44,7 +44,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/linux-lacros-asan-lsan-rel/properties.json b/infra/config/generated/builders/try/linux-lacros-asan-lsan-rel/properties.json
index 8f988f4..c9eebef 100644
--- a/infra/config/generated/builders/try/linux-lacros-asan-lsan-rel/properties.json
+++ b/infra/config/generated/builders/try/linux-lacros-asan-lsan-rel/properties.json
@@ -43,7 +43,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/linux-lacros-rel-compilator/properties.json b/infra/config/generated/builders/try/linux-lacros-rel-compilator/properties.json
index d2fd16f0..28004f8 100644
--- a/infra/config/generated/builders/try/linux-lacros-rel-compilator/properties.json
+++ b/infra/config/generated/builders/try/linux-lacros-rel-compilator/properties.json
@@ -93,7 +93,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/linux-official/properties.json b/infra/config/generated/builders/try/linux-official/properties.json
index 7eef119..4b1f219 100644
--- a/infra/config/generated/builders/try/linux-official/properties.json
+++ b/infra/config/generated/builders/try/linux-official/properties.json
@@ -40,7 +40,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/linux-rel-compilator/properties.json b/infra/config/generated/builders/try/linux-rel-compilator/properties.json
index a0b70d05..7afe6fe 100644
--- a/infra/config/generated/builders/try/linux-rel-compilator/properties.json
+++ b/infra/config/generated/builders/try/linux-rel-compilator/properties.json
@@ -160,7 +160,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/linux-siso-rel-compilator/properties.json b/infra/config/generated/builders/try/linux-siso-rel-compilator/properties.json
index 76180fb..3531d6f2 100644
--- a/infra/config/generated/builders/try/linux-siso-rel-compilator/properties.json
+++ b/infra/config/generated/builders/try/linux-siso-rel-compilator/properties.json
@@ -160,7 +160,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$build/siso": {
diff --git a/infra/config/generated/builders/try/linux-wayland-rel-compilator/properties.json b/infra/config/generated/builders/try/linux-wayland-rel-compilator/properties.json
index 0efe497..73a14ca 100644
--- a/infra/config/generated/builders/try/linux-wayland-rel-compilator/properties.json
+++ b/infra/config/generated/builders/try/linux-wayland-rel-compilator/properties.json
@@ -90,7 +90,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/linux-x64-castos/properties.json b/infra/config/generated/builders/try/linux-x64-castos/properties.json
index 3ad1cdcb..a34f23c1 100644
--- a/infra/config/generated/builders/try/linux-x64-castos/properties.json
+++ b/infra/config/generated/builders/try/linux-x64-castos/properties.json
@@ -39,7 +39,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/linux_chromium_asan_rel_ng-compilator/properties.json b/infra/config/generated/builders/try/linux_chromium_asan_rel_ng-compilator/properties.json
index 1b2a884..5a43429 100644
--- a/infra/config/generated/builders/try/linux_chromium_asan_rel_ng-compilator/properties.json
+++ b/infra/config/generated/builders/try/linux_chromium_asan_rel_ng-compilator/properties.json
@@ -79,7 +79,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/linux_chromium_chromeos_asan_rel_ng/properties.json b/infra/config/generated/builders/try/linux_chromium_chromeos_asan_rel_ng/properties.json
index 798dd509..163ef14 100644
--- a/infra/config/generated/builders/try/linux_chromium_chromeos_asan_rel_ng/properties.json
+++ b/infra/config/generated/builders/try/linux_chromium_chromeos_asan_rel_ng/properties.json
@@ -82,7 +82,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/linux_chromium_chromeos_msan_rel_ng/properties.json b/infra/config/generated/builders/try/linux_chromium_chromeos_msan_rel_ng/properties.json
index d3dcc61..91c38c5 100644
--- a/infra/config/generated/builders/try/linux_chromium_chromeos_msan_rel_ng/properties.json
+++ b/infra/config/generated/builders/try/linux_chromium_chromeos_msan_rel_ng/properties.json
@@ -80,7 +80,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/linux_chromium_compile_dbg_ng/properties.json b/infra/config/generated/builders/try/linux_chromium_compile_dbg_ng/properties.json
index 370b29ef..0c83107 100644
--- a/infra/config/generated/builders/try/linux_chromium_compile_dbg_ng/properties.json
+++ b/infra/config/generated/builders/try/linux_chromium_compile_dbg_ng/properties.json
@@ -75,7 +75,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/linux_chromium_msan_rel_ng/properties.json b/infra/config/generated/builders/try/linux_chromium_msan_rel_ng/properties.json
index fd3bb5e..fb52e96 100644
--- a/infra/config/generated/builders/try/linux_chromium_msan_rel_ng/properties.json
+++ b/infra/config/generated/builders/try/linux_chromium_msan_rel_ng/properties.json
@@ -74,7 +74,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng-compilator/properties.json b/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng-compilator/properties.json
index 4fcc212..d969504a 100644
--- a/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng-compilator/properties.json
+++ b/infra/config/generated/builders/try/linux_chromium_tsan_rel_ng-compilator/properties.json
@@ -77,7 +77,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/mac-builder-next/properties.json b/infra/config/generated/builders/try/mac-builder-next/properties.json
index 94c6d1c..d912fd1 100644
--- a/infra/config/generated/builders/try/mac-builder-next/properties.json
+++ b/infra/config/generated/builders/try/mac-builder-next/properties.json
@@ -40,7 +40,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics",
     "scandeps_server": true
   },
diff --git a/infra/config/generated/builders/try/mac-official/properties.json b/infra/config/generated/builders/try/mac-official/properties.json
index a150e65..c482247 100644
--- a/infra/config/generated/builders/try/mac-official/properties.json
+++ b/infra/config/generated/builders/try/mac-official/properties.json
@@ -40,7 +40,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics",
     "scandeps_server": true
   },
diff --git a/infra/config/generated/builders/try/mac-rel-compilator/properties.json b/infra/config/generated/builders/try/mac-rel-compilator/properties.json
index 07a3448..87b65db8 100644
--- a/infra/config/generated/builders/try/mac-rel-compilator/properties.json
+++ b/infra/config/generated/builders/try/mac-rel-compilator/properties.json
@@ -191,7 +191,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics",
     "scandeps_server": true
   },
diff --git a/infra/config/generated/builders/try/mac13-arm64-rel-compilator/properties.json b/infra/config/generated/builders/try/mac13-arm64-rel-compilator/properties.json
index 3f1f55b..b44e232 100644
--- a/infra/config/generated/builders/try/mac13-arm64-rel-compilator/properties.json
+++ b/infra/config/generated/builders/try/mac13-arm64-rel-compilator/properties.json
@@ -79,7 +79,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics",
     "scandeps_server": true
   },
diff --git a/infra/config/generated/builders/try/mac_chromium_asan_rel_ng/properties.json b/infra/config/generated/builders/try/mac_chromium_asan_rel_ng/properties.json
index e713e03..3bcd4cb 100644
--- a/infra/config/generated/builders/try/mac_chromium_asan_rel_ng/properties.json
+++ b/infra/config/generated/builders/try/mac_chromium_asan_rel_ng/properties.json
@@ -74,7 +74,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics",
     "scandeps_server": true
   },
diff --git a/infra/config/generated/builders/try/try-nougat-phone-tester/properties.json b/infra/config/generated/builders/try/try-nougat-phone-tester/properties.json
index c789678..cad7e0b 100644
--- a/infra/config/generated/builders/try/try-nougat-phone-tester/properties.json
+++ b/infra/config/generated/builders/try/try-nougat-phone-tester/properties.json
@@ -88,7 +88,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/win-asan/properties.json b/infra/config/generated/builders/try/win-asan/properties.json
index 6656bf8..5f9779a7 100644
--- a/infra/config/generated/builders/try/win-asan/properties.json
+++ b/infra/config/generated/builders/try/win-asan/properties.json
@@ -39,7 +39,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/win-official/properties.json b/infra/config/generated/builders/try/win-official/properties.json
index 61b9d4ba..5b9f2b5 100644
--- a/infra/config/generated/builders/try/win-official/properties.json
+++ b/infra/config/generated/builders/try/win-official/properties.json
@@ -40,7 +40,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/win-rel-compilator/properties.json b/infra/config/generated/builders/try/win-rel-compilator/properties.json
index 7ad937c..d6b194a 100644
--- a/infra/config/generated/builders/try/win-rel-compilator/properties.json
+++ b/infra/config/generated/builders/try/win-rel-compilator/properties.json
@@ -164,7 +164,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/win32-official/properties.json b/infra/config/generated/builders/try/win32-official/properties.json
index 64aac53..317ba72 100644
--- a/infra/config/generated/builders/try/win32-official/properties.json
+++ b/infra/config/generated/builders/try/win32-official/properties.json
@@ -40,7 +40,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/builders/try/win_chromium_compile_dbg_ng/properties.json b/infra/config/generated/builders/try/win_chromium_compile_dbg_ng/properties.json
index 10b305e..baa5cc2 100644
--- a/infra/config/generated/builders/try/win_chromium_compile_dbg_ng/properties.json
+++ b/infra/config/generated/builders/try/win_chromium_compile_dbg_ng/properties.json
@@ -40,7 +40,7 @@
   },
   "$build/reclient": {
     "instance": "rbe-chromium-untrusted",
-    "jobs": 400,
+    "jobs": 450,
     "metrics_project": "chromium-reclient-metrics"
   },
   "$recipe_engine/resultdb/test_presentation": {
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 7473dc8..e0819aa 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -30753,7 +30753,7 @@
         '  },'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$build/siso": {'
@@ -30887,7 +30887,7 @@
         '  },'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$build/siso": {'
@@ -31011,7 +31011,7 @@
         '  },'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$build/siso": {'
@@ -31138,7 +31138,7 @@
         '  },'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$build/siso": {'
@@ -31262,7 +31262,7 @@
         '  },'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$build/siso": {'
@@ -31389,7 +31389,7 @@
         '  },'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$build/siso": {'
@@ -39314,7 +39314,7 @@
         '  },'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$build/siso": {'
@@ -59203,7 +59203,7 @@
         '  },'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$recipe_engine/resultdb/test_presentation": {'
@@ -59665,7 +59665,7 @@
         '  },'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$recipe_engine/resultdb/test_presentation": {'
@@ -61268,7 +61268,7 @@
         '{'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$recipe_engine/resultdb/test_presentation": {'
@@ -61350,7 +61350,7 @@
         '{'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$recipe_engine/resultdb/test_presentation": {'
@@ -66865,7 +66865,7 @@
         '  },'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$recipe_engine/resultdb/test_presentation": {'
@@ -67148,7 +67148,7 @@
         '  },'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$recipe_engine/resultdb/test_presentation": {'
@@ -67494,7 +67494,7 @@
         '{'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$recipe_engine/resultdb/test_presentation": {'
@@ -75024,7 +75024,7 @@
         '  },'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$recipe_engine/resultdb/test_presentation": {'
@@ -75910,7 +75910,7 @@
         '{'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$recipe_engine/resultdb/test_presentation": {'
@@ -76631,7 +76631,7 @@
         '{'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$recipe_engine/resultdb/test_presentation": {'
@@ -78063,7 +78063,7 @@
         '{'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$recipe_engine/resultdb/test_presentation": {'
@@ -82524,7 +82524,7 @@
         '{'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$recipe_engine/resultdb/test_presentation": {'
@@ -83716,7 +83716,7 @@
         '  },'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics",'
         '    "scandeps_server": true'
         '  },'
@@ -83976,7 +83976,7 @@
         '{'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics",'
         '    "scandeps_server": true'
         '  },'
@@ -89097,7 +89097,7 @@
         '  },'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$recipe_engine/resultdb/test_presentation": {'
@@ -89222,7 +89222,7 @@
         '  },'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$recipe_engine/resultdb/test_presentation": {'
@@ -89837,7 +89837,7 @@
         '{'
         '  "$build/reclient": {'
         '    "instance": "rbe-chromium-untrusted",'
-        '    "jobs": 400,'
+        '    "jobs": 450,'
         '    "metrics_project": "chromium-reclient-metrics"'
         '  },'
         '  "$recipe_engine/resultdb/test_presentation": {'
diff --git a/infra/config/lib/builders.star b/infra/config/lib/builders.star
index 0291f89..ef9d9cc 100644
--- a/infra/config/lib/builders.star
+++ b/infra/config/lib/builders.star
@@ -120,7 +120,7 @@
         HIGH_JOBS_FOR_CI = 500,
         LOW_JOBS_FOR_CQ = 150,
         # TODO(b/285080767): increase this to 500 gradually.
-        HIGH_JOBS_FOR_CQ = 400,
+        HIGH_JOBS_FOR_CQ = 450,
     ),
 )
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/OWNERS b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/OWNERS
index b98e1d4..5aae130 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/OWNERS
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/OWNERS
@@ -1,2 +1,3 @@
 edchin@chromium.org
 marq@chromium.org
+lpromero@google.com
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.mm
index 040bd0c..9f28ffd 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_grid/grid/grid_view_controller.mm
@@ -407,13 +407,10 @@
 
     // After transition from other modes to the normal mode, the selection
     // border doesn't show around the selected item, because reloading
-    // operations like `reloadSections` loose the selected items. The
-    // collection view needs to be updated with the selected item again for it
-    // to appear correctly.
-    [self deselectAllCollectionViewItemsAnimated:NO];
-    [self selectCollectionViewItemWithID:self.selectedItemID
-                                animated:NO
-                          scrollPosition:UICollectionViewScrollPositionNone];
+    // operations like `reloadSections` lose the selected items. The collection
+    // view needs to be updated with the selected item again for it to appear
+    // correctly.
+    [self updateSelectedCollectionViewItemRingAndBringIntoView:NO];
 
     self.searchText = nil;
   }
@@ -495,8 +492,7 @@
     return;
   }
 
-  [self deselectAllCollectionViewItemsAnimated:NO];
-  [self selectCollectionViewItemWithID:self.selectedItemID animated:NO];
+  [self updateSelectedCollectionViewItemRingAndBringIntoView:YES];
 
   // Update the delegate, in case it wasn't set when `items` was populated.
   [self.delegate gridViewController:self didChangeItemCount:self.items.count];
@@ -1245,8 +1241,7 @@
 
   [self reloadTabs];
 
-  [self deselectAllCollectionViewItemsAnimated:NO];
-  [self selectCollectionViewItemWithID:self.selectedItemID animated:NO];
+  [self updateSelectedCollectionViewItemRingAndBringIntoView:YES];
 
   if ([self shouldShowEmptyState]) {
     [self animateEmptyStateIn];
@@ -1274,50 +1269,16 @@
     return;
   }
 
-  // Consistency check: `item`'s ID is not in `items`.
-  // (using DCHECK rather than DCHECK_EQ to avoid a checked_cast on NSNotFound).
-  DCHECK([self indexOfItemWithID:item.identifier] == NSNotFound);
-  auto modelUpdates = ^{
-    [self.items insertObject:item atIndex:index];
-    self.selectedItemID = selectedItemID;
-    self.lastInsertedItemID = item.identifier;
-    [self.delegate gridViewController:self didChangeItemCount:self.items.count];
-  };
-  auto collectionViewUpdates = ^{
-    [self removeEmptyStateAnimated:YES];
-    [self.collectionView insertItemsAtIndexPaths:@[ CreateIndexPath(index) ]];
-  };
   __weak __typeof(self) weakSelf = self;
-  auto completion = ^{
-    __typeof(self) strongSelf = weakSelf;
-    if (!strongSelf) {
-      return;
-    }
-    [strongSelf deselectAllCollectionViewItemsAnimated:NO];
-    [strongSelf selectCollectionViewItemWithID:strongSelf.selectedItemID
-                                      animated:YES];
-
-    [strongSelf.delegate gridViewController:strongSelf
-                         didChangeItemCount:strongSelf.items.count];
-
-    // Check `index` boundaries in order to filter out possible race conditions
-    // while mutating the collection.
-    if (index == NSNotFound || index >= strongSelf.items.count) {
-      return;
-    }
-
-    [strongSelf.collectionView
-        scrollToItemAtIndexPath:CreateIndexPath(index)
-               atScrollPosition:UICollectionViewScrollPositionCenteredVertically
-                       animated:YES];
-  };
-
-  [self performModelUpdates:modelUpdates
-      collectionViewUpdates:collectionViewUpdates
-                 completion:completion];
-
-  [self updateVisibleCellZIndex];
-  [self updateVisibleCellIdentifiers];
+  [self
+      performModelAndViewUpdates:^{
+        [weakSelf applyModelAndViewUpdatesForInsertionOfItem:item
+                                                     atIndex:index
+                                              selectedItemID:selectedItemID];
+      }
+      completion:^{
+        [weakSelf modelAndViewUpdatesForInsertionDidCompleteAtIndex:index];
+      }];
 }
 
 - (void)removeItemWithID:(NSString*)removedItemID
@@ -1330,58 +1291,29 @@
     return;
   }
 
-  auto modelUpdates = ^{
-    [self.items removeObjectAtIndex:index];
-    self.selectedItemID = selectedItemID;
-    [self deselectItemWithIDForEditing:removedItemID];
-    [self.delegate gridViewController:self didChangeItemCount:self.items.count];
-  };
-  auto collectionViewUpdates = ^{
-    [self.collectionView deleteItemsAtIndexPaths:@[ CreateIndexPath(index) ]];
-    if ([self shouldShowEmptyState]) {
-      [self animateEmptyStateIn];
-    }
-  };
   __weak __typeof(self) weakSelf = self;
-  auto completion = ^{
-    __typeof(self) strongSelf = weakSelf;
-    if (!strongSelf) {
-      return;
-    }
-    if (strongSelf.items.count > 0) {
-      [strongSelf deselectAllCollectionViewItemsAnimated:NO];
-      [strongSelf
-          selectCollectionViewItemWithID:strongSelf.selectedItemID
-                                animated:NO
-                          scrollPosition:UICollectionViewScrollPositionNone];
-    }
-    [strongSelf.delegate gridViewController:strongSelf
-                         didChangeItemCount:strongSelf.items.count];
-    [strongSelf.delegate gridViewController:strongSelf
-                        didRemoveItemWIthID:removedItemID];
-  };
+  [self
+      performModelAndViewUpdates:^{
+        [weakSelf
+            applyModelAndViewUpdatesForRemovalOfItemWithID:removedItemID
+                                            selectedItemID:selectedItemID];
+      }
+      completion:^{
+        [weakSelf modelAndViewUpdatesForRemovalDidCompleteForItemWithID:
+                      removedItemID];
+      }];
 
-  [self performModelUpdates:modelUpdates
-      collectionViewUpdates:collectionViewUpdates
-                 completion:completion];
-
-  [self updateVisibleCellZIndex];
-  [self updateVisibleCellIdentifiers];
-
-  if (_searchText.length)
+  if (_searchText.length) {
     [self updateSearchResultsHeader];
+  }
 }
 
 - (void)selectItemWithID:(NSString*)selectedItemID {
   if ([self.selectedItemID isEqualToString:selectedItemID])
     return;
 
-  [self deselectAllCollectionViewItemsAnimated:NO];
-
   self.selectedItemID = selectedItemID;
-  [self selectCollectionViewItemWithID:self.selectedItemID
-                              animated:NO
-                        scrollPosition:UICollectionViewScrollPositionNone];
+  [self updateSelectedCollectionViewItemRingAndBringIntoView:NO];
 }
 
 - (void)replaceItemID:(NSString*)itemID withItem:(TabSwitcherItem*)item {
@@ -1411,27 +1343,17 @@
       fromIndex == NSNotFound) {
     return;
   }
-  auto modelUpdates = ^{
-    TabSwitcherItem* item = self.items[fromIndex];
-    [self.items removeObjectAtIndex:fromIndex];
-    [self.items insertObject:item atIndex:toIndex];
-  };
-  auto collectionViewUpdates = ^{
-    [self.collectionView moveItemAtIndexPath:CreateIndexPath(fromIndex)
-                                 toIndexPath:CreateIndexPath(toIndex)];
-  };
-  __weak __typeof(self) weakSelf = self;
-  auto completion = ^{
-    [weakSelf.delegate gridViewController:weakSelf
-                        didMoveItemWithID:itemID
-                                  toIndex:toIndex];
-  };
-  [self performModelUpdates:modelUpdates
-      collectionViewUpdates:collectionViewUpdates
-                 completion:completion];
 
-  [self updateVisibleCellZIndex];
-  [self updateVisibleCellIdentifiers];
+  __weak __typeof(self) weakSelf = self;
+  [self
+      performModelAndViewUpdates:^{
+        [weakSelf applyModelAndViewUpdatesForMoveOfItemFromIndex:fromIndex
+                                                         toIndex:toIndex];
+      }
+      completion:^{
+        [weakSelf modelAndViewUpdatesForMoveDidCompleteForItemWithID:itemID
+                                                             toIndex:toIndex];
+      }];
 }
 
 - (void)dismissModals {
@@ -1495,6 +1417,7 @@
 
 - (void)selectAllItemsForEditing {
   if (_mode != TabGridModeSelection) {
+    base::debug::DumpWithoutCrashing();
     return;
   }
 
@@ -1506,6 +1429,7 @@
 
 - (void)deselectAllItemsForEditing {
   if (_mode != TabGridModeSelection) {
+    base::debug::DumpWithoutCrashing();
     return;
   }
 
@@ -1575,6 +1499,110 @@
   }];
 }
 
+#pragma mark - Private helpers for joint model and view updates
+
+// Performs model and view updates together.
+- (void)performModelAndViewUpdates:(ProceduralBlock)modelAndViewUpdates
+                        completion:(ProceduralBlock)completion {
+  __weak __typeof(self) weakSelf = self;
+  [self.collectionView
+      performBatchUpdates:^{
+        weakSelf.updating = YES;
+        modelAndViewUpdates();
+      }
+      completion:^(BOOL completed) {
+        if (weakSelf) {
+          completion();
+          weakSelf.updating = NO;
+        }
+      }];
+
+  [self updateVisibleCellZIndex];
+  [self updateVisibleCellIdentifiers];
+}
+
+// Makes the required changes to `items` and `collectionView` when a new item is
+// inserted.
+- (void)applyModelAndViewUpdatesForInsertionOfItem:(TabSwitcherItem*)item
+                                           atIndex:(NSUInteger)index
+                                    selectedItemID:(NSString*)selectedItemID {
+  // Consistency check: `item`'s ID is not in `items`.
+  // (using DCHECK rather than DCHECK_EQ to avoid a checked_cast on NSNotFound).
+  DCHECK([self indexOfItemWithID:item.identifier] == NSNotFound);
+  [self.items insertObject:item atIndex:index];
+  self.selectedItemID = selectedItemID;
+  self.lastInsertedItemID = item.identifier;
+  [self.delegate gridViewController:self didChangeItemCount:self.items.count];
+
+  [self removeEmptyStateAnimated:YES];
+  [self.collectionView insertItemsAtIndexPaths:@[ CreateIndexPath(index) ]];
+}
+
+// Makes the required changes when a new item has been inserted.
+- (void)modelAndViewUpdatesForInsertionDidCompleteAtIndex:(NSUInteger)index {
+  [self updateSelectedCollectionViewItemRingAndBringIntoView:YES];
+
+  [self.delegate gridViewController:self didChangeItemCount:self.items.count];
+
+  // Check `index` boundaries in order to filter out possible race conditions
+  // while mutating the collection.
+  if (index == NSNotFound || index >= self.items.count) {
+    return;
+  }
+
+  [self.collectionView
+      scrollToItemAtIndexPath:CreateIndexPath(index)
+             atScrollPosition:UICollectionViewScrollPositionCenteredVertically
+                     animated:YES];
+}
+
+// Makes the required changes to `items` and `collectionView` when an existing
+// item is removed.
+- (void)applyModelAndViewUpdatesForRemovalOfItemWithID:(NSString*)removedItemID
+                                        selectedItemID:
+                                            (NSString*)selectedItemID {
+  NSUInteger index = [self indexOfItemWithID:removedItemID];
+  [self.items removeObjectAtIndex:index];
+  self.selectedItemID = selectedItemID;
+  [self deselectItemWithIDForEditing:removedItemID];
+  [self.delegate gridViewController:self didChangeItemCount:self.items.count];
+
+  [self.collectionView deleteItemsAtIndexPaths:@[ CreateIndexPath(index) ]];
+  if ([self shouldShowEmptyState]) {
+    [self animateEmptyStateIn];
+  }
+}
+
+// Makes the required changes when a new item has been removed.
+- (void)modelAndViewUpdatesForRemovalDidCompleteForItemWithID:
+    (NSString*)removedItemID {
+  if (self.items.count > 0) {
+    [self updateSelectedCollectionViewItemRingAndBringIntoView:NO];
+  }
+  [self.delegate gridViewController:self didChangeItemCount:self.items.count];
+  [self.delegate gridViewController:self didRemoveItemWIthID:removedItemID];
+}
+
+// Makes the required changes to `items` and `collectionView` when an existing
+// item is moved.
+- (void)applyModelAndViewUpdatesForMoveOfItemFromIndex:(NSUInteger)fromIndex
+                                               toIndex:(NSUInteger)toIndex {
+  TabSwitcherItem* item = self.items[fromIndex];
+  [self.items removeObjectAtIndex:fromIndex];
+  [self.items insertObject:item atIndex:toIndex];
+
+  [self.collectionView moveItemAtIndexPath:CreateIndexPath(fromIndex)
+                               toIndexPath:CreateIndexPath(toIndex)];
+}
+
+// Makes the required changes when a new item has been moved.
+- (void)modelAndViewUpdatesForMoveDidCompleteForItemWithID:(NSString*)itemID
+                                                   toIndex:(NSUInteger)toIndex {
+  [self.delegate gridViewController:self
+                  didMoveItemWithID:itemID
+                            toIndex:toIndex];
+}
+
 #pragma mark - Private properties
 
 - (NSUInteger)selectedIndex {
@@ -1596,43 +1624,32 @@
 
 #pragma mark - Private
 
-// Selects the collection view's item with `itemID`.
-- (void)selectCollectionViewItemWithID:(NSString*)itemID
-                              animated:(BOOL)animated
-                        scrollPosition:
-                            (UICollectionViewScrollPosition)scrollPosition {
-  NSUInteger itemIndex = [self indexOfItemWithID:itemID];
-
-  // Check `itemIndex` boundaries in order to filter out possible race
-  // conditions while mutating the collection.
-  if (itemIndex == NSNotFound || itemIndex >= self.items.count) {
-    return;
-  }
-
-  NSIndexPath* itemIndexPath = CreateIndexPath(itemIndex);
-
-  [self.collectionView selectItemAtIndexPath:itemIndexPath
-                                    animated:animated
-                              scrollPosition:scrollPosition];
-}
-
-// Selects the collection view's item with `itemID` and scrolls to have it at
-// the top.
-- (void)selectCollectionViewItemWithID:(NSString*)itemID
-                              animated:(BOOL)animated {
-  [self selectCollectionViewItemWithID:itemID
-                              animated:animated
-                        scrollPosition:UICollectionViewScrollPositionTop];
-}
-
-// Deselects all the collection view items.
-- (void)deselectAllCollectionViewItemsAnimated:(BOOL)animated {
+// Updates the ring to be around the currently selected item. If
+// `shouldBringItemIntoView` is true, the collection view scrolls to present the
+// selected item at the top.
+- (void)updateSelectedCollectionViewItemRingAndBringIntoView:
+    (BOOL)shouldBringItemIntoView {
+  // Deselects all the collection view items.
   NSArray<NSIndexPath*>* indexPathsForSelectedItems =
       [self.collectionView indexPathsForSelectedItems];
   for (NSIndexPath* itemIndexPath in indexPathsForSelectedItems) {
-    [self.collectionView deselectItemAtIndexPath:itemIndexPath
-                                        animated:animated];
+    [self.collectionView deselectItemAtIndexPath:itemIndexPath animated:NO];
   }
+
+  // Select the collection view item for the selected index.
+  NSUInteger selectedIndex = self.selectedIndex;
+  // Check `selectedIndex` boundaries in order to filter out possible race
+  // conditions while mutating the collection.
+  if (selectedIndex == NSNotFound || selectedIndex >= self.items.count) {
+    return;
+  }
+  NSIndexPath* selectedIndexPath = CreateIndexPath(selectedIndex);
+  UICollectionViewScrollPosition scrollPosition =
+      shouldBringItemIntoView ? UICollectionViewScrollPositionTop
+                              : UICollectionViewScrollPositionNone;
+  [self.collectionView selectItemAtIndexPath:selectedIndexPath
+                                    animated:NO
+                              scrollPosition:scrollPosition];
 }
 
 - (void)voiceOverStatusDidChange {
@@ -1649,23 +1666,6 @@
   return !UIAccessibilityIsVoiceOverRunning();
 }
 
-// Performs model updates and view updates together.
-- (void)performModelUpdates:(ProceduralBlock)modelUpdates
-      collectionViewUpdates:(ProceduralBlock)collectionViewUpdates
-                 completion:(ProceduralBlock)completion {
-  [self.collectionView
-      performBatchUpdates:^{
-        self.updating = YES;
-        // Synchronize model and view updates.
-        modelUpdates();
-        collectionViewUpdates();
-      }
-      completion:^(BOOL completed) {
-        completion();
-        self.updating = NO;
-      }];
-}
-
 // Returns the index in `self.items` of the first item whose identifier is
 // `identifier`.
 - (NSUInteger)indexOfItemWithID:(NSString*)identifier {
@@ -1997,9 +1997,7 @@
   }];
   // Make sure to restore the selection. `reloadSections` cleared it.
   // https://developer.apple.com/forums/thread/656529
-  [self selectCollectionViewItemWithID:self.selectedItemID
-                              animated:NO
-                        scrollPosition:UICollectionViewScrollPositionNone];
+  [self updateSelectedCollectionViewItemRingAndBringIntoView:NO];
 }
 
 // Reconfigures the Inactive Tabs button header.
diff --git a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
index a0e4fa0..b6716b67 100644
--- a/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-6786afae996bd45bf8ebd4c63b3122a5de05d6db
\ No newline at end of file
+b12fcfb9b0bca9bc88ed1c9345f8b2685f7f08d5
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1 b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
index 9d3683e5..a7c655a5 100644
--- a/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
+++ b/ios/google_internal/frameworks/ChromeSSOInternal.framework.dSYM.ios.zip.sha1
@@ -1 +1 @@
-4ede9166453fbb37e56e4c026e1de8301b45d0d9
\ No newline at end of file
+48bac0db30e2817a8df2f5ff659db0cfeeb2d7ed
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
index 1ce639a7..3879c02 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-fabc01b538da24688068a0199e1191c11a25bfa5
\ No newline at end of file
+d60f2223c5ee43e1622d4c5a670ff2949ebe61ee
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
index 3cdb72f4..f25ad47 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-5ee9f61b8702091e77407bd32a4cc35e20c3b2ab
\ No newline at end of file
+f813a8e2bdfa9def1d143925647b6152eae46b15
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
index 27b81f8d..96f7cb90 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-8adfe17a9bbc4174a0315e04dc98ac4b8da9ec7e
\ No newline at end of file
+e1a6f703d5aa1317eeff62c84c3d2413662f8a19
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
index 5bc076d..1edd0f5 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-9823b047aeac2662486fcaa6c63f63ae81893d45
\ No newline at end of file
+956603577398ddd9ea1c6cd1467ea92651d54847
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
index be2d668..20dbf80 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-6dceb400f8ec287ddd8ad83f2201327f80a08c40
\ No newline at end of file
+81369aca9595a8a9e594e126f939fde6d4b5c80e
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
index a73eaf9..a4547fcb 100644
--- a/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_test_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-bd99e6ee505adafccd0d283b9739145790a59e39
\ No newline at end of file
+7f983cb1cda52efa2460b79e1247429c0fafa502
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
index 88b7a60..5b30ac7 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-4fc151e80aee30b2ff916db0f706828d7aa2fdb0
\ No newline at end of file
+6c9f8a6b776a755110cdc33c3e32c60821b75065
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
index 83f39bd..b142a38 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-4b510f5f3a98117f418457ec9a46eec2150306c3
\ No newline at end of file
+172f8c1cda7a75580ef7f62925cfe9bc11d1e496
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
index 27ed4db3..b535b71 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.ios.zip.sha1
@@ -1 +1 @@
-f72eb852dec490369e39308772bd9935afcc8f73
\ No newline at end of file
+a3d7b63b20accf461730bca89b382eb28e94ba2b
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
index d7f54f9..c63b6bd 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.iossimulator.zip.sha1
@@ -1 +1 @@
-fd45aab74432997669afe1db872d9d8c1d716a0e
\ No newline at end of file
+e35d1ea88384149fdd335a145dec09282fbe5b9a
\ No newline at end of file
diff --git a/media/cast/BUILD.gn b/media/cast/BUILD.gn
index 6849c3d..97e60c87 100644
--- a/media/cast/BUILD.gn
+++ b/media/cast/BUILD.gn
@@ -164,6 +164,7 @@
 
   deps = [
     ":common",
+    "//media/mojo/clients:clients",
     "//third_party/opus",
   ]
 
@@ -226,6 +227,7 @@
     "//components/openscreen_platform",
     "//media",
     "//media/capture:capture_base",
+    "//media/mojo/clients:clients",
     "//third_party/openscreen/src/cast/streaming:sender",
     "//ui/gfx/geometry",
   ]
@@ -396,6 +398,7 @@
     "//components/openscreen_platform",
     "//media:test_support",
     "//media/cast/openscreen:unit_tests",
+    "//media/mojo:test_support",
     "//media/test:run_all_unittests",
     "//mojo/public/cpp/bindings",
     "//net",
@@ -448,6 +451,7 @@
       "//base",
       "//base/test:test_support",
       "//media:test_support",
+      "//media/mojo:test_support",
       "//net",
       "//testing/gtest",
       "//ui/gfx/geometry",
@@ -465,6 +469,8 @@
       "//base",
       "//build/win:default_exe_manifest",
       "//media",
+      "//media/mojo:test_support",
+      "//testing/gmock",
     ]
   }
 
@@ -487,6 +493,7 @@
       "//base/test:test_support",
       "//build/win:default_exe_manifest",
       "//media:test_support",
+      "//media/mojo:test_support",
     ]
   }
 
diff --git a/media/cast/cast_sender.h b/media/cast/cast_sender.h
index 8fe46874..17aa2f4e 100644
--- a/media/cast/cast_sender.h
+++ b/media/cast/cast_sender.h
@@ -30,6 +30,8 @@
 
 namespace media {
 
+class MojoVideoEncoderMetricsProvider;
+
 namespace cast {
 
 class VideoFrameInput : public base::RefCountedThreadSafe<VideoFrameInput> {
@@ -102,6 +104,7 @@
   // |status_change_cb| will be run as operational status changes.
   virtual void InitializeVideo(
       const FrameSenderConfig& video_config,
+      std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider,
       const StatusChangeCallback& status_change_cb,
       const CreateVideoEncodeAcceleratorCallback& create_vea_cb) = 0;
 
diff --git a/media/cast/cast_sender_impl.cc b/media/cast/cast_sender_impl.cc
index 3d2d5297..35449b5 100644
--- a/media/cast/cast_sender_impl.cc
+++ b/media/cast/cast_sender_impl.cc
@@ -12,6 +12,7 @@
 #include "base/logging.h"
 #include "media/base/video_frame.h"
 #include "media/cast/common/video_frame_factory.h"
+#include "media/mojo/clients/mojo_video_encoder_metrics_provider.h"
 
 namespace media {
 namespace cast {
@@ -126,6 +127,7 @@
 
 void CastSenderImpl::InitializeVideo(
     const FrameSenderConfig& video_config,
+    std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider,
     const StatusChangeCallback& status_change_cb,
     const CreateVideoEncodeAcceleratorCallback& create_vea_cb) {
   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
@@ -137,7 +139,7 @@
       cast_environment_, video_config,
       base::BindRepeating(&CastSenderImpl::OnVideoStatusChange,
                           weak_factory_.GetWeakPtr(), status_change_cb),
-      create_vea_cb, transport_sender_,
+      create_vea_cb, transport_sender_, std::move(metrics_provider),
       base::BindRepeating(&CastSenderImpl::SetTargetPlayoutDelay,
                           weak_factory_.GetWeakPtr()),
       media::VideoCaptureFeedbackCB());
diff --git a/media/cast/cast_sender_impl.h b/media/cast/cast_sender_impl.h
index f11bfac..5e193bb 100644
--- a/media/cast/cast_sender_impl.h
+++ b/media/cast/cast_sender_impl.h
@@ -30,6 +30,7 @@
                        StatusChangeOnceCallback status_change_cb) final;
   void InitializeVideo(
       const FrameSenderConfig& video_config,
+      std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider,
       const StatusChangeCallback& status_change_cb,
       const CreateVideoEncodeAcceleratorCallback& create_vea_cb) final;
 
diff --git a/media/cast/encoding/av1_encoder.cc b/media/cast/encoding/av1_encoder.cc
index e11bb1aa..25f54711 100644
--- a/media/cast/encoding/av1_encoder.cc
+++ b/media/cast/encoding/av1_encoder.cc
@@ -5,10 +5,12 @@
 #include "media/cast/encoding/av1_encoder.h"
 
 #include "base/logging.h"
+#include "base/strings/strcat.h"
 #include "media/base/video_frame.h"
 #include "media/cast/common/openscreen_conversion_helpers.h"
 #include "media/cast/common/sender_encoded_frame.h"
 #include "media/cast/constants.h"
+#include "media/mojo/clients/mojo_video_encoder_metrics_provider.h"
 #include "third_party/libaom/source/libaom/aom/aomcx.h"
 #include "third_party/openscreen/src/cast/streaming/encoded_frame.h"
 
@@ -59,7 +61,9 @@
 
 }  // namespace
 
-Av1Encoder::Av1Encoder(const FrameSenderConfig& video_config)
+Av1Encoder::Av1Encoder(
+    const FrameSenderConfig& video_config,
+    std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider)
     : cast_config_(video_config),
       target_encoder_utilization_(
           video_config.video_codec_params.number_of_encode_threads > 2
@@ -67,6 +71,7 @@
               : (video_config.video_codec_params.number_of_encode_threads > 1
                      ? kMidTargetEncoderUtilization
                      : kLoTargetEncoderUtilization)),
+      metrics_provider_(std::move(metrics_provider)),
       key_frame_requested_(true),
       bitrate_kbit_(cast_config_.start_bitrate / 1000),
       next_frame_id_(FrameId::first()),
@@ -155,9 +160,19 @@
 
   config_.kf_mode = AOM_KF_DISABLED;
 
+  metrics_provider_->Initialize(media::AV1PROFILE_MIN, frame_size,
+                                /*is_hardware_encoder=*/false);
   aom_codec_flags_t flags = 0;
-  CHECK_EQ(aom_codec_enc_init(&encoder_, aom_codec_av1_cx(), &config_, flags),
-           AOM_CODEC_OK);
+  if (aom_codec_err_t ret =
+          aom_codec_enc_init(&encoder_, aom_codec_av1_cx(), &config_, flags);
+      ret != AOM_CODEC_OK) {
+    metrics_provider_->SetError(
+        {media::EncoderStatus::Codes::kEncoderInitializationError,
+         base::StrCat(
+             {"libvpx failed to initialize: ", aom_codec_err_to_string(ret)})});
+    LOG(FATAL) << "aom_codec_enc_init() failed: "
+               << aom_codec_err_to_string(ret);
+  }
 
   // This cpu_used setting is a trade-off between cpu usage and encoded video
   // quality. The default is zero, with increasingly less CPU to be used as the
@@ -231,11 +246,17 @@
   // zero to force the encoder to base its single-frame bandwidth calculations
   // entirely on |predicted_frame_duration| and the target bitrate setting being
   // micro-managed via calls to UpdateRates().
-  CHECK_EQ(aom_codec_encode(&encoder_, &aom_image, 0,
-                            predicted_frame_duration.InMicroseconds(),
-                            key_frame_requested_ ? AOM_EFLAG_FORCE_KF : 0),
-           AOM_CODEC_OK)
-      << "BUG: Invalid arguments passed to aom_codec_encode().";
+  if (aom_codec_err_t ret = aom_codec_encode(
+          &encoder_, &aom_image, 0, predicted_frame_duration.InMicroseconds(),
+          key_frame_requested_ ? AOM_EFLAG_FORCE_KF : 0);
+      ret != AOM_CODEC_OK) {
+    metrics_provider_->SetError(
+        {media::EncoderStatus::Codes::kEncoderFailedEncode,
+         base::StrCat(
+             {"libaom failed to encode: ", aom_codec_err_to_string(ret), " - ",
+              aom_codec_error_detail(&encoder_)})});
+    LOG(FATAL) << "BUG: Invalid arguments passed to aom_codec_encode().";
+  }
 
   // Pull data from the encoder, populating a new EncodedFrame.
   encoded_frame->frame_id = next_frame_id_++;
@@ -267,6 +288,7 @@
   }
   DCHECK(!encoded_frame->data.empty())
       << "BUG: Encoder must provide data since lagged encoding is disabled.";
+  metrics_provider_->IncrementEncodedFrameCount();
 
   // Compute encoder utilization as the real-world time elapsed divided by the
   // frame duration.
diff --git a/media/cast/encoding/av1_encoder.h b/media/cast/encoding/av1_encoder.h
index 00628c2..326bd8b 100644
--- a/media/cast/encoding/av1_encoder.h
+++ b/media/cast/encoding/av1_encoder.h
@@ -17,15 +17,18 @@
 #include "ui/gfx/geometry/size.h"
 
 namespace media {
+class MojoVideoEncoderMetricsProvider;
 class VideoFrame;
-}
+}  // namespace media
 
 namespace media {
 namespace cast {
 
 class Av1Encoder final : public SoftwareVideoEncoder {
  public:
-  explicit Av1Encoder(const FrameSenderConfig& video_config);
+  explicit Av1Encoder(
+      const FrameSenderConfig& video_config,
+      std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider);
 
   ~Av1Encoder() final;
 
@@ -54,6 +57,8 @@
 
   const double target_encoder_utilization_;
 
+  const std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider_;
+
   // AV1 internal objects.  These are valid for use only while is_initialized()
   // returns true.
   aom_codec_enc_cfg_t config_;
diff --git a/media/cast/encoding/external_video_encoder.cc b/media/cast/encoding/external_video_encoder.cc
index d7d3976..ada38d5 100644
--- a/media/cast/encoding/external_video_encoder.cc
+++ b/media/cast/encoding/external_video_encoder.cc
@@ -39,6 +39,7 @@
 #include "media/cast/common/sender_encoded_frame.h"
 #include "media/cast/encoding/vpx_quantizer_parser.h"
 #include "media/cast/logging/logging_defines.h"
+#include "media/mojo/clients/mojo_video_encoder_metrics_provider.h"
 #include "media/video/h264_parser.h"
 
 namespace {
@@ -109,12 +110,14 @@
     : public VideoEncodeAccelerator::Client,
       public base::RefCountedThreadSafe<VEAClientImpl> {
  public:
+  using EncoderStatusChangeCallback =
+      base::RepeatingCallback<void(media::EncoderStatus, OperationalStatus)>;
   VEAClientImpl(
       const scoped_refptr<CastEnvironment>& cast_environment,
       const scoped_refptr<base::SingleThreadTaskRunner>& encoder_task_runner,
       std::unique_ptr<media::VideoEncodeAccelerator> vea,
       double max_frame_rate,
-      StatusChangeCallback status_change_cb)
+      EncoderStatusChangeCallback status_change_cb)
       : cast_environment_(cast_environment),
         task_runner_(encoder_task_runner),
         max_frame_rate_(max_frame_rate),
@@ -160,9 +163,11 @@
 
     cast_environment_->PostTask(
         CastEnvironment::MAIN, FROM_HERE,
-        base::BindOnce(status_change_cb_, encoder_active_
-                                              ? STATUS_INITIALIZED
-                                              : STATUS_CODEC_INIT_FAILED));
+        base::BindOnce(
+            status_change_cb_,
+            encoder_active_ ? media::EncoderStatus::Codes::kOk
+                            : media::EncoderStatus::Codes::kEncoderFailedEncode,
+            encoder_active_ ? STATUS_INITIALIZED : STATUS_CODEC_INIT_FAILED));
   }
 
   void SetBitRate(int bit_rate) {
@@ -271,7 +276,7 @@
 
     cast_environment_->PostTask(
         CastEnvironment::MAIN, FROM_HERE,
-        base::BindOnce(status_change_cb_, STATUS_CODEC_RUNTIME_ERROR));
+        base::BindOnce(status_change_cb_, status, STATUS_CODEC_RUNTIME_ERROR));
 
     // Flush all in progress frames to avoid any getting stuck.
     while (!in_progress_frame_encodes_.empty())
@@ -579,7 +584,8 @@
   const scoped_refptr<CastEnvironment> cast_environment_;
   const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   const double max_frame_rate_;
-  const StatusChangeCallback status_change_cb_;  // Must be run on MAIN thread.
+  // Must be run on MAIN thread.
+  const EncoderStatusChangeCallback status_change_cb_;
   std::unique_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_;
   bool encoder_active_;
   FrameId next_frame_id_;
@@ -630,11 +636,13 @@
 ExternalVideoEncoder::ExternalVideoEncoder(
     const scoped_refptr<CastEnvironment>& cast_environment,
     const FrameSenderConfig& video_config,
+    MojoVideoEncoderMetricsProvider& metrics_provider,
     const gfx::Size& frame_size,
     FrameId first_frame_id,
     StatusChangeCallback status_change_cb,
     const CreateVideoEncodeAcceleratorCallback& create_vea_cb)
     : cast_environment_(cast_environment),
+      metrics_provider_(metrics_provider),
       frame_size_(frame_size),
       bit_rate_(video_config.start_bitrate) {
   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
@@ -665,6 +673,12 @@
   }
 }
 
+void ExternalVideoEncoder::SetErrorToMetricsProvider(
+    const media::EncoderStatus& encoder_status) {
+  DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
+  metrics_provider_->SetError(encoder_status);
+}
+
 bool ExternalVideoEncoder::EncodeVideoFrame(
     scoped_refptr<media::VideoFrame> video_frame,
     base::TimeTicks reference_time,
@@ -741,36 +755,43 @@
 
   // Create a callback that wraps the StatusChangeCallback. It monitors when a
   // fatal error occurs and schedules destruction of the VEAClientImpl.
-  StatusChangeCallback wrapped_status_change_cb = base::BindRepeating(
-      [](base::WeakPtr<ExternalVideoEncoder> self,
-         const StatusChangeCallback& status_change_cb,
-         OperationalStatus status) {
-        if (self.get()) {
-          switch (status) {
-            case STATUS_UNINITIALIZED:
-            case STATUS_INITIALIZED:
-            case STATUS_CODEC_REINIT_PENDING:
-              break;
+  VEAClientImpl::EncoderStatusChangeCallback wrapped_status_change_cb =
+      base::BindRepeating(
+          [](base::WeakPtr<ExternalVideoEncoder> self,
+             const StatusChangeCallback& status_change_cb,
+             media::EncoderStatus encoder_status, OperationalStatus status) {
+            if (self.get()) {
+              if (!encoder_status.is_ok()) {
+                self->SetErrorToMetricsProvider(encoder_status);
+              }
+              switch (status) {
+                case STATUS_UNINITIALIZED:
+                case STATUS_INITIALIZED:
+                case STATUS_CODEC_REINIT_PENDING:
+                  break;
 
-            case STATUS_INVALID_CONFIGURATION:
-            case STATUS_UNSUPPORTED_CODEC:
-            case STATUS_CODEC_INIT_FAILED:
-            case STATUS_CODEC_RUNTIME_ERROR:
-              // Something bad happened. Destroy the client to: 1) fail-out any
-              // currently in-progress frame encodes; and 2) prevent future
-              // EncodeVideoFrame() calls from queuing frames indefinitely.
-              self->DestroyClientSoon();
-              break;
-          }
-        }
-        status_change_cb.Run(status);
-      },
-      weak_factory_.GetWeakPtr(), status_change_cb);
+                case STATUS_INVALID_CONFIGURATION:
+                case STATUS_UNSUPPORTED_CODEC:
+                case STATUS_CODEC_INIT_FAILED:
+                case STATUS_CODEC_RUNTIME_ERROR:
+                  // Something bad happened. Destroy the client to: 1) fail-out
+                  // any currently in-progress frame encodes; and 2) prevent
+                  // future EncodeVideoFrame() calls from queuing frames
+                  // indefinitely.
+                  self->DestroyClientSoon();
+                  break;
+              }
+            }
+            status_change_cb.Run(status);
+          },
+          weak_factory_.GetWeakPtr(), status_change_cb);
 
   DCHECK(!client_);
   client_ = new VEAClientImpl(cast_environment_, encoder_task_runner,
                               std::move(vea), video_config.max_frame_rate,
                               std::move(wrapped_status_change_cb));
+  metrics_provider_->Initialize(codec_profile, frame_size_,
+                                /*is_hardware_encoder=*/true);
   client_->task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(&VEAClientImpl::Initialize, client_, frame_size_,
@@ -780,10 +801,12 @@
 SizeAdaptableExternalVideoEncoder::SizeAdaptableExternalVideoEncoder(
     const scoped_refptr<CastEnvironment>& cast_environment,
     const FrameSenderConfig& video_config,
+    std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider,
     StatusChangeCallback status_change_cb,
     const CreateVideoEncodeAcceleratorCallback& create_vea_cb)
     : SizeAdaptableVideoEncoderBase(cast_environment,
                                     video_config,
+                                    std::move(metrics_provider),
                                     std::move(status_change_cb)),
       create_vea_cb_(create_vea_cb) {}
 
@@ -793,8 +816,8 @@
 std::unique_ptr<VideoEncoder>
 SizeAdaptableExternalVideoEncoder::CreateEncoder() {
   return std::make_unique<ExternalVideoEncoder>(
-      cast_environment(), video_config(), frame_size(), next_frame_id(),
-      CreateEncoderStatusChangeCallback(), create_vea_cb_);
+      cast_environment(), video_config(), metrics_provider(), frame_size(),
+      next_frame_id(), CreateEncoderStatusChangeCallback(), create_vea_cb_);
 }
 
 QuantizerEstimator::QuantizerEstimator() = default;
diff --git a/media/cast/encoding/external_video_encoder.h b/media/cast/encoding/external_video_encoder.h
index ec91451..f63d742 100644
--- a/media/cast/encoding/external_video_encoder.h
+++ b/media/cast/encoding/external_video_encoder.h
@@ -10,6 +10,7 @@
 
 #include <memory>
 
+#include "base/memory/raw_ref.h"
 #include "base/memory/weak_ptr.h"
 #include "base/task/single_thread_task_runner.h"
 #include "media/cast/cast_environment.h"
@@ -19,6 +20,9 @@
 #include "ui/gfx/geometry/size.h"
 
 namespace media {
+
+class MojoVideoEncoderMetricsProvider;
+
 namespace cast {
 
 // Cast MAIN thread proxy to the internal media::VideoEncodeAccelerator
@@ -43,6 +47,7 @@
   ExternalVideoEncoder(
       const scoped_refptr<CastEnvironment>& cast_environment,
       const FrameSenderConfig& video_config,
+      MojoVideoEncoderMetricsProvider& metrics_provider,
       const gfx::Size& frame_size,
       FrameId first_frame_id,
       StatusChangeCallback status_change_cb,
@@ -67,6 +72,8 @@
   // of |client_| via the encoder task runner.
   void DestroyClientSoon();
 
+  void SetErrorToMetricsProvider(const media::EncoderStatus& encoder_status);
+
   // Method invoked by the CreateVideoEncodeAcceleratorCallback to construct a
   // VEAClientImpl to own and interface with a new |vea|.  Upon return,
   // |client_| holds a reference to the new VEAClientImpl.
@@ -79,6 +86,8 @@
 
   const scoped_refptr<CastEnvironment> cast_environment_;
 
+  base::raw_ref<MojoVideoEncoderMetricsProvider> metrics_provider_;
+
   // The size of the visible region of the video frames to be encoded.
   const gfx::Size frame_size_;
 
@@ -100,6 +109,7 @@
   SizeAdaptableExternalVideoEncoder(
       const scoped_refptr<CastEnvironment>& cast_environment,
       const FrameSenderConfig& video_config,
+      std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider,
       StatusChangeCallback status_change_cb,
       const CreateVideoEncodeAcceleratorCallback& create_vea_cb);
 
diff --git a/media/cast/encoding/h264_vt_encoder.cc b/media/cast/encoding/h264_vt_encoder.cc
index c95e9a67..d9c3b7b8 100644
--- a/media/cast/encoding/h264_vt_encoder.cc
+++ b/media/cast/encoding/h264_vt_encoder.cc
@@ -15,8 +15,10 @@
 #include "base/functional/callback_helpers.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/mac/mac_logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/power_monitor/power_monitor.h"
+#include "base/strings/strcat.h"
 #include "base/synchronization/lock.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
@@ -26,17 +28,14 @@
 #include "media/cast/common/sender_encoded_frame.h"
 #include "media/cast/common/video_frame_factory.h"
 #include "media/cast/constants.h"
+#include "media/mojo/clients/mojo_video_encoder_metrics_provider.h"
 #include "third_party/openscreen/src/cast/streaming/encoded_frame.h"
 
 using Dependency = openscreen::cast::EncodedFrame::Dependency;
 
 namespace media {
 namespace cast {
-
-namespace {
-
-// Container for the associated data of a video frame being processed.
-struct InProgressH264VTFrameEncode {
+struct H264VideoToolboxEncoder::InProgressH264VTFrameEncode {
   const RtpTimeTicks rtp_timestamp;
   const base::TimeTicks reference_time;
   VideoEncoder::FrameEncodedCallback frame_encoded_callback;
@@ -49,8 +48,6 @@
         frame_encoded_callback(std::move(callback)) {}
 };
 
-}  // namespace
-
 class H264VideoToolboxEncoder::VideoFrameFactoryImpl final
     : public base::RefCountedThreadSafe<VideoFrameFactoryImpl>,
       public VideoFrameFactory {
@@ -162,11 +159,13 @@
 H264VideoToolboxEncoder::H264VideoToolboxEncoder(
     const scoped_refptr<CastEnvironment>& cast_environment,
     const FrameSenderConfig& video_config,
+    std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider,
     StatusChangeCallback status_change_cb)
     : cast_environment_(cast_environment),
       video_config_(video_config),
       average_bitrate_((video_config_.min_bitrate + video_config_.max_bitrate) /
                        2),
+      metrics_provider_(std::move(metrics_provider)),
       status_change_cb_(std::move(status_change_cb)),
       next_frame_id_(FrameId::first()),
       encode_next_frame_as_keyframe_(false),
@@ -253,6 +252,9 @@
   for (auto* v : buffer_attributes_values)
     CFRelease(v);
 
+  metrics_provider_->Initialize(media::H264PROFILE_MAIN, frame_size_,
+                                /*is_hardware_encoder=*/true);
+
   // Create the compression session.
 
   // Note that the encoder object is given to the compression session as the
@@ -271,6 +273,10 @@
       reinterpret_cast<void*>(this), compression_session_.InitializeInto());
   if (status != noErr) {
     DLOG(ERROR) << " VTCompressionSessionCreate failed: " << status;
+    metrics_provider_->SetError(
+        {media::EncoderStatus::Codes::kEncoderInitializationError,
+         base::StrCat({"VTCompressionSessionCreate failed: ",
+                       logging::DescriptionFromOSStatus(status)})});
     // Notify that reinitialization has failed.
     cast_environment_->PostTask(
         CastEnvironment::MAIN, FROM_HERE,
@@ -412,6 +418,11 @@
       frame_props, reinterpret_cast<void*>(request.release()), nullptr);
   if (status != noErr) {
     DLOG(ERROR) << " VTCompressionSessionEncodeFrame failed: " << status;
+    metrics_provider_->SetError(
+        {media::EncoderStatus::Codes::kEncoderInitializationError,
+         base::StrCat({"VTCompressionSessionEncodeFrame failed: ",
+                       logging::DescriptionFromOSStatus(status)})});
+
     return false;
   }
 
@@ -494,25 +505,18 @@
   }
 }
 
+// static
 void H264VideoToolboxEncoder::CompressionCallback(void* encoder_opaque,
                                                   void* request_opaque,
                                                   OSStatus status,
                                                   VTEncodeInfoFlags info,
                                                   CMSampleBufferRef sbuf) {
-  auto* encoder = reinterpret_cast<H264VideoToolboxEncoder*>(encoder_opaque);
-  std::unique_ptr<InProgressH264VTFrameEncode> request(
-      reinterpret_cast<InProgressH264VTFrameEncode*>(request_opaque));
+  // This function may be called asynchronously, on a different thread from the
+  // one that calls VTCompressionSessionEncodeFrame().
   bool is_keyframe = false;
-  bool has_frame_data = false;
-
-  if (status != noErr) {
-    DLOG(ERROR) << " encoding failed: " << status;
-    encoder->cast_environment_->PostTask(
-        CastEnvironment::MAIN, FROM_HERE,
-        base::BindOnce(encoder->status_change_cb_, STATUS_CODEC_RUNTIME_ERROR));
-  } else if ((info & kVTEncodeInfo_FrameDropped)) {
-    DVLOG(2) << " frame dropped";
-  } else {
+  std::string data;
+  DVLOG_IF(2, (info & kVTEncodeInfo_FrameDropped)) << " frame dropped";
+  if (status == noErr && !(info & kVTEncodeInfo_FrameDropped)) {
     auto* sample_attachments =
         static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(
             CMSampleBufferGetSampleAttachmentsArray(sbuf, true), 0));
@@ -522,12 +526,37 @@
     // alternatively use kCMSampleAttachmentKey_DependsOnOthers == false.
     is_keyframe = !CFDictionaryContainsKey(sample_attachments,
                                            kCMSampleAttachmentKey_NotSync);
-    has_frame_data = true;
+    video_toolbox::CopySampleBufferToAnnexBBuffer(VideoCodec::kH264, sbuf,
+                                                  is_keyframe, &data);
+  }
+  auto* encoder = reinterpret_cast<H264VideoToolboxEncoder*>(encoder_opaque);
+  encoder->cast_environment_->PostTask(
+      CastEnvironment::MAIN, FROM_HERE,
+      base::BindOnce(&H264VideoToolboxEncoder::CompressionCallbackTask,
+                     encoder->weak_factory_.GetWeakPtr(),
+                     base::WrapUnique(static_cast<InProgressH264VTFrameEncode*>(
+                         request_opaque)),
+                     status, is_keyframe, std::move(data)));
+}
+
+void H264VideoToolboxEncoder::CompressionCallbackTask(
+    std::unique_ptr<InProgressH264VTFrameEncode> request,
+    OSStatus status,
+    bool is_keyframe,
+    std::string data) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  if (status != noErr) {
+    DLOG(ERROR) << " encoding failed: " << status;
+    metrics_provider_->SetError(
+        {media::EncoderStatus::Codes::kEncoderInitializationError,
+         base::StrCat(
+             {"encoding failed: ", logging::DescriptionFromOSStatus(status)})});
+    status_change_cb_.Run(STATUS_CODEC_RUNTIME_ERROR);
   }
 
   // Grab the next frame ID and increment |next_frame_id_| for next time.
   // VideoToolbox calls the output callback serially, so this is safe.
-  const FrameId frame_id = encoder->next_frame_id_++;
+  const FrameId frame_id = next_frame_id_++;
 
   std::unique_ptr<SenderEncodedFrame> encoded_frame(new SenderEncodedFrame());
   encoded_frame->frame_id = frame_id;
@@ -550,18 +579,15 @@
     encoded_frame->referenced_frame_id = frame_id - 1;
   }
 
-  if (has_frame_data) {
-    video_toolbox::CopySampleBufferToAnnexBBuffer(
-        VideoCodec::kH264, sbuf, is_keyframe, &encoded_frame->data);
+  if (!data.empty()) {
+    encoded_frame->data = std::move(data);
+    metrics_provider_->IncrementEncodedFrameCount();
   }
 
   encoded_frame->encode_completion_time =
-      encoder->cast_environment_->Clock()->NowTicks();
-  encoded_frame->encoder_bitrate = encoder->average_bitrate_;
-  encoder->cast_environment_->GetTaskRunner(CastEnvironment::MAIN)
-      ->PostTask(FROM_HERE,
-                 base::BindOnce(std::move(request->frame_encoded_callback),
-                                std::move(encoded_frame)));
+      cast_environment_->Clock()->NowTicks();
+  encoded_frame->encoder_bitrate = average_bitrate_;
+  std::move(request->frame_encoded_callback).Run(std::move(encoded_frame));
 }
 
 }  // namespace cast
diff --git a/media/cast/encoding/h264_vt_encoder.h b/media/cast/encoding/h264_vt_encoder.h
index 08c7f547..da79faad 100644
--- a/media/cast/encoding/h264_vt_encoder.h
+++ b/media/cast/encoding/h264_vt_encoder.h
@@ -32,6 +32,7 @@
   H264VideoToolboxEncoder(
       const scoped_refptr<CastEnvironment>& cast_environment,
       const FrameSenderConfig& video_config,
+      std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider,
       StatusChangeCallback status_change_cb);
 
   H264VideoToolboxEncoder(const H264VideoToolboxEncoder&) = delete;
@@ -53,6 +54,8 @@
   void OnResume() override;
 
  private:
+  // Container for the associated data of a video frame being processed.
+  struct InProgressH264VTFrameEncode;
   // VideoFrameFactory tied to the VideoToolbox encoder.
   class VideoFrameFactoryImpl;
 
@@ -73,12 +76,20 @@
   // session. This will also update the video frame factory.
   void UpdateFrameSize(const gfx::Size& size_needed);
 
-  // Compression session callback function to handle compressed frames.
+  // Compression session callback function to handle compressed frames. This can
+  // be called by any thread.
   static void CompressionCallback(void* encoder_opaque,
                                   void* request_opaque,
                                   OSStatus status,
                                   VTEncodeInfoFlags info,
                                   CMSampleBufferRef sbuf);
+  // Invoked from CompressionCallback() to handle an encoded frame on the Cast
+  // main thread.
+  void CompressionCallbackTask(
+      std::unique_ptr<InProgressH264VTFrameEncode> request,
+      OSStatus status,
+      bool is_keyframe,
+      std::string data);
 
   // The cast environment (contains worker threads & more).
   const scoped_refptr<CastEnvironment> cast_environment_;
@@ -96,10 +107,12 @@
   // a frame of a different size, which will cause a compression session reset.
   gfx::Size frame_size_;
 
+  const std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider_;
+
   // Callback used to report initialization status and runtime errors.
   const StatusChangeCallback status_change_cb_;
 
-  // Thread checker to enforce that this object is used on a specific thread.
+  // Thread checker to enforce that this object is used on cast main thread.
   THREAD_CHECKER(thread_checker_);
 
   // The compression session.
diff --git a/media/cast/encoding/h264_vt_encoder_unittest.cc b/media/cast/encoding/h264_vt_encoder_unittest.cc
index bf4c1e6..78971466 100644
--- a/media/cast/encoding/h264_vt_encoder_unittest.cc
+++ b/media/cast/encoding/h264_vt_encoder_unittest.cc
@@ -34,6 +34,7 @@
 #include "media/filters/ffmpeg_glue.h"
 #include "media/filters/ffmpeg_video_decoder.h"
 #include "media/media_buildflags.h"
+#include "media/mojo/clients/mock_mojo_video_encoder_metrics_provider.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using Dependency = openscreen::cast::EncodedFrame::Dependency;
@@ -232,6 +233,8 @@
         task_environment_.GetMainThreadTaskRunner());
     encoder_ = std::make_unique<H264VideoToolboxEncoder>(
         cast_environment_, video_sender_config_,
+        std::make_unique<MockMojoVideoEncoderMetricsProvider>(
+            media::mojom::VideoEncoderUseCase::kCastMirroring),
         base::BindRepeating(&SaveOperationalStatus, &operational_status_));
     base::RunLoop().RunUntilIdle();
     EXPECT_EQ(STATUS_INITIALIZED, operational_status_);
diff --git a/media/cast/encoding/size_adaptable_video_encoder_base.cc b/media/cast/encoding/size_adaptable_video_encoder_base.cc
index aa748bd..d031553 100644
--- a/media/cast/encoding/size_adaptable_video_encoder_base.cc
+++ b/media/cast/encoding/size_adaptable_video_encoder_base.cc
@@ -11,6 +11,7 @@
 #include "base/logging.h"
 #include "media/base/video_frame.h"
 #include "media/cast/common/sender_encoded_frame.h"
+#include "media/mojo/clients/mojo_video_encoder_metrics_provider.h"
 
 namespace media {
 namespace cast {
@@ -18,9 +19,11 @@
 SizeAdaptableVideoEncoderBase::SizeAdaptableVideoEncoderBase(
     const scoped_refptr<CastEnvironment>& cast_environment,
     const FrameSenderConfig& video_config,
+    std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider,
     StatusChangeCallback status_change_cb)
     : cast_environment_(cast_environment),
       video_config_(video_config),
+      metrics_provider_(std::move(metrics_provider)),
       status_change_cb_(std::move(status_change_cb)),
       frames_in_encoder_(0),
       next_frame_id_(FrameId::first()) {
@@ -166,6 +169,8 @@
   if (encoded_frame) {
     next_frame_id_ = encoded_frame->frame_id + 1;
   }
+
+  metrics_provider_->IncrementEncodedFrameCount();
   std::move(frame_encoded_callback).Run(std::move(encoded_frame));
 }
 
diff --git a/media/cast/encoding/size_adaptable_video_encoder_base.h b/media/cast/encoding/size_adaptable_video_encoder_base.h
index 820a3a8..f0e67a92 100644
--- a/media/cast/encoding/size_adaptable_video_encoder_base.h
+++ b/media/cast/encoding/size_adaptable_video_encoder_base.h
@@ -18,6 +18,9 @@
 #include "ui/gfx/geometry/size.h"
 
 namespace media {
+
+class MojoVideoEncoderMetricsProvider;
+
 namespace cast {
 
 struct SenderEncodedFrame;
@@ -32,6 +35,7 @@
   SizeAdaptableVideoEncoderBase(
       const scoped_refptr<CastEnvironment>& cast_environment,
       const FrameSenderConfig& video_config,
+      std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider,
       StatusChangeCallback status_change_cb);
 
   SizeAdaptableVideoEncoderBase(const SizeAdaptableVideoEncoderBase&) = delete;
@@ -55,6 +59,9 @@
   const FrameSenderConfig& video_config() const { return video_config_; }
   const gfx::Size& frame_size() const { return frame_size_; }
   FrameId next_frame_id() const { return next_frame_id_; }
+  MojoVideoEncoderMetricsProvider& metrics_provider() const {
+    return *metrics_provider_.get();
+  }
 
   // Returns a callback that calls OnEncoderStatusChange().  The callback is
   // canceled by invalidating its bound weak pointer just before a replacement
@@ -93,6 +100,8 @@
   // SetBitRate(), for when a replacement encoder is spawned.
   FrameSenderConfig video_config_;
 
+  const std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider_;
+
   // Run whenever the underlying encoder reports a status change.
   const StatusChangeCallback status_change_cb_;
 
diff --git a/media/cast/encoding/video_encoder.cc b/media/cast/encoding/video_encoder.cc
index 877e747..cee51dc3 100644
--- a/media/cast/encoding/video_encoder.cc
+++ b/media/cast/encoding/video_encoder.cc
@@ -9,6 +9,7 @@
 #include "media/cast/encoding/encoding_support.h"
 #include "media/cast/encoding/external_video_encoder.h"
 #include "media/cast/encoding/video_encoder_impl.h"
+#include "media/mojo/clients/mojo_video_encoder_metrics_provider.h"
 
 #if BUILDFLAG(IS_APPLE)
 #include "media/cast/encoding/h264_vt_encoder.h"
@@ -20,6 +21,7 @@
 std::unique_ptr<VideoEncoder> VideoEncoder::Create(
     const scoped_refptr<CastEnvironment>& cast_environment,
     const FrameSenderConfig& video_config,
+    std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider,
     StatusChangeCallback status_change_cb,
     const CreateVideoEncodeAcceleratorCallback& create_vea_cb) {
 // On MacOS and iOS: attempt to use the system VideoToolbox library to
@@ -31,21 +33,23 @@
   if (video_config.use_hardware_encoder &&
       H264VideoToolboxEncoder::IsSupported(video_config)) {
     return base::WrapUnique<VideoEncoder>(new H264VideoToolboxEncoder(
-        cast_environment, video_config, status_change_cb));
+        cast_environment, video_config, std::move(metrics_provider),
+        status_change_cb));
   }
 #endif  // BUILDFLAG(IS_APPLE)
 
   // If the system provides a hardware-accelerated encoder, use it.
   if (video_config.use_hardware_encoder) {
     return base::WrapUnique<VideoEncoder>(new SizeAdaptableExternalVideoEncoder(
-        cast_environment, video_config, std::move(status_change_cb),
-        create_vea_cb));
+        cast_environment, video_config, std::move(metrics_provider),
+        std::move(status_change_cb), create_vea_cb));
   }
 
   // Otherwise we must have a software configuration.
   DCHECK(encoding_support::IsSoftwareEnabled(video_config.codec));
   return base::WrapUnique<VideoEncoder>(
-      new VideoEncoderImpl(cast_environment, video_config, status_change_cb));
+      new VideoEncoderImpl(cast_environment, video_config,
+                           std::move(metrics_provider), status_change_cb));
 }
 
 std::unique_ptr<VideoFrameFactory> VideoEncoder::CreateVideoFrameFactory() {
diff --git a/media/cast/encoding/video_encoder.h b/media/cast/encoding/video_encoder.h
index 865d21b..44874151 100644
--- a/media/cast/encoding/video_encoder.h
+++ b/media/cast/encoding/video_encoder.h
@@ -17,6 +17,9 @@
 #include "media/cast/common/video_frame_factory.h"
 
 namespace media {
+
+class MojoVideoEncoderMetricsProvider;
+
 namespace cast {
 
 struct SenderEncodedFrame;
@@ -38,6 +41,7 @@
   static std::unique_ptr<VideoEncoder> Create(
       const scoped_refptr<CastEnvironment>& cast_environment,
       const FrameSenderConfig& video_config,
+      std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider,
       StatusChangeCallback status_change_cb,
       const CreateVideoEncodeAcceleratorCallback& create_vea_cb);
 
diff --git a/media/cast/encoding/video_encoder_impl.cc b/media/cast/encoding/video_encoder_impl.cc
index db96304..eff6020 100644
--- a/media/cast/encoding/video_encoder_impl.cc
+++ b/media/cast/encoding/video_encoder_impl.cc
@@ -18,6 +18,7 @@
 #include "media/cast/common/sender_encoded_frame.h"
 #include "media/cast/encoding/fake_software_video_encoder.h"
 #include "media/cast/encoding/vpx_encoder.h"
+#include "media/mojo/clients/mojo_video_encoder_metrics_provider.h"
 
 namespace media {
 namespace cast {
@@ -56,6 +57,7 @@
 VideoEncoderImpl::VideoEncoderImpl(
     scoped_refptr<CastEnvironment> cast_environment,
     const FrameSenderConfig& video_config,
+    std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider,
     StatusChangeCallback status_change_cb)
     : cast_environment_(cast_environment) {
   CHECK(cast_environment_->HasVideoThread());
@@ -63,7 +65,8 @@
 
   if (video_config.codec == Codec::kVideoVp8 ||
       video_config.codec == Codec::kVideoVp9) {
-    encoder_ = std::make_unique<VpxEncoder>(video_config);
+    encoder_ =
+        std::make_unique<VpxEncoder>(video_config, std::move(metrics_provider));
     cast_environment_->PostTask(
         CastEnvironment::VIDEO, FROM_HERE,
         base::BindOnce(&InitializeEncoderOnEncoderThread, cast_environment,
@@ -73,7 +76,8 @@
     encoder_ = std::make_unique<FakeSoftwareVideoEncoder>(video_config);
 #if BUILDFLAG(ENABLE_LIBAOM)
   } else if (video_config.codec == Codec::kVideoAv1) {
-    encoder_ = std::make_unique<Av1Encoder>(video_config);
+    encoder_ =
+        std::make_unique<Av1Encoder>(video_config, std::move(metrics_provider));
     cast_environment_->PostTask(
         CastEnvironment::VIDEO, FROM_HERE,
         base::BindOnce(&InitializeEncoderOnEncoderThread, cast_environment,
diff --git a/media/cast/encoding/video_encoder_impl.h b/media/cast/encoding/video_encoder_impl.h
index f4a9b12..76ccf0b03d 100644
--- a/media/cast/encoding/video_encoder_impl.h
+++ b/media/cast/encoding/video_encoder_impl.h
@@ -13,6 +13,8 @@
 #include "media/cast/encoding/video_encoder.h"
 
 namespace media {
+
+class MojoVideoEncoderMetricsProvider;
 class VideoFrame;
 
 namespace cast {
@@ -29,9 +31,11 @@
   // Returns true if VideoEncoderImpl can be used with the given |video_config|.
   static bool IsSupported(const FrameSenderConfig& video_config);
 
-  VideoEncoderImpl(scoped_refptr<CastEnvironment> cast_environment,
-                   const FrameSenderConfig& video_config,
-                   StatusChangeCallback status_change_cb);
+  VideoEncoderImpl(
+      scoped_refptr<CastEnvironment> cast_environment,
+      const FrameSenderConfig& video_config,
+      std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider,
+      StatusChangeCallback status_change_cb);
 
   VideoEncoderImpl(const VideoEncoderImpl&) = delete;
   VideoEncoderImpl& operator=(const VideoEncoderImpl&) = delete;
diff --git a/media/cast/encoding/video_encoder_unittest.cc b/media/cast/encoding/video_encoder_unittest.cc
index 0f9e410a..787b6c0 100644
--- a/media/cast/encoding/video_encoder_unittest.cc
+++ b/media/cast/encoding/video_encoder_unittest.cc
@@ -28,6 +28,7 @@
 #include "media/cast/test/fake_video_encode_accelerator_factory.h"
 #include "media/cast/test/utility/default_config.h"
 #include "media/cast/test/utility/video_utility.h"
+#include "media/mojo/clients/mock_mojo_video_encoder_metrics_provider.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/openscreen/src/cast/streaming/encoded_frame.h"
 
@@ -86,6 +87,8 @@
     video_config_.video_codec_params.max_number_of_video_buffers_used = 1;
     video_encoder_ = VideoEncoder::Create(
         cast_environment_, video_config_,
+        std::make_unique<media::MockMojoVideoEncoderMetricsProvider>(
+            media::mojom::VideoEncoderUseCase::kCastMirroring),
         base::BindRepeating(&VideoEncoderTest::OnOperationalStatusChange,
                             base::Unretained(this)),
         base::BindRepeating(
diff --git a/media/cast/encoding/vpx_encoder.cc b/media/cast/encoding/vpx_encoder.cc
index 813b8ff..85d0807 100644
--- a/media/cast/encoding/vpx_encoder.cc
+++ b/media/cast/encoding/vpx_encoder.cc
@@ -5,10 +5,12 @@
 #include "media/cast/encoding/vpx_encoder.h"
 
 #include "base/logging.h"
+#include "base/strings/strcat.h"
 #include "media/base/video_frame.h"
 #include "media/cast/common/openscreen_conversion_helpers.h"
 #include "media/cast/common/sender_encoded_frame.h"
 #include "media/cast/constants.h"
+#include "media/mojo/clients/mojo_video_encoder_metrics_provider.h"
 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h"
 #include "third_party/openscreen/src/cast/streaming/encoded_frame.h"
 
@@ -64,7 +66,9 @@
 
 }  // namespace
 
-VpxEncoder::VpxEncoder(const FrameSenderConfig& video_config)
+VpxEncoder::VpxEncoder(
+    const FrameSenderConfig& video_config,
+    std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider)
     : cast_config_(video_config),
       target_encoder_utilization_(
           video_config.video_codec_params.number_of_encode_threads > 2
@@ -72,6 +76,7 @@
               : (video_config.video_codec_params.number_of_encode_threads > 1
                      ? kMidTargetEncoderUtilization
                      : kLoTargetEncoderUtilization)),
+      metrics_provider_(std::move(metrics_provider)),
       key_frame_requested_(true),
       bitrate_kbit_(cast_config_.start_bitrate / 1000),
       next_frame_id_(FrameId::first()),
@@ -168,7 +173,17 @@
   config_.kf_mode = VPX_KF_DISABLED;
 
   vpx_codec_flags_t flags = 0;
-  CHECK_EQ(vpx_codec_enc_init(&encoder_, ctx, &config_, flags), VPX_CODEC_OK);
+  metrics_provider_->Initialize(cast_config_.codec == Codec::kVideoVp9
+                                    ? media::VP9PROFILE_MIN
+                                    : media::VP8PROFILE_ANY,
+                                frame_size, /*is_hardware_encoder=*/false);
+  if (vpx_codec_err_t ret = vpx_codec_enc_init(&encoder_, ctx, &config_, flags);
+      ret != VPX_CODEC_OK) {
+    metrics_provider_->SetError(
+        {media::EncoderStatus::Codes::kEncoderInitializationError,
+         base::StrCat(
+             {"libvpx failed to initialize: ", vpx_codec_err_to_string(ret)})});
+  }
 
   // Raise the threshold for considering macroblocks as static.  The default is
   // zero, so this setting makes the encoder less sensitive to motion.  This
@@ -272,12 +287,17 @@
   // zero to force the encoder to base its single-frame bandwidth calculations
   // entirely on |predicted_frame_duration| and the target bitrate setting being
   // micro-managed via calls to UpdateRates().
-  CHECK_EQ(vpx_codec_encode(&encoder_, &vpx_image, 0,
-                            predicted_frame_duration.InMicroseconds(),
-                            key_frame_requested_ ? VPX_EFLAG_FORCE_KF : 0,
-                            VPX_DL_REALTIME),
-           VPX_CODEC_OK)
-      << "BUG: Invalid arguments passed to vpx_codec_encode().";
+  if (vpx_codec_err_t ret = vpx_codec_encode(
+          &encoder_, &vpx_image, 0, predicted_frame_duration.InMicroseconds(),
+          key_frame_requested_ ? VPX_EFLAG_FORCE_KF : 0, VPX_DL_REALTIME);
+      ret != VPX_CODEC_OK) {
+    metrics_provider_->SetError(
+        {media::EncoderStatus::Codes::kEncoderFailedEncode,
+         base::StrCat(
+             {"libvpx failed to encode: ", vpx_codec_err_to_string(ret), " - ",
+              vpx_codec_error_detail(&encoder_)})});
+    LOG(FATAL) << "BUG: Invalid arguments passed to vpx_codec_encode().";
+  }
 
   // Pull data from the encoder, populating a new EncodedFrame.
   encoded_frame->frame_id = next_frame_id_++;
@@ -307,6 +327,7 @@
   }
   DCHECK(!encoded_frame->data.empty())
       << "BUG: Encoder must provide data since lagged encoding is disabled.";
+  metrics_provider_->IncrementEncodedFrameCount();
 
   // Compute encoder utilization as the real-world time elapsed divided by the
   // frame duration.
diff --git a/media/cast/encoding/vpx_encoder.h b/media/cast/encoding/vpx_encoder.h
index 563bdbf..a696094 100644
--- a/media/cast/encoding/vpx_encoder.h
+++ b/media/cast/encoding/vpx_encoder.h
@@ -17,6 +17,7 @@
 #include "ui/gfx/geometry/size.h"
 
 namespace media {
+class MojoVideoEncoderMetricsProvider;
 class VideoFrame;
 }
 
@@ -25,7 +26,8 @@
 
 class VpxEncoder final : public SoftwareVideoEncoder {
  public:
-  explicit VpxEncoder(const FrameSenderConfig& video_config);
+  VpxEncoder(const FrameSenderConfig& video_config,
+             std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider);
 
   ~VpxEncoder() final;
 
@@ -59,6 +61,8 @@
 
   const double target_encoder_utilization_;
 
+  const std::unique_ptr<MojoVideoEncoderMetricsProvider> metrics_provider_;
+
   // VPX internal objects.  These are valid for use only while is_initialized()
   // returns true.
   vpx_codec_enc_cfg_t config_;
diff --git a/media/cast/encoding/vpx_quantizer_parser_unittest.cc b/media/cast/encoding/vpx_quantizer_parser_unittest.cc
index 4f35957..152b6742f 100644
--- a/media/cast/encoding/vpx_quantizer_parser_unittest.cc
+++ b/media/cast/encoding/vpx_quantizer_parser_unittest.cc
@@ -15,6 +15,7 @@
 #include "media/cast/test/receiver/video_decoder.h"
 #include "media/cast/test/utility/default_config.h"
 #include "media/cast/test/utility/video_utility.h"
+#include "media/mojo/clients/mock_mojo_video_encoder_metrics_provider.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/openscreen/src/cast/streaming/encoded_frame.h"
 
@@ -75,7 +76,10 @@
   // Reconstruct a vp8 encoder with new config since the Vp8Encoder
   // class has no interface to update the config.
   void RecreateVp8Encoder() {
-    vp8_encoder_ = std::make_unique<VpxEncoder>(video_config_);
+    vp8_encoder_ = std::make_unique<VpxEncoder>(
+        video_config_,
+        std::make_unique<media::MockMojoVideoEncoderMetricsProvider>(
+            media::mojom::VideoEncoderUseCase::kCastMirroring));
     vp8_encoder_->Initialize();
   }
 
diff --git a/media/cast/sender/video_sender.cc b/media/cast/sender/video_sender.cc
index 1aec0b47..5102545 100644
--- a/media/cast/sender/video_sender.cc
+++ b/media/cast/sender/video_sender.cc
@@ -23,6 +23,7 @@
 #include "media/cast/net/cast_transport_config.h"
 #include "media/cast/sender/openscreen_frame_sender.h"
 #include "media/cast/sender/performance_metrics_overlay.h"
+#include "media/mojo/clients/mojo_video_encoder_metrics_provider.h"
 #include "third_party/openscreen/src/cast/streaming/encoded_frame.h"
 #include "third_party/openscreen/src/cast/streaming/sender.h"
 
@@ -109,6 +110,8 @@
     StatusChangeCallback status_change_cb,
     const CreateVideoEncodeAcceleratorCallback& create_vea_cb,
     CastTransport* const transport_sender,
+    std::unique_ptr<media::MojoVideoEncoderMetricsProvider>
+        encoder_metrics_provider,
     PlayoutDelayChangeCB playout_delay_change_cb,
     media::VideoCaptureFeedbackCB feedback_cb)
     : VideoSender(cast_environment,
@@ -119,6 +122,7 @@
                                       video_config,
                                       transport_sender,
                                       *this),
+                  std::move(encoder_metrics_provider),
                   std::move(playout_delay_change_cb),
                   std::move(feedback_cb)) {}
 
@@ -128,6 +132,8 @@
     StatusChangeCallback status_change_cb,
     const CreateVideoEncodeAcceleratorCallback& create_vea_cb,
     std::unique_ptr<openscreen::cast::Sender> sender,
+    std::unique_ptr<media::MojoVideoEncoderMetricsProvider>
+        encoder_metrics_provider,
     PlayoutDelayChangeCB playout_delay_change_cb,
     media::VideoCaptureFeedbackCB feedback_cb,
     FrameSender::GetSuggestedVideoBitrateCB get_bitrate_cb)
@@ -140,6 +146,7 @@
                                       std::move(sender),
                                       *this,
                                       std::move(get_bitrate_cb)),
+                  std::move(encoder_metrics_provider),
                   std::move(playout_delay_change_cb),
                   std::move(feedback_cb)) {
   DCHECK(base::FeatureList::IsEnabled(kOpenscreenCastStreamingSession));
@@ -155,6 +162,8 @@
     StatusChangeCallback status_change_cb,
     const CreateVideoEncodeAcceleratorCallback& create_vea_cb,
     std::unique_ptr<FrameSender> sender,
+    std::unique_ptr<media::MojoVideoEncoderMetricsProvider>
+        encoder_metrics_provider,
     PlayoutDelayChangeCB playout_delay_change_cb,
     media::VideoCaptureFeedbackCB feedback_callback)
     : frame_sender_(std::move(sender)),
@@ -164,6 +173,7 @@
       playout_delay_change_cb_(std::move(playout_delay_change_cb)),
       feedback_cb_(feedback_callback) {
   video_encoder_ = VideoEncoder::Create(cast_environment_, video_config,
+                                        std::move(encoder_metrics_provider),
                                         status_change_cb, create_vea_cb);
   if (!video_encoder_) {
     cast_environment_->PostTask(
diff --git a/media/cast/sender/video_sender.h b/media/cast/sender/video_sender.h
index 0db85c1a..1fb62e2a 100644
--- a/media/cast/sender/video_sender.h
+++ b/media/cast/sender/video_sender.h
@@ -23,6 +23,7 @@
 }
 
 namespace media {
+class MojoVideoEncoderMetricsProvider;
 class VideoFrame;
 }
 
@@ -50,6 +51,8 @@
               StatusChangeCallback status_change_cb,
               const CreateVideoEncodeAcceleratorCallback& create_vea_cb,
               CastTransport* const transport_sender,
+              std::unique_ptr<media::MojoVideoEncoderMetricsProvider>
+                  encoder_metrics_provider,
               PlayoutDelayChangeCB playout_delay_change_cb,
               media::VideoCaptureFeedbackCB feedback_callback);
 
@@ -61,6 +64,8 @@
               StatusChangeCallback status_change_cb,
               const CreateVideoEncodeAcceleratorCallback& create_vea_cb,
               std::unique_ptr<openscreen::cast::Sender> sender,
+              std::unique_ptr<media::MojoVideoEncoderMetricsProvider>
+                  encoder_metrics_provider,
               PlayoutDelayChangeCB playout_delay_change_cb,
               media::VideoCaptureFeedbackCB feedback_cb,
               FrameSender::GetSuggestedVideoBitrateCB get_bitrate_cb);
@@ -100,6 +105,8 @@
               StatusChangeCallback status_change_cb,
               const CreateVideoEncodeAcceleratorCallback& create_vea_cb,
               std::unique_ptr<FrameSender> sender,
+              std::unique_ptr<media::MojoVideoEncoderMetricsProvider>
+                  encoder_metrics_provider,
               PlayoutDelayChangeCB playout_delay_change_cb,
               media::VideoCaptureFeedbackCB feedback_callback);
 
diff --git a/media/cast/sender/video_sender_unittest.cc b/media/cast/sender/video_sender_unittest.cc
index d4f340e..932a9cd 100644
--- a/media/cast/sender/video_sender_unittest.cc
+++ b/media/cast/sender/video_sender_unittest.cc
@@ -30,6 +30,7 @@
 #include "media/cast/test/fake_video_encode_accelerator_factory.h"
 #include "media/cast/test/utility/default_config.h"
 #include "media/cast/test/utility/video_utility.h"
+#include "media/mojo/clients/mock_mojo_video_encoder_metrics_provider.h"
 #include "media/video/fake_video_encode_accelerator.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -110,20 +111,22 @@
 
 class PeerVideoSender : public VideoSender {
  public:
-  PeerVideoSender(
-      scoped_refptr<CastEnvironment> cast_environment,
-      const FrameSenderConfig& video_config,
-      const StatusChangeCallback& status_change_cb,
-      const CreateVideoEncodeAcceleratorCallback& create_vea_cb,
-      CastTransport* const transport_sender)
-      : VideoSender(cast_environment,
-                    video_config,
-                    status_change_cb,
-                    create_vea_cb,
-                    transport_sender,
-                    base::BindRepeating(&IgnorePlayoutDelayChanges),
-                    base::BindRepeating(&PeerVideoSender::ProcessFeedback,
-                                        base::Unretained(this))) {}
+  PeerVideoSender(scoped_refptr<CastEnvironment> cast_environment,
+                  const FrameSenderConfig& video_config,
+                  const StatusChangeCallback& status_change_cb,
+                  const CreateVideoEncodeAcceleratorCallback& create_vea_cb,
+                  CastTransport* const transport_sender)
+      : VideoSender(
+            cast_environment,
+            video_config,
+            status_change_cb,
+            create_vea_cb,
+            transport_sender,
+            std::make_unique<media::MockMojoVideoEncoderMetricsProvider>(
+                media::mojom::VideoEncoderUseCase::kCastMirroring),
+            base::BindRepeating(&IgnorePlayoutDelayChanges),
+            base::BindRepeating(&PeerVideoSender::ProcessFeedback,
+                                base::Unretained(this))) {}
 
   void OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) {
     frame_sender_for_testing()->OnReceivedCastFeedback(cast_feedback);
diff --git a/media/cast/test/cast_benchmarks.cc b/media/cast/test/cast_benchmarks.cc
index 1a57e65..a3583d0f 100644
--- a/media/cast/test/cast_benchmarks.cc
+++ b/media/cast/test/cast_benchmarks.cc
@@ -68,6 +68,7 @@
 #include "media/cast/test/utility/test_util.h"
 #include "media/cast/test/utility/udp_proxy.h"
 #include "media/cast/test/utility/video_utility.h"
+#include "media/mojo/clients/mock_mojo_video_encoder_metrics_provider.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace media {
@@ -497,9 +498,11 @@
 
   cast_sender_->InitializeAudio(audio_sender_config_,
                                 base::BindOnce(&ExpectAudioSuccess));
-  cast_sender_->InitializeVideo(video_sender_config_,
-                                base::BindRepeating(&ExpectVideoSuccess),
-                                base::DoNothing());
+  cast_sender_->InitializeVideo(
+      video_sender_config_,
+      std::make_unique<media::MockMojoVideoEncoderMetricsProvider>(
+          media::mojom::VideoEncoderUseCase::kCastMirroring),
+      base::BindRepeating(&ExpectVideoSuccess), base::DoNothing());
 
   receiver_to_sender_->Initialize(CreateSimplePipe(p),
                                   transport_sender_.PacketReceiverForTesting(),
diff --git a/media/cast/test/end2end_unittest.cc b/media/cast/test/end2end_unittest.cc
index 86c7dc97..3331c066 100644
--- a/media/cast/test/end2end_unittest.cc
+++ b/media/cast/test/end2end_unittest.cc
@@ -44,6 +44,7 @@
 #include "media/cast/test/utility/default_config.h"
 #include "media/cast/test/utility/udp_proxy.h"
 #include "media/cast/test/utility/video_utility.h"
+#include "media/mojo/clients/mock_mojo_video_encoder_metrics_provider.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace media {
@@ -918,6 +919,8 @@
       audio_sender_config_, base::BindOnce(&ExpectSuccessOperationalStatus));
   cast_sender_->InitializeVideo(
       video_sender_config_,
+      std::make_unique<media::MockMojoVideoEncoderMetricsProvider>(
+          media::mojom::VideoEncoderUseCase::kCastMirroring),
       base::BindRepeating(&ExpectSuccessOperationalStatus), base::DoNothing());
   task_runner_->RunTasks();
 
diff --git a/media/cast/test/receiver/video_decoder_unittest.cc b/media/cast/test/receiver/video_decoder_unittest.cc
index 3cd94a72..f19b5e53 100644
--- a/media/cast/test/receiver/video_decoder_unittest.cc
+++ b/media/cast/test/receiver/video_decoder_unittest.cc
@@ -21,6 +21,7 @@
 #include "media/cast/test/utility/default_config.h"
 #include "media/cast/test/utility/standalone_cast_environment.h"
 #include "media/cast/test/utility/video_utility.h"
+#include "media/mojo/clients/mock_mojo_video_encoder_metrics_provider.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/openscreen/src/cast/streaming/encoded_frame.h"
 
@@ -45,7 +46,10 @@
  public:
   VideoDecoderTest()
       : cast_environment_(new StandaloneCastEnvironment()),
-        vp8_encoder_(GetVideoSenderConfigForTest()),
+        vp8_encoder_(
+            GetVideoSenderConfigForTest(),
+            std::make_unique<media::MockMojoVideoEncoderMetricsProvider>(
+                media::mojom::VideoEncoderUseCase::kCastMirroring)),
         cond_(&lock_) {
     vp8_encoder_.Initialize();
   }
diff --git a/media/cast/test/sender.cc b/media/cast/test/sender.cc
index 24c4fa97..960a820 100644
--- a/media/cast/test/sender.cc
+++ b/media/cast/test/sender.cc
@@ -44,6 +44,7 @@
 #include "media/cast/test/fake_media_source.h"
 #include "media/cast/test/utility/default_config.h"
 #include "media/cast/test/utility/input_builder.h"
+#include "media/mojo/clients/mock_mojo_video_encoder_metrics_provider.h"
 
 namespace {
 
@@ -291,11 +292,14 @@
       media::cast::CastSender::Create(cast_environment, transport_sender.get());
   io_task_executor.task_runner()->PostTask(
       FROM_HERE,
-      base::BindOnce(&media::cast::CastSender::InitializeVideo,
-                     base::Unretained(cast_sender.get()),
-                     fake_media_source->get_video_config(),
-                     base::BindRepeating(&QuitLoopOnInitializationResult),
-                     base::DoNothing()));
+      base::BindOnce(
+          &media::cast::CastSender::InitializeVideo,
+          base::Unretained(cast_sender.get()),
+          fake_media_source->get_video_config(),
+          std::make_unique<media::MockMojoVideoEncoderMetricsProvider>(
+              media::mojom::VideoEncoderUseCase::kCastMirroring),
+          base::BindRepeating(&QuitLoopOnInitializationResult),
+          base::DoNothing()));
   base::RunLoop().Run();  // Wait for video initialization.
   io_task_executor.task_runner()->PostTask(
       FROM_HERE,
diff --git a/media/cast/test/simulator.cc b/media/cast/test/simulator.cc
index 2177d0b..2b622c4 100644
--- a/media/cast/test/simulator.cc
+++ b/media/cast/test/simulator.cc
@@ -91,6 +91,7 @@
 #include "media/cast/test/utility/test_util.h"
 #include "media/cast/test/utility/udp_proxy.h"
 #include "media/cast/test/utility/video_utility.h"
+#include "media/mojo/clients/mock_mojo_video_encoder_metrics_provider.h"
 
 using media::cast::proto::IPPModel;
 using media::cast::proto::NetworkSimulationModel;
@@ -432,9 +433,11 @@
   // Initializing audio and video senders.
   cast_sender->InitializeAudio(audio_sender_config,
                                base::BindOnce(&LogAudioOperationalStatus));
-  cast_sender->InitializeVideo(media_source.get_video_config(),
-                               base::BindRepeating(&LogVideoOperationalStatus),
-                               base::DoNothing());
+  cast_sender->InitializeVideo(
+      media_source.get_video_config(),
+      std::make_unique<media::MockMojoVideoEncoderMetricsProvider>(
+          media::mojom::VideoEncoderUseCase::kCastMirroring),
+      base::BindRepeating(&LogVideoOperationalStatus), base::DoNothing());
   task_runner->RunTasks();
 
   // Truncate YUV files to prepare for writing.
diff --git a/media/mojo/clients/BUILD.gn b/media/mojo/clients/BUILD.gn
index b0f140074..47618d1 100644
--- a/media/mojo/clients/BUILD.gn
+++ b/media/mojo/clients/BUILD.gn
@@ -11,6 +11,10 @@
     "//components/mirroring/service:mirroring_service",
     "//content/renderer:*",
 
+    # MojoVideoEncoderMetricsProvider is used in encoders in mirroring service.
+    "//media/cast:encoding",
+    "//media/cast:sender",
+
     # TODO(xhwang): Only allow //media/mojo/services:unit_tests
     "//chrome/browser:*",
     "//chrome/browser/thumbnail/generator",
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc
index 85d14f5..46a953b 100644
--- a/net/http/http_cache.cc
+++ b/net/http/http_cache.cc
@@ -69,8 +69,6 @@
 const char HttpCache::kDoubleKeyPrefix[] = "_dk_";
 const char HttpCache::kDoubleKeySeparator[] = " ";
 const char HttpCache::kSubframeDocumentResourcePrefix[] = "s_";
-const char HttpCache::kSingleKeyPrefix[] = "_sk_";
-const char HttpCache::kSingleKeySeparator[] = " ";
 
 HttpCache::DefaultBackend::DefaultBackend(
     CacheType type,
@@ -366,8 +364,7 @@
       request_info.load_flags |= ~LOAD_DO_NOT_SAVE_COOKIES;
   }
 
-  std::string key = *GenerateCacheKeyForRequest(
-      &request_info, /*use_single_keyed_cache=*/false);
+  std::string key = *GenerateCacheKeyForRequest(&request_info);
   disk_cache_->OnExternalCacheHit(key);
 }
 
@@ -439,11 +436,6 @@
     DCHECK_NE(pos, std::string::npos);
     pos += strlen(kDoubleKeySeparator);
     DCHECK_LE(pos, key.size() - 1);
-  } else if (pos == key.find(kSingleKeyPrefix, pos)) {
-    pos = key.rfind(kSingleKeySeparator);
-    DCHECK_NE(pos, std::string::npos);
-    pos += strlen(kSingleKeySeparator);
-    DCHECK_LE(pos, key.size() - 1);
   }
   return key.substr(pos);
 }
@@ -455,32 +447,18 @@
     int load_flags,
     const NetworkIsolationKey& network_isolation_key,
     int64_t upload_data_identifier,
-    bool is_subframe_document_resource,
-    bool use_single_keyed_cache,
-    const std::string& single_key_checksum) {
+    bool is_subframe_document_resource) {
   // The first character of the key may vary depending on whether or not sending
   // credentials is permitted for this request. This only happens if the
-  // SplitCacheByIncludeCredentials feature is enabled, or if the single-keyed
-  // cache is enabled. The single-keyed cache must always be split by
-  // credentials in order to make coep:credentialless work safely.
-  const char credential_key =
-      ((base::FeatureList::IsEnabled(
-            features::kSplitCacheByIncludeCredentials) ||
-        use_single_keyed_cache) &&
-       (load_flags & LOAD_DO_NOT_SAVE_COOKIES))
-          ? '0'
-          : '1';
+  // SplitCacheByIncludeCredentials feature is enabled.
+  const char credential_key = (base::FeatureList::IsEnabled(
+                                   features::kSplitCacheByIncludeCredentials) &&
+                               (load_flags & LOAD_DO_NOT_SAVE_COOKIES))
+                                  ? '0'
+                                  : '1';
 
   std::string isolation_key;
-  if (use_single_keyed_cache) {
-    DCHECK(IsSplitCacheEnabled());
-    DCHECK(!(load_flags &
-             (net::LOAD_VALIDATE_CACHE | net::LOAD_BYPASS_CACHE |
-              net::LOAD_SKIP_CACHE_VALIDATION | net::LOAD_ONLY_FROM_CACHE |
-              net::LOAD_DISABLE_CACHE | net::LOAD_SKIP_VARY_CHECK)));
-    isolation_key = base::StrCat(
-        {kSingleKeyPrefix, single_key_checksum, kSingleKeySeparator});
-  } else if (IsSplitCacheEnabled()) {
+  if (IsSplitCacheEnabled()) {
     // Prepend the key with |kDoubleKeyPrefix| = "_dk_" to mark it as
     // double-keyed (and makes it an invalid url so that it doesn't get
     // confused with a single-keyed entry). Separate the origin and url
@@ -507,16 +485,14 @@
 
 // static
 absl::optional<std::string> HttpCache::GenerateCacheKeyForRequest(
-    const HttpRequestInfo* request,
-    bool use_single_keyed_cache) {
+    const HttpRequestInfo* request) {
   DCHECK(request);
   const int64_t upload_data_identifier =
       request->upload_data_stream ? request->upload_data_stream->identifier()
                                   : int64_t(0);
   return GenerateCacheKey(
       request->url, request->load_flags, request->network_isolation_key,
-      upload_data_identifier, request->is_subframe_document_resource,
-      use_single_keyed_cache, request->checksum);
+      upload_data_identifier, request->is_subframe_document_resource);
 }
 
 // static
@@ -694,11 +670,7 @@
       net::NetworkAnonymizationKey::CreateFromNetworkIsolationKey(
           isolation_key);
   temp_info.is_subframe_document_resource = is_subframe_document_resource;
-  // This method is always used for "POST" requests, which never use the
-  // single-keyed cache, so therefore it is correct that use_single_keyed_cache
-  // be false.
-  std::string key =
-      *GenerateCacheKeyForRequest(&temp_info, /*use_single_keyed_cache=*/false);
+  std::string key = *GenerateCacheKeyForRequest(&temp_info);
 
   // Defer to DoomEntry if there is an active entry, otherwise call
   // AsyncDoomEntry without triggering a callback.
diff --git a/net/http/http_cache.h b/net/http/http_cache.h
index 8f4225d..96b41a8 100644
--- a/net/http/http_cache.h
+++ b/net/http/http_cache.h
@@ -265,12 +265,9 @@
       int load_flags,
       const NetworkIsolationKey& network_isolation_key,
       int64_t upload_data_identifier,
-      bool is_subframe_document_resource,
-      bool use_single_keyed_cache,
-      const std::string& single_key_checksum);
+      bool is_subframe_document_resource);
   static absl::optional<std::string> GenerateCacheKeyForRequest(
-      const HttpRequestInfo* request,
-      bool use_single_keyed_cache = false);
+      const HttpRequestInfo* request);
 
   // Enable split cache feature if not already overridden in the feature list.
   // Should only be invoked during process initialization before the HTTP
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index 471400a..cb90d19 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -28,15 +28,12 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/power_monitor/power_monitor.h"
-#include "base/strings/string_number_conversions.h"  // For HexEncode.
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"  // For EqualsCaseInsensitiveASCII.
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/clock.h"
 #include "base/trace_event/common/trace_event_common.h"
 #include "base/values.h"
-#include "crypto/secure_hash.h"
-#include "crypto/sha2.h"
 #include "net/base/auth.h"
 #include "net/base/cache_metrics.h"
 #include "net/base/features.h"
@@ -107,12 +104,6 @@
   kMaxValue = kReused
 };
 
-void RecordPervasivePayloadIndex(const char* histogram_name, int index) {
-  if (index != -1) {
-    base::UmaHistogramCustomCounts(histogram_name, index, 1, 323, 323);
-  }
-}
-
 bool ShouldByPassCacheForFirstPartySets(
     const absl::optional<int64_t>& clear_at_run_id,
     const absl::optional<int64_t>& written_at_run_id) {
@@ -687,26 +678,6 @@
   }
 }
 
-bool HttpCache::Transaction::ResponseChecksumMatches(
-    std::unique_ptr<crypto::SecureHash> checksum) const {
-  DCHECK(checksum);
-  uint8_t result[crypto::kSHA256Length];
-  checksum->Finish(result, crypto::kSHA256Length);
-  const std::string hex_result = base::HexEncode(result);
-  if (hex_result != request_->checksum) {
-    DVLOG(2) << "Pervasive payload checksum mismatch for \"" << request_->url
-             << "\": got " << hex_result << ", expected " << request_->checksum;
-    RecordPervasivePayloadIndex(
-        "Network.CacheTransparency2.MismatchedChecksums",
-        request_->pervasive_payloads_index_for_logging);
-    return false;
-  }
-  RecordPervasivePayloadIndex(
-      "Network.CacheTransparency2.SingleKeyedCacheIsUsed",
-      request_->pervasive_payloads_index_for_logging);
-  return true;
-}
-
 void HttpCache::Transaction::AddDiskCacheWriteTime(base::TimeDelta elapsed) {
   total_disk_cache_write_time_ += elapsed;
 }
@@ -1025,13 +996,6 @@
       case STATE_NETWORK_READ_COMPLETE:
         rv = DoNetworkReadComplete(rv);
         break;
-      case STATE_MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE:
-        DCHECK_EQ(0, rv);  // Here "rv" is a count of bytes.
-        rv = DoMarkSingleKeyedCacheEntryUnusable();
-        break;
-      case STATE_MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE_COMPLETE:
-        rv = DoMarkSingleKeyedCacheEntryUnusableComplete(rv);
-        break;
       default:
         NOTREACHED() << "bad state " << state;
         rv = ERR_FAILED;
@@ -1073,12 +1037,7 @@
   const bool should_pass_through = ShouldPassThrough();
 
   if (!should_pass_through) {
-    // The flag `use_single_keyed_cache_` will have been changed back to false
-    // if the entry was marked unusable and the transaction was restarted in
-    // DoCacheReadResponseComplete(), even though `request_` will still have a
-    // checksum. So it needs to be passed explicitly.
-    cache_key_ =
-        *cache_->GenerateCacheKeyForRequest(request_, use_single_keyed_cache_);
+    cache_key_ = *cache_->GenerateCacheKeyForRequest(request_);
 
     // Requested cache access mode.
     if (effective_load_flags_ & LOAD_ONLY_FROM_CACHE) {
@@ -1626,25 +1585,6 @@
     return OnCacheReadError(result, true);
   }
 
-  if (response_.single_keyed_cache_entry_unusable) {
-    RecordPervasivePayloadIndex("Network.CacheTransparency2.MarkedUnusable",
-                                request_->pervasive_payloads_index_for_logging);
-
-    // We've read the single keyed entry and it turned out to be unusable. Let's
-    // retry reading from the split cache.
-    if (use_single_keyed_cache_) {
-      DCHECK(!network_trans_);
-      use_single_keyed_cache_ = false;
-      DoneWithEntryForRestartWithCache();
-      TransitionToState(STATE_GET_BACKEND);
-      return OK;
-    } else {
-      LOG(WARNING) << "Unusable flag set on non-single-keyed cache entry; "
-                   << "possible disk corruption? (cache key: " << cache_key_
-                   << ")";
-    }
-  }
-
   // TODO(crbug.com/713354) Only get data size if there is no other transaction
   // currently writing the response body due to the data race mentioned in the
   // associated bug.
@@ -1993,17 +1933,6 @@
     return ERR_CACHE_AUTH_FAILURE_AFTER_READ;
   }
 
-  // The single-keyed cache only accepts responses with code 200 or 304.
-  // Anything else is considered unusable.
-  if (use_single_keyed_cache_ &&
-      !(new_response->headers->response_code() == 200 ||
-        new_response->headers->response_code() == 304)) {
-    // Either the new response will be written back to the cache, in which case
-    // it will not be reused due to the flag, or it will not be, in which case
-    // it will not be reused anyway.
-    mark_single_keyed_cache_entry_unusable_ = true;
-  }
-
   new_response_ = new_response;
   if (!ValidatePartialResponse() && !auth_response_.headers.get()) {
     // Something went wrong with this request and we have to restart it.
@@ -2096,12 +2025,6 @@
   response_.ssl_info = new_response_->ssl_info;
   response_.dns_aliases = new_response_->dns_aliases;
 
-  // Be careful never to set single_keyed_cache_entry_unusable back to false
-  // from true.
-  if (mark_single_keyed_cache_entry_unusable_) {
-    response_.single_keyed_cache_entry_unusable = true;
-  }
-
   // If the new response didn't have a vary header, we continue to use the
   // header from the stored response per the effect of headers->Update().
   // Update the data with the new/updated request headers.
@@ -2114,11 +2037,6 @@
     }
     TransitionToState(STATE_UPDATE_CACHED_RESPONSE_COMPLETE);
   } else {
-    if (use_single_keyed_cache_) {
-      DCHECK_EQ(method_, "GET");
-      ChecksumHeaders();
-    }
-
     // If we are already reading, we already updated the headers for this
     // request; doing it again will change Content-Length.
     if (!reading_) {
@@ -2200,11 +2118,6 @@
 
   SetResponse(*new_response_);
 
-  if (use_single_keyed_cache_) {
-    DCHECK_EQ(method_, "GET");
-    ChecksumHeaders();
-  }
-
   if (method_ == "HEAD") {
     // This response is replacing the cached one.
     DoneWithEntry(false);
@@ -2254,12 +2167,6 @@
     return OK;
   }
 
-  // Be careful never to set single_keyed_cache_entry_unusable back to false
-  // from true.
-  if (mark_single_keyed_cache_entry_unusable_) {
-    response_.single_keyed_cache_entry_unusable = true;
-  }
-
   TransitionToState(STATE_CACHE_WRITE_RESPONSE_COMPLETE);
   return WriteResponseInfoToEntry(response_, truncated_);
 }
@@ -2385,8 +2292,7 @@
   }
 
   if (network_trans_ && InWriters()) {
-    entry_->writers->SetNetworkTransaction(this, std::move(network_trans_),
-                                           std::move(checksum_));
+    entry_->writers->SetNetworkTransaction(this, std::move(network_trans_));
     moved_network_transaction_to_writers_ = true;
   }
 
@@ -2441,8 +2347,6 @@
     DCHECK(!entry_);
   } else {
     read_offset_ += result;
-    if (checksum_)
-      checksum_->Update(read_buf_->data(), result);
   }
   TransitionToState(STATE_NONE);
   return result;
@@ -2560,14 +2464,7 @@
 
   if (result > 0) {
     read_offset_ += result;
-    if (checksum_)
-      checksum_->Update(read_buf_->data(), result);
   } else if (result == 0) {  // End of file.
-    if (!FinishAndCheckChecksum()) {
-      TransitionToState(STATE_MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE);
-      return result;
-    }
-
     DoneWithEntry(true);
   } else {
     return OnCacheReadError(result, false);
@@ -2577,25 +2474,6 @@
   return result;
 }
 
-int HttpCache::Transaction::DoMarkSingleKeyedCacheEntryUnusable() {
-  DCHECK(use_single_keyed_cache_);
-  response_.single_keyed_cache_entry_unusable = true;
-  TransitionToState(STATE_MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE_COMPLETE);
-  return WriteResponseInfoToEntry(response_, /*truncated=*/false);
-}
-
-int HttpCache::Transaction::DoMarkSingleKeyedCacheEntryUnusableComplete(
-    int result) {
-  DCHECK_NE(result, ERR_IO_PENDING);
-  TransitionToState(STATE_NONE);
-  DoneWithEntry(/*entry_is_complete=*/true);
-  if (result < 0)
-    return result;
-
-  // Return 0 to indicate that we've finished reading the body.
-  return 0;
-}
-
 //-----------------------------------------------------------------------------
 
 void HttpCache::Transaction::SetRequest(const NetLogWithSource& net_log) {
@@ -2614,9 +2492,6 @@
   effective_load_flags_ = request_->load_flags;
   method_ = request_->method;
 
-  if (!request_->checksum.empty())
-    use_single_keyed_cache_ = true;
-
   if (cache_->mode() == DISABLE)
     effective_load_flags_ |= LOAD_DISABLE_CACHE;
 
@@ -3636,16 +3511,6 @@
   mode_ = NONE;  // switch to 'pass through' mode
 }
 
-void HttpCache::Transaction::DoneWithEntryForRestartWithCache() {
-  if (!entry_)
-    return;
-
-  cache_->DoneWithEntry(entry_, this, /*entry_is_complete=*/true,
-                        partial_ != nullptr);
-  entry_ = nullptr;
-  new_entry_ = nullptr;
-}
-
 int HttpCache::Transaction::OnCacheReadError(int result, bool restart) {
   DLOG(ERROR) << "ReadData failed: " << result;
 
@@ -4140,73 +4005,6 @@
   return;
 }
 
-void HttpCache::Transaction::ChecksumHeaders() {
-  DCHECK(use_single_keyed_cache_);
-  DCHECK(!checksum_);
-  checksum_ = crypto::SecureHash::Create(crypto::SecureHash::SHA256);
-  // For efficiency and concision, we list known headers matching a wildcard
-  // explicitly rather than doing prefix matching.
-  constexpr auto kHeadersToInclude = base::MakeFixedFlatSet<base::StringPiece>({
-      "access-control-allow-credentials",
-      "access-control-allow-headers",
-      "access-control-allow-methods",
-      "access-control-allow-origin",
-      "access-control-expose-headers",
-      "access-control-max-age",
-      "access-control-request-headers",
-      "access-control-request-method",
-      "clear-site-data",
-      "content-encoding",
-      "content-security-policy",
-      "content-type",
-      "cross-origin-embedder-policy",
-      "cross-origin-opener-policy",
-      "cross-origin-resource-policy",
-      "location",
-      "sec-websocket-accept",
-      "sec-websocket-extensions",
-      "sec-websocket-key",
-      "sec-websocket-protocol",
-      "sec-websocket-version",
-      "upgrade",
-      "vary",
-  });
-  // Pairs of (lower_case_header_name, header_value).
-  std::vector<std::pair<std::string, std::string>> filtered_headers;
-  // It's good to set the initial allocation size of the vector to the
-  // expected size to avoid a lot of reallocations. This value was chosen as
-  // it is a nice round number.
-  filtered_headers.reserve(16);
-  {
-    // Iterate the response headers looking for matches.
-    size_t iter = 0;
-    std::string name;
-    std::string value;
-    while (response_.headers->EnumerateHeaderLines(&iter, &name, &value)) {
-      std::string lowered_name = base::ToLowerASCII(name);
-      if (kHeadersToInclude.contains(lowered_name)) {
-        filtered_headers.emplace_back(lowered_name, value);
-      }
-    }
-  }
-  std::sort(filtered_headers.begin(), filtered_headers.end());
-  for (const auto& [name, value] : filtered_headers) {
-    checksum_->Update(name.data(), name.size());
-    checksum_->Update(": ", 2);
-    checksum_->Update(value.data(), value.size());
-    checksum_->Update("\n", 1);
-  }
-  checksum_->Update("\n", 1);
-}
-
-bool HttpCache::Transaction::FinishAndCheckChecksum() {
-  if (!checksum_)
-    return true;
-
-  DCHECK(use_single_keyed_cache_);
-  return ResponseChecksumMatches(std::move(checksum_));
-}
-
 void HttpCache::Transaction::BeginDiskCacheAccessTimeCount() {
   DCHECK(last_disk_cache_access_start_time_.is_null());
   if (partial_) {
diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h
index 0f0b39d..998afa9 100644
--- a/net/http/http_cache_transaction.h
+++ b/net/http/http_cache_transaction.h
@@ -38,10 +38,6 @@
 #include "net/socket/connection_attempts.h"
 #include "net/websockets/websocket_handshake_stream_base.h"
 
-namespace crypto {
-class SecureHash;
-}  // namespace crypto
-
 namespace net {
 
 class PartialData;
@@ -199,11 +195,6 @@
   // entry has finished writing.
   void WriteModeTransactionAboutToBecomeReader();
 
-  // True if the passed checksum calculated from the response matches the
-  // expected value from the HttpRequestInfo. Consumes `checksum`.
-  bool ResponseChecksumMatches(
-      std::unique_ptr<crypto::SecureHash> checksum) const;
-
   // Add time spent writing data in the disk cache. Used for histograms.
   void AddDiskCacheWriteTime(base::TimeDelta elapsed);
 
@@ -300,11 +291,6 @@
     // by the network layer (skipping the cache entirely).
     STATE_NETWORK_READ,
     STATE_NETWORK_READ_COMPLETE,
-
-    // These states are only entered a single-keyed cache entry needs to be
-    // marked unusable.
-    STATE_MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE,
-    STATE_MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE_COMPLETE,
   };
 
   // Used for categorizing validation triggers in histograms.
@@ -383,8 +369,6 @@
   int DoCacheReadDataComplete(int result);
   int DoNetworkRead();
   int DoNetworkReadComplete(int result);
-  int DoMarkSingleKeyedCacheEntryUnusable();
-  int DoMarkSingleKeyedCacheEntryUnusableComplete(int result);
 
   // Adds time out handling while waiting to be added to entry or after headers
   // phase is complete.
@@ -503,10 +487,6 @@
   // resumed or not.
   void DoneWithEntry(bool entry_is_complete);
 
-  // Informs the HttpCache that this transaction is done with the entry and
-  // resets related fields.
-  void DoneWithEntryForRestartWithCache();
-
   // Dooms the given entry so that it will not be re-used for other requests,
   // then calls `DoneWithEntry()`.
   //
@@ -609,15 +589,6 @@
   // headers.
   bool ShouldDisableCaching(const HttpResponseHeaders& headers) const;
 
-  // Checksum headers in `request_` for matching against the single-keyed cache
-  // checksum. Initializes `checksum_`.
-  void ChecksumHeaders();
-
-  // Finishes the checksum and validates that it matches the expected value.
-  // Returns true if the checksum matches. Returns false if it does not
-  // match. If no checksumming is taking place then returns true.
-  bool FinishAndCheckChecksum();
-
   // 304 revalidations of resources that set security headers and that get
   // forwarded might need to set these headers again to avoid being blocked.
   void UpdateSecurityHeadersBeforeForwarding();
@@ -704,10 +675,6 @@
                                                      // cache lock.
   bool fail_conditionalization_for_test_ =
       false;  // Fail ConditionalizeRequest.
-  bool mark_single_keyed_cache_entry_unusable_ =
-      false;  // Set single_keyed_cache_entry_unusable.
-  // This is initialised in Start().
-  bool use_single_keyed_cache_ = false;
 
   scoped_refptr<IOBuffer> read_buf_;
 
@@ -764,11 +731,6 @@
   raw_ptr<WebSocketHandshakeStreamBase::CreateHelper>
       websocket_handshake_stream_base_create_helper_ = nullptr;
 
-  // Set if we are currently calculating a checksum of the resource to validate
-  // it against the expected checksum for the single-keyed cache. Accumulates a
-  // hash of selected headers and the body of the response.
-  std::unique_ptr<crypto::SecureHash> checksum_;
-
   BeforeNetworkStartCallback before_network_start_callback_;
   ConnectedCallback connected_callback_;
   RequestHeadersCallback request_headers_callback_;
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index 0a8ab28..e5ef070 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -14180,459 +14180,5 @@
   EXPECT_EQ(304, response.headers->response_code());
   EXPECT_EQ("cross-origin", response_corp_header);
 }
-class CacheTransparencyHttpCacheTest
-    : public HttpCacheTest_SplitCacheFeatureEnabled {
- public:
-  CacheTransparencyHttpCacheTest() {
-    // The single-keyed cache feature is meaningless when the split cache is not
-    // enabled. The //net layer doesn't care whether or not the
-    // "CacheTransparency" feature is enabled.
-    CHECK(base::FeatureList::IsEnabled(
-        net::features::kSplitCacheByNetworkIsolationKey));
-  }
-
-  void RunTransactionTestForSingleKeyedCache(
-      HttpCache* cache,
-      const MockTransaction& trans_info,
-      const NetworkIsolationKey& network_isolation_key,
-      const std::string& checksum) {
-    ScopedMockTransaction transaction(trans_info);
-
-    MockHttpRequest request(transaction);
-    request.network_isolation_key = network_isolation_key;
-    request.network_anonymization_key =
-        net::NetworkAnonymizationKey::CreateFromNetworkIsolationKey(
-            network_isolation_key);
-    request.checksum = checksum;
-
-    HttpResponseInfo response_info;
-    RunTransactionTestWithRequest(cache, transaction, request, &response_info);
-  }
-
-  void RunSimpleTransactionTestForSingleKeyedCache(
-      HttpCache* cache,
-      const NetworkIsolationKey& network_isolation_key,
-      const std::string& checksum) {
-    RunTransactionTestForSingleKeyedCache(cache, kSimpleGET_Transaction,
-                                          network_isolation_key, checksum);
-  }
-};
-
-INSTANTIATE_TEST_SUITE_P(
-    All,
-    CacheTransparencyHttpCacheTest,
-    testing::ValuesIn({SplitCacheTestCase::kSplitCacheNikFrameSiteEnabled,
-                       SplitCacheTestCase::kSplitCacheNikCrossSiteFlagEnabled}),
-    [](const testing::TestParamInfo<SplitCacheTestCase>& info) {
-      switch (info.param) {
-        case (SplitCacheTestCase::kSplitCacheDisabled):
-          return "NotUsedForThisTestSuite";
-        case (SplitCacheTestCase::kSplitCacheNikFrameSiteEnabled):
-          return "SplitCacheNikFrameSiteEnabled";
-        case (SplitCacheTestCase::kSplitCacheNikCrossSiteFlagEnabled):
-          return "SplitCacheNikCrossSiteFlagEnabled";
-      }
-    });
-
-constexpr char kChecksumForSimpleGET[] =
-    "80B4C37CEF5CFE69B4A90830282AA2BB772DC4CBC00491A219CE5F2AD75C7B58";
-
-TEST_P(CacheTransparencyHttpCacheTest, SuccessfulGET) {
-  MockHttpCache cache;
-  // The first request adds the item to the cache.
-  {
-    const auto site_a = SchemefulSite(GURL("https://a.com/"));
-    RunSimpleTransactionTestForSingleKeyedCache(
-        cache.http_cache(), NetworkIsolationKey(site_a, site_a),
-        kChecksumForSimpleGET);
-
-    EXPECT_EQ(1, cache.network_layer()->transaction_count());
-    EXPECT_EQ(0, cache.disk_cache()->open_count());
-    EXPECT_EQ(1, cache.disk_cache()->create_count());
-  }
-
-  // The second request verifies that the same cache entry is used with a
-  // different NetworkIsolationKey
-  {
-    const auto site_b = SchemefulSite(GURL("https://b.com/"));
-    RunSimpleTransactionTestForSingleKeyedCache(
-        cache.http_cache(), NetworkIsolationKey(site_b, site_b),
-        kChecksumForSimpleGET);
-
-    EXPECT_EQ(1, cache.network_layer()->transaction_count());
-    EXPECT_EQ(1, cache.disk_cache()->open_count());
-    EXPECT_EQ(1, cache.disk_cache()->create_count());
-  }
-}
-
-TEST_P(CacheTransparencyHttpCacheTest, GETWithChecksumMismatch) {
-  MockHttpCache cache;
-  const auto site_a = SchemefulSite(GURL("https://a.com/"));
-  // The first request adds the item to the cache.
-  {
-    RunSimpleTransactionTestForSingleKeyedCache(
-        cache.http_cache(), NetworkIsolationKey(site_a, site_a),
-        "000000000000000000000000000000000000000000000000000000000000000");
-
-    EXPECT_EQ(1, cache.network_layer()->transaction_count());
-    EXPECT_EQ(0, cache.disk_cache()->open_count());
-    EXPECT_EQ(1, cache.disk_cache()->create_count());
-  }
-
-  // The second request doesn't use the item that was added to the single-keyed
-  // cache, but adds it to the split cache instead.
-  {
-    RunSimpleTransactionTestForSingleKeyedCache(
-        cache.http_cache(), NetworkIsolationKey(site_a, site_a),
-        "000000000000000000000000000000000000000000000000000000000000000");
-
-    // Fetches from the network again, this time into the split cache.
-    EXPECT_EQ(2, cache.network_layer()->transaction_count());
-    EXPECT_EQ(1, cache.disk_cache()->open_count());
-    EXPECT_EQ(2, cache.disk_cache()->create_count());
-  }
-
-  // The third request uses the split cache.
-  {
-    RunSimpleTransactionTestForSingleKeyedCache(
-        cache.http_cache(), NetworkIsolationKey(site_a, site_a),
-        "000000000000000000000000000000000000000000000000000000000000000");
-
-    // Fetches from the split cache.
-    EXPECT_EQ(2, cache.network_layer()->transaction_count());
-    EXPECT_EQ(3, cache.disk_cache()->open_count());  // opens both cache entries
-    EXPECT_EQ(2, cache.disk_cache()->create_count());
-  }
-}
-
-TEST_P(CacheTransparencyHttpCacheTest, GETWithBadResponseCode) {
-  MockHttpCache cache;
-  MockTransaction transaction = kSimpleGET_Transaction;
-  transaction.status = "HTTP/1.1 404 Not Found";
-  const auto site_a = SchemefulSite(GURL("https://a.com/"));
-  // The first request adds the item to the single-keyed cache.
-  {
-    RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
-                                          NetworkIsolationKey(site_a, site_a),
-                                          kChecksumForSimpleGET);
-
-    EXPECT_EQ(1, cache.network_layer()->transaction_count());
-    EXPECT_EQ(0, cache.disk_cache()->open_count());
-    EXPECT_EQ(1, cache.disk_cache()->create_count());
-  }
-
-  // The second request verifies that the cache entry is not re-used
-  // but a new one is created in the split cache.
-  {
-    RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
-                                          NetworkIsolationKey(site_a, site_a),
-                                          kChecksumForSimpleGET);
-
-    EXPECT_EQ(2, cache.network_layer()->transaction_count());
-    EXPECT_EQ(1, cache.disk_cache()->open_count());
-    EXPECT_EQ(2, cache.disk_cache()->create_count());
-  }
-}
-
-// This is identical to GETWithBadResponseCode but with a different response
-// code. It's not very realistic as it doesn't call DoneReading(), but it covers
-// the relevant code path.
-TEST_P(CacheTransparencyHttpCacheTest, RedirectUnusable) {
-  MockHttpCache cache;
-  MockTransaction transaction = kSimpleGET_Transaction;
-  transaction.status = "HTTP/1.1 301 Moved Permanently";
-  const auto site_a = SchemefulSite(GURL("https://a.com/"));
-  // The first request adds the item to the single-keyed cache.
-  {
-    RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
-                                          NetworkIsolationKey(site_a, site_a),
-                                          kChecksumForSimpleGET);
-
-    EXPECT_EQ(1, cache.network_layer()->transaction_count());
-    EXPECT_EQ(0, cache.disk_cache()->open_count());
-    EXPECT_EQ(1, cache.disk_cache()->create_count());
-  }
-
-  // The second request verifies that the cache entry is not re-used
-  // but a new one is created in the split cache.
-  {
-    RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
-                                          NetworkIsolationKey(site_a, site_a),
-                                          kChecksumForSimpleGET);
-
-    EXPECT_EQ(2, cache.network_layer()->transaction_count());
-    EXPECT_EQ(1, cache.disk_cache()->open_count());
-    EXPECT_EQ(2, cache.disk_cache()->create_count());
-  }
-}
-
-TEST_P(CacheTransparencyHttpCacheTest, GETWith206ResponseCode) {
-  MockHttpCache cache;
-  MockTransaction transaction = kSimpleGET_Transaction;
-  // We should never get a partial response since we never send a range request,
-  // but it behaves differently from other bad response codes.
-  transaction.status = "HTTP/1.1 206 Partial";
-  const auto site_a = SchemefulSite(GURL("https://a.com/"));
-  // The response is not cached.
-  {
-    RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
-                                          NetworkIsolationKey(site_a, site_a),
-                                          kChecksumForSimpleGET);
-
-    EXPECT_EQ(1, cache.network_layer()->transaction_count());
-    EXPECT_EQ(0, cache.disk_cache()->open_count());
-    EXPECT_EQ(1, cache.disk_cache()->create_count());
-  }
-
-  // It is fetched from the network again.
-  {
-    RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
-                                          NetworkIsolationKey(site_a, site_a),
-                                          kChecksumForSimpleGET);
-
-    EXPECT_EQ(2, cache.network_layer()->transaction_count());
-    EXPECT_EQ(0, cache.disk_cache()->open_count());
-    EXPECT_EQ(2, cache.disk_cache()->create_count());
-  }
-}
-
-TEST_P(CacheTransparencyHttpCacheTest, SuccessfulRevalidation) {
-  MockHttpCache cache;
-  MockTransaction transaction = kSimpleGET_Transaction;
-  // Add a cache control header to permit the entry to be cached, with max-age 0
-  // to force relatidation next time. Add Etag to permit it to be revalidated.
-  transaction.response_headers =
-      "Etag: \"foo\"\n"
-      "Cache-Control: max-age=0\n";
-  {
-    const auto site_a = SchemefulSite(GURL("https://a.com/"));
-    RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
-                                          NetworkIsolationKey(site_a, site_a),
-                                          kChecksumForSimpleGET);
-
-    EXPECT_EQ(1, cache.network_layer()->transaction_count());
-    EXPECT_EQ(0, cache.disk_cache()->open_count());
-    EXPECT_EQ(1, cache.disk_cache()->create_count());
-  }
-
-  // The second request revalidates the existing entry.
-  {
-    const auto site_b = SchemefulSite(GURL("https://b.com/"));
-    transaction.status = "HTTP/1.1 304 Not Modified";
-    // Allow it to be reused without validation next time by increasing max-age.
-    transaction.response_headers =
-        "Etag: \"foo\"\n"
-        "Cache-Control: max-age=10000\n";
-    RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
-                                          NetworkIsolationKey(site_b, site_b),
-                                          kChecksumForSimpleGET);
-
-    EXPECT_EQ(2, cache.network_layer()->transaction_count());
-    EXPECT_EQ(1, cache.disk_cache()->open_count());
-    EXPECT_EQ(1, cache.disk_cache()->create_count());
-  }
-
-  // The third request re-uses the entry.
-  {
-    const auto site_c = SchemefulSite(GURL("https://c.com/"));
-    // Load from cache again.
-    RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
-                                          NetworkIsolationKey(site_c, site_c),
-                                          kChecksumForSimpleGET);
-
-    EXPECT_EQ(2, cache.network_layer()->transaction_count());
-    EXPECT_EQ(1, cache.disk_cache()->open_count());
-    EXPECT_EQ(1, cache.disk_cache()->create_count());
-  }
-}
-
-TEST_P(CacheTransparencyHttpCacheTest, RevalidationChangingUncheckedHeader) {
-  MockHttpCache cache;
-  MockTransaction transaction = kSimpleGET_Transaction;
-  // Add a cache control header to permit the entry to be cached, with max-age 0
-  // to force relatidation next time. Add Etag to permit it to be revalidated.
-  transaction.response_headers =
-      "Etag: \"foo\"\n"
-      "Cache-Control: max-age=0\n";
-  {
-    const auto site_a = SchemefulSite(GURL("https://a.com/"));
-    RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
-                                          NetworkIsolationKey(site_a, site_a),
-                                          kChecksumForSimpleGET);
-
-    EXPECT_EQ(1, cache.network_layer()->transaction_count());
-    EXPECT_EQ(0, cache.disk_cache()->open_count());
-    EXPECT_EQ(1, cache.disk_cache()->create_count());
-  }
-
-  // The second request revalidates the existing entry.
-  {
-    const auto site_b = SchemefulSite(GURL("https://b.com/"));
-    transaction.status = "HTTP/1.1 304 Not Modified";
-    // Add a response header. This is the only difference from the
-    // SuccessfulRevalidation test.
-    transaction.response_headers =
-        "Etag: \"foo\"\n"
-        "Cache-Control: max-age=10000\n"
-        "X-Unchecked-Header: 1\n";
-    RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
-                                          NetworkIsolationKey(site_b, site_b),
-                                          kChecksumForSimpleGET);
-
-    EXPECT_EQ(2, cache.network_layer()->transaction_count());
-    EXPECT_EQ(1, cache.disk_cache()->open_count());
-    EXPECT_EQ(1, cache.disk_cache()->create_count());
-  }
-
-  // The third request re-uses the entry.
-  {
-    const auto site_c = SchemefulSite(GURL("https://c.com/"));
-    // Load from cache again.
-    RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
-                                          NetworkIsolationKey(site_c, site_c),
-                                          kChecksumForSimpleGET);
-
-    EXPECT_EQ(2, cache.network_layer()->transaction_count());
-    EXPECT_EQ(1, cache.disk_cache()->open_count());
-    EXPECT_EQ(1, cache.disk_cache()->create_count());
-  }
-}
-
-TEST_P(CacheTransparencyHttpCacheTest, RevalidationChangingCheckedHeader) {
-  MockHttpCache cache;
-  MockTransaction transaction = kSimpleGET_Transaction;
-  // Add a cache control header to permit the entry to be cached, with max-age 0
-  // to force relatidation next time. Add Etag to permit it to be revalidated.
-  transaction.response_headers =
-      "Etag: \"foo\"\n"
-      "Cache-Control: max-age=0\n";
-  {
-    const auto site_a = SchemefulSite(GURL("https://a.com/"));
-    RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
-                                          NetworkIsolationKey(site_a, site_a),
-                                          kChecksumForSimpleGET);
-
-    EXPECT_EQ(1, cache.network_layer()->transaction_count());
-    EXPECT_EQ(0, cache.disk_cache()->open_count());
-    EXPECT_EQ(1, cache.disk_cache()->create_count());
-  }
-
-  // The second request marks the single-keyed cache entry unusable because the
-  // checksum no longer matches.
-  {
-    const auto site_b = SchemefulSite(GURL("https://b.com/"));
-    transaction.status = "HTTP/1.1 304 Not Modified";
-    // Add the "Vary" response header.
-    transaction.response_headers =
-        "Etag: \"foo\"\n"
-        "Cache-Control: max-age=10000\n"
-        "Vary: Cookie\n";
-    RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
-                                          NetworkIsolationKey(site_b, site_b),
-                                          kChecksumForSimpleGET);
-
-    EXPECT_EQ(2, cache.network_layer()->transaction_count());
-    EXPECT_EQ(1, cache.disk_cache()->open_count());
-    EXPECT_EQ(1, cache.disk_cache()->create_count());
-  }
-
-  // The third request has to go to the network because the single-keyed cache
-  // entry is unusable. It writes a new entry to the split cache.
-  {
-    const auto site_c = SchemefulSite(GURL("https://c.com/"));
-    RunTransactionTestForSingleKeyedCache(cache.http_cache(), transaction,
-                                          NetworkIsolationKey(site_c, site_c),
-                                          kChecksumForSimpleGET);
-
-    EXPECT_EQ(3, cache.network_layer()->transaction_count());
-    EXPECT_EQ(2, cache.disk_cache()->open_count());
-    EXPECT_EQ(2, cache.disk_cache()->create_count());
-  }
-}
-
-TEST_P(CacheTransparencyHttpCacheTest, SuccessfulGETManyWriters) {
-  MockHttpCache cache;
-
-  MockHttpRequest request(kSimpleGET_Transaction);
-  request.checksum = kChecksumForSimpleGET;
-
-  constexpr int kNumTransactions = 2;
-  std::vector<Context> context_list(kNumTransactions);
-
-  for (Context& c : context_list) {
-    c.result = cache.CreateTransaction(&c.trans);
-    ASSERT_THAT(c.result, IsOk());
-
-    c.result =
-        c.trans->Start(&request, c.callback.callback(), NetLogWithSource());
-  }
-
-  // Allow all requests to move from the Create queue to the active entry.
-  // All would have been added to writers.
-  base::RunLoop().RunUntilIdle();
-  std::string cache_key = cache.http_cache()
-                              ->GenerateCacheKeyForRequest(
-                                  &request, /*use_single_keyed_cache=*/true)
-                              .value();
-  EXPECT_EQ(kNumTransactions, cache.GetCountWriterTransactions(cache_key));
-
-  // The second transaction skipped validation, thus only one network
-  // transaction is created.
-  EXPECT_EQ(1, cache.network_layer()->transaction_count());
-  EXPECT_EQ(0, cache.disk_cache()->open_count());
-  EXPECT_EQ(1, cache.disk_cache()->create_count());
-
-  // Complete the transactions.
-  for (Context& c : context_list) {
-    ReadAndVerifyTransaction(c.trans.get(), kSimpleGET_Transaction);
-  }
-
-  EXPECT_EQ(1, cache.network_layer()->transaction_count());
-  EXPECT_EQ(0, cache.disk_cache()->open_count());
-  EXPECT_EQ(1, cache.disk_cache()->create_count());
-}
-
-TEST_P(CacheTransparencyHttpCacheTest, BadChecksumManyWriters) {
-  MockHttpCache cache;
-
-  MockHttpRequest request(kSimpleGET_Transaction);
-  request.checksum =
-      "0000000000000000000000000000000000000000000000000000000000000000";
-
-  constexpr int kNumTransactions = 2;
-  std::vector<Context> context_list(kNumTransactions);
-
-  for (Context& c : context_list) {
-    c.result = cache.CreateTransaction(&c.trans);
-    ASSERT_THAT(c.result, IsOk());
-
-    c.result =
-        c.trans->Start(&request, c.callback.callback(), NetLogWithSource());
-  }
-
-  // Allow all requests to move from the Create queue to the active entry.
-  // All would have been added to writers.
-  base::RunLoop().RunUntilIdle();
-  std::string cache_key = cache.http_cache()
-                              ->GenerateCacheKeyForRequest(
-                                  &request, /*use_single_keyed_cache=*/true)
-                              .value();
-  EXPECT_EQ(kNumTransactions, cache.GetCountWriterTransactions(cache_key));
-
-  // The second transaction skipped validation, thus only one network
-  // transaction is created.
-  EXPECT_EQ(1, cache.network_layer()->transaction_count());
-  EXPECT_EQ(0, cache.disk_cache()->open_count());
-  EXPECT_EQ(1, cache.disk_cache()->create_count());
-
-  // Complete the transactions.
-  for (Context& c : context_list) {
-    ReadAndVerifyTransaction(c.trans.get(), kSimpleGET_Transaction);
-  }
-
-  EXPECT_EQ(1, cache.network_layer()->transaction_count());
-  EXPECT_EQ(0, cache.disk_cache()->open_count());
-  EXPECT_EQ(1, cache.disk_cache()->create_count());
-}
 
 }  // namespace net
diff --git a/net/http/http_cache_writers.cc b/net/http/http_cache_writers.cc
index 4630b52..f9371538 100644
--- a/net/http/http_cache_writers.cc
+++ b/net/http/http_cache_writers.cc
@@ -15,8 +15,6 @@
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/single_thread_task_runner.h"
-#include "crypto/secure_hash.h"
-#include "crypto/sha2.h"
 #include "net/base/net_errors.h"
 #include "net/disk_cache/disk_cache.h"
 #include "net/http/http_cache_transaction.h"
@@ -170,15 +168,12 @@
 
 void HttpCache::Writers::SetNetworkTransaction(
     Transaction* transaction,
-    std::unique_ptr<HttpTransaction> network_transaction,
-    std::unique_ptr<crypto::SecureHash> checksum) {
+    std::unique_ptr<HttpTransaction> network_transaction) {
   DCHECK_EQ(1u, all_writers_.count(transaction));
   DCHECK(network_transaction);
   DCHECK(!network_transaction_);
   network_transaction_ = std::move(network_transaction);
   network_transaction_->SetPriority(priority_);
-  DCHECK(!checksum_);
-  checksum_ = std::move(checksum);
 }
 
 void HttpCache::Writers::ResetNetworkTransaction() {
@@ -371,14 +366,6 @@
       case State::CACHE_WRITE_DATA_COMPLETE:
         rv = DoCacheWriteDataComplete(rv);
         break;
-      case State::MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE:
-        // `rv` is bytes here.
-        DCHECK_EQ(0, rv);
-        rv = DoMarkSingleKeyedCacheEntryUnusable();
-        break;
-      case State::MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE_COMPLETE:
-        rv = DoMarkSingleKeyedCacheEntryUnusableComplete(rv);
-        break;
       case State::UNSET:
         NOTREACHED() << "bad state";
         rv = ERR_FAILED;
@@ -520,18 +507,6 @@
     return write_len_;
   }
 
-  if (checksum_) {
-    if (write_len_ > 0) {
-      checksum_->Update(read_buf_->data(), write_len_);
-    } else {
-      DCHECK(active_transaction_);
-      if (!active_transaction_->ResponseChecksumMatches(std::move(checksum_))) {
-        next_state_ = State::MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE;
-        return result;
-      }
-    }
-  }
-
   if (!last_disk_cache_access_start_time_.is_null() && active_transaction_ &&
       !all_writers_.find(active_transaction_)->second.partial) {
     active_transaction_->AddDiskCacheWriteTime(
@@ -542,42 +517,9 @@
   next_state_ = State::NONE;
   OnDataReceived(write_len_);
 
-  // If we came from DoMarkSingleKeyedCacheUnusableComplete() then  result  will
-  // be the size of the metadata that was written. But DoLoop() needs to know
-  // the number of bytes of data that were written. So return that instead.
   return write_len_;
 }
 
-int HttpCache::Writers::DoMarkSingleKeyedCacheEntryUnusable() {
-  // `response_info_truncation_` is not actually truncated.
-  // TODO(ricea): Maybe change the name of the member?
-  response_info_truncation_.single_keyed_cache_entry_unusable = true;
-  next_state_ = State::MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE_COMPLETE;
-
-  // Update cache metadata. This is a subset of what
-  // HttpCache::Transaction::WriteResponseInfoToEntry does.
-  auto data = base::MakeRefCounted<PickledIOBuffer>();
-  response_info_truncation_.Persist(data->pickle(),
-                                    /*skip_transient_headers=*/true,
-                                    /*response_truncated=*/false);
-  data->Done();
-  io_buf_len_ = data->pickle()->size();
-  CompletionOnceCallback io_callback = base::BindOnce(
-      &HttpCache::Writers::OnIOComplete, weak_factory_.GetWeakPtr());
-  return entry_->disk_entry->WriteData(kResponseInfoIndex, 0, data.get(),
-                                       io_buf_len_, std::move(io_callback),
-                                       true);
-}
-
-int HttpCache::Writers::DoMarkSingleKeyedCacheEntryUnusableComplete(
-    int result) {
-  DCHECK(!checksum_);
-  // We run DoCacheWriteDataComplete again, but this time `checksum_` is null so
-  // we won't come back here.
-  next_state_ = State::CACHE_WRITE_DATA_COMPLETE;
-  return result < 0 ? result : write_len_;
-}
-
 void HttpCache::Writers::OnDataReceived(int result) {
   DCHECK(!all_writers_.empty());
 
diff --git a/net/http/http_cache_writers.h b/net/http/http_cache_writers.h
index eb6de8e4..12be1432 100644
--- a/net/http/http_cache_writers.h
+++ b/net/http/http_cache_writers.h
@@ -14,10 +14,6 @@
 #include "net/http/http_cache.h"
 #include "net/http/http_response_info.h"
 
-namespace crypto {
-class SecureHash;
-}
-
 namespace net {
 
 class HttpResponseInfo;
@@ -139,12 +135,10 @@
   LoadState GetLoadState() const;
 
   // Sets the network transaction argument to |network_transaction_|. Must be
-  // invoked before Read can be invoked. If |checksum| is set it will be
-  // validated and the cache entry will be marked unusable if it doesn't match.
+  // invoked before Read can be invoked.
   void SetNetworkTransaction(
       Transaction* transaction,
-      std::unique_ptr<HttpTransaction> network_transaction,
-      std::unique_ptr<crypto::SecureHash> checksum);
+      std::unique_ptr<HttpTransaction> network_transaction);
 
   // Resets the network transaction to nullptr. Required for range requests as
   // they might use the current network transaction only for part of the
@@ -166,8 +160,6 @@
     NETWORK_READ_COMPLETE,
     CACHE_WRITE_DATA,
     CACHE_WRITE_DATA_COMPLETE,
-    MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE,
-    MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE_COMPLETE,
   };
 
   // These transactions are waiting on Read. After the active transaction
@@ -197,8 +189,6 @@
   int DoNetworkReadComplete(int result);
   int DoCacheWriteData(int num_bytes);
   int DoCacheWriteDataComplete(int result);
-  int DoMarkSingleKeyedCacheEntryUnusable();
-  int DoMarkSingleKeyedCacheEntryUnusableComplete(int result);
 
   // Helper functions for callback.
   void OnNetworkReadFailure(int result);
@@ -295,11 +285,6 @@
   // The latest time `this` starts writing data to the disk cache.
   base::TimeTicks last_disk_cache_access_start_time_;
 
-  // Set if we are currently calculating a checksum of the resource to validate
-  // it against the expected checksum for the single-keyed cache. Initialised
-  // with selected headers and accumulates the body of the response.
-  std::unique_ptr<crypto::SecureHash> checksum_;
-
   CompletionOnceCallback callback_;  // Callback for active_transaction_.
 
   // Since cache_ can destroy |this|, |cache_callback_| is only invoked at the
diff --git a/net/http/http_cache_writers_unittest.cc b/net/http/http_cache_writers_unittest.cc
index 130d904..ac93e6ef 100644
--- a/net/http/http_cache_writers_unittest.cc
+++ b/net/http/http_cache_writers_unittest.cc
@@ -143,7 +143,7 @@
     writers_->AddTransaction(transaction.get(), parallel_writing_pattern_,
                              transaction->priority(), info);
     writers_->SetNetworkTransaction(transaction.get(),
-                                    std::move(network_transaction), nullptr);
+                                    std::move(network_transaction));
     EXPECT_TRUE(writers_->HasTransaction(transaction.get()));
     transactions_.push_back(std::move(transaction));
   }
diff --git a/net/http/http_request_info.h b/net/http/http_request_info.h
index 025725de..492470a 100644
--- a/net/http/http_request_info.h
+++ b/net/http/http_request_info.h
@@ -107,14 +107,6 @@
   // that the request is idempotent.
   net::Idempotency idempotency = net::DEFAULT_IDEMPOTENCY;
 
-  // Index of the requested URL in Cache Transparency's pervasive payload list.
-  // Only used for logging purposes.
-  int pervasive_payloads_index_for_logging = -1;
-
-  // Checksum of the request body and selected headers, in upper-case
-  // hexadecimal. Only non-empty if the USE_SINGLE_KEYED_CACHE load flag is set.
-  std::string checksum;
-
   // If not null, the value is used to evaluate whether the cache entry should
   // be bypassed; if is null, that means the request site does not match the
   // filter.
diff --git a/net/http/http_response_info.cc b/net/http/http_response_info.cc
index fbae14d4..6eac533 100644
--- a/net/http/http_response_info.cc
+++ b/net/http/http_response_info.cc
@@ -118,9 +118,10 @@
   // This bit is set if the response has a nonempty `dns_aliases` entry.
   RESPONSE_INFO_HAS_DNS_ALIASES = 1 << 27,
 
-  // This bit is set for an entry in the single-keyed cache that has been marked
-  // unusable due to the checksum not matching.
-  RESPONSE_INFO_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE = 1 << 28,
+  // This bit is now unused. It may be set on existing entries. Previously it
+  // was set for an entry in the single-keyed cache that had been marked
+  // unusable due to the cache transparency checksum not matching.
+  RESPONSE_INFO_UNUSED_WAS_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE = 1 << 28,
 
   // This bit is set if the response has `encrypted_client_hello` set.
   RESPONSE_INFO_ENCRYPTED_CLIENT_HELLO = 1 << 29,
@@ -372,8 +373,7 @@
 
   restricted_prefetch = (flags & RESPONSE_INFO_RESTRICTED_PREFETCH) != 0;
 
-  single_keyed_cache_entry_unusable =
-      (flags & RESPONSE_INFO_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE) != 0;
+  // RESPONSE_INFO_UNUSED_WAS_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE is unused.
 
   ssl_info.pkp_bypassed = (flags & RESPONSE_INFO_PKP_BYPASSED) != 0;
 
@@ -454,8 +454,7 @@
     flags |= RESPONSE_INFO_UNUSED_SINCE_PREFETCH;
   if (restricted_prefetch)
     flags |= RESPONSE_INFO_RESTRICTED_PREFETCH;
-  if (single_keyed_cache_entry_unusable)
-    flags |= RESPONSE_INFO_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE;
+  // RESPONSE_INFO_UNUSED_WAS_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE is not used.
   if (ssl_info.pkp_bypassed)
     flags |= RESPONSE_INFO_PKP_BYPASSED;
   if (!stale_revalidate_timeout.is_null())
diff --git a/net/http/http_response_info.h b/net/http/http_response_info.h
index 7a4b3c94..cd8d950 100644
--- a/net/http/http_response_info.h
+++ b/net/http/http_response_info.h
@@ -206,10 +206,6 @@
   // response is retrieved from the cache.
   bool async_revalidation_requested = false;
 
-  // True if this entry in the single-keyed cache is unusable due to a checksum
-  // mismatch.
-  bool single_keyed_cache_entry_unusable = false;
-
   // stale-while-revalidate, if any, will be honored until time given by
   // |stale_revalidate_timeout|. This value is latched the first time
   // stale-while-revalidate is used until the resource is revalidated.
diff --git a/net/third_party/quiche/BUILD.gn b/net/third_party/quiche/BUILD.gn
index 3b60857..6fa6e609 100644
--- a/net/third_party/quiche/BUILD.gn
+++ b/net/third_party/quiche/BUILD.gn
@@ -712,6 +712,8 @@
     "src/quiche/spdy/core/spdy_simple_arena.cc",
     "src/quiche/spdy/core/spdy_simple_arena.h",
     "src/quiche/spdy/core/zero_copy_output_buffer.h",
+    "src/quiche/web_transport/complete_buffer_visitor.cc",
+    "src/quiche/web_transport/complete_buffer_visitor.h",
     "src/quiche/web_transport/web_transport.h",
   ]
 
@@ -837,6 +839,7 @@
       "src/quiche/quic/tools/quic_name_lookup.h",
       "src/quiche/quic/tools/quic_server.cc",
       "src/quiche/quic/tools/quic_server.h",
+      "src/quiche/quic/tools/web_transport_test_server.cc",
     ]
 
     configs += [ ":quiche_internal_config" ]
@@ -1225,6 +1228,8 @@
     "src/quiche/quic/core/tls_chlo_extractor.cc",
     "src/quiche/quic/core/tls_chlo_extractor.h",
     "src/quiche/quic/platform/api/quic_default_proof_providers.h",
+    "src/quiche/quic/tools/devious_baton.cc",
+    "src/quiche/quic/tools/devious_baton.h",
     "src/quiche/quic/tools/fake_proof_verifier.h",
     "src/quiche/quic/tools/quic_backend_response.cc",
     "src/quiche/quic/tools/quic_backend_response.h",
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index e5469d0..88838c9 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -837,22 +837,6 @@
   void SetIdempotency(Idempotency idempotency) { idempotency_ = idempotency; }
   Idempotency GetIdempotency() const { return idempotency_; }
 
-  int pervasive_payloads_index_for_logging() const {
-    return pervasive_payloads_index_for_logging_;
-  }
-
-  void set_pervasive_payloads_index_for_logging(int index) {
-    pervasive_payloads_index_for_logging_ = index;
-  }
-
-  const std::string& expected_response_checksum() const {
-    return expected_response_checksum_;
-  }
-
-  void set_expected_response_checksum(base::StringPiece checksum) {
-    expected_response_checksum_ = std::string(checksum);
-  }
-
   void set_has_storage_access(bool has_storage_access) {
     DCHECK(!is_pending_);
     DCHECK(!has_notified_completion_);
@@ -1119,17 +1103,6 @@
   // See SetIsSharedDictionaryReadAllowedCallback() above for details.
   base::RepeatingCallback<bool()> is_shared_dictionary_read_allowed_callback_;
 
-  // The index of the request URL in Cache Transparency's Pervasive Payloads
-  // List. This is only used for logging purposes. It is initialized as -1 to
-  // signify that the index has not been set.
-  int pervasive_payloads_index_for_logging_ = -1;
-
-  // A SHA-256 checksum of the response and selected headers, stored as
-  // upper-case hexadecimal. If this is set to a non-empty value the transaction
-  // will attempt to use the single-keyed cache. On failure to match the cache
-  // entry will be marked as unusable and will not be re-used.
-  std::string expected_response_checksum_;
-
   bool upgrade_if_insecure_ = false;
 
   bool send_client_certs_ = true;
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 529e211d..23a9e7c 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -274,9 +274,6 @@
       net::MutableNetworkTrafficAnnotationTag(request_->traffic_annotation());
   request_info_.socket_tag = request_->socket_tag();
   request_info_.idempotency = request_->GetIdempotency();
-  request_info_.pervasive_payloads_index_for_logging =
-      request_->pervasive_payloads_index_for_logging();
-  request_info_.checksum = request_->expected_response_checksum();
 #if BUILDFLAG(ENABLE_REPORTING)
   request_info_.reporting_upload_depth = request_->reporting_upload_depth();
 #endif
diff --git a/services/network/network_service_memory_cache.cc b/services/network/network_service_memory_cache.cc
index ff5ad4c..413b9512 100644
--- a/services/network/network_service_memory_cache.cc
+++ b/services/network/network_service_memory_cache.cc
@@ -102,8 +102,7 @@
       resource_request.destination == mojom::RequestDestination::kIframe;
   return net::HttpCache::GenerateCacheKey(
       resource_request.url, resource_request.load_flags, network_isolation_key,
-      /*upload_data_identifier=*/0, is_subframe_document_resource,
-      /*use_single_keyed_cache=*/false, /*single_key_checksum=*/"");
+      /*upload_data_identifier=*/0, is_subframe_document_resource);
 }
 
 absl::optional<std::string> GenerateCacheKeyForURLRequest(
@@ -114,9 +113,7 @@
   return net::HttpCache::GenerateCacheKey(
       url_request.url(), url_request.load_flags(),
       url_request.isolation_info().network_isolation_key(),
-      /*upload_data_identifier=*/0, is_subframe_document_resource,
-      /*use_single_keyed_cache=*/false,
-      /*single_key_checksum=*/"");
+      /*upload_data_identifier=*/0, is_subframe_document_resource);
 }
 
 bool CheckCrossOriginReadBlocking(const ResourceRequest& resource_request,
diff --git a/services/network/resource_scheduler/resource_scheduler.cc b/services/network/resource_scheduler/resource_scheduler.cc
index 822620e..6258bc4 100644
--- a/services/network/resource_scheduler/resource_scheduler.cc
+++ b/services/network/resource_scheduler/resource_scheduler.cc
@@ -253,7 +253,7 @@
     const bool deprioritize =
         base::FeatureList::IsEnabled(
             features::kVisibilityAwareResourceScheduler) &&
-        !visible;
+        !(request->load_flags() & net::LOAD_IGNORE_LIMITS) && !visible;
     if (deprioritize) {
       // Deprioritize to IDLE if this is a background request.
       priority_.priority = net::RequestPriority::IDLE;
diff --git a/services/network/resource_scheduler/resource_scheduler_unittest.cc b/services/network/resource_scheduler/resource_scheduler_unittest.cc
index 4e4f8b59..117c623 100644
--- a/services/network/resource_scheduler/resource_scheduler_unittest.cc
+++ b/services/network/resource_scheduler/resource_scheduler_unittest.cc
@@ -2357,6 +2357,23 @@
   ASSERT_EQ(request->url_request()->priority(), net::IDLE);
 }
 
+TEST_F(VisibilityAwareResourceSchedulerTest, BackgroundRequestIgnoreLimit) {
+  InitializeScheduler();
+  std::unique_ptr<net::URLRequest> url_request =
+      NewURLRequest("https://a.test", net::MAXIMUM_PRIORITY);
+  url_request->SetLoadFlags(url_request->load_flags() |
+                            net::LOAD_IGNORE_LIMITS);
+  std::unique_ptr<ResourceScheduler::ScheduledResourceRequest>
+      scheduled_request =
+          scheduler()->ScheduleRequest(kBackgroundClientId,
+                                       /*is_async=*/true, url_request.get());
+  auto request = std::make_unique<TestRequest>(
+      std::move(url_request), std::move(scheduled_request), scheduler());
+  request->Start();
+  ASSERT_TRUE(request->started());
+  ASSERT_EQ(request->url_request()->priority(), net::MAXIMUM_PRIORITY);
+}
+
 TEST_F(VisibilityAwareResourceSchedulerTest, ChangePriorityBasedOnVisibility) {
   InitializeScheduler();
   SetMaxDelayableRequests(1);
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index ac00a1b..20aa4460 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -687,6 +687,7 @@
 
   int request_load_flags = request.load_flags;
 
+  // TODO(ricea): Remove Cache Transparency implementation.
   if (cache_transparency_settings_ &&
       cache_transparency_settings_->pervasive_payloads_enabled()) {
     auto index = cache_transparency_settings_->GetIndexForURL(request.url);
@@ -694,7 +695,6 @@
       // Remember that a pervasive payload was found so we can annotate the
       // URLLoaderCompletionStatus with it later.
       pervasive_payload_requested_ = true;
-      url_request_->set_pervasive_payloads_index_for_logging(index.value());
       base::UmaHistogramCustomCounts("Network.CacheTransparency2.URLMatched",
                                      index.value(), 1, 323, 323);
       DVLOG(2) << "Found pervasive payload: " << request.url.spec();
@@ -720,8 +720,6 @@
       } else if (HasHeadersIncompatibleWithSingleKeyedCache(request.headers)) {
         cache_not_used_reason =
             CacheTransparencyCacheNotUsedReason::kIncompatibleRequestHeaders;
-      } else {
-        url_request_->set_expected_response_checksum(checksum.value());
       }
       base::UmaHistogramEnumeration("Network.CacheTransparency.CacheNotUsed",
                                     cache_not_used_reason);
@@ -1482,9 +1480,6 @@
   DCHECK_EQ(emitted_devtools_raw_request_, emitted_devtools_raw_response_);
   response->emitted_extra_info = emitted_devtools_raw_request_;
 
-  // Ensure that the redirect target is not treated as a pervasive payload.
-  url_request_->set_expected_response_checksum(std::string());
-
   ProcessInboundAttributionInterceptorOnReceivedRedirect(redirect_info,
                                                          std::move(response));
 }
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc
index a6dec07..044276fb 100644
--- a/services/network/url_loader_unittest.cc
+++ b/services/network/url_loader_unittest.cc
@@ -7552,41 +7552,6 @@
       CacheTransparencyCacheNotUsedReason::kIncompatibleRequestHeaders);
 }
 
-// Do an end-to-end test of redirects, since their behaviour spans multiple
-// layers.
-TEST_F(URLLoaderCacheTransparencyTest, Redirect) {
-  // This use of this histogram is a layering violation. It is not strictly
-  // necessary to the test, but helps ensure it is passing for the right reason.
-  // TODO(ricea): Stop checking this histogram if it is removed.
-  static constexpr char kMarkedUnusableHistogram[] =
-      "Network.CacheTransparency2.MarkedUnusable";
-
-  set_expect_redirect(true);
-
-  SetOrigin("https://a.com/");
-  auto client1 = SendRequest(kRedirect301);
-  EXPECT_EQ(client1->redirect_info().status_code, 301);
-  histogram_tester().ExpectTotalCount(kMarkedUnusableHistogram, 0);
-
-  SetOrigin("https://b.com/");
-  auto client2 = SendRequest(kRedirect301);
-  EXPECT_EQ(client2->redirect_info().status_code, 301);
-  histogram_tester().ExpectUniqueSample(
-      kMarkedUnusableHistogram,
-      1,  // index of the URL in the pervasive payloads list
-      1   // number of samples
-  );
-
-  // TODO(ricea): Stop checking this histogram if it is removed.
-  histogram_tester().ExpectTotalCount(
-      "Network.CacheTransparency2.SingleKeyedCacheIsUsed", 0);
-
-  // The count includes the target of the redirects.
-  EXPECT_EQ(4, network_request_count());
-  ExpectNotUsedReason(
-      CacheTransparencyCacheNotUsedReason::kTryingSingleKeyedCache);
-}
-
 class SharedStorageRequestHelperURLLoaderTest : public URLLoaderTest {
  public:
   void RegisterAdditionalHandlers() override {
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json
index f84c6ea..9f5e5e43 100644
--- a/testing/buildbot/chrome.json
+++ b/testing/buildbot/chrome.json
@@ -1363,7 +1363,7 @@
               "pool": "chrome.tests"
             }
           ],
-          "hard_timeout": 10800,
+          "hard_timeout": 14400,
           "idempotent": false,
           "io_timeout": 3600,
           "service_account": "chrome-tester@chops-service-accounts.iam.gserviceaccount.com",
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 9876342..5d8df1f 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -5466,9 +5466,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5905.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5907.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 117.0.5905.0",
+        "description": "Run with ash-chrome version 117.0.5907.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5478,8 +5478,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5905.0",
-              "revision": "version:117.0.5905.0"
+              "location": "lacros_version_skew_tests_v117.0.5907.0",
+              "revision": "version:117.0.5907.0"
             }
           ],
           "dimension_sets": [
@@ -5625,9 +5625,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5905.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5907.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 117.0.5905.0",
+        "description": "Run with ash-chrome version 117.0.5907.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5637,8 +5637,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5905.0",
-              "revision": "version:117.0.5905.0"
+              "location": "lacros_version_skew_tests_v117.0.5907.0",
+              "revision": "version:117.0.5907.0"
             }
           ],
           "dimension_sets": [
@@ -5767,9 +5767,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5905.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5907.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 117.0.5905.0",
+        "description": "Run with ash-chrome version 117.0.5907.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -5779,8 +5779,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5905.0",
-              "revision": "version:117.0.5905.0"
+              "location": "lacros_version_skew_tests_v117.0.5907.0",
+              "revision": "version:117.0.5907.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json
index c8a9021b..82e98db 100644
--- a/testing/buildbot/chromium.coverage.json
+++ b/testing/buildbot/chromium.coverage.json
@@ -23265,9 +23265,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5905.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5907.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 117.0.5905.0",
+        "description": "Run with ash-chrome version 117.0.5907.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -23277,8 +23277,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5905.0",
-              "revision": "version:117.0.5905.0"
+              "location": "lacros_version_skew_tests_v117.0.5907.0",
+              "revision": "version:117.0.5907.0"
             }
           ],
           "dimension_sets": [
@@ -23424,9 +23424,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5905.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5907.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 117.0.5905.0",
+        "description": "Run with ash-chrome version 117.0.5907.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -23436,8 +23436,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5905.0",
-              "revision": "version:117.0.5905.0"
+              "location": "lacros_version_skew_tests_v117.0.5907.0",
+              "revision": "version:117.0.5907.0"
             }
           ],
           "dimension_sets": [
@@ -23566,9 +23566,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5905.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5907.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 117.0.5905.0",
+        "description": "Run with ash-chrome version 117.0.5907.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -23578,8 +23578,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5905.0",
-              "revision": "version:117.0.5905.0"
+              "location": "lacros_version_skew_tests_v117.0.5907.0",
+              "revision": "version:117.0.5907.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index bd381e6..2447633b 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -37620,9 +37620,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5905.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5907.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 117.0.5905.0",
+        "description": "Run with ash-chrome version 117.0.5907.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -37631,8 +37631,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5905.0",
-              "revision": "version:117.0.5905.0"
+              "location": "lacros_version_skew_tests_v117.0.5907.0",
+              "revision": "version:117.0.5907.0"
             }
           ],
           "dimension_sets": [
@@ -37779,9 +37779,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5905.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5907.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 117.0.5905.0",
+        "description": "Run with ash-chrome version 117.0.5907.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -37790,8 +37790,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5905.0",
-              "revision": "version:117.0.5905.0"
+              "location": "lacros_version_skew_tests_v117.0.5907.0",
+              "revision": "version:117.0.5907.0"
             }
           ],
           "dimension_sets": [
@@ -37921,9 +37921,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5905.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5907.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 117.0.5905.0",
+        "description": "Run with ash-chrome version 117.0.5907.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -37932,8 +37932,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5905.0",
-              "revision": "version:117.0.5905.0"
+              "location": "lacros_version_skew_tests_v117.0.5907.0",
+              "revision": "version:117.0.5907.0"
             }
           ],
           "dimension_sets": [
@@ -39333,9 +39333,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5905.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5907.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 117.0.5905.0",
+        "description": "Run with ash-chrome version 117.0.5907.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -39344,8 +39344,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5905.0",
-              "revision": "version:117.0.5905.0"
+              "location": "lacros_version_skew_tests_v117.0.5907.0",
+              "revision": "version:117.0.5907.0"
             }
           ],
           "dimension_sets": [
@@ -39492,9 +39492,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5905.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5907.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 117.0.5905.0",
+        "description": "Run with ash-chrome version 117.0.5907.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -39503,8 +39503,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5905.0",
-              "revision": "version:117.0.5905.0"
+              "location": "lacros_version_skew_tests_v117.0.5907.0",
+              "revision": "version:117.0.5907.0"
             }
           ],
           "dimension_sets": [
@@ -39634,9 +39634,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5905.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5907.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 117.0.5905.0",
+        "description": "Run with ash-chrome version 117.0.5907.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -39645,8 +39645,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5905.0",
-              "revision": "version:117.0.5905.0"
+              "location": "lacros_version_skew_tests_v117.0.5907.0",
+              "revision": "version:117.0.5907.0"
             }
           ],
           "dimension_sets": [
@@ -40359,9 +40359,9 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5905.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5907.0/test_ash_chrome"
         ],
-        "description": "Run with ash-chrome version 117.0.5905.0",
+        "description": "Run with ash-chrome version 117.0.5907.0",
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
@@ -40370,8 +40370,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5905.0",
-              "revision": "version:117.0.5905.0"
+              "location": "lacros_version_skew_tests_v117.0.5907.0",
+              "revision": "version:117.0.5907.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 2bcf3cb..a9757b6b 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -17676,12 +17676,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5905.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5907.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 117.0.5905.0",
+        "description": "Run with ash-chrome version 117.0.5907.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -17691,8 +17691,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5905.0",
-              "revision": "version:117.0.5905.0"
+              "location": "lacros_version_skew_tests_v117.0.5907.0",
+              "revision": "version:117.0.5907.0"
             }
           ],
           "dimension_sets": [
@@ -17855,12 +17855,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5905.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5907.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 117.0.5905.0",
+        "description": "Run with ash-chrome version 117.0.5907.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -17870,8 +17870,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5905.0",
-              "revision": "version:117.0.5905.0"
+              "location": "lacros_version_skew_tests_v117.0.5907.0",
+              "revision": "version:117.0.5907.0"
             }
           ],
           "dimension_sets": [
@@ -18012,12 +18012,12 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5905.0/test_ash_chrome",
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5907.0/test_ash_chrome",
           "--test-launcher-print-test-stdio=always",
           "--combine-ash-logs-on-bots",
           "--asan-symbolize-output"
         ],
-        "description": "Run with ash-chrome version 117.0.5905.0",
+        "description": "Run with ash-chrome version 117.0.5907.0",
         "isolate_profile_data": true,
         "merge": {
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
@@ -18027,8 +18027,8 @@
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v117.0.5905.0",
-              "revision": "version:117.0.5905.0"
+              "location": "lacros_version_skew_tests_v117.0.5907.0",
+              "revision": "version:117.0.5907.0"
             }
           ],
           "dimension_sets": [
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index be07acb3..21c22fa 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -1471,8 +1471,8 @@
       },
       'chromeos-eve-chrome': {
         'swarming': {
-          # Increased timeout to 3 hours due to shard timeout.
-          'hard_timeout': 10800,
+          # Increased timeout to 4 hours due to shard timeout.
+          'hard_timeout': 14400,
         }
       },
       # TODO(crbug.com/1141234): Move out of experimental if/when the bots are
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 7aa1727..56065844 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -20,16 +20,16 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5905.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v117.0.5907.0/test_ash_chrome',
     ],
-    'description': 'Run with ash-chrome version 117.0.5905.0',
+    'description': 'Run with ash-chrome version 117.0.5907.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_v117.0.5905.0',
-          'revision': 'version:117.0.5905.0',
+          'location': 'lacros_version_skew_tests_v117.0.5907.0',
+          'revision': 'version:117.0.5907.0',
         },
       ],
     },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index c628e3b02..bb58e97 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -12685,14 +12685,15 @@
             ],
             "experiments": [
                 {
-                    "name": "ServiceWorkerBypassFetchHandlerForMainResource_20230323",
+                    "name": "Enabled_ServiceWorkerBypassFetchHandlerForRace_20230724",
                     "params": {
-                        "bypass_for": "main_resource",
+                        "bypass_for": "all_with_race_network_request",
                         "script_checksum_to_bypass": "144B3D5485B621F5896FD51D6A6FE66A07B6DBC3ACF6404748A833C2D592F900",
                         "strategy": "allowlist"
                     },
                     "enable_features": [
-                        "ServiceWorkerBypassFetchHandler"
+                        "ServiceWorkerBypassFetchHandler",
+                        "ServiceWorkerBypassFetchHandlerHashStrings"
                     ]
                 }
             ]
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni
index 1a22a33..fea556b4 100644
--- a/third_party/blink/renderer/bindings/generated_in_modules.gni
+++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -1570,6 +1570,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_stats_type.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_video_codec_type.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_rtc_video_codec_type.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_running_status_enum.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_running_status_enum.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_scheduler_signal_inherit.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_scheduler_signal_inherit.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_scheduler_yield_priority.h",
diff --git a/third_party/blink/renderer/core/editing/ime/cached_text_input_info.cc b/third_party/blink/renderer/core/editing/ime/cached_text_input_info.cc
index f133d125..c429b3d1 100644
--- a/third_party/blink/renderer/core/editing/ime/cached_text_input_info.cc
+++ b/third_party/blink/renderer/core/editing/ime/cached_text_input_info.cc
@@ -141,7 +141,7 @@
     unsigned capacity = kInitialCapacity;
     if (auto* block_flow =
             DynamicTo<LayoutBlockFlow>(container.GetLayoutObject())) {
-      if (block_flow->HasNGInlineNodeData()) {
+      if (block_flow->GetNGInlineNodeData()) {
         if (const auto* mapping = NGInlineNode::GetOffsetMapping(block_flow))
           capacity = mapping->GetText().length();
       }
diff --git a/third_party/blink/renderer/core/editing/visible_units.cc b/third_party/blink/renderer/core/editing/visible_units.cc
index 2f2beb7..7b2f779 100644
--- a/third_party/blink/renderer/core/editing/visible_units.cc
+++ b/third_party/blink/renderer/core/editing/visible_units.cc
@@ -457,12 +457,13 @@
     // Note: tests[1][2] require this.
     // [1] editing/style/underline.html
     // [2] editing/inserting/return-with-object-element.html
-    if (block_flow->HasNGInlineNodeData() &&
-        block_flow->GetNGInlineNodeData()
-            ->ItemsData(false)
-            .text_content.empty() &&
-        block_flow->HasLineIfEmpty())
-      return false;
+    if (const NGInlineNodeData* inline_data =
+            block_flow->GetNGInlineNodeData()) {
+      if (inline_data->ItemsData(false).text_content.empty() &&
+          block_flow->HasLineIfEmpty()) {
+        return false;
+      }
+    }
   }
   const LayoutObject* stop = layout_object->NextInPreOrderAfterChildren();
   // TODO(editing-dev): Avoid single-character parameter names.
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.h b/third_party/blink/renderer/core/layout/layout_block_flow.h
index 2d343b1..770ff9ae 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow.h
+++ b/third_party/blink/renderer/core/layout/layout_block_flow.h
@@ -137,20 +137,21 @@
   // we're still working on LayoutNG.
   void AddVisualOverflowFromFloats(const NGPhysicalFragment& fragment);
 
-  virtual NGInlineNodeData* TakeNGInlineNodeData() {
-    NOT_DESTROYED();
-    return nullptr;
-  }
+  // Returns the associated `NGInlineNodeData`, or `nullptr` if `this` doesn't
+  // have one (i.e., not an NG inline formatting context.)
   virtual NGInlineNodeData* GetNGInlineNodeData() const {
     NOT_DESTROYED();
     return nullptr;
   }
-  virtual void ResetNGInlineNodeData() { NOT_DESTROYED(); }
-  virtual void ClearNGInlineNodeData() { NOT_DESTROYED(); }
-  virtual bool HasNGInlineNodeData() const {
+  // Same as `GetNGInlineNodeData` and then `ClearNGInlineNodeData`.
+  virtual NGInlineNodeData* TakeNGInlineNodeData() {
     NOT_DESTROYED();
-    return false;
+    return nullptr;
   }
+  // Reset `NGInlineNodeData` to a new instance.
+  virtual void ResetNGInlineNodeData() { NOT_DESTROYED(); }
+  // Clear `NGInlineNodeData` to `nullptr`.
+  virtual void ClearNGInlineNodeData() { NOT_DESTROYED(); }
   virtual void WillCollectInlines() { NOT_DESTROYED(); }
 
  protected:
diff --git a/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_combine.cc b/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_combine.cc
index 61d534a..1e4ea90 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_combine.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_combine.cc
@@ -45,7 +45,7 @@
 }
 
 String LayoutNGTextCombine::GetTextContent() const {
-  DCHECK(!NeedsCollectInlines() && HasNGInlineNodeData()) << this;
+  DCHECK(!NeedsCollectInlines() && GetNGInlineNodeData()) << this;
   return GetNGInlineNodeData()->ItemsData(false).text_content;
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
index d242dd1d..2deefbe 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -484,8 +484,9 @@
     : NGLayoutInputNode(block, kInline) {
   DCHECK(block);
   DCHECK(block->IsLayoutNGObject());
-  if (!block->HasNGInlineNodeData())
+  if (!block->GetNGInlineNodeData()) {
     block->ResetNGInlineNodeData();
+  }
 }
 
 bool NGInlineNode::IsPrepareLayoutFinished() const {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
index 7a697b1..d9c1e202 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
@@ -1149,35 +1149,35 @@
 
 TEST_F(NGInlineNodeTest, RemoveInlineNodeDataIfBlockBecomesEmpty1) {
   SetupHtml("container", "<div id=container><b id=remove><i>foo</i></b></div>");
-  ASSERT_TRUE(layout_block_flow_->HasNGInlineNodeData());
+  ASSERT_TRUE(layout_block_flow_->GetNGInlineNodeData());
 
   Element* to_remove = GetElementById("remove");
   to_remove->remove();
   UpdateAllLifecyclePhasesForTest();
 
-  EXPECT_FALSE(layout_block_flow_->HasNGInlineNodeData());
+  EXPECT_FALSE(layout_block_flow_->GetNGInlineNodeData());
 }
 
 TEST_F(NGInlineNodeTest, RemoveInlineNodeDataIfBlockBecomesEmpty2) {
   SetupHtml("container", "<div id=container><b><i>foo</i></b></div>");
-  ASSERT_TRUE(layout_block_flow_->HasNGInlineNodeData());
+  ASSERT_TRUE(layout_block_flow_->GetNGInlineNodeData());
 
   GetElementById("container")->setInnerHTML("");
   UpdateAllLifecyclePhasesForTest();
 
-  EXPECT_FALSE(layout_block_flow_->HasNGInlineNodeData());
+  EXPECT_FALSE(layout_block_flow_->GetNGInlineNodeData());
 }
 
 TEST_F(NGInlineNodeTest, RemoveInlineNodeDataIfBlockObtainsBlockChild) {
   SetupHtml("container",
             "<div id=container><b id=blockify><i>foo</i></b></div>");
-  ASSERT_TRUE(layout_block_flow_->HasNGInlineNodeData());
+  ASSERT_TRUE(layout_block_flow_->GetNGInlineNodeData());
 
   GetElementById("blockify")
       ->SetInlineStyleProperty(CSSPropertyID::kDisplay, CSSValueID::kBlock);
   UpdateAllLifecyclePhasesForTest();
 
-  EXPECT_FALSE(layout_block_flow_->HasNGInlineNodeData());
+  EXPECT_FALSE(layout_block_flow_->GetNGInlineNodeData());
 }
 
 // Test inline objects are initialized when |SplitFlow()| moves them.
diff --git a/third_party/blink/renderer/core/layout/ng/inline/text_auto_space.cc b/third_party/blink/renderer/core/layout/ng/inline/text_auto_space.cc
index 7e0ef1d..b39bd90 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/text_auto_space.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/text_auto_space.cc
@@ -31,6 +31,11 @@
 // static
 void TextAutoSpace::ApplyIfNeeded(NGInlineItemsData& data,
                                   Vector<wtf_size_t>* offsets_out) {
+  const String& text = data.text_content;
+  if (text.Is8Bit()) {
+    return;  // 8-bits never be `kIdeograph`. See `TextAutoSpaceTest`.
+  }
+
   HeapVector<NGInlineItem>& items = data.items;
   if (UNLIKELY(items.empty())) {
     return;
@@ -39,7 +44,6 @@
   // Compute `RunSegmenterRange` for the whole text content. It's pre-computed,
   // but packed in `NGInlineItemSegments` to save memory.
   NGInlineItemSegments::RunSegmenterRanges ranges;
-  const String& text = data.text_content;
   if (!data.segments) {
     const NGInlineItem& item0 = items.front();
     RunSegmenter::RunSegmenterRange range = item0.CreateRunSegmenterRange();
@@ -57,7 +61,6 @@
       return;
     }
   }
-  DCHECK(!text.Is8Bit());
   DCHECK_EQ(text.length(), ranges.back().end);
 
   Vector<wtf_size_t, 16> offsets;
@@ -145,9 +148,7 @@
 // static
 TextAutoSpace::CharType TextAutoSpace::GetTypeAndNext(const String& text,
                                                       wtf_size_t& offset) {
-  if (text.Is8Bit()) {
-    return GetType(text[offset++]);
-  }
+  CHECK(!text.Is8Bit());
   UChar ch;
   U16_NEXT(text.Characters16(), offset, text.length(), ch);
   return GetType(ch);
@@ -157,9 +158,7 @@
 TextAutoSpace::CharType TextAutoSpace::GetPrevType(const String& text,
                                                    wtf_size_t offset) {
   DCHECK_GT(offset, 0u);
-  if (text.Is8Bit()) {
-    return GetType(text[offset - 1]);
-  }
+  CHECK(!text.Is8Bit());
   UChar last_ch;
   U16_PREV(text.Characters16(), 0, offset, last_ch);
   return GetType(last_ch);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/text_auto_space_test.cc b/third_party/blink/renderer/core/layout/ng/inline/text_auto_space_test.cc
index 4fa37a7..ba30af7ca 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/text_auto_space_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/text_auto_space_test.cc
@@ -15,6 +15,17 @@
 
 using testing::ElementsAreArray;
 
+class TextAutoSpaceTest : public RenderingTest, ScopedCSSTextAutoSpaceForTest {
+public:
+  explicit TextAutoSpaceTest() : ScopedCSSTextAutoSpaceForTest(true) {}
+};
+
+TEST_F(TextAutoSpaceTest, Check8Bit) {
+  for (UChar32 ch = 0; ch <= std::numeric_limits<uint8_t>::max(); ++ch) {
+    EXPECT_NE(TextAutoSpace::GetType(ch), TextAutoSpace::kIdeograph);
+  }
+}
+
 struct TypeData {
   UChar32 ch;
   TextAutoSpace::CharType type;
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
index 01ae298..107551a 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
@@ -65,7 +65,6 @@
 template <typename Base>
 NGInlineNodeData* LayoutNGBlockFlowMixin<Base>::GetNGInlineNodeData() const {
   Base::CheckIsNotDestroyed();
-  DCHECK(ng_inline_node_data_);
   return ng_inline_node_data_;
 }
 
@@ -96,12 +95,6 @@
 }
 
 template <typename Base>
-bool LayoutNGBlockFlowMixin<Base>::HasNGInlineNodeData() const {
-  Base::CheckIsNotDestroyed();
-  return ng_inline_node_data_;
-}
-
-template <typename Base>
 void LayoutNGBlockFlowMixin<Base>::AddOutlineRects(
     OutlineRectCollector& collector,
     LayoutObject::OutlineInfo* info,
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h
index 3bd15c3..c63ac37 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h
@@ -43,7 +43,6 @@
   NGInlineNodeData* GetNGInlineNodeData() const final;
   void ResetNGInlineNodeData() final;
   void ClearNGInlineNodeData() final;
-  bool HasNGInlineNodeData() const final;
 
   bool NodeAtPoint(HitTestResult&,
                    const HitTestLocation&,
diff --git a/third_party/blink/renderer/modules/service_worker/router_condition.idl b/third_party/blink/renderer/modules/service_worker/router_condition.idl
index f4bbf28..5a8a518 100644
--- a/third_party/blink/renderer/modules/service_worker/router_condition.idl
+++ b/third_party/blink/renderer/modules/service_worker/router_condition.idl
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// https://github.com/yoshisatoyanagisawa/service-worker-static-routing-api/blob/main/final-form.md
+enum RunningStatusEnum { "running", "not-running" };
+
 // Experimental.
 // https://github.com/yoshisatoyanagisawa/service-worker-static-routing-api
 dictionary RouterCondition {
@@ -13,5 +16,8 @@
   USVString requestMethod;
   RequestMode requestMode;
   RequestDestination requestDestination;
+
+  // For the running status.
+  RunningStatusEnum runningStatus;
 };
 
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter.cc b/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter.cc
index 40ad31d..bc54d28 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter.cc
@@ -66,7 +66,7 @@
 absl::optional<blink::ServiceWorkerRouterCondition>
 RouterRequestConditionToBlink(blink::RouterCondition* v8_condition) {
   if (!v8_condition) {
-    // No UrlCondition configured.
+    // No condition configured.
     return absl::nullopt;
   }
 
@@ -97,6 +97,34 @@
   return condition;
 }
 
+absl::optional<blink::ServiceWorkerRouterCondition>
+RouterRunningStatusConditionToBlink(blink::RouterCondition* v8_condition) {
+  if (!v8_condition) {
+    // No condition configured.
+    return absl::nullopt;
+  }
+  if (!v8_condition->hasRunningStatus()) {
+    return absl::nullopt;
+  }
+
+  blink::ServiceWorkerRouterRunningStatusCondition running_status;
+  switch (v8_condition->runningStatus().AsEnum()) {
+    case blink::V8RunningStatusEnum::Enum::kRunning:
+      running_status.status = blink::ServiceWorkerRouterRunningStatusCondition::
+          RunningStatusEnum::kRunning;
+      break;
+    case blink::V8RunningStatusEnum::Enum::kNotRunning:
+      running_status.status = blink::ServiceWorkerRouterRunningStatusCondition::
+          RunningStatusEnum::kNotRunning;
+      break;
+  }
+  blink::ServiceWorkerRouterCondition condition;
+  condition.type =
+      blink::ServiceWorkerRouterCondition::ConditionType::kRunningStatus;
+  condition.running_status = std::move(running_status);
+  return condition;
+}
+
 blink::ServiceWorkerRouterSource RouterSourceEnumToBlink(
     blink::V8RouterSourceEnum v8_source_enum) {
   switch (v8_source_enum.AsEnum()) {
@@ -152,6 +180,14 @@
     }
     rule.conditions.emplace_back(*condition);
   }
+  if (input->condition()->hasRunningStatus()) {
+    absl::optional<blink::ServiceWorkerRouterCondition> condition;
+    condition = RouterRunningStatusConditionToBlink(input->condition());
+    if (!condition) {
+      return absl::nullopt;
+    }
+    rule.conditions.emplace_back(*condition);
+  }
   if (rule.conditions.empty()) {
     // At least one condition should exist per rule.
     return absl::nullopt;
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter_test.cc b/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter_test.cc
index 0b37588..108107d 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter_test.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_router_type_converter_test.cc
@@ -209,6 +209,45 @@
   validate_normalize("anythingElse", "anythingElse");
 }
 
+TEST(ServiceWorkerRouterTypeConverterTest, RunningStatus) {
+  auto verify =
+      [](blink::V8RunningStatusEnum::Enum idl_status,
+         blink::ServiceWorkerRouterRunningStatusCondition::RunningStatusEnum
+             blink_status) {
+        auto* idl_rule = blink::RouterRule::Create();
+        auto* idl_condition = blink::RouterCondition::Create();
+        idl_condition->setRunningStatus(idl_status);
+        idl_rule->setCondition(idl_condition);
+        idl_rule->setSource(blink::V8RouterSourceEnum::Enum::kNetwork);
+
+        blink::ServiceWorkerRouterRule expected_rule;
+        blink::ServiceWorkerRouterCondition expected_condition;
+        expected_condition.type =
+            blink::ServiceWorkerRouterCondition::ConditionType::kRunningStatus;
+        blink::ServiceWorkerRouterRunningStatusCondition expected_status;
+        expected_status.status = blink_status;
+        expected_condition.running_status = std::move(expected_status);
+        expected_rule.conditions.emplace_back(expected_condition);
+        blink::ServiceWorkerRouterSource expected_source;
+        expected_source.type =
+            blink::ServiceWorkerRouterSource::SourceType::kNetwork;
+        expected_source.network_source.emplace();
+        expected_rule.sources.emplace_back(expected_source);
+
+        auto blink_rule =
+            mojo::ConvertTo<absl::optional<blink::ServiceWorkerRouterRule>>(
+                idl_rule);
+        EXPECT_TRUE(blink_rule.has_value());
+        EXPECT_EQ(expected_rule, *blink_rule);
+      };
+  verify(blink::V8RunningStatusEnum::Enum::kRunning,
+         blink::ServiceWorkerRouterRunningStatusCondition::RunningStatusEnum::
+             kRunning);
+  verify(blink::V8RunningStatusEnum::Enum::kNotRunning,
+         blink::ServiceWorkerRouterRunningStatusCondition::RunningStatusEnum::
+             kNotRunning);
+}
+
 }  // namespace
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 7f0066c7f..de426b2 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1224,9 +1224,9 @@
       status: "stable",
     },
     {
-      // https://github.com/whatwg/html/pull/9195
+      // https://html.spec.whatwg.org/#dom-customelementregistry-getname
       name: "CustomElementsGetName",
-      status: "experimental",
+      status: "stable",
     },
     {
       name: "Database",
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 19002e0c..eee8396 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -6440,12 +6440,12 @@
 # Flaky test
 crbug.com/1454689 http/tests/inspector-protocol/tracing/cpu-profiling.js [ Failure Pass ]
 
-crbug.com/1455245 [ Mac ] virtual/fedcm-multi-idp/external/wpt/credential-management/fedcm-multi-idp/abort-multiple-gets-through-first-idp.https.html [ Failure Pass ]
+crbug.com/1455245 [ Mac ] virtual/fedcm-multi-idp/external/wpt/credential-management/fedcm-multi-idp/abort-multiple-gets-through-first-idp.https.html [ Crash Failure Pass ]
 crbug.com/1455245 [ Mac ] virtual/fedcm-multi-idp/external/wpt/credential-management/fedcm-multi-idp/abort-multiple-gets-through-second-idp.https.html [ Crash Failure Pass ]
 crbug.com/1455245 [ Mac ] virtual/fedcm-multi-idp/external/wpt/credential-management/fedcm-multi-idp/get-before-and-after-onload.https.html [ Failure Pass ]
 crbug.com/1455245 [ Mac ] virtual/fedcm-multi-idp/external/wpt/credential-management/fedcm-multi-idp/get-before-and-during-onload.https.html [ Failure Pass ]
 crbug.com/1455245 [ Mac ] virtual/fedcm-multi-idp/external/wpt/credential-management/fedcm-multi-idp/get-before-onload-and-during-dom-content-loaded.https.html [ Failure Pass ]
-crbug.com/1455245 [ Mac ] virtual/fedcm-multi-idp/external/wpt/credential-management/fedcm-multi-idp/multiple-gets-after-abort.https.html [ Failure Pass ]
+crbug.com/1455245 [ Mac ] virtual/fedcm-multi-idp/external/wpt/credential-management/fedcm-multi-idp/multiple-gets-after-abort.https.html [ Crash Failure Pass ]
 crbug.com/1455245 [ Mac ] virtual/fedcm-multi-idp/external/wpt/credential-management/fedcm-multi-idp/multiple-gets-after-onload.https.html [ Failure Pass ]
 crbug.com/1455245 [ Mac ] virtual/fedcm-multi-idp/external/wpt/credential-management/fedcm-multi-idp/multiple-gets-before-onload.https.html [ Failure Pass ]
 crbug.com/1455245 [ Mac ] virtual/fedcm-multi-idp/external/wpt/credential-management/fedcm-multi-idp/multiple-gets-during-onload.https.html [ Failure Pass ]
@@ -6562,3 +6562,6 @@
 
 # This test is unreliable because of delayed update of history.length during cross-document navigation.
 crbug.com/1466474 fast/history/history-back-twice-with-subframes-assert.html [ Pass Timeout ]
+
+# Gardener 2023-07-24
+crbug.com/1466702 [ Mac ] inspector-protocol/debugger/debugger-evaluate-in-worker-while-pause-in-page.js [ Pass Failure Timeout ]
diff --git a/third_party/blink/web_tests/fast/url/ipv6-expected.txt b/third_party/blink/web_tests/fast/url/ipv6-expected.txt
index 9bed86b..a25d0f57 100644
--- a/third_party/blink/web_tests/fast/url/ipv6-expected.txt
+++ b/third_party/blink/web_tests/fast/url/ipv6-expected.txt
@@ -23,7 +23,7 @@
 FAIL canonicalize('http://[::eeee:192.168.0.1]/') should be http://[::eeee:192.168.0.1]/. Was http://[::eeee:c0a8:1]/.
 FAIL canonicalize('http://[2001::192.168.0.1]/') should be http://[2001::192.168.0.1]/. Was http://[2001::c0a8:1]/.
 PASS canonicalize('http://[1:2:192.168.0.1:5:6]/') is 'http://[1:2:192.168.0.1:5:6]/'
-PASS canonicalize('http://[::ffff:192.1.2]/') is 'http://[::ffff:c001:2]/'
+PASS canonicalize('http://[::ffff:192.1.2]/') is 'http://[::ffff:192.1.2]/'
 PASS canonicalize('http://[::ffff:0xC0.0Xa8.0x0.0x1]/') is 'http://[::ffff:c0a8:1]/'
 PASS canonicalize('http://[0:0::0:0:8]/') is 'http://[::8]/'
 PASS canonicalize('http://[2001:db8::1]/') is 'http://[2001:db8::1]/'
diff --git a/third_party/blink/web_tests/fast/url/script-tests/ipv6.js b/third_party/blink/web_tests/fast/url/script-tests/ipv6.js
index bc007a9..37c3a015e 100644
--- a/third_party/blink/web_tests/fast/url/script-tests/ipv6.js
+++ b/third_party/blink/web_tests/fast/url/script-tests/ipv6.js
@@ -38,7 +38,7 @@
     ["[1:2:192.168.0.1:5:6]", ""],
 
     // IPv4 with last component missing.
-    ["[::ffff:192.1.2]", "[::ffff:c001:2]"],
+    ["[::ffff:192.1.2]", ""],
 
     // IPv4 using hex.
     // FIXME: Should this format be disallowed?
diff --git "a/third_party/blink/web_tests/flag-specific/highdpi/external/wpt/url/a-element_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/flag-specific/highdpi/external/wpt/url/a-element_exclude=\050file_javascript_mailto\051-expected.txt"
index b7fd1da..ded51f6 100644
--- "a/third_party/blink/web_tests/flag-specific/highdpi/external/wpt/url/a-element_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/flag-specific/highdpi/external/wpt/url/a-element_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -75,7 +75,7 @@
 FAIL Parsing: <http://2001::1]:80> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://2001::1]:80" but got "http://2001::1]/"
 PASS Parsing: <http://[2001::1]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[::127.0.0.1]> against <http://example.org/foo/bar>
-FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://[::127.0.0.1.]" but got "http://[::127.0.0.1.]/"
 PASS Parsing: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http:/example.com/> against <http://example.org/foo/bar>
@@ -270,10 +270,10 @@
 PASS Parsing: <http://[www.google.com]/> against <about:blank>
 FAIL Parsing: <http://[google.com]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[google.com]" but got "http://[google.com]/"
 FAIL Parsing: <http://[::1.2.3.4x]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.4x]" but got "http://[::1.2.3.4x]/"
-FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
-FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.]" but got "http://[::1.2.3.]/"
+FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.]" but got "http://[::1.2.]/"
 FAIL Parsing: <http://[::.1.2]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::.1.2]" but got "http://[::.1.2]/"
-FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.]" but got "http://[::1.]/"
 FAIL Parsing: <http://[::.1]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::.1]" but got "http://[::.1]/"
 FAIL Parsing: <http://[::%31]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
 FAIL Parsing: <http://%5B::1]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
diff --git "a/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-xhtml_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-xhtml_exclude=\050file_javascript_mailto\051-expected.txt"
index b7fd1da..ded51f6 100644
--- "a/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-xhtml_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element-xhtml_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -75,7 +75,7 @@
 FAIL Parsing: <http://2001::1]:80> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://2001::1]:80" but got "http://2001::1]/"
 PASS Parsing: <http://[2001::1]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[::127.0.0.1]> against <http://example.org/foo/bar>
-FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://[::127.0.0.1.]" but got "http://[::127.0.0.1.]/"
 PASS Parsing: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http:/example.com/> against <http://example.org/foo/bar>
@@ -270,10 +270,10 @@
 PASS Parsing: <http://[www.google.com]/> against <about:blank>
 FAIL Parsing: <http://[google.com]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[google.com]" but got "http://[google.com]/"
 FAIL Parsing: <http://[::1.2.3.4x]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.4x]" but got "http://[::1.2.3.4x]/"
-FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
-FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.]" but got "http://[::1.2.3.]/"
+FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.]" but got "http://[::1.2.]/"
 FAIL Parsing: <http://[::.1.2]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::.1.2]" but got "http://[::.1.2]/"
-FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.]" but got "http://[::1.]/"
 FAIL Parsing: <http://[::.1]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::.1]" but got "http://[::.1]/"
 FAIL Parsing: <http://[::%31]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
 FAIL Parsing: <http://%5B::1]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
diff --git "a/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element_exclude=\050file_javascript_mailto\051-expected.txt"
index b7fd1da..ded51f6 100644
--- "a/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/linux/external/wpt/url/a-element_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -75,7 +75,7 @@
 FAIL Parsing: <http://2001::1]:80> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://2001::1]:80" but got "http://2001::1]/"
 PASS Parsing: <http://[2001::1]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[::127.0.0.1]> against <http://example.org/foo/bar>
-FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://[::127.0.0.1.]" but got "http://[::127.0.0.1.]/"
 PASS Parsing: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http:/example.com/> against <http://example.org/foo/bar>
@@ -270,10 +270,10 @@
 PASS Parsing: <http://[www.google.com]/> against <about:blank>
 FAIL Parsing: <http://[google.com]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[google.com]" but got "http://[google.com]/"
 FAIL Parsing: <http://[::1.2.3.4x]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.4x]" but got "http://[::1.2.3.4x]/"
-FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
-FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.]" but got "http://[::1.2.3.]/"
+FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.]" but got "http://[::1.2.]/"
 FAIL Parsing: <http://[::.1.2]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::.1.2]" but got "http://[::.1.2]/"
-FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.]" but got "http://[::1.]/"
 FAIL Parsing: <http://[::.1]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::.1]" but got "http://[::.1]/"
 FAIL Parsing: <http://[::%31]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
 FAIL Parsing: <http://%5B::1]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
diff --git "a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-constructor.any.worker_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-constructor.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
index be91e5b..cf0313b 100644
--- "a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-constructor.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-constructor.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 674 tests; 501 PASS, 173 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 674 tests; 505 PASS, 169 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -77,9 +77,7 @@
 PASS Parsing: <http://2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[::127.0.0.1]> against <http://example.org/foo/bar>
-FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http:/example.com/> against <http://example.org/foo/bar>
@@ -300,16 +298,10 @@
 PASS Parsing: <http://[www.google.com]/> without base
 PASS Parsing: <http://[google.com]> against <http://other.com/>
 PASS Parsing: <http://[::1.2.3.4x]> against <http://other.com/>
-FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
-FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::1.2.3.]> against <http://other.com/>
+PASS Parsing: <http://[::1.2.]> against <http://other.com/>
 PASS Parsing: <http://[::.1.2]> against <http://other.com/>
-FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::1.]> against <http://other.com/>
 PASS Parsing: <http://[::.1]> against <http://other.com/>
 FAIL Parsing: <http://[::%31]> against <http://other.com/> assert_throws_js: function "function() {
           new URL(expected.input, base);
diff --git "a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-constructor.any_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-constructor.any_exclude=\050file_javascript_mailto\051-expected.txt"
index be91e5b..cf0313b 100644
--- "a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-constructor.any_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-constructor.any_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 674 tests; 501 PASS, 173 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 674 tests; 505 PASS, 169 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -77,9 +77,7 @@
 PASS Parsing: <http://2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[::127.0.0.1]> against <http://example.org/foo/bar>
-FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http:/example.com/> against <http://example.org/foo/bar>
@@ -300,16 +298,10 @@
 PASS Parsing: <http://[www.google.com]/> without base
 PASS Parsing: <http://[google.com]> against <http://other.com/>
 PASS Parsing: <http://[::1.2.3.4x]> against <http://other.com/>
-FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
-FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::1.2.3.]> against <http://other.com/>
+PASS Parsing: <http://[::1.2.]> against <http://other.com/>
 PASS Parsing: <http://[::.1.2]> against <http://other.com/>
-FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::1.]> against <http://other.com/>
 PASS Parsing: <http://[::.1]> against <http://other.com/>
 FAIL Parsing: <http://[::%31]> against <http://other.com/> assert_throws_js: function "function() {
           new URL(expected.input, base);
diff --git "a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters-a-area.window_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters-a-area.window_exclude=\050file_javascript_mailto\051-expected.txt"
index 1ad4428..5234a93f 100644
--- "a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters-a-area.window_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters-a-area.window_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 443 tests; 287 PASS, 156 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 443 tests; 299 PASS, 144 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS <a>: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged.
 PASS <area>: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged.
@@ -181,12 +181,12 @@
 PASS <area>: Setting <http://example.net/>.host = '[google.com]' Broken IPv6
 PASS <a>: Setting <http://example.net/>.host = '[::1.2.3.4x]'
 PASS <area>: Setting <http://example.net/>.host = '[::1.2.3.4x]'
-FAIL <a>: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL <area>: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL <a>: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL <area>: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL <a>: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
-FAIL <area>: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS <a>: Setting <http://example.net/>.host = '[::1.2.3.]'
+PASS <area>: Setting <http://example.net/>.host = '[::1.2.3.]'
+PASS <a>: Setting <http://example.net/>.host = '[::1.2.]'
+PASS <area>: Setting <http://example.net/>.host = '[::1.2.]'
+PASS <a>: Setting <http://example.net/>.host = '[::1.]'
+PASS <area>: Setting <http://example.net/>.host = '[::1.]'
 FAIL <a>: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got ""
 FAIL <area>: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got ""
 FAIL <a>: Setting <sc://test:12/>.host = '' assert_equals: expected "test:12" but got ""
@@ -255,12 +255,12 @@
 PASS <area>: Setting <http://example.net/>.hostname = '[google.com]' Broken IPv6
 PASS <a>: Setting <http://example.net/>.hostname = '[::1.2.3.4x]'
 PASS <area>: Setting <http://example.net/>.hostname = '[::1.2.3.4x]'
-FAIL <a>: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL <area>: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL <a>: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL <area>: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL <a>: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
-FAIL <area>: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS <a>: Setting <http://example.net/>.hostname = '[::1.2.3.]'
+PASS <area>: Setting <http://example.net/>.hostname = '[::1.2.3.]'
+PASS <a>: Setting <http://example.net/>.hostname = '[::1.2.]'
+PASS <area>: Setting <http://example.net/>.hostname = '[::1.2.]'
+PASS <a>: Setting <http://example.net/>.hostname = '[::1.]'
+PASS <area>: Setting <http://example.net/>.hostname = '[::1.]'
 FAIL <a>: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got ""
 FAIL <area>: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got ""
 FAIL <a>: Setting <sc://test:12/>.hostname = '' assert_equals: expected "test:12" but got ""
diff --git "a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
index f0ef429..03ddbd8 100644
--- "a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 222 tests; 140 PASS, 82 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 222 tests; 146 PASS, 76 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS URL: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged.
 PASS URL: Setting <a://example.net>.protocol = 'b'
@@ -91,9 +91,9 @@
 PASS URL: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.
 PASS URL: Setting <http://example.net/>.host = '[google.com]' Broken IPv6
 PASS URL: Setting <http://example.net/>.host = '[::1.2.3.4x]'
-FAIL URL: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL URL: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL URL: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS URL: Setting <http://example.net/>.host = '[::1.2.3.]'
+PASS URL: Setting <http://example.net/>.host = '[::1.2.]'
+PASS URL: Setting <http://example.net/>.host = '[::1.]'
 FAIL URL: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got ""
 FAIL URL: Setting <sc://test:12/>.host = '' assert_equals: expected "test:12" but got ""
 PASS URL: Setting <http://example.com/>.host = '///bad.com' Leading / is not stripped
@@ -128,9 +128,9 @@
 FAIL URL: Setting <view-source+http://example.net/path>.hostname = 'example.com\stuff' \ is not a delimiter for non-special schemes, but still forbidden in hosts assert_equals: expected "example.net" but got ""
 PASS URL: Setting <http://example.net/>.hostname = '[google.com]' Broken IPv6
 PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.4x]'
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.]'
+PASS URL: Setting <http://example.net/>.hostname = '[::1.2.]'
+PASS URL: Setting <http://example.net/>.hostname = '[::1.]'
 FAIL URL: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got ""
 FAIL URL: Setting <sc://test:12/>.hostname = '' assert_equals: expected "test:12" but got ""
 FAIL URL: Setting <non-spec:/.//p>.hostname = 'h' Drop /. from path assert_equals: expected "non-spec://h//p" but got "non-spec:/.//p"
diff --git "a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt"
index f0ef429..03ddbd8 100644
--- "a/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/linux/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 222 tests; 140 PASS, 82 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 222 tests; 146 PASS, 76 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS URL: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged.
 PASS URL: Setting <a://example.net>.protocol = 'b'
@@ -91,9 +91,9 @@
 PASS URL: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.
 PASS URL: Setting <http://example.net/>.host = '[google.com]' Broken IPv6
 PASS URL: Setting <http://example.net/>.host = '[::1.2.3.4x]'
-FAIL URL: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL URL: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL URL: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS URL: Setting <http://example.net/>.host = '[::1.2.3.]'
+PASS URL: Setting <http://example.net/>.host = '[::1.2.]'
+PASS URL: Setting <http://example.net/>.host = '[::1.]'
 FAIL URL: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got ""
 FAIL URL: Setting <sc://test:12/>.host = '' assert_equals: expected "test:12" but got ""
 PASS URL: Setting <http://example.com/>.host = '///bad.com' Leading / is not stripped
@@ -128,9 +128,9 @@
 FAIL URL: Setting <view-source+http://example.net/path>.hostname = 'example.com\stuff' \ is not a delimiter for non-special schemes, but still forbidden in hosts assert_equals: expected "example.net" but got ""
 PASS URL: Setting <http://example.net/>.hostname = '[google.com]' Broken IPv6
 PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.4x]'
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.]'
+PASS URL: Setting <http://example.net/>.hostname = '[::1.2.]'
+PASS URL: Setting <http://example.net/>.hostname = '[::1.]'
 FAIL URL: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got ""
 FAIL URL: Setting <sc://test:12/>.hostname = '' assert_equals: expected "test:12" but got ""
 FAIL URL: Setting <non-spec:/.//p>.hostname = 'h' Drop /. from path assert_equals: expected "non-spec://h//p" but got "non-spec:/.//p"
diff --git "a/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/a-element-xhtml_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/a-element-xhtml_exclude=\050file_javascript_mailto\051-expected.txt"
index d5389e82..e9547054 100644
--- "a/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/a-element-xhtml_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/a-element-xhtml_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -75,7 +75,7 @@
 FAIL Parsing: <http://2001::1]:80> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://2001::1]:80" but got "http://2001::1]/"
 PASS Parsing: <http://[2001::1]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[::127.0.0.1]> against <http://example.org/foo/bar>
-FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://[::127.0.0.1.]" but got "http://[::127.0.0.1.]/"
 PASS Parsing: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http:/example.com/> against <http://example.org/foo/bar>
@@ -270,10 +270,10 @@
 PASS Parsing: <http://[www.google.com]/> against <about:blank>
 FAIL Parsing: <http://[google.com]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[google.com]" but got "http://[google.com]/"
 FAIL Parsing: <http://[::1.2.3.4x]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.4x]" but got "http://[::1.2.3.4x]/"
-FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
-FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.]" but got "http://[::1.2.3.]/"
+FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.]" but got "http://[::1.2.]/"
 FAIL Parsing: <http://[::.1.2]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::.1.2]" but got "http://[::.1.2]/"
-FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.]" but got "http://[::1.]/"
 FAIL Parsing: <http://[::.1]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::.1]" but got "http://[::.1]/"
 FAIL Parsing: <http://[::%31]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
 FAIL Parsing: <http://%5B::1]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
diff --git "a/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/a-element_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/a-element_exclude=\050file_javascript_mailto\051-expected.txt"
index d5389e82..e9547054 100644
--- "a/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/a-element_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/a-element_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -75,7 +75,7 @@
 FAIL Parsing: <http://2001::1]:80> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://2001::1]:80" but got "http://2001::1]/"
 PASS Parsing: <http://[2001::1]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[::127.0.0.1]> against <http://example.org/foo/bar>
-FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://[::127.0.0.1.]" but got "http://[::127.0.0.1.]/"
 PASS Parsing: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http:/example.com/> against <http://example.org/foo/bar>
@@ -270,10 +270,10 @@
 PASS Parsing: <http://[www.google.com]/> against <about:blank>
 FAIL Parsing: <http://[google.com]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[google.com]" but got "http://[google.com]/"
 FAIL Parsing: <http://[::1.2.3.4x]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.4x]" but got "http://[::1.2.3.4x]/"
-FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
-FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.]" but got "http://[::1.2.3.]/"
+FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.]" but got "http://[::1.2.]/"
 FAIL Parsing: <http://[::.1.2]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::.1.2]" but got "http://[::.1.2]/"
-FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.]" but got "http://[::1.]/"
 FAIL Parsing: <http://[::.1]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::.1]" but got "http://[::.1]/"
 FAIL Parsing: <http://[::%31]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
 FAIL Parsing: <http://%5B::1]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
diff --git "a/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/url-constructor.any.worker_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/url-constructor.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
index d512fa3..0b414ce 100644
--- "a/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/url-constructor.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/url-constructor.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 674 tests; 500 PASS, 174 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 674 tests; 504 PASS, 170 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -77,9 +77,7 @@
 PASS Parsing: <http://2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[::127.0.0.1]> against <http://example.org/foo/bar>
-FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http:/example.com/> against <http://example.org/foo/bar>
@@ -300,16 +298,10 @@
 PASS Parsing: <http://[www.google.com]/> without base
 PASS Parsing: <http://[google.com]> against <http://other.com/>
 PASS Parsing: <http://[::1.2.3.4x]> against <http://other.com/>
-FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
-FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::1.2.3.]> against <http://other.com/>
+PASS Parsing: <http://[::1.2.]> against <http://other.com/>
 PASS Parsing: <http://[::.1.2]> against <http://other.com/>
-FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::1.]> against <http://other.com/>
 PASS Parsing: <http://[::.1]> against <http://other.com/>
 FAIL Parsing: <http://[::%31]> against <http://other.com/> assert_throws_js: function "function() {
           new URL(expected.input, base);
diff --git "a/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/url-constructor.any_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/url-constructor.any_exclude=\050file_javascript_mailto\051-expected.txt"
index d512fa3..0b414ce 100644
--- "a/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/url-constructor.any_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/url-constructor.any_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 674 tests; 500 PASS, 174 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 674 tests; 504 PASS, 170 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -77,9 +77,7 @@
 PASS Parsing: <http://2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[::127.0.0.1]> against <http://example.org/foo/bar>
-FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http:/example.com/> against <http://example.org/foo/bar>
@@ -300,16 +298,10 @@
 PASS Parsing: <http://[www.google.com]/> without base
 PASS Parsing: <http://[google.com]> against <http://other.com/>
 PASS Parsing: <http://[::1.2.3.4x]> against <http://other.com/>
-FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
-FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::1.2.3.]> against <http://other.com/>
+PASS Parsing: <http://[::1.2.]> against <http://other.com/>
 PASS Parsing: <http://[::.1.2]> against <http://other.com/>
-FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::1.]> against <http://other.com/>
 PASS Parsing: <http://[::.1]> against <http://other.com/>
 FAIL Parsing: <http://[::%31]> against <http://other.com/> assert_throws_js: function "function() {
           new URL(expected.input, base);
diff --git "a/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/url-setters-a-area.window_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/url-setters-a-area.window_exclude=\050file_javascript_mailto\051-expected.txt"
index c7c8809..cf1d29ee 100644
--- "a/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/url-setters-a-area.window_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/url-setters-a-area.window_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 443 tests; 285 PASS, 158 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 443 tests; 297 PASS, 146 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS <a>: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged.
 PASS <area>: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged.
@@ -181,12 +181,12 @@
 PASS <area>: Setting <http://example.net/>.host = '[google.com]' Broken IPv6
 PASS <a>: Setting <http://example.net/>.host = '[::1.2.3.4x]'
 PASS <area>: Setting <http://example.net/>.host = '[::1.2.3.4x]'
-FAIL <a>: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL <area>: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL <a>: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL <area>: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL <a>: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
-FAIL <area>: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS <a>: Setting <http://example.net/>.host = '[::1.2.3.]'
+PASS <area>: Setting <http://example.net/>.host = '[::1.2.3.]'
+PASS <a>: Setting <http://example.net/>.host = '[::1.2.]'
+PASS <area>: Setting <http://example.net/>.host = '[::1.2.]'
+PASS <a>: Setting <http://example.net/>.host = '[::1.]'
+PASS <area>: Setting <http://example.net/>.host = '[::1.]'
 FAIL <a>: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got ""
 FAIL <area>: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got ""
 FAIL <a>: Setting <sc://test:12/>.host = '' assert_equals: expected "test:12" but got ""
@@ -255,12 +255,12 @@
 PASS <area>: Setting <http://example.net/>.hostname = '[google.com]' Broken IPv6
 PASS <a>: Setting <http://example.net/>.hostname = '[::1.2.3.4x]'
 PASS <area>: Setting <http://example.net/>.hostname = '[::1.2.3.4x]'
-FAIL <a>: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL <area>: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL <a>: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL <area>: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL <a>: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
-FAIL <area>: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS <a>: Setting <http://example.net/>.hostname = '[::1.2.3.]'
+PASS <area>: Setting <http://example.net/>.hostname = '[::1.2.3.]'
+PASS <a>: Setting <http://example.net/>.hostname = '[::1.2.]'
+PASS <area>: Setting <http://example.net/>.hostname = '[::1.2.]'
+PASS <a>: Setting <http://example.net/>.hostname = '[::1.]'
+PASS <area>: Setting <http://example.net/>.hostname = '[::1.]'
 FAIL <a>: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got ""
 FAIL <area>: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got ""
 FAIL <a>: Setting <sc://test:12/>.hostname = '' assert_equals: expected "test:12" but got ""
diff --git "a/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
index 990f6ed..0645b0590 100644
--- "a/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 222 tests; 139 PASS, 83 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 222 tests; 145 PASS, 77 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS URL: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged.
 PASS URL: Setting <a://example.net>.protocol = 'b'
@@ -91,9 +91,9 @@
 PASS URL: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.
 PASS URL: Setting <http://example.net/>.host = '[google.com]' Broken IPv6
 PASS URL: Setting <http://example.net/>.host = '[::1.2.3.4x]'
-FAIL URL: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL URL: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL URL: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS URL: Setting <http://example.net/>.host = '[::1.2.3.]'
+PASS URL: Setting <http://example.net/>.host = '[::1.2.]'
+PASS URL: Setting <http://example.net/>.host = '[::1.]'
 FAIL URL: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got ""
 FAIL URL: Setting <sc://test:12/>.host = '' assert_equals: expected "test:12" but got ""
 PASS URL: Setting <http://example.com/>.host = '///bad.com' Leading / is not stripped
@@ -128,9 +128,9 @@
 FAIL URL: Setting <view-source+http://example.net/path>.hostname = 'example.com\stuff' \ is not a delimiter for non-special schemes, but still forbidden in hosts assert_equals: expected "example.net" but got ""
 PASS URL: Setting <http://example.net/>.hostname = '[google.com]' Broken IPv6
 PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.4x]'
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.]'
+PASS URL: Setting <http://example.net/>.hostname = '[::1.2.]'
+PASS URL: Setting <http://example.net/>.hostname = '[::1.]'
 FAIL URL: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got ""
 FAIL URL: Setting <sc://test:12/>.hostname = '' assert_equals: expected "test:12" but got ""
 FAIL URL: Setting <non-spec:/.//p>.hostname = 'h' Drop /. from path assert_equals: expected "non-spec://h//p" but got "non-spec:/.//p"
diff --git "a/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt"
index 990f6ed..0645b0590 100644
--- "a/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/linux/virtual/idna-2008/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 222 tests; 139 PASS, 83 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 222 tests; 145 PASS, 77 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS URL: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged.
 PASS URL: Setting <a://example.net>.protocol = 'b'
@@ -91,9 +91,9 @@
 PASS URL: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.
 PASS URL: Setting <http://example.net/>.host = '[google.com]' Broken IPv6
 PASS URL: Setting <http://example.net/>.host = '[::1.2.3.4x]'
-FAIL URL: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL URL: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL URL: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS URL: Setting <http://example.net/>.host = '[::1.2.3.]'
+PASS URL: Setting <http://example.net/>.host = '[::1.2.]'
+PASS URL: Setting <http://example.net/>.host = '[::1.]'
 FAIL URL: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got ""
 FAIL URL: Setting <sc://test:12/>.host = '' assert_equals: expected "test:12" but got ""
 PASS URL: Setting <http://example.com/>.host = '///bad.com' Leading / is not stripped
@@ -128,9 +128,9 @@
 FAIL URL: Setting <view-source+http://example.net/path>.hostname = 'example.com\stuff' \ is not a delimiter for non-special schemes, but still forbidden in hosts assert_equals: expected "example.net" but got ""
 PASS URL: Setting <http://example.net/>.hostname = '[google.com]' Broken IPv6
 PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.4x]'
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.]'
+PASS URL: Setting <http://example.net/>.hostname = '[::1.2.]'
+PASS URL: Setting <http://example.net/>.hostname = '[::1.]'
 FAIL URL: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got ""
 FAIL URL: Setting <sc://test:12/>.hostname = '' assert_equals: expected "test:12" but got ""
 FAIL URL: Setting <non-spec:/.//p>.hostname = 'h' Drop /. from path assert_equals: expected "non-spec://h//p" but got "non-spec:/.//p"
diff --git a/third_party/blink/web_tests/platform/linux/virtual/strict-ipv4-embedded-ipv6/fast/url/ipv6-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/strict-ipv4-embedded-ipv6/fast/url/ipv6-expected.txt
deleted file mode 100644
index 4119c7b..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/strict-ipv4-embedded-ipv6/fast/url/ipv6-expected.txt
+++ /dev/null
@@ -1,56 +0,0 @@
-Canonicalization of IPv6 addresses.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS canonicalize('http://[/') is 'http://[/'
-PASS canonicalize('http://[:/') is 'http://[:/'
-PASS canonicalize('http://]/') is 'http://]/'
-PASS canonicalize('http://:]/') is 'http://:]/'
-PASS canonicalize('http://[]/') is 'http://[]/'
-PASS canonicalize('http://[:]/') is 'http://[:]/'
-PASS canonicalize('http://2001:db8::1/') is 'http://2001:db8::1/'
-PASS canonicalize('http://[2001:db8::1/') is 'http://[2001:db8::1/'
-PASS canonicalize('http://2001:db8::1]/') is 'http://2001:db8::1]/'
-PASS canonicalize('http://[::]/') is 'http://[::]/'
-PASS canonicalize('http://[::1]/') is 'http://[::1]/'
-PASS canonicalize('http://[1::]/') is 'http://[1::]/'
-PASS canonicalize('http://[::192.168.0.1]/') is 'http://[::c0a8:1]/'
-PASS canonicalize('http://[::ffff:192.168.0.1]/') is 'http://[::ffff:c0a8:1]/'
-PASS canonicalize('http://[000:01:02:003:004:5:6:007]/') is 'http://[0:1:2:3:4:5:6:7]/'
-PASS canonicalize('http://[A:b:c:DE:fF:0:1:aC]/') is 'http://[a:b:c:de:ff:0:1:ac]/'
-PASS canonicalize('http://[1:0:0:2::3:0]/') is 'http://[1::2:0:0:3:0]/'
-PASS canonicalize('http://[1::2:0:0:3:0]/') is 'http://[1::2:0:0:3:0]/'
-FAIL canonicalize('http://[::eeee:192.168.0.1]/') should be http://[::eeee:192.168.0.1]/. Was http://[::eeee:c0a8:1]/.
-FAIL canonicalize('http://[2001::192.168.0.1]/') should be http://[2001::192.168.0.1]/. Was http://[2001::c0a8:1]/.
-PASS canonicalize('http://[1:2:192.168.0.1:5:6]/') is 'http://[1:2:192.168.0.1:5:6]/'
-FAIL canonicalize('http://[::ffff:192.1.2]/') should be http://[::ffff:c001:2]/. Was http://[::ffff:192.1.2]/.
-PASS canonicalize('http://[::ffff:0xC0.0Xa8.0x0.0x1]/') is 'http://[::ffff:c0a8:1]/'
-PASS canonicalize('http://[0:0::0:0:8]/') is 'http://[::8]/'
-PASS canonicalize('http://[2001:db8::1]/') is 'http://[2001:db8::1]/'
-PASS canonicalize('http://[2001::db8::1]/') is 'http://[2001::db8::1]/'
-PASS canonicalize('http://[2001:db8:::1]/') is 'http://[2001:db8:::1]/'
-PASS canonicalize('http://[:::]/') is 'http://[:::]/'
-PASS canonicalize('http://[2001::.com]/') is 'http://[2001::.com]/'
-PASS canonicalize('http://[::192.168.0.0.1]/') is 'http://[::192.168.0.0.1]/'
-PASS canonicalize('http://[::ffff:192.168.0.0.1]/') is 'http://[::ffff:192.168.0.0.1]/'
-PASS canonicalize('http://[1:2:3:4:5:6:7:8:9]/') is 'http://[1:2:3:4:5:6:7:8:9]/'
-PASS canonicalize('http://[0:0:0:0:0:0:0:192.168.0.1]/') is 'http://[0:0:0:0:0:0:0:192.168.0.1]/'
-PASS canonicalize('http://[1:2:3:4:5:6::192.168.0.1]/') is 'http://[1:2:3:4:5:6::192.168.0.1]/'
-PASS canonicalize('http://[1:2:3:4:5:6::8]/') is 'http://[1:2:3:4:5:6:0:8]/'
-PASS canonicalize('http://[1:2:3:4:5:6:7:8:]/') is 'http://[1:2:3:4:5:6:7:8:]/'
-PASS canonicalize('http://[1:2:3:4:5:6:192.168.0.1:]/') is 'http://[1:2:3:4:5:6:192.168.0.1:]/'
-PASS canonicalize('http://[-1:2:3:4:5:6:7:8]/') is 'http://[-1:2:3:4:5:6:7:8]/'
-FAIL canonicalize('http://[1::%1]/') should be http://[1::%1]/. Was http://[1::%251]/.
-FAIL canonicalize('http://[1::%eth0]/') should be http://[1::%eth0]/. Was http://[1::%25eth0]/.
-FAIL canonicalize('http://[1::%]/') should be http://[1::%]/. Was http://[1::%25]/.
-FAIL canonicalize('http://[%]/') should be http://[%]/. Was http://[%25]/.
-FAIL canonicalize('http://[::%:]/') should be http://[::%:]/. Was http://[::%25:]/.
-PASS canonicalize('http://[:0:0::0:0:8]/') is 'http://[:0:0::0:0:8]/'
-PASS canonicalize('http://[0:0::0:0:8:]/') is 'http://[0:0::0:0:8:]/'
-PASS canonicalize('http://[:0:0::0:0:8:]/') is 'http://[:0:0::0:0:8:]/'
-PASS canonicalize('http://[::192.168..1]/') is 'http://[::192.168..1]/'
-FAIL canonicalize('http://[::1 hello]/') should be http://[::1 hello]/. Was http://[::1%20hello]/.
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git "a/third_party/blink/web_tests/platform/linux/virtual/url-port-overflow/external/wpt/url/url-setters-a-area.window_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/linux/virtual/url-port-overflow/external/wpt/url/url-setters-a-area.window_exclude=\050file_javascript_mailto\051-expected.txt"
index 371b4cc4..d040b85 100644
--- "a/third_party/blink/web_tests/platform/linux/virtual/url-port-overflow/external/wpt/url/url-setters-a-area.window_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/linux/virtual/url-port-overflow/external/wpt/url/url-setters-a-area.window_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 443 tests; 289 PASS, 154 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 443 tests; 301 PASS, 142 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS <a>: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged.
 PASS <area>: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged.
@@ -181,12 +181,12 @@
 PASS <area>: Setting <http://example.net/>.host = '[google.com]' Broken IPv6
 PASS <a>: Setting <http://example.net/>.host = '[::1.2.3.4x]'
 PASS <area>: Setting <http://example.net/>.host = '[::1.2.3.4x]'
-FAIL <a>: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL <area>: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL <a>: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL <area>: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL <a>: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
-FAIL <area>: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS <a>: Setting <http://example.net/>.host = '[::1.2.3.]'
+PASS <area>: Setting <http://example.net/>.host = '[::1.2.3.]'
+PASS <a>: Setting <http://example.net/>.host = '[::1.2.]'
+PASS <area>: Setting <http://example.net/>.host = '[::1.2.]'
+PASS <a>: Setting <http://example.net/>.host = '[::1.]'
+PASS <area>: Setting <http://example.net/>.host = '[::1.]'
 FAIL <a>: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got ""
 FAIL <area>: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got ""
 FAIL <a>: Setting <sc://test:12/>.host = '' assert_equals: expected "test:12" but got ""
@@ -255,12 +255,12 @@
 PASS <area>: Setting <http://example.net/>.hostname = '[google.com]' Broken IPv6
 PASS <a>: Setting <http://example.net/>.hostname = '[::1.2.3.4x]'
 PASS <area>: Setting <http://example.net/>.hostname = '[::1.2.3.4x]'
-FAIL <a>: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL <area>: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL <a>: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL <area>: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL <a>: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
-FAIL <area>: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS <a>: Setting <http://example.net/>.hostname = '[::1.2.3.]'
+PASS <area>: Setting <http://example.net/>.hostname = '[::1.2.3.]'
+PASS <a>: Setting <http://example.net/>.hostname = '[::1.2.]'
+PASS <area>: Setting <http://example.net/>.hostname = '[::1.2.]'
+PASS <a>: Setting <http://example.net/>.hostname = '[::1.]'
+PASS <area>: Setting <http://example.net/>.hostname = '[::1.]'
 FAIL <a>: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got ""
 FAIL <area>: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got ""
 FAIL <a>: Setting <sc://test:12/>.hostname = '' assert_equals: expected "test:12" but got ""
diff --git "a/third_party/blink/web_tests/platform/linux/virtual/url-port-overflow/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/linux/virtual/url-port-overflow/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
index a8176b1..7041031 100644
--- "a/third_party/blink/web_tests/platform/linux/virtual/url-port-overflow/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/linux/virtual/url-port-overflow/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 222 tests; 141 PASS, 81 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 222 tests; 147 PASS, 75 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS URL: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged.
 PASS URL: Setting <a://example.net>.protocol = 'b'
@@ -91,9 +91,9 @@
 PASS URL: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.
 PASS URL: Setting <http://example.net/>.host = '[google.com]' Broken IPv6
 PASS URL: Setting <http://example.net/>.host = '[::1.2.3.4x]'
-FAIL URL: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL URL: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL URL: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS URL: Setting <http://example.net/>.host = '[::1.2.3.]'
+PASS URL: Setting <http://example.net/>.host = '[::1.2.]'
+PASS URL: Setting <http://example.net/>.host = '[::1.]'
 FAIL URL: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got ""
 FAIL URL: Setting <sc://test:12/>.host = '' assert_equals: expected "test:12" but got ""
 PASS URL: Setting <http://example.com/>.host = '///bad.com' Leading / is not stripped
@@ -128,9 +128,9 @@
 FAIL URL: Setting <view-source+http://example.net/path>.hostname = 'example.com\stuff' \ is not a delimiter for non-special schemes, but still forbidden in hosts assert_equals: expected "example.net" but got ""
 PASS URL: Setting <http://example.net/>.hostname = '[google.com]' Broken IPv6
 PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.4x]'
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.]'
+PASS URL: Setting <http://example.net/>.hostname = '[::1.2.]'
+PASS URL: Setting <http://example.net/>.hostname = '[::1.]'
 FAIL URL: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got ""
 FAIL URL: Setting <sc://test:12/>.hostname = '' assert_equals: expected "test:12" but got ""
 FAIL URL: Setting <non-spec:/.//p>.hostname = 'h' Drop /. from path assert_equals: expected "non-spec://h//p" but got "non-spec:/.//p"
diff --git "a/third_party/blink/web_tests/platform/linux/virtual/url-port-overflow/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/linux/virtual/url-port-overflow/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt"
index a8176b1..7041031 100644
--- "a/third_party/blink/web_tests/platform/linux/virtual/url-port-overflow/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/linux/virtual/url-port-overflow/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 222 tests; 141 PASS, 81 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 222 tests; 147 PASS, 75 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS URL: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged.
 PASS URL: Setting <a://example.net>.protocol = 'b'
@@ -91,9 +91,9 @@
 PASS URL: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.
 PASS URL: Setting <http://example.net/>.host = '[google.com]' Broken IPv6
 PASS URL: Setting <http://example.net/>.host = '[::1.2.3.4x]'
-FAIL URL: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL URL: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL URL: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS URL: Setting <http://example.net/>.host = '[::1.2.3.]'
+PASS URL: Setting <http://example.net/>.host = '[::1.2.]'
+PASS URL: Setting <http://example.net/>.host = '[::1.]'
 FAIL URL: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got ""
 FAIL URL: Setting <sc://test:12/>.host = '' assert_equals: expected "test:12" but got ""
 PASS URL: Setting <http://example.com/>.host = '///bad.com' Leading / is not stripped
@@ -128,9 +128,9 @@
 FAIL URL: Setting <view-source+http://example.net/path>.hostname = 'example.com\stuff' \ is not a delimiter for non-special schemes, but still forbidden in hosts assert_equals: expected "example.net" but got ""
 PASS URL: Setting <http://example.net/>.hostname = '[google.com]' Broken IPv6
 PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.4x]'
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.]'
+PASS URL: Setting <http://example.net/>.hostname = '[::1.2.]'
+PASS URL: Setting <http://example.net/>.hostname = '[::1.]'
 FAIL URL: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got ""
 FAIL URL: Setting <sc://test:12/>.hostname = '' assert_equals: expected "test:12" but got ""
 FAIL URL: Setting <non-spec:/.//p>.hostname = 'h' Drop /. from path assert_equals: expected "non-spec://h//p" but got "non-spec:/.//p"
diff --git "a/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element_exclude=\050file_javascript_mailto\051-expected.txt"
index b7fd1da..ded51f6 100644
--- "a/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/mac/external/wpt/url/a-element_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -75,7 +75,7 @@
 FAIL Parsing: <http://2001::1]:80> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://2001::1]:80" but got "http://2001::1]/"
 PASS Parsing: <http://[2001::1]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[::127.0.0.1]> against <http://example.org/foo/bar>
-FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://[::127.0.0.1.]" but got "http://[::127.0.0.1.]/"
 PASS Parsing: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http:/example.com/> against <http://example.org/foo/bar>
@@ -270,10 +270,10 @@
 PASS Parsing: <http://[www.google.com]/> against <about:blank>
 FAIL Parsing: <http://[google.com]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[google.com]" but got "http://[google.com]/"
 FAIL Parsing: <http://[::1.2.3.4x]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.4x]" but got "http://[::1.2.3.4x]/"
-FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
-FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.]" but got "http://[::1.2.3.]/"
+FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.]" but got "http://[::1.2.]/"
 FAIL Parsing: <http://[::.1.2]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::.1.2]" but got "http://[::.1.2]/"
-FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.]" but got "http://[::1.]/"
 FAIL Parsing: <http://[::.1]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::.1]" but got "http://[::.1]/"
 FAIL Parsing: <http://[::%31]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
 FAIL Parsing: <http://%5B::1]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
diff --git "a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-constructor.any.worker_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-constructor.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
index be91e5b..cf0313b 100644
--- "a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-constructor.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-constructor.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 674 tests; 501 PASS, 173 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 674 tests; 505 PASS, 169 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -77,9 +77,7 @@
 PASS Parsing: <http://2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[::127.0.0.1]> against <http://example.org/foo/bar>
-FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http:/example.com/> against <http://example.org/foo/bar>
@@ -300,16 +298,10 @@
 PASS Parsing: <http://[www.google.com]/> without base
 PASS Parsing: <http://[google.com]> against <http://other.com/>
 PASS Parsing: <http://[::1.2.3.4x]> against <http://other.com/>
-FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
-FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::1.2.3.]> against <http://other.com/>
+PASS Parsing: <http://[::1.2.]> against <http://other.com/>
 PASS Parsing: <http://[::.1.2]> against <http://other.com/>
-FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::1.]> against <http://other.com/>
 PASS Parsing: <http://[::.1]> against <http://other.com/>
 FAIL Parsing: <http://[::%31]> against <http://other.com/> assert_throws_js: function "function() {
           new URL(expected.input, base);
diff --git "a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-constructor.any_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-constructor.any_exclude=\050file_javascript_mailto\051-expected.txt"
index be91e5b..cf0313b 100644
--- "a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-constructor.any_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-constructor.any_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 674 tests; 501 PASS, 173 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 674 tests; 505 PASS, 169 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -77,9 +77,7 @@
 PASS Parsing: <http://2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[::127.0.0.1]> against <http://example.org/foo/bar>
-FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http:/example.com/> against <http://example.org/foo/bar>
@@ -300,16 +298,10 @@
 PASS Parsing: <http://[www.google.com]/> without base
 PASS Parsing: <http://[google.com]> against <http://other.com/>
 PASS Parsing: <http://[::1.2.3.4x]> against <http://other.com/>
-FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
-FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::1.2.3.]> against <http://other.com/>
+PASS Parsing: <http://[::1.2.]> against <http://other.com/>
 PASS Parsing: <http://[::.1.2]> against <http://other.com/>
-FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::1.]> against <http://other.com/>
 PASS Parsing: <http://[::.1]> against <http://other.com/>
 FAIL Parsing: <http://[::%31]> against <http://other.com/> assert_throws_js: function "function() {
           new URL(expected.input, base);
diff --git "a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
index f0ef429..03ddbd8 100644
--- "a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 222 tests; 140 PASS, 82 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 222 tests; 146 PASS, 76 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS URL: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged.
 PASS URL: Setting <a://example.net>.protocol = 'b'
@@ -91,9 +91,9 @@
 PASS URL: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.
 PASS URL: Setting <http://example.net/>.host = '[google.com]' Broken IPv6
 PASS URL: Setting <http://example.net/>.host = '[::1.2.3.4x]'
-FAIL URL: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL URL: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL URL: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS URL: Setting <http://example.net/>.host = '[::1.2.3.]'
+PASS URL: Setting <http://example.net/>.host = '[::1.2.]'
+PASS URL: Setting <http://example.net/>.host = '[::1.]'
 FAIL URL: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got ""
 FAIL URL: Setting <sc://test:12/>.host = '' assert_equals: expected "test:12" but got ""
 PASS URL: Setting <http://example.com/>.host = '///bad.com' Leading / is not stripped
@@ -128,9 +128,9 @@
 FAIL URL: Setting <view-source+http://example.net/path>.hostname = 'example.com\stuff' \ is not a delimiter for non-special schemes, but still forbidden in hosts assert_equals: expected "example.net" but got ""
 PASS URL: Setting <http://example.net/>.hostname = '[google.com]' Broken IPv6
 PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.4x]'
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.]'
+PASS URL: Setting <http://example.net/>.hostname = '[::1.2.]'
+PASS URL: Setting <http://example.net/>.hostname = '[::1.]'
 FAIL URL: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got ""
 FAIL URL: Setting <sc://test:12/>.hostname = '' assert_equals: expected "test:12" but got ""
 FAIL URL: Setting <non-spec:/.//p>.hostname = 'h' Drop /. from path assert_equals: expected "non-spec://h//p" but got "non-spec:/.//p"
diff --git "a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt"
index f0ef429..03ddbd8 100644
--- "a/third_party/blink/web_tests/platform/mac/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/mac/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 222 tests; 140 PASS, 82 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 222 tests; 146 PASS, 76 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS URL: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged.
 PASS URL: Setting <a://example.net>.protocol = 'b'
@@ -91,9 +91,9 @@
 PASS URL: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.
 PASS URL: Setting <http://example.net/>.host = '[google.com]' Broken IPv6
 PASS URL: Setting <http://example.net/>.host = '[::1.2.3.4x]'
-FAIL URL: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL URL: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL URL: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS URL: Setting <http://example.net/>.host = '[::1.2.3.]'
+PASS URL: Setting <http://example.net/>.host = '[::1.2.]'
+PASS URL: Setting <http://example.net/>.host = '[::1.]'
 FAIL URL: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got ""
 FAIL URL: Setting <sc://test:12/>.host = '' assert_equals: expected "test:12" but got ""
 PASS URL: Setting <http://example.com/>.host = '///bad.com' Leading / is not stripped
@@ -128,9 +128,9 @@
 FAIL URL: Setting <view-source+http://example.net/path>.hostname = 'example.com\stuff' \ is not a delimiter for non-special schemes, but still forbidden in hosts assert_equals: expected "example.net" but got ""
 PASS URL: Setting <http://example.net/>.hostname = '[google.com]' Broken IPv6
 PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.4x]'
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.]'
+PASS URL: Setting <http://example.net/>.hostname = '[::1.2.]'
+PASS URL: Setting <http://example.net/>.hostname = '[::1.]'
 FAIL URL: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got ""
 FAIL URL: Setting <sc://test:12/>.hostname = '' assert_equals: expected "test:12" but got ""
 FAIL URL: Setting <non-spec:/.//p>.hostname = 'h' Drop /. from path assert_equals: expected "non-spec://h//p" but got "non-spec:/.//p"
diff --git "a/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-xhtml_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-xhtml_exclude=\050file_javascript_mailto\051-expected.txt"
index 8c3b8bb..55b01e34d 100644
--- "a/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-xhtml_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/win/external/wpt/url/a-element-xhtml_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -75,7 +75,7 @@
 FAIL Parsing: <http://2001::1]:80> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://2001::1]:80" but got "http://2001::1]/"
 PASS Parsing: <http://[2001::1]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[::127.0.0.1]> against <http://example.org/foo/bar>
-FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://[::127.0.0.1.]" but got "http://[::127.0.0.1.]/"
 PASS Parsing: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http:/example.com/> against <http://example.org/foo/bar>
@@ -270,10 +270,10 @@
 PASS Parsing: <http://[www.google.com]/> against <about:blank>
 FAIL Parsing: <http://[google.com]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[google.com]" but got "http://[google.com]/"
 FAIL Parsing: <http://[::1.2.3.4x]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.4x]" but got "http://[::1.2.3.4x]/"
-FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
-FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.]" but got "http://[::1.2.3.]/"
+FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.]" but got "http://[::1.2.]/"
 FAIL Parsing: <http://[::.1.2]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::.1.2]" but got "http://[::.1.2]/"
-FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.]" but got "http://[::1.]/"
 FAIL Parsing: <http://[::.1]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::.1]" but got "http://[::.1]/"
 FAIL Parsing: <http://[::%31]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
 FAIL Parsing: <http://%5B::1]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
diff --git "a/third_party/blink/web_tests/platform/win/external/wpt/url/a-element_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/win/external/wpt/url/a-element_exclude=\050file_javascript_mailto\051-expected.txt"
index 8c3b8bb..55b01e34d 100644
--- "a/third_party/blink/web_tests/platform/win/external/wpt/url/a-element_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/win/external/wpt/url/a-element_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -75,7 +75,7 @@
 FAIL Parsing: <http://2001::1]:80> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://2001::1]:80" but got "http://2001::1]/"
 PASS Parsing: <http://[2001::1]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[::127.0.0.1]> against <http://example.org/foo/bar>
-FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_equals: failure should set href to input expected "http://[::127.0.0.1.]" but got "http://[::127.0.0.1.]/"
 PASS Parsing: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http:/example.com/> against <http://example.org/foo/bar>
@@ -270,10 +270,10 @@
 PASS Parsing: <http://[www.google.com]/> against <about:blank>
 FAIL Parsing: <http://[google.com]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[google.com]" but got "http://[google.com]/"
 FAIL Parsing: <http://[::1.2.3.4x]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.4x]" but got "http://[::1.2.3.4x]/"
-FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
-FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.3.]" but got "http://[::1.2.3.]/"
+FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.2.]" but got "http://[::1.2.]/"
 FAIL Parsing: <http://[::.1.2]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::.1.2]" but got "http://[::.1.2]/"
-FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
+FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::1.]" but got "http://[::1.]/"
 FAIL Parsing: <http://[::.1]> against <http://other.com/> assert_equals: failure should set href to input expected "http://[::.1]" but got "http://[::.1]/"
 FAIL Parsing: <http://[::%31]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
 FAIL Parsing: <http://%5B::1]> against <http://other.com/> assert_unreached: Expected URL to fail parsing Reached unreachable code
diff --git "a/third_party/blink/web_tests/platform/win/external/wpt/url/url-constructor.any.worker_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/win/external/wpt/url/url-constructor.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
index 2319ac3..648cc9a 100644
--- "a/third_party/blink/web_tests/platform/win/external/wpt/url/url-constructor.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/win/external/wpt/url/url-constructor.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 674 tests; 492 PASS, 182 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 674 tests; 496 PASS, 178 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -77,9 +77,7 @@
 PASS Parsing: <http://2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[::127.0.0.1]> against <http://example.org/foo/bar>
-FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http:/example.com/> against <http://example.org/foo/bar>
@@ -300,16 +298,10 @@
 PASS Parsing: <http://[www.google.com]/> without base
 PASS Parsing: <http://[google.com]> against <http://other.com/>
 PASS Parsing: <http://[::1.2.3.4x]> against <http://other.com/>
-FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
-FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::1.2.3.]> against <http://other.com/>
+PASS Parsing: <http://[::1.2.]> against <http://other.com/>
 PASS Parsing: <http://[::.1.2]> against <http://other.com/>
-FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::1.]> against <http://other.com/>
 PASS Parsing: <http://[::.1]> against <http://other.com/>
 FAIL Parsing: <http://[::%31]> against <http://other.com/> assert_throws_js: function "function() {
           new URL(expected.input, base);
diff --git "a/third_party/blink/web_tests/platform/win/external/wpt/url/url-constructor.any_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/win/external/wpt/url/url-constructor.any_exclude=\050file_javascript_mailto\051-expected.txt"
index 2319ac3..648cc9a 100644
--- "a/third_party/blink/web_tests/platform/win/external/wpt/url/url-constructor.any_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/win/external/wpt/url/url-constructor.any_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 674 tests; 492 PASS, 182 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 674 tests; 496 PASS, 178 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 PASS Parsing: <http://example	.
 org> against <http://example.org/foo/bar>
@@ -77,9 +77,7 @@
 PASS Parsing: <http://2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[::127.0.0.1]> against <http://example.org/foo/bar>
-FAIL Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::127.0.0.1.]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[0:0:0:0:0:0:13.1.68.3]> against <http://example.org/foo/bar>
 PASS Parsing: <http://[2001::1]:80> against <http://example.org/foo/bar>
 PASS Parsing: <http:/example.com/> against <http://example.org/foo/bar>
@@ -300,16 +298,10 @@
 PASS Parsing: <http://[www.google.com]/> without base
 PASS Parsing: <http://[google.com]> against <http://other.com/>
 PASS Parsing: <http://[::1.2.3.4x]> against <http://other.com/>
-FAIL Parsing: <http://[::1.2.3.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
-FAIL Parsing: <http://[::1.2.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::1.2.3.]> against <http://other.com/>
+PASS Parsing: <http://[::1.2.]> against <http://other.com/>
 PASS Parsing: <http://[::.1.2]> against <http://other.com/>
-FAIL Parsing: <http://[::1.]> against <http://other.com/> assert_throws_js: function "function() {
-          new URL(expected.input, base);
-        }" did not throw
+PASS Parsing: <http://[::1.]> against <http://other.com/>
 PASS Parsing: <http://[::.1]> against <http://other.com/>
 FAIL Parsing: <http://[::%31]> against <http://other.com/> assert_throws_js: function "function() {
           new URL(expected.input, base);
diff --git "a/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters-a-area.window_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters-a-area.window_exclude=\050file_javascript_mailto\051-expected.txt"
index 0a35647..dc5899e 100644
--- "a/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters-a-area.window_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters-a-area.window_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 443 tests; 267 PASS, 176 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 443 tests; 279 PASS, 164 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 FAIL <a>: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged. assert_equals: expected "a://example.net" but got "file:///A://example.net"
 FAIL <area>: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged. assert_equals: expected "a://example.net" but got "file:///A://example.net"
@@ -181,12 +181,12 @@
 PASS <area>: Setting <http://example.net/>.host = '[google.com]' Broken IPv6
 PASS <a>: Setting <http://example.net/>.host = '[::1.2.3.4x]'
 PASS <area>: Setting <http://example.net/>.host = '[::1.2.3.4x]'
-FAIL <a>: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL <area>: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL <a>: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL <area>: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL <a>: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
-FAIL <area>: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS <a>: Setting <http://example.net/>.host = '[::1.2.3.]'
+PASS <area>: Setting <http://example.net/>.host = '[::1.2.3.]'
+PASS <a>: Setting <http://example.net/>.host = '[::1.2.]'
+PASS <area>: Setting <http://example.net/>.host = '[::1.2.]'
+PASS <a>: Setting <http://example.net/>.host = '[::1.]'
+PASS <area>: Setting <http://example.net/>.host = '[::1.]'
 FAIL <a>: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got ""
 FAIL <area>: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got ""
 FAIL <a>: Setting <sc://test:12/>.host = '' assert_equals: expected "test:12" but got ""
@@ -255,12 +255,12 @@
 PASS <area>: Setting <http://example.net/>.hostname = '[google.com]' Broken IPv6
 PASS <a>: Setting <http://example.net/>.hostname = '[::1.2.3.4x]'
 PASS <area>: Setting <http://example.net/>.hostname = '[::1.2.3.4x]'
-FAIL <a>: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL <area>: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL <a>: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL <area>: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL <a>: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
-FAIL <area>: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS <a>: Setting <http://example.net/>.hostname = '[::1.2.3.]'
+PASS <area>: Setting <http://example.net/>.hostname = '[::1.2.3.]'
+PASS <a>: Setting <http://example.net/>.hostname = '[::1.2.]'
+PASS <area>: Setting <http://example.net/>.hostname = '[::1.2.]'
+PASS <a>: Setting <http://example.net/>.hostname = '[::1.]'
+PASS <area>: Setting <http://example.net/>.hostname = '[::1.]'
 FAIL <a>: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got ""
 FAIL <area>: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got ""
 FAIL <a>: Setting <sc://test:12/>.hostname = '' assert_equals: expected "test:12" but got ""
diff --git "a/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
index 4ab415a..7724849e 100644
--- "a/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters.any.worker_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 222 tests; 130 PASS, 92 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 222 tests; 136 PASS, 86 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 FAIL URL: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged. assert_equals: expected "a://example.net" but got "file:///A://example.net"
 FAIL URL: Setting <a://example.net>.protocol = 'b' assert_equals: expected "b://example.net" but got "file:///B:///A://example.net"
@@ -91,9 +91,9 @@
 PASS URL: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.
 PASS URL: Setting <http://example.net/>.host = '[google.com]' Broken IPv6
 PASS URL: Setting <http://example.net/>.host = '[::1.2.3.4x]'
-FAIL URL: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL URL: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL URL: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS URL: Setting <http://example.net/>.host = '[::1.2.3.]'
+PASS URL: Setting <http://example.net/>.host = '[::1.2.]'
+PASS URL: Setting <http://example.net/>.host = '[::1.]'
 FAIL URL: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got ""
 FAIL URL: Setting <sc://test:12/>.host = '' assert_equals: expected "test:12" but got ""
 PASS URL: Setting <http://example.com/>.host = '///bad.com' Leading / is not stripped
@@ -128,9 +128,9 @@
 FAIL URL: Setting <view-source+http://example.net/path>.hostname = 'example.com\stuff' \ is not a delimiter for non-special schemes, but still forbidden in hosts assert_equals: expected "example.net" but got ""
 PASS URL: Setting <http://example.net/>.hostname = '[google.com]' Broken IPv6
 PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.4x]'
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.]'
+PASS URL: Setting <http://example.net/>.hostname = '[::1.2.]'
+PASS URL: Setting <http://example.net/>.hostname = '[::1.]'
 FAIL URL: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got ""
 FAIL URL: Setting <sc://test:12/>.hostname = '' assert_equals: expected "test:12" but got ""
 FAIL URL: Setting <non-spec:/.//p>.hostname = 'h' Drop /. from path assert_equals: expected "non-spec://h//p" but got "non-spec:/.//p"
diff --git "a/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt" "b/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt"
index 4ab415a..7724849e 100644
--- "a/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt"
+++ "b/third_party/blink/web_tests/platform/win/external/wpt/url/url-setters.any_exclude=\050file_javascript_mailto\051-expected.txt"
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 222 tests; 130 PASS, 92 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 222 tests; 136 PASS, 86 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Loading data…
 FAIL URL: Setting <a://example.net>.protocol = '' The empty string is not a valid scheme. Setter leaves the URL unchanged. assert_equals: expected "a://example.net" but got "file:///A://example.net"
 FAIL URL: Setting <a://example.net>.protocol = 'b' assert_equals: expected "b://example.net" but got "file:///B:///A://example.net"
@@ -91,9 +91,9 @@
 PASS URL: Setting <http://example.net/path>.host = 'example.com:65536' Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.
 PASS URL: Setting <http://example.net/>.host = '[google.com]' Broken IPv6
 PASS URL: Setting <http://example.net/>.host = '[::1.2.3.4x]'
-FAIL URL: Setting <http://example.net/>.host = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL URL: Setting <http://example.net/>.host = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL URL: Setting <http://example.net/>.host = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS URL: Setting <http://example.net/>.host = '[::1.2.3.]'
+PASS URL: Setting <http://example.net/>.host = '[::1.2.]'
+PASS URL: Setting <http://example.net/>.host = '[::1.]'
 FAIL URL: Setting <sc://test@test/>.host = '' assert_equals: expected "test" but got ""
 FAIL URL: Setting <sc://test:12/>.host = '' assert_equals: expected "test:12" but got ""
 PASS URL: Setting <http://example.com/>.host = '///bad.com' Leading / is not stripped
@@ -128,9 +128,9 @@
 FAIL URL: Setting <view-source+http://example.net/path>.hostname = 'example.com\stuff' \ is not a delimiter for non-special schemes, but still forbidden in hosts assert_equals: expected "example.net" but got ""
 PASS URL: Setting <http://example.net/>.hostname = '[google.com]' Broken IPv6
 PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.4x]'
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.3.]' assert_equals: expected "http://example.net/" but got "http://[::102:3]/"
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.2.]' assert_equals: expected "http://example.net/" but got "http://[::100:2]/"
-FAIL URL: Setting <http://example.net/>.hostname = '[::1.]' assert_equals: expected "http://example.net/" but got "http://[::1]/"
+PASS URL: Setting <http://example.net/>.hostname = '[::1.2.3.]'
+PASS URL: Setting <http://example.net/>.hostname = '[::1.2.]'
+PASS URL: Setting <http://example.net/>.hostname = '[::1.]'
 FAIL URL: Setting <sc://test@test/>.hostname = '' assert_equals: expected "test" but got ""
 FAIL URL: Setting <sc://test:12/>.hostname = '' assert_equals: expected "test:12" but got ""
 FAIL URL: Setting <non-spec:/.//p>.hostname = 'h' Drop /. from path assert_equals: expected "non-spec://h//p" but got "non-spec:/.//p"
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 5d058d7d..796b2a5 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -1070,6 +1070,7 @@
     method constructor
     method define
     method get
+    method getName
     method upgrade
     method whenDefined
 interface CustomEvent : Event
diff --git a/third_party/cros-components/OWNERS b/third_party/cros-components/OWNERS
index aa580952..ac5fd53 100644
--- a/third_party/cros-components/OWNERS
+++ b/third_party/cros-components/OWNERS
@@ -1,2 +1,3 @@
 meredithl@chromium.org
 zafzal@google.com
+cfroussios@google.com
diff --git a/tools/make_gtest_filter.py b/tools/make_gtest_filter.py
index 93a1e3c3..d36f3687 100755
--- a/tools/make_gtest_filter.py
+++ b/tools/make_gtest_filter.py
@@ -171,7 +171,7 @@
   if class_only:
     fixtures = set([t.split('.')[0] for t in tests])
     return [c + '.*' for c in fixtures] + \
-          ['*/' + c + '/*.*' for c in fixtures] + \
+          ['*/' + c + '.*/*' for c in fixtures] + \
           [c + '.*/*' for c in fixtures] + \
           [c + '/*.*' for c in fixtures]
   else:
diff --git a/tools/make_gtest_filter_test.py b/tools/make_gtest_filter_test.py
index fbd10a2..5cef94e 100755
--- a/tools/make_gtest_filter_test.py
+++ b/tools/make_gtest_filter_test.py
@@ -46,7 +46,7 @@
     tests = ["TestSuite.TestName"]
     self.assertEqual(
         list(GetFiltersForTests(tests, class_only=True)),
-        ["TestSuite.*", "*/TestSuite/*.*", "TestSuite.*/*", "TestSuite/*.*"])
+        ["TestSuite.*", "*/TestSuite.*/*", "TestSuite.*/*", "TestSuite/*.*"])
     self.assertEqual(list(GetFiltersForTests(tests, class_only=False)), [
         "TestSuite.TestName", "*/TestSuite.TestName/*", "TestSuite.TestName/*",
         "TestSuite/*.TestName"
diff --git a/tools/metrics/histograms/metadata/apps/histograms.xml b/tools/metrics/histograms/metadata/apps/histograms.xml
index 0aa5068ee..aa5dbe2 100644
--- a/tools/metrics/histograms/metadata/apps/histograms.xml
+++ b/tools/metrics/histograms/metadata/apps/histograms.xml
@@ -1057,7 +1057,8 @@
 </histogram>
 
 <histogram name="Apps.AppList.Search.{SearchView}" enum="AppListSearchAction"
-    expires_after="2023-07-31">
+    expires_after="2024-07-31">
+  <owner>ypitsishin@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <summary>
@@ -1083,7 +1084,8 @@
 </histogram>
 
 <histogram name="Apps.AppList.Search.{SearchView}.LaunchIndex" units="index"
-    expires_after="2023-07-31">
+    expires_after="2024-07-31">
+  <owner>ypitsishin@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <summary>
@@ -1094,7 +1096,8 @@
 </histogram>
 
 <histogram name="Apps.AppList.Search.{SearchView}.{SearchAction}"
-    enum="AppListSearchResult" expires_after="2023-07-31">
+    enum="AppListSearchResult" expires_after="2024-07-31">
+  <owner>ypitsishin@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/metadata/network/histograms.xml b/tools/metrics/histograms/metadata/network/histograms.xml
index e1e06fdf..2fb8a24 100644
--- a/tools/metrics/histograms/metadata/network/histograms.xml
+++ b/tools/metrics/histograms/metadata/network/histograms.xml
@@ -671,54 +671,6 @@
   </summary>
 </histogram>
 
-<histogram name="Network.CacheTransparency.MarkedUnusable" units="list index"
-    expires_after="2023-09-10">
-  <obsolete>
-    Removed as of 03/2023, as it is replaced by Network.CacheTransparency2.
-    MarkedUnusable which has a higher range.
-  </obsolete>
-  <owner>nidhijaju@chromium.org</owner>
-  <owner>ricea@chromium.org</owner>
-  <summary>
-    Records whether a URL in the pervasive payloads list is marked as
-    &quot;unusable&quot; when the cached response is read. The list index is the
-    index of the URL in the pervasive payloads list.
-  </summary>
-</histogram>
-
-<histogram name="Network.CacheTransparency.MismatchedChecksums"
-    units="list index" expires_after="2023-09-10">
-  <obsolete>
-    Removed as of 03/2023, as it is replaced by Network.CacheTransparency2.
-    MismatchedChecksums which has a higher range.
-  </obsolete>
-  <owner>nidhijaju@chromium.org</owner>
-  <owner>ricea@chromium.org</owner>
-  <summary>
-    Records whether a URL in the pervasive payloads list has a different
-    checksum than what is expected when the response checksums are compared in
-    HttpCache::Transaction. The list index is the index of the URL in the
-    pervasive payloads list.
-  </summary>
-</histogram>
-
-<histogram name="Network.CacheTransparency.SingleKeyedCacheIsUsed"
-    units="list index" expires_after="2023-09-10">
-  <obsolete>
-    Removed as of 03/2023, as it is replaced by Network.CacheTransparency2.
-    SingleKeyedCacheIsUsed which has a higher range.
-  </obsolete>
-  <owner>nidhijaju@chromium.org</owner>
-  <owner>ricea@chromium.org</owner>
-  <summary>
-    Records whether the single-keyed cache is used for a URL in the pervasive
-    payloads list (not just when a cache entry is hit because there could be an
-    &quot;unusable&quot; flag set). This is recorded when the response checksum
-    matches the expected checksum in HttpCache::Transaction. The list index is
-    the index of the URL in the pervasive payloads list.
-  </summary>
-</histogram>
-
 <histogram name="Network.CacheTransparency.URLMatched" units="list index"
     expires_after="2023-09-10">
   <obsolete>
@@ -734,42 +686,6 @@
   </summary>
 </histogram>
 
-<histogram name="Network.CacheTransparency2.MarkedUnusable" units="list index"
-    expires_after="2023-11-01">
-  <owner>nidhijaju@chromium.org</owner>
-  <owner>ricea@chromium.org</owner>
-  <summary>
-    Records whether a URL in the pervasive payloads list is marked as
-    &quot;unusable&quot; when the cached response is read. The list index is the
-    index of the URL in the pervasive payloads list.
-  </summary>
-</histogram>
-
-<histogram name="Network.CacheTransparency2.MismatchedChecksums"
-    units="list index" expires_after="2023-11-01">
-  <owner>nidhijaju@chromium.org</owner>
-  <owner>ricea@chromium.org</owner>
-  <summary>
-    Records whether a URL in the pervasive payloads list has a different
-    checksum than what is expected when the response checksums are compared in
-    HttpCache::Transaction. The list index is the index of the URL in the
-    pervasive payloads list.
-  </summary>
-</histogram>
-
-<histogram name="Network.CacheTransparency2.SingleKeyedCacheIsUsed"
-    units="list index" expires_after="2023-11-01">
-  <owner>nidhijaju@chromium.org</owner>
-  <owner>ricea@chromium.org</owner>
-  <summary>
-    Records whether the single-keyed cache is used for a URL in the pervasive
-    payloads list (not just when a cache entry is hit because there could be an
-    &quot;unusable&quot; flag set). This is recorded when the response checksum
-    matches the expected checksum in HttpCache::Transaction. The list index is
-    the index of the URL in the pervasive payloads list.
-  </summary>
-</histogram>
-
 <histogram name="Network.CacheTransparency2.URLMatched" units="list index"
     expires_after="2023-11-01">
   <owner>nidhijaju@chromium.org</owner>
diff --git a/ui/file_manager/file_manager/background/js/drive_sync_handler.ts b/ui/file_manager/file_manager/background/js/drive_sync_handler.ts
index 30ee1cc..1f83855 100644
--- a/ui/file_manager/file_manager/background/js/drive_sync_handler.ts
+++ b/ui/file_manager/file_manager/background/js/drive_sync_handler.ts
@@ -23,17 +23,21 @@
 import {Speedometer} from './file_operation_util.js';
 
 /**
- * Keys in the metadata store related to individual sync status.
+ * Shorthand for metadata keys.
  */
-const METADATA_KEYS = [
-  chrome.fileManagerPrivate.EntryPropertyName.SYNC_STATUS,
-  chrome.fileManagerPrivate.EntryPropertyName.PROGRESS,
-];
+const {
+  SYNC_STATUS,
+  PROGRESS,
+  SYNC_COMPLETED_TIME,
+  AVAILABLE_OFFLINE,
+  PINNED,
+  CAN_PIN,
+} = chrome.fileManagerPrivate.EntryPropertyName;
 
 /**
- * Shorthand for the `COMPLETED` sync status.
+ * Shorthand for sync statuses.
  */
-const COMPLETED = chrome.fileManagerPrivate.SyncStatus.COMPLETED;
+const {COMPLETED} = chrome.fileManagerPrivate.SyncStatus;
 
 /**
  * Prefix for Out of Quota sync messages to ensure they reuse existing
@@ -114,6 +118,11 @@
   private statusMessages_: {[key: string]: {single: string, plural: string}};
 
   /**
+   * Recently completed URLs whose metadata should be updated after 300ms.
+   */
+  private completedUrls_: string[] = [];
+
+  /**
    * Rate limiter which is used to avoid sending update request for progress
    * bar too frequently.
    */
@@ -123,6 +132,46 @@
   }, 2000);
 
   /**
+   * With a rate limit of 200ms, update entries that have completed 300ms ago or
+   * longer.
+   */
+  private updateCompletedRateLimiter_ = new RateLimiter(async () => {
+    if (this.completedUrls_.length === 0) {
+      return;
+    }
+
+    const entriesToUpdate: Entry[] = [];
+    this.completedUrls_ = this.completedUrls_.filter(url => {
+      const [entry, syncCompletedTime] =
+          this.getEntryAndSyncCompletedTimeForUrl_(url);
+      // Stop tracking URLs that are no longer in the store.
+      if (!entry) {
+        return false;
+      }
+      // Update URLs that have completed over 300ms and stop tracking them.
+      if (Date.now() - syncCompletedTime > 300) {
+        entriesToUpdate.push(entry);
+        return false;
+      }
+      // Keep tracking URLs that are in the store and have completed <300ms ago.
+      return true;
+    });
+
+    if (entriesToUpdate.length) {
+      this.metadataModel_?.notifyEntriesChanged(entriesToUpdate);
+      this.metadataModel_?.get(entriesToUpdate, [
+        SYNC_STATUS,
+        PROGRESS,
+        AVAILABLE_OFFLINE,
+        PINNED,
+        CAN_PIN,
+      ]);
+    }
+
+    this.updateCompletedRateLimiter_.run();
+  }, 200);
+
+  /**
    * Saved dialog event to be sent to the next launched Files App UI window.
    */
   private savedDialogEvent_: chrome.fileManagerPrivate.DriveConfirmDialogEvent|
@@ -264,72 +313,52 @@
     }
   }
 
+  private getEntryAndSyncCompletedTimeForUrl_(url: string):
+      [Entry|null, number] {
+    const entry = getStore().getState().allEntries[url]?.entry;
+
+    if (!entry) {
+      return [null, 0];
+    }
+
+    const metadata =
+        this.metadataModel_?.getCache([entry], [SYNC_COMPLETED_TIME])[0];
+
+    return [
+      util.unwrapEntry(entry) as Entry,
+      metadata?.syncCompletedTime || 0,
+    ];
+  }
+
   /**
    * Handles file transfer status updates for individual files, updating their
    * sync status metadata.
    */
   private async updateSyncStateMetadata_(
       syncStates: chrome.fileManagerPrivate.SyncState[]) {
-    if (!this.metadataModel_) {
-      // Files app is still loading. This should have no user visible impact
-      // since sync status update events are constantly emitted.
-      return;
-    }
-
-    const completedUrls = [];
-    const completedValues = [];
-
     const urlsToUpdate = [];
     const valuesToUpdate = [];
 
     for (const {fileUrl, syncStatus, progress} of syncStates) {
-      if (syncStatus === COMPLETED) {
-        completedUrls.push(fileUrl);
-        completedValues.push([syncStatus, progress, Date.now()]);
-      } else {
+      if (syncStatus !== COMPLETED) {
         urlsToUpdate.push(fileUrl);
-        valuesToUpdate.push([syncStatus, progress]);
-      }
-    }
-
-    this.metadataModel_.update(urlsToUpdate, METADATA_KEYS, valuesToUpdate);
-
-    if (!completedUrls.length) {
-      return;
-    }
-
-    this.metadataModel_.update(
-        completedUrls,
-        [
-          ...METADATA_KEYS,
-          chrome.fileManagerPrivate.EntryPropertyName.SYNC_COMPLETED_TIME,
-        ],
-        completedValues);
-
-    // Hold "completed" state for 300ms to give users a chance to see it.
-    await new Promise(r => setTimeout(r, 300));
-
-    const {allEntries} = getStore().getState();
-    const completedEntries = [];
-    for (const url of completedUrls) {
-      const entry = allEntries[url]?.entry;
-      if (!entry) {
+        valuesToUpdate.push([syncStatus, progress, 0]);
         continue;
       }
-      completedEntries.push(util.unwrapEntry(entry));
+
+      // Only update status to completed if the previous status was different.
+      // Note: syncCompletedTime is 0 if the last event wasn't completed.
+      if (!this.getEntryAndSyncCompletedTimeForUrl_(fileUrl)[1]) {
+        urlsToUpdate.push(fileUrl);
+        valuesToUpdate.push([syncStatus, progress, Date.now()]);
+        this.completedUrls_.push(fileUrl);
+      }
     }
 
-    if (!completedEntries.length) {
-      return;
-    }
-
-    this.metadataModel_.notifyEntriesChanged(completedEntries);
-    this.metadataModel_.get(completedEntries, [
-      ...METADATA_KEYS,
-      chrome.fileManagerPrivate.EntryPropertyName.AVAILABLE_OFFLINE,
-      chrome.fileManagerPrivate.EntryPropertyName.PINNED,
-      chrome.fileManagerPrivate.EntryPropertyName.CAN_PIN,
-    ]);
+    this.metadataModel_?.update(
+        urlsToUpdate, [SYNC_STATUS, PROGRESS, SYNC_COMPLETED_TIME],
+        valuesToUpdate);
+    this.updateCompletedRateLimiter_.run();
   }
 
   /**
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
index 55dccc1..e456bb1 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
@@ -758,6 +758,7 @@
                              'canPin',
                              'syncStatus',
                              'progress',
+                             'syncCompletedTime',
                            ])[0] ||
           {};
       filelist.updateInlineStatus(listItem, metadata);
@@ -822,6 +823,7 @@
                            'canPin',
                            'syncStatus',
                            'progress',
+                           'syncCompletedTime',
                          ])[0] ||
         {};
 
@@ -843,7 +845,9 @@
     li.setAttribute('file-name', util.getEntryLabel(locationInfo, entry));
 
     if (locationInfo && locationInfo.isDriveBased) {
-      frame.appendChild(li.ownerDocument.createElement('xf-inline-status'));
+      const inlineStatus = li.ownerDocument.createElement('xf-inline-status');
+      inlineStatus.classList.add('tast-inline-status');
+      frame.appendChild(inlineStatus);
     }
 
     if (entry) {
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table.js b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
index 7a88998c..1555a86 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_table.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
@@ -836,7 +836,9 @@
     label.appendChild(
         filelist.renderFileNameLabel(this.ownerDocument, entry, locationInfo));
     if (locationInfo && locationInfo.isDriveBased) {
-      label.appendChild(this.ownerDocument.createElement('xf-inline-status'));
+      const inlineStatus = this.ownerDocument.createElement('xf-inline-status');
+      inlineStatus.classList.add('tast-inline-status');
+      label.appendChild(inlineStatus);
     }
     if (!util.isJellyEnabled() && !util.isInlineSyncStatusEnabled()) {
       const isEncrypted = FileType.isEncrypted(entry, metadata.contentMimeType);
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table_list.js b/ui/file_manager/file_manager/foreground/js/ui/file_table_list.js
index 050d371e..7970fb7 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_table_list.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_table_list.js
@@ -372,6 +372,7 @@
     'shortcut',
     'canPin',
     'isDlpRestricted',
+    'syncCompletedTime',
   ])[0];
   filelist.updateListItemExternalProps(
       li, entry, externalProps, util.isTeamDriveRoot(entry));
@@ -972,6 +973,7 @@
         'canPin',
         'syncStatus',
         'progress',
+        'syncCompletedTime',
       ])[0];
 
       filelist.updateInlineStatus(restoredItem, metadata);
@@ -989,7 +991,14 @@
     return;
   }
 
-  const {pinned, availableOffline, canPin, progress, syncStatus} = metadata;
+  const {
+    pinned,
+    availableOffline,
+    canPin,
+    progress,
+    syncStatus,
+    syncCompletedTime,
+  } = metadata;
 
   if (util.isDriveFsBulkPinningEnabled()) {
     const cantPin = canPin === false;
@@ -1005,8 +1014,16 @@
   inlineStatus.toggleAttribute('available-offline', pinned && !dimOffline);
 
   if (util.isInlineSyncStatusEnabled()) {
-    inlineStatus.setAttribute('sync-status', String(syncStatus));
-    inlineStatus.setAttribute('progress', String(progress));
+    let actualSyncStatus = syncStatus;
+    let actualProgress = progress;
+    // Force sync status as completed if it has been less than 300ms since the
+    // file has completed syncing.
+    if (Date.now() - syncCompletedTime < 300) {
+      actualSyncStatus = chrome.fileManagerPrivate.SyncStatus.COMPLETED;
+      actualProgress = 1;
+    }
+    inlineStatus.setAttribute('sync-status', String(actualSyncStatus));
+    inlineStatus.setAttribute('progress', String(actualProgress));
   }
 };
 
diff --git a/ui/file_manager/integration_tests/file_manager/drive_specific.js b/ui/file_manager/integration_tests/file_manager/drive_specific.js
index 2f39b58..ca5a4aa 100644
--- a/ui/file_manager/integration_tests/file_manager/drive_specific.js
+++ b/ui/file_manager/integration_tests/file_manager/drive_specific.js
@@ -1932,3 +1932,34 @@
   await remoteCall.waitForElement(
       appId, '.files-alert-dialog[aria-label="You are offline"]');
 };
+
+/*
+ * Verifies that once a file completes syncing, its syncing status
+ * indicator displays as "completed" and is dismissed about 300ms
+ * later.
+ */
+testcase.completedSyncStatusDismissesAfter300Ms = async () => {
+  const appId = await setupAndWaitUntilReady(RootPath.DRIVE, [], [
+    ENTRIES.hello,
+  ]);
+
+  const timeBeforeCompletion = Date.now();
+
+  // Fake the file finishing syncing.
+  await sendTestMessage({
+    name: 'setDriveSyncProgress',
+    path: `/root/${ENTRIES.hello.targetPath}`,
+    progress: 100,
+  });
+
+  const completedQuery = '#file-list xf-inline-status[sync-status=completed]';
+
+  // Verify the "sync completed" icon is displayed.
+  await remoteCall.waitForElement(appId, completedQuery);
+
+  // Verify the completed state is eventually dismissed.
+  await remoteCall.waitForElementLost(appId, completedQuery);
+
+  // Verify that at least 300ms have passed since the syncing completed.
+  chrome.test.assertTrue(Date.now() - timeBeforeCompletion >= 300);
+};
diff --git a/ui/ozone/BUILD.gn b/ui/ozone/BUILD.gn
index ad8071c7..8f89df9 100644
--- a/ui/ozone/BUILD.gn
+++ b/ui/ozone/BUILD.gn
@@ -125,6 +125,13 @@
     "public/system_input_injector.h",
   ]
 
+  if (is_chromeos_ash) {
+    sources += [
+      "public/palm_detector.cc",
+      "public/palm_detector.h",
+    ]
+  }
+
   defines = [ "IS_OZONE_BASE_IMPL" ]
 
   public_deps = [
diff --git a/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc b/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
index 31b808a..06b967ce 100644
--- a/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
@@ -138,7 +138,10 @@
     shell_toplevel_->SurfaceResize(connection(), hittest);
 
   connection()->Flush();
+#if !BUILDFLAG(IS_CHROMEOS_LACROS)
+  // TODO(crbug.com/1454893): Revisit to resolve the correct impl.
   connection()->event_source()->ResetPointerFlags();
+#endif
 }
 
 void WaylandToplevelWindow::Show(bool inactive) {
diff --git a/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
index 5d31bfa..03bb7df 100644
--- a/ui/ozone/platform/wayland/ozone_platform_wayland.cc
+++ b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
@@ -38,6 +38,7 @@
 #include "ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.h"
 #include "ui/ozone/platform/wayland/gpu/wayland_overlay_manager.h"
 #include "ui/ozone/platform/wayland/gpu/wayland_surface_factory.h"
+#include "ui/ozone/platform/wayland/host/surface_augmenter.h"
 #include "ui/ozone/platform/wayland/host/wayland_buffer_manager_connector.h"
 #include "ui/ozone/platform/wayland/host/wayland_buffer_manager_host.h"
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
@@ -369,6 +370,12 @@
         properties.supports_native_pixmaps =
             surface_factory_->SupportsNativePixmaps();
       }
+
+      if (connection_->surface_augmenter()) {
+        properties.supports_out_of_window_clip_rect =
+            connection_->surface_augmenter()
+                ->SupportsClipRectOnAugmentedSurface();
+      }
     } else if (buffer_manager_) {
       DCHECK(has_initialized_gpu());
       // These properties are set when the GetPlatformRuntimeProperties is
diff --git a/ui/ozone/public/ozone_platform.cc b/ui/ozone/public/ozone_platform.cc
index dbd88dc..b7c7ec8 100644
--- a/ui/ozone/public/ozone_platform.cc
+++ b/ui/ozone/public/ozone_platform.cc
@@ -20,6 +20,10 @@
 #include "ui/ozone/public/platform_screen.h"
 #include "ui/ozone/public/platform_user_input_monitor.h"
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ui/ozone/public/palm_detector.h"
+#endif
+
 namespace ui {
 
 namespace {
@@ -196,4 +200,15 @@
 
 void OzonePlatform::PreEarlyInitialize() {}
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+void OzonePlatform::SetPalmDetector(
+    std::unique_ptr<PalmDetector> palm_detector) {
+  palm_detector_ = std::move(palm_detector);
+}
+
+PalmDetector* OzonePlatform::GetPalmDetector() {
+  return palm_detector_.get();
+}
+#endif
+
 }  // namespace ui
diff --git a/ui/ozone/public/ozone_platform.h b/ui/ozone/public/ozone_platform.h
index 9b342b4..85bbebb5 100644
--- a/ui/ozone/public/ozone_platform.h
+++ b/ui/ozone/public/ozone_platform.h
@@ -36,6 +36,9 @@
 class InputController;
 class KeyEvent;
 class OverlayManagerOzone;
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+class PalmDetector;
+#endif
 class PlatformClipboard;
 class PlatformGLEGLUtility;
 class PlatformGlobalShortcutListener;
@@ -195,7 +198,7 @@
     bool needs_background_image = false;
 
     // Wayland only: determines whether clip rects can be delegated via the
-    // wayland protocol.
+    // wayland protocol when no quad is out of window.
     bool supports_clip_rect = false;
 
     // Wayland only: determine whether toplevel surfaces can be activated and
@@ -205,6 +208,10 @@
     // Wayland only: determines whether non axis-aligned 2d transforms can be
     // delegated via the wayland protocol.
     bool supports_affine_transform = false;
+
+    // Wayland only: determines whether clip rects can be delegated via the
+    // wayland protocol when some quads are out of window.
+    bool supports_out_of_window_clip_rect = false;
   };
 
   // Corresponds to chrome_browser_main_extra_parts.h.
@@ -351,6 +358,17 @@
 
   virtual void DumpState(std::ostream& out) const {}
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  // Sets the proper PalmDetector implementation from outside Ozone. This is
+  // used for touch screen palm rejection on ChromeOS, so this interface should
+  // be only used from ChromeOS. We use this interface instead of directly
+  // creating the implementation because we don't want Ozone code to depend on
+  // ChromeOS code to avoid circular dependency.
+  void SetPalmDetector(std::unique_ptr<PalmDetector> params);
+
+  PalmDetector* GetPalmDetector();
+#endif
+
  protected:
   bool has_initialized_ui() const { return initialized_ui_; }
   bool has_initialized_gpu() const { return initialized_gpu_; }
@@ -387,6 +405,10 @@
   // modifications to |single_process_| visible by other threads. Mutex is not
   // needed since it's set before other threads are started.
   volatile bool single_process_ = false;
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+  std::unique_ptr<PalmDetector> palm_detector_;
+#endif
 };
 
 }  // namespace ui
diff --git a/ui/ozone/public/palm_detector.cc b/ui/ozone/public/palm_detector.cc
new file mode 100644
index 0000000..242bd8c
--- /dev/null
+++ b/ui/ozone/public/palm_detector.cc
@@ -0,0 +1,13 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/public/palm_detector.h"
+
+namespace ui {
+
+PalmDetector::PalmDetector() = default;
+
+PalmDetector::~PalmDetector() = default;
+
+}  // namespace ui
diff --git a/ui/ozone/public/palm_detector.h b/ui/ozone/public/palm_detector.h
new file mode 100644
index 0000000..d236a49
--- /dev/null
+++ b/ui/ozone/public/palm_detector.h
@@ -0,0 +1,33 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PUBLIC_PALM_DETECTOR_H_
+#define UI_OZONE_PUBLIC_PALM_DETECTOR_H_
+
+#include "base/component_export.h"
+#include "base/functional/callback.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace ui {
+
+// Interface for touch screen palm detector.
+class COMPONENT_EXPORT(OZONE_BASE) PalmDetector {
+ public:
+  enum class DetectionResult { kNoPalm = 0, kPalm = 1 };
+
+  using DetectionDoneCallback = base::OnceCallback<void(DetectionResult)>;
+
+  PalmDetector();
+  PalmDetector(const PalmDetector&) = delete;
+  PalmDetector& operator=(const PalmDetector&) = delete;
+  virtual ~PalmDetector();
+
+  // Detects if a frame of heatmap data, provided by `data`, contains a palm.
+  // The `callback` will be supplied with the detection result asynchronously.
+  virtual void DetectPalm(const std::vector<double>& data,
+                          DetectionDoneCallback callback) = 0;
+};
+
+}  // namespace ui
+#endif  // UI_OZONE_PUBLIC_PALM_DETECTOR_H_
diff --git a/ui/touch_selection/touch_handle_drawable_aura.cc b/ui/touch_selection/touch_handle_drawable_aura.cc
index 68853d1..2ff4bbdd 100644
--- a/ui/touch_selection/touch_handle_drawable_aura.cc
+++ b/ui/touch_selection/touch_handle_drawable_aura.cc
@@ -39,6 +39,9 @@
 // applied when touch text editing redesign is enabled.
 constexpr int kSelectionHandlePadding = 6;
 
+// Max opacity of the selection handle image.
+constexpr float kSelectionHandleMaxOpacity = 0.8f;
+
 // Epsilon value used to compare float values to zero.
 constexpr float kEpsilon = 1e-8f;
 
@@ -161,7 +164,12 @@
     return;
 
   alpha_ = alpha;
-  window_->layer()->SetOpacity(alpha_);
+  if (::features::IsTouchTextEditingRedesignEnabled()) {
+    window_->layer()->SetOpacity(alpha_ * kSelectionHandleMaxOpacity);
+  } else {
+    window_->layer()->SetOpacity(alpha_);
+  }
+
   if (IsVisible())
     window_->Show();
   else
diff --git a/ui/touch_selection/touch_handle_drawable_aura.h b/ui/touch_selection/touch_handle_drawable_aura.h
index 93c0b05..c88bb289 100644
--- a/ui/touch_selection/touch_handle_drawable_aura.h
+++ b/ui/touch_selection/touch_handle_drawable_aura.h
@@ -61,6 +61,10 @@
   std::unique_ptr<aura::Window> window_;
 
   bool enabled_;
+
+  // Used to set the opacity of the handle drawable. The actual handle opacity
+  // is further scaled by a max opacity value (since the handle can be slightly
+  // transparent by default).
   float alpha_;
   ui::TouchHandleOrientation orientation_;
 
diff --git a/ui/views/controls/menu/menu_item_view.cc b/ui/views/controls/menu/menu_item_view.cc
index dd34e00..e226edcb 100644
--- a/ui/views/controls/menu/menu_item_view.cc
+++ b/ui/views/controls/menu/menu_item_view.cc
@@ -1142,9 +1142,8 @@
         render_text->GetContentWidth() -
         (minor_text.empty() ? 0 : config.item_horizontal_padding) -
         image.width();
-    const int image_y =
-        (minor_text_bounds.y() + minor_text_bounds.height() - image.height()) /
-        2;
+    const int image_y = minor_text_bounds.y() +
+                        (minor_text_bounds.height() - image.height()) / 2;
     canvas->DrawImageInt(
         image, GetMirroredXWithWidthInView(image_x, image.width()), image_y);
   }
diff --git a/ui/views/controls/textfield/textfield_unittest.cc b/ui/views/controls/textfield/textfield_unittest.cc
index b1001b6..585176d 100644
--- a/ui/views/controls/textfield/textfield_unittest.cc
+++ b/ui/views/controls/textfield/textfield_unittest.cc
@@ -3822,6 +3822,11 @@
 // TODO(crbug.com/1465767): Rewrite these long press tests when EventGenerator
 // can generate long press gestures.
 TEST_F(TextfieldTest, LongPressSelection) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitWithFeatures(
+      /*enabled_features=*/{::features::kTouchTextEditingRedesign},
+      /*disabled_features=*/{});
+
   InitTextfield();
   textfield_->SetText(u"Hello string world");
 
@@ -3834,12 +3839,16 @@
       ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
   event_generator_->Dispatch(&long_press);
 
-  // Check that nearest word is selected and that touch selection has been
-  // activated.
+  // Check that the nearest word is selected, but that the touch selection
+  // controller is not activated yet.
   gfx::Range range;
   textfield_->GetEditableSelectionRange(&range);
   EXPECT_EQ(range, gfx::Range(0, 5));
   EXPECT_EQ(textfield_->GetSelectedText(), u"Hello");
+  EXPECT_FALSE(test_api_->touch_selection_controller());
+
+  // Check that touch selection is activated after the long press is released.
+  event_generator_->ReleaseTouch();
   EXPECT_TRUE(test_api_->touch_selection_controller());
 }
 
@@ -4146,61 +4155,36 @@
 }
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-// Touch selection and dragging currently only works for chromeos.
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-TEST_F(TextfieldTest, TouchSelectionAndDraggingTest) {
+// No touch on desktop Mac. Tracked in http://crbug.com/445520.
+#if !BUILDFLAG(IS_MAC)
+TEST_F(TextfieldTest, TapActivatesTouchSelection) {
   InitTextfield();
   textfield_->SetText(u"hello world");
   EXPECT_FALSE(test_api_->touch_selection_controller());
-  const int x = GetCursorPositionX(2);
 
-  // Tapping on the textfield should turn on the TouchSelectionController.
-  ui::GestureEventDetails tap_details(ui::ET_GESTURE_TAP);
-  tap_details.set_tap_count(1);
-  ui::GestureEvent tap = CreateTestGestureEvent(x, 0, tap_details);
-  textfield_->OnGestureEvent(&tap);
+  // Tapping in the textfield should activate touch selection.
+  const gfx::Point kPointInTextfield = views::View::ConvertPointToScreen(
+      textfield_, {GetCursorPositionX(2), GetCursorYForTesting()});
+  event_generator_->GestureTapAt(kPointInTextfield);
+  EXPECT_TRUE(test_api_->touch_selection_controller());
+}
+
+TEST_F(TextfieldTest, ClearingFocusDeactivatesTouchSelection) {
+  InitTextfield();
+  textfield_->SetText(u"hello world");
+  EXPECT_FALSE(test_api_->touch_selection_controller());
+
+  // Tap textfield to activate touch selection.
+  const gfx::Point kPointInTextfield = views::View::ConvertPointToScreen(
+      textfield_, {GetCursorPositionX(2), GetCursorYForTesting()});
+  event_generator_->GestureTapAt(kPointInTextfield);
   EXPECT_TRUE(test_api_->touch_selection_controller());
 
-  // Un-focusing the textfield should reset the TouchSelectionController
+  // Clearing focus should deactivate touch selection.
   textfield_->GetFocusManager()->ClearFocus();
   EXPECT_FALSE(test_api_->touch_selection_controller());
-  textfield_->RequestFocus();
-
-  // With touch editing enabled, long press should not show context menu.
-  // Instead, select word and invoke TouchSelectionController.
-  ui::GestureEvent long_press_1 = CreateTestGestureEvent(
-      x, 0, ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
-  textfield_->OnGestureEvent(&long_press_1);
-  EXPECT_EQ(u"hello", textfield_->GetSelectedText());
-  EXPECT_TRUE(test_api_->touch_selection_controller());
-  EXPECT_TRUE(long_press_1.handled());
-
-  // With touch drag drop enabled, long pressing in the selected region should
-  // start a drag and remove TouchSelectionController.
-  ASSERT_TRUE(switches::IsTouchDragDropEnabled());
-  ui::GestureEvent long_press_2 = CreateTestGestureEvent(
-      x, 0, ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
-  textfield_->OnGestureEvent(&long_press_2);
-  EXPECT_EQ(u"hello", textfield_->GetSelectedText());
-  EXPECT_FALSE(test_api_->touch_selection_controller());
-  EXPECT_FALSE(long_press_2.handled());
-
-  // After disabling touch drag drop, long pressing again in the selection
-  // region should not do anything.
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kDisableTouchDragDrop);
-  ASSERT_FALSE(switches::IsTouchDragDropEnabled());
-  ui::GestureEvent long_press_3 = CreateTestGestureEvent(
-      x, 0, ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
-  textfield_->OnGestureEvent(&long_press_3);
-  EXPECT_EQ(u"hello", textfield_->GetSelectedText());
-  EXPECT_FALSE(test_api_->touch_selection_controller());
-  EXPECT_FALSE(long_press_3.handled());
 }
-#endif
 
-// No touch on desktop Mac. Tracked in http://crbug.com/445520.
-#if !BUILDFLAG(IS_MAC)
 TEST_F(TextfieldTest, TapOnSelection) {
   InitTextfield();
   textfield_->SetText(u"hello world");
@@ -4237,6 +4221,35 @@
   EXPECT_EQ(range, kTapRange);
 }
 
+// When touch drag drop is enabled, long pressing on selected text initiates
+// drag-drop behaviour. So, long pressing on selected text should preserve the
+// selection rather than selecting the nearest word and activating touch
+// selection.
+TEST_F(TextfieldTest, LongPressOnSelection) {
+  InitTextfield();
+  textfield_->SetText(u"Hello string world");
+  constexpr gfx::Range kSelectionRange(2, 7);
+  textfield_->SetEditableSelectionRange(kSelectionRange);
+  EXPECT_EQ(textfield_->GetSelectedText(), u"llo s");
+
+  // Long press on the selected text.
+  const gfx::Point kLongPressPoint = views::View::ConvertPointToScreen(
+      textfield_, {GetCursorPositionX(3), GetCursorYForTesting()});
+  event_generator_->PressTouch(kLongPressPoint);
+  ui::GestureEvent long_press = CreateTestGestureEvent(
+      kLongPressPoint.x(), kLongPressPoint.y(),
+      ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
+  event_generator_->Dispatch(&long_press);
+
+  // Check that the selection has not changed and that touch selection is not
+  // activated.
+  gfx::Range range;
+  textfield_->GetEditableSelectionRange(&range);
+  EXPECT_EQ(range, kSelectionRange);
+  EXPECT_EQ(textfield_->GetSelectedText(), u"llo s");
+  EXPECT_FALSE(test_api_->touch_selection_controller());
+}
+
 TEST_F(TextfieldTest, TouchSelectionInUnfocusableTextfield) {
   InitTextfield();
   textfield_->SetText(u"hello world");
diff --git a/ui/views/touchui/touch_selection_controller_impl.cc b/ui/views/touchui/touch_selection_controller_impl.cc
index 705837e..7b4e83b9 100644
--- a/ui/views/touchui/touch_selection_controller_impl.cc
+++ b/ui/views/touchui/touch_selection_controller_impl.cc
@@ -72,6 +72,9 @@
 // boundaries.
 constexpr int kSelectionHandleBarBottomAllowance = 3;
 
+// Opacity of the selection handle image.
+constexpr float kSelectionHandleOpacity = 0.8f;
+
 // Delay before showing the quick menu after it is requested, in milliseconds.
 constexpr int kQuickMenuDelayInMs = 200;
 
@@ -257,6 +260,12 @@
       std::make_unique<views::Widget>(std::move(params));
   widget->GetNativeWindow()->SetEventTargeter(
       std::make_unique<aura::WindowTargeter>());
+  if (::features::IsTouchTextEditingRedesignEnabled()) {
+    // Disable visibility change animations so that the handle's opacity is not
+    // overridden by fade effects.
+    widget->SetVisibilityChangedAnimationsEnabled(false);
+    widget->SetOpacity(kSelectionHandleOpacity);
+  }
 
   return widget;
 }
diff --git a/url/url_features.cc b/url/url_features.cc
index b74864c..858e827 100644
--- a/url/url_features.cc
+++ b/url/url_features.cc
@@ -18,7 +18,7 @@
 
 BASE_FEATURE(kStrictIPv4EmbeddedIPv6AddressParsing,
              "StrictIPv4EmbeddedIPv6AddressParsing",
-             base::FEATURE_DISABLED_BY_DEFAULT);
+             base::FEATURE_ENABLED_BY_DEFAULT);
 
 // Kill switch for crbug.com/1220361.
 BASE_FEATURE(kResolveBareFragmentWithColonOnNonHierarchical,